commit 611aebc86e4df7ee32af4e9ec5a742e16ccbf6d8 Author: Repellent Date: Thu Sep 18 17:05:50 2025 +0500 init repo diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..78bcfa3 --- /dev/null +++ b/.htaccess @@ -0,0 +1,337 @@ +###################### AVE.CMS_HTACCESS_BEGIN ########################## +# Options: +# -MultiViews: Turns off multiviews so it doesn't interfer with our rewrite rules +# -Indexes: Stop directory listings +# +FollowSymlinks: Let out rewrite rules work + +Options -Indexes +FollowSymLinks + + +# ------------------------------------------------------------------------------ +# | PHP Configuration | +# ------------------------------------------------------------------------------ + + php_value default_charset utf-8 + + #Отлючаем вывод ошибок + #php_value error_reporting E_NONE + + # Этот параметр устанавливает максимальное время в секундах, позволяющее скрипту запускаться прежде, чем он завершается синтаксическим анализатором. + #php_value max_execution_time 300 + + # Максимальное время загрузки данных для скрипта, в том числе и файлов из формы + #php_value max_input_time 300 + + # Ограничивает максимальный объем данных, получаемых от пользователя методом POST + #php_value post_max_size 512M + + # Устанавливает максимальный размер файла, который может быть получен методом POST (меньше, чем post_max_size) + #php_value upload_max_filesize 128M + + # Максимальное кол-во загружаемых файлов + #php_value max_file_uploads 50 + + # Включаем у PHP короткие + + + SetEnvIf Origin ":" IS_CORS + Header set Access-Control-Allow-Origin "*" env=IS_CORS + + + + + +# ------------------------------------------------------------------------------ +# | Web fonts access | +# ------------------------------------------------------------------------------ + +# Allow access to web fonts from all domains. + + + + Header set Access-Control-Allow-Origin "*" + + + + +# ############################################################################## +# # INTERNET EXPLORER # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Better website experience | +# ------------------------------------------------------------------------------ + +# Force Internet Explorer to render pages in the highest available mode +# in the various cases when it may not. +# http://hsivonen.iki.fi/doctype/ie-mode.pdf + + + Header set X-UA-Compatible "IE=edge" + # `mod_headers` cannot match based on the content-type, however, this + # header should be send only for HTML pages and not for the other resources + + Header unset X-UA-Compatible + + + + +# ############################################################################## +# # MIME TYPES AND ENCODING # +# ############################################################################## + +# ------------------------------------------------------------------------------ +# | Proper MIME types for all files | +# ------------------------------------------------------------------------------ + + + + # Audio + AddType audio/mp4 m4a f4a f4b + AddType audio/ogg oga ogg opus + + # Data interchange + AddType application/json json map + AddType application/ld+json jsonld + + # JavaScript + # Normalize to standard type. + # http://tools.ietf.org/html/rfc4329#section-7.2 + AddType application/javascript js + + # Video + AddType video/mp4 f4v f4p m4v mp4 + AddType video/ogg ogv + AddType video/webm webm + AddType video/x-flv flv + + # Web fonts + AddType application/font-woff woff + AddType application/vnd.ms-fontobject eot + + # Browsers usually ignore the font MIME types and simply sniff the bytes + # to figure out the font type. + # http://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern + + # Chrome however, shows a warning if any other MIME types are used for + # the following fonts. + + AddType application/x-font-ttf ttc ttf + AddType font/opentype otf + + # Make SVGZ fonts work on the iPad. + # https://twitter.com/FontSquirrel/status/14855840545 + AddType image/svg+xml svgz + AddEncoding gzip svgz + + # Other + AddType application/octet-stream safariextz + AddType application/x-chrome-extension crx + AddType application/x-opera-extension oex + AddType application/x-web-app-manifest+json webapp + AddType application/x-xpinstall xpi + AddType application/xml atom rdf rss xml + AddType image/webp webp + AddType image/x-icon cur + AddType text/cache-manifest appcache manifest + AddType text/vtt vtt + AddType text/x-component htc + AddType text/x-vcard vcf + + + +# ------------------------------------------------------------------------------ +# | UTF-8 encoding | +# ------------------------------------------------------------------------------ + +# Use UTF-8 encoding for anything served as `text/html` or `text/plain`. +AddDefaultCharset utf-8 + +# Force UTF-8 for certain file formats. + + AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml + + + +# ------------------------------------------------------------------------------ +# | Expires headers | +# ------------------------------------------------------------------------------ + +# The following expires headers are set pretty far in the future. If you +# don't control versioning with filename-based cache busting, consider +# lowering the cache time for resources such as style sheets and JavaScript +# files to something like one week. + + + + ExpiresActive on + ExpiresDefault "access plus 1 month" + + # CSS + ExpiresByType text/css "access plus 1 year" + + # Data interchange + ExpiresByType application/json "access plus 0 seconds" + ExpiresByType application/ld+json "access plus 0 seconds" + ExpiresByType application/xml "access plus 0 seconds" + ExpiresByType text/xml "access plus 0 seconds" + + # Favicon (cannot be renamed!) and cursor images + ExpiresByType image/x-icon "access plus 2 months" + + # HTML components (HTCs) + ExpiresByType text/x-component "access plus 1 month" + + # HTML + ExpiresByType text/html "access plus 0 seconds" + + # JavaScript + ExpiresByType application/javascript "access plus 1 year" + ExpiresByType text/javascript "access plus 1 year" + + # Manifest files + ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" + ExpiresByType text/cache-manifest "access plus 0 seconds" + + # Media + ExpiresByType audio/ogg "access plus 1 month" + ExpiresByType image/gif "access plus 1 month" + ExpiresByType image/jpeg "access plus 1 month" + ExpiresByType image/png "access plus 1 month" + ExpiresByType image/webp "access plus 1 month" + ExpiresByType video/mp4 "access plus 1 month" + ExpiresByType video/ogg "access plus 1 month" + ExpiresByType video/webm "access plus 1 month" + + # Web feeds + ExpiresByType application/atom+xml "access plus 1 hour" + ExpiresByType application/rss+xml "access plus 1 hour" + + # Web fonts + ExpiresByType application/font-woff "access plus 1 month" + ExpiresByType application/vnd.ms-fontobject "access plus 1 month" + ExpiresByType application/x-font-ttf "access plus 1 month" + ExpiresByType font/opentype "access plus 1 month" + ExpiresByType image/svg+xml "access plus 1 month" + + # Images + ExpiresByType image/gif "access plus 2 months" + ExpiresByType image/jpeg "access plus 2 months" + ExpiresByType image/x-icon "access plus 2 months" + ExpiresByType image/png "access plus 2 months" + ExpiresByType image/webp "access plus 2 months" + + + + Order allow,deny + + + + Header set Cache-Control "max-age=2592000, must-revalidate" + + + + SecFilterScanPOST Off + + +# ------------------------------------------------------------------------------ +# | mod_deflate.c | +# ------------------------------------------------------------------------------ + + + + SetOutputFilter DEFLATE + + + +# ------------------------------------------------------------------------------ +# | mod_gzip.c | +# ------------------------------------------------------------------------------ + + + mod_gzip_on Yes + mod_gzip_dechunk Yes + mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$ + mod_gzip_item_include mime ^application/x-javascript.* + mod_gzip_item_include mime ^text/.* + mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.* + mod_gzip_item_exclude mime ^image/.* + mod_gzip_item_include handler ^cgi-script$ + + +# ------------------------------------------------------------------------------ +# | Rewrite engine | +# ------------------------------------------------------------------------------ + + + RewriteEngine on + RewriteBase / + + # Заглушка для index.php + RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/ + RewriteRule ^index\.php$ http://%{HTTP_HOST}/ [R=301,L] + + # Убираем слеш в конце +# RewriteCond %{HTTP_HOST} (.*) +# RewriteCond %{REQUEST_URI} /$ [NC] +# RewriteRule ^(.*)(/)$ $1 [L,R=301] + + # Редирект с www.domain.com на domain.com +# RewriteCond %{HTTP_HOST} ^www\.(.+) [NC] +# RewriteRule (.*) http://%1/$1 [R=permanent,L] + + # Редирект с domain.com на www.domain.com +# RewriteCond %{HTTP_HOST} !^www\. [NC] +# RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [QSA,L] + +# RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR] +# RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR] +# RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2}) + + RewriteCond %{REQUEST_URI} !^/(class|config|fields|functions|inc|modules|lib|templates|tmp)/ + + # Файл robots.txt + RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC] + + # Файл sitemap.xml + RewriteRule ^sitemap.xml$ inc/sitemap.php [QSA,L] + RewriteRule ^sitemap-([0-9]+).xml$ inc/sitemap.php?id=$1 [QSA,L] + +#--start-ave-editor--# + +#--end-ave-editor--# + + # RSS + RewriteRule ^rss/rss-([0-9]+).xml$ inc/rss.php?id=$1 [QSA,L] + + RewriteRule \.(ico)$ - [NC,L] + + # If-Modified-Since + RewriteRule .* - [E=HTTP_IF_MODIFIED_SINCE:%{HTTP:If-Modified-Since}] + RewriteRule .* - [E=HTTP_IF_NONE_MATCH:%{HTTP:If-None-Match}] + + RewriteRule ^index.php$ - [L] + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule .* index.php [L] + +####################### AVE.CMS_HTACCESS_END ########################### \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..11cce92 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +### Альтернативная версия AVE.CMS v3.28 ALT +#### Основное отличие: +#### Удалены оригинальные запросы. На замену им вернулись запросы из старой доброй AVE.CMS ver 2.09RC1 с полным рефакторингом кода под текущие среды и задачи. Теперь снова доступен выпадающий список в качестве панели управления условиями запроса из публичной части сайта, создавать фильтры стало как никогда легко и просто, а условия, созданные в админке, полностью работоспособны. +#### Работает в программной среде: PHP-8.4 MySQL-8.4 +#### Добавлена поддержка графических файлов изображений в формате .webp +#### Обновлены библиотеки diff --git a/admin/.htaccess b/admin/.htaccess new file mode 100644 index 0000000..4951997 --- /dev/null +++ b/admin/.htaccess @@ -0,0 +1 @@ + RewriteEngine off diff --git a/admin/admin.favicon.ico b/admin/admin.favicon.ico new file mode 100644 index 0000000..a0e897a Binary files /dev/null and b/admin/admin.favicon.ico differ diff --git a/admin/admin.php b/admin/admin.php new file mode 100644 index 0000000..5c5cdff --- /dev/null +++ b/admin/admin.php @@ -0,0 +1,99 @@ +get_config_vars('EXIT_ADMIN')); + user_logout(); + header('Location:admin.php'); + } + + if (auth_cookie()) + { + header('Location:index.php'); + exit; + } + + if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'login') + { + // Авторизация + if (! empty($_POST['user_login']) && !empty($_POST['user_pass'])) + { + if (ADMIN_CAPTCHA) + { + if (isset($_SESSION['captcha_keystring']) && isset($_POST['securecode']) && $_SESSION['captcha_keystring'] == $_POST['securecode']) + $captcha_ok = 1; + else + { + unset($_SESSION['user_id'], $_SESSION['user_pass']); + unset($_SESSION['captcha_keystring']); + $error = $AVE_Template->get_config_vars('WRONG_CAPTCHA'); + $AVE_Template->assign('error', $error); + } + } + else + $captcha_ok = 1; + + if ($captcha_ok) + { + if (true === user_login($_POST['user_login'], $_POST['user_pass'], 1,(int)(isset($_POST['SaveLogin']) && $_POST['SaveLogin'] == '1'))) + { + //_echo($_SESSION); + if (!empty($_SESSION['redirectlink'])) + { + header('Location:' . $_SESSION['redirectlink']); + unset($_SESSION['redirectlink']); + exit; + } + + reportLog($AVE_Template->get_config_vars('LOGIN_ADMIN')); + //Перенапрявляем пользователя + header('Location:'.get_referer_admin_link().''); + exit; + + } + else + { + reportLog($AVE_Template->get_config_vars('ERROR_ADMIN') . ' - ' + . stripslashes($_POST['user_login']) . ' / ' + . stripslashes($_POST['user_pass'])); + + unset($_SESSION['user_id'], $_SESSION['user_pass']); + unset($_SESSION['captcha_keystring']); + $error = $AVE_Template->get_config_vars('WRONG_PASS'); + $AVE_Template->assign('error', $error); + } + + } + + } + } + + $AVE_Template->assign('captcha', ADMIN_CAPTCHA); + $AVE_Template->display('login.tpl'); +?> \ No newline at end of file diff --git a/admin/blocks.php b/admin/blocks.php new file mode 100644 index 0000000..6fb590f --- /dev/null +++ b/admin/blocks.php @@ -0,0 +1,131 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/blocks.txt', 'blocks'); + + switch ($_REQUEST['action']) + { + case '': + if (check_permission_acp('blocks_view')) + { + $AVE_Block->blockList(); + } + break; + + case 'new': + if (check_permission_acp('blocks_edit')) + { + $AVE_Block->blockNew(); + } + break; + + case 'edit': + if (check_permission_acp('blocks_edit')) + { + $AVE_Block->blockEdit(isset($_REQUEST['id']) ? $_REQUEST['id'] : null); + } + break; + + case 'save': + if (check_permission_acp('blocks_edit')) + { + $AVE_Block->blockSave(isset($_REQUEST['id']) ? $_REQUEST['id'] : null); + } + break; + + case 'del': + if (check_permission_acp('blocks_edit')) + { + $AVE_Block->blockDelete($_REQUEST['id']); + } + break; + + case 'alias': + if (check_permission_acp('blocks_edit')) + { + echo $AVE_Block->blockValidate($_REQUEST['alias'], (int)$_REQUEST['id']); + } + exit; + + case 'multi': + if (check_permission_acp('blocks_edit')) + { + $_REQUEST['sub'] = (!isset($_REQUEST['sub'])) ? '' : $_REQUEST['sub']; + $errors = array(); + switch ($_REQUEST['sub']) + { + case 'save': + $ok = true; + $row = $AVE_DB->Query(" + SELECT block_name + FROM " . PREFIX . "_blocks + WHERE block_name = '" . $_REQUEST['block_name'] . "' + ")->FetchRow(); + + if (@$row->block_name != '') + { + array_push($errors, $AVE_Template->get_config_vars('BLOCK_EXIST')); + $AVE_Template->assign('errors', $errors); + $ok = false; + } + + if ($_REQUEST['block_name'] == '') + { + array_push($errors, $AVE_Template->get_config_vars('BLOCK_COPY_TIP')); + $AVE_Template->assign('errors', $errors); + $ok = false; + } + + if ($ok) + { + $row = $AVE_DB->Query(" + SELECT block_text + FROM " . PREFIX . "_blocks + WHERE id = '" . (int)$_REQUEST['id'] . "' + ")->FetchRow(); + + $AVE_DB->Query(" + INSERT + INTO " . PREFIX . "_blocks + SET + Id = '', + block_name = '" . $_REQUEST['block_name'] . "', + block_text = '" . addslashes($row->block_text) . "', + block_author_id = '" . $_SESSION['user_id'] . "', + block_created = '" . time() . "' + "); + + reportLog($_SESSION['user_name'] . ' - создал копию блока (' . (int)$_REQUEST['id'] . ')', 2, 2); + + header('Location:index.php?do=blocks'.'&cp=' . SESSION); + } + + $AVE_Template->assign('content', $AVE_Template->fetch('blocks/multi.tpl')); + + break; + } + } + } +?> \ No newline at end of file diff --git a/admin/browser.php b/admin/browser.php new file mode 100644 index 0000000..91e389d --- /dev/null +++ b/admin/browser.php @@ -0,0 +1,198 @@ +config_load(BASE_DIR . '/admin/lang/' . $lang . '/main.txt'); +$AVE_Template->assign('tpl_dir', 'templates/'); +$AVE_Template->assign('ABS_PATH', '../'); + +$action = $_REQUEST['action'] ?? ''; + +switch ($action) { + case 'list': + $dir = $_REQUEST['dir'] ?? '/'; + if (strpos($dir, '..') !== false || strpos($dir, '//') !== false) { + $dir = '/'; + } + + $path = $upload_path . (is_dir($upload_path . $dir) ? $dir : '/'); + + $new_dir = $path . ($_REQUEST['newdir'] ?? ''); + $new_dir_result = (!is_dir($new_dir) && !mkdir($new_dir, 0777)); + + $skip_entry = [THUMBNAIL_DIR, 'recycled', 'index.php']; + + $dirs = []; + $files = []; + + $d = @dir($path); + if ($d) { + while (false !== ($entry = $d->read())) { + if (in_array($entry, $skip_entry, true) || $entry[0] === '.') { + continue; + } + + $fullPath = $path . $entry; + + if (is_dir($fullPath)) { + $dirs[$entry] = 'index.php?do=browser&type=' . ($_REQUEST['type'] ?? '') . + '&action=list&dir=' . $dir . $entry . '/'; + } else { + $nameParts = explode('.', $entry); + $ext = strtolower(end($nameParts)); + + $file = []; + $file['icon'] = file_exists("templates/images/mediapool/{$ext}.gif") ? $ext : 'attach'; + $file['filesize'] = round(filesize($fullPath) / 1024, 2); + $file['moddate'] = date("d.m.y, H:i", filemtime($fullPath)); + + if (in_array($ext, $images_ext, true)) { + $nameParts[count($nameParts) - 2] .= $thumb_size; + $file['bild'] = '/' . UPLOAD_DIR . $dir . THUMBNAIL_DIR . '/' . implode('.', $nameParts); + } else { + $file['bild'] = 'templates/images/file.gif'; + } + + $files[$entry] = $file; + } + } + $d->close(); + } + + ksort($dirs); + ksort($files); + + $AVE_Template->assign('new_dir_result', $new_dir_result); + $AVE_Template->assign('recycled', strpos($dir, '/recycled/') === 0); + $AVE_Template->assign('dirs', $dirs); + $AVE_Template->assign('files', $files); + $AVE_Template->assign('max_size', $max_size); + $AVE_Template->assign('dir', $dir); + $AVE_Template->assign('dirup', rtrim(dirname($dir), '\\/') . '/'); + $AVE_Template->assign('mediapath', UPLOAD_DIR); + + $AVE_Template->display('browser.tpl'); + break; + + case 'upload': + if (check_permission('mediapool_add')) { + $AVE_Template->display('browser_upload.tpl'); + } else { + echo ''; + } + break; + + case 'upload2': + header('Location:index.php?do=browser&type=image&target=' . ($_REQUEST['target'] ?? '') . '&tval=/' . UPLOAD_DIR . ($_REQUEST['tval'] ?? '')); + exit; + + case 'delfile': + if (check_permission('mediapool_del')) { + $file = $_REQUEST['file'] ?? ''; + $dir = $_REQUEST['dir'] ?? ''; + + if ($file === '' || $dir === '') { + exit(0); + } + + $file_name = basename($file); + $del_file = $upload_path . $dir . $file_name; + + if (strpos($del_file, '..') !== false || !is_file($del_file)) { + exit(0); + } + + $recycled_path = $upload_path . '/recycled/'; + if (!is_dir($recycled_path) && !mkdir($recycled_path)) { + exit(0); + } + + do { + $nameParts = explode('.', $file_name); + $nameParts[count($nameParts) - 2] .= '-' . uniqid('', true); + $recycled_file_name = implode('.', $nameParts); + } while (file_exists($recycled_path . $recycled_file_name)); + + @copy($del_file, $recycled_path . $recycled_file_name); + + if (@unlink($del_file)) { + foreach (glob($upload_path . $dir . THUMBNAIL_DIR . '/*') as $f_name) { + $base_file = basename($del_file); + $nameParts = explode('.', $base_file); + $start = strtolower(array_shift($nameParts)); + $ext = strtolower(array_pop($nameParts)); + + $regexp = '/^(' . preg_quote($start, '/') . ')*(-)(t|f|c|s).{3,}\.(' . preg_quote($ext, '/') . ')$/'; + + if (preg_match($regexp, basename($f_name))) { + @unlink($upload_path . $dir . THUMBNAIL_DIR . '/' . basename($f_name)); + } + } + + reportLog(($_SESSION['user_name'] ?? 'unknown') . ' - удалил файл (' . UPLOAD_DIR . $dir . $file_name . ')'); + } + } + + echo ''; + break; + + default: + list($target, $target_id) = explode('__', $_REQUEST['target'] ?? '__'); + + $tval = '/'; + + if (!empty($_REQUEST['tval']) && str_starts_with($_REQUEST['tval'], '/' . UPLOAD_DIR . '/')) { + $full_path = BASE_DIR . '/' . $_REQUEST['tval']; + if (is_dir($full_path)) { + $tval = rtrim(substr($_REQUEST['tval'], strlen('/' . UPLOAD_DIR)), '\\/') . '/'; + } elseif (is_file($full_path)) { + $tval = rtrim(dirname(substr($_REQUEST['tval'], strlen('/' . UPLOAD_DIR))), '\\/') . '/'; + } + } + + $AVE_Template->assign('dir', $tval); + $AVE_Template->assign('target', $target); + $AVE_Template->assign('target_id', $target_id); + $AVE_Template->assign('cppath', substr($_SERVER['PHP_SELF'], 0, -18)); + $AVE_Template->assign('mediapath', UPLOAD_DIR); + + $AVE_Template->display('browser_2frames.tpl'); + break; +} + +$out = ob_get_clean(); + +echo $out; + diff --git a/admin/dbsettings.php b/admin/dbsettings.php new file mode 100644 index 0000000..7d57816 --- /dev/null +++ b/admin/dbsettings.php @@ -0,0 +1,70 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/dbactions.txt', 'db'); + + require (BASE_DIR . '/class/class.dbdump.php'); + + $AVE_DB_Service = new AVE_DB_Service; + + if (!empty($_REQUEST['action'])) + { + switch ($_REQUEST['action']) + { + case 'optimize': + $AVE_DB_Service->databaseTableOptimize(); + break; + + case 'repair': + $AVE_DB_Service->databaseTableRepair(); + break; + + case 'dump_top': + $AVE_DB_Service->databaseDumpExport(1); + exit; + + case 'dump': + $AVE_DB_Service->databaseDumpExport(); + exit; + + case 'restore': + $AVE_DB_Service->databaseDumpImport(BASE_DIR . '/tmp/backup/'); + break; + + case 'download': + $AVE_DB_Service->databaseDumpFileSave($_REQUEST['file']); + break; + + case 'restorefile': + $AVE_DB_Service->databaseDumpFileImport($_REQUEST['file']); + break; + + case 'deletefile': + $AVE_DB_Service->databaseDumpFileDelete($_REQUEST['file']); + break; + } + } + + $AVE_Template->assign('db_size', get_mysql_size()); + $AVE_Template->assign('files', $AVE_DB_Service->databaseFilesGet()); + $AVE_Template->assign('tables', $AVE_DB_Service->databaseTableGet()); + $AVE_Template->assign('content', $AVE_Template->fetch('dbactions/actions.tpl')); +?> \ No newline at end of file diff --git a/admin/docs.php b/admin/docs.php new file mode 100644 index 0000000..2740e48 --- /dev/null +++ b/admin/docs.php @@ -0,0 +1,340 @@ +documentTemplateTimeAssign(); + + $AVE_Rubric->rubricPermissionFetch(); + + $AVE_Template->config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/docs.txt', 'docs'); + + $AVE_Template->assign("navi", $AVE_Template->fetch("navi/navi.tpl")); + + switch($_REQUEST['action']) + { + case '' : + $_docs_template = 'documents/docs.tpl'; + + if (check_permission_acp('document_view')) + { + switch($_REQUEST['sub']) + { + case 'quicksave': + $AVE_Document->quickSave(); + break; + } + $AVE_Document->documentListGet(); + } + + if (isset($_REQUEST['rubric_id']) && is_numeric($_REQUEST['rubric_id'])) + // Если существет файл с ID рубрики + if (file_exists(BASE_DIR . '/admin/templates/documents/docs-' .$_REQUEST['rubric_id'] . '.tpl')) + $_docs_template = 'documents/docs-' . $_REQUEST['rubric_id'] . '.tpl'; + + $AVE_Template->assign('content', $AVE_Template->fetch($_docs_template)); + break; + + case 'add_new': + if (check_permission_acp('document_view')) + { + $AVE_Request->requestListFetch(); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/docs_add_new.tpl')); + } + break; + + case 'showsimple': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentListGet(); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/docs_simple.tpl')); + } + break; + + case 'edit': + if (check_permission_acp('document_view')) + { + if (isset($_REQUEST['sub']) && $_REQUEST['sub'] != 'save') + { + $AVE_Navigation->navigationAllItemList(); + $AVE_Request->requestListFetch(); + } + $AVE_Document->documentEdit((int)$_REQUEST['Id']); + } + break; + + case 'copy': + if (check_permission_acp('document_view')) + { + $AVE_Navigation->navigationAllItemList(); + $AVE_Request->requestListFetch(); + $AVE_Document->documentCopy((int)$_REQUEST['Id']); + } + break; + + case 'new': + if (check_permission_acp('document_view')) + { + if (isset($_REQUEST['sub']) && $_REQUEST['sub'] != 'save') + { + $AVE_Navigation->navigationAllItemList(); + $AVE_Request->requestListFetch(); + } + + $AVE_Document->documentNew((int)$_REQUEST['rubric_id']); + } + break; + + case 'innavi': + if (check_permission_acp('document_view') && check_permission_acp('navigation_new')) + { + $AVE_Document->documentInNavi(); + } + break; + + case 'after': + if (check_permission_acp('document_view')) + { + $AVE_Navigation->navigationAllItemList(); + $AVE_Document->documentFormAfter(); + } + break; + + case 'open': + if (check_permission_acp('document_view')) + { + $AVE_Navigation->navigationItemStatusOn((int)$_REQUEST['Id']); + $AVE_Document->documentStatusSet((int)$_REQUEST['Id'], 1); + } + break; + + case 'close': + if (check_permission_acp('document_view')) + { + $AVE_Navigation->navigationItemStatusOff((int)$_REQUEST['Id']); + $AVE_Document->documentStatusSet((int)$_REQUEST['Id'], 0); + } + break; + + case 'delete': + if (check_permission_acp('document_view')) + { + $AVE_Navigation->navigationItemStatusOff((int)$_REQUEST['Id']); + $AVE_Document->documentMarkDelete((int)$_REQUEST['Id']); + } + break; + + case 'redelete': + if (check_permission_acp('document_view')) + { + $AVE_Navigation->navigationItemStatusOn((int)$_REQUEST['Id']); + $AVE_Document->documentUnmarkDelete((int)$_REQUEST['Id']); + } + break; + + case 'enddelete': + if (check_permission_acp('alles')) + { + $AVE_Navigation->navigationItemDeleteFromDoc((int)$_REQUEST['Id']); + $AVE_Document->documentDelete((int)$_REQUEST['Id']); + // Выполняем обновление страницы + header('Location:index.php?do=docs&cp=' . SESSION); + } + break; + + case 'revision_recover': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentRevissionRestore((int)$_REQUEST['doc_id'], (int)$_REQUEST['revission'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'revision_delete': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentRevissionDelete((int)$_REQUEST['doc_id'], (int)$_REQUEST['revission'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'revisions_delete': + if (check_permission_acp('document_view')) { + $AVE_Document->documentRevissionsDelete((int) $_REQUEST['doc_id'], (int) $_REQUEST['revission'], (int) $_REQUEST['rubric_id']); + } + break; + + case 'remark': + if (check_permission_acp('remark_view')) + { + $AVE_Document->documentRemarkNew((int)$_REQUEST['Id'], 0); + } + break; + + case 'remark_reply': + if (check_permission_acp('remark_view')) + { + $AVE_Document->documentRemarkNew((int)$_REQUEST['Id'], 1); + } + break; + + case 'remark_status': + if (check_permission_acp('remark_edit')) + { + $AVE_Document->documentRemarkStatus((int)$_REQUEST['Id'], (int)$_REQUEST['remark_status']); + } + break; + + case 'remark_del': + if (check_permission_acp('remark_edit')) + { + $AVE_Document->documentRemarkDelete((int)$_REQUEST['Id'], (int)$_REQUEST['remark_first']); + } + break; + + case 'change': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentRubricChange(); + } + break; + + case 'change_user': + if (check_permission_acp('document_view')) + { + switch($_REQUEST['sub']) + { + case 'save': + $AVE_Document->changeAutorSave(); + break; + } + $AVE_Template->assign('content', $AVE_Template->fetch('documents/user.tpl')); + } + break; + + case 'find_user': + if (check_permission_acp('document_view')) + { + findautor($_REQUEST['q'], 10); + } + exit; + + case 'keywords': + if (check_permission_acp('document_view')) + { + searchKeywords($_REQUEST['q']); + } + exit; + + case 'editstatus': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentEditStatus(); + } + break; + + case 'image_import': + echo json_encode(array("respons"=>image_multi_import($_REQUEST['path']), "status"=>"error", "action"=>"return")); + exit; + + case 'translit': + echo($AVE_Document->documentAliasCreate()); + exit; + + case 'checkurl': + $AVE_Document->documentAliasCheck(); + break; + + case 'aliases': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentAliasHistoryList(); + } + break; + + case 'aliases_doc': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentAliasListDoc((int)$_REQUEST['doc_id']); + } + break; + + case 'aliases_new': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentAliasNew(); + } + break; + + case 'aliases_edit': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentAliasEdit(); + } + break; + + case 'aliases_save': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentAliasSave(); + } + break; + + case 'aliases_del': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentAliasDel(); + } + break; + + case 'redirect': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentSaveRedirect(); + } + break; + + case 'changepos': + if (check_permission_acp('document_view')) + { + $AVE_Document->documentPosition(); + } + break; + + case 'publish': + if (check_permission_acp('document_view')) { + $AVE_Document->documentPublish(); + } + break; + + case 'recycle': + if (check_permission_acp('document_view')) { + $AVE_Document->documentRecycle(); + } + break; + } +?> \ No newline at end of file diff --git a/admin/fields.php b/admin/fields.php new file mode 100644 index 0000000..bb02e4b --- /dev/null +++ b/admin/fields.php @@ -0,0 +1,84 @@ +Query(" + SELECT * + FROM " . PREFIX . "_documents + WHERE Id = '" . (int)$_REQUEST['doc_id'] . "' + ")->FetchRow(); + + // запрещаем доступ, + // если автору документа не разрешено изменять свои документы в рубрике + // или пользователю не разрешено изменять все документы в рубрике + if (is_object($document)) { + $_REQUEST['rubric_id'] = (int)$document->rubric_id; + if (! + ( + ( + isset($_SESSION['user_id']) && $document->document_author_id == $_SESSION['user_id'] + && isset($_SESSION[$_REQUEST['rubric_id'] . '_editown']) && $_SESSION[$_REQUEST['rubric_id'] . '_editown'] == 1 + ) + || (isset($_SESSION[$_REQUEST['rubric_id'] . '_editall']) && $_SESSION[$_REQUEST['rubric_id'] . '_editall'] == 1) + ) + ) + { + $show = false; + } + } else { + $_REQUEST['rubric_id'] = (isset($_REQUEST['rubric_id']) && !empty($_REQUEST['rubric_id'])) ? (int)$_REQUEST['rubric_id'] : 0; + $show = false; + } + + // разрешаем доступ, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$_REQUEST['rubric_id'] . '_alles']) && $_SESSION[$_REQUEST['rubric_id'] . '_alles'] == 1) ) + { + $show = true; + } + + if ($show) + { + // Выполняем запрос к БД и получаем значение по умолчанию + $default = $AVE_DB->Query(" + SELECT + rubric_field_default + FROM " . PREFIX . "_rubric_fields + WHERE Id = '" . (int)$_REQUEST['field_id'] . "' AND rubric_id = '" . (int)$_REQUEST['rubric_id'] . "' + ")->GetCell(); + + $field_value = (isset($_REQUEST['field_value']) ? (string)$_REQUEST['field_value'] : ''); + + $field_function = 'get_field_' . (string)$_REQUEST['field']; + $field_function($field_value, $_REQUEST['type'], (int)$_REQUEST['field_id'], '', 0, $x, 0, 0, $default); + } + else + { + exit; + } + +?> \ No newline at end of file diff --git a/admin/finder.php b/admin/finder.php new file mode 100644 index 0000000..6c08684 --- /dev/null +++ b/admin/finder.php @@ -0,0 +1,24 @@ +assign('content', $AVE_Template->fetch('finder/finder.tpl')); + } +?> \ No newline at end of file diff --git a/admin/functions/func.admin.common.php b/admin/functions/func.admin.common.php new file mode 100644 index 0000000..6fa3607 --- /dev/null +++ b/admin/functions/func.admin.common.php @@ -0,0 +1,688 @@ + 0, + '404' => 0, + 'sql' => 0 + ]; + + $_logdir = BASE_DIR . '/tmp/logs/log.csv'; + $_404dir = BASE_DIR . '/tmp/logs/404.csv'; + $_sqldir = BASE_DIR . '/tmp/logs/sql.csv'; + + // Проверяем, существует ли файл и доступен ли он для чтения + if (is_readable($_logdir)) { + $fp = file($_logdir); + $logs['logs'] = count($fp); + } + + if (is_readable($_404dir)) { + $fp = file($_404dir); + $logs['404'] = count($fp); + } + + if (is_readable($_sqldir)) { + $fp = file($_sqldir); + $logs['sql'] = count($fp); + } + + // Передаем данные в шаблон для вывода + $AVE_Template->assign('logs', $logs); +} + + + /** + * Список пользователей за последние $onlinetime секунд + * + * @param int $onlinetime количество секунд + * + * @return void массив из пользователей отсортированный по последней активности + */ + function get_online_users($onlinetime = USERS_TIME_SHOW) + { + global $AVE_DB, $AVE_Template; + + $time = (time() - intval($onlinetime)); + + $sql = @$AVE_DB->Query("SELECT * FROM " . PREFIX . "_users WHERE last_visit > " . $time . " ORDER BY last_visit DESC"); + + $online_users = array(); + + while ($row = $sql->FetchRow()) + { + $row->user_name = get_username_by_id($row->Id); + $row->user_group_name = get_usergroup_by_id($row->user_group); + array_push($online_users,$row); + } + + $AVE_Template->assign('online_users', $online_users); + } + + + /** + * Форматированный вывод размера + * + * @param int $file_size размер + * @return string нормированный размер с единицой измерения + */ + function format_size($file_size) + { + if ($file_size >= 1073741824) + $file_size = round($file_size / 1073741824 * 100) / 100 . ' Gb'; + elseif ($file_size >= 1048576) + $file_size = round($file_size / 1048576 * 100) / 100 . ' Mb'; + elseif ($file_size >= 1024) + $file_size = round($file_size / 1024 * 100) / 100 . ' Kb'; + else + $file_size = $file_size . ' b'; + + return $file_size; + } + + + /** + * Извлечение из БД статистики по основным компонентам системы + * + */ + function get_ave_info() + { + global $AVE_DB, $AVE_Template; + + $cnts = array(); + + $cnts['templates'] = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_templates")->GetCell(); + $cnts['request'] = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_request")->GetCell(); + $cnts['rubrics'] = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_rubrics")->GetCell(); + + $sql = $AVE_DB->Query(" + SELECT + `ModuleStatus`, + COUNT(`ModuleStatus`) AS cntStatus + FROM + " . PREFIX . "_module + GROUP BY `ModuleStatus` + "); + + while ($row = $sql->FetchRow()) + $cnts['modules_' . $row->ModuleStatus] = $row->cntStatus; + + $sql = $AVE_DB->Query(" + SELECT + status, + COUNT(status) AS cntStatus + FROM + " . PREFIX . "_users + GROUP BY status + "); + + while ($row = $sql->FetchRow()) + $cnts['users_' . $row->status] = $row->cntStatus; + + $AVE_Template->assign('cnts', $cnts); + } + + + function countDocuments($rubric_id = null) + { + global $AVE_DB; + + if (is_numeric($rubric_id) && $rubric_id > 0) + $count = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_documents WHERE rubric_id = '".$rubric_id."'")->GetCell(); + else + $count = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_documents")->GetCell(); + + echo $count; + } + + + /** + * Размер дириктории + * + * @param string $directory наименование директории + * @return int + */ + function get_dir_size($directory) + { + if (! is_dir($directory)) + return 0; + + $size = 0; + + if ($DIR = opendir($directory)) + { + while (($dirfile = readdir($DIR)) !== false) + { + if (@is_link($directory . '/' . $dirfile) || $dirfile == '.' || $dirfile == '..') + continue; + + if (@is_file($directory . '/' . $dirfile)) + { + $size += filesize($directory . '/' . $dirfile); + } + elseif (@is_dir($directory . '/' . $dirfile)) + { + $dirSize = get_dir_size($directory . '/' . $dirfile); + + if ($dirSize >= 0) + $size += $dirSize; + else + return -1; + } + } + + closedir($DIR); + } + + return $size > 0 ? $size : 0; + } + + + /** + * Размер базы данных + * + * @return int + */ + function get_mysql_size() + { + global $AVE_DB; + + $mysql_size = 0; + + $sql = $AVE_DB->Query("SHOW TABLE STATUS LIKE '" . PREFIX . "_%'"); + + while ($row = $sql->FetchAssocArray()) + $mysql_size += $row['Data_length'] + $row['Index_length']; + + return format_size($mysql_size); + } + + + function get_ave_tags($srcfile) + { + if (@include_once($srcfile)) + { + reset ($vorlage); + $vl = array(); + + while (list($key, $value) = each($vorlage)) + { + $tag = new stdClass; + $tag->cp_tag = $key; + $tag->cp_desc = $value; + array_push($vl, $tag); + unset($tag); + } + + return $vl; + } + + return null; + } + + + function get_all_templates() + { + global $AVE_DB; + + static $templates = null; + + if ($templates == null) + { + $templates = array(); + + $sql = $AVE_DB->Query(" + SELECT + Id, + template_title + FROM " . PREFIX . "_templates + "); + + while ($row = $sql->FetchRow()) + { + array_push($templates, $row); + } + } + + return $templates; + } + + + function getInstaledModules() + { + global $AVE_Template, $AVE_Module; + + $modules = $AVE_Module->_modules; + + $modules_instaled = []; + + foreach ($modules AS $module) + { + if ($module['ModuleAdminEdit'] == 1 && $module['ModuleStatus']) + $modules_instaled[] = array( + 'ModuleName' => $module['ModuleName'], + 'ModuleSysName' => $module['ModuleSysName'] + ); + } + + unset ($modules); + + $modules_instaled = msort($modules_instaled,'ModuleName'); + + $AVE_Template->assign('modules', $modules_instaled); + } + + + function get_mime_type($file) + { + $file_extension = strtolower(mb_substr(strrchr($file, '.'), 1)); + + switch ($file_extension) + { + case 'psd': $ctype = 'image/x-photoshop'; break; + case 'rar': $ctype = 'application/x-rar-compressed'; break; + case 'zip': $ctype = 'application/x-zip-compressed'; break; + case 'pdf': $ctype = 'application/pdf'; break; + case 'bz2': $ctype = 'application/bzip2'; break; + case 'doc': + case 'dot': + case 'wiz': + case 'wzs': $ctype = 'application/msword'; break; + case 'eps': $ctype = 'application/postscript'; break; + case 'pot': + case 'ppa': + case 'pps': + case 'ppt': + case 'pwz': $ctype = 'application/vnd.ms-powerpoint'; break; + case 'rtf': $ctype = 'application/rtf'; break; + case 'rnx': $ctype = 'application/vnd.rn-realmedia'; break; + case 'hlp': $ctype = 'hlp'; break; + case 'gtar': $ctype = 'application/x-gtar'; break; + case 'gzip': + case 'tgz': $ctype = 'application/x-gzip'; break; + case 'lnx': $ctype = 'application/x-latex'; break; + case 'exe': $ctype = 'application/x-msdownload'; break; + case 'swf': $ctype = 'application/x-shockwafe-flash'; break; + case 'xml': $ctype = 'application/xml'; break; + case 'midi': $ctype = 'audio/midi'; break; + case 'mp3': + case 'mp2': + case 'mpga': $ctype = 'audio/mpeg'; break; + case 'wav': $ctype = 'audio/wav'; break; + case 'bmp': $ctype = 'audio/wav'; break; + case 'gif': $ctype = 'image/gif'; break; + case 'jpeg': + case 'jpg': + case 'jpe': $ctype = 'image/jpeg'; break; + case 'png': $ctype = 'image/png'; break; + case 'tif': + case 'tiff': $ctype = 'image/tiff'; break; + case 'ico': $ctype = 'image/x-icon'; break; + case 'csv': $ctype = 'text/comma-separated-values'; break; + case 'css': $ctype = 'text/css'; break; + case 'htm': + case 'html': + case 'shtml': $ctype = 'text/html'; break; + case 'txt': + case 'klp': + case 'tex': + case 'php': + case 'asp': + case 'aspx': + case 'php3': + case 'php4': + case 'php5': + case 'sql': $ctype = 'text/plain'; break; + case 'xml': $ctype = 'text/xml'; break; + case 'xhtm': $ctype = 'text/xhtml'; break; + case 'wml': $ctype = 'text/wml'; break; + case 'mpeg': + case 'mpg': + case 'mpe': + case 'mlv': + case 'mpa': + case 'wma': + case 'wmv': $ctype = 'video/mpeg'; break; + case 'avi': $ctype = 'video/x-msvideo'; break; + case 'mov': $ctype = 'video/quicktime'; break; + case 'xls': $ctype = 'application/vnd.ms-excel'; break; + case 'ai': $ctype = 'application/postscript'; break; + case 'rm': $ctype = 'application/vnd.rn-realmedia'; break; + case 'gz': $ctype = 'application/x-gzip'; break; + case 'js': $ctype = 'application/x-javascript'; break; + case 'pl': + case 'cc': $ctype = 'text/plain'; break; + case 'qt': $ctype = 'video/quicktime'; break; + default : $ctype='application/force-download'; + } + + return $ctype; + } + + + function file_download($filename, $retbytes = true) + { + $chunksize = 1 * (1024 * 1024); + $buffer = ''; + $cnt = 0; + + $handle = fopen($filename, 'rb'); + + if ($handle === false) + return false; + + while (! feof($handle)) + { + $buffer = fread($handle, $chunksize); + + echo $buffer; + + flush(); + + if ($retbytes) + $cnt += strlen($buffer); + } + + $status = fclose($handle); + + if ($retbytes && $status) + return $cnt; + + return $status; + } + + + function is_php_code($check_code) + { + $check_code = stripslashes($check_code); + $check_code = str_replace(' ', '', $check_code); + $check_code = strtolower($check_code); + + if (strpos($check_code, '') !== false || + strpos($check_code, 'language="php"') !== false || + strpos($check_code, "language='php'") !== false || + strpos($check_code, 'language=php') !== false) + { + return true; + } + + return false; + } + + + function check_permission_acp($perm) + { + if (! check_permission($perm)) + { + if (! defined('NOPERM')) + define('NOPERM', 1); + + return false; + } + + return true; + } + + + //Проверка на наличие модуля Контакты и новых писем + function ContactsModuleCheck() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query("SELECT * FROM " . PREFIX . "_module WHERE ModuleFunction = 'contact' and ModuleStatus = '1'"); + $enable = $sql->NumRows(); + if ($enable != "0" || $enable != "") + { + $contacts = "1"; + $sql_num = $AVE_DB->Query("SELECT * FROM " . PREFIX . "_modul_contact_info WHERE Aw_Zeit = '0'"); + $num_posts = $sql_num->NumRows(); + } + else + { + $contacts = "0"; + } + $AVE_Template->assign('num_posts', $num_posts); + $AVE_Template->assign('contacts', $contacts); + } + + + //Проверка на наличие модуля Логин + function LoginModuleCheck() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query("SELECT * FROM " . PREFIX . "_module WHERE ModuleFunction = 'mod_login' and ModuleStatus = '1'"); + + $enable = $sql->NumRows(); + + if ($enable != '0' || $enable != '') + $login_menu = '1'; + else + $login_menu = '0'; + + $AVE_Template->assign('login_menu', $login_menu); + } + + + /** + * Выводим на главную список последних 15 документов + */ + function DisplayMainDocuments() + { + global $AVE_DB, $AVE_Template; + + $doc_start = array(); + + $sql = $AVE_DB->Query(" + SELECT + doc.*, + rub.rubric_admin_teaser_template + FROM " . PREFIX . "_documents doc + LEFT JOIN " . PREFIX . "_rubrics AS rub ON rub.Id = doc.rubric_id + WHERE 1 = 1 + AND rub.rubric_docs_active = '1' + ORDER BY doc.document_published DESC LIMIT 0,10"); + while($row = $sql->FetchRow()) { + $row->rubric_title = showrubricName($row->rubric_id); + $row->document_title = stripslashes(htmlspecialchars_decode(pretty_chars($row->document_title))); + $row->document_breadcrum_title = stripslashes(htmlspecialchars_decode(pretty_chars($row->document_breadcrum_title))); + $row->document_author = get_username_by_id($row->document_author_id); // Получаем имя пользователя (Автора) + $row->cantEdit = 0; + $row->canDelete = 0; + $row->canEndDel = 0; + $row->canOpenClose = 0; + $row->rubric_admin_teaser_template = @eval2var(' ?>'.($row->rubric_admin_teaser_template > '' + ? @showrequestelement($row, $row->rubric_admin_teaser_template) + : '') . 'document_author_id == @$_SESSION['user_id'] + && isset($_SESSION[$row->rubric_id . '_editown']) && @$_SESSION[$row->rubric_id . '_editown'] == 1) + || (isset($_SESSION[$row->rubric_id . '_editall']) && $_SESSION[$row->rubric_id . '_editall'] == 1)) + { + $row->cantEdit = 1; + $row->canDelete = 1; + } + // запрещаем редактирование главной страницы и страницу ошибки 404 если требуется одобрение Администратора + if (($row->Id == 1 || $row->Id == PAGE_NOT_FOUND_ID) + && isset($_SESSION[$row->rubric_id . '_newnow']) && @$_SESSION[$row->rubric_id . '_newnow'] != 1) + { + $row->cantEdit = 0; + } + // разрешаем автору блокировать и разблокировать свои документы если не требуется одобрение Администратора + if ($row->document_author_id == @$_SESSION['user_id'] + && isset($_SESSION[$row->rubric_id . '_newnow']) && @$_SESSION[$row->rubric_id . '_newnow'] == 1) + { + $row->canOpenClose = 1; + } + // разрешаем всё, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if (UGROUP == 1 || @$_SESSION[$row->rubric_id . '_alles'] == 1) + { + $row->cantEdit = 1; + $row->canDelete = 1; + $row->canEndDel = 1; + $row->canOpenClose = 1; + } + // Запрещаем удаление Главной страницы и страницы с 404 ошибкой + if ($row->Id == 1 || $row->Id == PAGE_NOT_FOUND_ID) + { + $row->canDelete = 0; + $row->canEndDel = 0; + } + array_push($doc_start, $row); + } + $AVE_Template->assign('doc_start', $doc_start); + } + + + /** + * @param $id + * + * @return mixed + */ + function showrubricName($id) + { + global $AVE_DB; + + $sql = $AVE_DB->Query("SELECT rubric_title FROM " . PREFIX . "_rubrics WHERE Id = '$id'"); + $row = $sql->FetchRow(); + return $row->rubric_title; + } + + + /** + * @param $id + * + * @return mixed + */ + function showuserName($id) + { + global $AVE_DB; + + $sql = $AVE_DB->Query("SELECT user_name FROM " . PREFIX . "_users WHERE Id = '$id'"); + $row = $sql->FetchRow(); + return $row->user_name; + } + + + /** + * + */ + function cacheShow() + { + global $AVE_Template; + + $showCache[] = format_size(get_dir_size($AVE_Template->compile_dir)); + $showCache[] = format_size(get_dir_size($AVE_Template->sql_cache_dir)); + + $showCache = implode(' / ', $showCache); + + echo json_encode(array($showCache, 'accept')); + } + + + /** + * @param $id + * + * @return mixed + */ + function templateName($id) + { + global $AVE_DB; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_templates + WHERE + Id = '$id' + "); + + $row = $sql->FetchRow(); + + return $row->template_title; + } + + + /** + * @param $id + * + * @return mixed + */ + function groupName($id) + { + global $AVE_DB; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_user_groups + WHERE + user_group = '$id' + "); + + $row = $sql->FetchRow(); + + return $row->user_group_name; + } +?> \ No newline at end of file diff --git a/admin/groups.php b/admin/groups.php new file mode 100644 index 0000000..d4f9c91 --- /dev/null +++ b/admin/groups.php @@ -0,0 +1,68 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/groups.txt', 'groups'); + +switch ($_REQUEST['action']) +{ + case '': + if (check_permission_acp('group_view')) + { + $AVE_User->userGroupListShow(); + } + break; + + case 'grouprights': + if (check_permission_acp('group_edit')) + { + switch ($_REQUEST['sub']) + { + case '': + $AVE_User->userGroupPermissionEdit($_REQUEST['Id']); + break; + + case 'save': + $AVE_User->userGroupPermissionSave($_REQUEST['Id']); + break; + } + } + break; + + case 'new': + if (check_permission_acp('group_edit')) + { + $AVE_User->userGroupNew(); + } + break; + + case 'delete': + if (check_permission_acp('group_edit')) + { + $AVE_User->userGroupDelete($_REQUEST['Id']); + } + break; +} + +?> \ No newline at end of file diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 0000000..0860164 --- /dev/null +++ b/admin/index.php @@ -0,0 +1,137 @@ +assign('captcha', ADMIN_CAPTCHA); + $AVE_Template->display('login.tpl'); + exit; + } + + if (! defined('UID') || ! check_permission('adminpanel')) + { + user_logout(); + header('Location:admin.php'); + exit; + } + + if (empty($_SESSION['admin_language'])) + { + if (! empty($_REQUEST['feld']) && ! empty($_REQUEST['Id']) && ! empty($_REQUEST['rubric_id'])) + { + $_SESSION['redirectlink'] = 'index.php?do=docs&action=edit&pop=1' + . '&rubric_id=' . (int)$_REQUEST['rubric_id'] + . '&Id=' . (int)$_REQUEST['Id'] + . '&feld=' . (int)$_REQUEST['feld'] + . '#' . (int)$_REQUEST['feld']; + } + else + { + unset($_SESSION['redirectlink']); + } + + header('Location:admin.php'); + exit; + } + + /* Вывод модулей на всех страницах */ + getInstaledModules(); + LoginModuleCheck(); + + $AVE_Template->assign('user_avatar', getAvatar($_SESSION['user_id'],25)); + + if (! isset($_REQUEST['do'])) $_REQUEST['do'] = ''; + if (! isset($_REQUEST['action'])) $_REQUEST['action'] = ''; + if (! isset($_REQUEST['sub'])) $_REQUEST['sub'] = ''; + if (! isset($_REQUEST['submit'])) $_REQUEST['submit'] = ''; + + //Шаблоны навигации + $AVE_Template->assign('navi', $AVE_Template->fetch('navi/navi.tpl')); + $AVE_Template->assign('navi_top', $AVE_Template->fetch('navi/navi_top.tpl')); + + //Разрешенные методы + $allowed = array( + 'index', + 'start', + 'templates', + 'rubs', + 'user', + 'finder', + 'groups', + 'docs', + 'navigation', + 'logs', + 'request', + 'modules', + 'settings', + 'blocks', + 'sysblocks', + 'dbsettings', + 'browser', + 'fields' + ); + + $do = (! empty($_REQUEST['do']) && in_array($_REQUEST['do'], $allowed)) + ? $_REQUEST['do'] + : 'start'; + + header("Cache-Control: no-store, no-cache, must-revalidate"); + header("Expires: " . date("r")); + + include_once (BASE_DIR . '/admin/' . $do . '.php'); + + if (defined('NOPERM')) + $AVE_Template->assign('content', $config_vars['MAIN_NO_PERMISSION']); + + //Шаблоны + $tpl = (isset($_REQUEST['pop']) && $_REQUEST['pop'] == 1) + ? 'pop.tpl' + : 'main.tpl'; + + if (isset($_REQUEST['onlycontent']) && $_REQUEST['onlycontent'] == 1) + $tpl = 'onlycontent.tpl'; + + // Выводим шаблон + $AVE_Template->display($tpl); + + // Статистика + if ((defined('PROFILING_ADMIN') && PROFILING_ADMIN) && ! isAjax()) + echo Debug::displayInfo(); +?> \ No newline at end of file diff --git a/admin/init.php b/admin/init.php new file mode 100644 index 0000000..8b98bd9 --- /dev/null +++ b/admin/init.php @@ -0,0 +1,48 @@ +assign('tpl_dir', ABS_PATH . 'admin/templates'); + + require (BASE_DIR . '/admin/functions/func.admin.common.php'); + require (BASE_DIR . '/lib/redactor/ckeditor/adapters/ckeditor.php'); + + $lang_system = $AVE_DB->Query(" + SELECT + lang_alias_pref + FROM + " . PREFIX . "_settings_lang + WHERE + lang_default = '1' + ")->GetCell(); + + $_SESSION['admin_language'] = $lang_system; + + // Файлы шаблонов для CodeMirror + $AVE_Template->assign('codemirror_connect', BASE_DIR . '/lib/redactor/codemirror/codemirror_connect.tpl'); + $AVE_Template->assign('codemirror_editor', BASE_DIR . '/lib/redactor/codemirror/codemirror_editor.tpl'); + + // Подключаем основные ланги + $AVE_Template->config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/main.txt'); + + define('SESSION', session_id()); + $AVE_Template->assign('sess', SESSION); +?> \ No newline at end of file diff --git a/admin/js/worker/calcfilehash.js b/admin/js/worker/calcfilehash.js new file mode 100644 index 0000000..5b414c2 --- /dev/null +++ b/admin/js/worker/calcfilehash.js @@ -0,0 +1,20 @@ +var type = self.data.type, + bin = self.data.bin, + hashOpts = self.data.hashOpts; + +self.res = {}; +if (type === 'md5') { + let sp = new self.SparkMD5.ArrayBuffer(); + sp.append(bin); + self.res.hash = sp.end(); +} else { + let sha = new jsSHA('SHA' + (type.length === 5? type : ('-' + type)).toUpperCase(), 'ARRAYBUFFER'), + opts = {}; + if (type === 'ke128') { + opts.shakeLen = hashOpts.shake128len; + } else if (type === 'ke256') { + opts.shakeLen = hashOpts.shake256len; + } + sha.update(bin); + self.res.hash = sha.getHash('HEX', opts); +} diff --git a/admin/js/worker/quicklook.tiff.js b/admin/js/worker/quicklook.tiff.js new file mode 100644 index 0000000..7a994b9 --- /dev/null +++ b/admin/js/worker/quicklook.tiff.js @@ -0,0 +1,10 @@ +if (self.data.memory) { + Tiff.initialize({ TOTAL_MEMORY: self.data.memory }); +} + +var tiff = new Tiff({ buffer: self.data.data }); +self.res = { + image: tiff.readRGBAImage(), + width: tiff.width(), + height: tiff.height() +}; diff --git a/admin/js/worker/quicklook.unzip.js b/admin/js/worker/quicklook.unzip.js new file mode 100644 index 0000000..a1a7d1a --- /dev/null +++ b/admin/js/worker/quicklook.unzip.js @@ -0,0 +1,65 @@ +var type = self.data.type, + bin = new Uint8Array(self.data.bin), + unzipFiles = function() { + /** @type {Array.} */ + var filenameList = []; + /** @type {number} */ + var i; + /** @type {number} */ + var il; + /** @type {Array.} */ + var fileHeaderList; + // need check this.Y when update cdns.zlibUnzip + this.Y(); + fileHeaderList = this.i; + for (i = 0, il = fileHeaderList.length; i < il; ++i) { + // need check fileHeaderList[i].J when update cdns.zlibUnzip + filenameList[i] = fileHeaderList[i].filename + (fileHeaderList[i].J? ' ({formatSize(' + fileHeaderList[i].J + ')})' : ''); + } + return filenameList; + }, + tarFiles = function(tar) { + var filenames = [], + tarlen = tar.length, + offset = 0, + toStr = function(arr) { + return String.fromCharCode.apply(null, arr).replace(/\0+$/, ''); + }, + h, name, prefix, size, dbs; + while (offset < tarlen && tar[offset] !== 0) { + h = tar.subarray(offset, offset + 512); + name = toStr(h.subarray(0, 100)); + if (prefix = toStr(h.subarray(345, 500))) { + name = prefix + name; + } + size = parseInt(toStr(h.subarray(124, 136)), 8); + dbs = Math.ceil(size / 512) * 512; + if (name === '././@LongLink') { + name = toStr(tar.subarray(offset + 512, offset + 512 + dbs)); + } + (name !== 'pax_global_header') && filenames.push(name + (size? ' ({formatSize(' + size + ')})': '')); + offset = offset + 512 + dbs; + } + return filenames; + }; + +self.res = {}; + +switch (type) { + case 'tar': + self.res.files = tarFiles(bin); + break; + case 'zip': + self.res.files = unzipFiles.call(new Zlib.Unzip(bin)); + break; + case 'gzip': + self.res.files = tarFiles(new Zlib.Gunzip(bin).decompress()); + break; + case 'bzip2': + self.res.files = tarFiles(self.bzip2.simple(self.bzip2.array(bin))); + break; + default: + + break; +} + diff --git a/admin/lang/bg/.gitkeep b/admin/lang/bg/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/admin/lang/bg/blocks.txt b/admin/lang/bg/blocks.txt new file mode 100644 index 0000000..f2fa3fd --- /dev/null +++ b/admin/lang/bg/blocks.txt @@ -0,0 +1,69 @@ +BLOCK_HEAD = "Визуални блокове" +BLOCK_EDIT = "Управление на визуални блокове" +BLOCK_EDIT_TIP = "В този раздел се намират всички визуални блокове." +BLOCK_ID = "Id" +BLOCK_NAME = "Наименование на визуален блок" +BLOCK_HTML = "Код на визуалния блок" +BLOCK_TAGS = "Таг" +BLOCK_TAGS_2 = "HTML Tags" + + +BLOCK_VISUAL = "Визуален редактор" +BLOCK_VISUAL_H = "Визуален редакторр" + +BLOCK_MEDIAPATH = "Системен таг, път до папката с дизайна" +BLOCK_BREADCRUMB = "Системен таг, Breadcrumb" +BLOCK_DOCID_INFO = "Системен таг, идентификатор на документа" +BLOCK_PATH = "Път до корена на инсталацията" +BLOCK_HOME = "Линк към главната страница на сайта" + +BLOCK_AUTHOR = "Автор" +BLOCK_DATE = "Дата на създаване" +BLOCK_TAG = "Системен таг" +BLOCK_ACTIONS = "Действия" +BLOCK_NO_ITEMS = "Съобщение:
В този момент създадени визуални блокове." +BLOCK_BUTTON_SAVE = "Запази промените" +BLOCK_BUTTON_ADD = "Добави визуален блок" +BLOCK_BUTTON_COPY = "Копиране" +BLOCK_INSERT_H = "Добавяне на визуален блок" +BLOCK_EDIT_H = "Редактиране на визуален блок" +BLOCK_INNAME = "Въведете наименование на визуалния блок" +BLOCK_ENTER_NAME = "Моля, въведете наименованието на визуалния блок" +BLOCK_INSERT = "Тук може да добавяте и редактирате визуални блокове" + +BLOCK_SAVE = "Добави" +BLOCK_SAVEDIT = "Запази промените" +BLOCK_SAVE_NEXT = "Добави и продължи редактирането" +BLOCK_SAVEDIT_NEXT = "Приложи (CTRL+S)" + +BLOCK_INTEXT = "Визуален блок" +BLOCK_ADD = "Добави нов визуален блок" +BLOCK_ADD_BUTTON = "Добави" +BLOCK_EDIT_HINT = "Редактиране на визуален блок" +BLOCK_DELETE_HINT = "Узтриване на блок" +BLOCK_DEL_HINT = "Сигурни ли сте, че желаете да изтриете визуалния блок?" +BLOCK_LIST_LINK = "Списък с визуални блокове" +BLOCK_FILE = "Файл на шаблона" +BLOCK_SAVED = "Блокът е успешно записан." +BLOCK_COPY_TITLE = "Копиране на визуален блок" +BLOCK_COPY = "Копиране на визуален блок" +BLOCK_COPY_TIP = "Моля, въведете наименованието на визуалния блок" +BLOCK_COPY_TIP2 = "Моля, въведете наименование на копирания визуален блок" +BLOCK_EXIST = "Вече съшествува визуален блок със същото наименование" +BLOCK_SQLUPDATE = "Променил блок" +BLOCK_SQLNEW = "Създал нов визуален блок" +BLOCK_SQLDEL = "Изтрил визуален блок" +BLOCK_OR = " или " + +BLOCK_SAVED = "Визуалния блок е успешно записан" +BLOCK_SAVED_ERR = "Неуспешен запис на визуален блок.
Опитайте отново." +BLOCK_ERROR = "Грешка" +BLOCK_SUCCESS = "Изпълнено" + +// v 3.2 +BLOCK_DESCRIPTION = "Кратко описание" +BLOCK_ALIAS = "Алиас" +BLOCK_I = "Опционално. Алиасът позволява да се използва лесно запомнящсе таг [tag:BLOCK:alias] [tag:BLOCK:id]. Алиасът не може да бъде число, може да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа и трябва да бъде уникален в пределите на блоковете." +BLOCK_ACCEPT = "Этот алиас можно использовать" +BLOCK_ER_SYN = "Грешен алиас!
Алиасът не трябва да е число, да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа" +BLOCK_ER_EXISTS ="Грешен алиас!
Този алиас вече е използван в друг визуален блок" \ No newline at end of file diff --git a/admin/lang/bg/dbactions.txt b/admin/lang/bg/dbactions.txt new file mode 100644 index 0000000..dabeeae --- /dev/null +++ b/admin/lang/bg/dbactions.txt @@ -0,0 +1,50 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +DB_SUB_TITLE = "Управление на базите данни" +DB_ACTION_WARNING = "Внимание!\nВие извършвате всички действия с базите данни на свой риск.\n\nПомнете, че всякакви действия с базите данни, биха могли да повредят съществуващата информация. \n\nСигурни ли сте, че желаете да продължите?\n\n" +DB_ACTION_RESET = "Внимание!\nВие се опитвате да възстановите базата даннни от резервно копие. Цалата текуща информация, ще бъде изтрита и презаписана.\nМоля, вземете под внимание, че след възстановяването на данни, Вие ще трябва да се ауторизирате отново.\n\nСигурни ли сте, че желаете да продължите?\n\n" +DB_OPTION_LIST = "Структура на базата дани" +DB_BUTTON_ACTION = "Изпълни действие" +DB_OPTIMIZE_DATABASE = "Оптимизация на базата данни" +DB_OPTIMIZE_INFO = "Това действие позволява да се увеличи производителността и да се намали обема на Вашите бази данни. Препоръчвания интервал между оптимизацията не трябва да бъде по-малък от 1 път в седмицата." +DB_REPAIR_DATABASE = "Възстановяване на повредени таблици" +DB_REPAIR_INFO = "Това действие позволява да се направи опит да се възстановят повреди в таблиците на базата данни, в случай на некоретно представяне на информацията по страниците." +DB_BACKUP_DATABASE = "Създаване на резервно копие" +DB_BACKUP_INFO = "Това позволява да се направи резервно копие както на цялата база данни, така и наотделни таблици. Моля, изберете в списъка отляво, таблиците за които искате да създадете резервно коппие. За избор на няколко таблици натиснете клавиша CTRL." +DB_RESTORE_TITLE = "Възстановяване на базите данни от резервно копие" +DB_RESTORE_FILE = "Възстановяване на базите данни от от файл" +DB_BUTTON_RESTORE = "Възстанови" +DB_ACTION = "Изберете действие" +DB_TIPS = "Внимание! Вие изпълнявате всички действия с базите данни на свой риск и отговорност. Помнете, че всички действия извършвани с базата данни могат да повредят съществуващата информация." +DB_BACKUP_SERVER = "Запази резервно копие на сървъра" +DB_SC = "Операцията с базите данни е успешно изпълнена" + +DB_OPTIMIZE_DATABASE_SC = "Оптимизацията на базите данни е успешно изпълнена" +DB_REPAIR_DATABASE_SC = "Възстановяването на повредените таблици е успешно изпълнено" + +DB_REPORT_DUMP = "Извършил резервно копиране на базите данни" +DB_REPORT_DUMP_RECOVER = "Изпълнил възстановяване на базите данни от резервно копие" +DB_REPORT_DUMP_OPTIM = "Изпълнил оптимизация на базите данни" +DB_REPORT_DUMP_TABLE = "Изпълнил възстановяване на таблици в базите данни" + +DB_FILE_DATA = "Дата на създаване" +DB_FILE_SIZE = "Размер" +DB_FILE_NAME = "Наименование на файл" +DB_ACTIONS = "Действия" +DB_ACTIONS_EDIT = "Редактиране" +DB_ACTIONS_DEL = "Изтриване" +DB_ACTIONS_RESTORE = "Възстановяване" +DB_ACTIONS_SAVE = "Запази на компютъра" + +DB_REPORT_DUMP_DEL_OK = "Изтрил файл с резервно копие на базите данни" +DB_REPORT_DUMP_DEL_ER = "Неуспешно изтриване на файл с резервно копие на базите данни" +DB_REPORT_DUMP_ER = "Грешка: Импорта на базите данни не е изпълнен, т.к. файлът липсва или е повреден." + +DB_ACTIONS_RESTORE_H = "Възстановаване на резервно копие" +DB_ACTIONS_RESTORE_T = "Сигурни ли сте, че желаете са възстановите резервно копие на базите данни?" + +DB_ACTIONS_DELETE_H = "Изтриване на файл" +DB_ACTIONS_DELETE_T = "Сигурни ли сте, че желаете да изтриете файл с резервно копие на базите данни?" + +DB_NO_FILES_MESS = "В момента липсват файлове с резевно копие на базите данни" +DB_BACKUP_FILE_NAME = "Име на файла:" \ No newline at end of file diff --git a/admin/lang/bg/docs.txt b/admin/lang/bg/docs.txt new file mode 100644 index 0000000..b7ce593 --- /dev/null +++ b/admin/lang/bg/docs.txt @@ -0,0 +1,318 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +[docs] +DOC_SUB_TITLE = "Управление на документи" +DOC_TIPS = "В този раздел е сипсъка на всички документи в системата. Тук може да изпълните основните операции с документи, като: Преглед, Редактиране, Изтриване на документ, а също и да напишете бележка към даден документ." +DOC_DATE_FORMAT = "%d.%m.%Y %H:%M" +DOC_LEGEND = "Легенда" +DOC_LEGEND_EDIT = "Редактиране на документ" +DOC_LEGEND_SHOW = "Преглед на страницата в нов прозорец" +DOC_LEGEND_ENABLE = "Направи документа активен" +DOC_LEGEND_DISABLE = "Направи документа неактивен" +DOC_LEGEND_TEMP_DELETE = "Временно изтриване на документ (в кошчето)" +DOC_LEGEND_RESTORE = "Възстанови документа (от кошчето)" +DOC_LEGEND_FINAL_DELETE = "Окончателно изтриване на документа" +DOC_CHOSE_RUB = "Изберете рубрика" +DOC_ID = "ID" +DOC_URL_RUB = "URL" +DOC_TITLE = "Наименование документ" +DOC_URL_TITLE = "Линк към документа" +DOC_IN_RUBRIK = "Рубрика" +DOC_IN_NEW = "Нов документ" +DOC_CREATED = "Публикуван" +DOC_EDIT = "Редактиран" +DOC_PRINTED = "Отпечатан" +DOC_CLICKS = "Видян" +DOC_AUTHOR = "Автор" +DOC_ACTIONS = "Действия" +DOC_EDIT_TITLE = "Редактиране на текущия документ" +DOC_CHANGE_RUBRIC = "Преместване на текущия документ в друга рубрика" +DOC_CHANGE_AUTOR = "Промяна на автора на документа" +DOC_SHOW_TITLE = "Преглед на документа(линк без ЧПУ)" +DOC_SHOW2_TITLE = "Преглед на документа(линк c ЧПУ)" +DOC_SHOW3_TITLE = "Документ без наименование" +DOC_CREATE_NOTICE_TITLE = "Създаване на бележка" +DOC_REPLY_NOTICE_TITLE = "Преглед/отговор на бележка" +DOC_ENABLE_TITLE = "Публикуване на документа" +DOC_DISABLE_TITLE = "Сваляне от публикация(деактивиране)" +DOC_TEMPORARY_DELETE = "Поставяне на документа в кошчето" +DOC_RESTORE_DELETE = "Възстанови от кошчето" +DOC_FINAL_DELETE = "Изтриване на документ" +DOC_ICON_COMMENT = "Има въведени бележки" +DOC_ICON_PUBLIC = "Документа е спрян от публикуване(деактивиран)" +DOC_ICON_RECYCLE = "Документа е поставен в кошчето(временно изтрит)" +DOC_SORT_TEXT = "Сортиране на документите по:" +DOC_TEMPORARY_CONFIRM = "Сигурни ли сте, че желаете временно да изтриете този документ?" +DOC_FINAL_CONFIRM = "Сигурни ли сте, че желаете окончателно да изтриете този документ?" +DOC_INSERT_LINK_TIP = "За избор на търсения документ, натиснете бутона "Избор"" +DOC_BUTTON_INSERT_LINK = "Избери" +DOC_BUTTON_LINK_POPUP = "Избери в нов прозорец" +DOC_BUTTON_ADD_DOCUMENT = "Добави документ" +DOC_BUTTON_ADD_DOCUMENT_NEXT = "Добави и продължи редактирането" +DOC_BUTTON_EDIT_DOCUMENT = "Запази промените" +DOC_BUTTON_EDIT_DOCUMENT_NEXT = "Запиши и продължи(Ctrl+S)" +DOC_ADD_DOCUMENT = "Добави нов документ" +DOC_EDIT_DOCUMENT = "Редактиране на документ" +DOC_OPTIONS = "Параметри на документ" +DOC_NAME = "Наименование документ
(HTML <title>)" +DOC_URL = "Псевдоним на документа
(SEO alias)" +DOC_URL_LINK = "Подстановка Алиасов" +DOC_URL_INFO = "За да изглежда линка към документа например така:
http://www.domain.tld/phone/samsung/
напишете в това поле: phone/samsung

Суффикс на линка автоматически се добавя при извеждане
в зависимост с настройките иказани във файла inc/config.php

В наименованието е разрешено да се използват:
a-z — латински символи;
а-я — символи кирилица (ако е разрешено);
/ — слеш;
- — знак тире;
_ — знак за подчертаване.

Наименованието на линка не трябва да съдържа:
print/ или /print/ или /print;
page-XX/ или /page-XX/ или /page-XX;
apage-XX/ или /apage-XX/ или /apage-XX;
artpage-XX/ или /artpage-XX/ или /artpage-XX;
където XX - цифри" +DOC_URL_LOG = "Използване на историята на алиасите за редирект" +DOC_URL_LOG_T = "Да се съхранява или не историята на алиасите на документа за последващ редирект" +DOC_URL_LOG_RUBRIC = "Използвай настройките на рубриката" +DOC_URL_LOG_USE = "Използвай винаги" +DOC_FIELD_G_UNKNOW = "Без група" +DOC_PROPERTY = "Параметри на документа" +DOC_URL_LOG_NOTUSE = "Не използвай" +DOC_QUERIES = "Налични заявки" +DOC_META_TITLE = "TITLE - текст, който се извежда като заглавие на документа в прозореца на браузерра. Този таг е важен за SEO оптимизацията, затова моля избирайте внимателно зазглавието." +DOC_META_KEYWORDS = "Ключови думи:
(meta keywords)" +DOC_META_KEYWORDS_INFO = "Описват съдържанието на страницата, могат да бъдат използвани от търсещите системи.

Необходимо е поне част от изброените думи да присъстват в текста на страницата." +DOC_META_DESCRIPTION = "Описание на страницата
(meta description)" +DOC_META_DESCRIPTION_INFO= "Кратът текстм описващ съдържанието на страницата. Също може да бъде използвано от търсещите машини и да се извежда като пояснение в резултатите от търсенето или в интернет каталози." +DOC_CAN_SEARCH = "Разреши търсенето в документа
(за модула Търсене)" +DOC_INDEX_TYPE = "Тип индексиране на страницата
(meta robots)" +DOC_INDEX_FOLLOW = "Индексиране и преход по линковете" +DOC_INDEX_NOFOLLOW = "Индексиране, но без преход по линковете" +DOC_NOINDEX_NOFOLLOW = "Без индексиране и без преход по линковете" +DOC_SITEMAP_FREQ = "Честота на обновяване
sitemap.xml" +DOC_SITEMAP_FREQ_DOC = "Честота на обновяване на страницата" +DOC_SITEMAP_ALWAYS = "Винаги" +DOC_SITEMAP_HOURLY = "Ежечасно" +DOC_SITEMAP_DAILY = "Ежедневно" +DOC_SITEMAP_WEEKLY = "Ежеседмично" +DOC_SITEMAP_MONTHLY = "Ежемесечно" +DOC_SITEMAP_YEARLY = "Ежегодно" +DOC_SITEMAP_NEVER = "Никога" +DOC_SITEMAP_PRIORITY = "Приоритет
sitemap.xml" +DOC_SITEMAP_PRIORITY_DOC = "Приоритет на тази страница спрямо останалите" +DOC_SITEMAP_PRIORITY_LOW = "Нисък приоритет" +DOC_SITEMAP_PRIORITY_MID = "Среден приоритет" +DOC_SITEMAP_PRIORITY_HIG = "Висш приоритет" +DOC_START_PUBLICATION = "Начало на публикуване" +DOC_END_PUBLICATION = "Край на публикуване" +DOC_STATUS = "Статус на документа" +DOC_STATUS_ACTIVE = "Активен" +DOC_STATUS_INACTIVE = "Неактивен" +DOC_ADD_IN_NAVIGATION = "Добави подпункт в меню" +DOC_USE_NAVIGATION = "Свържи с пункт в меню" +DOC_USE_RUB_ALIAS = "Подстановки алиасов родителски документи, указване родителския документ за breadcrumb." +DOC_USE_BREADCRUMB = "Свържи с документ
(може да се използва за breadcrumb)" +DOC_USE_LANG_PACK = "Свържи с документ от езикова група" +DOC_NAVIGATION_INFO = "За да свържете документът с пункт от менюто, изберете съответния ред от падащия списък. Ако не е необходимо свързване, оставете полето празно." +DOC_MAIN_CONTENT = "Основно съдържание на документа" +DOC_MAIN_NOCONTENT = "Липсват полета за документа" +DOC_AFTER_CREATE_TITLE = "Следващи действия" +DOC_AFTER_CREATE_INFO = "Моля, изберете действие от списъка по долу:" +DOC_EDIT_THIS_DOCUMENT = "Продължаване редактирането на документа" +DOC_INCLUDE_NAVIGATION = "Добавяне на създадения документ в меню за навигация" +DOC_ADD_NEW_DOCUMENT = "Добавяне на нов документ в текущата рубрика" +DOC_ADD_COPY_DOCUMENT = "Добавяне на копие на документа в текущата рубрика" +DOC_DISPLAY_NEW_WINDOW = "Преглед на документа в нов прозорец (Ctrl+O)" +DOC_CLOSE_WINDOW = "Към списъка на всички документи" +DOC_CLOSE_WINDOW_RUBRIC = "Към списъка с документи от текущата рубрика" +DOC_TO_NAVI_TITLE = "Добавление документа в меню навигации" +DOC_NAVIGATION_POSITION = "Позиция в списъка:" +DOC_NAVIGATION_TITLE = "Наименование на реда в менюто:" +DOC_TARGET = "Отваряне:" +DOC_TARGET_SELF = "в текущия прозорец" +DOC_TARGET_BLANK = "в нов прозорец" +DOC_BUTTON_ADD_MENU = "Добави в меню" +DOC_TOP_MENU_ITEM = "Нов ред от 1-во ниво" +DOC_NOTICE = "Бележки към документа" +DOC_NOTICE_NEW_LINK = "Добави нова бележка" +DOC_NOTICE_AUTHOR = "Добавил: " +DOC_NOTICE_DELETE_LINK = "Изтриване на бележка" +DOC_ALLOW_NOTICE = "Разреши коментарите към бележките" +DOC_BUTTON_NOTICE = "Бележки" +DOC_NOTICE_TITLE = "Заглавие:" +DOC_NOTICE_TEXT = "Бележка:" +DOC_BUTTON_ADD_NOTICE = "Добави бележка" +DOC_SEND_NOTICE_INFO = "За да добавите нова бележка към докумнета, моля попълнете полетата във формата по долу." +DOC_NEW_NOTICE_TITLE = "Добави нова бележка" +DOC_MAIL_BODY_CHECK = "Потребителя %USER% е добавил нов документ с наименование '%TITLE%'.%N%Моля, проверете този документ преди публикуване." +DOC_MAIL_SUBJECT_CHECK = "Добавен е нов документ" +DOC_MAIL_BODY_USER = "Здравейте %USER%.%N%Създадения от Вас документ е успешно добавен и е изпратено уведомление на Администратора за проверка. Документа ще бъде публикуван след проверка." +DOC_MAIL_SUBJECT_USER = "Вашият документа е добавен и очаква проверка" +DOC_MAIL_BODY_NOTICE = "Потребителя %USER% е добавил нова бележка към документ.%N%Ауторизирайте се в панела за управление и преминете по линка по-долу, за да прочете бележката.:%N%%LINK%" +DOC_MAIL_SUBJECT_NOTICE = "Добавена е нова бележка към документ" +DOC_NEW_PAGE = "Добави нова страница" +DOC_CLOSE_HELP_WINDOW = "

" +DOC_HELP = "Помощ" +DOC_VIDEO_TYPE_HELP = "Добавяне на видео файл
При добавяне на видео файл, Вие може да зададете ширина и височина на прозореца за показване на видеото. Първото число е за ширината на прозореца, второто за височина.

Например:

video.avi|300|300
или
video.avi|100%|300" +DOC_FLASH_TYPE_HELP = "Добавяне на флаш
При добавяне на флаш, Вие може да укажете ширина и височина на прозореца за преглед. Първото значение определя ширината, второто височината.

Например:

flash.swf|300|300
или
flash.swf|100%|300" +DOC_FILE_TYPE_HELP = "Вмъкване на файл
При добавяне на файл, Вие може да зададете наименование на линка. За това е необходимо след наименованието на файла да въведете разделителен знак | и след него въведете наименованието на линка.

Например:

file.zip|Свали файла" +DOC_NO_PERMISSION = "Извинете, но Вие нямате права за редактиране на този документ." +DOC_NO_PERMISSION_RUB = "Извинете, но Вие нямате права за добавяне на документ в тази рубрика." +DOC_NO_DEL_REVISION = "Извинете, но Вие нямате права за изтриване на ревизия на документ." +DOC_NO_RES_REVISION = "Извинете, но Вие нямате права за възстановяване на ревизия на документ." +DOC_EDIT_RUB = "Прехвърли в друга рубрика" +DOC_RUBRIC = "Рубрика" +DOC_SORT_RUB = "Сортиране по рубрики" +DOC_IMAGE = "Изображението в списъка на новините" +DOC_IMAGE_MAX_W = "Максимална ширина" +DOC_IMAGE_MAX_H = "Максимална височина" +DOC_INTRO = "Тизер
(текста в списъка на новините)" +DOC_ALIAS_CREATE = "Формиране" +DOC_ENTER_NAME = "Моля, изберете рубрика в която желаете да добавите новия документ." +DOC_SORT_NAME = "Моля, изберете рубрика." +DOC_OR = " или " +DOC_NO_DOCS = "Липсват документи, отговарящи на тези условия." + +DOC_COPY = "Копиране на документ" +DOC_COPY_DOCUMENT = "Копиране на документ" +DOC_COPY_TIP = "Моля, въведете наименование на документа" + +DOC_ADD_NEW_LIGHT_TIP = "За да добваите нов документ, моля изберете рубрика." +DOC_ADD_NEW_LIGHT_ADD = "Добавяне на документ" +DOC_ADD_NEW_LIGHT_BTN = "Добави документ" + +DOC_CHANGE_TITLE = "Преместване на документ в друга рубрика" +DOC_CHANGE_INFO = "Внимание! При промяна на рубриката, непрехвърлените полета се губят!" +DOC_CHANGE_OLD_FIELD = "Поле на документ" +DOC_CHANGE_NEW_FIELD = "Преместване в ново" +DOC_CHANGE_DROP_FIELD = "-- не пренасяй --" +DOC_CHANGE_CREATE_FIELD = "-- създай ново --" +DOC_CHANGE_BUTTON = "Промени" + +DOC_CHANGE_AU_TITLE = "Промяна автор на документа" +DOC_CHANGE_AU_INFO = "Внимание! При промяна на автора, предишния автор може да бъде лишен от правата си да редактира документа." +DOC_CHANGE_BUTTON = "Запази" + +DOC_IN_MENU = "в меню" + +DOC_REVISSION = "История на промените" +DOC_REVISSION_DATA = "Дата и време на промяна" +DOC_REVISSION_USER = "Автор" +DOC_REVISSION_VIEW = "Преглед на версията" +DOC_REVISSION_RECOVER = "Възстановяване на версията" +DOC_REVISSION_RECOVER_T = "Сигурни ли сте, че желаете да възстановите версията?" +DOC_REVISSION_DELETE = "Изтриване на версия" +DOC_REVISSION_DELETE_T = "Сигурни ли сте, че желаете да изтриете тази версия?" +DOC_REVISSION_NO_ITEMS = "В момента няма данни" + +DOC_URL_ERROR_SYMBOL = " недопустими символи " +DOC_URL_ERROR_START = " започва с / " +DOC_URL_ERROR_END = " завършва на / (при това суффикс URL започва с /)" +DOC_URL_ERROR_SEGMENT = " недопустими сегменти: " +DOC_URL_ERROR_EMTY = " липсват данни за проверка " +DOC_URL_ERROR_DUPLICATES = " псевдонима вече се използва " +DOC_URL_H_ERROR_DUPLICATES = "псевдонима вече се използва в историята на алиасите" +DOC_URL_CHECK_OK = " този URL може да се използва " +DOC_URL_CHECK_ER = " в URL има грешки:
" + +DOC_REQUEST_NOT_INFO = "Липсва описание за тази заявка." + +DOC_REVISION_DELETE = "Изтрил версия на документа" +DOC_REVISION_RECOVER = "Възстановил версия на документа" + +DOC_BREADCRUMB_BTN = "Избери" +DOC_BREADCRUMB_TITLE = "Наименование на линк за breadcrumb" +DOC_BREADCRUMB_WITH = "Свързан с" + +DOC_DOCUMENT_OPEN = "Документа е активиран" +DOC_DOCUMENT_CLOSE = "Документа е деактивиран" + +DOC_DOCUMENT_DOC = "документ" +DOC_DOCUMENT_ACT = "Активирал" +DOC_DOCUMENT_DISACT = "Деактивирал" + +DOC_DOCUMENT_OPEN_ERR = "Този документ не може да бъде неактивен!" +DOC_DOCUMENT_OPEN_PRIVE = "Нямате достатъчно права за да извършите това действие!" + +DOC_ACTION_SELECT = "Действие с избраните" +DOC_ACTION_SELECT_ACT = "Активен" +DOC_ACTION_SELECT_NACT = "Неактивен" +DOC_ACTION_SELECT_TRASH = "Временно изтриване" +DOC_ACTION_SELECT_OUTTRASH = "Възстановяване" +DOC_ACTION_SELECT_DEL = "Изтриване" +DOC_ACTION_BUTTON = "Запази промените" + +DOC_CHOOSE_LANG = "Избор на език за документа" +DOC_LANG_VERSION = "Версия на документа на други езици" +DOC_LINK_CHOOSE = "Изберете документ" +DOCUMENT_SAVED = "Документът е успешно записан" + +DOC_REV_DELETED = "Ревизиите на документите са успешно изтрити" +DOC_REV_DELETED_ERR = "Неуспешно изтриване на ревизиите.
Пробвайте отново." +DOC_REV_ERROR = "Грешка" +DOC_REV_SUCCESS = "Изпълнено" +DOC_REV_UPDATE = "Изтрил ревизиите на документите" + +DOC_ALIASES = "Управление на редиректите на документите" +DOC_ALIASES_LIST_NM = "Наименование на документ" +DOC_ALIASES_LIST_RB = "Рубрика" +DOC_ALIASES_LIST_CH = "Изменено" +DOC_ALIASES_LIST_CR = "Брой" +DOC_ALIASES_LIST_AT = "Действия" +DOC_ALIASES_TITLE = "Списък на всички документи, които имата вътрешни редиректи.
Тук може да изпзълните основните операции с документите: преглед, редактиране, изтриване." +DOC_ALIASES_BREAD_RUB = "Рубрика:" +DOC_ALIASES_BREAD_DOC = "Документ:" +DOC_ALIASES_BREAD_URL = "Основен URL:" +DOC_ALIASES_DOC_LIST = "Списък документи с редиректи" +DOC_ALIASES_ADD = "Добави нов редирект" +DOC_ALIASES_ADD_VAL = "Значение на редиректа" +DOC_ALIASES_LIST = "Списък с редиректи" +DOC_ALIASES_LIST_EMPT = "Празен списък" +DOC_ALIASES_TABL_H_URL = "Алиас на редиректа" +DOC_ALIASES_TABL_H_ADD = "Добавен" +DOC_ALIASES_TABL_H_AUT = "Автор" +DOC_ALIASES_TABL_CHECK = "Маркирай този пункт за изтриване" +DOC_ALIASES_GO = "Премени по линка" +DOC_ALIASES_DEL_T = "Изтриване на алиас" +DOC_ALIASES_DEL_C = "Сигурни ли сте, че желаете да изтриете алиаса?" +DOC_ALIASES_BUTT_DEL = "изтрий" +DOC_ALIASES_BUTT_CLO = "Затвори прозореца" +DOC_ALIASES_BUTT_APP = "Приложи" +DOC_ALIASES_BUTT_CNL = "Отмени" +DOC_ALIASES_BUTT_SAV = "Запази" +DOC_ALIASES_BUTT_ADD = "Добави" +DOC_ALIASES_REP_OK = "Изпълнено" +DOC_ALIASES_REP_OK_T = "Редиректът е успешно добавен" +DOC_ALIASES_REP_OK_T_E = "Редиректът е успешно обновен" +DOC_ALIASES_REP_ER = "Грешка" +DOC_ALIASES_REP_ER_T = "Редиректът не е добавен. Пробвайте отново." +DOC_ALIASES_REP_ER_T_E = "Редиректът не е обновен. Пробвайте отново." + +DOC_RUBRIC_TMPLS = "Избери шаблон на рубрика" +DOC_RUBRIC_TMPLS_HINT = "Може да зададете на документа, всеки шаблон от рубриката" + +DOC_SEARCH_FIELD = "Изберете поле" +DOC_SEARCH_FIELD_LIKE = "Съдържа" +DOC_SEARCH_FIELD_EQ = "Равно на" +DOC_SEARCH_FIELD_TEXT = "Стойност" +DOC_TEMPLATE_DEFAULT = "Използвай по подразбиране" +DOC_SHOW_LANG = "Покажи" + +// 3.2 +DOC_TABS_META = "Meta данни" +DOC_TABS_URL = "URL на документа" +DOC_TABS_DATE = "Дата на публикация" +DOC_TABS_OTHER = "Други параметри" + +DOC_WITHOUT_TITLE = "Документ без наименование" +DOC_SAVE_ADD = "Добавил" +DOC_SAVE_EDIT = "Редактирал" +DOC_SAVE_LOG_DOC = " документ" + +DOC_LANG = "Език" +DOC_LANG_ID = "Език на документа:" +DOC_LANG_SELECT = "Изберете език" + +// 3.25 +DOC_CLOSE_SEARCH_RUBRIC = "Върни се в раздела, според параметрите на търсенето" + +// 3.26 +DOC_POSITION = "Позиция" +DOCUMENT_POSITION = "Позиция на документа" +DOCUMENT_POSITION_ERR = "Неуспешен запис на позицията на документа" +DOCUMENT_POSITION_ERROR = "Грешка" +DOCUMENT_POSITION_OK = "Позицията на документа е успешно записана" +DOCUMENT_POSITION_SUCCESS = "Выполнено" + +DOC_SEARCH_PARAM = "Параметър на документа" +DOC_SEARCH_PARAM_SELECT = "Изберете параметър" +DOC_SEARCH_PARAM_LIKE = "Съдържа" +DOC_SEARCH_PARAM_EQ = "Равно" +DOC_SEARCH_PARAM_TEXT = "Значение" diff --git a/admin/lang/bg/groups.txt b/admin/lang/bg/groups.txt new file mode 100644 index 0000000..a8741f3 --- /dev/null +++ b/admin/lang/bg/groups.txt @@ -0,0 +1,125 @@ +# npop 04,2017 Neli Popova, npop@abv.bg +[groups] +UGROUP_TITLE = "Управление на групите потребители" +UGROUP_TITLE2 = "Управление правата за достъп на група" +UGROUP_TITLE_MENU = "Групи потребители" +UGROUP_INFO = "В този раздел са всички потребителе в системата. За всяка група Вие може да определите персонални права, които разрешават или ограничават действията на потребителите както в Панела за управление, така и в Публичната част на сайта." +UGROUP_ID = "ID" +UGROUP_NAME = "Наименование" +UGROUP_COUNT = "В групата" +UGROUP_ACTIONS = "Действия" +UGROUP_IN_GROUP = "Преглед на списъка на потребителите, отнасящи се към дадената група" +UGROUP_EDIT = "Редактиране правата на групата" +UGROUP_NO_PERMISSION = "Извинете, Вие нямате права за редактиране" +UGROUP_DELETE = "Изтриване на текущата група" +UGROUP_USERS_IN_GROUP = "В момента Вие не може да изтриете дадената група. т.к. в нея има въведени потребители." +UGROUP_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете тази група?" +UGROUP_NO_DELETABLE = "Вие не може да изтриете дадената група, т.к. е системна." +UGROUP_NO_PERM_DELETE = "Извинете, но Вие нямате права за изтриване на група." +UGROUP_NEW_GROUP = "Добавяне на нова група" +UGROUP_NEW_NAME = "Наименование на групата:" +UGROUP_BUTTON_ADD = "Добавяне" +UGROUP_LEGEND_LINK = "Легенда" +UGROUP_LEGEND_EDIT = "Редактиране правата на групата" +UGROUP_LEGEND_DELETE = "Изтриване на група" +UGROUP_ENTER_NAME = "Моля, въведете наименованието на групата потребители" +UGROUP_WARNING_TIP = "Внимание! Бъдете крайно внимателни при определянето на правата за групите потребители. Помнете, че като разрешаване достъпа до някои раздели, може да доведе до уязвимост на системата." +UGROUP_YOUR_NOT_CHANGE = "Грешка! Извинете, но Вие нямате права за редактиране на групите потребители." +UGROUP_NOT_EXIST = "Грешка! Извинете, но такава група не съществува." +UGROUP_NO_MODULES = "Липсват инсталирани модули" +UGROUP_MODULES_RIGHT = "Моля, изберете модулите до които ще има достъп тази група потребители." +UGROUP_CONTROL_RIGHT = "Моля, изберете раздели от Административния панел за които ще бъде разрешен или ограничен достъпа за тази група потребители." +UGROUP_BUTTON_SAVE = "Запази промените" +UGROUP_BUTTON_SAVE_AJAX = "Приложи (CTRL+S)" +UGROUP_SAVE_CONFIRM = "Сигурни ли сте, че желаете да запишите правата за тази група потребители?" +UGROUP_NAME_EDIT = "Редактиране наименованието на групата" +UGROUP_OR = "или" +UGROUP_SAVED = "Правата за групата са успешно записани" +UGROUP_SAVED_ERR = "Неуспешно записване на правата за групата.
Пробвайте отново." +UGROUP_ERROR = "Грешка" +UGROUP_SUCCESS = "Изпълнено" +UGROUP_SAVE_MAIN = "Променил правата за достъп за групата" + +UGROUP_REPORT_ADD = "Създал група потребители" +UGROUP_REPORT_DEL = "Изтрил група потребители" + +alles = "Разреши всички права (Бъдете много внимателни!)" +adminpanel = "Достъп в панела за управление" + +gen_settings = "Достъп за управлението на общите настройки на системата" +gen_settings_more = "Достъп за управлението на допълнителните настройки на системата" +gen_settings_countries = "Достъп за управлението на списъка с държави" +gen_settings_languages = "Достъп за управлението на езиците" +gen_settings_robots = "Достъп за редактиране на файла robots.txt" +gen_settings_fcustom = "Достъп за редактиране на файла func.custom.php" + +logs_view = "Достъп за преглед на системните съобщения" +logs_clear = "Достъп за изтриване на системните съобщения" + +db_actions = "Достъп за управление на базата данни (Резервно копиране, Възстановяване, Оптимизация)" + +modules_view = "Достъп до списъка с модули" +modules_admin = "Достъп до модули (Настройка, Управление, Използване)" +modules_system = "Достъп за управление на модулите (Изтриване, Инсталиране)" + +navigation_view = "Достъп до списъка с менюта за навигация" +navigation_edit = "Достъп за управление на менюта за навигация (Създаване, Редактиране, Изтриване)" + +remark_view = "Достъп до списъка с бележки" +remark_edit = "Достъп за управление на бележките към документите (Създаване, Редактиране, Изтриване)" + +document_php = "Достъп за използване на PHP код в документите (Бъдете много внимателни!)" +document_view = "Достъп до списъка с документи (правава за Достъп към докуметите зависят и се определят в настройките на Рубриките)" +document_revisions = "Достъп за изтриване на всички ревизии на документите" + +rubric_view = "Достъп за преглед на списъка с рубрики" +rubric_edit = "Достъп за управление на рубриките (Създаване, Редактиране, Изтриване)" +rubric_php = "Достъп за използване на PHP код в шаблоните на рубриките (Бъдете много внимателни!)" +rubric_perms = "Достъп за управление на Правата за достъп на документите на рубриките" +rubric_code = "Достъп до изпълнимия код за рубриките (Бъдете много внимателни!)" + +template_view = "Достъп до списъка със шаблони" +template_edit = "Достъп до упралението на шаблоните (Създаване, Редактиране, Изтриване)" +template_php = "Достъп за използване на PHP код в шаблоните (Бъдете много внимателни!)" + +request_view = "Достъп до списъка със заявките" +request_edit = "Достъп до управлението на заявките (Създаване, Редактиране, Изтриване)" +request_php = "Достъп за използване на PHP код в шаблоните на заявките (Бъдете много внимателни!)" + +blocks_view = "Достъп за преглед на списъка с визуални блокове" +blocks_edit = "Достъп за управление навизуални блокове (Създаване, Редактиране, Изтриване)" + +sysblocks_view = "Достъп за преглед на списъка със системните блокове" +sysblocks_edit = "Достъп за управление на системните блокове (Създаване, Редактиране, Изтриване)" + +user_view = "Достъп до списъка на потребителите" +user_edit = "Достъп за редактиране на параметрите на потребителите" +user_perms = "Достъп за управление на правата на потребителите" + +group_view = "Достъп за преглед списъка на групите потребители" +group_edit = "Достъп за управление на правата на групите потребители (Създаване, Редактиране, Изтриване)" + +mediapool_int = "Достъп до файловия мениджър" +mediapool_add = "Достъп за добавяне на нови файлове на сървъра (чрез файловия мениджър)" +mediapool_del = "Достъп за изтриване на файлове на съсръра (чрез файловия мениджър)" +mediapool_finder = "Достъп до Файловия мениджър (elFinder)" + +cache_clear = "Достъп за изтриване на кеша" +cache_thumb = "Достъп за изтриване на удалению thumbnail изображенията (thumbnail)" + +logs = "Системни съобщния" +cache = "Управление на кеша" +gen = "Системни настройки" +db = "База данни" +sysblocks = "Системни блокове" +rubric = "Рубрики" +document = "Документи" +modules = "Модули" +mediapool = "Файлови мениджъри" +navigation = "Навигация" +request = "Заявки" +template = "Шаблони" +remark = "Бележки към документите" +document = "Документи" +user = "Потребители" +group = "Групи потребители" \ No newline at end of file diff --git a/admin/lang/bg/logs.txt b/admin/lang/bg/logs.txt new file mode 100644 index 0000000..efd76e5 --- /dev/null +++ b/admin/lang/bg/logs.txt @@ -0,0 +1,54 @@ +# npop 04,2017 Neli Popova, npop@abv.bg +[logs] +LOGS_SUB_TITLE = "Управление на системните съобщения" +LOGS_TITLE = "Журнал системни събития" +LOGS_TIP = "В този раздел е списъка на всички действия, извършвани в Административния панел." +LOGS_ID = "№" +LOGS_IP = "Ip-адрес" +LOGS_DATE = "Дата" +LOGS_USER = "Потребител" +LOGS_ACTION = "Действие" +LOGS_BUTTON_DELETE = "Изтриване на системните съобщения" +LOGS_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете системните съобщения?" +LOGS_BUTTON_EXPORT = "Експорт на ситемните съобщения" +LOGS_BUTTON_EXPORT_404 = "Експорт на дневника с грешки 404" +LOGS_DATE_FORMAT = "%d.%m.%y г." +LOGS_DATE_FORMAT2 = "%H:%M" +LOGS_IN = "в" +LOGS_CLEAR = "Системните съобщения са успешно изтрити." +LOGS_CLEAN = "Изтрил системните съобщения" +LOGS_EXPORT = "Експортирал системните съобщения" + +LOGS_404_SUB_TITLE = "Дневник грешки 404" +LOGS_404_TITLE = "Дневник грешки 404" +LOGS_404_TIP = "В този раздел е списъка на всички грешки 404." +LOGS_404_ID = "№" +LOGS_404_IP = "Ip-адрес" +LOGS_404_DATE = "Дата" +LOGS_404_ACTION = "Действие" +LOGS_404_BUTTON_DELETE = "Изтриване на дневника" +LOGS_404_DELETE_CONFIRM = "Сисурнили сте, че желаете да изтриете дневника с грешки 404?" +LOGS_404_BUTTON_EXPORT = "Експорт на дневника с грешки" +LOGS_404_DATE_FORMAT = "%d.%m.%y г." +LOGS_404_DATE_FORMAT2 = "%H:%M" +LOGS_404_IN = "в" +LOGS_404_CLEAR = "Системните съобщения са успешно изтрити." +LOGS_404_CLEAN = "изтрил Дневника с грешки 404" +LOGS_404_EXPORT = "експортирал Дневника с грешки 404" + +LOGS_SQL_SUB_TITLE = "Дневник MySQL грешки" +LOGS_SQL_TITLE = "Дневник MySQL грешки" +LOGS_SQL_TIP = "Списък на всички MySQL грешки." +LOGS_SQL_ID = "№" +LOGS_SQL_IP = "Ip-адрес" +LOGS_SQL_DATE = "Дата" +LOGS_SQL_ACTION = "Действие" +LOGS_SQL_BUTTON_DELETE = "Изтриване на дневника с MySQL грешки" +LOGS_SQL_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете дневника с MySQL грешки?" +LOGS_SQL_BUTTON_EXPORT = "Експорт на дневника с MySQL грешки" +LOGS_SQL_DATE_FORMAT = "%d.%m.%y г." +LOGS_SQL_DATE_FORMAT2 = "%H:%M" +LOGS_SQL_IN = "в" +LOGS_SQL_CLEAR = "Дневника с MySQL грешки еуспешно изтрит." +LOGS_SQL_CLEAN = "Изтрил дневника с MySQL грешки" +LOGS_SQL_EXPORT = "Експортирал дневника с MySQL грешки" \ No newline at end of file diff --git a/admin/lang/bg/main.txt b/admin/lang/bg/main.txt new file mode 100644 index 0000000..20032ed --- /dev/null +++ b/admin/lang/bg/main.txt @@ -0,0 +1,305 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +MAIN_WELCOME = "Добре дошли в Панела за управление!" +MAIN_WELCOME_INFO = "На главната страница Вие може да изберете някое от най-често изпълняваните функции." + +MAIN_PAGE = "Начална страница" + +MAIN_LOGIN_INTRO = "Вход в системата" +MAIN_LOGIN_BACK_SITE = "Обратно към сайта" +MAIN_LOGIN_NAME = "Потребител" +MAIN_LOGIN_PASSWORD = "Парола" +MAIN_LOGIN_BUTTON = "Вход" +MAIN_LOGIN_REGISTER = "Регистрация" +MAIN_LOGIN_LOST = "Забравена парола?" +MAIN_LOGIN_HELP = "Помощ" +MAIN_LOGIN_REMEMBER = "Запомни ме" +MAIN_LOGIN_CAP_CODE = "Код:" +MAIN_LOGIN_CAP_CODE_REF = "Обновяване на кода:" +MAIN_LOGIN_CAP_CODE_REFR = "Обновяване на кода" + +MAIN_LINK_HOME = "Начало" +MAIN_LINK_AUTHOR = "Сайт за поддръжка" +MAIN_LINK_DATABASE = "База данни" +MAIN_LINK_NAVIGATION = "Навигация" +MAIN_LINK_MODULES = "Модули" +MAIN_LINK_MODULES_H = "Модули" +MAIN_LINK_SETTINGS = "Настройки" +MAIN_LINK_SETTINGS_H = "Настройки" +MAIN_LINK_USERS = "Потребители" +MAIN_LINK_TEMPLATES = "Шаблони" +MAIN_LINK_RUBRICS = "Рубрики" +MAIN_LINK_DOCUMENT = "Документи" +MAIN_LINK_QUERYES = "Заявки" +MAIN_LINK_GROUPS = "Групи потребители" +MAIN_LINK_LANG = "Езици" + +MAIN_BUTTON_LOGIN = "Вход" +MAIN_BUTTON_ADD = "Добави" +MAIN_BUTTON_LOGOUT = "Изход" + +MAIN_SETTINGS_EDIT_1 = "Общи настройки" +MAIN_SETTINGS_EDIT_2 = "Допълнителни настройки" +MAIN_SETTINGS_EDIT_3 = "Държави" +MAIN_SETTINGS_EDIT_4 = "Създай резервно копие на БД" + +MAIN_LINK_DOC_TIPS = "В този раздел е списъка на всички въведени в системата документи." +MAIN_LINK_RUBRIK_TIP = "В този раздел е списъка на всички съществуващи рубрики в системата." +MAIN_LINK_REQUEST_TIP = "В този раздел е списъка на всички съществуващи заявки в системата." +MAIN_LINK_NAVI_TIP = "В този раздел е списъка на всички менюта за навигация в системата." +MAIN_LINK_TEMPLATES_TIP = "В този раздел е списъка на всички шаблони, използвани в системата." +MAIN_LINK_MODULES_TIP = "В този раздел е списъка на всички достъпни/активни и неактивни/ модули в системата." +MAIN_LINK_SETTINGS_TIP = "В този раздел може да променяте/редактирате глобалните параметри на системата." +MAIN_LINK_DB_TIP = "В този раздел вие може да работите с базите данни на системата." +MAIN_LINK_USER_TIP = "В този раздел е списъка на всички потребители, въведени в системата." +MAIN_LINK_UGROUP_TIP = "В този раздел е списъка на всички групи потребители в системата." + +MAIN_PAGE_TITLE = "Административен панел" +MAIN_LOGIN_TEXT = "Вход в системата" +MAIN_LOGIN_TEXT2 = "Моля, въведете вашите данни:" +MAIN_LOGIN_CAPTCHA = "Въведете кода:" +MAIN_SELECT_LANGUAGE = "Език:" +MAIN_SELECT_THEME = "Шаблон:" +MAIN_YOUR_EMAIL = "Имейл:" +MAIN_YOUR_LOGIN = "Логин или имейл:" +MAIN_YOUR_PASSWORD = "Парола:" + +MAIN_LINK_SITE = "Преглед сайт" +MAIN_LINK_HOME = "Начало" +MAIN_LINK_LOGOUT = "Изход от админ панела" +MAIN_LINK_LOGOUT_QUEST = "Сигурни ли сте, че желаете да излезете?" +MAIN_LINK_CACHE_CLEAR = "Изтриване на кеша" +MAIN_LINK_CACHE_CLEAR_QUEST = "Сигурни ли сте, че желаете да изтриете кеша?" + +MAIN_LINK_SITE_ON = "С включен редактор" +MAIN_LINK_SITE_OFF = "Без редактор" + +MAIN_LINK_EDIT = "Редактиране на сайта" +MAIN_ADD_IN_RUB = "Добавяне на нов документ" +MAIN_DOCUMENTS_ALL = "Списък с документи" +MAIN_SEARCH_DOCUMENTS = "Търсене на документи" +MAIN_SORT_DOCUMENTS = "Филтър по рубрика" +MAIN_TIME_PERIOD = "Период на публикация" +MAIN_TIME_START = "Начало" +MAIN_TIME_END = "Край" +MAIN_BUTTON_SEARCH = "Търсене" +MAIN_TITLE_SEARCH = "Наименование документ" +MAIN_TITLE_DOC_NAME = "Наименование документ" +MAIN_TITLE_DOC_ID = "ID на документ" +MAIN_SEARCH_HELP = "Използване на търсенето

Използвайте знака "+" за задължтелно включване на думата в търсенето.
Използвайте знака "-" за изключване на дума от търсенето.

Задължително използвайте интервал преди знаците "+" и "-". " +MAIN_ID_SEARCH = "ID на документ" +MAIN_SELECT_RUBRIK = "В рубрика" +MAIN_ALL_RUBRUKS = "във всички рубрики" +MAIN_ALL_DOCUMENTS = "всички" +MAIN_DOCUMENT_STATUS = "Статус на документ" +MAIN_DOCUMENT_ACTIVE = "само активните" +MAIN_DOCUMENT_INACTIVE = "само неактивните" +MAIN_TEMP_DELETE_DOCS = "временно изтрити" +MAIN_RESULTS_ON_PAGE = "Резултати на стр." +MAIN_OPEN_MEDIAPATH = "Преглед на сървара" +MAIN_NAVI_UGROUPS = "Групи" +MAIN_UGROUP_EDIT = "Редактиране правата на групите" +MAIN_UGROUP_DELETE = "Изтриване на тази група" +MAIN_LOGS = "Логове" +MAIN_NAVI_MODULES = "Модули" +MAIN_NAVIGATION = "Навигация" +MAIN_NAVIGATION_NEW = "Добавяне на ново меню" +MAIN_QUERIES = "Заявки" +MAIN_REQUEST_NEW = "Добавяне на нова заявка" +MAIN_RUBRIKS = "Рубрики" +MAIN_RUBRIK_NEW = "Добавяне на нова рибрика" +MAIN_RUBRIK_EDIT_FIELDS = "Редактиране полетата на рубриката" +MAIN_RUBRIK_EDIT_TEMPL = "Редактиране шаблона на рубриката" +MAIN_SETTINGS = "Настройки" +MAIN_COUNTRY_EDIT = "Държави" +MAIN_SYSBLOCKS = "Системни блокове" +MAIN_TEMPLATES = "Шаблони" +MAIN_TEMPLATES_NEW = "Добавяне на нов шаблон" +MAIN_USERS = "Потребители" +MAIN_DATABASE_INFO = "База данни" +MAIN_NAVI_DOCUMENTS = "Документи" +MAIN_BROWSE_DOCUMENTS = "Преглед на документите" +MAIN_USERS_LIST = "Списък потребители" +MAIN_USER_ADD = "Добавяне на нов потребител" +MAIN_SEARCH_USERS = "Търсене на потребители по:" +MAIN_USER_PARAMS = "Име, Id, E-mail, E-mail домейн" +MAIN_USER_STATUS = "Със статус:" +MAIN_USER_STATUS_ALL = "Всички" +MAIN_USER_STATUS_ACTIVE = "Активен" +MAIN_USER_STATUS_INACTIVE = "Очакващ активация" +MAIN_USER_GROUP = "Принадлежи към група" +MAIN_USER_ONLINE = "Здравейте, " +MAIN_USER_PERM = "Статус:" +MAIN_ALL_USER_GROUP = "Във всяка" +MAIN_BUTTON_SEARCH_USER = "Намери потребител по параметри" +MAIN_NO_PERMISSION = "Извинете, но вие нямате права за достъп до дадения раздел" +MAIN_LOGOUT_CONFIRM = "Сигурни ли сте, че желаете да излезете?" + +MAIN_START_DOC_TITLE = "Последни документи" +MAIN_START_DOC_ID = "id" +MAIN_START_DOC_NAME = "Наименование" +MAIN_START_DOC_RUBRIC = "Рубрика" +MAIN_START_DOC_DATE = "Публикуван" +MAIN_START_DOC_AUTOR = "Автор" + +MAIN_START_SEARCH = "Търсене:" +MAIN_START_SEARCH_T = "Търсене на документ" + +MAIN_START_LOGS_LOG = "Дневник операции" +MAIN_START_LOGS_404 = "Грешки 404" +MAIN_START_LOGS_SQL = "Грешки MySQL" + +MAIN_TABLE_SUCC = "Брой успешно заредени таблици: " +MAIN_TABLE_ERROR = "Брой таблици с грешки: " +MAIN_SQL_FILE_ERROR = "SQL-файла има грешен формат или има грешки в структурата на заявката." +MAIN_RESTORE_OK = "Базата данни е успешно възстановена" + +MAIN_NO_PERM_MODULES = "Извинете, но вие нямате достатъчно права за да управлявате дадения модул" +MAIN_MP_FILE_DELETE = "Изтриване на файл" +MAIN_MP_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете файла: " +MAIN_MP_DOC_FOLDER = "Списък на папки/ файлове" +MAIN_MP_FILE_SIZE = "Размер на файла" +MAIN_MP_FILE_DATE = "Дата на създаване" +MAIN_MP_ACTIONS = "Действия" +MAIN_MP_FILE_INFO = "За да добавите файл, кликнете върху заглавието му, а след това на бутон Закачи файл" +MAIN_MP_UP_LEVEL = "Връщане на едно ниво нагоре" +MAIN_MP_CREATE_FOLDER = "Създаване на папка" +MAIN_MP_UPLOAD_FILE = "Зареждане на файл" +MAIN_MP_FILE_INSERT = "Закачи файл" +MAIN_MP_DIR_INSERT = "Избери папка" +MAIN_MP_SELECT_FILES = "Изберете файлове за зареждане" +MAIN_MP_IMAGE_RESIZE = "Промяна на размера на зарежданите изображения" +MAIN_MP_IMAGE_WIDTH = "Ширина" +MAIN_MP_IMAGE_HEIGHT = "Височина" +MAIN_BUTTON_UPLOAD = "Зареди" +MAIN_BUTTON_WAIT = "Моля, почакайте..." +MAIN_MP_PLEASE_SELECT = "Моля, изберете файл" +MAIN_ADD_IN = "Изберете рубрика:" +MAIN_GROUP_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете тази група?" +MAIN_RUBRIKS_LIST = "Списък на рубриките" +MAIN_USER = "Потребител" +ButtonSave = "Запиши" +MAIN_NEW_PAGE = "Добави нова страница" +MAIN_BUTTON_SORT = "Филтър" +MAIN_QUICK_MODULE = "Управление на модули" +MAIN_STAT = "Статистика" +MAIN_STAT_SYSTEM_INFO = "Системна информация" +MAIN_STAT_DOCUMENTS = "Общо документи" +MAIN_STAT_RUBRICS = "Общо рубрики" +MAIN_STAT_QUERIES = "Общо заявки" +MAIN_STAT_TEMPLATES = "Общо шаблони" +MAIN_STAT_MYSQL = "Размер на БД" +MAIN_STAT_CACHE = "Общ размер на кеша" +MAIN_STAT_CACHE_SHOW = "Покажи" +MAIN_STAT_MODULES = "Инсталирани модули:" +MAIN_STAT_MODULES_OFF = "Деинсталирани модули:" +MAIN_STAT_USERS = "Всичко потребители:" +MAIN_STAT_USERS_WAIT = "Очакващи активация:" +MAIN_STAT_AVE = "ILEN.cms" +MAIN_STAT_DOMEN = "Домейн" +MAIN_STAT_PHP = "PHP версия:" +MAIN_STAT_MYSQL_VERSION = "MySQL версия:" +MAIN_STAT_CLEAR_CACHE = "Изтриване на кеша" +MAIN_STAT_CLEAR_CACHE_FULL= "Изтриване на кеша и сесиите" +MAIN_STAT_CLEAR_THUMB = "Изтриване на миниатюрите" +MAIN_STAT_CLEAR_REV = "Изтриване на ревизиите" +MAIN_STAT_CLEAR_COUNT = "Зануляване на дневния брояч" +MAIN_ADD_FOLDER = "Моля, въведете наименование на новата папка:" +MAIN_NO_ADD_FOLDER = "Не е въведено наименование на папка или действието е отменено!" +MAIN_NO_ADD_TEMPL = "Не е въведено наименование на шаблон или действието е отменено!" +MAIN_NO_ADD_GROUP = "Не е въведено наименование на група или действието е отменено!" +MAIN_NO_ADD_RUB = "Не е въведено наименование на рубрика или действието е отменено!" +MAIN_NO_ADD_QUERY = "Не е въведено наименование на заявка или действието е отменено!" +MAIN_NO_ADD_NAV = "Не е въведено наименование на меню или действието е отменено!" +MAIN_NO_ADD_BLOCK = "Не е въведено наименование на системния блок или действието е отменено!" +MAIN_NO_ADD_USER = "Не е въведено име на потребител или действието е отменено!" +MAIN_NO_ADD_DOCS = "Не е въведено наименование на документа или действието е отменено!" +MAIN_CLEAR_CACHE_OK = "Кешът е изтрит" +MAIN_FILE_MANAGER_TITLE = "Файлов мениджър" +MAIN_FILE_MANAGER_TIP = "Изберете необходимия файл и натиснете бутона "Вмъкни файл"" + +MAIN_SVN_NEW = "Излезе нова версия" +MAIN_SVN_SAIT = "Премини към сайта" +MAIN_SVN_REPOS = "Премини към сайт репозиторий" +MAIN_SVN_MAILTO = "Напиши писмо" +MAIN_SVN_LOOK = "Преглед на ревизията на сайт репозиторий" +MAIN_SVN_RECOM = "Препоръчва се обновяване!" + +MAIN_FINDER = "Файлов мениджър" + +MAIN_ADD_NEW_GROUP = "Добави нова група" +MAIN_ADD_NEW_GROUP_NAME = "Наименование на група" + +MAIN_ADD_NEW_USER = "Добави нов потребител" +MAIN_ADD_NEW_USER_NAME = "Име на потребител:" + +MAIN_ADD_NEW_NAV = "Добави ново меню за навигация" +MAIN_ADD_NEW_NAV_NAME = "Наименование меню за навигация:" + +MAIN_ADD_NEW_TEMPL = "Добави нов шаблон" +MAIN_ADD_NEW_TEMPL_NAME = "Наименование на шаблона:" + +MAIN_ADD_NEW_REQUEST = "Добави нова заявка" +MAIN_ADD_NEW_REQUEST_NAME = "Наименование на заявката:" + +MAIN_ADD_NEW_RUB = "Добави нова рубрика" +MAIN_ADD_NEW_RUB_NAME = "Наименование на рубриката:" + +MAIN_ADD_NEW_BLOCK = "Добави нов системен блок" +MAIN_ADD_NEW_BLOCK_NAME = "Наименование на системния блок:" + +MAIN_USERS_LAST_TIME = "За последен път:" + +MAIN_LOGS_ID = "№" +MAIN_LOGS_IP = "Ip-адрес" +MAIN_LOGS_DATE = "Дата" +MAIN_LOGS_USER = "Потребител" +MAIN_LOGS_ACTION = "Действие" + +MAIN_DOC_SHOW3_TITLE = "Документ без наименование" +MAIN_DOC_EDIT_TITLE = "Редактиране на този документ" +MAIN_DOC_SHOW_TITLE = "Преглед на документа (линк без ЧПУ)" +MAIN_DOC_SHOW2_TITLE = "Преглед на документа (линк c ЧПУ)" + +MAIN_ADD_DOC = "Документ" +MAIN_ADD_RUB = "Рубрика" +MAIN_ADD_REQ = "Заявка" +MAIN_ADD_SYS = "Системен блок" +MAIN_ADD_TEM = "Шаблон" +MAIN_ADD_NAV = "Навигация" +MAIN_ADD_USR = "Потребител" +MAIN_ADD_GRP = "Група" + +MAIN_BRANCHES = "Раздели" +MAIN_SHOWHIDE = "Покажи/Скрий меню" + +MAIN_CODEMIRROR_HELP = "Ctrl-F/Cmd-F (Търси) | Ctrl-G/Cmd-G (Търси следващ) | Shift-Ctrl-G/Shift-Cmd-G (Търси предходен) | Shift-Ctrl-F/Cmd-Option-F (Замени) | Shift-Ctrl-R / Shift-Cmd-Option-F (Замени всички) | F11 (На цял екран)" + +TEMPLATES_MESSAGE = "Съобщение:" +TEMPLATES_CACHE_SUCCESS = "Кешът е успешно изтрит." +TEMPLATES_CACHE_SUCCESS_LOG = "Изтрил кеша" +TEMPLATES_CACHE_DB_SUCCESS = "Таблицата _sessions е успешно изчистена." +TEMPLATES_CACHE_DB_SUCCESS_LOG = "Изчистил таблицата _sessions." +TEMPLATES_CACHE_CT_SUCCESS = "Изтрити са компилираните шаблони." +TEMPLATES_CACHE_CT_SUCCESS_LOG = "Изтрил компилираните шаблони" +TEMPLATES_CACHE_MC_SUCCESS = "изтрити компилираните шаблони на модулите." +TEMPLATES_CACHE_MC_SUCCESS_LOG = "Изтрил компилираните шаблони на модулите" +TEMPLATES_CACHE_SU_SUCCESS = "Изтрити сесии на потребителите." +TEMPLATES_CACHE_SU_SUCCESS_LOG = "Изтрил сесиите на потребителите" +TEMPLATES_CACHE_SC_SUCCESS = "Изтрит кеш на sql заявките." +TEMPLATES_CACHE_SC_SUCCESS_LOG = "Изтрил кеш на sql заявките." +TEMPLATES_THUMBNAILS_SUCCESS = "Миниатюрите са успешно изтрити." +TEMPLATES_THUMBNAILS_SUCCESS_LOG = "Изтрил миниатюрите" + +EXIT_ADMIN = "Завършил сесия в Административния панел" +LOGIN_ADMIN = "Започнал сесия в Административния панел" +ERROR_ADMIN = "Грешка при вход в Административния панел" + +WRONG_PASS = "Грешка:
Грешно потребителско име или парола!" +WRONG_CAPTCHA = "Грешка:
Грешен защитен код" + +oficial_site = "Официален сайт" +support = "Техническо обслужване" + +// 3.1.9 +MAIN_BLOCKS = "Визуални блокове" \ No newline at end of file diff --git a/admin/lang/bg/modules.txt b/admin/lang/bg/modules.txt new file mode 100644 index 0000000..11b8be5 --- /dev/null +++ b/admin/lang/bg/modules.txt @@ -0,0 +1,37 @@ +# npop 04,2017 Neli Popova, npop@abv.bg +[modules] +MODULES_SUB_TITLE = "Управление на модулите" +MODULES_TIP = "В този раздел може да инсталирате, деинсталирате или обновявате модулите, както и да редактирате спесифичните им настройки." +MODULES_NAME = "Наименование на модула" +MODULES_INFO = "Информация" +MODULES_TEMPLATE = "Шаблон за изход" +MODULES_SYSTEM_TAG = "Системен таг" +MODULES_VERSION = "Версия" +MODULES_ACTIONS = "Действия" +MODULES_SETTINGS = "Параметри" +MODULES_SETTINGS_INFO = "Информация" +MODULES_DELETE = "Изтриване на модул" +MODULES_DELETE_CONFIRM = "Модулът се изтрива само на програмно ниво. В последствие може да бъде инсталиран.

Сигурни ли сте, че желаете да изтриете този модул?" +MODULES_INSTALL = "Инсталиране на модул" +MODULES_REMOVE = "Изтриване на модула от сървъра" +MODULES_REINSTALL = "Преинсталиране на модула" +MODULES_REINSTALL_CONF = "Сигурни ли сте, че желаете да преинсталирате този модул?" +MODULES_UPDATE = "Обновяване на модула" +MODULES_STOP = "Спиране на модула" +MODULES_START = "Стартиране на модула" +MODULES_BUTTON_SAVE = "Запазване на промените" +MODULES_LEGEND = "Легенда" +MODULES_AUTHOR = "Автор на модула" +MODULES_ERROR = "Възникна грешка при зареждане на модула " +MODULES_INSTALLED = "Инсталирани модули" +MODULES_NOT_INSTALLED = "Неинсталирани модули" +MODULES_SETUP = "Премини към управлението на модула" +MODULES_NO_INSTALL = "Съобщение:
Липсват инсталирани модули." +MODULES_NOT_INSTALL = "Сообщение:
Липсват неинсталирани модули." +MODULES_ACTION_INSTALL = "е инсталирал модул" +MODULES_ACTION_ONLINE = "е стартирал модул" +MODULES_ACTION_OFFLINE = "е спрял модул" +MODULES_ACTION_REINSTALL = "е преинсталирал модул" +MODULES_ACTION_UPDATE = "е обновил модул" +MODULES_ACTION_DELETE = "е изтрил модула от системата" +MODULES_ACTION_REMOVE = "е изтрил модула от сървъра" \ No newline at end of file diff --git a/admin/lang/bg/navigation.txt b/admin/lang/bg/navigation.txt new file mode 100644 index 0000000..306a7bb --- /dev/null +++ b/admin/lang/bg/navigation.txt @@ -0,0 +1,132 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +[navi] +NAVI_ID = "ID" +NAVI_SUB_TITLE = "Управление менюта за навигация" +NAVI_SUB_TITLE2 = "Управление на редовете в менюто" +NAVI_SUB_TITLE3 = "Редактиране шаблон на меню" +NAVI_SUB_TITLE4 = "Създаване на нов шаблон за менюто" +NAVI_TIP_TEMPLATE = "В този раздел са всички менюта в системата. Тук Вие може да измените шаблона за всяко меню, както и да изтриете или добавите нови редове." +NAVI_TIP_TEMPLATE2 = "В този раздел, като използвате HTML, Вие може да създадете шаблон за това меню навигация. Също така може да изберете групите потребители, които ще имат достъп към даденото меню. За избор на няколко групи натиснете клавиша CTRL." +NAVI_ITEMS_TIP = "Добавяне на нов ред в менюто" +NAVI_NEW_MENU = "Създаване на ново меню" +NAVI_LIST_TIP = "Списъка съдържа всички редове от даденото меню. Помнете, че максималното ниво на вложеност не може да бъде по-голямо от 2." +NAVI_LIST = "Списък на редовете на менюто" +NAVI_EDIT_TEMPLATE = "Редактиране шаблона на менюто" +NAVI_EDIT_ITEMS = "Редактиране пунктовете на менюто" +NAVI_OPEN_IN_THIS = "в текущия прозорец" +NAVI_OPEN_IN_NEW = "в нов прозорец" +NAVI_TARGET_WINDOW = "Отваряне" +NAVI_POSITION = "Позиция" +NAVI_LINK_TO_DOCUMENT = "Линк към документ/файл" +NAVI_ENTRIES_NO_ITEMS = "Съобщение:
В момента липсват редове в менюто." + +NAVI_LINK_TITLE = "Наименование ред от менюто" +NAVI_LINK_SOLUT = "Описание за реда" +NAVI_LINK_IMGID = "Id изображение" +NAVI_LINK_IMGTL = "Избери изображение" +NAVI_LINK_IMAGE = "Изображение за реда" +NAVI_TITLE = "Наименование" +NAVI_TITLE2 = "Наименование на менюто" +NAVI_BROWSE_DOCUMENTS = "Свързване със съществуващи документи" +NAVI_ADD_SUBITEM = "Добави нов подпункт" +NAVI_BUTTON_CHANGE = "Избери" +NAVI_BUTTON_OPTION = "Опции" +NAVI_BUTTON_SUBITEM = "+" +NAVI_BROWSE_MEDIAPOOL = "Свързване с файл на сървара" +NAVI_SYSTEM_TAG = "Системен таг" +NAVI_NAME = "Наименование на менюто" +NAVI_LINK_TARGET = "Таг, определящ начина на отваряне на документа ( в нов или в текущия прозорец )" +NAVI_LINK_URL = "Таг, определящ адреса за преход" +NAVI_LINK_NAME = "Таг, определящ наименованието на линковете, които ще бъдат показвани в менюто" +NAVI_LINK_ID = "Таг, определящ уникалния идентификатор на линка" +NAVI_LINK_INACTIVE = "Шаблон неактивен линк" +NAVI_LINK_ACTIVE = "Шаблон активен линк" +NAVI_HEADER_START = "Горна част шаблон" +NAVI_FOOTER_END = "Долна част шаблон" +NAVI_HEADER_TIP = "Например, заглавие "Каталог на стоки" (незадължително)" +NAVI_COPY_TEMPLATE = "Копиране шаблона на менюто" +NAVI_FOOTER_TIP = "Долна част шаблон (незадължително)" +NAVI_DELETE = "Изтриване на менюто" +NAVI_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете това меню?" +NAVI_HTML_START = "Начален HTML код" +NAVI_HTML_END = "Краен HTML код" +NAVI_LEVEL1 = "Шаблон за главното(първо) ниво на менюто" +NAVI_LEVEL2 = "Шаблон за първото от вложените нива на менюто" +NAVI_LEVEL3 = "Шаблон за второто от вложените нива на менюто" +NAVI_MARK_DELETE = "Маркирай този ред за изтриване" +NAVI_MARK_ACTIVE = "За да забраните временно даден ред от менюто, махнете маркера и натиснете "Запази промените"" +NAVI_GROUPS = "Групи потребители за които менюто ще е достъпно" +NAVI_ACTIONS = "Действия" +NAVI_OR_BUTTON = " или " +NAVI_BUTTON_SAVE = "Запази промените" +NAVI_BUTTON_SAVE_NEXT = "Запази и продължи редактирането (CTRL+S)" +NAVI_BUTTON_ADD = "Добави ред" +NAVI_BUTTON_ADD_MENU = "Създаване на меню" +NAVI_LEGEND = "Легенда" +NAVI_ENTER_NAME = "Моля, въведете наименованието на менюто за навигация." +NAVI_ALL = "Списък на менютата за навигация" +NAVI_PRINT_TYPE = "Тип на извеждане" +NAVI_EXPAND_ALL = "FULL EXPAND (разкриване на всички нива)" +NAVI_EXPAND_WAY = "Текущо и родителско ниво" +NAVI_EXPAND_LEVEL = "Само текущото ниво" +NAVI_MENU_NOT_FOUND = "Липсва меню id=" +NAVI_SAVE = "Шаблонът на менюто за навигации е успешно съхранен" +NAVI_SORTED = "Подреждането е успешно запазено" + +NAVI_REPORT_NEW = "Създал меню за навигация" +NAVI_REPORT_COPY = "Създал копие на меню за навигация" +NAVI_REPORT_EDIT = "Изменил шаблон меню за навигацияи" +NAVI_REPORT_DEL = "Изтрил меню за навигация" +NAVI_REPORT_ADDIT = "Добавил ред в меню за навигация" +NAVI_REPORT_DELIT = "Изтрил ред в меню за навигация" +NAVI_REPORT_FLEV = "на перво ниво" +NAVI_REPORT_SLEV = "на второ ниво" +NAVI_REPORT_TLEV = "на трето ниво" +NAVI_REPORT_DEACT = "Деактивирал ред в меню за навигация" +NAVI_REPORT_ACT = "Активирал ред в меню за навигация" +NAVI_REPORT_SAVED = "Шаблон на менюто за навигацията е успешно записан" +NAVI_REPORT_SAVED_ERR = "Неуспешно записване на шаблона за навигация.
Пробвайте отново." +NAVI_REPORT_ERROR = "Грешка" +NAVI_REPORT_SUCCESS = "Изпълнено" + +NAVI_ITEM_ON_OFF = "Вкл/Изкл пункт в меню" +NAVI_ITEM_EDIT = "Редактиране пункт в менюто" +NAVI_ITEM_DELETE = "Изтриване на пункта в менюто" +NAVI_ITEM_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете този пункт в менюто?" + +// v 3.2 +NAVI_ALIAS = "Алиас" +NAVI_I = "Опционално. Алиасът позволява да се използва лесно запомнящсе таг [tag:sysblock:alias] вместо [tag:sysblock:id]. Алиасът не може да бъде чосло, може да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа и трябва да бъде уникален в пределите на модула." +NAVI_ACCEPT = "Този алиас можр да се използва" +NAVI_ER_SYN = "Грешен алиас!
Алиасът не трябва да е число, да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа" +NAVI_ER_EXISTS = "Грешен алиас!
Този алиас вече е използван в друга контактна форма" + +//from templates +NAVI_NOLINK_DOC = "Липсва свързан документ" +NAVI_EDIT_ITEM = "Редактиране на реда в менюто" +NAVI_LINK_FILEDOC = "Свържи с документ/файл" +NAVI_LINKED_DOC = "Свързан документ" +NAVI_DEL_LINKED_DOC = "Убрать связь с документом" +NAVI_LINK_DOC = "Свържи с документ" +NAVI_LINK_FILE = "Свържи с файл" +NAVI_NO_LINK = "Липсва свързан документ" +NAVI_STRUCTURE = "Структура" +NAVI_RETURN_TO_LIST = "Връщане към списъка" +NAVI_EDIT_TEMPLATE = "Редактиране на шаблон" +NAVI_ITEM_ADD = "Добави ред в менюто" +NAVI_OPEN_ALL = "Покажи всички" +NAVI_CLOSE_ALL = "Скрий всички" +NAVI_ITEM_DESCR = "Описание на реда в менюто" +NAVI_ITEM_IMAGE = "Изображение" +NAVI_ITEM_IMAGE_DESCR = "Активно изображение, наименованието трябва да завършва на _act" +NAVI_ITEM_IMAGE_ID = "Id на изображение" +NAVI_PLACE_INSERT = "Място за вмъкване на поднивото" +NAVI_EXAMPLE = "Пример" +NAVI_ITEM_EVEN = "четен" +NAVI_ITEM_ODD = "нечетен" +NAVI_TAG = "Таг за вмъкване на редовете" +NAVI_LAVEL_TEMPL = "Шаблон на нивото" +NAVI_CONDITIONS = "Условия" +NAVI_CLOSE = "Затвори" +NAVI_ADD_AFTER = "Добави след" \ No newline at end of file diff --git a/admin/lang/bg/request.txt b/admin/lang/bg/request.txt new file mode 100644 index 0000000..53ffc5c --- /dev/null +++ b/admin/lang/bg/request.txt @@ -0,0 +1,205 @@ +# npop 04,2017 Neli Popova, npop@abv.bg +[request] +REQUEST_ID = "ID" +REQUEST_DELETE = "Изтриване заявка" +REQUEST_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете тази заявка?" +REQUEST_TITLE = "Управление на заявките" +REQUEST_NAME = "Наименование на заявката" +REQUEST_NAME2 = "Наименование на заявка:" +REQUEST_NAME3 = "Наименование" +REQUEST_CACHE = "Кеширане" +REQUEST_CACHE_ELEMENTS = "Кеширане на елементите на заявката" +REQUEST_SETTINGS = "Параметри на заявката" +REQUEST_TIP = "В този раздел са всички заявки в системата. За да използвате заявката включете "Системния таг" на нужното място във вашия шаблон или документ." +REQUEST_EDIT_TIP = "В този раздел може да редактирате заявката, да промените рубриката, шаблона за изход, а също така и условията на заявката." +REQUEST_NEW = "Създаване на нова заявка" +REQUEST_EDIT = "Редактиране на заявката" +REQUEST_EDIT2 = "Редактиране на заявка" +REQUEST_SYSTEM_TAG = "Системен таг" +REQUEST_AUTHOR = "Автор" +REQUEST_DATE_CREATE = "Дата на създаване" +REQUEST_ACTIONS = "Действия" +REQUEST_NO_DESCRIPTION = "Заявка без описание" +REQUEST_NO_REQUST = "Липсват заявки." +REQUEST_DATE_FORMAT = "%d.%m.%y г." +REQUEST_DATE_FORMAT2 = "%d.%m.%y г. в %H:%M" +REQUEST_IN = "в" +REQUEST_COPY = "Копиране на заявка" +REQUEST_COPY_FAILED = "Неуспешно копиране на заявката" +REQUEST_PLEASE_NAME = "Моля, въведете наименование за копираната заявка" +REQUEST_CONDITION_EDIT = "Условия за заявка" +REQUEST_CONDITION_IF = "Условия" +REQUEST_PLEASE_SELECT = "Моля, изберете рубрика" +REQUEST_SELECT_RUBRIK = "Изберете рубрика:" +REQUEST_SELECT_INFO = "Сигурни ли сте, че желаете да промените рубриката" +REQUEST_NEW_TIP = "Внимание! Преди да създадете нова заявка Вие трябва да изберете рубриката, от която ще се извеждат и филтрират документи." +REQUEST_DESCRIPTION = "Описание на заявката" +REQUEST_INTERNAL_INFO = "(използва се във системата)" +REQUEST_BUTTON_COND = "Добави/Промени" +REQUEST_CONDITION = "Условия на заявката" +REQUEST_ACTION_AFTER = "Върни се към редактирането на заявката след създаването, за да въведете условията на заявката." +REQUEST_SORT_BY = "Сортиране по параметър на документа:" +REQUEST_SORT_BY_NAT = "Сортиране по поле на документа:" +REQUEST_ASC_DESC = "В ред:" +REQUEST_DESC = "низходящ" +REQUEST_ASC = "възходящ" +REQUEST_BY_DATE = "Дата на създаване (публикация)" +REQUEST_BY_DATECHANGE = "Дата на променя (на документа)" +REQUEST_BY_NAME = "Наименование на документа" +REQUEST_BY_EDIT = "Име на автор" +REQUEST_BY_PRINTED = "Брой разпечатки" +REQUEST_BY_VIEWS = "Брой прегледи" +REQUEST_BY_RAND = "В случаен ред (високо натоварване)" +REQUEST_DOC_PER_PAGE = "Брой на страница" +REQUEST_DOC_PER_PAGE_ALL = "Извеждане на всички" +REQUEST_SHOW_NAVI = "Показване на навигация" +REQUEST_USE_LANG = "Само на езика на потребителя:" +REQUEST_USE_QUERY = "Исполване на GET заявки в навигацията по страници" +REQUEST_TEMPLATE_QUERY = "Основен шаблон на заявката" +REQUEST_MAIN_CONTENT = "Системен таг, отговарящ за извеждане елементите на заявката, указани в поле "Елементи на заявката"" +REQUEST_DOC_COUNT = "Системен таг, отговарящ за извеждане брой елементи на заявката" +REQUEST_DOCITEMNUM_INFO= "Системен таг, отговарящ за извеждане поредния номер на елемента на заявката" +REQUEST_MAIN_NAVI = "Системен таг, отговарящ за извеждане на постранична навигация за заявката (< 1 2 3 >)" +REQUEST_MEDIAPATH = "Системен таг, определящ пътя до папката с шаблоните (Например: [tag:mediapath]images/logo.gif)" +REQUEST_PATH = "Системен таг, определящ корена на инсталацията" +REQUEST_DOCDB = "Системен таг за извеждане на поле от документа от БД" +REQUEST_LANGFILE = "Системен таг за извеждане на езикова променлива от файла" +REQUEST_LANGUAGE = "Таг за зареждане на езиковитв файлове. Препоръчително е да се указва тагът, преди основния шаблон." +REQUEST_LANG = "Съдържанието ще бъде показано, ако езикът на документа съвпада с указания." + +REQUEST_TEMPLATE_ITEMS = "Шаблон за оформление на елементите на заявката" +REQUEST_TEMPLATE_INFO = "В това поле, като използвате HTML-код, Вие може да определите начина на оформление на вътрешните елементи на заявката (Например, оформление списъка с новините). Всички елементи, оформени според дадения шаблон, ще се изобразяват циклично в "Основния паблон" на заявката, според условията на заявката." +REQUEST_TEMPLATE_SAVED = "Заявката е съхранена успешно" +REQUEST_SELECT_IN_LIST = "Моля, изберете поле от рубриката от списъка по-долу." +REQUEST_RUB_INFO = "Системен таг, отговарящ за изход на съдържанието на полето от рубриката. ID-номер на поле. ХХХ-брой символи за изобразяване." +REQUEST_LINK_INFO = "Системен таг, определящ линка към документа. Например, < a href="[tag:link]">Линк < /a >" +REQUEST_RUBRIK_FIELD = "Системен таг на полето" +REQUEST_THUMBNAIL = "Таг, отговарящ за създаването на миниатюра(thumbail)(При условие,че в шаблона за полето в рубриката(шаблон за заявка) е избрано за извеждане: [tag:parametr:0])" +REQUEST_FIELD_NAME = "Наименование на полето" +REQUEST_FIELD_TYPE = "Тип на полето" +REQUEST_FIELD_G_UNKNOW = "Без група" + +REQUEST_BUTTON_ADD = "Създай заявка" +REQUEST_BUTTON_ADD_NEXT = "Създай и продължи редактирането" +REQUEST_BUTTON_SAVE = "Запиши промените" +REQUEST_BUTTON_SAVE_NEXT = "Приложи (CTRL+S)" +REQUEST_BUTTON_CLOSE = "Затвори прозореца" + +REQUEST_INSERT_INFO = "Натиснете върху системния таг, за да го добавите в шаблона" +REQUEST_CONDITIONS = "Управление условията на заявката" +REQUEST_CONDITION_TIP = "В този раздел Вие можа да определяте специални условия за избор на данни за заявката. Условията за заявкара позволяват точно да се определи избора на данни по определени параметри." +REQUEST_NEW_CONDITION = "Добави ново условие" +REQUEST_FROM_FILED = "Избери от поле" +REQUEST_OPERATOR = "Където значението" +REQUEST_VALUE = "Значение" +REQUEST_COND_SELF = "Равно" +REQUEST_COND_NOSELF = "Различно" +REQUEST_COND_USE = "Съдържа значение" +REQUEST_COND_NOTUSE = "Не съдържа значение" +REQUEST_COND_START = "Започва с" +REQUEST_SMALL1 = "По малко или равно" +REQUEST_BIG1 = "По голямо или равно" +REQUEST_SMALL2 = "По малко" +REQUEST_BIG2 = "По голямо" +REQUEST_N_COND_SELF = "Число равно" +REQUEST_N_SMALL1 = "Число по малко или равно" +REQUEST_N_BIG1 = "Число по голямо или равно" +REQUEST_N_SMALL2 = "Число по малко" +REQUEST_N_BIG2 = "Число по голямо" +REQUEST_SEGMENT = "Принадлежи отрезку (разделени с ,)" +REQUEST_INTERVAL = "Принадлежи на интервала (разделени с ,)" +REQUEST_IN = "В списъка (разделени с ,)" +REQUEST_NOTIN = "Не е в списъка(разделени с ,)" +REQUEST_ANY_NUM = "ОПАСНО!!! Число в заявка" +REQUEST_FREE = "ОПАСНО!!! Произволно условие [field]={Значение}" +REQUEST_MARK_DELETE = "Маркирай условието за изтриване" +REQUEST_CONR_AND = "И" +REQUEST_CONR_OR = "ИЛИ" +REQUEST_OR = " или " + +REQUEST_VIEWS_INFO = "Системен таг, извеждащ брой прегледи на документа" +REQUEST_COMMENTS_INFO = "Системен таг, извеждащ броя коментари към документа. Внимание! Работи само при инсталиран модул КОМЕНТАРИ!" +REQUEST_CONTROL_FIELD = "Системен таг, извеждащ панела ФИЛТЪР. Само за рубрики с полета тип падащ списък" +REQUEST_CONTROL_SORT = "Системен таг, извеждащ панела СОРТИРАНЕ по дата на публикация, наименование и брой прегледи на заявката" +REQUEST_NO_DROPDOWN = "В избраната рубрика липсват полета с тип падащ списък." +REQUEST_ENTER_NAME = "Моля, въведете наименование на заявката." +REQUEST_ALL = "Списък заявки" +REQUEST_IF_EMPTY = "Системен таг(pair), между които се въвежда шаблон за извеждане при отсъствие на резултат от заявката" +REQUEST_NOT_EMPTY = "Системен таг(pair), между които се въвежда шаблон за извеждане при наличие на резултати от заявката" +REQUEST_DOCID_INFO = "Системен таг за идентификатора на документа" +REQUEST_DOCTITLE_INFO = "Системен таг за наименованието на документа" +REQUEST_CDOCID_INFO = "Системен таг за идентификатора на текущия документ (в който се извежда заявката)" +REQUEST_DOCDATE_INFO = "Системен таг за датата на публикуване на документа" +REQUEST_CDOCDATE_INFO = "Системен таг за датата на публикуване на текущия документ (в който се извежда заявката)" +REQUEST_DOCTIME_INFO = "Системен таг за датата и часът на публикуване на документа" +REQUEST_CDOCTIME_INFO = "Системен таг за датата и часът на публикуване на текущия документ (в който се извежда заявката)" +REQUEST_DATE_INFO = "Системен таг за извеждане на дате и час на публикуване на документа - с избор на шаблон.
Пример: [tag:date:d.m.Y]
Може да се използват разделители (space - . /)" +REQUEST_CDATE_INFO = "Системен таг за извеждане на дате и час на публикуване на документа - с избор на шаблон.
Пример: [tag:date:d.m.Y]
(в който се извежда заявката)
Може да се използват разделители (space - . /)" +REQUEST_DOCAUTHOR_INFO = "Системен таг за автора на документа" +REQUEST_DOCAUTHOR_AVATAR = "Системен таг за аватара на автора на документа" +REQUEST_CDOCAUTHOR_INFO = "Системен таг за автора на текущия документ(в който се извежда заявката)" +REQUEST_SAMPLE = "Пример" +REQUEST_HIDE_CURRENT = "Не показвай в заявката текущия документ" +REQUEST_ONLY_OWNER = "Само СВОИТЕ документи" +REQUEST_CONDITION_JOIN = "Оператор" +REQUEST_CONDITION_SAVE = "Запази условията" +REQUEST_CONDITION_ADD = "Добави условие" + +REQUEST_SUCCESS = "Изпълнено" +REQUEST_ERROR = "Грешка" +REQUEST_CANCEL = "Отемени" + +REQUEST_SORTED = "Редът е успешно съхранен" +REQUEST_COND_MESSAGE = "Липсват условия за заявката" +REQUEST_COND_VALUE_ERR = "Празно поле Значение" +REQUEST_COND_NEW_ERR = "Неуспешно добавяне на условие
Опитайте отново" +REQUEST_COND_NEW_SUC = "Условието е успешно добавено" +REQUEST_COND_POST_OK = "Условията са успешно записани" +REQUEST_COND_POST_ERR = "Неуспешно съхраняване на условита за заявка
Опитайте отново" +REQUEST_COND_NO_POST = "Липсват данни за съхраняване
Опитайте отново" + +REQUEST_COND_ADD_SUC = "Добавил условия към заявката" +REQUEST_COND_CHA_SUC = "Променил условия към заявката" +REQUEST_COND_DEL_SUC = "Изтрил условия към заявката" +REQUEST_SAVE_CHA_SUC = "Редактирал заявката" +REQUEST_ADD_NEW_SUC = "Добавил нова заявка" +REQUEST_DELETE_SUC = "Изтрил заявка" +REQUEST_COPY_SUC = "Създал копие на заявката" + +REQUEST_HEADER_SELF = "Основни параметри на заявката" +REQUEST_HEADER_NAME = "Значение" +REQUEST_HEADER_PARAMETR = "Параметър" + +REQUEST_REPORT_ERR_TITLE = "Не е въведено наименование на заявката" +REQUEST_REPORT_ERR_TEXT = "Липсва основен шаблон за заявката" +REQUEST_REPORT_ERR_PHP = "Забранено е използването на PHP код" +REQUEST_REPORT_ERR_PHP_N = "Опит за използване на PHP код в шаблоне към заявката при създаване на заявката" +REQUEST_REPORT_ERR_PHP_E = "Опит за използване на PHP код в шаблона към заявката" +REQUEST_REPORT_ERR_RUBRIC= "Не е избрана рубрика" +REQUEST_BY_PARENT = "Родителски документ" +REQUEST_SHOW_STAT = "Покажи статистиката" + +// v 3.1.9 +REQUEST_ALIAS = "Алиас" +REQUEST_I = "Опционално. Алиасът позволява да се използва лесно запомнящсе таг [tag:sysblock:alias] вместо [tag:sysblock:id]. Алиасът не може да бъде чосло, може да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа и трябва да бъде уникален в пределите на модула." +REQUEST_ACCEPT = "Този алиас можр да се използва" +REQUEST_ER_SYN = "Грешен алиас!
Алиасът не трябва да е число, да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа" +REQUEST_ER_EXISTS = "Грешен алиас!
Този алиас вече е използван за друга заявка" +REQUEST_HEADER_EXTERNAL = "Външно обръщание" +REQUEST_EXTERNAL = "Разреши външно обръщение" +REQUEST_ONLY_AJAX = "Изпълнение само чрез Ajax" + +// v 3.2 +REQUEST_PAGINATION = "Постранична навигация" +REQUEST_NAVI_TPL = "Шаблон за постранична навигация" +REQUEST_OTHER = "Още" +REQUEST_SHOW_SQL = "Покажи SQL заявката" +REQUEST_DOC_ON_PAGE = "Брой елементи на заявката на страница" +REQUEST_PAGES_CURENT = "Номер страница" +REQUEST_PAGES_TOTAL = "Общ брой страници" + +// v 3.24 +REQUEST_COUNT_ITEMS = "Получаване на бр. елементи(ако не се използва постранична навигация)" + +// v 3.26 +REQUEST_BY_POSITION = "Позиция на документа" \ No newline at end of file diff --git a/admin/lang/bg/rubs.txt b/admin/lang/bg/rubs.txt new file mode 100644 index 0000000..6b7ff72 --- /dev/null +++ b/admin/lang/bg/rubs.txt @@ -0,0 +1,326 @@ +# npop 04,2017 Neli Popova, npop@abv.bg +[rubs] +RUBRIK_SUB_TITLE = "Управление на рубрики" +RUBRIK_TIP = "В този раздел са всички рубрики в системата. Тук може да добавяте, редактирате или копирате рубриките. Може да редактирате шаблона за показване на документите в рубриката и правата за достъп." +RUBRIK_ID = "ID" +RUBRIK_NAME = "Наименование на рубрика" +RUBRIK_NAME2 = "Наименование на рубрика:" +RUBRIK_TEMPLATE_OUT = "Извеждане в шаблон" +RUBRIK_TEMPLATE_OUT2 = "Извеждане в шаблон:" +RUBRIK_URL_PREFIX = "Префикс за линка" +RUBRIK_URL_PREFIX2 = "Префикс за линка:" +RUBRIK_DOCS_VI = "Показвай документите в списъка" +RUBRIK_URL_PREFIX2 = "Префикс за линка:" +RUBRIK_COUNT_DOCS = "Брой документи" +RUBRIK_COUNT_FIELDS = "Брой полета" +RUBRIK_AUTHOR = "Автор" +RUBRIK_ACTION = "Действия" +RUBRIK_FORMAT = "Използвайте" +RUBRIK_FORMAT_TIME = "за линковете в формат за време" +RUBRIK_FORMAT_ID = "за вмъкване id документ" +RUBRIK_EDIT = "Редактиране полетата и правата на рубриката" +RUBRIK_EDIT_TMPLS = "Дополнительные шаблоны" +RUBRIK_NO_VIEW = "Извинете, но Вие нямате права за преглед на списъка с рубрики." +RUBRIK_NO_CHANGE1 = "Извинете, но Вие нямате права за редактиране полетата на рубриката." +RUBRIK_NO_CHANGE2 = "Извинете, но Вие нямате права за редактиране на шаблона на тази рубрика." +RUBRIK_NO_CHANGE3 = "Извинете, но Вие нямате права за създаване на нови рубрики." +RUBRIK_EDIT_TEMPLATE = "Редактиране шаблон на рубрика" +RUBRIK_EDIT_CODE = "Редактиране на изпълнимия код за рубриката" +RUBRIK_EDIT_CODE_T = "Редактиране на изпълнимия код за рубриката" +RUBRIK_EDIT_CODE_NO = "Нямате достъп за редактиране на изпълнимия код" +RUBRIK_DELETE = "Изтриване на тази рубрика" +RUBRIK_DELETE_LEGEND = "Изтрий рубриката" +RUBRIK_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете тази рубрика?" +RUBRIK_NO_PERMISSION = "Извинете, но вие нямате права за изтриване на рубрика." +RUBRIK_USE_DOCUMENTS = "Извинете, но вие не можете да изтриете тази рубрика, т.к. в нея има въведени документи." +RUBRIK_MULTIPLY = "Копиране на рубрика" +RUBRIK_NO_MULTIPLY = "Извинете, но нямате права за копиране на рубрика" +RUBRIK_BUTTON_SAVE = "Запази промените" +RUBRIK_BUTTON_TEMPL = "Редактиране на шаблон" +RUBRIK_BUTTON_FIELDS = "Редактиране на полета" +RUBRIK_BUTTON_CODE = "Редактиране код на рубрика" +RUBRIK_LEGEND = "Легенда" +RUBRIK_NEW = "Създаване на нова рубрика" +RUBRIK_NEW_TIP = "Създаване на нова рубрика. Моля, въведете наименованието на новата рубрика и изберете шаблон за извеждане." +RUBRIK_BUTTON_NEW = "Добави рубрика" +RUBRIK_EDIT_FIELDS = "Управление полетата и правата за достъп към рубриката" +RUBRIK_DESCRIPTION = "Описание на рубриката" +RUBRIK_NO_FIELDS = "Внимание! Вие не сте създали нито едно поле. Моля, добавете поне едно поле." +RUBRIK_FIELDS_INFO = "Тук може да създавате група от полета, които ще се използват в документите за тази рубрика." +RUBRIK_MULTIPLY2 = "Копиране на рубрика" +RUBRIK_MULTIPLY_TIP = "Моля, въведете наименование и префикс за линковете на новата рубрика" +RUBRIK_BUTTON_COPY = "Копиране" +RUBRIK_TEMPLATE_EDIT = "Редактиране шаблона на рубриката" +RUBRIK_TEMPLATE_NEW = "Създаване на шаблон за рубриката" +RUBRIK_TEMPLATE_SAVED = "Шаблонът е успешно записан" +RUBRIK_NO_FIELD = "В рубриката не се въведени полета" +RUBRIK_FIELD_NAME = "Наименование на полето" +RUBRIK_FIELD_GROUP = "Група" +RUBRIK_FIELD_GROUP_SEL = "Изберете група" +RUBRIK_FIELD_ALIAS = "Алиас(синоним) на полето" +RUBRIK_FIELD_TYPE = "Тип на полето" +RUBRIK_FIELD_UNKNOW = "Неизвестно" +RUBRIK_FIELD_G_UNKNOW = "Без група" +RUBRIK_POSITION = "Позиция" +RUBRIK_NEW_FIELD = "Създаване на ново поле в рубриката" +RUBRIK_BUTTON_ADD = "Добави поле" +RUBRIK_SET_PERMISSION = "Права за достъп към документите за групите потребители" +RUBRIK_USER_GROUP = "Група" +RUBRIK_DOC_READ = "Преглед" +RUBRIK_ALL_PERMISSION = "Всички права" +RUBRIK_CREATE_DOC = "Създаване с проверка" +RUBRIK_CREATE_DOC_NOW = "Създаване без проверка" +RUBRIK_EDIT_OWN = "Редактиране на свои" +RUBRIK_EDIT_DELREV = "Управление на ревизиите" +RUBRIK_EDIT_OTHER = "Редактиране на всички" +RUBRIK_VIEW_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да преглеждат документите" +RUBRIK_ALL_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да изпълняват всички действия с документите от тази рубрика." +RUBRIK_DOC_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да създава документи.
Внимание!
Преди публикуване, документа трябва да бъде проверен от Администратор." +RUBRIK_DOC_NOW_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да създават документи.
Внимание!
Докуентите ще се публикуват без проверка от Администратор." +RUBRIK_OWN_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да редактират само своите документи" +RUBRIK_OTHER_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да редактират своите и чуждите документи" +RUBRIK_DELREV_TIP = "Установете флага, ако желаете да разрешите дадената група потребители да работят с ревизиите на документите" +RUBRIK_BUTTON_PERM = "Запазете правата" +RUBRIK_FIELD_DEFAULT = "Значение по подразбиране" +RUBRIK_TEMPLATE_TIP = "В този раздел, с използване на HTML, вие трябва да създадете шаблон за извеждане на документа в публичната част на сайта." +RUBRIK_HTML = "Шаблон за извеждаме на рубриката" +RUBRIK_HTML_2 = "Шаблон за извеждане на HEADER" +RUBRIK_HTML_3 = "Шаблон за извеждане на TEASER" +RUBRIK_HTML_4 = "Шаблон за извеждане на ADMIN TEASER" +RUBRIK_PHP_DENIDED = "Грешка!
Вие нямате права за редактиране шаблона на рубриката, понеже той съдържа PHP код, а вие нямате права да използвате PHP код." +RUBRIK_PHP_MESSAGE = "Забранено използването на PHP код." +RUBRIK_EMPTY_MESSAGE = "Не е въведено наименование на полето." +RUBRIK_INSERT_HELP = "Натиснете за да добавите системния таг в шаблона" +RUBRIK_BUTTON_TPL = "Запази шаблона" +RUBRIK_BUTTON_TPL_NEXT = "Приложи (CTRL+S)" +RUBRIK_BUTTON_TPL_CLOSE = "Затвори" +RUBRIK_NO_RUBRIK = "Липсва такава рубрика!" +RUBRIK_NO_NAME = "Моля, въведете наименованието на рубриката" +RUBRIK_NAME_EXIST = "Извинете, но съществува рубтика с това наименование. Моля, въведете друго наименование на рубриката." +RUBRIK_PREFIX_EXIST = "Извинете, но съществува рубрика с такъе URL-префикс. Моля, въведете друг URL-префикс на рубриката." +RUBRIK_VIEWS_INFO = "Системен таг, извеждащ броя прегледи на документа" +RUBRIK_HIDE_INFO = "Системен таг, позволяващ скриването на текст, за определени групи потребители, където Х - номер на група, text - съобщение (ако не е указано се използва код по подразбиране, виж. общи настройки на системата)" +RUBRIK_THUMBNAIL = "Таг отговарящ за създаването на миниатюра(thumbail)(При условии, че в шаблона за полето в рубриката за извеждане в документа) е избрано: [tag:parametr:0])" +RUBRIK_LINK_HOME = "Линк към главната страница на сайта" +RUBRIK_MARK_DELETE = "Маркирай този ред за изтриване" +RUBRIK_MARK_DEL_ALL = "Маркирай всички" +RUBRIK_CHECK_SEARCH = "Търси по това поле" +RUBRIK_CHECK_NUMERIC = "Числово поле" +RUBRIK_SEARCH_TIP = "Отметнете полето, ако желаете по него да се осъществява търсене (работи с модул 'Търсене' версия минимум 2.0.2 )" +RUBRIK_NUMERIC_TIP = "Отметнете полето, ако значението на полето е винаги число. Използва се в заявките за сортиране" +RUBRIK_ALL = "Списък рубрики" +RUBRIK_EDIT_FIELDS_GROUPS = "Редактиране на група от полета" +RUBRIK_FIELDS_GROUPS = "Група от полета" +RUBRIK_ENTER_NAME = "Моля, въведете наименованието на рубриката." +RUBRIK_TEMPLATE_HIDE = "Покажи/скрий шаблоните за всички полета" +RUBRIK_FILED_TEMPLATE_H = "Редактиране на шаблона и описанието на полето" +RUBRIK_FILED_TEMPLATE_DESCR = "Описание на полето" +RUBRIK_FILED_TEMPLATE_F = "Шаблон на полето" +RUBRIK_DOCID_INFO = "Системен таг, идентификатор документа" +RUBRIK_DOCDATE_INFO = "Системен таг, дата на публикуване на документа" +RUBRIK_DOCTIME_INFO = "Системен таг, дата и час на публикуване на документа" +RUBRIK_DATE_INFO = "Системен таг, дата и час на публикуване на документа - по шаблон.
Пример: [tag:date:Y]" +RUBRIK_DOCAUTHOR_INFO = "Системен таг, автор на документа" +RUBRIK_TITLE_INFO = "Системен таг, заглавие на документа" +RUBRIK_PATH_INFO = "Системен таг, път към корена на инсталацията" +RUBRIK_MEDIAPATH_INFO = "Системен таг, път към папката с дизайна" +RUBRIK_PREFIX_BAD_CHAR = "Недопустими символи в префикса" +RUBRIK_FIELDS_TITLE = "Полета на рубриката" +RUBRIK_FIELDS_TPL = "Шаблон за изход на полето в документ" +RUBRIK_RUBRIK_TPL = "Шаблон за изход на полето в заявка" +RUBRIK_SORTED = "Редът е успешно записан" +RUBRIK_F_SORT_TIP = "За пренареждане на полетата, натиснете в/у кръстчето и като го държите, преместете полето" +RUBRIK_R_SORT_TIP = "За пренареждане на рубриките, натиснете в/у кръстчето и като го държите, преместете рубриката" +RUBRIK_META_GEN_TIP = "Автоматично генериране на ключови думи( keywords) и описание ( description ) за документа, възоснова на неговото съдържание" +RUBRIK_ALIAS_HISTORY_TIP = "Съхраняване историята на алиасите на документите" +RUBRIK_MOVE = "Премести" +RUBRIK_REQUEST_TPL = "Шаблон за извеждане на полето в заявката" +RUBRIK_BREADCRUMB = "Системен таг Breadcrumb" +RUBRIK_CODE = "Изпълним код за рубриката" +RUBRIK_START_CODE = "Код, изпълнявам преди зареждането на документа" +RUBRIK_CODE_START = "Код, изпълним преди съхраняването на документа" +RUBRIK_CODE_END = "Код, изпълним след съхраняването на документа" +RUBRIK_TAGS = "Таг" +RUBRIK_TAGS_ID = "Тег ID" +RUBRIK_TAGS_ALIAS = "Тег Алиас" +RUBRIK_HTML_T = "HTML код на шаблона" +RUBRIK_TAG_DESC = "Описание на тага" +RUBRIK_NEW_FIEL_TITLE = "За полетата Падащ списък и Мулти списък, Значенията по подразбиране се въвеждат разделени със запетая" +RUBRIK_LINK = "Свържи рубриката" +RUBRIK_LINK_DESC = "При задаването на връзка между рубриките, при добавянето на документи може автоматически да се поставят алиаси(имена)." +RUBRIK_NOLINK = "Не е избрано" +RUBRIK_OR = " или " + +RUBRIC_F_GROUP_TITLE = "Наименование на група" +RUBRIC_F_GROUP_DELETE = "Изтриване на група" +RUBRIC_F_GROUP_DELETE_H = "Сигурни ли сте, че желаета да изтриете групата?" +RUBRIC_NO_GROUPS = "В момента, за тази рубрика няма групи от полета" +RUBRIC_GROUP_ADD = "Добави група" +RUBRIK_NEW_GROUP = "Добави нова група" +RUBRIK_HEADER_GROUP = "Управление на групи от полета" + +RUBRIK_TEMPLATES_TAGS = "Таг" +RUBRIK_TEMPLATES_TAG_DESC = "Описание на тага" +RUBRIK_TEMPLATES_THEME_FOLDER = "Наименование на шаблона (Име на папката с файлове за дадения шаблон)" +RUBRIK_TEMPLATES_PAGENAME = "Наименование на сайта" +RUBRIK_TEMPLATES_TITLE = "Наименование на страницата" +RUBRIK_TEMPLATES_KEYWORDS = "Ключови думи (Meta - Keywords)" +RUBRIK_TEMPLATES_DESCRIPTION = "Описание на страницата (Meta - Description)" +RUBRIK_TEMPLATES_INDEXFOLLOW = "Тип индексиране" +RUBRIK_TEMPLATES_PATH = "Път към корена на инсталацията" +RUBRIK_TEMPLATES_MEDIAPATH = "Път до папката с шаблона (Пример: [tag:mediapath]images/logo.gif)" +RUBRIK_TEMPLATES_CSS = "Компресира няколко css-файла в един. Връща път.
FFF - имена на файлове, разделени със запетая
P - път към папката с файлове, незадължително. По подразбиране - [tag:mediapath]css/

Пример: href="[tag:css:reset.css,style.css]"" +RUBRIK_TEMPLATES_JS = "Компресира няколко js-файла в един. Връща път.
FFF - имена на файлове, разделени със запетая
P - път към папката с файлове, незадължително. По подразбиране - [tag:mediapath]js/

Пример: href="[tag:js:common.js,main.js]"" + +RUBRIK_RUB_INFO = "Системен таг, отговарящ за извеждане на съдържанието на поле от рубрика. ID-номер на полето. ХХХ-брой символи за извеждане." +RUBRIK_SELECT_IN_LIST = "Моля, изберете поле от рубриката от списъка, показан по-долу." +RUBRIK_TEMPLATE_ITEMS = "Шаблон за извеждане на елементите на заявката" +RUBRIK_DOCID_INFO = "Системен таг, съответстващ на идентификатора на документа" +RUBRIK_DOCTITLE_INFO = "Системен таг, съответстващ на наименованието на документа" +RUBRIK_CDOCID_INFO = "Системен таг, съответстващ на идентификатора на текущия документ(в който се извежда заявката)" +RUBRIK_DOCDATE_INFO = "Системен таг, съответстващ на датата на публикуване на документа" +RUBRIK_CDOCDATE_INFO = "Системен таг, съответстващ на датата на публикуване на текущия документ(в който се извежда заявката)" +RUBRIK_DOCTIME_INFO = "Системен таг, съответстващ на датата и часът на публикуване на документа" +RUBRIK_CDOCTIME_INFO = "Системен таг, съответстващ на датата и часът на публикуване на текущия документ(в който се извежда заявката)" +RUBRIK_DATE_INFO = "Системен таг, дата и час на публикуване на документа - по шаблон.
Пример: [tag:date:d.m.Y]
Може да се използват разделители (space - . /)" +RUBRIK_CDATE_INFO = "Системен таг, дата и час на публикуване на документа - по шаблон.
Пример: [tag:date:d.m.Y]
(в който се извежда заявката)
Може да се използват разделители (space - . /)" +RUBRIK_DOCAUTHOR_INFO = "Системен таг, съответстващ на автора на документа" +RUBRIK_DOCAUTHOR_AVATAR = "Системен таг, съответстващ на аватаре на автора на документа" +RUBRIK_CDOCAUTHOR_INFO = "Системен таг, съответстващ на автора на текущия документ(в който се извежда заявката)" +RUBRIK_VIEWS_INFO = "Системен таг, извеждащ брой прегледи на документа" +RUBRIK_COMMENTS_INFO = "Системен таг, извеждащ брой коментари към документа. Внимание! Работи само при инсталиран модул Коментари!" +RUBRIK_PATH = "Системен таг, път към корена на инсталацията" +RUBRIK_MEDIAPATH = "Системен таг, път към папките с шаблона (Например: [tag:mediapath]images/logo.gif)" +RUBRIK_THUMBNAIL = "Таг, отговарящ за създаването на миниатюри (При условие, че шаблона за полето в рубриката(шаблон за извеждане в заявка) е избрано: [tag:parametr:0])" + +RUBRIK_ALIAS_HEAD = "Въвеждане алиас за поле" +RUBRIK_ALIAS_HEAD_T = "Може да използвате само латински символи и цифри!
Пример: header" +RUBRIK_ALIAS_HEAD_R = "Рубрика:" +RUBRIK_ALIAS_HEAD_F = "Поле:" +RUBRIK_ALIAS_ALIAS = "Алиас на полето" +RUBRIK_ALIAS_NAME = "Наименование на алиаса" +RUBRIK_ALIAS_BUTT = "Запази" + +RUBRIK_ALIAS_ERROR = "Грешка:" +RUBRIK_ALIAS_RUBID = "Неправилно избрана рубрика" +RUBRIK_ALIAS_FIELDID = "Неправилно избрано поле" +RUBRIK_ALIAS_MATCH = "Неправилно въведен алиас" +RUBRIK_ALIAS_USED = "Този алиас вече се използва" + +RUBRIK_REPORT_QUICKSAVE = "Изпълнил бързо записване на настройките на рубриките" +RUBRIK_REPORT_SORTE = "Изпълнил сортиране на рубриките" +RUBRIK_REPORT_SORTE_FIELDS = "Изпълнил сортировка на полетата в рубрика" +RUBRIK_REPORT_PERMISION = "Променил правата за достъп към документите на рубриката" +RUBRIK_REPORT_COPY = "Създал копие на рубрика" +RUBRIK_REPORT_TEMPL_RUB = "Редактирал шаблон на рубрика" +RUBRIK_REPORT_FIELD_EDIT = "Редактирал поле" +RUBRIK_REPORT_FIELD_DEL = "Изтрил поле" +RUBRIK_REPORT_RUB = "рубрика" + +RUBRIK_REP_QUICKSAVE_H = "Изпълнено" +RUBRIK_REP_QUICKSAVE_T = "Настройките на рубриката са успешно записани" + +RUBRIK_REPORT_ADD = "Добавил рубрика" +RUBRIK_REPORT_SAVE_TPL = "Записал шаблоба за офорление на рубриката" + +RUBRIK_CODE_SAVED = "Изпълнимия код за рубриката е успешно записан" +RUBRIK_CODE_SAVED_ERR = "Неуспешно записване на изпълнимия код за рубриката.
Моля, опитайте отново." +RUBRIK_CODE_ERROR = "Грешка" +RUBRIK_CODE_SUCCESS = "Изпълнено" +RUBRIK_CODE_UPDATE = "Променил изпълнимия код за рубрика" + +RUBRIK_LOG_NEW_FIELD = "Добавил поле в рубрика" +RUBRIK_LOG_DEL_RUBRIC = "Изтрил рубрика" +RUBRIK_LOG_NEW_RUBRIC = "Създал рубрика" + +RUBRIK_FILDS_SAVED = "Успешно записано" +RUBRIK_FILD_SAVED = "Полето е добавено успешно" +RUBRIK_FILDS_REPORT = "Записал полетета на рубрика" +RUBRIK_FILDS_ERROR = "Грешка" +RUBRIK_FILDS_SUCCESS = "Изпълнено" + +RUBRIC_ERROR = "Грешка" +RUBRIC_SUCCESS = "Изпълнено" +RUBRIC_SAVED_PHP_ERR = "Забранено е използването в шаблоните на PHP код" +RUBRIC_SAVED_TPL_ERR = "Неуспешно запазване на шаблона на рубриката.
Моля, опитайте отново." +RUBRIC_SAVED_TPL = "Шаблонът на рубриката е успешно записан." +RUBRIC_SAVED_FLDTPL = "Шаблонът на полето е успешно записан." +RUBRIK_TAG_SYSBLOCK = "Системен таг за извеждане на системен блок" +RUBRIK_TAG_TEASER = "Системен таг за извеждане на тизер" +RUBRIK_TAG_ALIAS = "Системен таг за извеждане алиаса на документа" +RUBRIK_TAG_REQUEST = "Системен таг за извеждане на заявка" +RUBRIC_SAVED_PERMS = "Правава за достъп до документите са успешно записани " +RUBRIK_IFELSE = "Условия" +RUBRIK_IFELSE_1 = "извеждаме ако полето не е празно" +RUBRIK_IFELSE_2 = "иначе извеждаме ако полето е празно" +RUBRIK_SAMPLE = "Пример" +RUBRIK_TAG_DOCDB = "Системный тег вывода поля документа из БД" +RUBRIK_TAG_LANGFILE = "Системный тег для вывода языковой переменной из файла" + +RUBRIC_TMPLS_BUTTON = "Допълнителни шаблони за рубриката" +RUBRIC_TMPLS_HEAD = "Списък на допълнителните шаблони на рубриката" +RUBRIC_TMPLS_ADD = "Добави нов шаблон" +RUBRIC_TMPLS_ID = "id" +RUBRIC_TMPLS_NAME = "Наименование" +RUBRIC_TMPLS_NAME_FULL = "Наименование на шаблона на рубриката" +RUBRIC_TMPLS_AUTHOR = "Автор" +RUBRIC_TMPLS_DATE = "Дата" +RUBRIC_TMPLS_COUNT_DOCS = "Кол-во документи" +RUBRIC_TMPLS_ACTIONS = "Действия" +RUBRIC_TMPLS_COPY = "Копирай шаблона" +RUBRIC_TMPLS_COPY_TIP = "Моля, въведете наименование на шаблона" +RUBRIC_TMPLS_COPY_TIP2 = "Моля, въведете наименование на копирания шаблон" +RUBRIC_TMPLS_EDIT = "Редактиране" +RUBRIC_TMPLS_DELETE = "Изтриване" +RUBRIC_TMPLS_DELETE_C = "Сигурни ли сте, че желаете да изтриете шаблона?" +RUBRIC_TMPLS_TIP = "Вие може да създавате неограничен брой шаблони за една рубрика" +RUBRIC_TMPLS_NO_ITEMS = "Съобщение
В моментта липсват допълнителни шаблони." +RUBRIC_TMPLS_FROM = "Създай копие на основния шаблон" +RUBRIC_TMPLS_INNAME = "Въведете наименование на шаблона" +RUBRIC_TEMPL_REPORT = "Редайтирал допълнителен шаблон за рубрика" +RUBRIC_TMPLS_LOG_DEL = "Изтрил допълнителен шаблон за рубрика" + +// 3.24 +RUBRIC_WARNING_TIP = "Внимание! Моля, бъдете внимателни - неверните параметри ще доведат до неработоспособна система." + +RUBRIK_EDIT_FIELDS = "Управление на полетата" +RUBRIK_EDIT_RULES = "Управление на правата за достъп към рубриката" + +RUBRIC_TABLE_BTN_FIELDS = "Полета на рубриката" +RUBRIC_TABLE_BTN_FTEMPLATES = "Шаблони на полетата" +RUBRIC_TABLE_BTN_FGROUPS = "Групи полета" +RUBRIC_TABLE_BTN_TEMPLATES = "Шаблон за рубрика" +RUBRIC_TABLE_BTN_CODE = "Изпълним код" +RUBRIC_TABLE_BTN_RULES = "Права за достъп" + +RUBRIK_EDIT_CODE_TIP = "Внимание! Моля, бъдете внимателни - неверните параметри ще доведат до неработоспособна система." +RUBRIK_EDIT_CODE_LOAD_TIP = "Достъп към данните:
$this->curentdoc - Данни документ, преди поставяне в шаблона за извеждане" +RUBRIK_EDIT_CODE_BEF_TIP = "Достъп към данните:
$data - Всички данни на документа
$data['feld'] - Данни полета на документа
$rubric_id - ID рубрика" +RUBRIK_EDIT_CODE_AFT_TIP = "Достъп към данните:
$data - Всички данни на документа
$rubric_id - ID рубрика
$document_id - ID документ - Число или False" + +RUBRIK_FIELDS_TEMPLATES_H1 = "Управление шаблоните на полетата" +RUBRIK_FIELDS_TEMPLATES_H2 = "Шаблони на полетата" +RUBRIK_FIELDS_TEMPLATES_T1 = "Създаване/Редактиране/Изтриване на шаблони за полетата (tpl)" +RUBRIK_FIELDS_TEMPLATES_T2 = "Редактиране на шаблоните за извеждане на полетата" +RUBRIK_FIELDS_TEMPLATES_LIST = "Списък типове полета, използвани в рубриката" +RUBRIK_FIELDS_TEMPLATES_FNAME = "Наименование на поле" +RUBRIK_FIELDS_TEMPLATES_FFUNC = "Функция" +RUBRIK_FIELDS_TEMPLATES_FTEMP = "Шаблон .tpl (по подразбиране)" +RUBRIK_FIELDS_TEMPLATES_FTEMPL = "Шаблон .tpl по ID поле" +RUBRIK_FIELDS_TEMPLATES_PANEL = "Панел" +RUBRIK_FIELDS_TEMPLATES_DOC = "Документ" +RUBRIK_FIELDS_TEMPLATES_REQ = "Заявка" +RUBRIK_FIELDS_TEMPLATES_DB = "База данни" +RUBRIK_FIELDS_TEMPLATES_BACK = "Към списъка с типове полета" +RUBRIK_FIELDS_NO_TEMPLATES = "Липсва шаблон" +RUBRIK_FIELDS_EDIT_RUBRIC = "Рубрика" +RUBRIK_FIELDS_EDIT_FIELD = "Поле:" +RUBRIK_FIELDS_EDIT_TYPE = "Тип:" +RUBRIK_FIELDS_EDIT_TPL_ADM = "Шаблон за панела" +RUBRIK_FIELDS_EDIT_TPL_DOC = "Шаблон за извеждане в документ" +RUBRIK_FIELDS_EDIT_TPL_REQ = "Шаблон за извеждане в заявка" +RUBRIK_FIELDS_EDIT_TPL_CREAT = "Създаване на шаблон от основния файл" +RUBRIK_FIELDS_EDIT_TPL_EDIT = "Редактиране на шаблон" +RUBRIK_FIELDS_EDIT_NO_TPL = "Отсъства основен файл на шаблона" +RUBRIC_TMPLS_CREAT = "Създай" +RUBRIC_TMPLS_DELETE = "Изтрий" \ No newline at end of file diff --git a/admin/lang/bg/scripts.js b/admin/lang/bg/scripts.js new file mode 100644 index 0000000..e69de29 diff --git a/admin/lang/bg/settings.txt b/admin/lang/bg/settings.txt new file mode 100644 index 0000000..b03dcd1 --- /dev/null +++ b/admin/lang/bg/settings.txt @@ -0,0 +1,165 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +[settings] +SETTINGS_COUNTRIES = "Управление на държавите" +SETTINGS_COUNTRIES_ALL = "Списък държави" +SETTINGS_COUNTRY_TIP = "Моля, изберете държави, които да бъдат достъпни при регистрацията на нови потребители в системата. Помнете, че избрания от вас списък може да бъде използван и от други модули в системата." +SETTINGS_ACTIVE = "Активна?" +SETTINGS_COUNTRY_NAME = "Наименование държава" +SETTINGS_IN_EC = "Член на ЕС?" +SETTINGS_YES = "Да" +SETTINGS_NO = "Не" +SETTINGS_BUTTON_SAVE = "Запиши промените" +SETTINGS_BUTTON_SAVE_AJAX = "Приложи (CTRL+S)" +SETTINGS_OR = "или" +SETTINGS_MAIN_TITLE = "Управление на общите настройки на системата" +SETTINGS_CASE_TITLE = "Допълнителни настройки" +SETTINGS_MAIN = "Общи настройки на системата" +SETTINGS_SAVED = "Настройките на системата са успешно записани" +SETTINGS_SAVED_ERR = "Неуспешно записване на настройките.
Пробвайте отново." +SETTINGS_SAVE_INFO = "В този раздел Вие може да редактирате глобалните параметри на системата. Моля, бъдете пределно внимателни и понете, че Грешно въведени параметри могат да доведат до неработеща ситема." +SETTINGS_SAVE_CONFIRM = "Сигурни ли сте, че желате да запазите настройките на системата?" +SETTINGS_SITE_NAME = "Наименование на сайта:" +SETTINGS_SITE_COUNTRY = "Държава на сайта:" +SETTINGS_EMAIL_SENDER = "Имейл от който се изпраща:" +SETTINGS_EMAIL_NAME = "Име от което се изпраща имейла:" +SETTINGS_MAIL_TRANSPORT = "Метод за изпращане на писмата:" +SETTINGS_MAIL = "mail" +SETTINGS_SENDMAIL = "sendmail" +SETTINGS_SMTP = "smtp" +SETTINGS_SMTP_SERVER = "Сървър SMTP:" +SETTINGS_MAIL_PORT = "Порт SMTP:" +SETTINGS_SMTP_NAME = "Потребител:" +SETTINGS_SMTP_PASS = "Парола:" +SETTINGS_SMTP_ENCRYPT = "Кодиране" +SETTINGS_SMTP_NOENCRYPT = "не" +SETTINGS_MAIL_PATH = "Път до папката sendmail:" +SETTINGS_SYMBOL_BREAK = "Принудителен пренос след (знака):" +SETTINGS_SYMBOL_BREAK_INFO = "Не повече от 1000 според RFC 2822" +SETTINGS_SYMBOLS = "символа" +SETTINGS_TEXT_EMAIL = "Съобщение до потребителя след създаването на акаунта, където:" +SETTINGS_TEXT_INFO = "%NAME% - Име на потребител
%HOST% - Линк към сайта
%PASSWORD% - Парола
%EMAIL% - Имейл на потребителя
%EMAILSIGNATURE% - Подпис на съобщението" +SETTINGS_EMAIL_FOOTER = "Текст на подписа:" +SETTINGS_ERROR_PAGE = "Страница с грешка HTTP 404: Page not found" +SETTINGS_PAGE_DEFAULT = "(по подразбиране Id:2)" +SETTINGS_TEXT_PERM = "Текст на съобщението, ако потребителя няма права:" +SETTINGS_HIDDEN_TEXT = "Текст на съобщението, ако потребителя няма права за разглеждане на скрит таг [tag:hide:X,X]...[/tag:hide]" + +SETTINGS_NAVI_BOX = "Контейнер за постранична навигация:
Пример: <ul>%s</ul>" +SETTINGS_LINK_BOX = "Контейнер за елементите на постраничната навигация:
Пример: <li>%s</li>" +SETTINGS_TOTAL_BOX = "Контейнер за текста преди номерата на страниците:
Пример: <span>%s</span>" +SETTINGS_ACTIVE_LINK_BOX= "Контейнер за активния елемент:
Пример: <span class="active">%s</span>" +SETTINGS_PAGE_SEPAR = "Контейнер за етикета за наличие на страница:
Пример: <li>%s</li>" +SETTINGS_PAGE_BEFORE = "Текст пред номерата на страниците:
Пример: Страница %d от %d" +SETTINGS_PAGE_START = "Текст за линка "Перва":" +SETTINGS_PAGE_END = "Текст за линка "Последна":" +SETTINGS_PAGE_SEPARATOR = "Текст на етикета за наличие на страници освен видимите:" +SETTINGS_PAGE_NEXT = "Текст на линка "Следваща":" +SETTINGS_PAGE_PREV = "Текст на линка "Предходна":" + +SETTINGS_MAIN_BREADCRUMBS = "Настройки за извеждането на «Breadcrumb»" +SETTINGS_BREAD_BOX = "Контейнер «Breadcrumb»:
Пример: <ul class="breadcrumb">%s</ul>" +SETTINGS_BREAD_MAIN = "Показвай първия елемент: Главна страница:
Да/Не" +SETTINGS_BREAD_HOST = "Добавяй адреса на хоста в url:
Да/Не" +SETTINGS_BREAD_SEPPARATOR = "Разделител между линковете:
Пример: <li> → </li>" +SETTINGS_BREAD_SEPP_USE = "Покажи:
Да/Не" +SETTINGS_BREAD_BOX_LINK = "Контейнер за линка:
Пример: <li>%s</li>" +SETTINGS_BREAD_LINK_TPL = "Шаблон за линка
Използват се таговете: [name], [link], [count]" +SETTINGS_BREAD_BOX_LASTLINK = "Показване на последния елемент:" +SETTINGS_BREAD_SELF_BOX = "Контейнер за последния елемент:
Пример: <li class="active">%s</li>" + + +SETTINGS_DATE_FORMAT = "Формат за дата:" +SETTINGS_TIME_FORMAT = "Формат за дата и час:" +SETTINGS_CLEAR_CACHE = "Изтриване на кеша" +SETTINGS_USE_DOCTIME = "Използване на датата на публикация на документите" +SETTINGS_INFO = "Допълнително" +SETTINGS_MAIN_SETTINGS = "Общи настройки на системата" +SETTINGS_MAIN_MAIL = "Настройки на пощата" +SETTINGS_MAIN_PAGENAVI = "Настройки на извеждането на пострничната навигация" +SETTINGS_NAME = "Параметър" +SETTINGS_VALUE = "Значение" +SETTINGS_EDITOR_CKEDITOR = "CKEditor" + +SETTINGS_ERROR = "Грешка" +SETTINGS_SUCCESS = "Изпълнено" + +SETTINGS_SAVE_DOP = "Променил допълнителните настройки на системата" +SETTINGS_SAVE_MAIN = "Променил общите настройки на системата" +SETTINGS_SAVE_COUNTRY = "Променил настройките за държавите" + +SETTINGS_LANG_EDIT = "Управление на езиците" +SETTINGS_LANG_TITLE = "Внимание! Настройката на езиците трябва да стане, задължително преди добавянето на документите в сайта!" +SETTINGS_LANG_AEDIT = "Редактиране" +SETTINGS_LANG_AON = "Включи" +SETTINGS_LANG_AOFF = "Изключи" +SETTINGS_LANG_ADEFAULT = "Включи по подразбиране" +SETTINGS_LANG_ADEFAULT_HINT = "" +SETTINGS_LANG_ID = "Id" +SETTINGS_LANG_FLAG = "Флаг" +SETTINGS_LANG_SYSTEM = "Системно" +SETTINGS_LANG_PREFIX = "Префикс" +SETTINGS_LANG_NAME = "Наименование" +SETTINGS_LANG_DEFAULT = "По подразбиране" +SETTINGS_LANG_ACTION = "Действия" +SETTINGS_LANG_ADD = "Добави език" +SETTINGS_LANG_SAVE = "Запази промените" + +SETTINGS_REV_DELETED = "Ревизиите на документите са успешно изтрити" +SETTINGS_REV_DELETED_ERR = "Неуспешно изтриване на ревизиите на документите.
Опитайте отново." +SETTINGS_REV_UPDATE = "Изтрил ревизиите на документите" +SETTINGS_COUNT_DELETED = "Дневния брояч на документите
е успешно занулен." +SETTINGS_COUNT_DELETED_ERR = "Неуспешно изтриване на дневния
брояч на документите.
Опитайте отново." +SETTINGS_COUNT_UPDATE = "Занулил дневния брояч на документите" +SETTINGS_CACHE_LIFETIME = "Внимание!!! Включено кеширование запроса к настройкам системы. Изменения вступят в силу, только после окончания времени жизни кеша или отключения кеширования" + +// v3.2 +SETTINGS_PAGINATION = "Настройка на пагинация" +PAGINATION_ADD = "Създай шаблон за пагинация" +PAGINATION_NAME = "Наименование" +PAGINATION_ACTIONS = "Действия" +PAGINATION_EDIT_HINT = "Редактиране" +PAGINATION_DELETE_HINT = "Изтриване на шаблон за пагинация" +PAGINATION_DEL_HINT = "Сигурни ли сте, че желаете да изтриете този шаблон за пагинация?" +PAGINATION_SAVED = "Шаблонът за пагинация е записан успешно" +PAGINATION_SAVED_ERR = "Шаблонът за пагинация не е записан.
Опитайте отново." +PAGINATION_ERROR = "Грешка" +PAGINATION_SUCCESS = "Изпълнено" + +pagination_name = "Наименование" +pagination_navigation_box = "Контейнер за постранична навигации
Пример: <ul class="pagination pagination-sm">%s</ul>" +pagination_link_box = "Контейнер за елемент
Пример: <li>%s</li>" +pagination_active_link_box = "Контейнер за активен елемент
Пример: <li class="active">%s</li>" +pagination_link_template = "Шаблон за линка на елемента
[link] - линк към страница
[page] - Номер страница за линка
[name] - Номер на страница
" +pagination_link_active_template = "Шаблон за активен линк на елемента
[link] - линк към страницата
[page] - Номер на страница за линка
[name] - Номер на страница
" +pagination_separator_box = "Контейнер за етикера за наличие на страница
Пример: <li>%s</li>" +pagination_separator_label = "Текст за етекета за наличие на страници" +pagination_start_label = "Текст за линк "Първа"" +pagination_end_label = "Текст за линк "Последна"" +pagination_next_label = "Текст за линк "Следваща"" +pagination_prev_label = "Текст за линк "Предходна"" + +// v3.24 +SETTINGS_SAVED_ERR_FILE = "Грешка при записване на файла. Моля, пробвайте отново." +SETTINGS_SAVED_FILE = "Файлът е успешно записан." +SETTINGS_FILE_EDIT_H = "Редактиране на файла" +SETTINGS_FILE_CONTENT = "Съдържание на файла:" +SETTINGS_FILE_ROBOTS = "Файл robots.txt" +SETTINGS_FILE_CUSTOM = "Файл func.custom.php" + +// v3.25 +_const_auth = "Авторизация" +_const_url = "Формиране на URL" +_const_themes = "Оформление" +_const_folders = "Папки" +_const_thumbs = "Генериране на миниатюри" +_const_watermarks = "Водни знаци" +_const_sessions = "Session и Cookie" +_const_dev = "Разработка" +_const_smarty = "Настройки на Smarty" +_const_cache = "Кеширане на SQL" +_const_compression = "Компресия" +_const_memcached = "Memcached" +_const_request = "Заявки" +_const_database = "База данни" +_const_other = "Още" \ No newline at end of file diff --git a/admin/lang/bg/sysblocks.txt b/admin/lang/bg/sysblocks.txt new file mode 100644 index 0000000..e07037d --- /dev/null +++ b/admin/lang/bg/sysblocks.txt @@ -0,0 +1,95 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +SYSBLOCK_HEAD = "Системни блокове" +SYSBLOCK_EDIT = "Управление на системни блокове" +SYSBLOCK_EDIT_TIP = "В този раздел се намират всички системни блокове." +SYSBLOCK_ID = "Id" +SYSBLOCK_NAME = "Наименование на системния блок" +SYSBLOCK_HTML = "Код на системния блок" +SYSBLOCK_TAGS = "Таг" +SYSBLOCK_TAGS_2 = "HTML Tags" +SYSBLOCK_EXTERNAL = "Разреши външно обръщение от линк" +SYSBLOCK_EXTERNAL_H = "Външно обръщение от линк" +SYSBLOCK_EXTERNAL_GO = "Преход" +SYSBLOCK_AJAX = "Разреши да се изпълнява само чрез Ajax" +SYSBLOCK_AJAX_H = "Изпълнява се само чрез Ajax" + +SYSBLOCK_VISUAL = "Визуален редактор" +SYSBLOCK_VISUAL_H = "Визуален редактор" + +SYSBLOCK_MEDIAPATH = "Системен таг, път до папката с дизайна" +SYSBLOCK_BREADCRUMB = "Системен таг, Breadcrumb" +SYSBLOCK_DOCID_INFO = "Системен таг, идентификатор на документа" +SYSBLOCK_PATH = "Път до корена на инсталацията" +SYSBLOCK_HOME = "Линк към главната страница на сайта" + +SYSBLOCK_AUTHOR = "Автор" +SYSBLOCK_DATE = "Дата на създаване" +SYSBLOCK_TAG = "Системен таг" +SYSBLOCK_ACTIONS = "Действия" +SYSBLOCK_NO_ITEMS = "Съобщение:
В момента няма въведени системни блокове." +SYSBLOCK_BUTTON_SAVE = "Запази промените" +SYSBLOCK_BUTTON_ADD = "Добави системен блок" +SYSBLOCK_BUTTON_COPY = "Копиране" +SYSBLOCK_INSERT_H = "Добавяне на ситемен блок" +SYSBLOCK_EDIT_H = "Редактиране на системен блок" +SYSBLOCK_INNAME = "Въведете наименование на системния блок" +SYSBLOCK_ENTER_NAME = "Моля, въведете наименование на системния блок" +SYSBLOCK_INSERT = "Тук може да добавите или редактирате избрания от вас системен блок" + +SYSBLOCK_LINK = "Системният блок е достъпен чрез линка:" + +SYSBLOCK_SAVE = "Добави" +SYSBLOCK_SAVEDIT = "Запази промените" +SYSBLOCK_SAVE_NEXT = "Добави и продолжи редактирането" +SYSBLOCK_SAVEDIT_NEXT = "Приложи (CTRL+S)" + +SYSBLOCK_INTEXT = "Системен блок" +SYSBLOCK_ADD = "Добави нов системен блок" +SYSBLOCK_ADD_BUTTON = "Добави" +SYSBLOCK_EDIT_HINT = "Редактиране на системен блок" +SYSBLOCK_DELETE_HINT = "Изтриване на системен блок" +SYSBLOCK_DEL_HINT = "Сигурни ли сте, че желаете да изтриете системния блок?" +SYSBLOCK_LIST_LINK = "Списък системни блокове" +SYSBLOCK_FILE = "Файл на шаблона" +SYSBLOCK_SAVED = "Системният блок е успешно съхранен." +SYSBLOCK_COPY_TITLE = "Копиране на системен блок" +SYSBLOCK_COPY = "Копиране на системен блок" +SYSBLOCK_COPY_TIP = "Моля, въведете наименование на системен блок" +SYSBLOCK_COPY_TIP2 = "Моля, въведете наименование на копирания системен блок" +SYSBLOCK_EXIST = "Извинете, съществува системен блок с това наименование" +SYSBLOCK_SQLUPDATE = "е променил системен блок" +SYSBLOCK_SQLNEW = "е създал нов системен блок" +SYSBLOCK_SQLDEL = "е изтрил системен блок" +SYSBLOCK_OR = " или " + +SYSBLOCK_SAVED = "Системният блок е успешно записан" +SYSBLOCK_SAVED_ERR = "Неуспешно записване на системния блок.
Опитайте отново." +SYSBLOCK_ERROR = "Грешка" +SYSBLOCK_SUCCESS = "Изпълнено" + +// v 3.2 +SYSBLOCK_DESCRIPTION = "Кратко описание" +SYSBLOCK_ALIAS = "Алиас" +SYSBLOCK_I = "Опционално. Алиасът позволява да се използва лесно запомнящсе таг [tag:sysblock:alias] вместо [tag:sysblock:id]. Алиасът не може да бъде чосло, може да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа и трябва да бъде уникален в пределите на модула." +SYSBLOCK_ACCEPT = "Този алиас може да се използва" +SYSBLOCK_ER_SYN = "Грешен алиас!
Алиасът не трябва да е число, може да съдържа само цифри, латински букви, долна черта, тире и е с дължина не-повече от 20 символа" +SYSBLOCK_ER_EXISTS = "Грешен алиас!
Този алиас вече е използван в друг системен блок" + +// v 3.26 +SYSBLOCK_EVAL = "Изпълнявай PHP преди връщане на резултата" +SYS_GROUP_NO_TITLE = "Без групи" +SYS_GROUP_NO_DESCRIPTION = "Лписва описание" +SYS_GROUP_PLEASE_SELECT = "Изберете група" +SYS_GROUP_TITLE = "Наименование на група" +SYS_GROUP_DESCRIPTION = "Описание на група" +SYS_GROUP_BTN = "Добави група" +SYS_GROUPS = "Списък групи" +SYS_GROUPS_SORT_TIP = "За да подредите полетата, натиснете на кръсчето и без да пускате го преместете." +SYS_GROUPS_GROUP_TITLE = "Наименование на група" +SYS_GROUPS_TIP = "Списък групи за системни блокове" +SYS_NO_GROUPS = "В момента няма групио са системни блокове" +SYS_GROUPS_DELETE = "Изтриване на група" +SYS_GROUPS_DELETE_H = "Сигурни ли сте, че желаете да изтриете групата?" +SYS_GROUPS_NEW = "Добави нова група" +SYSBLOCK_COPY_LOG = "създал копие на системния блок" \ No newline at end of file diff --git a/admin/lang/bg/templates.txt b/admin/lang/bg/templates.txt new file mode 100644 index 0000000..d3c32a0 --- /dev/null +++ b/admin/lang/bg/templates.txt @@ -0,0 +1,122 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +TEMPLATES_SUB_TITLE = "Управление на шаблони" +TEMPLATES_TIP1 = "В този раздел са всички шаблони, изполвани в системата. Тук може да изтриете, редактирате или копирате шаблон, за да създадете на негова база нов." +TEMPLATES_ID = "ID" +TEMPLATES_NAME = "Наименование шаблон" +TEMPLATES_NAME2 = "Наименование шаблон:" +TEMPLATES_NAME3 = "Въведете наименованието на шаблона:" +TEMPLATES_AUTHOR = "Автор" +TEMPLATES_DATE = "Дата на създаване" +TEMPLATES_ACTION = "Действия" +TEMPLATES_DATE_FORMAT = "%d.%m.%y г." +TEMPLATES_DATE_FORMAT2 = "%H:%M" +TEMPLATES_IN = "в" +TEMPLATES_EDIT = "Редактиране на шаблон" +TEMPLATES_NO_CHANGE = "Извинете, но нямате достатъчно права за да редактирате шаблона" +TEMPLATES_DELETE = "Изтриване на шаблон" +TEMPLATES_DELETE_CONF = "Сигурни ли сте, че желаете да изтриете този шаблон?" +TEMPLATES_NO_DELETE2 = "Извинете, този шаблон не може да бъде изтрит, т.к. се използва в рубрика" +TEMPLATES_NO_DELETE3 = "Извинете, но Вие нямате достатъчно права за да изтриете шаблона" +TEMPLATES_COPY = "Копиране на шаблон" +TEMPLATES_NO_COPY = "Извинете, но нямате достатъчно права за да копирате шаблона" +TEMPLATES_LEGEND = "Легенда" +TEMPLATES_COPY_TITLE = "Копиране на шаблона" +TEMPLATES_TIP2 = "Моля, въведете наименование на копирания шаблон" +TEMPLATES_TIP3 = "Моля, въведете наименование на шаблона" +TEMPLATES_BUTTON_COPY = "Копиране" +TEMPLATES_TAG_INSERT = "Натиснете върху наименованието на системния таг, за да го добавите в полето на шаблона" +TEMPLATES_TITLE_NEW = "Създаване на нов шаблон" +TEMPLATES_TITLE_EDIT = "Редактиране на шаблон" +TEMPLATES_WARNING1 = "Моля, бъдете възможно най-внимателни при редактирането на шаблона и помнете, че грешно въведения код може да развли външния вид на сайта" +TEMPLATES_WARNING2 = "В този раздел вие може да създавате ръчно нов шаблон, а също така и да заредите готова структура на шаблона от съществуващ файл. Моля, помнете, че файловете с готовата структура на шаблона трябва да бъдат разположени в директори /inc/data/prefabs/templates/" +TEMPLATES_HTML = "HTML код на шаблона" +TEMPLATES_USE_PHP = "Извинете, но вие нямате достатъчно права за да редактирате шаблона, т.к. той използва PHP код" +TEMPLATES_BUTTON_SAVE = "Запази промените" +TEMPLATES_BUTTON_SAVE_NEXT = "Приложи(CTRL+S)" +TEMPLATES_FILE_SAVED = "Файлът е успешно записан" +TEMPLATES_BUTTON_ADD = "Добави шаблон" +TEMPLATES_BUTTON_ADD_NEXT = "Добави и продължи редактирането" +TEMPLATES_BUTTON_LOAD = "Зареди" +TEMPLATES_LOAD_INFO = "Моля, изберете от списъка файл с готова структура на шаблона" +TEMPLATES_EXIST = "Извинете, вече съществува шаблон с това наименование" +TEMPLATES_NO_NAME = "Моля, въведете наименование на шаблона" +TEMPLATES_ALL = "Списък шаблони" +TEMPLATES_OR = " или " + +TEMPLATES_FILE_NAME = "Наименование на файла" +TEMPLATES_CSS_FILES = "Списък css файлове" +TEMPLATES_JS_FILES = "Списък js файлове" +TEMPLATES_FILES = "Файлов мениджър" +TEMPLATES_EDIT_FILE = "Редактиране на файл" +TEMPLATES_DEL_FILE = "Изтриване на файл" + +TEMPLATES_TAGS = "Таг" +TEMPLATES_TAG_DESC = "Описание на тага" +TEMPLATES_THEME_FOLDER = "Наименование на шаблона (име на папка с файловете за дадения шаблон)" +TEMPLATES_FOLDER = "Папка:" +TEMPLATES_PAGENAME = "Наименование на сайта" +TEMPLATES_FILENAME = "Наименование на файла" +TEMPLATES_TITLE = "Наименование на страницата" +TEMPLATES_KEYWORDS = "Ключови думи (Meta - Keywords)" +TEMPLATES_DESCRIPTION = "Описание на страницата (Meta - Description)" +TEMPLATES_INDEXFOLLOW = "Тип индексиране" +TEMPLATES_CANONICAL = "Каноническа страница – препоръчвания екземпляр от страници с много близко съдържание." +TEMPLATES_PATH = "Път към корена на инсталацията" +TEMPLATES_MEDIAPATH = "Път до папката със шаблона (Пример: [tag:mediapath]images/logo.gif)" + +TEMPLATES_CSS = "Събира няколко css-файлов в един. Връща път.
FFF - имената на файловете, разделени със запетая
P - път към папката с файловете, незадължителен. По подразбиране - [tag:mediapath]css/

Пример: href="[tag:css:reset.css,style.css]"" + +TEMPLATES_JS = "Събира няколко js-файлове в един. Връща път.
FFF - имената на файловете, разделени със запетая
P - път към папката с файловете, незадължителен. По подразбиране - [tag:mediapath]js/

Пример: href="[tag:js:common.js,main.js]"" + +TEMPLATES_MEDIAPATH = "Път до папката с шаблона (Пример: [tag:mediapath]images/logo.gif)" +TEMPLATES_MAINCONTENT = "Таг за главното съдържание" +TEMPLATES_ALIAS = "Линк към текущия документ (Alias)" +TEMPLATES_SYSBLOCK = "Системен таг за Системни блокове" +TEMPLATES_TEASER = "Системен таг за Тизери" +TEMPLATES_PRINTLINK = "Линк за "Версия за печат"" +TEMPLATES_HOME = "Линк към главната страница на сайта" +TEMPLATES_BREADCRUMB = "Системен таг Breadcrumb" +TEMPLATES_VERSION = "Показване на лицензна информация" +TEMPLATES_NAVIGATION = "Меню за навигация (ххх - номер на менюто)" +TEMPLATES_IF_PRINT = "Съдържание ще бъде показано при печат." +TEMPLATES_DONOT_PRINT = "Съдържанието няма да бъде показано при печат." +TEMPLATES_RUBHEADER = "Настройва се шаблона на рубриката
(Шаблон за извеждане на HEADER)" +TEMPLATES_NO_ITEMS = "В момента липсват файлове" +TEMPLATES_DOMAIN = "Системен таз за извеждане на домейна" +TEMPLATES_DOCDB = "Системен таг за извеждане на поле на документ от БД" +TEMPLATES_LANGFILE = "Системен таг за извеждане на езикова променлива от файла" +TEMPLATES_LANGUAGE = "Таг за зареждане на езиковите файлове. Препоръчително тагът да е преди основния шаблон." +TEMPLATES_LANG = "Съдържанието ще бъде показано ако езика на документа съвпада с указания" + +TEMPLATES_CACHE_SUCCESS = "Кешът е успешно изтрит." +TEMPLATES_CACHE_SUCCESS_LOG = "е изтрил кеша" + +TEMPLATES_CSS_TITLE = "Моля, бъдете много внимателни при редактирането на шаблона и помнете, че грешно въведения код може да промени или повреде външното оформление на сайта." +TEMPLATES_CSS_EDITOR = "Редактор на CSS файлове" + +TEMPLATES_JS_TITLE = "Моля, бъдете много внимателни при редактирането на шаблона и помнете, че грешно въведения код може да повреди външния вид на сайта" +TEMPLATES_JS_EDITOR = "Редактор на CSS файлове" + +TEMPLATES_REPORT_NEW = "Създал шаблон" +TEMPLATES_REPORT_CHANGE = "Променил шаблон" +TEMPLATES_REPORT_PHP = "Опит за използване на PHP код в шаблона" +TEMPLATES_REPORT_PHP_CSS = "Опит за използване на PHP код в css файл" +TEMPLATES_REPORT_PHP_JS = "Опит за използване на PHP код в js файл" +TEMPLATES_REPORT_PHP_ERR = "Използването на PHP кода е забранено" +TEMPLATES_REPORT_ID_ERR = "Опит за изтриване на основния шаблон" +TEMPLATES_REPORT_DELETE = "Изтрил шаблон" +TEMPLATES_REPORT_FILE = "Редактирал файл" +TEMPLATES_REPORT_COPY = "Създал копие на шаблона" +TEMPLATES_REPORT_DEL_OK = "Файлът е успешно изтрит" +TEMPLATES_REPORT_DEL_ER = "Неуспешно изтриване на файл" + +TEMPLATES_REPORT_ERROR_TEXT = "HTML кода на шаблона е празен" +TEMPLATES_REPORT_ERROR_TITLE = "Не е попълнено - Наименование на шаблона" + +TEMPLATES_SAVED = "Шаблонът е успешно запазен" +TEMPLATES_SAVED_FILE = "Файлът е успешно записан" +TEMPLATES_SAVED_ERR = "Неуспешно запазване на шаблона.
Опитайте отново." +TEMPLATES_SAVED_ERR_FILE = "Неуспешно запазване на файла.
Опитайте отново." +TEMPLATES_ERROR = "Грешка" +TEMPLATES_SUCCESS = "Изпълнено" \ No newline at end of file diff --git a/admin/lang/bg/user.txt b/admin/lang/bg/user.txt new file mode 100644 index 0000000..4afb52e --- /dev/null +++ b/admin/lang/bg/user.txt @@ -0,0 +1,92 @@ +# npop 04,2017 Neli Popova, npop@abv.bg + +[user] +USER_SUB_TITLE = "Управление на потребители" +USER_TIP1 = "В този раздел са всички потребители в системата. Вие може да редактирате параметрите на потребителя, изтриете потребител, а също така да преместите потребител в друга група." +USER_ID = "ID" +USER_NAME = "Име и Фамилия на потребител" +USER_NAME2 = "Име на потребител" +USER_GROUP = "Принадлежи към група" +USER_STATUS_WAIT = "Очаква активация" +USER_LAST_VISIT = "Последен вход" +USER_REGISTER_DATE = "Дата на регистрация" +USER_ACTION = "Действия" +USER_DELETE = "Изтриване на потребителя" +USER_EDIT = "Редактиране на потребителя" +USER_DATE_FORMAT = "%d.%m.%Y %H:%M" +USER_NO_CHANGE = "Извинете, но нямате права за редактиране на потребители" +USER_DELETE_CONFIRM = "Сигурни ли сте, че желаете да изтриете дадения потребител?" +USER_LEGEND = "Легенда" +USER_BUTTON_SAVE = "Запази промените" +USER_ORDERS = "История заявки " +USER_DOWNLOADS = "История заявки ПО" +USER_MARK_DELETE = "Маркирай за изтриване" +USER_NEW_TITLE = "Създаване на нов потребител" +USER_NEW_TIP = "За да добавите нов потребител, запълнете полетата със съответните данни. Моля, бъдете крайно внимателнипри избора на група за потребителя. Грешно въведената група може да ограничи достъпа на потребителя к определени раздели на сайта или обратно да разреши достъп към закритите раздели." +USER_EDIT_TITLE = "Редактиране на потребител" +USER_EDIT_TIP = "В този раздел Вие може да редактирате параметрите на потребителите, а също така да промените паролата и групата на потребителя." +USER_ERRORS = "Грешка: " +USER_FIRSTNAME = "Име на потребител" +USER_FIRSTNAME_ADD = "Въведете име на потребител" +USER_LASTNAME = "Фамилия на потребител" +USER_EMAIL = "E-mail адрес" +USER_NICK = "Ник във форума" +USER_SIGNATURE = "Подпис във форума" +USER_AVATAR = "Аватар на потребителя" +USER_TAX = "Облагане с данък" +USER_COMPANY = "Компания" +USER_HOUSE_STREET = "Улица / Номер:" +USER_ZIP_CODE = "Пощенски код:" +USER_CITY = "Град:" +USER_PASSWORD = "Парола:" +USER_PASSWORD_CHANGE = "промени" +USER_PASSWORD_SHOW = "Покажи паролата" +USER_YES = "Да" +USER_NO = "Не" +USER_COUNTRY = "Държава:" +USER_PHONE = "Телефон за контакти:" +USER_FAX = "Факс:" +USER_BIRTHDAY = "Дата на раждане:" +USER_BIRTHDAY_FORMAT = " във формат (ДД.ММ.ГГГГ)" +USER_NOTICE = "Допълнителна информация:" +USER_MAIN_GROUP = "Основна група:" +USER_SECOND_GROUP = "Допълнителна група:" +USER_SECOND_INFO = "За избор на няколко групи натиснете клавиша CTRL" +USER_STATUS = "Статус на потребителя:" +USER_ACTIVE = "Активен" +USER_INACTIVE = "Неактивен" +USER_BUTTON_ADD = "Добави потребител" +USER_SEND_INFO = "Изпрати е-майл съобщение на потребителя:" +USER_MESSAGE_SUBJECT = "Тема на съобщението:" +USER_MESSAGE_TEXT = "Текст на съобщението:" +USER_EMAIL_EXIST = "Извинете, но въведения имайл адрес вече се използва в системата." +USER_ERROR_DATEFORMAT = "Датата на раждане е въведена с грешен формат." +USER_PASSWORD_SHORT = "Въведената парола е много кратка. Моля, използвайте минимум 5 символа." +USER_PASSWORD_ERROR = "Полето Парола съдържа недопустими символи." +USER_NO_EMAIL = "Полето Имейл не е попълнено. Моля, въведете валиден имейл адрес.." +USER_NO_PASSWORD = "Полето Парола не е попълнено. Моля, въведете паролата.." +USER_EMAIL_ERROR = "Полето Имейл адрес съдържа недопустими символи. Моля, проверете въведения имейл адрес." +USER_NO_FIRSTNAME = "Полето Собствено име на потребител не е попълнено. Моля, въведете Собствено име на потребител." +USER_NO_USERNAME = "Полето Потребителско име не заполнено. Моля, въведете Потребителско име." +USER_ERROR_FIRSTNAME = "Полето Собствено име съдържа недопустими символи." +USER_ERROR_USERNAME = "Полето Потребителско име съдържа недопустими символи." +USER_NO_LASTNAME = "Полето Фамилия на потребителя не е попълнено. Моля, въведете Фамилия на потребителя." +USER_ERROR_LASTNAME = "Полето Фамилия на потребителя съдържа недопустими символи." +USER_MAIL_BODY1 = "Здравейте, %USER%,%N%%N%" +USER_MAIL_BODY2 = "Вашият акаунт е успешно активиран. Моля, използвайте вашите регистрационни данни за вход в сайта %HOST%." +USER_MAIL_FOOTER = "%N%%N%С уважение, %HOMEPAGENAME%%N%%N%%HOST%" +USER_MAIL_SUBJECT = "Вашият акаунт е активиран" +USER_MAIL_PASSWORD = "Информация за смяна на паролата" +USER_MAIL_PASSWORD2 = "Съобщение за промяна на парола.%N%%N%Вашата нова парола е: %NEWPASS%" +USER_NEW_ADD = "Създаване на нов потребител" +USER_ALL = "Списък на потребители" +USER_LOGIN = "Потребителско име в системата:" +SETTINGS_NAME = "Параметър" +SETTINGS_VALUE = "Значение" +USER_LIST_EMPTY = "не са открити потребители, съответстващи на зададените условия за търсене.
Пробвайте да промените условията за търсене." +USER_REPORT_ADD = "Добавил потребител" +USER_REPORT_EDIT = "Редактирал параметрите на потребителя" +USER_REPORT_DEL = "Изтрил потребителя" +USER_REPORT_GROUP = "Променил групата на потребителя" +USER_YOUR_NOT_CHANGE = "Грешка! Извинете, но вие нямате права за редактиране на дадения потребител." +USER_WARNING_TIP = "Внимание! Бъдете пределно внимателни при редактирането на дадения потребител." \ No newline at end of file diff --git a/admin/lang/cz/dbactions.txt b/admin/lang/cz/dbactions.txt new file mode 100644 index 0000000..1841068 --- /dev/null +++ b/admin/lang/cz/dbactions.txt @@ -0,0 +1,49 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +DB_SUB_TITLE = "Správa databáze" +DB_ACTION_WARNING = "Varování!\nVeškeré úpravy v databázi provádíte na vlastní zodpovědnost a riziko.\n\nPamatujte, že jakékoliv akce vykonané s databází mohou poškodit stávající informace.\n\n Přejete si pokračovat?\n\n" +DB_ACTION_RESET = "Varování!\nPokoušíte se otevřít databázi ze zálohy. Veškeré stávající informace budou odstraněny a přepsány.\n Berte prosím na vědomí, že po obnovení databáze bude zapotřebí znovu provést autorizaci.\n\nPřejete si pokračovat?\n\n" +DB_OPTION_LIST = "Struktura databáze." +DB_BUTTON_ACTION = "Provést akci" +DB_OPTIMIZE_DATABASE = "Optimalizace databáze." +DB_OPTIMIZE_INFO = "Tato volba umožňuje zvýšit produktivitu a snížit velikost Vaší databáze. Doporučený interval mezi optimalizacemi musí být nejméně jednou týdně." +DB_REPAIR_DATABASE = "Obnovení poškozených tabulek" +DB_REPAIR_INFO = "Tato volba umožňuje vykonat pokus o obnovení poškozených tabulek v databázi v případě chybných výstupních dat na webových stránkách." +DB_BACKUP_DATABASE = "Vytvoření zálohy" +DB_BACKUP_INFO = "Tato volba umožňuje vytvořit zálohu jak celé databáze, tak i samostatných tabulek. Vyberte prosím ze seznamu vlevo tabulky, pro které chcete vytvořit zálohu. Pro výběr vícero tabulek držte CTRL." +DB_RESTORE_TITLE = "Obnovení databáze ze zálohy" +DB_RESTORE_FILE = "Obnovení databáze ze souboru" +DB_BUTTON_RESTORE = "Obnovit" +DB_ACTION = "Vyberte akci" +DB_TIPS = "Varování! Veškeré úpravy v databázi provádíte na vlastní zodpovědnost a riziko. Pamatujte, že jakékoliv akce vykonané s databází mohou poškodit stávající informace" +DB_BACKUP_SERVER = "Uložit zálohu na serveru" +DB_SC = "Databázová operace byla úspěšně splněna." + +DB_OPTIMIZE_DATABASE_SC = "Optimalizace databáze byla úspěšně splněna." +DB_REPAIR_DATABASE_SC = "Obnovení poškozených tabulek bylo úspěšně splněno." + +DB_REPORT_DUMP = "Zálohování databáze dokončeno" +DB_REPORT_DUMP_RECOVER = "Obnovení databáze ze zálohy dokončeno" +DB_REPORT_DUMP_OPTIM = "Optimalizace databáze dokončena" +DB_REPORT_DUMP_TABLE = "Obnovení tabulek databáze dokončeno" + +DB_FILE_DATA = "Vytvořeno" +DB_FILE_SIZE = "Velikost" +DB_FILE_NAME = "Název" +DB_ACTIONS = "Akce" +DB_ACTIONS_EDIT = "Editovat" +DB_ACTIONS_DEL = "Odstranit" +DB_ACTIONS_RESTORE = "Obnovit" +DB_ACTIONS_SAVE = "Uložit do počítače" + +DB_REPORT_DUMP_DEL_OK = "Vymazat zálohu databáze" +DB_REPORT_DUMP_DEL_ER = "Nepodařilo se vymazat zálohu databáze" +DB_REPORT_DUMP_ER = "Chyba: Import databáze se nezdařil, jelikož soubor výpisu je poškozen nebo chybí." + +DB_ACTIONS_RESTORE_H = "Obnovit zálohu" +DB_ACTIONS_RESTORE_T = "Jste si jisti, že chcete obnovit zálohu databáze?" + +DB_ACTIONS_DELETE_H = "Odstanit soubor" +DB_ACTIONS_DELETE_T = "Jste si jisti, že chcete smazat zálohu databáze?" + +DB_NO_FILES_MESS = "V současné době nejsou k dispozici žádné záložní soubory databáze." diff --git a/admin/lang/cz/docs.txt b/admin/lang/cz/docs.txt new file mode 100644 index 0000000..c239e6c --- /dev/null +++ b/admin/lang/cz/docs.txt @@ -0,0 +1,260 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[Docs] +DOC_SUB_TITLE = "Správa dokumentu" +DOC_TIPS = "Zde je seznam všech dokumentů v systému. Můžete zde provádět základní operace s dokumenty::. revize , Upravení , odstranění dokumentu , a takézanechat poznámky ke každému dokumentu. " +DOC_DATE_FORMAT = "% D. M.%% Y% H:% M" +DOC_LEGEND = "Hodnoty ikon" +DOC_LEGEND_EDIT = "Upravit dokument" +DOC_LEGEND_SHOW = "zobrazit stránku v novém okně" +DOC_LEGEND_ENABLE= "aktivovat dokument" +DOC_LEGEND_DISABLE = "deaktivovat dokument" +DOC_LEGEND_TEMP_DELETE = "dočasně odstranit dokument (do koše)" +DOC_LEGEND_RESTORE = "Obnovit dokument (z koše)" +DOC_LEGEND_FINAL_DELETE = "Trvale smazat dokument" +DOC_CHOSE_RUB = "Vybrat rubriku" +DOC_ID = "ID" +DOC_URL_RUB = "URL" +DOC_TITLE = "Název dokumentu" +DOC_URL_TITLE= "Odkaz na dokument" +DOC_IN_RUBRIK = "Rubrika" +DOC_IN_NEW = "Nový dokument" +DOC_CREATED = "Publikováné" +DOC_EDIT = "Upraveno" +DOC_PRINTED= "Rozepsáné" +DOC_CLICKS = "Náhledy" +DOC_AUTHOR = "Autor" +DOC_ACTIONS = "Akce" +DOC_EDIT_TITLE = "Upravit tento dokument" +DOC_CHANGE_RUBRIC= "Přesunout dokument do jiné rubriky" +DOC_CHANGE_AUTOR = "Změna autora dokumentu" +DOC_SHOW_TITLE = "Náhled dokumentu (bez CNC Linků)" +DOC_SHOW2_TITLE= "Náhled dokumentu (s CNC Linky)" +DOC_SHOW3_TITLE = "Dokument Bez názvu" +DOC_CREATE_NOTICE_TITLE = "Zanechat poznámky" +DOC_REPLY_NOTICE_TITLE = "Podívat se / odpověďět na poznámky" +DOC_ENABLE_TITLE= "Publikovat dokument" +DOC_DISABLE_TITLE = "Stáhnout dokument z publikace" +DOC_TEMPORARY_DELETE = "Vložit dokument do koše" +DOC_RESTORE_DELETE = "Obnovit dokument z koše" +DOC_FINAL_DELETE= "Odstranit dokument" +DOC_ICON_COMMENT = "Jsou poznámky" +DOC_ICON_PUBLIC = "Dokument stažen z publikace" +DOC_ICON_RECYCLE = "Dokument přesunut do koše" +DOC_SORT_TEXT= "Řadit dokumenty za:" +DOC_TEMPORARY_CONFIRM = "Jste si jisti, že chcete vložit dokument do koše?" +DOC_FINAL_CONFIRM = "Jste si jisti, že chcete smazat tento dokument?" +DOC_INSERT_LINK_TIP = "Chcete-li vybrat požadovaný dokument, klikněte na "Vybrat"" +DOC_BUTTON_INSERT_LINK = "Vybrat" +DOC_BUTTON_LINK_POPUP = "Vyberte v novém okně" +DOC_BUTTON_ADD_DOCUMENT = "Přidat dokument" +DOC_BUTTON_ADD_DOCUMENT_NEXT = "Přidat a pokračovat v úpravách (Ctrl + S)" +DOC_BUTTON_EDIT_DOCUMENT = "Uložit změny" +DOC_BUTTON_EDIT_DOCUMENT_NEXT = "Použít (Ctrl + S)" +DOC_ADD_DOCUMENT = "Přidávání nového dokumentu" +DOC_EDIT_DOCUMENT = "editování dokumentu" +DOC_OPTIONS = "Nastavení dokumentu" +DOC_NAME = "Název dokumentu:
(HTML < title>) " +DOC_URL = "Pseudonym dokumentu:
(SEO alias) " +DOC_URL_LINK = "Nahrazení pseudonymů" +DOC_URL_INFO = " Chcete-li, aby odkaz na dokument vypadal následovně:
http://www.domain.tld/phone/samsung/
piště do tohoto pole: phone/samsung

přípona odkazu je automaticky přidána na výstupu
spolu s uvedeným nastavením inc / config.php

V názvu je povolena:
AZ - latinka;
а-я - azbuka (je-li povoleno) ;
/ - lomítko;
-- pomlčka
_ - podtržení

název odkaz by neměl obsahovat:.
tisk / nebo / print / nebo / print;
page-XX / nebo / page-XX / nebo / page-XX;
apage-XX / nebo / apage-XX / nebo / apage-XX;
artpage-XX / nebo / artpage-XX / nebo / artpage-XX;
kde XX - čísla " +DOC_URL_LOG = "Využívat historii pseudonymů pro přesměrování" +DOC_URL_LOG_T = "Ukládat nebo neukládat historii pseudonymů dokumentu pro příští přesměrování" +DOC_URL_LOG_RUBRIC = "Využívat nastavení rubrik" +DOC_URL_LOG_USE = "vždy" +DOC_FIELD_G_UNKNOW = "Bez skupiny" +DOC_PROPERTY = "Nastavení dokumentu" +DOC_URL_LOG_NOTUSE= "Nepoužívat" +DOC_QUERIES = "Dostupné požadavky:" +DOC_META_TITLE = "TITLE - řádek, který se zobrazí v záhlaví okna prohlížeče, tento tag je důležitý pro optimalizaci pro vyhledávače, protože umožňuje ovládat systém, stejně jako některými jinými tagy." +DOC_META_KEYWORDS= "Klíčová slova:
(meta keywords) " +DOC_META_KEYWORDS_INFO = " Popisuje obsah stránky, mohou se započítat vyhledávacími systémy.

Některá z klíčových slov, musí být přítomen v textu na stránce. " +DOC_META_DESCRIPTION= "Popis stránky:
(meta description) " +DOC_META_DESCRIPTION_INFO = "Malý text, který popisuje obsah stránky, může se také započítat do vyhledávače, zobrazeny jako vysvětlení ve výsledcích vyhledávání nebo internetových adresářů." +DOC_CAN_SEARCH= "Povolit hledání dokumentu:
(vyhledávání modulu) " +DOC_INDEX_TYPE = "Typ indexování stránky:
(meta robots) " +DOC_INDEX_FOLLOW= "Indexovat a přecházet na odkaz" +DOC_INDEX_NOFOLLOW = "index, ale nepřecházet na odkaz" +DOC_NOINDEX_NOFOLLOW = "Neindexovat a nepřecházet na odkaz" +DOC_SITEMAP_FREQ= "Obnovovací frekvence
sitemap.xml " +DOC_SITEMAP_FREQ_DOC = "Obnovovací frekvence stránky" +DOC_SITEMAP_ALWAYS = "Vždy" +DOC_SITEMAP_HOURLY = "Každou hodinu" +DOC_SITEMAP_DAILY = "Denně" +DOC_SITEMAP_WEEKLY = "Každý týden" +DOC_SITEMAP_MONTHLY = "Každý měsíc" +DOC_SITEMAP_YEARLY = "Ročně" +DOC_SITEMAP_NEVER = "Nikdy" +DOC_SITEMAP_PRIORITY = "Priority
sitemap.xml " +DOC_SITEMAP_PRIORITY_DOC = "Priority této stránky co se týče srovnání s jinými stránkami" +DOC_SITEMAP_PRIORITY_LOW = "nejnižší priorita" +DOC_SITEMAP_PRIORITY_MID = "Střední priorita" +DOC_SITEMAP_PRIORITY_HIG = "nejvyšší priorita" +DOC_START_PUBLICATION = "Start publikování:" +DOC_END_PUBLICATION = "Konec publikování" +DOC_STATUS = "Stav dokumentu" +DOC_STATUS_ACTIVE= "Aktivní" +DOC_STATUS_INACTIVE = "neaktivní" +DOC_ADD_IN_NAVIGATION = "Přidat podmenu" +DOC_USE_NAVIGATION = "Svázat s bodem menu" +DOC_USE_RUB_ALIAS= "Nahrazování pseudonymů nadřazených dokumentů, přiřazení nadřazený dokument pro drobečkovou navigaci." +DOC_USE_BREADCRUMB = "Svázat s dokumentem
(můžete využít pro drobečkovou navigaci) " +DOC_USE_LANG_PACK = "Svázat s dokumentem z jazykové skupiny" +DOC_NAVIGATION_INFO = "Chcete-li propojit dokument s bodem z menu, vyberte ze seznamu existující položky menu. Chcete-li dočasně připojit dokument z menu, ponechte pole prázdné." +DOC_MAIN_CONTENT = "Hlavní náplň dokumentu" +DOC_MAIN_NOCONTENT = "Žádná pole pro dokument" +DOC_AFTER_CREATE_TITLE = "Další kroky" +DOC_AFTER_CREATE_INFO = "Vyberte další kroky ze seznamu:" +DOC_EDIT_THIS_DOCUMENT= "Zpět k úpravám dokumentu" +DOC_INCLUDE_NAVIGATION = "Přidat vytvořený dokument do navigačního menu" +DOC_ADD_NEW_DOCUMENT = "Vložit nový dokument do této rubriky" +DOC_ADD_COPY_DOCUMENT = "Vložit kopii dokument do této rubriky" +DOC_DISPLAY_NEW_WINDOW= "Náhled v novém okně (Ctrl + O)" +DOC_CLOSE_WINDOW = "Přejít k seznamu dokumentů" +DOC_CLOSE_WINDOW_RUBRIC = "Přejít do seznamu dokumentů této rubriky" +DOC_TO_NAVI_TITLE = "Přidávání dokumentu v navigačním menu" +DOC_NAVIGATION_POSITION = "pozici v seznamu" +DOC_NAVIGATION_TITLE = "název bodu menu" +DOC_TARGET = "Otevírat" +DOC_TARGET_SELF = "ve stejném okně" +DOC_TARGET_BLANK = "V novém okně" +DOC_BUTTON_ADD_MENU = "Přidat do menu" +DOC_TOP_MENU_ITEM = "Nový bod prvního úrovně" +DOC_NOTICE = "Poznámky k dokumentu" +DOC_NOTICE_NEW_LINK = "Přidat novou poznámku" +DOC_NOTICE_AUTHOR = "Vložit:" +DOC_NOTICE_DELETE_LINK = "Smazat poznámku" +DOC_ALLOW_NOTICE = "Povolit komentář poznámek" +DOC_BUTTON_NOTICE = "Splnit" +DOC_NOTICE_TITLE = "Záhlaví" +DOC_NOTICE_TEXT= "Poznámka:" +DOC_BUTTON_ADD_NOTICE = "Přidat poznámku" +DOC_SEND_NOTICE_INFO = "Chcete-li přidat novou poznámku k dokumentu, vyplňte pole ve formuláři níže." +DOC_NEW_NOTICE_TITLE= "Přidat novou poznámku" +DOC_MAIL_BODY_CHECK = "Uživatel %USER% přidal nový dokument s názvem '%TITLE%'. %N% Zkontrolujte dokument před zveřejněním. " +DOC_MAIL_SUBJECT_CHECK = "Přidán nový dokument" +DOC_MAIL_BODY_USER = "Vítejte %USER%.%N% Úspěšně vytvořen dokument byl přidán do oznámení, Administrátor byl uvědoměn a po prověření bude publikován." +DOC_MAIL_SUBJECT_USER = "Váš dokument byl podán, čeká na ověření." +DOC_MAIL_BODY_NOTICE = "Uživatel %USER% přidal novou poznámku k dokumentu. %N% Přihlaste se do ovládacího panelu a klikněte na odkaz níže pro zobrazení poznámky:%N%%LINK%" +DOC_MAIL_SUBJECT_NOTICE = "Přidána nová poznámka k dokumentu" +DOC_NEW_PAGE = "Přidat novou stránku" +DOC_CLOSE_HELP_WINDOW = "

" +DOC_HELP= "Pomoc" +DOC_VIDEO_TYPE_HELP = " Vložit video souboru
Když přidáte video soubor, můžete určit šířku a výšku okna pro zobrazení videa. První hodnota určuje šířku okna, druhý výšku.

Například:

video.avi | 300 | 300

nebo video.avi | 100% | 300 " +DOC_FLASH_TYPE_HELP = " Vložení Flash filmu
Když přidáte Flash videa můžete určit šířku a výšku okna pro zobrazení. První hodnota určuje šířku, druhá výšku.

Například:..

flash.swf | 300 | 300

nebo flash.swf | 100% | 300 " +DOC_FILE_TYPE_HELP= " Vložení souborů
Když přidáte soubor, můžete zadat název odkazu. Je nutné zadat distributorský znak. |. a poté zadat název odkazu

například:

file.zip | Nahrát soubor " +DOC_NO_PERMISSION = "Je nám líto, ale nemáte oprávnění k úpravě tohoto dokumentu." +DOC_NO_PERMISSION_RUB = "Je nám líto, ale nemáte oprávnění k vytvoření dokumentu v této rubrice." +DOC_NO_DEL_REVISION = "Je nám líto, ale nemáte oprávnění k odstranění revize." +DOC_NO_RES_REVISION = "Je nám líto, ale nemáte oprávnění k obnovení revize." +DOC_EDIT_RUB = "Přesunout do jiné rubriky" +DOC_RUBRIC = "Rubrika" +DOC_SORT_RUB = "Uspořádat podle rubriky" +DOC_IMAGE = "Obrázky ve zprávách" +DOC_IMAGE_MAX_W = "Maximální šířka" +DOC_IMAGE_MAX_H = "Maximální výška" +DOC_INTRO= "Teaser
(text ve zprávách)" +DOC_ALIAS_CREATE = "Zformovat" +DOC_ENTER_NAME = "Vyberte rubriku, do které chcete přidat nový dokument." +DOC_SORT_NAME= "Vyberte prosím rubriku." +DOC_OR = "& nbsp; nebo & nbsp;" +DOC_NO_DOCS = " Dokumenty, které splňují tato kritéria, neexistují." +DOC_COPY= "Kopírovat dokument" +DOC_COPY_DOCUMENT = "kopírování dokumentu" +DOC_COPY_TIP = "Uveďte prosím název dokumentu" +DOC_ADD_NEW_LIGHT_TIP= "Chcete-li přidat nový dokument, vyberte rubriku." +DOC_ADD_NEW_LIGHT_ADD = "Přidávání dokumenti" +DOC_ADD_NEW_LIGHT_BTN = "Přidat dokument" +DOC_CHANGE_TITLE= "Převod dokumentů do jiné rubriky" +DOC_CHANGE_INFO = " Důležité! Pokud změníte rubriku, pole, které nebyly přeneseny, budou ztraceny!" +DOC_CHANGE_OLD_FIELD = "Pole dokumentu" +DOC_CHANGE_NEW_FIELD= "Přesunout do nového" +DOC_CHANGE_DROP_FIELD = "--nepřenášet--" +DOC_CHANGE_CREATE_FIELD = "-- vytvořit nový --" +DOC_CHANGE_BUTTON = "změnit" +DOC_CHANGE_AU_TITLE = "Změna autora dokumentu" +DOC_CHANGE_AU_INFO = " Důležité! Pokud změníte autora, předchozí autor může být zbaven práv upravovat dokument." +DOC_CHANGE_BUTTON = "Uložit" +DOC_IN_MENU = "do menu" +DOC_REVISSION= "Historie změn" +DOC_REVISSION_DATA = "Datum a čas změny" +DOC_REVISSION_USER = "Autor" +DOC_REVISSION_VIEW = "Náhled verze" +DOC_REVISSION_RECOVER= "Obnovit verzi" +DOC_REVISSION_RECOVER_T = "Opravdu chcete obnovit tuto verzi?" +DOC_REVISSION_DELETE = "Odstranit verzi" +DOC_REVISSION_DELETE_T= "Jste si jisti, že chcete smazat tuto verzi?" +DOC_REVISSION_NO_ITEMS = "Žádná data" +DOC_URL_ERROR_SYMBOL = "Neplatné znaky" +DOC_URL_ERROR_START = "začíná z /" +DOC_URL_ERROR_END= "Končí na/ (přípona URL začíná na /)" +DOC_URL_ERROR_SEGMENT = "Neplatné segmenty" +DOC_URL_ERROR_EMTY = "Nic k ověření" +DOC_URL_ERROR_DUPLICATES= "Přezdívka se již používá" +DOC_URL_H_ERROR_DUPLICATES = "Přezdívka se již používá v historii pseudonymů" +DOC_URL_CHECK_OK = "Toto URL může být použito" +DOC_URL_CHECK_ER= "URL obsahuje chyby:
" +DOC_REQUEST_NOT_INFO = "Chybí popis požadavku." +DOC_REVISION_DELETE = "Verze dokumentu odstraněna" +DOC_REVISION_RECOVER= "Verzi dokumentu obnovena" +DOC_BREADCRUMB_BTN = "Vybrat" +DOC_BREADCRUMB_TITLE = "Název odkaz v drobečkové navigaci" +DOC_BREADCRUMB_WITH = "Souvisí s" +DOC_DOCUMENT_OPEN= "Dokument zveřejněn" +DOC_DOCUMENT_CLOSE = "Dokument stažen z publikace" +DOC_DOCUMENT_DOC = "Dokument" +DOC_DOCUMENT_ACT = "Publikoval" +DOC_DOCUMENT_DISACT= "Odstraněno z publikace" +DOC_DOCUMENT_OPEN_ERR = "Tento dokument nemůže být neaktivní!" +DOC_DOCUMENT_OPEN_PRIVE = "K tomuto nemáte oprávnění!" +DOC_ACTION_SELECT = "Akce se zvolenými" +DOC_ACTION_SELECT_ACT= "Aktivní" +DOC_ACTION_SELECT_NACT = "Neaktivní" +DOC_ACTION_SELECT_TRASH = "dočasně odstraněny" +DOC_ACTION_SELECT_OUTTRASH = "Obnovit" +DOC_ACTION_SELECT_DEL = "Odstranit" +DOC_ACTION_BUTTON = "Uložit změny" +DOC_CHOOSE_LANG= "Výběr jazyka dokumentu" +DOC_LANG_VERSION = "Verze dokumentu v jiných jazycích" +DOC_LINK_CHOOSE = "Zvolte Dokument" +DOCUMENT_SAVED = "Dokument byl úspěšně uložen" +DOC_REV_DELETED = "Revize dokumenty úspěšně odstraněn" +DOC_REV_DELETED_ERR = "Nepodařilo se smazat revizi.
Zkuste znovu." +DOC_REV_ERROR = "Chyba" +DOC_REV_SUCCESS= "Hotovo" +DOC_REV_UPDATE = "Revize dokumentů odstraněny" +DOC_ALIASES = "Správce přesměrování dokumentů"DOC_ALIASES_LIST_N= "Název dokumentu" +DOC_ALIASES_LIST_RB = "Rubrika" +DOC_ALIASES_LIST_CH = "Změněno" +DOC_ALIASES_LIST_CR = "Množství" +DOC_ALIASES_LIST_AT = "Akce" +DOC_ALIASES_TITLE= "Zde je seznam všech dokumentů, ve kterých jsou vnitřní přesměrování.
Můžete provádět základní operace s dokumenty, jako je prohlížení, editaci, mazání, či přesměrování." +DOC_ALIASES_BREAD_RUB = "Rubrika" +DOC_ALIASES_BREAD_DOC = "Dokument" +DOC_ALIASES_BREAD_URL = "Hlavní URL" +DOC_ALIASES_DOC_LIST = "Seznam dokumentů s přesměrováním" +DOC_ALIASES_ADD = "Přidat nové přesměrování" +DOC_ALIASES_ADD_VAL = "Hodnota přesměrování" +DOC_ALIASES_LIST = "Seznam přesměrování" +DOC_ALIASES_LIST_EMPT = "Prázdný seznam" +DOC_ALIASES_TABL_H_URL= "Alias ​​přesměrování" +DOC_ALIASES_TABL_H_ADD = "Vloženo" +DOC_ALIASES_TABL_H_AUT = "Autor" +DOC_ALIASES_TABL_CHECK = "Zaškrtněte tuto možnost pro odstranění" +DOC_ALIASES_GO= "Přejít k přesměrování" +DOC_ALIASES_DEL_T = "Odstranit alias" +DOC_ALIASES_DEL_C = "Jste si jisti, že chcete smazat alias?" +DOC_ALIASES_BUTT_DEL = "Odstranit" +DOC_ALIASES_BUTT_CLO = "Zavřít okno" +DOC_ALIASES_BUTT_APP= "Použít" +DOC_ALIASES_BUTT_CNL = "Zrušit" +DOC_ALIASES_BUTT_SAV = "Uložit" +DOC_ALIASES_BUTT_ADD = "Vložit" +DOC_ALIASES_REP_OK = "Hotovo" +DOC_ALIASES_REP_OK_T = "Přesměrování úspěšně přidáno" +DOC_ALIASES_REP_OK_T_E= "Přesměrování úspěšně obnoveno" +DOC_ALIASES_REP_ER = "Chyba" +DOC_ALIASES_REP_ER_T = "NEpodařilo se přidat přesměrování. Zkuste znovu." +DOC_ALIASES_REP_ER_T_E = "Nepodařilo se aktualizovat přesměrování. Zkuste znovu." +DOC_RUBRIC_TMPLS= "Vyberte šablonu rubriky" +DOC_RUBRIC_TMPLS_HINT = "Můžete nastavit dokument pro výstup, jakoukoliv šablonu z této rubriky" diff --git a/admin/lang/cz/groups.txt b/admin/lang/cz/groups.txt new file mode 100644 index 0000000..af4654d --- /dev/null +++ b/admin/lang/cz/groups.txt @@ -0,0 +1,121 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[groups] +UGROUP_TITLE = "Správce skupin uživatelů" +UGROUP_TITLE2 = "Správce skupiny uživatelů" +UGROUP_TITLE_MENU = "Skupina uživatelů" +UGROUP_INFO = " Zde je seznam všech skupin uživatelů v systému. Každé skupině můžete přiřadit osobní práva, která dovolují, či omezují, akce užvatelů, a to jak v Ovládacích panelech, tak i na veřejné části stránek." +UGROUP_ID = "ID" +UGROUP_NAME = "Název skupiny" +UGROUP_COUNT = "Uživatelé ve skupině" +UGROUP_ACTIONS = "Akce" +UGROUP_IN_GROUP = "Zobrazit seznam uživatelů patřící do této skupiny" +UGROUP_EDIT = "Upravit název a práva skupiny" +UGROUP_NO_PERMISSION = "Je nám líto, nemáte dostatečná práva k provádění úprav." +UGROUP_DELETE = "Smazat skupinu" +UGROUP_USERS_IN_GROUP = "V současné době nelze smazat skupinu, jelikož ve skupině jsou stále přiřazení uživatelé." +UGROUP_DELETE_CONFIRM = "Opravdu chcete smazat skupinu?" +UGROUP_NO_DELETABLE = "Nelze smazat systémovou skupinu." +UGROUP_NO_PERM_DELETE = "Je nám líto, nemáte dostatečná práva ke smazání skupiny." +UGROUP_NEW_GROUP = "Přidat novou skupinu" +UGROUP_NEW_NAME = "Název skupiny:" +UGROUP_BUTTON_ADD = "Přidat" +UGROUP_LEGEND_LINK = "Hodnota ikony" +UGROUP_LEGEND_EDIT = "Upravit skupinu uživatelů" +UGROUP_LEGEND_DELETE = "Odstranit skupinu uživatelů" +UGROUP_ENTER_NAME = "Zadejte prosím název skupiny uživetelů" +UGROUP_WARNING_TIP = "Varování! Buďte opatrní při udělování práv této skupině uživatelů. Pamatujte, že umožňujete přístup do úseků, které mohou způsobit nestabilitu systému." +UGROUP_YOUR_NOT_CHANGE = "Chyba! Je nám líto, nemáte dostatečná práva k provádění úprav této skupiny uživatelů." +UGROUP_NOT_EXIST = "Chyba! Je nám líto, ale skupina, kterou hledáte, neexistuje. " +UGROUP_NO_MODULES = "Nejsou nainstalované moduly" +UGROUP_MODULES_RIGHT = " Zadejte prosím moduly, do kterých budou mít uživatelé přístup." +UGROUP_CONTROL_RIGHT = "Zadejte prosím oddíly Ovládacích panelů, ke kterým bude povolen, či zakázán, přístup pro tuto skupinu uživatelů." +UGROUP_BUTTON_SAVE = "Uložit změny" +UGROUP_BUTTON_SAVE_AJAX = "Použít(CTRL+S)" +UGROUP_SAVE_CONFIRM = "Opravdu chcete uložit práva pro tuto skupinu uživatelů?" +UGROUP_NAME_EDIT = "Upravit název skupiny" +UGROUP_OR = "nebo" +UGROUP_SAVED = "Práva skupiny úspěšně uložena" +UGROUP_SAVED_ERR = "Nepodařilo se uložit změny.
Zkuste znovu." +UGROUP_ERROR = "Chyba" +UGROUP_SUCCESS = "Hotovo" +UGROUP_SAVE_MAIN = "Práva pro skupinu změnena" + +UGROUP_REPORT_ADD = "Skupina uživetelůp vytvořena" +UGROUP_REPORT_DEL = "Skupina uživatelů smazána" + +alles = "Povolit všechna práva (Pozor!)" +adminpanel = "Přístup k Ovládacímu panelu" + +gen_settings = "Přístup k obecným nastavením systému" +gen_settings_more = "Přístup k pokročilým nastavením systému +gen_settings_countries = "Přístup k nastavení seznamu zemí." +gen_settings_languages = "Přístup k nastavení jazyků" + +logs_view = "Přístup k zobrazení systémových zpráv." +logs_clear = "Přístup k odstranění systémových zpráv" + +db_actions = "Přístup ke správě databáze (Zálohování, obnovení, aktualizace)" + +modules_view = "Přístup k seznamu modulů" +modules_admin = "Přístup k modulům (Nastavení, správa, použití)" +modules_system = "Přístup ke správě modulů (smazání, instalace)" + +navigation_view = " Přístup k seznamu navigačního menu" +navigation_edit = "Přístup ke správě navigačního menu (Vytvoření, úprava, odstranění)" + +remark_view = "Přístup k poznámkám" +remark_edit = " Přístup ke správě poznámek v dokumentech(Vytvoření, úprava, odstranění)" + +document_php = "Přístup k využití PHP kódu v dokumentech(Pozor!)" +document_view = "Přístup k seznamenu dokumentů (práva k přístupu k dokumentům závisí od nastavení rubriky)" +document_revisions = "Přístup k odstranění všech revizí dokumentů" + +rubric_view = "Přístup k zobrazení seznamu rubrik" +rubric_edit = "Přístup ke správe rubrik (Vytvoření, úprava, odstranění)" +rubric_php = "Přístup k využití PHP kódu v šablonách rubrik(Pozor!)" +rubric_perms = "Přístup ke správě přístupu k dokumentům rubriky" +rubric_code = "Přístup ke spustitelným částem kódu(Pozorі!)" + +template_view = "Přístup k setnamu šablon" +template_edit = "Přístup ke správě šablon (Stvoření, úprava, odstranění)" +template_php = "Přístup k využití PHP kodu v šablonách (Pozorі!)" + +request_view = "Přístup k seznamu požadavků" +request_edit = "Přístup ke správě požadavků (Vytvoření, úprava, odstranění)" +request_php = "Přístup k využití PHP kodu v šablonách požadavků (Pozor!)" + +sysblocks_view = "Přístup k zobrazení seznamu systémových bloků" +sysblocks_edit = "Přístup k řízení systémových bloků (Vytvoření, úprava, odstranění)" + +user_view = "Přístup k seznamu uživatelů" +user_edit = " Přístup k úpravě parametrů uživatelůД" +user_perms = "Přístup ke správě práv uživatelů" + +group_view = "Přístup k seznamu skupin uživatelů" +group_edit = "Přístup ke správe práv skupin uživatelů (Vytvoření, úprava, odstranění)" + +mediapool_int = "Přístup k Správce dokumentů" +mediapool_add = "Přístup k přidávání nových souborů na server (ve Správci dokumentů)" +mediapool_del = " Přístup k odstranění souborů ze serveru(ve Správci dokumentů)" +mediapool_finder = "Přístup ke Správci dokumentů (elFinder)" + +cache_clear = "Přístup ke smazání chache" +cache_thumb = " Přístup ke smazání preview zobrazení(thumbnail)" + +logs = "Systémové zprávy" +cache = "Správa cache" +gen = "Systémová nastavení" +db = "Databáze" +sysblocks = "Systémové bloky" +rubric = "Rubriky" +document = "Dokumenty" +modules = "Moduly" +mediapool = "Správce souborů" +navigation = "Navigace" +request = "Požadavky" +template = "Šablony" +remark = "Poznámky dokumentů" +document = "Dokumenty" +user = "Uživatelé" +group = "Uživatelské skupiny" \ No newline at end of file diff --git a/admin/lang/cz/logs.txt b/admin/lang/cz/logs.txt new file mode 100644 index 0000000..a289b34 --- /dev/null +++ b/admin/lang/cz/logs.txt @@ -0,0 +1,55 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[logs] +LOGS_SUB_TITLE = "Správce systémových zpráv" +LOGS_TITLE = "Systémový protokol" +LOGS_TIP = "Zde je seznam všech činností, které se provádí v Ovládacím panelu." +LOGS_ID = "№" +LOGS_IP = "IP-adresa" +LOGS_DATE = "Data" +LOGS_USER = "Uživatel" +LOGS_ACTION = "Akce" +LOGS_BUTTON_DELETE = "Smazat protokol" +LOGS_DELETE_CONFIRM = "Jste si jistí, že chcete vymazat protokol systémových zpráv?" +LOGS_BUTTON_EXPORT = "Export protokolu systémových zpráv" +LOGS_BUTTON_EXPORT_404 = "Export chybového protokolu 404" +LOGS_DATE_FORMAT = "%d.%m.%y g." +LOGS_DATE_FORMAT2 = "%H:%M" +LOGS_IN = "v" +LOGS_CLEAR = "Systémové zprávy úspěšně smazány." +LOGS_CLEAN = "Protokol událostí smazán" +LOGS_EXPORT = "Protokol událostí exportován" + +LOGS_404_SUB_TITLE = "Protokol chyb 404" +LOGS_404_TITLE = "Protokol chyb 404" +LOGS_404_TIP = "Zde je seznam všech chyb 404" +LOGS_404_ID = "№" +LOGS_404_IP = "IP-adresa" +LOGS_404_DATE = "Datum" +LOGS_404_ACTION = "Akce" +LOGS_404_BUTTON_DELETE = "Smazat protokol" +LOGS_404_DELETE_CONFIRM = "Opravdu si přejete vymazat protokol chyb 404?" +LOGS_404_BUTTON_EXPORT = "Export protokolu chyb" +LOGS_404_DATE_FORMAT = "%d.%m.%y g." +LOGS_404_DATE_FORMAT2 = "%H:%M" +LOGS_404_IN = "v" +LOGS_404_CLEAR = "Systémové zprávy úspěšně smazány." +LOGS_404_CLEAN = "Protokol chyb 404 smazán" +LOGS_404_EXPORT = "Protokol chyb 404 exportován" + +LOGS_SQL_SUB_TITLE = "Protokol MySQL chyb" +LOGS_SQL_TITLE = "Protokol MySQL chyb" +LOGS_SQL_TIP = "Zde je seznam všech MySQL chyb." +LOGS_SQL_ID = "№" +LOGS_SQL_IP = "IP-adresa" +LOGS_SQL_DATE = "Datum" +LOGS_SQL_ACTION = "Akce" +LOGS_SQL_BUTTON_DELETE = "Smazat protokol MySQL chyb" +LOGS_SQL_DELETE_CONFIRM = "Opravdu si přejete smazat protokol MySQL chyb?" +LOGS_SQL_BUTTON_EXPORT = "Export protokolu MySQL chyb" +LOGS_SQL_DATE_FORMAT = "%d.%m.%y g." +LOGS_SQL_DATE_FORMAT2 = "%H:%M" +LOGS_SQL_IN = "v" +LOGS_SQL_CLEAR = "Protokol chyb MySQL úspěšně smazán." +LOGS_SQL_CLEAN = "Protokol MySQL chyb smazán" +LOGS_SQL_EXPORT = "Protokol MySQL chyb exportován" \ No newline at end of file diff --git a/admin/lang/cz/main.txt b/admin/lang/cz/main.txt new file mode 100644 index 0000000..55194ec --- /dev/null +++ b/admin/lang/cz/main.txt @@ -0,0 +1,302 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +MAIN_WELCOME = "Vítejte v Ovládacích panelech!" +MAIN_WELCOME_INFO = "Na hlavní stránce si můžete vybrat jednu z nejčastěji prováděných akcí." + +MAIN_PAGE = "Hlavní strana" + +MAIN_LOGIN_INTRO = "Autorizace" +MAIN_LOGIN_BACK_SITE = "Návrat na stránku" +MAIN_LOGIN_NAME = "Login:" +MAIN_LOGIN_PASSWORD = "Heslo:" +MAIN_LOGIN_BUTTON = "Vejít" +MAIN_LOGIN_REGISTER = "Registrace" +MAIN_LOGIN_LOST = "Zapomněli jste heslo?" +MAIN_LOGIN_HELP = "Nápověda" +MAIN_LOGIN_REMEMBER = "Zapamatovat si mně" +MAIN_LOGIN_CAP_CODE = "Kód:" +MAIN_LOGIN_CAP_CODE_REF = "Update kódu:" +MAIN_LOGIN_CAP_CODE_REFR = "Update kódu" + +MAIN_LINK_HOME = "Hlavní menu" +MAIN_LINK_AUTHOR = "Stránka podpory" +MAIN_LINK_DATABASE = "Správce databáze" +MAIN_LINK_NAVIGATION = "Správce navigačního menu" +MAIN_LINK_MODULES = "Správce modulů" +MAIN_LINK_MODULES_H = "Moduly" +MAIN_LINK_SETTINGS = "Správce nastavení" +MAIN_LINK_SETTINGS_H = "Nastavení" +MAIN_LINK_USERS = "Správce uživatelů" +MAIN_LINK_TEMPLATES = "Správce šablon" +MAIN_LINK_RUBRICS = "Správce rubrik" +MAIN_LINK_DOCUMENT = "Správce dokumentů" +MAIN_LINK_QUERYES = "Správa požadavků" +MAIN_LINK_GROUPS = "Správce skupin" +MAIN_LINK_LANG = "Správa jazyků" + +MAIN_BUTTON_LOGIN = "Vejít" +MAIN_BUTTON_ADD = "Přidat" +MAIN_BUTTON_LOGOUT = "Odejít" + +MAIN_SETTINGS_EDIT_1 = "Obecná nastavení" +MAIN_SETTINGS_EDIT_2 = "Pokročilá nastavení" +MAIN_SETTINGS_EDIT_3 = "Správce zemí" +MAIN_SETTINGS_EDIT_4 = "Vytvořit zálohu BD" + +MAIN_LINK_DOC_TIPS = "Zde je seznam všech dokumentů v systému." +MAIN_LINK_RUBRIK_TIP = "Zde je seznam všech rubrik v systému." +MAIN_LINK_REQUEST_TIP = "Zde je seznam všech existujících požadavků v systému." +MAIN_LINK_NAVI_TIP = "Zde je seznam všech navigačních menu v systému." +MAIN_LINK_TEMPLATES_TIP = "Zde je seznam všech šablon použitých v systému." +MAIN_LINK_MODULES_TIP = "Zde je seznam všech dostupných modulů v systému." +MAIN_LINK_SETTINGS_TIP = "Zde jsou všechny globální parametry systému." +MAIN_LINK_DB_TIP = "Zde můžete pracovat s databázovým systémem." +MAIN_LINK_USER_TIP = "Zde je seznam všech uživatelů v systému." +MAIN_LINK_UGROUP_TIP = "Zde je seznam všechny skupiny uživatelů v systému." + +MAIN_PAGE_TITLE = "Ovládací panely" +MAIN_LOGIN_TEXT = "Autorizace" +MAIN_LOGIN_TEXT2 = "Zadejte prosím své údaje:" +MAIN_LOGIN_CAPTCHA = "Zadejte kód:" +MAIN_SELECT_LANGUAGE = "Jazyk:" +MAIN_SELECT_THEME = "Téma designu:" +MAIN_YOUR_EMAIL = "E-mail:" +MAIN_YOUR_LOGIN = "Login nebo e-mail:" +MAIN_YOUR_PASSWORD = "Heslo:" + +MAIN_LINK_SITE = "Náhled stránky" +MAIN_LINK_HOME = "Na hlavní" +MAIN_LINK_LOGOUT = "Ukončit práci s Ovládacím panelem" +MAIN_LINK_LOGOUT_QUEST = "Opravdu chcete ukončit?" +MAIN_LINK_CACHE_CLEAR = "Čištění Cache" +MAIN_LINK_CACHE_CLEAR_QUEST = "Opravdu chcete vyprázdnit mezipaměť?" + +MAIN_LINK_SITE_ON = "Zapnout editor" +MAIN_LINK_SITE_OFF = "Vypnout editor" + +MAIN_LINK_EDIT = "Editovat stránku" +MAIN_ADD_IN_RUB = "Vložit nový dokument:" +MAIN_DOCUMENTS_ALL = "Seznam dokumentů:" +MAIN_SEARCH_DOCUMENTS = "Hledat dokumenty:" +MAIN_SORT_DOCUMENTS = "Rychlý výběr:" +MAIN_TIME_PERIOD = "Perioda publikace" +MAIN_TIME_START = "Počátek" +MAIN_TIME_END = "Konec" +MAIN_BUTTON_SEARCH = "Hledat" +MAIN_TITLE_SEARCH = "Název dokumentu:" +MAIN_TITLE_DOC_NAME = "Název dokumentu" +MAIN_TITLE_DOC_ID = "ID dokumentu" +MAIN_SEARCH_HELP = Využití vyhledávače

Použijte znak "+" дpro rychlé vložení slova do vyhledávače.
Použijte znak "-" pro vylouření slova z vyhledávání

je nutné využít mezery před znaky "+" a "-"." +MAIN_ID_SEARCH = "ID dokumentu:" +MAIN_SELECT_RUBRIK = "V rubrice:" +MAIN_ALL_RUBRUKS = "Všechny rubriky" +MAIN_ALL_DOCUMENTS = "Jakýkoli status" +MAIN_DOCUMENT_STATUS = "Status dokumentu" +MAIN_DOCUMENT_ACTIVE = "Pouze aktivní" +MAIN_DOCUMENT_INACTIVE = "Pouze neaktivní" +MAIN_TEMP_DELETE_DOCS = "Dočasně odstraněn" +MAIN_RESULTS_ON_PAGE = "Výsledky na stránce:" +MAIN_OPEN_MEDIAPATH = "Náhled na serveru" +MAIN_NAVI_UGROUPS = "Uživatelské skupiny" +MAIN_UGROUP_EDIT = "Upravit práva skupiny" +MAIN_UGROUP_DELETE = "Odstranit skupinu" +MAIN_LOGS = "Systémové události" +MAIN_NAVI_MODULES = "Správce modulů" +MAIN_NAVIGATION = "Menu navigace" +MAIN_NAVIGATION_NEW = "Přidat nové menu" +MAIN_QUERIES = "Požadavky" +MAIN_REQUEST_NEW = "Přidat nový požadavek" +MAIN_RUBRIKS = "Rubriky" +MAIN_RUBRIK_NEW = "Přidat novou rubriku" +MAIN_RUBRIK_EDIT_FIELDS = "Upravit pole rubriky" +MAIN_RUBRIK_EDIT_TEMPL = "Upravit šablonu rubriky" +MAIN_SETTINGS = "Nastavení systému" +MAIN_COUNTRY_EDIT = "Správce zemí" +MAIN_SYSBLOCKS = "Systémové bloky" +MAIN_TEMPLATES = "Šablony" +MAIN_TEMPLATES_NEW = "Přidat novou šablonu" +MAIN_USERS = "Uživatelé" +MAIN_DATABASE_INFO = "Databáze" +MAIN_NAVI_DOCUMENTS = "Dokumenty" +MAIN_BROWSE_DOCUMENTS = "Zobrazit v dokumentech" +MAIN_USERS_LIST = "Seznam uživatelů" +MAIN_USER_ADD = "Přidat nového uživatele" +MAIN_SEARCH_USERS = "Hledání uživatelů přes:" +MAIN_USER_PARAMS = "Jméno, ID, E-mail, e-mailovou doménu" +MAIN_USER_STATUS = "Se statusem:" +MAIN_USER_STATUS_ALL = "Jakýkoli status" +MAIN_USER_STATUS_ACTIVE = "Aktivní" +MAIN_USER_STATUS_INACTIVE = "Očekává aktivaci" +MAIN_USER_GROUP = "Je ve skupině:" +MAIN_USER_ONLINE = "Vítejte," +MAIN_USER_PERM = "Status:" +MAIN_ALL_USER_GROUP = "Jakýkoli" +MAIN_BUTTON_SEARCH_USER = "Najít uživatele s parametry" +MAIN_NO_PERMISSION = "Je nám líto, ale k tomuto nemáte oprávnění" +MAIN_LOGOUT_CONFIRM = "Opravdu chcete skončit?" + +MAIN_START_DOC_TITLE = "Poslední dokumenty" +MAIN_START_DOC_ID = "ID" +MAIN_START_DOC_NAME = "Název" +MAIN_START_DOC_RUBRIC = "Rubrika" +MAIN_START_DOC_DATE = "Publikováno" +MAIN_START_DOC_AUTOR = "Autor" + +MAIN_START_SEARCH = "Vyhledávání:" +MAIN_START_SEARCH_T = "Hledat dokument" + +MAIN_START_LOGS_LOG = "Historie operací" +MAIN_START_LOGS_404 = "Chyby 404" +MAIN_START_LOGS_SQL = "Chyby MySQL" + +MAIN_TABLE_SUCC = "Počet úspěšně nahraných tabulek: " +MAIN_TABLE_ERROR = "Počet tabulek s chybami: " +MAIN_SQL_FILE_ERROR = "SQL soubor má nesprávný formát nebo obsahuje chyby ve struktuře požadavků." +MAIN_RESTORE_OK = "Databáze úspěšně obnovena" + +MAIN_NO_PERM_MODULES = "Je nám líto, ale nemáte sdostatečná práva řídit tento modul" +MAIN_MP_FILE_DELETE = "Odstranit soubor" +MAIN_MP_DELETE_CONFIRM = "Opravdu chcete odstranit soubor: " +MAIN_MP_DOC_FOLDER = "Seznam složek / souborů" +MAIN_MP_FILE_SIZE = "Velikost souboru" +MAIN_MP_FILE_DATE = "Datum vytvoření" +MAIN_MP_ACTIONS = "Akce" +MAIN_MP_FILE_INFO = "Chcete-li přidat soubor, klepněte na jeho název a poté na tlačítko vložit soubor" +MAIN_MP_UP_LEVEL = "Jít o úroveň výše" +MAIN_MP_CREATE_FOLDER = "Vytvořit složku" +MAIN_MP_UPLOAD_FILE = "Stáhnout soubor" +MAIN_MP_FILE_INSERT = "Vložit soubor" +MAIN_MP_DIR_INSERT = "Vybrat složku" +MAIN_MP_SELECT_FILES = "Vybrat soubory ke stažení" +MAIN_MP_IMAGE_RESIZE = "Změnit velikost nahraných obrázků" +MAIN_MP_IMAGE_WIDTH = "Šířka" +MAIN_MP_IMAGE_HEIGHT = "Výška" +MAIN_BUTTON_UPLOAD = "Stáhnout" +MAIN_BUTTON_WAIT = "Čekejte prosím" +MAIN_MP_PLEASE_SELECT = "Vyberte prosím soubor" +MAIN_ADD_IN = "Vyberte rubriku:" +MAIN_GROUP_DELETE_CONFIRM = "Opravdu chcete odstranit tuto skupinu?" +MAIN_RUBRIKS_LIST = "Seznam rubrik" +MAIN_USER = "Uživatel:" +ButtonSave = "Uložit" +MAIN_NEW_PAGE = "Přidat novou stránku" +MAIN_BUTTON_SORT = "Odebrat" +MAIN_QUICK_MODULE = "Správce modulů" +MAIN_STAT = "Statistika" +MAIN_STAT_SYSTEM_INFO = "Systémové informace" +MAIN_STAT_DOCUMENTS = "Všechny dokumenty:" +MAIN_STAT_RUBRICS = "Všechny rubriky:" +MAIN_STAT_QUERIES = "Všechny požadavky:" +MAIN_STAT_TEMPLATES = "Všechny šablony:" +MAIN_STAT_MYSQL = "Velikost databáze:" +MAIN_STAT_CACHE = "Celková velikost mezipaměti:" +MAIN_STAT_CACHE_SHOW = "Ukázat" +MAIN_STAT_MODULES = "Nainstalováno modulů:" +MAIN_STAT_MODULES_OFF = "Vypnuté moduly:" +MAIN_STAT_USERS = "Všechny uživetelé:" +MAIN_STAT_USERS_WAIT = "Očekávající aktivaci:" +MAIN_STAT_AVE = "AVE.cms" +MAIN_STAT_DOMEN = "Doména" +MAIN_STAT_PHP = "PHP Verze:" +MAIN_STAT_MYSQL_VERSION = "MySQL Verze:" +MAIN_STAT_CLEAR_CACHE = "Smazat mezipaměť" +MAIN_STAT_CLEAR_CACHE_FULL= "Vymazat mezipaměť a relaci" +MAIN_STAT_CLEAR_THUMB = "Smazat miniatury" +MAIN_STAT_CLEAR_REV = "Smazat revize" +MAIN_STAT_CLEAR_COUNT = "Vynulovat počítadlo" +MAIN_ADD_FOLDER = "Zadejte prosím jméno nové složky:" +MAIN_NO_ADD_FOLDER = "Chybí název složky nebo akce byla zrušena!" +MAIN_NO_ADD_TEMPL = "Chybí název šablony nebo akce byla zrušena!" +MAIN_NO_ADD_GROUP = "Chybí název skupiny nebo akce byla zrušena!" +MAIN_NO_ADD_RUB = "Chybí název rubriky nebo akce byla zrušena!" +MAIN_NO_ADD_QUERY = "Chybí název požadavku nebo akce byla zrušena!" +MAIN_NO_ADD_NAV = "Chybí název navigace nebo akce byla zrušena!" +MAIN_NO_ADD_BLOCK = "Chybí název systémového bloku nebo akce byla zrušena!" +MAIN_NO_ADD_USER = "Chybí jméno uživatele nebo akce byla zrušena!" +MAIN_NO_ADD_DOCS = "Chybí název dokumentu nebo akce byla zrušena!" +MAIN_CLEAR_CACHE_OK = "Mezipaměť smazána" +MAIN_FILE_MANAGER_TITLE = "Správce souborů" +MAIN_FILE_MANAGER_TIP = "Vyberte požadovaný soubor a klikněte na "vložit soubor"" + +MAIN_SVN_NEW = "Vyšla nová verze" +MAIN_SVN_SAIT = "Přejít na stránky" +MAIN_SVN_REPOS = "Přejít na stránky úložiště" +MAIN_SVN_MAILTO = "Napsat zprávu" +MAIN_SVN_LOOK = "Zobrazit revizi na stránce úložiště" +MAIN_SVN_RECOM = "Doporučeno aktualizovat!" + +MAIN_FINDER = "Správce souborů" + +MAIN_ADD_NEW_GROUP = "Přidat novou skupinu" +MAIN_ADD_NEW_GROUP_NAME = "Název skupiny:" + +MAIN_ADD_NEW_USER = "Přidat nového uživatele" +MAIN_ADD_NEW_USER_NAME = "Jméno uživatele:" + +MAIN_ADD_NEW_NAV = "Додати нову навігацію" +MAIN_ADD_NEW_NAV_NAME = "Název navigace:" + +MAIN_ADD_NEW_TEMPL = "Přidat novou šablonu" +MAIN_ADD_NEW_TEMPL_NAME = "Název šablony:" + +MAIN_ADD_NEW_REQUEST = "Přidat nový požadavek" +MAIN_ADD_NEW_REQUEST_NAME = "Název požadavku:" + +MAIN_ADD_NEW_RUB = "Přidat novou rubriku" +MAIN_ADD_NEW_RUB_NAME = "Název rubriky:" + +MAIN_ADD_NEW_BLOCK = "Přidat nový systémový blok" +MAIN_ADD_NEW_BLOCK_NAME = "Název systémového bloku:" + +MAIN_USERS_LAST_TIME = "V poslední době byl:" + +MAIN_LOGS_ID = "№" +MAIN_LOGS_IP = "IP-adresa" +MAIN_LOGS_DATE = "Datum" +MAIN_LOGS_USER = "Uživatel" +MAIN_LOGS_ACTION = "Akce" + +MAIN_DOC_SHOW3_TITLE = "Dokument Bez Názvu" +MAIN_DOC_EDIT_TITLE = "Upravit tento dokument" +MAIN_DOC_SHOW_TITLE = "Zobrazit dokument (bez CNC linků)" +MAIN_DOC_SHOW2_TITLE = "Zobrazit dokument (s CNC linky)" + +MAIN_ADD_DOC = "Dokument" +MAIN_ADD_RUB = "Rubriky" +MAIN_ADD_REQ = "Požadavek" +MAIN_ADD_SYS = "Systémový blok" +MAIN_ADD_TEM = "Šablona" +MAIN_ADD_NAV = "Navigaci" +MAIN_ADD_USR = "Uživatele" +MAIN_ADD_GRP = "Skupiny" + +MAIN_BRANCHES = "Sekce" +MAIN_SHOWHIDE = "Ukázat/schovat menu" + +MAIN_CODEMIRROR_HELP = "Ctrl-F/Cmd-F (Hledat) | Ctrl-G/Cmd-G (Pokračovat ve hledání) | Shift-Ctrl-G/Shift-Cmd-G (Najít předešlé) | Shift-Ctrl-F/Cmd-Option-F (Nahradit) | Shift-Ctrl-R / Shift-Cmd-Option-F (Nahradit vše) | F11 (Celá obrazovka)" + +TEMPLATES_MESSAGE = "Zpráva:" +TEMPLATES_CACHE_SUCCESS = "Mezipaměť úspěšně smazána." +TEMPLATES_CACHE_SUCCESS_LOG = "Mezipaměť smazána." +TEMPLATES_CACHE_DB_SUCCESS = "Tabulka _sessions úspěšně smazány." +TEMPLATES_CACHE_DB_SUCCESS_LOG = "Tabulka smazána _sessions." +TEMPLATES_CACHE_CT_SUCCESS = "Odstraněné zkompilované šablony." +TEMPLATES_CACHE_CT_SUCCESS_LOG = "Zkompilované šablony odstraněny." +TEMPLATES_CACHE_MC_SUCCESS = "Odstraněné zkompilované šablony modulů." +TEMPLATES_CACHE_MC_SUCCESS_LOG = "Zkompilované šablony modulů odstraněny." +TEMPLATES_CACHE_SU_SUCCESS= "Uživatelské relace odstraněny." +TEMPLATES_CACHE_SU_SUCCESS_LOG = "Uživatelské relace odstraněny." +TEMPLATES_CACHE_SC_SUCCESS = "Odstraněné mezipaměti SQL požadavků." +TEMPLATES_CACHE_SC_SUCCESS_LOG = "Mezipaměti SQL požadavků odstraněny." +TEMPLATES_THUMBNAILS_SUCCESS = "Miniatury úspěšně odstraněny." +TEMPLATES_THUMBNAILS_SUCCESS_LOG = "Miniatury odstraněny" + +EXIT_ADMIN = "Konec akce v Ovládacích panelech" +LOGIN_ADMIN = "Počátek akce v Ovládacích panelech" +ERROR_ADMIN = "Chyba při vstupu k Ovládacím panelům" + +WRONG_PASS = "Chyba:
Špatné jméno nebo heslo!" +WRONG_CAPTCHA = "Chyba:
Špatný bezpečnostní kód" + +oficial_site = "Oficiální stránky" +support = "Technická podpora" \ No newline at end of file diff --git a/admin/lang/cz/modules.txt b/admin/lang/cz/modules.txt new file mode 100644 index 0000000..3db2260 --- /dev/null +++ b/admin/lang/cz/modules.txt @@ -0,0 +1,38 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[modules] +MODULES_SUB_TITLE = "Správce modulů" +MODULES_TIP = "Zde je seznam všech dostupných modulů v systému. Můžete zde nastavit, vypnout či aktualizovat jakýkoli modul a udělat dodatečné personální změny pro kterýkoli z modulů." +MODULES_NAME = "Název modulu" +MODULES_INFO = "Informace" +MODULES_TEMPLATE = "Šablony výstupu" +MODULES_SYSTEM_TAG = "Tag systém" +MODULES_VERSION = "Verze" +MODULES_ACTIONS = "Akce" +MODULES_SETTINGS = "Parametry" +MODULES_SETTINGS_INFO = "Informace" +MODULES_DELETE = "Odstranit modul" +MODULES_DELETE_CONFIRM = "Nezapomeňte, že odstraněním modulu ze systému jej smažete pouze na programové úrovni. V budoucnu jej vždy můžete znovu nainstalovat.
Opravdu chcete odstranit tento modul?" +MODULES_INSTALL = "Nastavit modul" +MODULES_REMOVE = "Odstranit modul ze serveru" +MODULES_REINSTALL = "Resetovat modul" +MODULES_REINSTALL_CONF = "Opravdu chcete resetovat tento modul?" +MODULES_UPDATE = "Aktualizovat modul" +MODULES_STOP = "Vypnout modul" +MODULES_START = "Zapnout modul" +MODULES_BUTTON_SAVE = "Uložit změny" +MODULES_LEGEND = "Hodnota ikon" +MODULES_AUTHOR = "Autor modulu" +MODULES_ERROR = "Vyskytla se chyba při načítání modulu: " +MODULES_INSTALLED = "Instalovené moduly:" +MODULES_NOT_INSTALLED = "Neinstalované moduly:" +MODULES_SETUP = "Přejít do nastavení modulu" +MODULES_NO_INSTALL = "Zpráva:
Žádné nainstalované moduly." +MODULES_NOT_INSTALL = "Zpráva:
Žádné moduly k instalaci." +MODULES_ACTION_INSTALL = "Modul instalován" +MODULES_ACTION_ONLINE = "Modul zapnut" +MODULES_ACTION_OFFLINE = "Modul vypnut" +MODULES_ACTION_REINSTALL = "Modul přeinstalován" +MODULES_ACTION_UPDATE = "Modul aktualizován" +MODULES_ACTION_DELETE = "Modul odstraněn ze systému" +MODULES_ACTION_REMOVE = "Modul odstraněn ze serveru" \ No newline at end of file diff --git a/admin/lang/cz/navigation.txt b/admin/lang/cz/navigation.txt new file mode 100644 index 0000000..d5e3826 --- /dev/null +++ b/admin/lang/cz/navigation.txt @@ -0,0 +1,96 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[navi] +NAVI_ID = "ID" +NAVI_SUB_TITLE = "Ovládání menu navigace" +NAVI_SUB_TITLE2 = "Ovládací menu" +NAVI_SUB_TITLE3 = "Editace šablon menu" +NAVI_SUB_TITLE4 = "Vytvoření nové šablony menu" +NAVI_TIP_TEMPLATE = "Zde je seznam všech navigačních menu v systému. Můžete tu změnit šablonu výstupu jakéhokoli z dostupných menu a také přidat, či odebrat položky menu." +NAVI_TIP_TEMPLATE2 = "V této části můžete, za pomocí kodování HTML, vytvořit šablonu návrhu pro navigaci v menu. Můžete také vybrat skupinu uživatelů, kterým bude toto navigační menu k dispozici. Pro výběr několika skupin držte CTRL." +NAVI_ITEMS_TIP = "Vytvořit novou položku menu" +NAVI_NEW_MENU = "Vytvořit nové menu" +NAVI_LIST_TIP = "Seznam níže obsahuje všechny položky vztahující se k tomuto menu. Nezapomeňte, že maximální úroveň vložení nemůže být více jak dva." +NAVI_LIST = "Seznam položek menu" +NAVI_EDIT_TEMPLATE = "Editace šablon menu" +NAVI_EDIT_ITEMS = "Editace položek menu" +NAVI_OPEN_IN_THIS = "V aktuálním okně" +NAVI_OPEN_IN_NEW = "V novém okně" +NAVI_TARGET_WINDOW = "Otevřít" +NAVI_POSITION = "Pozice" +NAVI_LINK_TO_DOCUMENT = "Odkaz na dokument/soubor" +NAVI_ENTRIES_NO_ITEMS = "Zpráva:
V současné době zde nejsou žádné položky menu." + +NAVI_LINK_TITLE = "Název položky menu" +NAVI_LINK_SOLUT = "Popis položky menu:" +NAVI_LINK_IMGID = "ID obrázku:" +NAVI_LINK_IMGTL = "Vybrat obrázek:" +NAVI_LINK_IMAGE = "Zobrazení pro položku menu" +NAVI_TITLE = "Název navigačního menu:" +NAVI_TITLE2 = "Zadejte název navigačního menu:" +NAVI_BROWSE_DOCUMENTS = "Propojit s existujícím dokumentem" +NAVI_ADD_SUBITEM = "Vybrat novou položku" +NAVI_BUTTON_CHANGE = "Vybrat" +NAVI_BUTTON_OPTION = "Nastavení" +NAVI_BUTTON_SUBITEM = "+" +NAVI_BROWSE_MEDIAPOOL = "Propojit se souborem na serveru" +NAVI_SYSTEM_TAG = "Tag systém" +NAVI_NAME = "Název menu" +NAVI_LINK_TARGET = "Tag, který určuje typ otevření dokumentu (v novém, či aktuálním okně)" +NAVI_LINK_URL = "Tag, který určuje adresu přechodu" +NAVI_LINK_NAME = "Tag, který určuje název odkazu, který bude zobrazen v menu" +NAVI_LINK_ID = "Tag, který definuje unikátní identifikátor odkazu" +NAVI_LINK_INACTIVE = "Registrace neaktivního odkazu:" +NAVI_LINK_ACTIVE = "Registrace aktivního odkazu:" +NAVI_HEADER_START = "Horní část designu:" +NAVI_FOOTER_END = "Dolní část designu:" +NAVI_HEADER_TIP = "Například, nadpis
" Katalog zboží"
(volitelné)" +NAVI_COPY_TEMPLATE = "Kopírovat šablonu menu" +NAVI_FOOTER_TIP = "Spodní část designu menu
(volitelné)" +NAVI_DELETE = "Odstranit menu" +NAVI_DELETE_CONFIRM = "Opravdu chcete smazat toto navigační menu?" +NAVI_HTML_START = "Primární HTML kód:" +NAVI_HTML_END = "Konečný HTML kód:" +NAVI_LEVEL1 = " Šablona designu pro hlavní (první) položku menu." +NAVI_LEVEL2 = "Šablona designu pro první úroveň dílčích položek" +NAVI_LEVEL3 = "Šablona designu pro druhou úroveň dílčích položek" +NAVI_MARK_DELETE = "Označit tuto položku k odstranění" +NAVI_MARK_ACTIVE = " Aby bylo možné dočasně deaktivovat tuto položku menu, zrušte výběr a stiskněte "Uložit změny"" +NAVI_GROUPS = "Skupiny uživatelů, kterým bude menu dostupné:" +NAVI_ACTIONS = "Akce" +NAVI_OR_BUTTON = " nebo " +NAVI_BUTTON_SAVE = "Uložit změny" +NAVI_BUTTON_SAVE_NEXT = "Použít (CTRL+S)" +NAVI_BUTTON_ADD = "Přidat položku" +NAVI_BUTTON_ADD_MENU = "Vytvořit menu" +NAVI_LEGEND = "Hodnota ikon" +NAVI_ENTER_NAME = "Zadejte název navigačního menu." +NAVI_ALL = "Seznam navigačních menu" +NAVI_PRINT_TYPE = "Typ výstupu" +NAVI_EXPAND_ALL = "Plně (otevřít všechny úrovně)" +NAVI_EXPAND_WAY = "Současnou a rodičovskou úroveň" +NAVI_EXPAND_LEVEL = "Pouze současnou úroveň" +NAVI_MENU_NOT_FOUND = "Žádné menu ID=" +NAVI_SAVE = "Šablona navigačního menu úspěšně uložena" +NAVI_SORTED = "Postup úspěšně uložen" + +NAVI_REPORT_NEW = "Navigační menu vytvořeno" +NAVI_REPORT_COPY = "Záloha navigačního menu vytvořena" +NAVI_REPORT_EDIT = "Šablona navigačního menu změněna" +NAVI_REPORT_DEL = "Navigační menu smazáno" +NAVI_REPORT_ADDIT = "Přidat položku navigačního menu" +NAVI_REPORT_DELIT = "Odstranit položku navigačního menu" +NAVI_REPORT_FLEV = "Na první úroveň" +NAVI_REPORT_SLEV = "Na druhou úroveň" +NAVI_REPORT_TLEV = "Na třetí úroveň" +NAVI_REPORT_DEACT = "Položka navigačního menu deaktivována" +NAVI_REPORT_ACT = "Položka navigačního menu aktivována" +NAVI_REPORT_SAVED = "Šablona navigace úspěšně uložena." +NAVI_REPORT_SAVED_ERR = "Nezdařilo se uložit šablonu navigace..
Zkuste ještě jednou." +NAVI_REPORT_ERROR = "Chyba" +NAVI_REPORT_SUCCESS = "Hotovo" + +NAVI_ITEM_ON_OFF = "Zap/Vyp položku menu" +NAVI_ITEM_EDIT = "Editovat položku menu" +NAVI_ITEM_DELETE = "Odstranit tuto položku menu" +NAVI_ITEM_DELETE_CONFIRM = "Opravdu chcete odstranit tuto položku navigačního menu?" \ No newline at end of file diff --git a/admin/lang/cz/request.txt b/admin/lang/cz/request.txt new file mode 100644 index 0000000..ab38283 --- /dev/null +++ b/admin/lang/cz/request.txt @@ -0,0 +1,177 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[request] +REQUEST_ID = "ID" +REQUEST_DELETE = "Odstranit požadavek" +REQUEST_DELETE_CONFIRM = "Opravdu chcete odstranit tento požadavek??" +REQUEST_TITLE = "Správce požadavků" +REQUEST_NAME = "Název požadavků" +REQUEST_NAME2 = "Název požadavku:" +REQUEST_NAME3 = "Zadejte název požadavku:" +REQUEST_CACHE = "Uložit do mezipaměti:" +REQUEST_CACHE_ELEMENTS = "Uložit do mezipaměti prvky požadavku" +REQUEST_SETTINGS = "Parametry požadavku" +REQUEST_TIP = "Zde najdete seznam všech požadavků v systému. Pro využití požadavků umístěte "Systémový tag" na potřebném místě Vaší šablony, nebo dokumentu." +REQUEST_EDIT_TIP = "Zde můžete editovat požadavek, měníc rubriku pro získávání údajů, šablony výstupu a také podmínky volby dat." +REQUEST_NEW = "Vytvoření nového požadavku" +REQUEST_EDIT = "Editovat požadavek" +REQUEST_EDIT2 = "Editování požadavku" +REQUEST_SYSTEM_TAG = "Systémový tag" +REQUEST_AUTHOR = "Autor" +REQUEST_DATE_CREATE = "Datum vytvoření" +REQUEST_ACTIONS = "Akce" +REQUEST_NO_DESCRIPTION = "Požadavek bez popisu" +REQUEST_NO_REQUST = "Chybějící požadavek." +REQUEST_DATE_FORMAT = "%d.%m.%y g." +REQUEST_DATE_FORMAT2 = "%d.%m.%y g. v %H:%M" +REQUEST_IN = "v" +REQUEST_COPY = "Kopírovat požadavek" +REQUEST_COPY_FAILED = "Nezdařilo se kopírování požadavku" +REQUEST_PLEASE_NAME = "Zadejte prosím název zkopírovaného požadavku" +REQUEST_CONDITION_EDIT = "Podmínky pro požadavky" +REQUEST_CONDITION_IF = "Podmínky" +REQUEST_PLEASE_SELECT = "Vyberte, prosím, rubriku" +REQUEST_SELECT_RUBRIK = "Vyberte rubriku:" +REQUEST_SELECT_INFO = "Opravdu chcete změnit rubriku?" +REQUEST_NEW_TIP = "Pozor! Před tím, než vytvoříte nový požadavek, musíte vybrat rubriku, ze které budou čerpat dokumenty." +REQUEST_DESCRIPTION = "Popis požadavku:" +REQUEST_INTERNAL_INFO = "(použitý v rámci systému)" +REQUEST_BUTTON_COND = "Přidat / změnit" +REQUEST_CONDITION = "Podmínky požadavku:" +REQUEST_ACTION_AFTER = "Po vytvoření se vrátit k úpravě požadavků, pro dodání podmínek požadavku." +REQUEST_SORT_BY = "Třídit podle vlastností dokumentu:" +REQUEST_SORT_BY_NAT = "Třídit dle oblasti dokumentu:" +REQUEST_ASC_DESC = "V pořadí:" +REQUEST_DESC = "pokles" +REQUEST_ASC = "růst" +REQUEST_BY_DATE = "Datum vytvoření (publikace)" +REQUEST_BY_DATECHANGE = "Datum změny (dokumentu)" +REQUEST_BY_NAME = "Nadpis dokumentů" +REQUEST_BY_EDIT = "Název autora" +REQUEST_BY_PRINTED = "Počet výtisků" +REQUEST_BY_VIEWS = "Počet shlédnutí" +REQUEST_BY_RAND = "V náhodném pořadí (Vysoké zatížení)" +REQUEST_DOC_PER_PAGE = "Počet na stránce:" +REQUEST_DOC_PER_PAGE_ALL = "vyvést vše" +REQUEST_SHOW_NAVI = "Zobrazovat navigaci:" +REQUEST_USE_LANG = "Pouze jazyk uživatele:" +REQUEST_USE_QUERY = "Používat GET požadavky pro stránkovou navigaci" +REQUEST_TEMPLATE_QUERY = "Základní požadavek na design šablony" +REQUEST_MAIN_CONTENT = "Systémový tag, odpovídající za vývod prvků požadavků, uvedené v poli "prvky požadavků"" +REQUEST_DOC_COUNT = "Systémový tag, odpovídající za vývod počtu prvků požadavku" +REQUEST_DOCITEMNUM_INFO= "Systémový tag, odpovídající za vývod pořadového čísla prvku požadavku" +REQUEST_MAIN_NAVI = "Systémový tag, odpovídající za vývod stránková navigace pro požadavky (< 1 2 3 >)" +REQUEST_MEDIAPATH = "Systémový tag, který definuje cestu ke složce se šablonou (například: [tag:mediapath]images/logo.gif)" +REQUEST_PATH = "Systém tag, který definuje kořenový adresář instalace" +REQUEST_TEMPLATE_ITEMS = "Šablona designu pro pvy požadavku" +REQUEST_TEMPLATE_INFO = "Toto pole využívající HTML kód, můžete využít pro design vnitřních prvků požadavku.(např., design seznamu novin). Všechny prvky jsou navrženy podle tohoto vzoru se cyklicky zobrazí v "Základní šabloně" požadavku, dokud bude počet kusů odpovídat podmínkám požadavku." +REQUEST_TEMPLATE_SAVED = "Požadavek úspěšně uložen" +REQUEST_SELECT_IN_LIST = "Vyberte prosím pole rubriky ze seznamu níže" +REQUEST_RUB_INFO = "Systémový tag zodpovědný za výstup obsahu sloupce. ID-číslo sloupce. ХХХ-počet symbolů pro zobrazení." +REQUEST_LINK_INFO = "Systémový tag, který definuje odkaz na dokument například, < a href="[tag:link]">odkaz < /a >" +REQUEST_RUBRIK_FIELD = "Systémový tag pole" +REQUEST_THUMBNAIL = "Tag odpovídá za vytvoření miniatury (Za předpokladu, že v kategorii pole šablony (šablony pro výstup dotazu) byl zvolen výstup: [tag:parametr:0])" +REQUEST_FIELD_NAME = "Název sloupce" +REQUEST_FIELD_TYPE = "Typ pole" +REQUEST_FIELD_G_UNKNOW = "Bez skupiny" + +REQUEST_BUTTON_ADD = "Vytvořit požadavek" +REQUEST_BUTTON_ADD_NEXT = "Vytvořit a pokračovat" +REQUEST_BUTTON_SAVE = "Uložit změny" +REQUEST_BUTTON_SAVE_NEXT = "Použít (CTRL+S)" +REQUEST_BUTTON_CLOSE = "Zavřít okno" + +REQUEST_INSERT_INFO = "Stlačte systémový tag, k jeho přidání do šablony" +REQUEST_CONDITIONS = "Správa dotazu" +REQUEST_CONDITION_TIP = "Zde si můžete vytvořit speciální podmínky dat požadavku. Podmínky požadavku umožňují nejpřesněji určit výstupní data podle různých parametrů." +REQUEST_NEW_CONDITION = "Přidat novou podmínku" +REQUEST_FROM_FILED = "Vybrat z pole" +REQUEST_OPERATOR = "Tam, kde hodnota" +REQUEST_VALUE = "Hodnota" +REQUEST_COND_SELF = "Rovná se" +REQUEST_COND_NOSELF = "Nerovná se" +REQUEST_COND_USE = "Obsahuje" +REQUEST_COND_NOTUSE = "Neobsahuje" +REQUEST_COND_START = "Začíná z" +REQUEST_SMALL1 = "Menší nebo rovno" +REQUEST_BIG1 = "Větší nebo rovno" +REQUEST_SMALL2 = "Méně" +REQUEST_BIG2 = "Více" +REQUEST_N_COND_SELF = "Rovná se" +REQUEST_N_SMALL1 = "Menší nebo rovno" +REQUEST_N_BIG1 = "Větší nebo rovno" +REQUEST_N_SMALL2 = "Číslo menší" +REQUEST_N_BIG2 = "Číslo větší" +REQUEST_SEGMENT = "Nepatří intervalu (přes ,)" +REQUEST_INTERVAL = "Patří intrvalu (přes ,)" +REQUEST_IN = "v seznamu (přes ,)" +REQUEST_NOTIN = "Není v seznamu(přes ,)" +REQUEST_ANY_NUM = "NEBEZPEČÍ!!! Číslo v požadavku" +REQUEST_FREE = "NEBEZPEČÍ!!! Libovolná podmínka [field]={value}" +REQUEST_MARK_DELETE = " Označit podmínku pro odstranění" +REQUEST_CONR_AND = "A" +REQUEST_CONR_OR = "Nebo" +REQUEST_OR = " nebo " + +REQUEST_VIEWS_INFO = "Systémový tag, který ukazuje počet zhlédnutí dokumentu"REQUEST_COMMENTS_INFO = "Systémový tag, ukazující počet připomínek k dokumentu. Varování! Funguje pouze při nainstalovaném modulu!" +REQUEST_CONTROL_FIELD = "Systémový tag, odpovídající za vývod požadavku Ovládacího panelu. Pouze pro rubriky s poli typu rozevíracího seznamu." +REQUEST_CONTROL_SORT = "Systémový tag, odpovídající vývodu panelu pro třídění podle data vydání, název a četnost přehledů výstupních vývodů požadavku" +REQUEST_NO_DROPDOWN = "Ve vybrané rubrice nejsou žádná typové pole rozevíracího seznamu" +REQUEST_ENTER_NAME = "Zadejte prosím název požadavku." +REQUEST_ALL = "Seznam požadavků" +REQUEST_IF_EMPTY = "Párový systémový tag, ve kterém můžete určit výstupní vzor v nepřítomnosti výsledků požadavku." +REQUEST_NOT_EMPTY = "Párový systémový tag, ve kterém můžete určit výstupní vzor za přítomnosti výsledků požadavku." +REQUEST_DOCID_INFO = "Systémový tag, odpovídající ID dokumentu" +REQUEST_DOCTITLE_INFO = "Systémový tag, odpovídající názvu dokumentu" +REQUEST_CDOCID_INFO = "Systémový tag, odpovídající ID aktuálního dokumentu (ve kterém je požadavek na výstup)" +REQUEST_DOCDATE_INFO = "Systémový tag, odpovídající datu publikace dokumentu" +REQUEST_CDOCDATE_INFO = "Systémový tag, odpovídající datu publikace aktuálního dokumentu (ve kterém je požadavek na výstup)" +REQUEST_DOCTIME_INFO = "Systémový tag, odpovídající datu a času publikace dokumkentu" +REQUEST_CDOCTIME_INFO = "Systémový tag, odpovídající datu a času publikace aktuálního dokumentu (ve kterém je požadavek na výstup)" +REQUEST_DATE_INFO = "Systémový tag, datu a času publikace dokumentu - přizpůsobitelný vzhled.
Příklad: [tag:date:d.m.Y]
Můžete použít rozvody (space - . /)" +REQUEST_CDATE_INFO = "Systémový tag, datu a času publikace dokumentu - přizpůsobitelný vzhled.
Příklad: [tag:date:d.m.Y]
ve kterém je požadavek na výstup)
Můžete použít rozvody (space - . /)" +REQUEST_DOCAUTHOR_INFO = "Systémový tag, odpovídající autoru dokumentu" +REQUEST_DOCAUTHOR_AVATAR = "Systémový tag, odpovídající аватару автора документа" +REQUEST_CDOCAUTHOR_INFO = "Systémový tag, odpovídající autoru aktuálního dokumentu(ve kterém je požadavek na výstup)" +REQUEST_SAMPLE = "Příklad" +REQUEST_HIDE_CURRENT = "Neukazovat v aktuálním dokumentu požadavku" +REQUEST_ONLY_OWNER = "Pouze své (UserID) dokumenty" +REQUEST_CONDITION_JOIN = "Operátor" +REQUEST_CONDITION_SAVE = "Uložit podmínku" +REQUEST_CONDITION_ADD = "Přidat podmínku" + +REQUEST_SUCCESS = "Hotovo" +REQUEST_ERROR = "Chyba" +REQUEST_CANCEL = "Zrušit" + +REQUEST_SORTED = "Postup úspěšně uložen" +REQUEST_COND_MESSAGE = "Žádné podmínky požadavku" +REQUEST_COND_VALUE_ERR = "Prázdné pole hodnoty" +REQUEST_COND_NEW_ERR = "Nepodařilo se přidat novou podmínku
Zkuste znovu" +REQUEST_COND_NEW_SUC = "Požadavek úspěšně přidán" +REQUEST_COND_POST_OK = "Požadavky úspěšně uloženy" +REQUEST_COND_POST_ERR = "Nepodařilo se uložit podmínky požadavku
Zkuste znovu" +REQUEST_COND_NO_POST = "Žádná data k uložení
Zkuste znovu" + +REQUEST_COND_ADD_SUC = "Přidat podmínky požadavku" +REQUEST_COND_CHA_SUC = "Podmínky požadavku změněny" +REQUEST_COND_DEL_SUC = "Podmínky požadavku odstraněny" +REQUEST_SAVE_CHA_SUC = "Požadavek upraven" +REQUEST_ADD_NEW_SUC = "Přidat nový požadavek" +REQUEST_DELETE_SUC = "Požadavek odstraněn" +REQUEST_COPY_SUC = "Kopie požadavku vytvořena" + +REQUEST_HEADER_SELF = "Hlavní požadavky parametru" +REQUEST_HEADER_NAME = "Hodnota" +REQUEST_HEADER_PARAMETR = "Parametr" + +REQUEST_REPORT_ERR_TITLE = "Cyhbí název požadavku" +REQUEST_REPORT_ERR_TEXT = "Chybí základní šablona designu požadavku" +REQUEST_REPORT_ERR_PHP = "Je zakázáno využívat PHP kodu +REQUEST_REPORT_ERR_PHP_N = "Pokus využítí PHP kodu v šabloně požadavku při vytvoření požadavku" +REQUEST_REPORT_ERR_PHP_E += "Pokus použítí PHP kodu v šabloně požadavku" +REQUEST_REPORT_ERR_RUBRIC= "Není vybraná rubrika" +REQUEST_BY_PARENT = "Nadřazený dokument" +REQUEST_SHOW_STAT = "Zobrazit statistiky" + diff --git a/admin/lang/cz/rubs.txt b/admin/lang/cz/rubs.txt new file mode 100644 index 0000000..adb95b8 --- /dev/null +++ b/admin/lang/cz/rubs.txt @@ -0,0 +1,260 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[Rubs] +RUBRIK_SUB_TITLE = "Správce rubrik" +RUBRIK_TIP = "Zde je seznam všech rubrik v systému. Můžete zde upravit šablonu rubriky, oprávnění, odstranit rubriku, a také zkopírovat rubriku a na jejím základě vytvořit novou." +RUBRIK_ID = "ID" +RUBRIK_NAME = "Název rubriky" +RUBRIK_NAME2 = "Název rubriky" +RUBRIK_TEMPLATE_OUT = "Použít v šabloně" +RUBRIK_TEMPLATE_OUT2 = "Používat v šabloně" +RUBRIK_URL_PREFIX = "Prefix odkazu" +RUBRIK_URL_PREFIX2 = "Prefix odkazu" +RUBRIK_DOCS_VI = "Zobrazit dokument v seznamu" +RUBRIK_URL_PREFIX2 = "Prefix odkazu" +RUBRIK_COUNT_DOCS = "Počet dokumentů" +RUBRIK_COUNT_FIELDS = "Počet polí" +RUBRIK_AUTHOR = "Autor" +RUBRIK_ACTION = "akce" +RUBRIK_FORMAT= "Použít" +RUBRIK_FORMAT_TIME = "pro odkaz ve formátu času" +RUBRIK_FORMAT_ID = "pro vložení id dokumentu" +RUBRIK_EDIT = "Upravit pole a práva rubriky" +RUBRIK_EDIT_TMPLS = "Další šablony" +RUBRIK_NO_VIEW = "Je nám líto, ale nemáte oprávnění k zobrazení seznamu rubrik." +RUBRIK_NO_CHANGE1 = "Je nám líto, ale nemáte oprávnění k úpravě polí rubriky." +RUBRIK_NO_CHANGE2= "Je nám líto, ale nemáte oprávnění k úpravě šablonu této rubriky." +RUBRIK_NO_CHANGE3= "Je nám líto, ale nemáte oprávnění k vytvoření nových rubrik." +RUBRIK_EDIT_TEMPLATE = "Upravit šablonu rubriky" +RUBRIK_EDIT_CODE = "Upravit spustitelný kód rubrik" +RUBRIK_EDIT_CODE_T = "Upravit spustitelný kód rubrik" +RUBRIK_EDIT_CODE_NO = "Nemáte přístup k úpravě spustitelného kódi" +RUBRIK_DELETE = "Odstranit rubriku" +RUBRIK_DELETE_LEGEND = "Smazat rubriku" +RUBRIK_DELETE_CONFIRM = "Jste si jisti, že chcete smazat tuto rubriku?" +RUBRIK_NO_PERMISSION = "Je nám líto, ale nemáte oprávnění k odstranění rubriky." +RUBRIK_USE_DOCUMENTS = "Je nám líto, ale nemůžete odstranit tuto rubriku, protože obsahuje dokumenty." +RUBRIK_MULTIPLY = "Kopírovat rubriku" +RUBRIK_NO_MULTIPLY = "Je nám líto, ale nemáte oprávnění ke kopírování rubrik" +RUBRIK_BUTTON_SAVE = "Uložit změny" +RUBRIK_BUTTON_TEMPL = "Upravit šablonu" +RUBRIK_BUTTON_FIELDS = "Upravit pole" +RUBRIK_BUTTON_CODE = "Upravit kód rubriky" +RUBRIK_LEGEND = "Hodnota ikony" +RUBRIK_NEW = "Vytvořit novou rubriku" +RUBRIK_NEW_TIP= "Zde můžete vytvořit novou rubriku. Uveďte název nové rubriky a vyberte šablonu pro výstup." +RUBRIK_BUTTON_NEW = "Vytvořit rubriku" +RUBRIK_EDIT_FIELDS = "Správa polí a přístupová práva k rubrice" +RUBRIK_DESCRIPTION = "Popis rubriky" +RUBRIK_NO_FIELDS = " Důležité! Nevytvořili jstežádnou pole. Prosím, přidejte alespoň jedno pole." +RUBRIK_FIELDS_INFO = "Zde můžete vytvořit skupinu polí, které budou použity pro dokumenty v této kategorii." +RUBRIK_MULTIPLY2 = "Kopírování rubriky" +RUBRIK_MULTIPLY_TIP = "Uveďte prosím název a prefix pro odkaz na novou rubriku" +RUBRIK_BUTTON_COPY = "Kopírovat" +RUBRIK_TEMPLATE_EDIT = "Upravování šablony rubriky" +RUBRIK_TEMPLATE_NEW = "Vytvoření šablony rubriky" +RUBRIK_TEMPLATE_SAVED = "Šablona úspěšně uložena" +RUBRIK_NO_FIELD = "V této kategorii nejsou žádná pole" +RUBRIK_FIELD_NAME = "Název pole" +RUBRIK_FIELD_GROUP = "Skupina" +RUBRIK_FIELD_GROUP_SEL = "Vyberte skupinu" +RUBRIK_FIELD_ALIAS = "Alias ​​pole" +RUBRIK_FIELD_TYPE = "Typ pole" +RUBRIK_FIELD_UNKNOW = "Neznámý" +RUBRIK_FIELD_G_UNKNOW = "Žádná skupina" +RUBRIK_POSITION = "Pozice" +RUBRIK_NEW_FIELD = "Vytvoření nového pole pro rubriku" +RUBRIK_BUTTON_ADD = "Přidat pole" +RUBRIK_SET_PERMISSION = "Právo na přístup k dokumentům pro skupiny uživatelů" +RUBRIK_USER_GROUP = "Skupina" +RUBRIK_DOC_READ = "Zobrazit" +RUBRIK_ALL_PERMISSION = "Všechna práva" +RUBRIK_CREATE_DOC = "Vytvářet s kontrolou" +RUBRIK_CREATE_DOC_NOW = "Vytvořet bez kontroly" +RUBRIK_EDIT_OWN = "Editovat své" +RUBRIK_EDIT_DELREV = "Správa verzí" +RUBRIK_EDIT_OTHER = "Editovat vše" +RUBRIK_VIEW_TIP = "Zaškrtněte, pokud chcete povolit této skupině uživatelů prohlížení dokumentů" +RUBRIK_ALL_TIP = "Zaškrtněte, pokud chcete povolit této skupině uživatelů provádět jakékoliv akce s dokumenty v této rubrice." +RUBRIK_DOC_TIP= "Zaškrtněte, pokud chcete povolit této skupině uživatelů vytvářet dokumenty.
Pozor!
Před zveřejněním dokumentu, jej ověří Administrátor" +RUBRIK_DOC_NOW_TIP = "Zaškrtněte, pokud chcete povolit této skupině uživatelů vytvářet dokumenty.
Pozor!
Zveřejnění dokumentů bude provedeno bez kontroly Adminitrátora." +RUBRIK_OWN_TIP = "Zaškrtněte, pokud chcete povolit této skupině uživatelů upravovat pouze své dokumenty" +RUBRIK_OTHER_TIP = "Zaškrtněte, pokud chcete povolit této skupině uživatelů upravovat své i cizí dokumenty" +RUBRIK_DELREV_TIP = "Zaškrtněte, pokud chcete povolit této skupině uživatelů pracovat s revizemi dokumentů" +RUBRIK_BUTTON_PERM = "Uložit práva" +RUBRIK_FIELD_DEFAULT = "Výchozí hodnoty" +RUBRIK_TEMPLATE_TIP = "V této části pomocí jazyka HTML, musíte vytvořit design šablony pro dokumenty s úplnou revizi." +RUBRIK_HTML = "Šablona designu rubriky" +RUBRIK_HTML_2 = "Šablona designu HEADER" +RUBRIK_HTML_3 = "Šablona designu TEASER" +RUBRIK_HTML_4 = "Šablona designu ADMIN TEASER" +RUBRIK_PHP_DENIDED = " Chyba!
Nemáte povolení k úpravě šablony rubriky, protože používá PHP kód a Vy nemáte práva k užívání PHP kódu." +RUBRIK_PHP_MESSAGE = "Je zakázáno používat PHP kód." +RUBRIK_EMPTY_MESSAGE = "Nezadán název pole." +RUBRIK_INSERT_HELP = "Kliknutím přidate systémový tag do šablony" +RUBRIK_BUTTON_TPL = "Uložit šablonu" +RUBRIK_BUTTON_TPL_NEXT = "Použít (CTRL + S)" +RUBRIK_BUTTON_TPL_CLOSE = "Zavřít" +RUBRIK_NO_RUBRIK = "Rubrika neexistuje!" +RUBRIK_NO_NAME = "Zadejte název rubriky" +RUBRIK_NAME_EXIST = "Je nám líto, ale rubrika se stejným názvem již existuje. Zadejte jiný název kategorie." +RUBRIK_PREFIX_EXIST = "Je nám líto, ale rubrika s takovým URL prefixem již existuje. Zadejte jiný URL prefix rubriky." +RUBRIK_VIEWS_INFO = "Systemový tag, která zobrazuje počet zhlédnutí dokumentu" +RUBRIK_HIDE_INFO = "Systémový tag, který umožňuje skrýt text pro specifické skupiny uživatelů, kde X - číslo skupiny" +RUBRIK_THUMBNAIL = "Tag odpovědný za vytvoření miniatury (za předpokladu, že u šablony pole rubriky (šablona pro výstup dokumentů) je obrán výstup: [tag: parametr: 0])" +RUBRIK_LINK_HOME = "Odkaz na domovskou stránku webové stránky" +RUBRIK_MARK_DELETE = "Zaškrtněte tuto možnost pro odstranění" +RUBRIK_MARK_DEL_ALL = "Označit vše" +RUBRIK_CHECK_SEARCH = "Hledat v tomto poli"RUBRIK_CHECK_NUMERIC = "Číselné pole" +RUBRIK_SEARCH_TIP= "Zaškrtněte políčko, pokud chcete aby se takto provedlo hledání (práce s modulem" hledat "verze 2.0.2 a vyšší)" +RUBRIK_NUMERIC_TIP = "Zaškrtněte políčko pokud jsou hodnoty vždy číselné. Slouží k seřazení požadavků" +RUBRIK_ALL = "Seznam rubrik" +RUBRIK_EDIT_FIELDS_GROUPS = "Upravit skupinu pole" +RUBRIK_FIELDS_GROUPS = "Skupina polí" +RUBRIK_ENTER_NAME = "Zadejte název rubriky." +RUBRIK_TEMPLATE_HIDE= "Ukázat/ schovat šablony všech polí" +RUBRIK_FILED_TEMPLATE_H = "Upravit šablonu a popis polí" +RUBRIK_FILED_TEMPLATE_DESCR = "Popis pole" +RUBRIK_FILED_TEMPLATE_F = "Šablona pole" +RUBRIK_DOCID_INFO = "Systémový tag Identifikačního dokumentu" +RUBRIK_DOCDATE_INFO = "System tag, data vydání dokumentu" +RUBRIK_DOCTIME_INFO = "Systémový tag, datum a čas zveřejnění dokumentu" +RUBRIK_DATE_INFO = "Systémový tag, datum a čas zveřejnění dokumentu - přizpůsobitelný vzhledu
Příklad: [tag: Datum: Y]" +RUBRIK_DOCAUTHOR_INFO = "Systémový tag, autor dokumentu" +RUBRIK_TITLE_INFO = "Systémový tag, záhlaví dokumentu" +RUBRIK_PATH_INFO = "Systémový tag, cesta ke kořenové instalaci" +RUBRIK_MEDIAPATH_INFO = "Systémový tag, cesta ke složce designu" +RUBRIK_PREFIX_BAD_CHAR= "Neplatné znaky v prefixu" +RUBRIK_FIELDS_TITLE = "Pole rubriky" +RUBRIK_FIELDS_TPL = "Šablona výstupních polí v dokumentu" +RUBRIK_RUBRIK_TPL = "Šablona výstupních polí v požadavku" +RUBRIK_SORTED = "Nasatvení bylo úspěšně uloženo" +RUBRIK_F_SORT_TIP = "Chcete-li spravovat pole, stiskněte na křížek a, držíc ho, přetáhněte pole" +RUBRIK_R_SORT_TIP = "Chcete-li spravovat rubriky, stiskněte na křížek a, držíc ho, přetáhněte pole" +RUBRIK_META_GEN_TIP = "Automaticky generovat klíčová slova, popis pro dokument, na základě jeho obsahu" +RUBRIK_ALIAS_HISTORY_TIP = "Ukládat historii pseudonymů u dokumentů" +RUBRIK_MOVE = "Přemístit" +RUBRIK_REQUEST_TPL = "Výstupní šablona pole požadavku" +RUBRIK_BREADCRUMB = "Systémový tag drobečkové navigace" +RUBRIK_CODE = "spustitelný kód pro rubriky" +RUBRIK_START_CODE = "Kód, který se spouští před stažením dokumentu" +RUBRIK_CODE_START= "Kód se spouští před uložením dokumentu" +RUBRIK_CODE_END = "Kód, který se spouští po uložení dokumentu" +RUBRIK_TAGS = "tag" +RUBRIK_TAGS_ID = "tag ID" +RUBRIK_TAGS_ALIAS = "Tag Alias" +RUBRIK_HTML_T = "HTML kód šablony" +RUBRIK_TAG_DESC = "Popis tagu" +RUBRIK_NEW_FIEL_TITLE = "Pole pro rozevírací seznam a Univerzální seznamu , výchozí hodnoty se oddělují čárkami"RUBRIK_LINK = "Odkaz rubriky" +RUBRIK_LINK_DESC = "Zadáním odkazu mezi rubrikami, při přidání dokumentů, je možné automaticky dodat aliasy." +RUBRIK_NOLINK = "Nevybráno" +RUBRIK_OR = "Název skupiny" +RUBRIC_F_GROUP_DELETE = "Odstranit skupinu" +RUBRIC_F_GROUP_DELETE_H = "Opravdu chcete smazat skupinu?" +RUBRIC_NO_GROUPS = "V současné době v této rubrice nejsou žádné skupiny polí" +RUBRIC_GROUP_ADD = "Přidat skupinu" +RUBRIK_NEW_GROUP = "Přidat novou skupinu" +RUBRIK_HEADER_GROUP= "Správce skupiny polí" +RUBRIK_TEMPLATES_TAGS = "tag" +RUBRIK_TEMPLATES_TAG_DESC = "Popis tagu" +RUBRIK_TEMPLATES_THEME_FOLDER = "Název šablony (název souboru se složkami pro tuto šablonu)" +RUBRIK_TEMPLATES_PAGENAME = "Název webové stránky" +RUBRIK_TEMPLATES_TITLE= "Název stránky" +RUBRIK_TEMPLATES_KEYWORDS = "klíčová slova (Meta - Keywords)" +RUBRIK_TEMPLATES_DESCRIPTION = "popis stránky (Meta - Description)" +RUBRIK_TEMPLATES_INDEXFOLLOW = "Index zboží" +RUBRIK_TEMPLATES_PATH = "Instalace kořenové cesty" +RUBRIK_TEMPLATES_MEDIAPATH = "cesta ke složce se šablonou (Příklad: [tag: mediapath] images / logo.gif)" +RUBRIK_TEMPLATES_CSS = "Komprimuje několik CSS souborů do jednoho. Vrací cestu
FFF - Názvy souborů oddělené čárkou
P - cesta ke složce se soubory se nevyžaduje. Výchozí hodnota je - [tag: mediapath] css /
Příklad: href = & quot; [tag: css: reset.css, style.css] Termín "RUBRIK_TEMPLATES_JS= "Komprimuje několik JS-souborů do jednoho. Vrací cestu
FFF - Názvy souborů oddělené čárkou
P - cesta ke složce se soubory se nevyžaduje. Výchozí hodnota je - [tag: mediapath] js /
Příklad: href = & quot; [tag: JS: common.js, main.js] Termín "RUBRIK_RUB_INFO= "Systémový tag odpovídající za vývod obsahu pole rubriky. ID-číslo pole. Xxx počet symbolů pro zobrazení." RUBRIK_SELECT_IN_LIST = "Prosím vyberte pole rubriky ze seznamu níže" +RUBRIK_TEMPLATE_ITEMS = "3ablona designu pro prvky požadavku." +RUBRIK_DOCID_INFO = "Systémový tag, který odpovídá identifikátoru dokumentu" +RUBRIK_DOCTITLE_INFO = "Systemový tag, který odpovídá názvu dokument" +RUBRIK_CDOCID_INFO = "Systémový tag, který odpovídá ID aktuálního dokumentu (ke kterému se váže požadavek)" +RUBRIK_DOCDATE_INFO = "Systémový tag, který odpovídá datu vydání publikace" +RUBRIK_CDOCDATE_INFO = "Systémový tag, který odpovídá datu vydání aktuálního dokumentu (ke kterému se váže požadavek)" +RUBRIK_DOCTIME_INFO = "Systémový tag, který odpovídá datu a času zveřejnění dokumentu" +RUBRIK_CDOCTIME_INFO = "Systémový tag, který odpovídá datu a času zveřejnění tohoto dokumentu (ke kterému se váže požadavek)" +RUBRIK_DATE_INFO = "Systémový tag, data a času zveřejnění dokumentu - přizpůsobený vzhled
. Příklad: [tag: Datum: d.m.Y]
Můžete použít distribuční systémy (Space -. /)" +RUBRIK_CDATE_INFO = "System tag, datum a čas zveřejnění dokumentu - přizpůsobitelné vzhledu
Příklad: [tag: Datum: DMY]
(ve kterém je požadavek na výstup)
můžete použít rozvody (. Space - /) " +RUBRIK_DOCAUTHOR_INFO = "Systémový tag, který odpovídá autoru dokumentu" +RUBRIK_DOCAUTHOR_AVATAR = "Systémový tag, který odpovídá avataru autora dokumentu" +RUBRIK_CDOCAUTHOR_INFO = "Systémový tag, který odpovídá autoru tohoto dokumentu (ke kterému se váže požadavek)" +RUBRIK_VIEWS_INFO = "Systémový tag, který zobrazuje počet zhlédnutí dokumentu" +RUBRIK_COMMENTS_INFO = "Systémový tag, který ukazuje počet komentářů u dokumentu . Upozornění:! Funguje pouze při nainstalovaném modulu "RUBRIK_PATH= "Systémový tag, který identifikuje kořen instalace" +RUBRIK_MEDIAPATH = "System tag, který definuje cestu ke složce šablony (příklad: [Tag: mediapath] images / logo.gif)" +RUBRIK_THUMBNAIL = "Tag odpovídající za vytvoření miniatury(za předpokladu, že v šabloně pole rubriky (šablony pro výstup předpokladu) je vybrán výstup: [tag: parametr: 0])" +RUBRIK_ALIAS_HEAD = "Přiřadit alias pro pole" +RUBRIK_ALIAS_HEAD_T = "Můžete použít pouze latinky a čísla
Příklad:! záhlaví " +RUBRIK_ALIAS_HEAD_R = "Rubrika" +RUBRIK_ALIAS_HEAD_F = "pole" +RUBRIK_ALIAS_ALIAS = "Alias ​​pole" +RUBRIK_ALIAS_NAME= "Název aliasu" +RUBRIK_ALIAS_BUTT = "Uložit" +RUBRIK_ALIAS_ERROR = "Chyba" +RUBRIK_ALIAS_RUBID = "Nesprávná rubrika" +RUBRIK_ALIAS_FIELDID = "Nesprávné pole" +RUBRIK_ALIAS_MATCH = "Nesprávné hodnoty" +RUBRIK_ALIAS_USED = "Tato hodnota je již používána" +RUBRIK_REPORT_QUICKSAVE = "Provedeno rychlé uložení nastavení rubriky" +RUBRIK_REPORT_SORTE = "Roztřídění rubriky provedeno" +RUBRIK_REPORT_SORTE_FIELDS = "Roztřídění polí rubriky provedeno" +RUBRIK_REPORT_PERMISION = "Právo na přístup k dokumentům v rubrice změněno" +RUBRIK_REPORT_COPY = "Kopie rubriky vytvořena" +RUBRIK_REPORT_TEMPL_RUB = "Šablona rubriky upravena" +RUBRIK_REPORT_FIELD_EDIT= "Pole upraveno" +RUBRIK_REPORT_FIELD_DEL = "Pole smazáno" +RUBRIK_REPORT_RUB = "Rubriky" +RUBRIK_REP_QUICKSAVE_H = "Hotovo" +RUBRIK_REP_QUICKSAVE_T = "Nastavení rubrik úsěšně uloženo" +RUBRIK_REPORT_ADD = "Rubrika přidána" +RUBRIK_REPORT_SAVE_TPL = "Šablona designu rubriky uložena" +RUBRIK_CODE_SAVED = "Spustitelný kód rubriky úspěšně uložen" +RUBRIK_CODE_SAVED_ERR = "Nelze uložit spustitelný kód pro danou rubriku.
Zkuste znovu." +RUBRIK_CODE_ERROR = "Chyba" +RUBRIK_CODE_SUCCESS = "Hotovo" +RUBRIK_CODE_UPDATE = "Spustitelný kód pro rubriku změněn" +RUBRIK_LOG_NEW_FIELD = "Pole rubriky přidáno" +RUBRIK_LOG_DEL_RUBRIC = "Rubrika odstraněna" +RUBRIK_LOG_NEW_RUBRIC = "Rubrika vytvořena" +RUBRIK_FILDS_SAVED = "Úspěšně uloženo" +RUBRIK_FILD_SAVED = "Pole úspěšně přidáno" +RUBRIK_FILDS_REPORT = "Pole rubriky uloženo" +RUBRIK_FILDS_ERROR = "Chyba" +RUBRIK_FILDS_SUCCESS = "Hotovo" +RUBRIC_ERROR = "Chyba" +RUBRIC_SUCCESS = "Hotovo" +RUBRIC_SAVED_PHP_ERR = "Je zakázáno využívat PHP kód v šablonách" +RUBRIC_SAVED_TPL_ERR = "Nepodařilo se uložit šablonu rubriky.
Zkusteznovu." +RUBRIC_SAVED_TPL = "Šablona rubriky úspěšně uložena." +RUBRIC_SAVED_FLDTPL = "Šablona pole byla úspěšně uložena." +RUBRIK_TAG_SYSBLOCK = "Systémový tag výstupu systémového bloku." +RUBRIK_TAG_TEASER = "Systémový tag vývodu teaseru" +RUBRIK_TAG_ALIAS = "Systémový tag výstupu aliasu dokumenat" +RUBRIK_TAG_REQUEST = "Systémový tag výstupu dotazu" +RUBRIC_SAVED_PERMS = "Právo přístupu k dokumentům úspěšně uloženo" +RUBRIK_IFELSE = "Podmínky" +RUBRIK_IFELSE_1 = "Výstup v případě, pokud pole není prázdné" +RUBRIK_IFELSE_2 = "Jiný výstup, pokud je pole prázdné" +RUBRIK_SAMPLE = "Příklad" +RUBRIC_TMPLS_BUTTON = "Jiné šablony rubriky" +RUBRIC_TMPLS_HEAD = "Seznam dalších šablon rubriky" +RUBRIC_TMPLS_ADD = "Přidat novou šablonu" +RUBRIC_TMPLS_ID = "id" +RUBRIC_TMPLS_NAME = "Název" +RUBRIC_TMPLS_NAME_FULL = "Název šablony designu rubriky" +RUBRIC_TMPLS_AUTHOR = "Autor" +RUBRIC_TMPLS_DATE = "Datum" +RUBRIC_TMPLS_COUNT_DOCS = "Počet dokumentů" +RUBRIC_TMPLS_ACTIONS = "Akce" +RUBRIC_TMPLS_COPY = "Kopírovat šablonu" +RUBRIC_TMPLS_COPY_TIP = "Zadejte název šablony" +RUBRIC_TMPLS_COPY_TIP2 = "Uveďte prosím název kopírované šablony" +RUBRIC_TMPLS_EDIT = "Upravit" +RUBRIC_TMPLS_DELETE = "Odstranit" +RUBRIC_TMPLS_DELETE_C = "Opravdu chcete smazat šablonu?" +RUBRIC_TMPLS_TIP = "Můžete vytvořit neomezené množství šablon pro jednu rubriku" +RUBRIC_TMPLS_NO_ITEMS = " Zpráva:
Nejsou k dispozici žádné další šablony." +RUBRIC_TMPLS_FROM = "Kopie primární šablony vytvořena" +RUBRIC_TMPLS_INNAME = "Zadejte název šablony" +RUBRIC_TEMPL_REPORT = "Dodatečná šablona rubriky upravena" +RUBRIC_TMPLS_LOG_DEL = "Dodatečná šablona rubriky smazaná." diff --git a/admin/lang/cz/scripts.js b/admin/lang/cz/scripts.js new file mode 100644 index 0000000..ce2e152 --- /dev/null +++ b/admin/lang/cz/scripts.js @@ -0,0 +1,65 @@ +// Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +var logoutTitle = "východ z Ovládacích panelů"; +var logoutConfirm = "Opravdu chcete odejít?"; +var clearCacheTitle = "Smazání mezipaměti"; +var clearCacheConfirm = "Opravdu chcete smazat mezipaměť?"; +var clearCacheSessTitle = "Mazání mezipaměti a relací"; +var clearCacheSessConfirm = "Opravdu chcete vymazat mezipaměť a relace?"; +var clearThumbTitle = "Odstranit miniatury"; +var clearThumbConfirm = "Opravdu chcete vymazat všechny miniatury zobrazení?
z adresáře pro ukládání souborů (UPLOAD_DIR)?"; +var clearRevTitle = "Smazat revizi dokumentů"; +var clearRevConfirm = "Opravdu chcete vymazat všechny revize dokumentů?"; +var clearCountTitle = "Resetovat denní počítadlo dokumentů"; +var clearCountConfirm = "Opravdu chcete vynulovat denní počítadlo dokumentů?"; +var cacheShowTitle = "Zobrazit velikost cache"; +var cacheShowConfirm = "Jste si jisti, že chcete vidět velikost cache?
může to trvat nějaký čas."; +var ajaxErrorStatus = "Žádné spojení.
Zkontrolujte připojení."; +var ajaxErrorStatus404 = "Stránka, kterou hledáte nebyla nalezena. [404]"; +var ajaxErrorStatus401 = "Požadavek nelze splnit.
Chyba autorizaca pro vykonání požadavku [401]"; +var ajaxErrorStatus500 = "Došlo k vnitřní chybě.
Zkuste to znovu později. [500]"; +var ajaxErrorStatusJSON = "Špatná odpověď serveru
Data jsou ve špatném formátu JSON."; +var ajaxErrorStatusTimeOut = "Čas požadavku uplynul."; +var ajaxErrorStatusAbort = "Ajax požadavek přerušen."; +var ajaxErrorStatusMess = "Cyhba:
"; +var delCascadTitle = "odstranit zobrazení; +var delCascadConfirm += "Opravdu chcete smazat?"; +var saveMessageOk = "Data uložena"; + +//===== Date & Time Pickers =====// +$.datepicker.regional['cz'] = { + closeText: 'Zavřít', + prevText: '', + currentText: 'Nyní', + monthNames: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', + 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec' + ], + monthNamesShort: ['Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čvn', + 'Čvc', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro' + ], + dayNames: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'], + dayNamesShort: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], + dayNamesMin: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], + weekHeader: 'Ne', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: '' +}; +$.datepicker.setDefaults($.datepicker.regional['cz']); + +$.timepicker.regional['cz'] = { + timeOnlyTitle: 'Vyberte čas', + timeText: 'Čas', + hourText: 'Hodiny', + minuteText: 'Minuty', + secondText: 'Sekundy', + millisecText: 'milisekundy', + currentText: 'Teď', + closeText: 'Zavřít', + ampm: false +}; +$.timepicker.setDefaults($.timepicker.regional['cz']); \ No newline at end of file diff --git a/admin/lang/cz/settings.txt b/admin/lang/cz/settings.txt new file mode 100644 index 0000000..9ca4ae1 --- /dev/null +++ b/admin/lang/cz/settings.txt @@ -0,0 +1,109 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[settings] +SETTINGS_COUNTRIES = "Správce zemí" +SETTINGS_COUNTRIES_ALL = "Seznam zemí" +SETTINGS_COUNTRY_TIP = "Vyberte prosím země, které budou k dispozici při registraci nových uživatelů v systému. Pamatujte, že Vámi vybraný seznam může být použit jinými moduly v systému." +SETTINGS_ACTIVE = "Aktivní?" +SETTINGS_COUNTRY_NAME = "Název země" +SETTINGS_IN_EC = "Vztahuje se k EU?" +SETTINGS_YES = "Ano" +SETTINGS_NO = "Ne" +SETTINGS_BUTTON_SAVE = "Uložit změny" +SETTINGS_BUTTON_SAVE_AJAX = "Použít (CTRL+S)" +SETTINGS_OR = "nebo" +SETTINGS_MAIN_TITLE = "Správa obecných nastavení systému" +SETTINGS_CASE_TITLE = "Dodatečná nastavení" +SETTINGS_MAIN = "Obecná nastavení systému" +SETTINGS_SAVED = "Nastavení systému úspěšně uloženo" +SETTINGS_SAVED_ERR = "Nepodařilo se uložit nastavení.
Zkuste znovu." +SETTINGS_SAVE_INFO = "Zde můžete upravit globální parametry systému. Prosím, buďte nanejvýš opatrní a pamatujte, že nesprávné nastavení může vyřadit systém z provozu." +SETTINGS_SAVE_CONFIRM = "Opravdu chcete uložit nastavení systému?" +SETTINGS_SITE_NAME = "Název webové stránky:" +SETTINGS_SITE_COUNTRY = "Země webové stránky:" +SETTINGS_EMAIL_SENDER = "E-mail odesílatele" +SETTINGS_EMAIL_NAME = "jméno odesílatele e-mailu:" +SETTINGS_MAIL_TRANSPORT = "Způsob odeslání:" +SETTINGS_MAIL = "mail" +SETTINGS_SENDMAIL = "sendmail" +SETTINGS_SMTP = "smtp" +SETTINGS_SMTP_SERVER = "Server SMTP:" +SETTINGS_MAIL_PORT = "Port SMTP:" +SETTINGS_SMTP_NAME = "Uživatel:" +SETTINGS_SMTP_PASS = "Heslo:" +SETTINGS_SMTP_ENCRYPT = "Šifrování" +SETTINGS_SMTP_NOENCRYPT = "Ne" +SETTINGS_MAIL_PATH = "Cesta ke složce sendmail:" +SETTINGS_SYMBOL_BREAK = "Nucený přenos po (znaky):" +SETTINGS_SYMBOL_BREAK_INFO = "Ne více než 1000 podle RFC 2822" +SETTINGS_SYMBOLS = "znaky" +SETTINGS_TEXT_EMAIL = "Zpráva uživateli po vytvoření účtu, kde:" +SETTINGS_TEXT_INFO = "%NAME% - Jméno uživatele
%HOST% - Odkaz na stránky
%PASSWORD% - Heslo
%EMAIL% - E-mail uživatele
%EMAILSIGNATURE% - Podpis zprávy" +SETTINGS_EMAIL_FOOTER = "Text podpisu:" +SETTINGS_ERROR_PAGE = "Chyba HTTP Stránka 404: Stránka nebyla nalezena" +SETTINGS_PAGE_DEFAULT = "(default Id:2)" +SETTINGS_TEXT_PERM = "text zprávy v případě, že uživatel nemá práva:" +SETTINGS_HIDDEN_TEXT = "text zprávy v případě, že uživatel nemá práva pro dostup informací skryté tagem [tag:hide:X,X]...[/tag:hide]" + +SETTINGS_NAVI_BOX = "Box stránkové navigace:
Např.: <ul>%s</ul>" +SETTINGS_LINK_BOX = "Box prvků pro stránkovou navigaci:
Příklad: <li>%s</li>" +SETTINGS_TOTAL_BOX = "Box textu před čísly stránek:
Příklad: <span>%s</span>" +SETTINGS_ACTIVE_LINK_BOX= "Box aktivního prvku:
Např.: <span class="active">%s</span>" +SETTINGS_PAGE_SEPAR = "Box značící přítomnost stran:
Např.: <li>%s</li>" +SETTINGS_PAGE_BEFORE = "Text před čísly stránek:
Např.: strana %d z %d" +SETTINGS_PAGE_START = "Text odkazu "První":" +SETTINGS_PAGE_END = "Text odkazu "Poslední":" +SETTINGS_PAGE_SEPARATOR = "Text označující přítomnost stránek kromě viditelných" +SETTINGS_PAGE_NEXT = "Text odkazu "Další":" +SETTINGS_PAGE_PREV = "Text odkazu "Předchozí":" + +SETTINGS_MAIN_BREADCRUMBS = "Výstupní nastavení “drobečkové navigace”" +SETTINGS_BREAD_BOX = "Box “drobečková navigaced”:" +SETTINGS_BREAD_SEPPARATOR = "Dělič mezi odkazy:" +SETTINGS_BREAD_BOX_LINK = "Odkazový box:" +SETTINGS_BREAD_BOX_LASTLINK = "Ukazovat poslední prvek:" +SETTINGS_BREAD_SELF_BOX = "Box posledního prvku" + +SETTINGS_DATE_FORMAT = "Formát data:" +SETTINGS_TIME_FORMAT = "Formát data a času:" +SETTINGS_CLEAR_CACHE = "Smazat cache" +SETTINGS_USE_DOCTIME = "Použít datum zveřejnění dokumentů" +SETTINGS_INFO = "Pokročilé" +SETTINGS_MAIN_SETTINGS = "Obecná nastavení systému" +SETTINGS_MAIN_MAIL = "Nastavení pošty" +SETTINGS_MAIN_PAGENAVI = "Nastavení výstupu stránkové navigace" +SETTINGS_NAME = "Parametr" +SETTINGS_VALUE = "Hodnota" +SETTINGS_EDITOR_CKEDITOR = "CKEditor" + +SETTINGS_ERROR = "Chyba" +SETTINGS_SUCCESS = "Hotovo" + +SETTINGS_SAVE_DOP = "Pokročilá nastavení systému změněna" +SETTINGS_SAVE_MAIN = "Obecná nastavení systému změněna" +SETTINGS_SAVE_COUNTRY = "Nastavení zemí změněno" + +SETTINGS_LANG_EDIT = "Správa jazyků" +SETTINGS_LANG_TITLE = "Pozor! Nastavení jazyku se musí odehrát před vyplněním stránky!" +SETTINGS_LANG_AEDIT = "Upravit" +SETTINGS_LANG_AON = "Zapnout" +SETTINGS_LANG_AOFF = "Vypnout" +SETTINGS_LANG_ADEFAULT = "Nastavit jako výchozí" +SETTINGS_LANG_ADEFAULT_HINT = "" +SETTINGS_LANG_ID = "Id" +SETTINGS_LANG_FLAG = "Checkbox" +SETTINGS_LANG_SYSTEM = "Systémové" +SETTINGS_LANG_PREFIX = "Prefix" +SETTINGS_LANG_NAME = "Název" +SETTINGS_LANG_DEFAULT = "Výchozí" +SETTINGS_LANG_ACTION = "Akce" +SETTINGS_LANG_ADD = "Přidat jazyk" +SETTINGS_LANG_SAVE = "Uložit změny" + +SETTINGS_REV_DELETED = "Revize dokomentů úspěšně odstraněny" +SETTINGS_REV_DELETED_ERR = "Nepodařilo se odstranit revizi dokumentů.
Zkuste znovu." +SETTINGS_REV_UPDATE = "Revize dokumentů odstraněna" +SETTINGS_COUNT_DELETED = "Počítadlo dokumentů
úspěšně vynulován." +SETTINGS_COUNT_DELETED_ERR = "Nepodařilo se vynulovat hrubé
počítadlo dokumentů.
Zkuste znovu." +SETTINGS_COUNT_UPDATE = "Počítadlo dokumentů vynulován" +SETTINGS_CACHE_LIFETIME = "Pozor!!! Povoleno ukládání mezipaměti do nastavení systému. Změny vejdou v platnost, pouze po skončení životnosti cache, nebo po zákazu ukládání do mezipaměti." diff --git a/admin/lang/cz/sysblocks.txt b/admin/lang/cz/sysblocks.txt new file mode 100644 index 0000000..37230ba --- /dev/null +++ b/admin/lang/cz/sysblocks.txt @@ -0,0 +1,69 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +SYSBLOCK_HEAD = "Systémové jednotky" +SYSBLOCK_EDIT = "Ovládání systémových jednotek" +SYSBLOCK_EDIT_TIP = "Tato část obsahuje veškeré systémové jednotky." +SYSBLOCK_ID = "Id" +SYSBLOCK_NAME = "Název systémové jednotky" +SYSBLOCK_HTML = "Kód systémové jednotky" +SYSBLOCK_TAGS = "Tag" +SYSBLOCK_TAGS_2 = "HTML Tagy" +SYSBLOCK_EXTERNAL = "Povolit externí přístup k odkazu" +SYSBLOCK_EXTERNAL_H = "externí přístup k odkazu" +SYSBLOCK_EXTERNAL_GO = "Přejít" +SYSBLOCK_AJAX = "Dovolit provádění pouze Ajax" +SYSBLOCK_AJAX_H = "provádět pouze Ajax" + +SYSBLOCK_VISUAL = "Візуальний редактор" +SYSBLOCK_VISUAL_H = "Vizuální editor" + +SYSBLOCK_MEDIAPATH = "Systémový tag, cesty do designové složky" +SYSBLOCK_BREADCRUMB = "Systémový tag chlebových drobečků" +SYSBLOCK_DOCID_INFO = "Systémový tag, identifikátor dokomentu" +SYSBLOCK_PATH = "Instalace kořenové cesty" +SYSBLOCK_HOME = " Odkaz na domovskou stránku webové stránky" + +SYSBLOCK_AUTHOR = "Autor" +SYSBLOCK_DATE = "Datum vytvoření" +SYSBLOCK_TAG = "Systémový tag" +SYSBLOCK_ACTIONS = "Akce" +SYSBLOCK_NO_ITEMS = "Zpráva:
V současné době zde nejsou žádné uložené systémové jednotky" +SYSBLOCK_BUTTON_SAVE = "Uložit změny" +SYSBLOCK_BUTTON_ADD = "Přidat systémovou jednotku" +SYSBLOCK_BUTTON_COPY = "Kopírovat" +SYSBLOCK_INSERT_H = "Přidání systémové jednotky" +SYSBLOCK_EDIT_H = "Úpravy systémové jednotky" +SYSBLOCK_INNAME = "Zadejte název systémové jednotky" +SYSBLOCK_ENTER_NAME = "Zadejte název systémové jednotky" +SYSBLOCK_INSERT = "Zde můžete přidat, či změnit vybranou systémovou jednotku" + +SYSBLOCK_LINK = "Systémová jednotka je dostupná na adrese:" + +SYSBLOCK_SAVE = "Přidat" +SYSBLOCK_SAVEDIT = "Uložit změny" +SYSBLOCK_SAVE_NEXT = "Přidat a pokračovat v úpravách" +SYSBLOCK_SAVEDIT_NEXT = "Použít (CTRL+S)" + +SYSBLOCK_INTEXT = "Systémová jednotka" +SYSBLOCK_ADD = "Přidat novou systémovou jednotku" +SYSBLOCK_ADD_BUTTON = "Přidat" +SYSBLOCK_EDIT_HINT = "Upravit systémovou jednotku" +SYSBLOCK_DELETE_HINT = "Odstranit systémovou jednotku" +SYSBLOCK_DEL_HINT = "Opravdu chcete odstranit systémovou jednotku?" +SYSBLOCK_LIST_LINK = "Seznam systémových jednotek" +SYSBLOCK_FILE = "Soubor šablony" +SYSBLOCK_SAVED = "Systémova jednotka úspěšně uložena." +SYSBLOCK_COPY_TITLE = "írování systémové jednotky" +SYSBLOCK_COPY = "Kopírovat systémovou jednotku" +SYSBLOCK_COPY_TIP = "Zadejte název systémové jednotky" +SYSBLOCK_COPY_TIP2 = "Zadejte název systémové jednotky, která se kopíruje" +SYSBLOCK_EXIST = "Je nám líto, ale tento systém jednotky se stejným názvem již existuje." +SYSBLOCK_SQLUPDATE = "Systémová jednotka změněna" +SYSBLOCK_SQLNEW = "Nová systémová jednotka stvořena" +SYSBLOCK_SQLDEL = "Systémová jednotka odstraněna" +SYSBLOCK_OR = " nebo " + +SYSBLOCK_SAVED = "Systémová jednotka úspěšně uložena" +SYSBLOCK_SAVED_ERR = " Nepodařilo se uložit systémovou jednotku
Zkuste znovu." +SYSBLOCK_ERROR = "Chyba" +SYSBLOCK_SUCCESS = "Hotovo" \ No newline at end of file diff --git a/admin/lang/cz/templates.txt b/admin/lang/cz/templates.txt new file mode 100644 index 0000000..06cc191 --- /dev/null +++ b/admin/lang/cz/templates.txt @@ -0,0 +1,119 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +TEMPLATES_SUB_TITLE = "Správce šablon" +TEMPLATES_TIP1 = "Zde je seznam všech šablon v systému. Můžete zde smazat, editovat, nebo zkopírovat šablonu a vytvořit tak na její bázi novou." +TEMPLATES_ID = "ID" +TEMPLATES_NAME = "Název šablony" +TEMPLATES_NAME2 = "Název šablony:" +TEMPLATES_NAME3 = "zadejte název šablony:" +TEMPLATES_AUTHOR = "Autor" +TEMPLATES_DATE = "Datum vytvoření" +TEMPLATES_ACTION = "Akce" +TEMPLATES_DATE_FORMAT = "%d.%m.%y g." +TEMPLATES_DATE_FORMAT2 = "%H:%M" +TEMPLATES_IN = "v" +TEMPLATES_EDIT = "Editovat šablonu" +TEMPLATES_NO_CHANGE = "Je nám líto, ale nemáte oprávnění pro úpravy šablon." +TEMPLATES_DELETE = "odstranit šablonu" +TEMPLATES_DELETE_CONF = "Opravdu chcete odstranit tuto šablonu?" +TEMPLATES_NO_DELETE2 = "Je nám líto, ale nemůžete odstranit tuto šablonu, jelikož tato šablona využívá rubriku, nebo modul." +TEMPLATES_NO_DELETE3 = "Je nám líto, ale nemáte oprávnění pro mazání šablon" +TEMPLATES_COPY = "Kopírovat šablonu" +TEMPLATES_NO_COPY = "Je nám líto, ale nemáte oprávnění pro kopírování šablon." +TEMPLATES_LEGEND = "Hodnota ikony" +TEMPLATES_COPY_TITLE = "kopírování šablony" +TEMPLATES_TIP2 = "Zadejte prosím název zkopírované šablony" +TEMPLATES_TIP3 = "Zadejte prosím název šablony" +TEMPLATES_BUTTON_COPY = "Kopírovat" +TEMPLATES_TAG_INSERT = "Stiskněte název systémového tagu pro jeho vložení do pole šablony" +TEMPLATES_TITLE_NEW = "Vytvoření nové šablony" +TEMPLATES_TITLE_EDIT = "editování šablony" +TEMPLATES_WARNING1 = "Buďte opatrní při úpravách šablon a pamatujte, že nesprávným zadáním kódu může dojít ke zničení externího designu stránky." +TEMPLATES_WARNING2 = "Zde můžete ručně vytvořit novou šablonu a nahrát hotovou strukturu šablony z existujícího souboru. Mějte na paměti, že soubory z hotovou strukturou musí být umístěny v adresáři /inc/data/prefabs/templates/" +TEMPLATES_HTML = "HTML kod šablony" +TEMPLATES_USE_PHP = "Je nám líto, ale nemáte oprávnění pro editování šablony, jelikož využívá PHP kód." +TEMPLATES_BUTTON_SAVE = "Uložit změny" +TEMPLATES_BUTTON_SAVE_NEXT = "Použít (CTRL+S)" +TEMPLATES_FILE_SAVED = "Soubor byl úspěšně uložen" +TEMPLATES_BUTTON_ADD = "Přidat šablonu" +TEMPLATES_BUTTON_ADD_NEXT = "Přidat a pokračovat v úpravách" +TEMPLATES_BUTTON_LOAD = "Stáhnout" +TEMPLATES_LOAD_INFO = "Vyberte prosím ze seznamu soubor s hotovou strukturou šablony." +TEMPLATES_EXIST = "Je nám líto, ale šablona s tímto názvem již existuje." +TEMPLATES_NO_NAME = "Zadejte porsím název šablony" +TEMPLATES_ALL = "Seznam šablon" +TEMPLATES_OR = " nebo " + +TEMPLATES_FILE_NAME = "Název souboru" +TEMPLATES_CSS_FILES = "Seznam css souborů" +TEMPLATES_JS_FILES = "Seznam js souborů" +TEMPLATES_FILES = "Správce souborů" +TEMPLATES_EDIT_FILE = "Upravit soubor" +TEMPLATES_DEL_FILE = "odstranit soubor" + +TEMPLATES_TAGS = "Tag" +TEMPLATES_TAG_DESC = "Popis tagu" +TEMPLATES_THEME_FOLDER = "Název šablony (název složky ze soubory pro tuto šablonu)" +TEMPLATES_FOLDER = "Složka:" +TEMPLATES_PAGENAME = "Název webové stránky" +TEMPLATES_FILENAME = "Název souboru" +TEMPLATES_TITLE = "Název stránky" +TEMPLATES_KEYWORDS = "Klíčová slova (Meta - Keywords)" +TEMPLATES_DESCRIPTION = "Popis stránky (Meta - Description)" +TEMPLATES_INDEXFOLLOW = "Index zboží" +TEMPLATES_CANONICAL = "Kanonická stránka - doporučený exemplář sady stránek s velmi podobným obsahem." +TEMPLATES_PATH = "Instalace kořenové cesty" +TEMPLATES_MEDIAPATH = "Cesty ke složce s šablonou (Např.: [tag:mediapath]images/logo.gif)" + +TEMPLATES_CSS = "Komprimuje několik CSS souborů do jednoho. Vrací cestu.
FFF - název souborů, oddělených čárkou
P - cesta ke složce se soubory není vyžadována. Výchozí - [tag:mediapath]css/

Např.: href="[tag:css:reset.css,style.css]"" + +TEMPLATES_JS = "Komprimuje několok js souborů do jednoho. Vrací cestu.
FFF - název souborů, oddělených čárkou
P - cesta ke složce se soubory není vyžadována. Výchozí - [tag:mediapath]js/

Např.: href="[tag:js:common.js,main.js]"" + +TEMPLATES_MEDIAPATH = "Cesta ke složce se šablonou (Např.: [tag:mediapath]images/logo.gif)" +TEMPLATES_MAINCONTENT = "Tag k hlavnímu obsahu" +TEMPLATES_QUICKFINDER = "Pop-up menu rychlé navigace" +TEMPLATES_DOCUMENT = "Odkaz na aktuální dokument" +TEMPLATES_ALIAS = "Odkaz na aktuální dokument (Alias)" +TEMPLATES_SYSBLOCK = "Systémový tag bloků" +TEMPLATES_TEASER = "Systémový tag hlavolamu" +TEMPLATES_PRINTLINK = "Odkaz na "Verze pro tisk"" +TEMPLATES_HOME = "Odkaz na hlavní stránku" +TEMPLATES_BREADCRUMB = "Systémový tag drobečkové navigace" +TEMPLATES_VERSION = "Zobrazení info o bezpečnosti informací" +TEMPLATES_NAVIGATION = "Menu navigace (ххх - číslo menu)" +TEMPLATES_IF_PRINT = "Obsah se zobrazí při tisku." +TEMPLATES_DONOT_PRINT = "Obsah se nezobrazí při tisku" +TEMPLATES_RUBHEADER = "Nastavitelná šablona kategorie
(Šablona designu HEADER)" +TEMPLATES_NO_ITEMS = "V současné době zde nejsou žádné soubory" + +TEMPLATES_CACHE_SUCCESS = "Cache úspěšně smazána" +TEMPLATES_CACHE_SUCCESS_LOG = "Cache smazán" + +TEMPLATES_CSS_TITLE = "Buďte opatrní při úpravách souborů a pamatujte, že nesprávným zadáním kódu může dojít ke zničení externího designu stránky" +TEMPLATES_CSS_EDITOR = "Editor CSS souborů" + +TEMPLATES_JS_TITLE = "Buďte opatrní při úpravách souborů a pamatujte, že nesprávným zadáním kódu může dojít ke zničení externího designu stránky" +TEMPLATES_JS_EDITOR = "Editor CSS souborů" + +TEMPLATES_REPORT_NEW = "Šablona vytvořena" +TEMPLATES_REPORT_CHANGE = "Šablona změněna" +TEMPLATES_REPORT_PHP = "Pokus využití PHP kodu v šabloně" +TEMPLATES_REPORT_PHP_CSS = "Pokus využití PHP kodu v css souboru" +TEMPLATES_REPORT_PHP_JS = "Pokus využití PHP kodu js sabouru" +TEMPLATES_REPORT_PHP_ERR = "Využití PHP kodu je zakázáno." +TEMPLATES_REPORT_ID_ERR = " Pokus o odstranění hlavní šablony" +TEMPLATES_REPORT_DELETE = "Šablona smazána" +TEMPLATES_REPORT_FILE = "Soubor upraven" +TEMPLATES_REPORT_COPY = "Kopie šablony vytvořena" +TEMPLATES_REPORT_DEL_OK = "Soubor úspěšně smazán" +TEMPLATES_REPORT_DEL_ER = "Nelze odstranit soubor" + +TEMPLATES_REPORT_ERROR_TEXT = "HTML kód šablony je prázdný" +TEMPLATES_REPORT_ERROR_TITLE = "Nevyplněný název šablony" + +TEMPLATES_SAVED = "Šablona úspěšně uložena" +TEMPLATES_SAVED_FILE = "Soubor úspěšně uložen" +TEMPLATES_SAVED_ERR = " Nepovedlo se uložit šablonu.
Zkuste ještě jednou." +TEMPLATES_SAVED_ERR_FILE = "Nepovedlo se uložit soubor.
Zkuste ještě jednou." +TEMPLATES_ERROR = "Chyba" +TEMPLATES_SUCCESS = "Hotovo" \ No newline at end of file diff --git a/admin/lang/cz/user.txt b/admin/lang/cz/user.txt new file mode 100644 index 0000000..6323b3f --- /dev/null +++ b/admin/lang/cz/user.txt @@ -0,0 +1,92 @@ +# Slavík))) 02,2017 Olga "Un.Known" Andělová # https://www.facebook.com/olga.andelova + +[user] +USER_SUB_TITLE = "Správce uživatelů" +USER_TIP1 = "Zde je uveden seznam uživatelů v systému. Můžete zde upravovat parametry uživatelů, odstranit uživatele, nebo jej převést do jiné skupiny." +USER_ID = "ID" +USER_NAME = "Jméno a příjmení uživatele" +USER_NAME2 = "Uživatelské jméno" +USER_GROUP = "Umístění ve skupině" +USER_STATUS_WAIT = "Očekává aktivaci" +USER_LAST_VISIT = "Poslední přihlášení" +USER_REGISTER_DATE = "Datum registrace" +USER_ACTION = "Akce" +USER_DELETE = "Odstranit uživatele" +USER_EDIT = "Upravit uživatele" +USER_DATE_FORMAT = "%d.%m.%Y %H:%M" +USER_NO_CHANGE = "Je nám líto, ale nemáte dostatečná práva k upravování uživatelů" +USER_DELETE_CONFIRM = "Opravdu chcete odstranit tohoto uživatele?" +USER_LEGEND = "Hodnoty ikon" +USER_BUTTON_SAVE = "Uložit změny" +USER_ORDERS = "Historie objednávek" +USER_DOWNLOADS = "Historie objednávek PO " +USER_MARK_DELETE = "Označit pro vymazání" +USER_NEW_TITLE = "Vytvořit nový účet" +USER_NEW_TIP = "Pro přidání nového uživatele vyplňte příslušné informace. Buďte opatrní při výběru skupiny pro tohoto uživatele. Neplatná skupina může omezit přístup uživatele k příslušným oddílům na webové stránce, či naopak umožnit přístup do uzavřených úseků." +USER_EDIT_TITLE = "Úprav uživatele" +USER_EDIT_TIP = " Zde můžete upravovat uživatelská nastavení také změnit heslo a skupinu uživatele." +USER_ERRORS = "Chyba:" +USER_FIRSTNAME = "Jméno:" +USER_FIRSTNAME_ADD = "Zadejte uživatelské jméno:" +USER_LASTNAME = "Příjmení:" +USER_EMAIL = "E-mailová adresa:" +USER_NICK = "Nick na fóru:" +USER_SIGNATURE = "Podpis na fóru:" +USER_AVATAR = "Avatar:" +USER_TAX = "Zdanění:" +USER_COMPANY = "Společnost:" +USER_HOUSE_STREET = "Ulice / Číslo budovy:" +USER_ZIP_CODE = "PSČ:" +USER_CITY = "Místo bydliště:" +USER_PASSWORD = "Heslo:" +USER_PASSWORD_CHANGE = "Změnit" +USER_PASSWORD_SHOW = "Ukázat heslo" +USER_YES = "Ano" +USER_NO = "Ne" +USER_COUNTRY = "Země:" +USER_PHONE = "Mobil:" +USER_FAX = "Fax:" +USER_BIRTHDAY = "Datum narození:" +USER_BIRTHDAY_FORMAT = " ve formátu (DD.MM.RRRR)" +USER_NOTICE = "Doplňující informace:" +USER_MAIN_GROUP = "Hlavní skupina:" +USER_SECOND_GROUP = "Další skupina:" +USER_SECOND_INFO = "Výběr několika skupin" +USER_STATUS = "Status uživatele:" +USER_ACTIVE = "Aktivní" +USER_INACTIVE = "Neaktivní" +USER_BUTTON_ADD = "Přidat uživatele" +USER_SEND_INFO = "Informovat uživatele poštou" +USER_MESSAGE_SUBJECT = "Téma zprávy:" +USER_MESSAGE_TEXT = "Text zprávy:" +USER_EMAIL_EXIST = "Je nám líto, ale zadané e-mailová adresa se již v systému používá." +USER_ERROR_DATEFORMAT = "Datum narození není uvedeno ve správném formátu." +USER_PASSWORD_SHORT = "Zadané heslo je příliš krátké. Zadejte prosím nejméně pět znaků." +USER_PASSWORD_ERROR = " Pole pro heslo obsahuje neplatné znaky." +USER_NO_EMAIL = "Pole E-mailová adresa není vyplněno. Zadejte, prosím, Váš e-mail." +USER_NO_PASSWORD = " Pole Heslo není vyplněno. Zadejt, prosím, Vaše heslo." +USER_EMAIL_ERROR = "E-mailová adresa obsahuje neplatné znaky, zkontrolujte zadanou adresu." +USER_NO_FIRSTNAME = "Pole Uživatelské jméno je prázdné, zadejte prosím jméno uživatele. " +USER_NO_USERNAME = "Pole login je prázdné, zadejte prosím login uživatele." +USER_ERROR_FIRSTNAME = "Pole Jménno uživatele obsahuje neplatné znaky." +USER_ERROR_USERNAME = "Pole login obsahuje neplatné znaky." +USER_NO_LASTNAME = "Pole příjmení uživatele je prázdné. Zadejte prosím příjmení uživatele." +USER_ERROR_LASTNAME = "Pole příjmení obsahuje neplatné znaky." +USER_MAIL_BODY1 = "Vítejte %USER%,%N%%N%" +USER_MAIL_BODY2 = "Váš účet byl úspěšně aktivován. Použijte své přihlašovací údaje pro přístup k webu. %HOST%." +USER_MAIL_FOOTER = "%N%%N%S pozdravy, %HOMEPAGENAME%%N%%N%%HOST%" +USER_MAIL_SUBJECT = "Váš účet byl aktivován" +USER_MAIL_PASSWORD = "Informace pro změnu hesla" +USER_MAIL_PASSWORD2 = "Upozorňujeme Vás na změnu hesla.%N%%N%Vaše nové heslo je: %NEWPASS%" +USER_NEW_ADD = "Vytvoření nového uživatele" +USER_ALL = "Seznam uživatelů" +USER_LOGIN = "Login v systému:" +SETTINGS_NAME = "Parametr" +SETTINGS_VALUE = "Hodnota" +USER_LIST_EMPTY = "Hledaný uživatel neexistuje.
Zkuste upravit parametry hledání." +USER_REPORT_ADD = "Uživatel přidán" +USER_REPORT_EDIT = "Uživatelské nastavení editováno" +USER_REPORT_DEL = "Uživatel odstraněn" +USER_REPORT_GROUP = "Skupina pro uživatele změněna" +USER_YOUR_NOT_CHANGE = "Chyba! Je nám líto, ale nemáte oprávnění pro úpravy tohoto uživatele." +USER_WARNING_TIP = "Pozor! Buďte opatrní při úpravě tohoto uživatele." \ No newline at end of file diff --git a/admin/lang/pl/blocks.txt b/admin/lang/pl/blocks.txt new file mode 100644 index 0000000..eb919b9 --- /dev/null +++ b/admin/lang/pl/blocks.txt @@ -0,0 +1,68 @@ +BLOCK_HEAD = "Візуальні блоки" +BLOCK_EDIT = "Керування візуальними блоками" +BLOCK_EDIT_TIP = "У цьому розділі надані усі візуальні блоки." +BLOCK_ID = "Id" +BLOCK_NAME = "Назва візуального блока" +BLOCK_HTML = "Код візуального блока" +BLOCK_TAGS = "Тег" +BLOCK_TAGS_2 = "HTML Tags" + + +BLOCK_VISUAL = "Візуальний редактор" +BLOCK_VISUAL_H = "Візуальний редактор" + +BLOCK_MEDIAPATH = "Системний тег, шлях до папки дизайна" +BLOCK_BREADCRUMB = "Системний тег хлібних крихт" +BLOCK_DOCID_INFO = "Системний тег, ідентифікатор документа" +BLOCK_PATH = "Кореневий шлях установки" +BLOCK_HOME = "Посилання на головну сторінку сайта" + +BLOCK_AUTHOR = "Автор" +BLOCK_DATE = "Дата створення" +BLOCK_TAG = "Системний тег" +BLOCK_ACTIONS = "Дія" +BLOCK_NO_ITEMS = "Повідомлення:
На даний час немає збережених візуальних блоків." +BLOCK_BUTTON_SAVE = "Зберегти зміни" +BLOCK_BUTTON_ADD = "Додати візуальний блок" +BLOCK_BUTTON_COPY = "Копіювати" +BLOCK_INSERT_H = "Додавання візуального блока" +BLOCK_EDIT_H = "Редагування візуального блока" +BLOCK_INNAME = "Введіть назву візуального блока" +BLOCK_ENTER_NAME = "Будь ласка, вкажіть назву візуального блока" +BLOCK_INSERT = "Тут Ви можете додати або змінити обраний Вами візуальний блок" + +BLOCK_SAVE = "Додати" +BLOCK_SAVEDIT = "Зберегти зміни" +BLOCK_SAVE_NEXT = "Додати та продовжити редагування" +BLOCK_SAVEDIT_NEXT = "Примінити (CTRL+S)" + +BLOCK_INTEXT = "Візуальний блок" +BLOCK_ADD = "Додати новый візуальний блок" +BLOCK_ADD_BUTTON = "Додати" +BLOCK_EDIT_HINT = "Редагувати візуальний блок" +BLOCK_DELETE_HINT = "Видалити блок" +BLOCK_DEL_HINT = "Ви впевнені, що бажаєте видалити візуальний блок?" +BLOCK_LIST_LINK = "Список візуальних блоків" +BLOCK_FILE = "Файл шаблона" +BLOCK_SAVED = "Блок успішно збережено." +BLOCK_COPY_TITLE = "Копіювання візуального блока" +BLOCK_COPY = "Копіювати візуальний блок" +BLOCK_COPY_TIP = "Будь ласка, вкажіть назву візуального блока" +BLOCK_COPY_TIP2 = "Будь ласка, вкажіть назву для зкопійованого візуального блока" +BLOCK_EXIST = "Даруйте, але візуальний блок з такою назвою уже існує" +BLOCK_SQLUPDATE = "Змінив блок" +BLOCK_SQLNEW = "Створив новий візуальний блок" +BLOCK_SQLDEL = "Видалив візуальний блок" +BLOCK_OR = " або " + +BLOCK_SAVED = "Візуальний блок успіщно збережено" +BLOCK_SAVED_ERR = "Не вдалося зберегти візуальний блок.
Спробуйте ще раз." +BLOCK_ERROR = "Помилка" +BLOCK_SUCCESS = "Виконано" + +BLOCK_DESCRIPTION = "Короткий опис" +BLOCK_ALIAS = "Аліас" +BLOCK_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:BLOCK:alias] замість [tag:BLOCK:id]. Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах цих блоків" +BLOCK_ACCEPT = "Цей аліас можна використовувати" +BLOCK_ER_SYN = "Неправильний аліас!
Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +BLOCK_ER_EXISTS = "Неправильний аліас!
Такий аліас уже прив’язаний до іншого візкального блока" \ No newline at end of file diff --git a/admin/lang/pl/dbactions.txt b/admin/lang/pl/dbactions.txt new file mode 100644 index 0000000..62d7a92 --- /dev/null +++ b/admin/lang/pl/dbactions.txt @@ -0,0 +1,49 @@ +# Język polski 02,2017 duncan + +DB_SUB_TITLE = "Zarządzanie bazami danych" +DB_ACTION_WARNING = "Uwaga!\nWszystkie działania codo pracy z bazą danych wykonujesz na własne ryzyko.\n\nProszę pamiętać, że wszelkie działania w bazie danych mogą uszkodzić istniejącą informację.\n\Czy na pewno chcesz kontynuować?\n\n" +DB_ACTION_RESET = "Uwaga!\nPróbujesz odzyskać bazę danych z kopii zapasowej. Wszystkie istniejące informacje zostaną usunięte i zaisane ponownie.\nProszę pamiętać, że podczas przywracania bazy danych, trzeba będzie awtoryzować się ponownie\n\nCzy na pewno chcesz kontynuować?\n\n" +DB_OPTION_LIST = "Struktura bazy danych" +DB_BUTTON_ACTION = " wykonać działanie" +DB_OPTIMIZE_DATABASE = "Optymalizacja bazy danych" +DB_OPTIMIZE_INFO = "Opcja ta pozwala zwiększyć wydajność i zmniejszyć rozmiar bazy danych. Zalecany odstęp pomiędzy optymalizacjami musi wynosić co najmniej 1 raz w tygodniu." +DB_REPAIR_DATABASE = "Odbudowa uszkodzonych tablic" +DB_REPAIR_INFO = "Ta funkcja pozwala wykonać próbę naprawy uszkodzonych tablic w bazie danych, w przypadku nieprawidłowego wyświetlania informacji na stronie internetowej." +DB_BACKUP_DATABASE = "Utworzenie kopii zapasowej " +DB_BACKUP_INFO = "Ta funkcja umożliwia utworzenie kopii zapasowej wszystkich baz danych, lub poszczególnych tablic. Proszę wybrać z listy po lewej te tablicy, dla których chcesz wykonać kopię zapasową. Aby wybrać wiele tablic przytrzymaj przycisk CTRL." +DB_RESTORE_TITLE = " Przywracanie bazę danych z kopii zapasowej" +DB_RESTORE_FILE = "Przywracanie bazy danych z pliku" +DB_BUTTON_RESTORE = " Przywrócić" +DB_ACTION = "Wybierz działanie" +DB_TIPS = "Uwaga! Wszystkie działania codo pracy z bazą danych wykonujesz na własne ryzyko. Należy pamiętać, że wszelkie działania w bazie danych mogą uszkodzić istniejącą informację." +DB_BACKUP_SERVER = "Przechować kopię zapasową na serwerze" +DB_SC = "Operacja z bazą danych jest wykonana pomyślnie" + +DB_OPTIMIZE_DATABASE_SC = "Optymalizacja bazy danyzh jest wykonana pomyślnie" +DB_REPAIR_DATABASE_SC = "Odbudowa uszkodzonych tablic jest wykonana pomyślnie" + +DB_REPORT_DUMP = "Kopiowanie zapasowe bazy danych jest zakończone" +DB_REPORT_DUMP_RECOVER = "Odnowienie bazy danych z kopii zapasowej jest zakończone" +DB_REPORT_DUMP_OPTIM = "Optymaizacja bazy danych jest zakończona" +DB_REPORT_DUMP_TABLE = "Odnowienie tablic bazy danych jest zakończone" + +DB_FILE_DATA = "Data utworzenia" +DB_FILE_SIZE = "Rozmiar" +DB_FILE_NAME = "Nazwa pliku" +DB_ACTIONS = "Działanie" +DB_ACTIONS_EDIT = "Edytować" +DB_ACTIONS_DEL = "Usunąć" +DB_ACTIONS_RESTORE = "Odnowić" +DB_ACTIONS_SAVE = "Zapisz w komputerze" + +DB_REPORT_DUMP_DEL_OK = "Plik kopii zapasowej bazy danych jest usunięty" +DB_REPORT_DUMP_DEL_ER = "Nie udało się usunąć pliku kopii zapasowej bazy danych" +DB_REPORT_DUMP_ER = " Błąd. Import bazy danych nie powiódł się, ponieważ plik zrzutu jest nieobecny lub uszkodzony" + +DB_ACTIONS_RESTORE_H = "Odnowić kopię zapasową" +DB_ACTIONS_RESTORE_T = "Czy na pewno chcesz odnowić kopię zapasową bazy danych?" + +DB_ACTIONS_DELETE_H = "Usunąć plik" +DB_ACTIONS_DELETE_T = "Czy na pewno chcesz usunąć plik kopii zapasowej bazy danych?" + +DB_NO_FILES_MESS = "Obecnie nie ma plików bazy danych kopii zapasowych" diff --git a/admin/lang/pl/docs.txt b/admin/lang/pl/docs.txt new file mode 100644 index 0000000..bed7639 --- /dev/null +++ b/admin/lang/pl/docs.txt @@ -0,0 +1,279 @@ +# Język polski 02,2017 duncan + +[docs] +DOC_SUB_TITLE = "Zarządzanie dokumentami" +DOC_TIPS = "Tutaj znajduje się lista wszystkich dokumentów znajdujących się w systemie. Można wykonywać podstawowe operacje na dokumentach, takich jak:. przegląd, redagowanie, usunięcie dokumentu , a także zostawić notatkę do dowolnego dokumentu." +DOC_DATE_FORMAT = "%d.%m.%Y %H:%M" +DOC_LEGEND = "Znaczenie piktogramu" +DOC_LEGEND_EDIT = "Redagowanie dokumentu" +DOC_LEGEND_SHOW = "Przegląd strony w nowym oknie" +DOC_LEGEND_ENABLE = "Zrobić dokument aktywnym" +DOC_LEGEND_DISABLE = "Zrobić dokument nieaktywnym" +DOC_LEGEND_TEMP_DELETE = "Tymczasowo usunąć dokument (w kosz)" +DOC_LEGEND_RESTORE = "Odnowić dokument (z kosza)" +DOC_LEGEND_FINAL_DELETE = "Ostateczne usunięcie dokumentu" +DOC_CHOSE_RUB = "Wybierz rubrykę" +DOC_ID = "ID" +DOC_URL_RUB = "URL" +DOC_TITLE = "Nazwa dokumentu" +DOC_URL_TITLE = "Link (odsyłacz) do dokumentu" +DOC_IN_RUBRIK = "Rubryka" +DOC_IN_NEW = "Nowy dokument" +DOC_CREATED = "Opublikowane" +DOC_EDIT = "Odredagowane" +DOC_PRINTED = "Nadrukowane" +DOC_CLICKS = "przeglądów" +DOC_AUTHOR = "Aauthor" +DOC_ACTIONS = "Działania" +DOC_EDIT_TITLE = "Edytuj ten dokument" +DOC_CHANGE_RUBRIC = "Przenieś ten dokument do innej rubryki" +DOC_CHANGE_AUTOR = "Zmień autora dokumentu" +DOC_SHOW_TITLE = "Przegląd dokumentu (odsyłacz bez CNC)" +DOC_SHOW2_TITLE = "Przegląd dokumentu (odsyłacz z CNC)" +DOC_SHOW3_TITLE = "Document bez nazwy" +DOC_CREATE_NOTICE_TITLE = "Zostawić notatkę" +DOC_REPLY_NOTICE_TITLE = "Obejrzeć / odpowiedźieć na notatkę" +DOC_ENABLE_TITLE = "Opublikować dokument" +DOC_DISABLE_TITLE = "Usuń dokument z publikacji" +DOC_TEMPORARY_DELETE = "Włóż dokument do kosza" +DOC_RESTORE_DELETE = "Przywróć dokument z kosza" +DOC_FINAL_DELETE = "Usuń dokument" +DOC_ICON_COMMENT = "Są notatki" +DOC_ICON_PUBLIC = "Dokument zdjęto z publikacji" +DOC_ICON_RECYCLE = "Dokument przeniesiono do kosza" +DOC_SORT_TEXT = "Uporządkuj dokumenty po:" +DOC_TEMPORARY_CONFIRM = "Czy na pewno chcesz umieścić dokument do kosza?" +DOC_FINAL_CONFIRM = "Czy na pewno chcesz usunąć ten dokument?" +DOC_INSERT_LINK_TIP = "Aby wybrać żądany dokument, kliknij na przycisk "Wybierz"" +DOC_BUTTON_INSERT_LINK = "Wybierz" +DOC_BUTTON_LINK_POPUP = "Wybierz w nowym oknie" +DOC_BUTTON_ADD_DOCUMENT = "Dodać dokument" +DOC_BUTTON_ADD_DOCUMENT_NEXT = "Dodać i kontynuować redagowanie (Ctrl + S)" +DOC_BUTTON_EDIT_DOCUMENT = "Zapisz zmiany" +DOC_BUTTON_EDIT_DOCUMENT_NEXT = "Zastosuj (Ctrl + S)" +DOC_ADD_DOCUMENT = "Dodaj nowy dokument" +DOC_EDIT_DOCUMENT = "Redagowanie dokumentu" +DOC_OPTIONS = "Ustawienia dokumentu" +DOC_NAME = "Nazwa dokumentu:
(HTML & lt;title>)" +DOC_URL = "Pseudonim dokumentu:
(SEO alias) " +DOC_URL_LINK = "Podstawianie aliasów" +DOC_URL_INFO = " Aby link na dokument wyglądał, na przykład, tak:
http :
//www.domain.tld/phone/samsung/
zapisz w tym oknie: phone/samsung

Przyrostek linku jest dodawany automatycznie przy wyprowadzeniu
według ustawień określonych w pliku inc/config.php

 W tytule pozwolone jest wykorzystanie:
a-z – liter łacińskich;
а-я - znaków cyrylicy (jeśli jest to dozwolone) ;
 / - ukośnik;
- — kreska
_ -

znak podkreślenia. Tytuł linku nie powinien zawierać:
print /  lub / print /  lub / print; page-XX /  lub / page-XX /  lub / page-XX ;
Apage-XX / lub / Apage-XX /  lub / Apage-XX ;
artpage-XX /  lub / artpage-XX /  lub / artpage-XX ;
 gdzie xx - cyfry " +DOC_URL_LOG = "Wykorzystać historię aliasów, dlia przekierowaninia" +DOC_URL_LOG_T = "Zapisywać lub nie zapisywać historię aliasów dokumentu dla następnego przekierowania" +DOC_URL_LOG_RUBRIC = "Używać ustawienia rubryki" +DOC_URL_LOG_USE = "Zawsze używać" +DOC_FIELD_G_UNKNOW = "Bez grupy" +DOC_PROPERTY = "Ustawienia dokumentu" +DOC_URL_LOG_NOTUSE = "Nie wykorzystywać" +DOC_QUERIES = "Dostępne zapytania" +DOC_META_TITLE = " TITLE (TYTUŁ) – to szereg, który będzie wyświetlany na pasku tytułowym przeglądarki, znacznik ten ma istotne znaczenie dla optymizacji wyszukiwarek, dla tego system pozwala nim kierować, a także kilkoma innymi znacznikami." +DOC_META_KEYWORDS = "Słowa kluczowe:
(meta keywords) " +DOC_META_KEYWORDS_INFO = " opisują zawartość strony, magą być uwzględnione przez wyszukiwarki.

 Niektóre z tych słów muszą być obece w tekście strony. " +DOC_META_DESCRIPTION = "Opis strony:
(meta opis) " +DOC_META_DESCRIPTION_INFO = "Mały tekst, który opisuje zawartość strony, może również zostać uznany przez wyszukiwarki, wyprowadza się jako wyjaśnienie w wynikach wyszukiwania lub katalogów internetowych." +DOC_CAN_SEARCH = "Pozwól na przeszukiwanie w dokumencie:
(dla modułu wyszukiwanie) " +DOC_INDEX_TYPE = "Typ indeksowania strony":
(meta robots)" +DOC_INDEX_FOLLOW = "Indeksować i przejść za linkiem" +DOC_INDEX_NOFOLLOW = "indeksować, ale nie przechodzić za linkiem " +DOC_NOINDEX_NOFOLLOW = "Nie indeksować i nie przechodzić za linkiem " +DOC_SITEMAP_FREQ = "Częstotliwość odświeżania
sitemap.xml " +DOC_SITEMAP_FREQ_DOC = "Częstotliwość odświeżania strony" +DOC_SITEMAP_ALWAYS = "Zawsze" +DOC_SITEMAP_HOURLY = "Każdą godzinę" +DOC_SITEMAP_DAILY = "Codziennie" +DOC_SITEMAP_WEEKLY = "Co tydzień" +DOC_SITEMAP_MONTHLY = "Każdy miesiąc" +DOC_SITEMAP_YEARLY = "Rocznie" +DOC_SITEMAP_NEVER = "Nigdy" +DOC_SITEMAP_PRIORITY = "Priorytet
sitemap.xml " +DOC_SITEMAP_PRIORITY_DOC = "Priorytet tej strony w stosunku do innych stron" +DOC_SITEMAP_PRIORITY_LOW = "Najniższy priorytet" +DOC_SITEMAP_PRIORITY_MID = "Średni priorytet" +DOC_SITEMAP_PRIORITY_HIG = "Najwyższy priorytet" +DOC_START_PUBLICATION = "Rozpocznij publikowanie" +DOC_END_PUBLICATION = "Koniec publikowania" +DOC_STATUS = "Status dokumentu" +DOC_STATUS_ACTIVE = "Aktywny" +DOC_STATUS_INACTIVE = "Nieaktywny" +DOC_ADD_IN_NAVIGATION = "Dodaj podpunkt menu" +DOC_USE_NAVIGATION = "Powiązać z punktem menu" +DOC_USE_RUB_ALIAS = "Podstawienia aliasów dokumentu nadrzędnego, cel dokumentu nadrzędnego nawigacji okruszkowej." +DOC_USE_BREADCRUMB = "Powiązać z dokumentem
(może być stosowany do nawigacji okruszkowej) " +DOC_USE_LANG_PACK = " Powiązać z dokumentem z grupy językowej" +DOC_NAVIGATION_INFO = "Aby połączyć ten dokument z punktem menu, wybierz z listy istniejący punkt menu, jeśli tymczasowo nie chcesz połączyć ten dokument z punktem menu, należy pozostawić to pole puste." +DOC_MAIN_CONTENT = "Główna treść dokumentu" +DOC_MAIN_NOCONTENT = "Nie ma pola do dokumentu" +DOC_AFTER_CREATE_TITLE = "Dalshe działania" +DOC_AFTER_CREATE_INFO = "Proszę wybrać swoje dalsze działania z poniższej listy:" +DOC_EDIT_THIS_DOCUMENT = "Powrót do redagowania dokumentu" +DOC_INCLUDE_NAVIGATION = "Dodaj wygenerowany dokument do menu nawigacji" +DOC_ADD_NEW_DOCUMENT = "Dodaj nowy dokument do tej rubryki" +DOC_ADD_COPY_DOCUMENT = "Dodaj kopię dokumentu do tej rubryki" +DOC_DISPLAY_NEW_WINDOW = "Zobaczyć w nowym oknie (Ctrl + O)" +DOC_CLOSE_WINDOW = "Przejść do listy dokumentów" +DOC_CLOSE_WINDOW_RUBRIC = " Przejść do listy dokumentów należących do tej rubryki" +DOC_TO_NAVI_TITLE = "Dodawanie dokumentu do menu nawigacji" +DOC_NAVIGATION_POSITION = "Pozycja na liście" +DOC_NAVIGATION_TITLE = "Nazwa punkta menu" +DOC_TARGET = "Otwierać:" +DOC_TARGET_SELF = "w tym samym oknie" +DOC_TARGET_BLANK = "w nowym oknie" +DOC_BUTTON_ADD_MENU = "Dodać do menu" +DOC_TOP_MENU_ITEM = "Nowy punkt 1-go poziomu" +DOC_NOTICE = "Notatki do dokumentu" +DOC_NOTICE_NEW_LINK = "Dodaj nową notatkę" +DOC_NOTICE_AUTHOR = "Dodaj:" +DOC_NOTICE_DELETE_LINK = "Usuń notatkę" +DOC_ALLOW_NOTICE = "Zezwolić komentarz do notatek" +DOC_BUTTON_NOTICE = "Wykonać" +DOC_NOTICE_TITLE = "Tytuł" +DOC_NOTICE_TEXT = "Notatka" +DOC_BUTTON_ADD_NOTICE = "Dodaj notatkę" +DOC_SEND_NOTICE_INFO = "Aby dodać nową notatkę do dokumentu, proszę, wypełnij pola w poniższym formularzu." +DOC_NEW_NOTICE_TITLE = "Dodaj nową notatkę" +DOC_MAIL_BODY_CHECK = "Użytkownik %USER% dodał nowy dokument o nazwie %TITLE%".% N % Proszę sprawdzić ten dokument przed publikacją." +DOC_MAIL_SUBJECT_CHECK = "Dodano nowy dokument" +DOC_MAIL_BODY_USER = "Witamy %USER%.%N% pomyślnie utworzony pzez Pana/Panią dokument był pomyślnie dodany, Administrator otrzymał powiadomienie o sprawdzeniu, po sprawdzeniu dokumentu, zostanie on opublikowany." +DOC_MAIL_SUBJECT_USER = "Dokument był dodany, czeka na sprawdzenie" +DOC_MAIL_BODY_NOTICE = "Użytkownik % USER% dodał nową notatkę do dokumentu %N% Autoryzuj się w Panelu sterowania, a następnie kliknij na link poniżej, aby zobaczyć notatkę:% N%" %% LINK +DOC_MAIL_SUBJECT_NOTICE = "Dodano nową notatkę do dokumentu" +DOC_NEW_PAGE = "Dodać nową stronę" +DOC_CLOSE_HELP_WINDOW = "

" +DOC_HELP = "Pomoc" +DOC_VIDEO_TYPE_HELP = " Dodanie pliku wideo
Po dodaniu pliku wideo można określić szerokość i wysokość okna, aby obejrzeć wideo. Pierwsza wartość określa szerokość okna, druga - wysokość.

na przykład:

 video.avi | 300 | 300

lub video.avi | 100% | 300 " +DOC_FLASH_TYPE_HELP = " Dodanie filmu Flash
Po dodaniu filmu Flash, można określić szerokość i wysokość okna przy przeglądzie. Pierwsza wartość określa szerokość, druga – wysokość

na przykład:

flash.swf | 300 | 300

lub flash.swf | 100% | 300 " +DOC_FILE_TYPE_HELP = " Dodanie pliku
Po dodaniu pliku, można zadać nazwę linku. Dla tego po nazwie pliku należy podać znak rozpodzielczy | , a następnie wprowadźić nazwę linku

na przykład:

 file.zip | Pobierz plik " +DOC_NO_PERMISSION = "Przepraszamy, ale nie masz uprawnień do edytowania tego dokumentu." +DOC_NO_PERMISSION_RUB = "Przepraszamy, ale nie jesteś upoważniony do utworzenia dokumentu w tej rubryce." +DOC_NO_DEL_REVISION = "Przepraszamy, ale nie jesteś upoważniony do usunięcia rewizji." +DOC_NO_RES_REVISION = "Przepraszamy, ale nie jesteś upoważniony do przywrócenia rewizji." +DOC_EDIT_RUB = "Przenieść do innej rubryki" +DOC_RUBRIC = "Rubryka" +DOC_SORT_RUB = "Sortuj według rubryk" +DOC_IMAGE = "Obrazy w liście wiadomośći" +DOC_IMAGE_MAX_W = "Maksymalna szerokość" +DOC_IMAGE_MAX_H = "Maksymalna wysokość" +DOC_INTRO = "
Teaser (tekst w liście wiadomośći)" +DOC_ALIAS_CREATE = "Sformować" +DOC_ENTER_NAME = "Wybierz rubrykę, do której chcesz dodać nowy dokument." +DOC_SORT_NAME = "Proszę wybrać rubrykę." +DOC_OR = "& nbsp; lub & nbsp;" +DOC_NO_DOCS = "Dokumenty, które spełniają te kryteria, są nieobecne". +DOC_COPY = "Skopiowaniać dokument" +DOC_COPY_DOCUMENT = "Kopiowanie dokumentu" +DOC_COPY_TIP = "Proszę podać nazwę dokumentu" +DOC_ADD_NEW_LIGHT_TIP = "Aby dodać nowy dokument, wybierz rubrykę." +DOC_ADD_NEW_LIGHT_ADD = "Dodawanie dokumentu" +DOC_ADD_NEW_LIGHT_BTN = "Dodać dokument" +DOC_CHANGE_TITLE = " przeniesienie dokumentu do innej rubryki" +DOC_CHANGE_INFO = " Uwaga! Po zmianie rubryki pola, które nie zostały przeniesione, zostaną utracone!" +DOC_CHANGE_OLD_FIELD = "Pole dokumentu" +DOC_CHANGE_NEW_FIELD = "Przenieść do nowego" +DOC_CHANGE_DROP_FIELD = "- nie przenosić -" +DOC_CHANGE_CREATE_FIELD = "- stworzyć nowy -" +DOC_CHANGE_BUTTON = "zmienić" +DOC_CHANGE_AU_TITLE = "Zmiana autora dokumentu" +DOC_CHANGE_AU_INFO = " Uwaga! Przy zmianie autora, poprzedni autor może być pozbawiony prawa do edycji tego dokumentu." +DOC_CHANGE_BUTTON = "Zapisz" +DOC_IN_MENU = "do menu" +DOC_REVISSION = "Historia zmian" +DOC_REVISSION_DATA = "Data i czas modyfikacji" +DOC_REVISSION_USER = "Author" +DOC_REVISSION_VIEW = "Zobaczyć wersję" +DOC_REVISSION_RECOVER = "Przywrócić wersję" +DOC_REVISSION_RECOVER_T = "Czy na pewno chcesz przywrócić tę wersję?" +DOC_REVISSION_DELETE = "Usunąć wersję" +DOC_REVISSION_DELETE_T = "Czy na pewno chcesz usunąć tę wersję?" +DOC_REVISSION_NO_ITEMS = "Obecnie brak danych" +DOC_URL_ERROR_SYMBOL = "Nieprawidłowe znaki" +DOC_URL_ERROR_START = "zaczyna się od /" +DOC_URL_ERROR_END = "kończy się na / (przy tym przyrostek URL zaczyna się od /)" +DOC_URL_ERROR_SEGMENT = "Nieprawidłowe segmenty" +DOC_URL_ERROR_EMTY = "Nic do sprawdzenia" +DOC_URL_ERROR_DUPLICATES = "Pseudonim (nick) jest już w użyciu" +DOC_URL_H_ERROR_DUPLICATES = " Pseudonim (nick jest już w użyciu w historii aliasów " +DOC_URL_CHECK_OK = "Ten adres URL może być używany" +DOC_URL_CHECK_ER = "URL zawiera błędy:
" +DOC_REQUEST_NOT_INFO = "Dla tego zapytania nie ma opisu" +DOC_REVISION_DELETE = "Usunięto wersję dokumentu" +DOC_REVISION_RECOVER = "Przywrócono wersję dokumentu" +DOC_BREADCRUMB_BTN = "Wybierz" +DOC_BREADCRUMB_TITLE = " Nazwa linku dla nawigacji okruszkowej" +DOC_BREADCRUMB_WITH = "Pozwiązany z" +DOC_DOCUMENT_OPEN = "Dokument opublikowany" +DOC_DOCUMENT_CLOSE = "Dokument zdjęty z publikacji" +DOC_DOCUMENT_DOC = "Dokument" +DOC_DOCUMENT_ACT = "Opublikowano" +DOC_DOCUMENT_DISACT = "Usunięty z publikacji" +DOC_DOCUMENT_OPEN_ERR = "Ten dokument nie może być nieaktywny!" +DOC_DOCUMENT_OPEN_PRIVE = "Nie masz do tego prawa!" +DOC_ACTION_SELECT = "Operacje z wybranymi" +DOC_ACTION_SELECT_ACT = "Aktywny" +DOC_ACTION_SELECT_NACT = "Nieaktywny" +DOC_ACTION_SELECT_TRASH = "Tymczasowo usunąć" +DOC_ACTION_SELECT_OUTTRASH = "Przywrócić" +DOC_ACTION_SELECT_DEL = "Usunąć" +DOC_ACTION_BUTTON = "Zapisz zmiany" +DOC_CHOOSE_LANG = "Wybierz język dokumentu" +DOC_LANG_VERSION = "Wersja dokumentu w innych językach" +DOC_LINK_CHOOSE = "Wybierz dokument" +DOCUMENT_SAVED = "Dokument zapisany pomyślnie" +DOC_REV_DELETED = "Rewizje dokumentów usunięte pomyślnie" +DOC_REV_DELETED_ERR = "Nie można usunąć rewizje dokumentów.
Spróbuj ponownie." +DOC_REV_ERROR = "Błąd" +DOC_REV_SUCCESS = "Gotowe" +DOC_REV_UPDATE = "Usunięto rewizje dokumentów" +DOC_ALIASES = "Kierowanie przekierowaniami dokumentów" +DOC_ALIASES_LIST_NM = "Nazwa dokumentu" +DOC_ALIASES_LIST_RB = "Rubryka" +DOC_ALIASES_LIST_CH = "Zmieniono" +DOC_ALIASES_LIST_CR = "Ilość" +DOC_ALIASES_LIST_AT = "Działania" +DOC_ALIASES_TITLE = "Tutaj znajduje się lista wszystkich dokumentów, w których znajdują się przekierowania wewnętrzne.
Tu można wykonać podstawowe operacje na dokumentach, takich jak: przegląd, edytowanie, usuwanie przekierowania." +DOC_ALIASES_BREAD_RUB = "Rubryka" +DOC_ALIASES_BREAD_DOC = "Dokument" +DOC_ALIASES_BREAD_URL = "Główny adres URL:" +DOC_ALIASES_DOC_LIST = "Lista dokumentów z przekierowaniami" +DOC_ALIASES_ADD = "Dodaj nowe przekierowanie" +DOC_ALIASES_ADD_VAL = "Wartość przekierowania" +DOC_ALIASES_LIST = "Lista przekierowań" +DOC_ALIASES_LIST_EMPT = "Lista pusta" +DOC_ALIASES_TABL_H_URL = "Alias przekierowania" +DOC_ALIASES_TABL_H_ADD = "Dodane" +DOC_ALIASES_TABL_H_AUT = "Author" +DOC_ALIASES_TABL_CHECK = "Zaznacz tę opcję, aby usunąć" +DOC_ALIASES_GO = "Przejść po linku" +DOC_ALIASES_DEL_T = "Usunąć alias" +DOC_ALIASES_DEL_C = "Czy na pewno chcesz usunąć alias?" +DOC_ALIASES_BUTT_DEL = "Usuń" +DOC_ALIASES_BUTT_CLO = "Zamknij okno" +DOC_ALIASES_BUTT_APP = "Zastosuj" +DOC_ALIASES_BUTT_CNL = "Anuluj" +DOC_ALIASES_BUTT_SAV = "Zapisz" +DOC_ALIASES_BUTT_ADD = "Dodaj" +DOC_ALIASES_REP_OK = "Gotowe" +DOC_ALIASES_REP_OK_T = "Przekierowanie pomyślnie dodane" +DOC_ALIASES_REP_OK_T_E = "Przekierowanie pomyślnie zmienione" +DOC_ALIASES_REP_ER = "Błąd" +DOC_ALIASES_REP_ER_T = "Nie można dodać przekierowanie. Spróbuj ponownie." +DOC_ALIASES_REP_ER_T_E = "Nie udało się zaktualizować przekierowanie. Spróbuj ponownie." +DOC_RUBRIC_TMPLS = "Wybierz szablon rubryk" +DOC_RUBRIC_TMPLS_HINT = "Można ustawić dowolny szablon z tej rubryki dla dokumentu, wyprowadzenia" + +DOC_SEARCH_FIELD = "Оберіть поле" +DOC_SEARCH_FIELD_LIKE = "Містить" +DOC_SEARCH_FIELD_EQ = "Дорівнює" +DOC_SEARCH_FIELD_TEXT = "Значення" +DOC_TEMPLATE_DEFAULT = "Використовувати по замовчуванню" +DOC_SHOW_LANG = "Показати" + +// 3.2 +DOC_TABS_META = "Meta дані" +DOC_TABS_URL = "URL документа" +DOC_TABS_DATE = "Дата публікації" +DOC_TABS_OTHER = "Інші параметри" + +DOC_WITHOUT_TITLE = "Документ без назви" +DOC_SAVE_ADD = "Додав" +DOC_SAVE_EDIT = "Відредагував" +DOC_SAVE_LOG_DOC = " документ" \ No newline at end of file diff --git a/admin/lang/pl/groups.txt b/admin/lang/pl/groups.txt new file mode 100644 index 0000000..661d225 --- /dev/null +++ b/admin/lang/pl/groups.txt @@ -0,0 +1,103 @@ +# Język polski 02,2017 duncan + +[groups] +UGROUP_TITLE = "Zarządzanie grupami użytkowników" +UGROUP_TITLE2 = " Zarządzanie grupą użytkowników" +UGROUP_TITLE_MENU = "Grupy użytkowników" +UGROUP_INFO = "Oto lista wszystkich grup użytkowników w systemie. Dla każdej grupy można przypisać prawa osobiste, które umożliwiają lub ograniczają działalność z Panelu sterowania i na Publicznej częąći strony internetowej." +UGROUP_ID = "ID" +UGROUP_NAME = "Nazwa grupy" +UGROUP_COUNT = "Użytkowników w grupie" +UGROUP_ACTIONS = "Działania" +UGROUP_IN_GROUP = "Zobacz listę ludzi, którzy należą do tej grupy" +UGROUP_EDIT = "Edytuj tytuł i prawa grupy" +UGROUP_NO_PERMISSION = "Przepraszamy, ale nie masz dostatecznych praw do edycji" +UGROUP_DELETE = "Usuń tę grupę" +UGROUP_USERS_IN_GROUP = "Obecnie nie można usunąć tę grupę, ponieważ są ludzie, którzy są w tej grupie." +UGROUP_DELETE_CONFIRM = "Czy na pewno chcesz usunąć tę grupę?" +UGROUP_NO_DELETABLE = "Nie można usunąć tę grupę, ponieważ jest ona systemną". +UGROUP_NO_PERM_DELETE = "Przepraszamy, ale nie masz dostatecznych praw do usunięcia grupy." +UGROUP_NEW_GROUP = "Dodaj nową grupę" +UGROUP_NEW_NAME = "Nazwa grupy" +UGROUP_BUTTON_ADD = "Dodaj" +UGROUP_LEGEND_LINK = "Znaczenie piktogram" +UGROUP_LEGEND_EDIT = "Edytuj grupę użytkowników" +UGROUP_LEGEND_DELETE = "Usuń grupę użytkowników" +UGROUP_ENTER_NAME = "Proszę podać nazwę użytkowników" +UGROUP_WARNING_TIP = " Ważne! Bądź ostrożny, gdy przypisujesz pewne prawa dla tej grupy użytkowników. Pamiętaj, że dajesz dostęp do niektórych rubryk, można sprawić, że system jest podatny." +UGROUP_YOUR_NOT_CHANGE = " Błąd! Przepraszamy, ale nie masz uprawnień do edytowania tej grupy użytkowników." +UGROUP_NOT_EXIST = " Błąd! Niestety, ale grupa użytkowników, których szukasz, nie istnieje." +UGROUP_NO_MODULES = "Brak zainstalowanych modułów" +UGROUP_MODULES_RIGHT = "Proszę podać moduły, które będą mieć dostęp do tej grupy użytkowników." +UGROUP_CONTROL_RIGHT = "Proszę wybrać rubryki na Panelu sterowania, które będą dozwolone lub ograniczone dla tej grupy użytkowników." +UGROUP_BUTTON_SAVE = "Zapisz zmiany" +UGROUP_BUTTON_SAVE_AJAX = "Zastosuj (CTRL + S)" +UGROUP_SAVE_CONFIRM = "Czy na pewno chcesz zachować prawa dla tej grupy użytkowników?" +UGROUP_NAME_EDIT = "Edytuj nazwę grupy" +UGROUP_OR = "lub" +UGROUP_SAVED = "Prawa grupy pomyślnie zapisane" +UGROUP_SAVED_ERR = "Nie można zapisać prawa grupy.
Spróbuj ponownie." +UGROUP_ERROR = "Błąd" +UGROUP_SUCCESS = "Gotowe" +UGROUP_SAVE_MAIN = "Zmieniono uprawnienia dla grup" +UGROUP_REPORT_ADD = "Stworzono grupę użytkowników" +UGROUP_REPORT_DEL = "Usunięto grupę użytkowników" +alles = "Zezwól wszystkie prawa (Należy zachować ostrożność!) " +adminpanel = "Dostęp do Panelu sterowania" +gen_settings = " Dostęp do zarządzania ustawieniami ogólnymi systemu" +gen_settings_more = " Dostęp do zarządzania ustawieniami dodatkowymi systemu" +gen_settings_countries = " Dostęp do zarządzania listą krajów" +gen_settings_languages = "Dostęp do zarządzania językami" +logs_view = "Dostęp do przeglądania wiadomości systemowych." +logs_clear = "Dostęp do usunięcia wiadomości systemowych" +db_actions = "Dostęp do zarządzania bazą danych ( Tworzenie kopii zapasowych, odzyskiwanie, optymalizacja )" +modules_view = "Dostęp do listy modułów" +modules_admin = "Dostęp do modułów (Ustawienia, zarządzanie, wykorzystanie) " +modules_system = " Dostęp do zarządzania modułami (usunieńcie, instalacja) " +navigation_view = "Dostęp do menu nawigacyjnego" +navigation_edit = "Dostęp do zarządzania menu nawigacyjnego (Tworzenie, edycja, usuwanie) " +remark_view = "Dostęp do notatek" +remark_edit = "Dostęp do zarządzania notatkami w dokumenach (Tworzenie, edycja, usuwanie) " +document_php = "Dostęp do używania kodu PHP w dokumentach (Należy zachować ostrożność!) " +document_view = "Dostęp do listy dokumentów (prawa dostępu do dokumentów, w zależności od konfiguracji rubryki)" +document_revisions = "Dostęp do usunięcia wszystkich rewizji dokumentów" +rubric_view = "Dostęp do przeglądu listy rubryk" +rubric_edit = " Dostęp do zarządzania rubrykami (Tworzenie, edycja, usuwanie) " +rubric_php = "Dostęp do użycia kodu PHP w szablonach rubryk (Należy zachować ostrożność!) " +rubric_perms = " Dostęp do zarządzania uprawnieniami dostępu dokumentów rubryki" +rubric_code = " Dostęp do wykonywalnego kodu dla rubryk (Należy zachować ostrożność!) " +template_view = "Dostęp do listy szablonów" +template_edit = " Dostęp do zarządzania szablonami (Tworzenie, edycja, usuwanie) " +template_php = "Dostęp do użytku kodu PHP w szablonach (Należy zachować ostrożność!) " +request_view = "Dostęp do listy wniosków" +request_edit = " Dostęp do zarządzania wniaskami (Tworzenie, edycja, usuwanie) " +request_php = "Dostęp do używania kodu PHP w szablonach wniosku (Należy zachować ostrożność!) " +sysblocks_view = "Dostęp do przeglądu listy bloków systemowych" +sysblocks_edit = "Dostęp do zarządzania lokami systemowymi (Tworzenie, edycja, usuwanie) " +user_view = "Dostęp do listy użytkowników" +user_edit = "Dostęp do edycji parametrów użytkowników" +user_perms = "Dostęp do kontrolowania praw użytkownika" +group_view = "Dostęp do listy grup użytkowników" +group_edit = "Dostęp do zarządzania prawami grupy użytkowników (Tworzenie, edycja, usuwanie) " +mediapool_int = "Dostęp do menedżera plików " +mediapool_add = "Dostęp do dodawania nowych plików na serwer (w menedżerze plików) " +mediapool_del = "Dostęp do usuwania plików z serwera (w menedżerze plików) " +mediapool_finder = "Dostęp do menedżera plików (elFinder) " +cache_clear = "Dostęp do usuwania pamięci podręcznej" +cache_thumb = "Dostęp do usuwania obrazów podglądu (miniaturek) " +kłody = "Komunikaty systemowe" +cache = "Zarządzanie pamięcą podręczną" +gen = "Preferencje systemowe" +db = "Baza danych" +sysblocks = "Bloki systemowe" +Rubryki = "Rubryki" +document = "Dokumenty" +Moduły = "Moduły" +Mediapool = "Menedżery plików" +Nawigacja = "Nawigacja" +request = "Wnioski" +template = "Szablony" +uwaga = "Notatki w dokumentach" +document = "Dokumenty" +user = "Użytkownicy" +group = "Grupy użytkowników" diff --git a/admin/lang/pl/logs.txt b/admin/lang/pl/logs.txt new file mode 100644 index 0000000..0b9c5de --- /dev/null +++ b/admin/lang/pl/logs.txt @@ -0,0 +1,53 @@ +# Język polski 02,2017 duncan + +[logs] +LOGS_SUB_TITLE = "Kierowanie komunikatami systemowymi" +LOGS_TITLE = "Dziennik zdarzeń systemowych" +LOGS_TIP = "Tutaj znajduje się lista wszystkich działań podejmowanych w Panelu sterowania." +LOGS_ID = "№" +LOGS_IP = "Adres IP" +LOGS_DATE = "Data" +LOGS_USER = "Użytkownik" +LOGS_ACTION = "Działania" +LOGS_BUTTON_DELETE = "Oczyśćić dziennik" +LOGS_DELETE_CONFIRM = "Czy na pewno chcesz wyczyścić dziennika komunikatów systemowych?" +LOGS_BUTTON_EXPORT = " Export dziennika komunikatów systemowych" +LOGS_BUTTON_EXPORT_404 = "Export dziennika błędów 404" +LOGS_DATE_FORMAT = "%d.%m.%y г." +LOGS_DATE_FORMAT2 = "%H:%M" +LOGS_IN = "w" +LOGS_CLEAR = "Komunikaty systemowe pomyślnie usunięte." +LOGS_CLEAN = "Oczyścił dziennik zdarzeń" +LOGS_EXPORT = "Eksportował dziennik zdarzeń" +LOGS_404_SUB_TITLE = "Dziennik błędów 404" +LOGS_404_TITLE = " Dziennik błędów 404" +LOGS_404_TIP = "Tutaj znajduje się lista wszystkich błędów 404." +LOGS_404_ID = "№" +LOGS_404_IP = "Adres IP" +LOGS_404_DATE = "Data" +LOGS_404_ACTION = "Działania" +LOGS_404_BUTTON_DELETE = "Oczyścić dziennik" +LOGS_404_DELETE_CONFIRM = "Czy na pewno chcesz usunąć dziennik błędów 404?" +LOGS_404_BUTTON_EXPORT = "Eksport dziennika błędów" +LOGS_404_DATE_FORMAT = "%d.%m.%y г." +LOGS_404_DATE_FORMAT2 = "%H:%M" +LOGS_404_IN = "w" +LOGS_404_CLEAR = "komunikaty systemowe pomyślnie usunięte." +LOGS_404_CLEAN = "wyczyszczony dziennik błędów 404" +LOGS_404_EXPORT = "Eksportował dziennik błędów 404" +LOGS_SQL_SUB_TITLE = "Dziennik błędów MySQL" +LOGS_SQL_TITLE = " Dziennik błędów MySQL" +LOGS_SQL_TIP = "Tutaj znajduje się lista wszystkich błędów MySQL." +LOGS_SQL_ID = "№" +LOGS_SQL_IP = "Adres IP" +LOGS_SQL_DATE = "Data" +LOGS_SQL_ACTION = "Działania" +LOGS_SQL_BUTTON_DELETE = "Wyczyść dziennik błędów MySQL " +LOGS_SQL_DELETE_CONFIRM = "Czy na pewno chcesz wyczyścić dziennik błędów MySQL?" +LOGS_SQL_BUTTON_EXPORT = "Export dziennika błędów MySQL" +LOGS_SQL_DATE_FORMAT = "%d.%m.%y г." +LOGS_SQL_DATE_FORMAT2 = "%H:%M" +LOGS_SQL_IN = "in" +LOGS_SQL_CLEAR = "Dziennik błędów MySQL pomyślnie usunięty." +LOGS_SQL_CLEAN = "Wyczyszczony dziennik błędów MySQL" +LOGS_SQL_EXPORT = "Eksportowany dziennik błędów MySQL" diff --git a/admin/lang/pl/main.txt b/admin/lang/pl/main.txt new file mode 100644 index 0000000..77af7e4 --- /dev/null +++ b/admin/lang/pl/main.txt @@ -0,0 +1,271 @@ +# Język polski 02,2017 duncan + +MAIN_WELCOME = "Witamy w Panelu sterowania!" +MAIN_WELCOME_INFO = "Na stronie głównej można wybrać jedną z najczęściej wykonywanych operacji." +MAIN_PAGE = "Strona główna" +MAIN_LOGIN_INTRO = "Autoryzacja" +MAIN_LOGIN_BACK_SITE = "Powrót do strony" +MAIN_LOGIN_NAME = "Login" +MAIN_LOGIN_PASSWORD = "Hasło" +MAIN_LOGIN_BUTTON = "Wejść" +MAIN_LOGIN_REGISTER = "Rejestracja" +MAIN_LOGIN_LOST = "Zapomniałeś hasła?" +MAIN_LOGIN_HELP = "Pomoc" +MAIN_LOGIN_REMEMBER = "Pamiętaj mnie" +MAIN_LOGIN_CAP_CODE = "Kod" +MAIN_LOGIN_CAP_CODE_REF = "Obnowić kod" +MAIN_LOGIN_CAP_CODE_REFR = " Obnowić kod" +MAIN_LINK_HOME = "Menu główne" +MAIN_LINK_AUTHOR = "Wsparcie strony" +MAIN_LINK_DATABASE = "Zarządzenie bazami danych" +MAIN_LINK_NAVIGATION = " Zarządzanie menu nawigacji" +MAIN_LINK_MODULES = "Zarządzanie modułami" +MAIN_LINK_MODULES_H = "Moduły" +MAIN_LINK_SETTINGS = "Zarządzaj ustawieniami" +MAIN_LINK_SETTINGS_H = "Ustawienia" +MAIN_LINK_USERS = "Zarządzanie użytkownikami" +MAIN_LINK_TEMPLATES = "Zarządzaj szablonami" +MAIN_LINK_RUBRICS = "Zarządzanie rubrykami" +MAIN_LINK_DOCUMENT = "Zarządzanie dokumentami" +MAIN_LINK_QUERYES = "Zarządzanie wnioskami" +MAIN_LINK_GROUPS = " Zarządzanie grupami" +MAIN_LINK_LANG = "Zarządzanie językami" +MAIN_BUTTON_LOGIN = "Wejść" +MAIN_BUTTON_ADD = "Dodać" +MAIN_BUTTON_LOGOUT = "Wyjść" +MAIN_SETTINGS_EDIT_1 = "Ustawienia ogólne" +MAIN_SETTINGS_EDIT_2 = "Ustawienia zaawansowane" +MAIN_SETTINGS_EDIT_3 = " Zarządzanie krajami" +MAIN_SETTINGS_EDIT_4 = "Stworzyć kopję rezerwową BD" +MAIN_LINK_DOC_TIPS = "Tutaj znajduje się lista wszystkich dokumentów znajdujących się w systemie." +MAIN_LINK_RUBRIK_TIP = "Tutaj znajduje się lista wszystkich rubryk w systemie." +MAIN_LINK_REQUEST_TIP = "Tutaj znajduje się lista wszystkich istniejących wniosków w systemie." +MAIN_LINK_NAVI_TIP = "Tutaj znajduje się lista wszystkich menu nawigacji w systemie." +MAIN_LINK_TEMPLATES_TIP = "Tutaj znajduje się lista wszystkich szablonów używanych w systemie." +MAIN_LINK_MODULES_TIP = "Tutaj znajduje się lista wszystkich dostępnych modułów w systemie." +MAIN_LINK_SETTINGS_TIP = " Tutaj znajdują się wszystkie globalne parametry systemu." +MAIN_LINK_DB_TIP = "Tutaj można pracować z systemem bazy danych." +MAIN_LINK_USER_TIP = "Tutaj znajduje się lista wszystkich użytkowników w systemie." +MAIN_LINK_UGROUP_TIP = " Tutaj znajduje się lista wszystkich grup użytkowników w systemie." +MAIN_PAGE_TITLE = "Panel sterowania" +MAIN_LOGIN_TEXT = "Autoryzacja" +MAIN_LOGIN_TEXT2 = "Proszę podać swoje dane" +MAIN_LOGIN_CAPTCHA = "Wpisz kod" +MAIN_SELECT_LANGUAGE = "Język" +MAIN_SELECT_THEME = "Temat wystroju" +MAIN_YOUR_EMAIL = "E-mail" +MAIN_YOUR_LOGIN = "Nazwa użytkownika lub adres e-mail:" +MAIN_YOUR_PASSWORD = "Hasło" +MAIN_LINK_SITE = "Przejdź na stronę" +MAIN_LINK_HOME = "Do strony głównej" +MAIN_LINK_LOGOUT = "Wyjśćie z panelu sterowania" +MAIN_LINK_LOGOUT_QUEST = "Czy na pewno chcesz wyjść?" +MAIN_LINK_CACHE_CLEAR = "Opróżnić pamięć podręczną " +MAIN_LINK_CACHE_CLEAR_QUEST = "Czy na pewno chcesz opróżnić pamięć podręczną?" +MAIN_LINK_SITE_ON = "Włącz edytor" +MAIN_LINK_SITE_OFF = "Wyłącz edytor" +MAIN_LINK_EDIT = "Edytuj stronę" +MAIN_ADD_IN_RUB = "Dodaj nowy dokument" +MAIN_DOCUMENTS_ALL = "Lista dokumentów" +MAIN_SEARCH_DOCUMENTS = "Szukaj dokumentów" +MAIN_SORT_DOCUMENTS = "Szybki wybór " +MAIN_TIME_PERIOD = "Okres publikacji" +MAIN_TIME_START = "Początek" +MAIN_TIME_END = "Koniec" +MAIN_BUTTON_SEARCH = "Szukaj" +MAIN_TITLE_SEARCH = "Nazwa dokumentu" +MAIN_TITLE_DOC_NAME = "Nazwa dokumentu" +MAIN_TITLE_DOC_ID = "ID Dokumentu" +MAIN_SEARCH_HELP = Korzystanie z wyszukiwarki
Użyj znak & quot; + & quot; . dla wyraźnego włączenia słowa do wyszukiwarki.
Wykorzystaj znak & quot; - & quot; aby wykluczyć słowa z wyszukiwarki
obowiązkowe jest używanie spacji przed znakami & quot; + & quot; i & quot; - & quot;." +MAIN_ID_SEARCH = "ID Dokumentu" +MAIN_SELECT_RUBRIK = "W rubryce" +MAIN_ALL_RUBRUKS = "Wszystkie rubryki" +MAIN_ALL_DOCUMENTS = "Dowolny status" +MAIN_DOCUMENT_STATUS = "Status dokumentu" +MAIN_DOCUMENT_ACTIVE = "Tylko aktywny" +MAIN_DOCUMENT_INACTIVE = "Tylko nieaktywny" +MAIN_TEMP_DELETE_DOCS = "Tymczasowo usunięty" +MAIN_RESULTS_ON_PAGE = "Wyników na stronie:" +MAIN_OPEN_MEDIAPATH = "Popatrzeć na serwerze" +MAIN_NAVI_UGROUPS = "Grupy użytkowników" +MAIN_UGROUP_EDIT = "Edytuj prawa grupy" +MAIN_UGROUP_DELETE = "Usuń tę grupę" +MAIN_LOGS = "Zdarzenia systemowe" +MAIN_NAVI_MODULES = "Zarządzanie modułami" +MAIN_NAVIGATION = "Menu nawigacyjne" +MAIN_NAVIGATION_NEW = "Dodaj nowe menu" +MAIN_QUERIES = "Wnioski" +MAIN_REQUEST_NEW = "Dodaj nowy wniosek" +MAIN_RUBRIKS = "Rubryki" +MAIN_RUBRIK_NEW = "Dodaj nową rubrykę" +MAIN_RUBRIK_EDIT_FIELDS = "Edytuj polia rubryki" +MAIN_RUBRIK_EDIT_TEMPL = "Edytuj szablon rubryki" +MAIN_SETTINGS = "Preferencje systemowe" +MAIN_COUNTRY_EDIT = "Zarządzanie krajami" +MAIN_SYSBLOCKS = "Bloki systemowe" +MAIN_TEMPLATES = "Szablony" +MAIN_TEMPLATES_NEW = "Dodaj nowy szablon" +MAIN_USERS = "Użytkownicy" +MAIN_DATABASE_INFO = "Baza danych" +MAIN_NAVI_DOCUMENTS = "Dokumenty" +MAIN_BROWSE_DOCUMENTS = "Popatrzeć w dokumentach" +MAIN_USERS_LIST = "Lista użytkowników" +MAIN_USER_ADD = "Dodaj nowego użytkownika" +MAIN_SEARCH_USERS = "Szukaj użytkowników po:" +MAIN_USER_PARAMS = "Imieniu, ID, E-mail, E-mail domena" +MAIN_USER_STATUS = "Ze statusem" +MAIN_USER_STATUS_ALL = "Każdy status" +MAIN_USER_STATUS_ACTIVE = "Aktywny" +MAIN_USER_STATUS_INACTIVE = "Oczekuje aktywacji" +MAIN_USER_GROUP = "Znajduje się w grupie" +MAIN_USER_ONLINE = "Witaj" +MAIN_USER_PERM = "Status" +MAIN_ALL_USER_GROUP = "W dowolny" +MAIN_BUTTON_SEARCH_USER = "Znajdź użytkowników za parametrami" +MAIN_NO_PERMISSION = "Przepraszamy, ale nie masz prawa dostępu do następujących rozdziałów" +MAIN_LOGOUT_CONFIRM = "Czy na pewno chcesz zakończyć?" +MAIN_START_DOC_TITLE = "Najnowsze dokumenty" +MAIN_START_DOC_ID = "ID" +MAIN_START_DOC_NAME = "Nazwa" +MAIN_START_DOC_RUBRIC = "Rubryka" +MAIN_START_DOC_DATE = "Opublikowane" +MAIN_START_DOC_AUTOR = "Author" +MAIN_START_SEARCH = "Szukaj" +MAIN_START_SEARCH_T = "Szukaj dokumentu" +MAIN_START_LOGS_LOG = "Historia transakcji" +MAIN_START_LOGS_404 = "Błąd 404" +MAIN_START_LOGS_SQL = "Błąd MySQL" +MAIN_TABLE_SUCC = "Liczba pomyślnie przesłanych tablic:" +MAIN_TABLE_ERROR = "Liczba tablic z błędami:" +MAIN_SQL_FILE_ERROR = "SQL plik jest uszkodzony lub zawiera błędy w strukturze wniosków". +MAIN_RESTORE_OK = "Baza danych jest z powodzeniem odnowiona" +MAIN_NO_PERM_MODULES = "Przepraszamy, ale nie masz praw do zarządzania tym modułem" +MAIN_MP_FILE_DELETE = "Usuń plik" +MAIN_MP_DELETE_CONFIRM = "Czy na pewno chcesz usunąć plik:" +MAIN_MP_DOC_FOLDER = "Lista folderów / plików" +MAIN_MP_FILE_SIZE = "Rozmiar pliku" +MAIN_MP_FILE_DATE = "Utworzony" +MAIN_MP_ACTIONS = "Działania" +MAIN_MP_FILE_INFO = "Aby dodać plik, kliknij na jego nazwę i potem na przycisk dodać plik" +MAIN_MP_UP_LEVEL = "Przejdź do góry o jeden poziom" +MAIN_MP_CREATE_FOLDER = "Stworzyć nowy folder" +MAIN_MP_UPLOAD_FILE = "Pobierz plik" +MAIN_MP_FILE_INSERT = "Wstaw plik" +MAIN_MP_DIR_INSERT = "Wybierz folder" +MAIN_MP_SELECT_FILES = "Wybierz pliki do pobirania" +MAIN_MP_IMAGE_RESIZE = "Zmień rozmiar pobranych zdjęć" +MAIN_MP_IMAGE_WIDTH = "Szerokość" +MAIN_MP_IMAGE_HEIGHT = "Wysokość" +MAIN_BUTTON_UPLOAD = "Pobierz" +MAIN_BUTTON_WAIT = "Proszę czekać ..." +MAIN_MP_PLEASE_SELECT = "Wybierz plik" +MAIN_ADD_IN = "Wybierz rubrykę" +MAIN_GROUP_DELETE_CONFIRM = "Czy na pewno chcesz usunąć tę grupę?" +MAIN_RUBRIKS_LIST = "Lista rubryk" +MAIN_USER = "Użytkownik" +ButtonSave = "Zapisz" +MAIN_NEW_PAGE = "Dodaj nową stronę" +MAIN_BUTTON_SORT = "Zabrać" +MAIN_QUICK_MODULE = "Zarządzanie modułami" +MAIN_STAT = "Statystyka" +MAIN_STAT_SYSTEM_INFO = "Informacje o systemie" +MAIN_STAT_DOCUMENTS = "Wszystkie dokumenty" +MAIN_STAT_RUBRICS = "Wszystkie kategorie" +MAIN_STAT_QUERIES = "Wszystkie wnioski" +MAIN_STAT_TEMPLATES = "Wszystkie szablony" +MAIN_STAT_MYSQL = "Rozmiar bazy danych" +MAIN_STAT_CACHE = "Całkowity rozmiar pamięci podręcznej" +MAIN_STAT_CACHE_SHOW = "Pokaż" +MAIN_STAT_MODULES = "Zainstalowane moduły:" +MAIN_STAT_MODULES_OFF = "Wyłączone moduły" +MAIN_STAT_USERS = "Wszystkie użytkowniki" +MAIN_STAT_USERS_WAIT = "Oczekują aktywacji" +MAIN_STAT_AVE = "AVE.cms" +MAIN_STAT_DOMEN = "Domain" +MAIN_STAT_PHP = "Wersja PHP" +MAIN_STAT_MYSQL_VERSION = " Wersja MySQL:" +MAIN_STAT_CLEAR_CACHE = "Wyczyść pamięć podręczną" +MAIN_STAT_CLEAR_CACHE_FULL = "Wyczyść pamięć podręczną i sesje" +MAIN_STAT_CLEAR_THUMB = "Wyczyść miniatury" +MAIN_STAT_CLEAR_REV = "Usuwanie rewizji" +MAIN_STAT_CLEAR_COUNT = "Reset licznika na dniówki" +MAIN_ADD_FOLDER = "Podaj nazwę nowego folderu" +MAIN_NO_ADD_FOLDER = "Nie podano nazwy folderu lub czynność odwołano!" +MAIN_NO_ADD_TEMPL = "Nie podano nazwy szablonu lub czynność odwołano!" +MAIN_NO_ADD_GROUP = "Nie podano nazwy grupy lub czynność odwołano!" +MAIN_NO_ADD_RUB = "Nie podano nazwy rubryki lub czynność odwołano!" +MAIN_NO_ADD_QUERY = "Nie podano nazwy wniosku lub czynność odwołano!" +MAIN_NO_ADD_NAV = "Nie podano nazwy nawigacji lub czynność odwołano!" +MAIN_NO_ADD_BLOCK = "Nie podano nazwy systemnego bloka lub czynność odwołano!" +MAIN_NO_ADD_USER = " Nie podano nazwy użytkownika lub czynność odwołano!" +MAIN_NO_ADD_DOCS = "Nie podano nazwy dokumentu lub czynność odwołano!" +MAIN_CLEAR_CACHE_OK = "Pamięć podręczna została wyczyszczona" +MAIN_FILE_MANAGER_TITLE = "File Manager" +MAIN_FILE_MANAGER_TIP = "Wybierz żądany plik i kliknij przycisk & quot; wstawić plik & quot;" +MAIN_SVN_NEW = "Nowa wersja" +MAIN_SVN_SAIT = "Przejść na stronę" +MAIN_SVN_REPOS = " Przejść na stronę repozytorium" +MAIN_SVN_MAILTO = "Napisać list" +MAIN_SVN_LOOK = "Zobaczyć na stronie repozytorium" +MAIN_SVN_RECOM = "Zalecane jest uaktualnienie!" +MAIN_FINDER = "File Manager" +MAIN_ADD_NEW_GROUP = "Dodaj nową grupę" +MAIN_ADD_NEW_GROUP_NAME = "Nazwa grupy" +MAIN_ADD_NEW_USER = "Dodaj nowego użytkownika" +MAIN_ADD_NEW_USER_NAME = "Nazwa użytkownika" +MAIN_ADD_NEW_NAV = "Dodaj nową nawigację" +MAIN_ADD_NEW_NAV_NAME = "Nazwa nawigacji" +MAIN_ADD_NEW_TEMPL = "Dodaj nowy szablon" +MAIN_ADD_NEW_TEMPL_NAME = "Nazwa szablonu" +MAIN_ADD_NEW_REQUEST = "Dodaj nowy wniosek" +MAIN_ADD_NEW_REQUEST_NAME = "Nazwa wniosku" +MAIN_ADD_NEW_RUB = "Dodaj nową rubrykę" +MAIN_ADD_NEW_RUB_NAME = "Nazwa rubryki" +MAIN_ADD_NEW_BLOCK = "Dodaj nowy blok systemowy" +MAIN_ADD_NEW_BLOCK_NAME "Nazwa bloku systemowego:" +MAIN_USERS_LAST_TIME = "Niedawno było" +MAIN_LOGS_ID = "№" +MAIN_LOGS_IP = "Adres IP" +MAIN_LOGS_DATE = "Data" +MAIN_LOGS_USER = "Użytkownik" +MAIN_LOGS_ACTION = "Działania" +MAIN_DOC_SHOW3_TITLE = "Dokument bez nazwy" +MAIN_DOC_EDIT_TITLE = "Edytuj ten dokument" +MAIN_DOC_SHOW_TITLE = "Wyświetl dokument (link bez CNC)" +MAIN_DOC_SHOW2_TITLE = "Zobacz dokument (link z CNC)" +MAIN_ADD_DOC = "Dokument" +MAIN_ADD_RUB = "Rubrykę" +MAIN_ADD_REQ = "Wniosek" +MAIN_ADD_SYS = "Blok systemowy" +MAIN_ADD_TEM = "Szablon" +MAIN_ADD_NAV = "Nawigację" +MAIN_ADD_USR = "Użytkownika" +MAIN_ADD_GRP = "Grupę" +MAIN_BRANCHES = "Sekcje" +MAIN_SHOWHIDE = "Pokaż / Ukryj menu" +MAIN_CODEMIRROR_HELP = " Ctrl- F / Cmd-F ( Szukaj) | Ctrl-G / Cmd-G ( Znajdź następny) | Shift-Ctrl -G / shift -Cmd-G (Znajdź poprzedni) | Shift-Ctrl -F / Cmd-Option-F ( Zamień) | Shift-Ctrl -R / Shift-Cmd-Option- F (Zamień wszystkie) | F11 (Pełny ekran) " +TEMPLATES_MESSAGE = " Wiadomość: " +TEMPLATES_CACHE_SUCCESS = "Pamięć podręczna została pomyślnie usunięta" +TEMPLATES_CACHE_SUCCESS_LOG = "Pamięć podręczna została wyczyszczona" +TEMPLATES_CACHE_DB_SUCCESS = "Tablica sessions została wyczyszczona" +TEMPLATES_CACHE_DB_SUCCESS_LOG = "Tablice _sessions zostały wyczyszczone". +TEMPLATES_CACHE_CT_SUCCESS = "Skompilowane szablony usunięte". +TEMPLATES_CACHE_CT_SUCCESS_LOG = "Skompilowane szablony usunięte " +TEMPLATES_CACHE_MC_SUCCESS = "Skompilowane szablony modułów usunięte". +TEMPLATES_CACHE_MC_SUCCESS_LOG = "Skompilowane szablony modułów usunięte" +TEMPLATES_CACHE_SU_SUCCESS = "Usunięto sesji użytkowników" +TEMPLATES_CACHE_SU_SUCCESS_LOG = "Sesje użytkowników usunięte" +TEMPLATES_CACHE_SC_SUCCESS = "Pamięć podręczna zapytań SQL usunięta" +TEMPLATES_CACHE_SC_SUCCESS_LOG = "Pamięć podręczna zapytań SQL usunięta " +TEMPLATES_THUMBNAILS_SUCCESS = "Miniatury pomyślnie usunięte." +TEMPLATES_THUMBNAILS_SUCCESS_LOG = "Usunięto miniatury" +EXIT_ADMIN = "Sesja zakończona w Panelu sterowania" +LOGIN_ADMIN = "Sesja rozpoczęta w Panelu sterowania" +ERROR_ADMIN = "Błąd przy wejściu do Panelu sterowania" +WRONG_PASS = " Błąd:
Nazwa użytkownika lub hasło nieprawidłowe!" +WRONG_CAPTCHA = " Błąd:
Nieprawidłowy kod bezpieczeństwa" +oficial_site = "Strona oficjalna" +support = "Pomoc techniczna" + +// 3.1.9 +MAIN_BLOCKS = "Візуальні блоки" \ No newline at end of file diff --git a/admin/lang/pl/modules.txt b/admin/lang/pl/modules.txt new file mode 100644 index 0000000..85dcfb1 --- /dev/null +++ b/admin/lang/pl/modules.txt @@ -0,0 +1,38 @@ +# Język polski 02,2017 duncan + +[modules] +MODULES_SUB_TITLE = "Zarządzanie modułami" +MODULES_TIP = "Tutaj znajduje się lista wszystkich dostępnych modułów w systemie. Można ustawić, wyłączyć, uaktualnić którykolwiek z modułów i wykonać dodatkowe ustawienia osobiste dla każdego z modułów." +MODULES_NAME = "Nazwa modułu" +MODULES_INFO = "Informacje" +MODULES_TEMPLATE = " Szablon wyprowadzenia" +MODULES_SYSTEM_TAG = "Znacznik systemowy" +MODULES_VERSION = "Wersja" +MODULES_ACTIONS = "Działania" +MODULES_SETTINGS = "Opcje" +MODULES_SETTINGS_INFO = "Informacje" +MODULES_DELETE = " Usuń moduł" +MODULES_DELETE_CONFIRM = "Pamiętaj, że usuwając moduł z systemu, usuwasz go tylko na poziomie programu. W związku z tym w przyszłości, zawsze można zainstalować go ponownie.
Czy na pewno chcesz usunąć ten moduł?" +Modules_install = "Ustawić moduł" +MODULES_REMOVE = "Usunąć moduł z serwera" +MODULES_REINSTALL = "Ponowne zainstalowanie modułu" +MODULES_REINSTALL_CONF = "Czy na pewno chcesz ponownie zainstalować ten moduł?" +MODULES_UPDATE = "Aktualizować moduł" +MODULES_STOP = "Wyłączyć moduł" +MODULES_START = "Włącz moduł" +MODULES_BUTTON_SAVE = "Zapisz zmiany" +MODULES_LEGEND = "Znaczenie piktogramu" +MODULES_AUTHOR = "Autor modułu" +MODULES_ERROR = "Stał się błąd przy załadowaniu modułu" +MODULES_INSTALLED = "Zainstalowane moduły" +MODULES_NOT_INSTALLED = "Niezainstalowane moduły " +MODULES_SETUP = "Idź do sterowania modułem" +MODULES_NO_INSTALL = " Wiadomość:
Nie ma zainstalowanych modułów". +MODULES_NOT_INSTALL = " Wiadomość:
Nie ma nieinstalowanych modułów." +MODULES_ACTION_INSTALL = "Moduł zainstalowany" +MODULES_ACTION_ONLINE = "Moduł wączony" +MODULES_ACTION_OFFLINE = "Moduł wyłączony" +MODULES_ACTION_REINSTALL = "Moduł ponownie zainstalowany" +MODULES_ACTION_UPDATE = "Aktualizacja modułu" +MODULES_ACTION_DELETE = "Usunięto moduł z systemu" +MODULES_ACTION_REMOVE = "Usunięto z modułem serwera" diff --git a/admin/lang/pl/navigation.txt b/admin/lang/pl/navigation.txt new file mode 100644 index 0000000..44b188b --- /dev/null +++ b/admin/lang/pl/navigation.txt @@ -0,0 +1,128 @@ +# Język polski 02,2017 duncan + +[navi] +NAVI_ID = "ID" +NAVI_SUB_TITLE = "Zarządzanie menu nawigacji" +NAVI_SUB_TITLE2 = "Zarządzanie punktami menu" +NAVI_SUB_TITLE3 = "Edycja szablona menu" +NAVI_SUB_TITLE4 = "Tworzenie nowych szablonów menu" +NAVI_TIP_TEMPLATE = "Tutaj znajduje się lista wszystkich menu nawigacji w systemie. Można zmienić wyjście szablony wyprowadzenia dowolnego z dostępnych menu i dodać lub usunąć punkty menu." +NAVI_TIP_TEMPLATE2 = "Tutaj, za pomocą języka znaczników HTML, można utworzyć szablon do menu nawigacji. Można również wybrać grupę użytkowników, która będzie dostępna w tym menu nawigacji. Aby wybrać wiele grup przytrzymaj przycisk Ctrl." +NAVI_ITEMS_TIP = "Utwórz nowy punkt menu" +NAVI_NEW_MENU = "Tworzenie nowego menu" +NAVI_LIST_TIP = "Lista poniżej zawiera wszystkie elementy związane z tym menu. Pamiętaj, że maksymalny poziom włożeń nie może zawierać więcej niż 2." +NAVI_LIST = "Lista punktów menu" +NAVI_EDIT_TEMPLATE = "Edycja szablonów menu" +NAVI_EDIT_ITEMS = " Edycja szablonów menu" +NAVI_OPEN_IN_THIS = "W bieżącym oknie" +NAVI_OPEN_IN_NEW = "W nowym oknie" +NAVI_TARGET_WINDOW = "Odkryj" +NAVI_POSITION = "Pozycja" +NAVI_LINK_TO_DOCUMENT = "Link do dokumentu / pliku" +NAVI_ENTRIES_NO_ITEMS = " Wiadomość:
Obecnie niema żadnych punktów menu." +NAVI_LINK_TITLE = "Nazwa punktu menu" +NAVI_LINK_SOLUT = "Opis dla punktu menu" +NAVI_LINK_IMGID = "ID obrazku" +NAVI_LINK_IMGTL = "Wybierz obrazek" +NAVI_LINK_IMAGE = "Obrazek dla punktu menu" +NAVI_TITLE = "Nazwa menu nawigacyjnego" +NAVI_TITLE2 = "Wprowadź nazwę menu nawigacyjnego" +NAVI_BROWSE_DOCUMENTS = "Link do istniejącego dokumentu" +NAVI_ADD_SUBITEM = "Dodaj nowy element" +NAVI_BUTTON_CHANGE = "Wybierz" +NAVI_BUTTON_OPTION = "Opcje" +NAVI_BUTTON_SUBITEM = "+" +NAVI_BROWSE_MEDIAPOOL = "Link do pliku na serwerze" +NAVI_SYSTEM_TAG = "Znacznik systemowy" +NAVI_NAME = "Nazwa Menu" +NAVI_LINK_TARGET = "Znacznik, który określa rodzaj odkrycia dokumentu (w nowym lub bieżącym oknie)" +NAVI_LINK_URL = "Znacznik, który określa adres dla przejścia" +NAVI_LINK_NAME = "Znacznik, który określa nazwę odnośnika, który będzie wyświetlany w menu" +NAVI_LINK_ID = "Znacznik, który definiuje unikalny identyfikator do odnośnika" +NAVI_LINK_INACTIVE = "Oprawa nieaktywnego odnośnika" +NAVI_LINK_ACTIVE = "Oprawa aktywnego odnośnika" +NAVI_HEADER_START = "Górna część oprawy" +NAVI_FOOTER_END = "Dolna część oprawy" +NAVI_HEADER_TIP = "Na przykład, tytuł
& quot; katalog artykułów & quot;
(opcjonalnie)" +NAVI_COPY_TEMPLATE = "Kopiuj szablon menu" +NAVI_FOOTER_TIP = "Niższa część oprawy menu
(opcjonalnie)" +NAVI_DELETE = "Usuń to menu" +NAVI_DELETE_CONFIRM = "Czy na pewno chcesz usunąć to menu nawigacji?" +NAVI_HTML_START = "Początkowy kod HTML" +NAVI_HTML_END = "Ostateczny kod HTML" +NAVI_LEVEL1 = "Szablon oprawy dla głównego (pierwszego) poziomu punktów menu" +NAVI_LEVEL2 = "Szablonu oprawydla pierwszego poziomu włożonych punktów menu" +NAVI_LEVEL3 = "Szablon oprawy dla drugiego poziomu włożonych punktów" +NAVI_MARK_DELETE = "Zaznacz tę opcję, aby usunąć" +NAVI_MARK_ACTIVE = "Aby tymczasowo wyłączyć ten punkt menu, usuń zaznaczenie i kliknij & quot; Zapisz zmiany & quot" +NAVI_GROUPS = "Grupy użytkowników, dla których będzie dostępne menu" +NAVI_ACTIONS = "Działania" +NAVI_OR_BUTTON = "& nbsp; lub & nbsp;" +NAVI_BUTTON_SAVE = "Zapisz zmiany" +NAVI_BUTTON_SAVE_NEXT = "Zastosuj (CTRL + S)" +NAVI_BUTTON_ADD = "Dodaj punkt" +NAVI_BUTTON_ADD_MENU = "Tworzenie menu" +NAVI_LEGEND = "Znaczenie piktogramy" +NAVI_ENTER_NAME = "Proszę podać nazwę menu nawigacji." +NAVI_ALL = "Lista menu nawigacji" +NAVI_PRINT_TYPE = "Typ wyjśćia" +NAVI_EXPAND_ALL = "W całości (ujawnić wszystkie poziomy)" +NAVI_EXPAND_WAY = "Bieżący i rodzicielski poziomy" +NAVI_EXPAND_LEVEL = "Tylko aktualny poziom" +NAVI_MENU_NOT_FOUND = "Niema menu id =" +NAVI_SAVE = "Szablon nawigacyjny zapisany" +NAVI_SORTED = "Porządek został dodany pomyślnie" +NAVI_REPORT_NEW = "Menu nawigacyjne stworzone" +NAVI_REPORT_COPY = "Utworzono kopię menu nawigacyjnego" +NAVI_REPORT_EDIT = "Zmieniono szablon menu nawigacyjnego" +NAVI_REPORT_DEL = "Usunięte menu nawigacyjne" +NAVI_REPORT_ADDIT = "Dodać punkt menu nawigacyjnego" +NAVI_REPORT_DELIT = "Usunięto punkt menu nawigacyjnego" +NAVI_REPORT_FLEV = "Na pierwszy poziom" +NAVI_REPORT_SLEV = "Na drugi poziom" +NAVI_REPORT_TLEV = "Na trzeci poziom" +NAVI_REPORT_DEACT = "Wyłączyć punkt menu nawigacyjnego" +NAVI_REPORT_ACT = "Aktywuj punkt menu nawigacyjnego" +NAVI_REPORT_SAVED = "Szablon nawigacyjny zapisany" +NAVI_REPORT_SAVED_ERR = "Nie można zapisać szablonu nawigacyjnego.
Spróbuj ponownie." +NAVI_REPORT_ERROR = "Błąd" +NAVI_REPORT_SUCCESS = "Gotowe" +NAVI_ITEM_ON_OFF = "Włącz / Wyłącz punkt menu" +NAVI_ITEM_EDIT = "Edytuj punkt menu" +NAVI_ITEM_DELETE = "Usuń ten punkt menu" +NAVI_ITEM_DELETE_CONFIRM = "Czy na pewno chcesz usunąć ten punkt menu nawigacyjnego?" + + +// v 3.2 +NAVI_ALIAS = "Аліас" +NAVI_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:sysblock:alias] замість [tag:sysblock:id]. Аліас не може бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах модуля" +NAVI_ACCEPT = "Цей аліас можна використовувати" +NAVI_ER_SYN = "Неправильний аліас!
Аліас не може бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +NAVI_ER_EXISTS = "Неправильний аліас!
Цей аліас уже прив’язаний до іншого меню" + +//from templates +NAVI_NOLINK_DOC = "Немає зв’язаного документа" +NAVI_EDIT_ITEM = "Редагування пункта меню" +NAVI_LINK_FILEDOC = "Зв’язати з документом/файлом" +NAVI_LINKED_DOC = "Зв’язаний документ" +NAVI_DEL_LINKED_DOC = "Вилучити зв’язок з документом" +NAVI_LINK_DOC = "Зв’язати з документом" +NAVI_LINK_FILE = "Зв’язати з файлом" +NAVI_NO_LINK = "Немає зв’язаного документа" +NAVI_STRUCTURE = "Структура" +NAVI_RETURN_TO_LIST = "Повернутися до списку" +NAVI_EDIT_TEMPLATE = "Редагувати шаблон" +NAVI_ITEM_ADD = "Додати пункт меню" +NAVI_OPEN_ALL = "Розкрити усе" +NAVI_CLOSE_ALL = "Згоргути усе" +NAVI_ITEM_DESCR = "Опис пункта меню" +NAVI_ITEM_IMAGE = "Зображення" +NAVI_ITEM_IMAGE_DESCR = "Зображення активне, у кінці назви зображення має бути _act" +NAVI_ITEM_IMAGE_ID = "Id зображення" +NAVI_PLACE_INSERT = "Місце вставки підрівня" +NAVI_EXAMPLE = "Приклад" +NAVI_ITEM_EVEN = "парний" +NAVI_ITEM_ODD = "непарний" +NAVI_TAG = "Тег для вставки пунктів" +NAVI_LAVEL_TEMPL = "Шаблон рівня" +NAVI_CONDITIONS = "Умови" \ No newline at end of file diff --git a/admin/lang/pl/request.txt b/admin/lang/pl/request.txt new file mode 100644 index 0000000..c9b275a --- /dev/null +++ b/admin/lang/pl/request.txt @@ -0,0 +1,188 @@ +# Język polski 02,2017 duncan + +[request] +REQUEST_ID = "ID" +REQUEST_DELETE = "Usuń wniosek" +REQUEST_DELETE_CONFIRM = "Czy na pewno chcesz usunąć ten wniosek?" +REQUEST_TITLE = "Zarządzanie wnioskami" +REQUEST_NAME = "Nazwa wniosku" +REQUEST_NAME2 = "Nazwa wniosku" +REQUEST_NAME3 = "Wprowadź nazwę wniosku" +REQUEST_CACHE = "Dodaj do pamięci podręcznej" +REQUEST_CACHE_ELEMENTS = " Dodaj do pamięci podręcznej elementy wniosku" +REQUEST_SETTINGS = "Parametr wniosku" +REQUEST_TIP = "Tutaj znajduje się lista wszystkich istniejących wniosków w systemie. Aby wykorzystać wniosek, umieść " znacznik systemowy " we właściwym miejscu na szablonie lub dokumencie". +REQUEST_EDIT_TIP = "Tutaj można edytować wniosek, zamieniw rubrykę dla uzyskania danych, szablon wyprowadzenia, a także warunki wyboru danych." +REQUEST_NEW = "Utwórz nowy wniosek" +REQUEST_EDIT = "Edytuj wniosek" +REQUEST_EDIT2 = "Edytuj wniosek" +REQUEST_SYSTEM_TAG = "Znacznik systemowy" +REQUEST_AUTHOR = "Author" +REQUEST_DATE_CREATE = "Data utworzenia" +REQUEST_ACTIONS = "Działania" +REQUEST_NO_DESCRIPTION = "Wniosek bez opisu" +REQUEST_NO_REQUST = "Wnioski nieobecne" +REQUEST_DATE_FORMAT = "%d.%m .%w r." +REQUEST_DATE_FORMAT2 = "%d.%m.% w r. w %H:%M" +REQUEST_IN = "w" +REQUEST_COPY = "Kopiuj wniosek" +REQUEST_COPY_FAILED = "Nie można skopiować wniosek" +REQUEST_PLEASE_NAME = "Proszę podać nazwę dla kopiowanego wniosku" +REQUEST_CONDITION_EDIT = "Warunki dla wniosku" +REQUEST_CONDITION_IF = "Warunki" +REQUEST_PLEASE_SELECT = "Proszę wybrać rubrykę" +REQUEST_SELECT_RUBRIK = "Wybierz rubrykę" +REQUEST_SELECT_INFO = "Czy na pewno chcesz zmienić rubrykę" +REQUEST_NEW_TIP = " Ważne! Przed utworzeniem nowego wniosku, należy wybrać rubrykę, z której będą wyświetlane dokumenty." +REQUEST_DESCRIPTION = "Opis wniosku" +REQUEST_INTERNAL_INFO = "(używane w systemie)" +REQUEST_BUTTON_COND = "Dodawanie / Edycja" +REQUEST_CONDITION = "Warunki wniosku" +REQUEST_ACTION_AFTER = "Powrót do edytowania wniosku po utworzeniu, aby dodać warunki wniosku" +REQUEST_SORT_BY = "Sortuj według właściwości dokumentu" +REQUEST_SORT_BY_NAT = "Sortuj według pola dokumentu" +REQUEST_ASC_DESC = "Według" +REQUEST_DESC = "spadania" +REQUEST_ASC = "wzrostu" +REQUEST_BY_DATE = "daty utworzenia (publikacji)" +REQUEST_BY_DATECHANGE = "Daty zmiany (dokumentu)" +REQUEST_BY_NAME = "Nazwy dokumentu" +REQUEST_BY_EDIT = "Nazwy autora" +REQUEST_BY_PRINTED = "Liczby odbitek" +REQUEST_BY_VIEWS = "Liczby wyświetleń" +REQUEST_BY_RAND = "W praypadkowym porządku (duże obciążenie)" +REQUEST_DOC_PER_PAGE = "Liczba na stronie" +REQUEST_DOC_PER_PAGE_ALL = "Wyświetlij wszystko" +REQUEST_SHOW_NAVI = "Pokaż nawigacje" +REQUEST_USE_LANG = "Tylko język użytkownika" +REQUEST_USE_WNIOSEK = "Wykorzystaj tylko GET wnioski do wykorzystania w nawigacji stronicowania" +REQUEST_TEMPLATE_WNIOSEK = "Podstawowy szablon wyglądu wniosku" +REQUEST_MAIN_CONTENT = "Znacznik systemowy, który jest odpowiedzialny za wyjśćie elementów wniosku, określonych w "elementy wniosku& quot;" +REQUEST_DOC_COUNT = "Znacznik systemowy, który jest odpowiedzialny za wyjście liczby elementów wniosku" +REQUEST_DOCITEMNUM_INFO = "Znacznik systemowy, który jest odpowiedzialny za wyjście numeru seryjnego elementu wniosku" +REQUEST_MAIN_NAVI = "Znacznik systemowy, który jest odpowiedzialny za wyjście nawigacji stronicowania dla wniosku (< 1 2 3 >)" +REQUEST_MEDIAPATH = "Znacznik systemowy, który określa ścieżki do folderu z szablonem (np: [tag:mediapath]images/logo.gif)" +REQUEST_PATH = "Znacznik systemowy, który określa korzeń instalacji" +REQUEST_TEMPLATE_ITEMS = "Szablon projektu dla elementów wniosku" +REQUEST_TEMPLATE_INFO = "W tym polu, stosując kod HTML, można określić projekt dla wewnętrznych elementów wniosku (na przykład, wygląd listy wiadomości). Wszystkie elementy zostały zaprojektowane według tego szablonu, będą cyklicznie wyświetlane w "podstawowym szablonie" wniosku, dopóki liczba elementów będzię spełniać warunki złożenia wniosku". +REQUEST_TEMPLATE_SAVED = "Wniosek pomyślnie zapisany" +REQUEST_SELECT_IN_LIST = "Proszę wybrać pole rubryki z listy poniżej" +REQUEST_RUB_INFO = "Znacznika systemowy, który jest odpowiedzialny za wyjście zawartośći pola rubryki. ID pola. Xxx-liczba znaków do wyświetlania". +REQUEST_LINK_INFO = "Znacznik systemowy, który określa odnośnik do dokumentu, na przykład < a href = "[tag:link]">  odnośnik < /a>" +REQUEST_RUBRIK_FIELD = "Znacznik systemowy pola" +REQUEST_THUMBNAIL = "Znacznik jest odpowiedzialny za tworzenie miniatury (pod warunkiem, że w szablonie pola rubryki (szablon dla wyjścia we wniosku) jest wybrane wyjście: [tag: parametr:0])" +REQUEST_FIELD_NAME = "Nazwa pola" +REQUEST_FIELD_TYPE = "Typ pola" +REQUEST_FIELD_G_UNKNOW = "Bez grupy" +REQUEST_BUTTON_ADD = "Utwórz wniosek" +REQUEST_BUTTON_ADD_NEXT = " Utwórz i kontynuuj" +REQUEST_BUTTON_SAVE = "Zapisz zmiany" +REQUEST_BUTTON_SAVE_NEXT = "Zastosuj (CTRL + S)" +REQUEST_BUTTON_CLOSE = "Zamknij okno" +REQUEST_INSERT_INFO = "Kliknij na znacznik systemowy, aby dodaćgo do szablonu" +REQUEST_CONDITIONS = "Zarządzanie warunkami wniosku" +REQUEST_CONDITION_TIP = "Tutaj można stworzyć specjalne warunki wyboru danych do wniosku. Warunki wniosku pozwalają najdokładniej określić wyjście danych o różnych parametrach." +REQUEST_NEW_CONDITION = "Dodaj nowy warunek" +REQUEST_FROM_FILED = "Wybierz z pola" +REQUEST_OPERATOR = "Gdzie znaczenie" +REQUEST_VALUE = "Znaczenie" +REQUEST_COND_SELF = "Równe" +REQUEST_COND_NOSELF = "Nie równa się" +REQUEST_COND_USE = "Zawiera znaczenie" +REQUEST_COND_NOTUSE = "Nie zawiera znaczenia" +REQUEST_COND_START = "Zaczyna się od" +REQUEST_SMALL1 = "Mniejsze lub równe" +REQUEST_BIG1 = "Większe lub równe" +REQUEST_SMALL2 = "Mniejsze" +REQUEST_BIG2 = "Większe" +REQUEST_N_COND_SELF = "Liczba jest równa" +REQUEST_N_SMALL1 = "Liczba jest mniejsza niż lub równa" +REQUEST_N_BIG1 = "Liczba jest większa niż lub równa" +REQUEST_N_SMALL2 = "Liczba mniejsza" +REQUEST_N_BIG2 = "Liczba większa" +REQUEST_SEGMENT = "Należy segmentu (przez)" +REQUEST_INTERVAL = "Należy interwału (przez)" +REQUEST_IN = "W liscie (przez)" +REQUEST_NOTIN = "Nie ma na liście (przez)" +REQUEST_ANY_NUM = "NIEBEZPIECZEŃSTWO !!! Numer we wniosku" +REQUEST_FREE = "NIEBEZPIECZEŃSTWO !!! Dowolny warunek [field] = {znaczenie}" +REQUEST_MARK_DELETE = "Odznacz warunek, aby usunąć" +REQUEST_CONR_AND = "I" +REQUEST_CONR_OR = "Lub" +REQUEST_OR = "& nbsp; lib & nbsp;" +REQUEST_VIEWS_INFO = "Znacznik systemowy, który pokazuje liczbę odsłon dokumentu" +REQUEST_COMMENTS_INFO = "Znacznik systemowy, który pokazuje liczbę komentarzy do dokumentu Uwaga! Działa tylko przy zainstalowanym module!" +REQUEST_CONTROL_FIELD = "Znacznik systemowy, który jest odpowiedzialny wyjście Panelu sterowania wnioskiem. Tylko dla rubryk z polami typu lista rozwijana" +REQUEST_CONTROL_SORT = "Znacznik systemowy, który jest odpowiedzialny za wyjście panelu sortowania według daty publikacji, tytule i liczbie przeglądów wyników wyjścia wniosku" +REQUEST_NO_DROPDOWN = "W wybranej rubrycę nie ma pola takich jak lista rozwijana" +REQUEST_ENTER_NAME = "Proszę podać nazwę tego wniosku." +REQUEST_ALL = "Lista wniosków" +REQUEST_IF_EMPTY = "Sparowany znacznik systemowy, w którym można określić szablon wyjścia przy braku wyników roboty wniosku" +REQUEST_NOT_EMPTY = "Sparowany znacznik systemowy, w którym można określić szablon wyjścia przy obecnośći wyników roboty wniosku" +REQUEST_DOCID_INFO = "Znacznik systemowy, który odpowiada identyfikatoru dokumentu" +REQUEST_DOCTITLE_INFO = " Znacznik systemowy, który odpowiada imieniu dokumentu" +REQUEST_CDOCID_INFO = "Znacznik systemowy, który odpowiada ID bieżącego dokumentu (w którym wywodzi się wniosek)" +REQUEST_DOCDATE_INFO = "Znacznik systemowy, który odpowiada dacie publikacji dokumentu" +REQUEST_CDOCDATE_INFO = "Znacznik systemowy, który odpowiada dacie publikacji niniejszego dokumentu (w którym wywodzi się wniosek)" +REQUEST_DOCTIME_INFO = "Znacznik systemowy, który odpowiada odpowiada dacie i godzinie publikacji dokumentu" +REQUEST_CDOCTIME_INFO = "Znacznik systemowy, który odpowiada dacie i godzinie publikacji niniejszego dokumentu (którego wywodzi się wniosek)" +REQUEST_DATE_INFO = "Znacznik systemowy, data i godzina publikacji dokumentu - wygląd konfigurowany
. Przykład: [tag: data: DMY] 
 Można używać dystrybutorów (spacja - /)" +REQUEST_CDATE_INFO = "Znacznik systemowy, data i godzina publikacji dokumentu - wygląd konfigurowany
. Przykład: [tag: data: DMY] 
( W którym wywodzi się wniosek)
Można używać dystrybutorów (spacja - / )". +REQUEST_DOCAUTHOR_INFO = "Znacznik systemowy, który odpowiada autorowi dokumentu" +REQUEST_DOCAUTHOR_AVATAR = "Znacznik systemowy, który odpowiada awataru autora dokumentu" +REQUEST_CDOCAUTHOR_INFO = "Znacznik systemowy, który odpowiada autoru tego dokumentu (w którym wywodzi się wniosek)" +REQUEST_SAMPLE = "Przykład" +REQUEST_HIDE_CURRENT = "Nie pokazuj we wniosku bieżący dokument" +REQUEST_ONLY_OWNER = "Tylko swoje (UserID) dokumenty" +REQUEST_CONDITION_JOIN = "Operator" +REQUEST_CONDITION_SAVE = "Zapisz warunki" +REQUEST_CONDITION_ADD = "Dodaj warunek" +REQUEST_SUCCESS = "Gotowe" +REQUEST_ERROR = "Błąd" +REQUEST_CANCEL = "Anuluj" +REQUEST_SORTED = "Porządek został dodany pomyślnie" +REQUEST_COND_MESSAGE = "Niema warunków wniosku" +REQUEST_COND_VALUE_ERR = "Puste pole znaczenia" +REQUEST_COND_NEW_ERR = "Nie można dodać nowy warunek
Spróbuj ponownie" +REQUEST_COND_NEW_SUC = "Warunek pomyślnie dodany" +REQUEST_COND_POST_OK = "Warunki pomyślnie zapisane" +REQUEST_COND_POST_ERR = "Nie można zapisać warunki wniosku
Spróbuj ponownie" +REQUEST_COND_NO_POST = "Brak danych do zapisania
Spróbuj ponownie" +REQUEST_COND_ADD_SUC = "Dodaj warunki wniosku" +REQUEST_COND_CHA_SUC = "Zmieniono warunki wniosku" +REQUEST_COND_DEL_SUC = "Usunięto warunki wniosku" +REQUEST_SAVE_CHA_SUC = "Edytowane warunki wniosku" +REQUEST_ADD_NEW_SUC = "Dodaj nowe wniosku" +REQUEST_DELETE_SUC = "Usunięto wniosek" +REQUEST_COPY_SUC = "Stworzono kopię wniosku" +REQUEST_HEADER_SELF = "Główne parametry wniosku" +REQUEST_HEADER_NAME = "Znaczenie" +REQUEST_HEADER_PARAMETR = "Parametr" +REQUEST_REPORT_ERR_TITLE = "Nie ma nazwy wniosku" +REQUEST_REPORT_ERR_TEXT = "Nie ma podstawowego szablonu wniosku" +REQUEST_REPORT_ERR_PHP = "Nie używaj kodu PHP" +REQUEST_REPORT_ERR_PHP_N = "Próba użycia kodu PHP w szablonie wniosku przy tworzeniu wniosku" +REQUEST_REPORT_ERR_PHP_E = "Próba użycia kodu PHP w szablonie wniosku" +REQUEST_REPORT_ERR_RUBRIC = "Nie wybrano rubryki" +REQUEST_BY_PARENT = "Dokumentu nadrzędnemu" +REQUEST_SHOW_STAT = "Pokaż statystyki" + + +// v 3.1.9 +REQUEST_ALIAS = "Аліас" +REQUEST_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:request:alias] замість [tag:request:id]. Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах модуля" +REQUEST_ACCEPT = "Цей Аліас можна використовувати" +REQUEST_ER_SYN = "Неправильний Аліас!
Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +REQUEST_ER_EXISTS = "Неправильний Аліас!
Цей Аліас уже прив’язано до іншого запиту" +REQUEST_HEADER_EXTERNAL = "Зовнішнє звернення" +REQUEST_EXTERNAL = "Дозволити зовнішнє звернення" +REQUEST_ONLY_AJAX = "Виконувати тільки по Ajax" + +// v 3.2 +REQUEST_PAGINATION = "Посторінкова навігація" +REQUEST_NAVI_TPL = "Шаблон посторінкової навігації" +REQUEST_OTHER = "Інше" +REQUEST_SHOW_SQL = "Показати SQL запит" +REQUEST_DOC_ON_PAGE = "Число елементів запиту на сторінці" +REQUEST_PAGES_CURENT = "Номер сторінки пагінації" +REQUEST_PAGES_TOTAL = "Загальна кількість сторінок пагінації" \ No newline at end of file diff --git a/admin/lang/pl/rubs.txt b/admin/lang/pl/rubs.txt new file mode 100644 index 0000000..d800b7b --- /dev/null +++ b/admin/lang/pl/rubs.txt @@ -0,0 +1,267 @@ +# Język polski 02,2017 duncan + +[rubs] +RUBRIK_SUB_TITLE = "Zarządzanie rubrykami" +RUBRIK_TIP = "Tutaj znajduje się lista wszystkich rubryk w systemie. Można edytować szablon rubryki, uprawnienia, usunąć rubrykę i skopiować rubrykę, aby na jej podstawie utworzyć nową." +RUBRIK_ID = "ID" +RUBRIK_NAME = "Nazwa rubryki" +RUBRIK_NAME2 = "Nazwa rubryki:" +RUBRIK_TEMPLATE_OUT = "Użyj w szablonie" +RUBRIK_TEMPLATE_OUT2 = "Użyj w szablonie" +RUBRIK_URL_PREFIX = "Przedrostek dla linków" +RUBRIK_URL_PREFIX2 = "Przedrostek dla linków" +RUBRIK_DOCS_VI ="Pokaż dokumenty na liscię" +RUBRIK_URL_PREFIX2 = "Przedrostek dla linków" +RUBRIK_COUNT_DOCS Ilosc = "Ilość dokumentów" +RUBRIK_COUNT_FIELDS = "Ilość pól" +RUBRIK_AUTHOR = "Author" +RUBRIK_ACTION = "Działania" +RUBRIK_FORMAT = "Użyj" +RUBRIK_FORMAT_TIME = "Do linku w formacie czasu" +RUBRIK_FORMAT_ID = "Do wstawienia ID dokumentu" +RUBRIK_EDIT = "Edycja pola i uprawnienia rubryki" +RUBRIK_EDIT_TMPLS = "Dodatkowe szablony" +RUBRIK_NO_VIEW = "Przepraszamy, ale nie masz uprawnień, aby zobaczyć listę rubryk". +RUBRIK_NO_CHANGE1 = "Przepraszamy, ale nie masz uprawnień do edycji pola rubryki." +RUBRIK_NO_CHANGE2 = "Przepraszamy, ale nie masz uprawnień do edycji szablonu tej rubryki." +RUBRIK_NO_CHANGE3 = "Przepraszamy, ale nie masz uprawnień do tworzenia nowyhc rubryk". +RUBRIK_EDIT_TEMPLATE = "Edycja szablonu rubryki" +RUBRIK_EDIT_CODE = "Edytuj kod wykonywalny dla rubryk" +RUBRIK_EDIT_CODE_T = "Redagowanie kodu wykonywalnego dla rubryk" +RUBRIK_EDIT_CODE_NO = "Brak dostępu do edycji kodu wykonywalnego" +RUBRIK_DELETE = "Usunąć tę rubrykę" +RUBRIK_DELETE_LEGEND = "Usuń rubrykę" +RUBRIK_DELETE_CONFIRM = "Czy na pewno chcesz usunąć tę rubrykę?" +RUBRIK_NO_PERMISSION = "Przepraszamy, ale nie wolno usunąć rubrykę". +RUBRIK_USE_DOCUMENTS = "Przepraszamy, ale nie można usunąć tę rubrykę, ponieważ zawiera ona dokumenty". +RUBRIK_MULTIPLY = "Kopiuj rubrykę" +RUBRIK_NO_MULTIPLY = "Przepraszamy, ale nie masz uprawnień do kopiowania rubryk" +RUBRIK_BUTTON_SAVE = "Zapisz zmiany" +RUBRIK_BUTTON_TEMPL = "Edytuj szablon" +RUBRIK_BUTTON_FIELDS = "Edytuj pola" +RUBRIK_BUTTON_CODE = "Edytuj kod rubryki" +RUBRIK_LEGEND = "Znaczenie piktogramu" +RUBRIK_NEW = "Utwórz nową rubrykę" +RUBRIK_NEW_TIP = "Tutaj można utworzyć nową rubrykę. Proszę podać nazwę nowej rubryki i wybrać szablon dla wyjścia". +RUBRIK_BUTTON_NEW = "Tworzenie rubryki" +RUBRIK_EDIT_FIELDS = "Zarządzanie polami i prawami dostępu do rubryki" +RUBRIK_DESCRIPTION = "Opis rubryki" +RUBRIK_NO_FIELDS = " Uwaga! Nie utworzono żadnego pola. Należy dodać co najmniej jedno pole." +RUBRIK_FIELDS_INFO = "Tutaj można utworzyć grupę pól, które będą wykorzystywane do dokumentów znajdujących się w tej rybrycę." +RUBRIK_MULTIPLY2 = "Kopiowanie rubryki" +RUBRIK_MULTIPLY_TIP = "Proszę podać nazwę i prefiks do linku do nowej rubryki" +RUBRIK_BUTTON_COPY = "Kopiuj" +RUBRIK_TEMPLATE_EDIT = "Edycja szablonu rubryki" +RUBRIK_TEMPLATE_NEW = "Utwórz szablon rubryki" +RUBRIK_TEMPLATE_SAVED = "Szablon zapisany" +RUBRIK_NO_FIELD = "W tej rubryki nie ma pola" +RUBRIK_FIELD_NAME = "Nazwa pola" +RUBRIK_FIELD_GROUP = "Grupa" +RUBRIK_FIELD_GROUP_SEL = "Wybierz grupę" +RUBRIK_FIELD_ALIAS = "Alias pola" +RUBRIK_FIELD_TYPE = "Typ pola" +RUBRIK_FIELD_UNKNOW = "Nieznane" +RUBRIK_FIELD_G_UNKNOW = "Bez grupy" +RUBRIK_POSITION = "Pozycja" +RUBRIK_NEW_FIELD = "Utwórz nowe pole dla rubryki" +RUBRIK_BUTTON_ADD = "Dodaj pole" +RUBRIK_SET_PERMISSION = "Prawo dostępu do dokumentów dla grup użytkowników" +RUBRIK_USER_GROUP = "Grupa" +RUBRIK_DOC_READ = "Przegląd" +RUBRIK_ALL_PERMISSION = "Wszystkie prawa" +RUBRIK_CREATE_DOC = "Utwórz z kontrolą" +RUBRIK_CREATE_DOC_NOW = "Utwórz bez sprawdzania" +RUBRIK_EDIT_OWN = "Edytuj swoje" +RUBRIK_EDIT_DELREV = "Zarządzanie rewizjami" +RUBRIK_EDIT_OTHER = "Edycja wszystkich" +RUBRIK_VIEW_TIP = "Zaznacz, jeśli chcesz, aby ta grupa użytkowników przeglądała dokumenty" +RUBRIK_ALL_TIP = "Zaznacz, jeśli chcesz, aby włączyć tę grupę użytkowników do wykonywania jakichkolwiek działań z dokumentami, znajdujących się w tej rybrycę." +RUBRIK_DOC_TIP = "Zaznacz, jeśli chcesz, aby włączyć tę grupę użytkowników do tworzenia dokumentów.
Uwaga!
Przed publikacją dokumentu, musi on być zweryfikowany przez Administratora" +RUBRIK_DOC_NOW_TIP = "Zaznacz, jeśli chcesz, aby włączyć tę grupę użytkowników do tworzenia dokumentów.
Uwaga! />
Wydanie dokumentu będzie wykonywane bez sprawdzania Administratorem" +RUBRIK_OWN_TIP = "Zaznacz, jeśli chcesz, aby ta grupa użytkowników edytowała tylko swoje dokumenty" +RUBRIK_OTHER_TIP = "Zaznacz, jeśli chcesz, aby ta grupa użytkowników edytowała swoje i obce dokumenty" +RUBRIK_DELREV_TIP = "Zaznacz, jeśli chcesz, aby ta grupa użytkowników pracowała z rewizjami dokumentów" +RUBRIK_BUTTON_PERM = "Zapisz uprawnienia" +RUBRIK_FIELD_DEFAULT = "Znaczenia domyślne" +RUBRIK_TEMPLATE_TIP = "Tutaj, za pomocą języka znaczników HTML, należy utworzyć szablon dla dokumentów z pełnym przeglądem" +RUBRIK_HTML = "Szablon projektu rubryki" +RUBRIK_HTML_2 = "Szablon projektu HEADER" +RUBRIK_HTML_3 = "Szablon projektu TEASER" +RUBRIK_HTML_4 = "Szablon projektu ADMIN TEASER" +RUBRIK_PHP_DENIDED = " Błąd!
Nie masz uprawnień do edytowania rubryki szablonów, ponieważ wykorzystujesz kod PHP i nie masz uprawnień do korzystania z kodu PHP." +RUBRIK_PHP_MESSAGE = "Nie używaj kodu PHP." +RUBRIK_EMPTY_MESSAGE = "Nie podano nazwę pola". +RUBRIK_INSERT_HELP = "Kliknij, aby dodać znacznik systemowy od szablonu" +RUBRIK_BUTTON_TPL = "Zapisz szablon" +RUBRIK_BUTTON_TPL_NEXT = "Zastosuj (CTRL + S)" +RUBRIK_BUTTON_TPL_CLOSE = "Zamknij" +RUBRIK_NO_RUBRIK = "Nie ma takiej rubryki!" +RUBRIK_NO_NAME = "Proszę podać nazwę rubryki" +RUBRIK_NAME_EXIST = "Niestety, ale rubryka o tej samej nazwie już istnieje. Proszę podać inną nazwę rubryki." +RUBRIK_PREFIX_EXIST = "Przepraszamy, ale z takim URL-prefiksem już istnieje. Proszę podać inny adres URL-prefiks rubryki." +RUBRIK_VIEWS_INFO = "Znacznik systemowy, który pokazuje liczbę odsłon dla dokumentu" +RUBRIK_HIDE_INFO = "Znacznik systemowy, który pozwala na ukrycie tekstu dla określonych grup użytkowników, gdzie X – numer grupy" +RUBRIK_THUMBNAIL = "Znacznik jest odpowiedzialny za tworzenie miniatury (pod warunkiem, że w szablonie pola rubryki (szablon dla wyjścia w dokumencie) wybrane jest wyjście: [tag: parametr: 0])" +RUBRIK_LINK_HOME = "Link do strony głównej strony internetowej" +RUBRIK_MARK_DELETE = "Zaznacz tę opcję, aby usunąć" +RUBRIK_MARK_DEL_ALL = "Zaznacz wszystko" +RUBRIK_CHECK_SEARCH = "Szukaj w tym polu" +RUBRIK_CHECK_NUMERIC = "Pole numeryczne" +RUBRIK_SEARCH_TIP = "Zaznacz, jeśli chcesz przeprowadzać w nim poszukiwanie (współpracuje z modułem "szukaj" wersji 2.0.2 i nowsze)" +RUBRIK_NUMERIC_TIP = "Zaznacz, jeśli jego znaczenie jest zawsze liczbą. Służy do sortowania we wnioskach" +RUBRIK_ALL = "Lista rubryk" +RUBRIK_EDIT_FIELDS_GROUPS = "Edytuj grupy pól" +RUBRIK_FIELDS_GROUPS = "Grupy pól" +RUBRIK_ENTER_NAME = "Podaj nazwę rubryki." +RUBRIK_TEMPLATE_HIDE = "Pokaż / Zwiń szablony wszystkich pól" +RUBRIK_FILED_TEMPLATE_H = "Edytuj szablon i opis pola" +RUBRIK_FILED_TEMPLATE_DESCR = "Opis pola" +RUBRIK_FILED_TEMPLATE_F = "Szablon pola" +RUBRIK_DOCID_INFO = "Znacznik systemowy, identyfikator dokumentu" +RUBRIK_DOCDATE_INFO = "Znacznik systemowy, data publikacji dokumentu" +RUBRIK_DOCTIME_INFO = "Znacznik systemowy, data i godzina publikacji dokumentu" +RUBRIK_DATE_INFO = "Znacznik systemowy, data i godzina publikacji dokumentu - konfigurowalny wygląd
. Przykład: [tag: data: Y] " +RUBRIK_DOCAUTHOR_INFO = "Znacznik systemowy, autor dokumentu" +RUBRIK_TITLE_INFO = "Znacznik systemowy, tytuł dokumentu" +RUBRIK_PATH_INFO = "Znacznik systemowy, ścieżki do instalacji root" +RUBRIK_MEDIAPATH_INFO = "Znacznik systemowy, ścieżki do folderu projektowania" +RUBRIK_PREFIX_BAD_CHAR = "Nieprawidłowe znaki w prefiksie" +RUBRIK_FIELDS_TITLE = "Pola rubryki" +RUBRIK_FIELDS_TPL = "Szablon wyjścia pola w dokumencie" +RUBRIK_RUBRIK_TPL = "Szablonu wyjścia pola we wniosku" +RUBRIK_SORTED = "Porządek został zapisaany pomyślnie" +RUBRIK_F_SORT_TIP = "Aby usprawnić pola kliknij na krzyżyk i, przytrzymując go, przeciągnij pole" +RUBRIK_R_SORT_TIP = "Aby usprawnić rubryki, kliknij na krzyżyk i, utrzymując go, przeciągnij pole" +RUBRIK_META_GEN_TIP = "Automatycznie generować słowa kluczowe, opis dokumentu na podstawie jego treści" +RUBRIK_ALIAS_HISTORY_TIP = "Przechowywanie historii aliasów w dokumencie" +RUBRIK_MOVE = "Przemieścić" +RUBRIK_REQUEST_TPL = "Szablon wyjścia pola we wniosku" +RUBRIK_BREADCRUMB = "Znacznik systemowy nawigacji okruszkowej" +RUBRIK_CODE = "Kod wykonywalny dla rubryk" +RUBRIK_START_CODE = "Kod, który jest wykonywany przed pobraniem dokumentu" +RUBRIK_CODE_START = "Kod, który jest wykonywany przed zapisaniem dokumentu" +RUBRIK_CODE_END = "Kod, który jest wykonywany po zapisaniu dokumentu" +RUBRIK_TAGS = "Znacznik" +RUBRIK_TAGS_ID = "Znacznik systemowy ID" +RUBRIK_TAGS_ALIAS = "Znacznik systemowy Alias" +RUBRIK_HTML_T = "HTML kod szablonu" +RUBRIK_TAG_DESC = "Opis znacznika" +RUBRIK_NEW_FIEL_TITLE = "Dla pól Lista rozwijana i Multi-lista , znaczenia domyślne są pisane przez przecinek" +RUBRIK_LINK = "Połączyć rubrykę" +RUBRIK_LINK_DESC = "Ustawianie połączenia pomiędzy rubrykami, podczas dodawania dokumentów możliwe jest automatyczny zastąpienie aliasów." +RUBRIK_NOLINK = "Nie wybrane" +RUBRIK_OR = "& nbsp; lub & nbsp;" +RUBRIC_F_GROUP_TITLE = "Nazwa grupy" +RUBRIC_F_GROUP_DELETE = "Usuń grupę" +RUBRIC_F_GROUP_DELETE_H = "Czy na pewno chcesz usunąć grupę?" +RUBRIC_NO_GROUPS = "Obecnie dla tej rubryki niema żadnych grup pól" +RUBRIC_GROUP_ADD = "Dodaj grupę" +RUBRIK_NEW_GROUP = "Dodaj nową grupę" +RUBRIK_HEADER_GROUP = "Zarządzania grupami pól" +RUBRIK_TEMPLATES_TAGS = "Znacznik" +RUBRIK_TEMPLATES_TAG_DESC = "Opis znacznika" +RUBRIK_TEMPLATES_THEME_FOLDER = "Nazwa szablonu (Nazwa folderu plików dla tego szablonu)" +RUBRIK_TEMPLATES_PAGENAME = "Nazwa strony internetowej" +RUBRIK_TEMPLATES_TITLE = "Nzawa strony" +RUBRIK_TEMPLATES_KEYWORDS = "Słowa kluczowe (Meta - słowa kluczowe)" +RUBRIK_TEMPLATES_DESCRIPTION = "Opis strony (Meta - Opis)" +RUBRIK_TEMPLATES_INDEXFOLLOW = "Typ indeksowania" +RUBRIK_TEMPLATES_PATH = "Ścieżka instalacji root" +RUBRIK_TEMPLATES_MEDIAPATH = "Ścieżka do folderu z szablonem (Przykład: [tag: mediapath] images / logo.gif)" +. RUBRIK_TEMPLATES_CSS = "Kompresuje kilka css-plików w jednym. Zwraca ścieżkę
FFF. - nazwy plików oddzielone przecinkami
P - ścieżki do folderu z plikami nie są wymagane. Domyślne - [tag: mediapath] css / 
 Przykład: href = & quot; [tag: CSS: reset.css, style.css] & quot; " +RUBRIK_TEMPLATES_JS = "Kompresuje kilka js-plików w jeden. Zwraca ścieżkę.
FFF. - nazwy plików oddzielone przecinkami
P ścieżki do folderu z plikami nie są wymagane. Domyślne - [tag: mediapath] js / 
 Przykład: href = & quot; [tag: JS: common.js, main.js] & quot; " +RUBRIK_RUB_INFO = "Znacznik systemowy, co odpowiada za wyjście zawartości rubryki. Numer ID pola. XXX - liczba znaków do wyświetlania". +RUBRIK_SELECT_IN_LIST = "Proszę wybrać pole rubryki z poniższej listy" +RUBRIK_TEMPLATE_ITEMS = "Szablon projektu dla elementów wniosku" +RUBRIK_DOCID_INFO = "Znacznik systemowy, który odpowiada identyfikatorowi dokumentu" +RUBRIK_DOCTITLE_INFO = "Znacznik systemowy, który pasuje do imienia dokumentu" +RUBRIK_CDOCID_INFO = "Znacznik systemowy, który odpowiada identyfikatorowi bieżącego dokumentu (w którym wywodzi się wniosek)" +RUBRIK_DOCDATE_INFO = "Znacznik systemowy, który odpowiada dacie publikacji niniejszego dokumentu" +RUBRIK_CDOCDATE_INFO = "Znacznik systemowy, który odpowiada dacie publikacji niniejszego dokumentu (w którym wywodzi się wniosek)" +RUBRIK_DOCTIME_INFO = "Znacznik systemowy, który odpowiada dacie i godzinie publikacji dokumentu" +RUBRIK_CDOCTIME_INFO = "Znacznik systemow, który odpowiada dacie i godzinie publikacji niniejszego dokumentu (w którym wywodzi się wniosek)" +RUBRIK_DATE_INFO = "Znacznik systemowy, data i godzina publikacji dokumentu - konfigurowalny wygląd
. Przykład: [tag: data: DMY] 
 Można używać systemów dystrybucyjnych (Spacja - /)" +RUBRIK_CDATE_INFO = "Znacznik systemowy, data i godzina publikacji dokumentu - konfigurowalny wygląd
. Przykład: [tag: data: DMY] 
(W którym wywodzi się wniosek)
Można używać systemów dystrybucyjnych (spacja - / ) " +RUBRIK_DOCAUTHOR_INFO = "Znacznik systemowy, który odpowiada autoru dokumentu" +RUBRIK_DOCAUTHOR_AVATAR = "Znacznik systemowy, który odpowiada awataru autora dokumentu" +RUBRIK_CDOCAUTHOR_INFO = "Znacznik systemowy, który odpowiada autoru tego dokumentu (w którym wywodzi się wniosek)" +RUBRIK_VIEWS_INFO = "Znacznik systemowy, który pokazuje liczbę przeglądów dokumentu" +RUBRIK_COMMENTS_INFO = "Znacznik systemowy, który pokazuje liczbę przeglądów dokumentu Uwaga! Działa tylko w module " +RUBRIK_PATH = "Znacznik systemowy, identyfikujący instalacje root" +RUBRIK_MEDIAPATH = "Znacznik systemowy, który określa ścieżki do folderu z szablonem (Przykład: [TAG: mediapath] images / logo.gif)" +RUBRIK_THUMBNAIL = "Znacznik systemowy jest odpowiedzialny za tworzenie miniatury (Pod warunkiem, że w szablonie pola rubryki (szablon dla wyjścia do wniosku) wybrany hest wyjście: [tag: parametr: 0])" +RUBRIK_ALIAS_HEAD = "Przypisywanie aliasu w polu" +RUBRIK_ALIAS_HEAD_T = "Można używać tylko łacińskich liter i cyfr
Przykład: header " +RUBRIK_ALIAS_HEAD_R = "Rubryka" +RUBRIK_ALIAS_HEAD_F = "Pole" +RUBRIK_ALIAS_ALIAS = "Alias pola" +RUBRIK_ALIAS_NAME = "Nazwa aliasa" +RUBRIK_ALIAS_BUTT = "Zapisz" +RUBRIK_ALIAS_BŁĄD = "Błąd" +RUBRIK_ALIAS_RUBID = "Nieprawidłowo podano rubrykę" +RUBRIK_ALIAS_FIELDID = "Nieprawidłowo podano pole" +RUBRIK_ALIAS_MATCH = "Nieprawidłowo podano znaczenie" +RUBRIK_ALIAS_USED = "To znaczenie jest już wykorzystywane" +RUBRIK_REPORT_QUICKSAVE = "Zakończone szybkie zapisywanie ustawień rubryk" +RUBRIK_REPORT_SORTE = "Wykonane sortowanie rubryk" +RUBRIK_REPORT_SORTE_FIELDS = "Wykonane sortowanie pól rubryki" +RUBRIK_REPORT_PERMISION = "Zmieniono prawo dostępu do dokumentów należących do rubryki" +RUBRIK_REPORT_COPY = "Utworzono kopię rubryki" +RUBRIK_REPORT_TEMPL_RUB = "Odedytowano szablon rubryki" +RUBRIK_REPORT_FIELD_EDIT = "Odedytowano pole" +RUBRIK_REPORT_FIELD_DEL = "Usunięto pole" +RUBRIK_REPORT_RUB = "Rubryki" +RUBRIK_REP_QUICKSAVE_H = "Gotowe" +RUBRIK_REP_QUICKSAVE_T = "Ustawienia rubryki zostały pomyślnie zapisane" +RUBRIK_REPORT_ADD = "Dodano rubrykę" +RUBRIK_REPORT_SAVE_TPL = "Zapisano szablon projektu rubryki" +RUBRIK_CODE_SAVED = "Kod wykonywalny dla rubryki pomyślnie zapisany" +RUBRIK_CODE_SAVED_ERR = "Nie można zapisać kod wykonywalny dla danej rubryki.
Spróbuj ponownie." +RUBRIK_CODE_BŁĄD = "Błąd" +RUBRIK_CODE_SUCCESS = "Gotowe" +RUBRIK_CODE_UPDATE = "Zmieniono kod wykonywalny dla rubryki" +RUBRIK_LOG_NEW_FIELD = "Dodano pole rubryki" +RUBRIK_LOG_DEL_RUBRIC = "Usunięto rubrykę" +RUBRIK_LOG_NEW_RUBRIC = "Utworzono rubrykę" +RUBRIK_FILDS_SAVED = "Pomyślnie zapisane" +RUBRIK_FILD_SAVED = "Pole dodane pomyślnie" +RUBRIK_FILDS_REPORT = "Zapisano pola rubryki" +RUBRIK_FILDS_BŁĄD = "Błąd" +RUBRIK_FILDS_SUCCESS = "Gotowe" +RUBRIC_BŁĄD = "Błąd" +RUBRIC_SUCCESS = "Gotowe" +RUBRIC_SAVED_PHP_ERR = "Nie używaj kodu PHP w szablonach" +RUBRIC_SAVED_TPL_ERR = "Nie można zapisać rubrykę szablonów.
Spróbuj ponownie." +RUBRIC_SAVED_TPL = "Szablon rubryki pomyślnie zapisany" +RUBRIC_SAVED_FLDTPL = "Szablon pola pomyślnie zapisany" +RUBRIK_TAG_SYSBLOCK = "Znacznik systemowy wyjśćia bloku systemowego" +RUBRIK_TAG_TEASER = "Znacznik systemowy wyjścia teaser’a" +RUBRIK_TAG_ALIAS = "Znacznik systemowy wyjścia alias’a dokumentu" +RUBRIK_TAG_REQUEST = " Znacznik systemowy wyjścia wniosku" +RUBRIC_SAVED_PERMS = "Prawo dostępu do dokumentów pomyślnie zapisane" +RUBRIK_IFELSE = "Warunki" +RUBRIK_IFELSE_1 = "Wyjście, jeśli pole nie jest puste" +RUBRIK_IFELSE_2 = "Inne wyjście, jeśli pole jest puste" +RUBRIK_SAMPLE = "Przykład" +RUBRIC_TMPLS_BUTTON = "Dodatkowe szablony rubryki" +RUBRIC_TMPLS_HEAD = "Lista dodatkowych szablonów rubryki" +RUBRIC_TMPLS_ADD = "Dodaj nowy szablon" +RUBRIC_TMPLS_ID = "ID" +RUBRIC_TMPLS_NAME = "Nazwa" +RUBRIC_TMPLS_NAME_FULL = "Nazwa szablonu projektu rubryki" +RUBRIC_TMPLS_AUTHOR = "Author" +RUBRIC_TMPLS_DATE = "Data" +RUBRIC_TMPLS_COUNT_DOCS = "Ilosc dokumentów" +RUBRIC_TMPLS_ACTIONS = "Działania" +RUBRIC_TMPLS_COPY = "Kopiuj szablon" +RUBRIC_TMPLS_COPY_TIP = "Proszę podać nazwę szablonu" +RUBRIC_TMPLS_COPY_TIP2 = "Proszę podać nazwę szablonu, który jest kopiowany" +RUBRIC_TMPLS_EDIT = "Edytuj" +RUBRIC_TMPLS_DELETE = "Usuń" +RUBRIC_TMPLS_DELETE_C = "Czy na pewno chcesz usunąć ten szablon?" +RUBRIC_TMPLS_TIP = "Można utworzyć nieograniczoną ilosc szablonów dla jednej z rubryk" +RUBRIC_TMPLS_NO_ITEMS = " Wiadomość:
Na razie nie ma żadnych dodatkowych szablonów". +RUBRIC_TMPLS_FROM = "Stworzyć kopię podstawowego szablonu" +RUBRIC_TMPLS_INNAME = "Wprowadź nazwę dla szablonu" +RUBRIC_TEMPL_REPORT = "Odedytowano dodatkowy szablon rubryki" +RUBRIC_TMPLS_LOG_DEL = "Usunięto dodatkowy szablon rubryki" diff --git a/admin/lang/pl/scripts.js b/admin/lang/pl/scripts.js new file mode 100644 index 0000000..e4b7ee2 --- /dev/null +++ b/admin/lang/pl/scripts.js @@ -0,0 +1,64 @@ +// Język polski 02,2017 duncan + +var logoutTitle = "Wyjdz z Panelu sterowania"; +var logoutConfirm = "Czy na pewno chcesz zakończyć?"; +var clearCacheTitle = "Opróżnij pamięć podręczną"; +var clearCacheConfirm = "Czy na pewno chcesz opróżnić pamięć podręczną?"; +var clearCacheSessTitle = "Czyszczenie pamięci podręcznej i sesji"; +var clearCacheSessConfirm = "Czy na pewno chcesz wyczyścić pamięć podręczną i sesji?"; +var clearThumbTitle = "Usuń miniatury"; +var clearThumbConfirm = "Czy na pewno chcesz usunąć wszystkie miniaturki obrazków
z katalogu zapisywania plików (UPLOAD_DIR)?"; +var clearRevTitle = "Usuń rewizji dokumentów"; +var clearRevConfirm = "Czy na pewno chcesz usunąć wszystkie rewizje dokumentów?"; +var clearCountTitle = "Wyzerować codzienny licznik dokumentów"; +var clearCountConfirm = "Czy na pewno chcesz wyzerować codzienny licznik dokumentów?"; +var cacheShowTitle = "Pokaż rozmiar pamięci podręcznej"; +var cacheShowConfirm = "Czy na pewno chcesz sprawdzić rozmiar pamięci podręcznej
może zająć trochę czasu."; +var ajaxErrorStatus = "Brak połączenia
Sprawdź połączenie."; +var ajaxErrorStatus404 = "Strona, której szukasz nie została odnaleziona [404]."; +var ajaxErrorStatus401 = "Żądanie nie może być spełnione
Błąd autoryzacji dla spełnienia tego żądania [401]"; +var ajaxErrorStatus500 = "Wystąpił błąd wewnętrzny
Spróbuj ponownie później [500]"; +var ajaxErrorStatusJSON = "Nieprawidłowa odpowiedź serwera
Dane nie są w formacie JSON."; +var ajaxErrorStatusTimeOut = "Limit czasu zapytania."; +var ajaxErrorStatusAbort = "Żądanie Ajax przerwane."; +var ajaxErrorStatusMess = "Błąd:
"; +var delCascadTitle = "Usuń obrazek"; +var delCascadConfirm = "Czy na pewno chcesz usunąć?"; +var saveMessageOk = "Dane zapisane"; + +//===== Date & Time Pickers =====// +$.datepicker.regional['pl'] = { + closeText: 'Zamknij', + prevText: '', + currentText: 'Dzisiaj', + monthNames: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', + 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień' + ], + monthNamesShort: ['Sty', 'Lut', 'Mar', 'Kvi', 'Maj', 'Sze', + 'Lip', 'Sie', 'Wrs', 'Paź', 'Lis', 'Gru' + ], + dayNames: ['niedziela', 'poniedziałek', 'wtorek', 'środa', 'czwartek', 'piątek', 'sobota'], + dayNamesShort: ['niedz', 'pon', 'wt', 'śr', 'czw', 'piąt', 'sob'], + dayNamesMin: ['Ni', 'Pn', 'Wt', 'Sr', 'Cz', 'Pt', 'So'], + weekHeader: 'Nie', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: '' +}; +$.datepicker.setDefaults($.datepicker.regional['pl']); + +$.timepicker.regional['pl'] = { + timeOnlyTitle: 'Wybierz czas', + timeText: 'Czas', + hourText: 'Godziny', + minuteText: 'Minuty', + secondText: 'Sekundy', + millisecText: 'Milisekundy', + currentText: 'Teraz', + closeText: 'Zamknij', + ampm: false +}; +$.timepicker.setDefaults($.timepicker.regional['pl']); \ No newline at end of file diff --git a/admin/lang/pl/settings.txt b/admin/lang/pl/settings.txt new file mode 100644 index 0000000..7d72581 --- /dev/null +++ b/admin/lang/pl/settings.txt @@ -0,0 +1,130 @@ +# Język polski 02,2017 duncan + +[settings] +SETTINGS_COUNTRIES = "Zarządzanie krajami" +SETTINGS_COUNTRIES_ALL = "Lista krajów" +SETTINGS_COUNTRY_TIP = "Proszę wybrać kraje, które będą dostępne do wyboru przy rejestracji nowych użytkowników w systemie. Pamiętaj, że obrana lista krajów może być wykorzystywana przez inne moduły w systemie." +SETTINGS_ACTIVE = "Aktywna?" +SETTINGS_COUNTRY_NAME = "Nazwa kraju" +SETTINGS_IN_EC = "Odnosi się do UE?" +SETTINGS_YES = "Tak" +SETTINGS_NO = "Nie" +SETTINGS_BUTTON_SAVE = "Zapisz zmiany" +SETTINGS_BUTTON_SAVE_AJAX = "Zastosuj (CTRL + S)" +SETTINGS_OR = "lub" +SETTINGS_MAIN_TITLE = "Zarządzanie ustawieniami ogólnymi systemu" +SETTINGS_CASE_TITLE = "Ustawienia zaawansowane" +SETTINGS_MAIN = "Ogólne ustawienia systemowe" +Settings_saved = "Ustawienia systemowe pomyślnie zapisane" +SETTINGS_SAVED_ERR = "Nie można zapisać ustawień.
Spróbuj ponownie." +SETTINGS_SAVE_INFO = "Tutaj można edytować globalne parametry systemu. Należy być maksymalnie ostrożnym i pamiętać, że nieprawidłowe ustawienia mogą sprawić, że system nie będzie działać" +SETTINGS_SAVE_CONFIRM = "Czy na pewno chcesz zapisać ustawienia systemowe?" +SETTINGS_SITE_NAME = "Nazwa strony internetowej" +SETTINGS_SITE_COUNTRY = "Kraj strony internetowej" +SETTINGS_EMAIL_SENDER = "E-mail nadawcy" +SETTINGS_EMAIL_NAME = "Imię nadawcy E-mail:" +SETTINGS_MAIL_TRANSPORT = "Metoda wysyłania poczty" +SETTINGS_MAIL = "poczta" +SETTINGS_SENDMAIL = "wyśij mail" +SETTINGS_SMTP = "SMTP" +SETTINGS_SMTP_SERVER = "Serwer SMTP" +SETTINGS_MAIL_PORT = "Port SMTP:" +SETTINGS_SMTP_NAME = "Użytkownik" +SETTINGS_SMTP_PASS = "Hasło" +SETTINGS_SMTP_ENCRYPT = "Szyfrowanie" +SETTINGS_SMTP_NOENCRYPT = "Nie" +SETTINGS_MAIL_PATH = "Ścieżki do foldera sendmail:" +SETTINGS_SYMBOL_BREAK = "Wymuszone przeniesienie po (znaków):" +SETTINGS_SYMBOL_BREAK_INFO = "Nie więcej niż 1000 zgodnie z RFC 2822" +SETTINGS_SYMBOLS = "symboli" +SETTINGS_TEXT_EMAIL = "Wiadomość do użytkownika po utworzeniu konta, gdzie" +SETTINGS_TEXT_INFO = "%NAME% - Imię użytkownika />
% HOST% - odnośnik do strony internetowej
% HASŁO% - Hasło
% EMAIL% - E-mail użytkownika
%EMAILSIGNATURE% - Podpis wiadomośći" +SETTINGS_EMAIL_FOOTER = "Tekst podpisu" +SETTINGS_ERROR_PAGE = "Strona z błędem HTTP Page 404: Nie znaleziono strony" +SETTINGS_PAGE_DEFAULT = "(domyślnie ID: 2)" +SETTINGS_TEXT_PERM = "Tekst wiadomości, jeśli użytkownik nie ma praw:" +SETTINGS_HIDDEN_TEXT = "Tekst wiadomości bez praw dostępu do informacji ukrytej znacznikiem [tag: hide: x, x] ... [/ tag: hide]" +SETTINGS_NAVI_BOX = "Kontener nawigacji stronicowanej:
Przykład: & lt; ul & gt; % s & lt; / ul & gt; " +SETTINGS_LINK_BOX = "Kontener dla elementów nawigacji stronicowanej:
Przykład: & lt; li & gt; % s & lt; / li & gt; " +SETTINGS_TOTAL_BOX = "Kontener dla tekstu przed numerami stron:
Przykład: & lt; span & gt; % s & lt; / span & gt; " +SETTINGS_ACTIVE_LINK_BOX = "Kontener dla aktywnego elementu:
Przykład: & lt; span class ="aktywny"& gt;% s & lt; / span & gt; " +SETTINGS_PAGE_SEPAR = "Kontener dla metki obecności stron:
Przykład: & lt; li & gt; % s & lt; / li & gt; " +SETTINGS_PAGE_BEFORE = "Tekst przed numerami stron:
Przykład: Strona%d od %d" +SETTINGS_PAGE_START = "Tekst odnośnika " Pierwsza& quot;:" +SETTINGS_PAGE_END = " Tekst odnośnika "Ostatnia":" +SETTINGS_PAGE_SEPARATOR = "Tekst metki codo obecnośći stron, z wyjątkiem widocznych" +SETTINGS_PAGE_NEXT = "Tekst odnośnika " następna & quot;:" +SETTINGS_PAGE_PREV = "Tekst odnośnika & quot; poprzednia & quot;:" +SETTINGS_MAIN_BREADCRUMBS = "Ustawienia wyjścia "nawigacji okruszkowej"" +SETTINGS_BREAD_BOX = "Kontener "nawigacji okruszkowej":" +SETTINGS_BREAD_SEPPARATOR = "Przegroda między linkami" +SETTINGS_BREAD_BOX_LINK = "Kontener dla linków" +SETTINGS_BREAD_BOX_LASTLINK = "Pokaż ostatni element" +SETTINGS_BREAD_SELF_BOX = "Kontener dla ostatniego elementu" +SETTINGS_DATE_FORMAT = "Format daty" +SETTINGS_TIME_FORMAT = "Format daty i czasu" +SETTINGS_CLEAR_CACHE = "Wyczyść pamięć podręczną" +SETTINGS_USE_DOCTIME = "Użyj daty publikacji dokumentów" +SETTINGS_INFO = "Dodatkowo" +SETTINGS_MAIN_SETTINGS = "Ogólne ustawienia systemowe" +SETTINGS_MAIN_MAIL = "Ustawienia poczty" +SETTINGS_MAIN_PAGENAVI = "Ustawienia wyjścia nawigacji stronicowania" +SETTINGS_NAME = "Parametr" +SETTINGS_VALUE = "Znaczenie" +SETTINGS_EDITOR_CKEDITOR = "CKEditor" +SETTINGS_ERROR = "Błąd" +SETTINGS_SUCCESS = "Gotowe" +SETTINGS_SAVE_DOP = "Zmieniono ustawienia dodatkowe systemu" +SETTINGS_SAVE_MAIN = "Zmieniono ustawienia ogólne systemu" +SETTINGS_SAVE_COUNTRY = "Zmieniono ustawienia krajów" +SETTINGS_LANG_EDIT = "Zarządzanie językami" +SETTINGS_LANG_TITLE = " Uwaga! Ustawienia języków powinne odbywać się wyraźnie przed wypełnieniem strony internetowej!" +SETTINGS_LANG_AEDIT = "Edycja" +SETTINGS_LANG_AON = "Włącz" +SETTINGS_LANG_AOFF = "Wyłącz" +SETTINGS_LANG_ADEFAULT = "Ustaw jako domyślne" +SETTINGS_LANG_ADEFAULT_HINT = "" +SETTINGS_LANG_ID = "ID" +SETTINGS_LANG_FLAG = "Proporzec" +SETTINGS_LANG_SYSTEM = "Systemowe" +SETTINGS_LANG_PREFIX = "Przedrostek" +SETTINGS_LANG_NAME = "Nazwa" +SETTINGS_LANG_DEFAULT = "Domyślny" +SETTINGS_LANG_ACTION = "Działania" +SETTINGS_LANG_ADD = "Dodaj język" +SETTINGS_LANG_SAVE = "Zapisz zmiany" +SETTINGS_REV_DELETED = "Przeglądów dokumentów usunięte pomyślnie" +SETTINGS_REV_DELETED_ERR = "Nie można usunąć przeglądu dokumentów.
Spróbuj ponownie." +SETTINGS_REV_UPDATE = "Usunięto przegląd dokumentów" +SETTINGS_COUNT_DELETED = "Licznik dokumentów na dniuwki
pomyślnie zresetowany." +SETTINGS_COUNT_DELETED_ERR = "Nie można wyczyścić licznik dokumentów />
na dniuwki.
Spróbuj ponownie." +SETTINGS_COUNT_UPDATE = "Wyczyszczono licznik dokumentów na dniuwki" +SETTINGS_CACHE_LIFETIME = "Uwaga!!! Włączono dodanie do pamięci podręcznej wniosku do ustawień systemowych. Zmiany te stają się skuteczne dopiero po upływie czasu żywotności pamięci podręcznej lub wyłączenia buforowania" + + + +// v3.2 +SETTINGS_PAGINATION = "Налаштування пагінації" +PAGINATION_ADD = "Створити шаблон пагінації" +PAGINATION_NAME = "Найменування" +PAGINATION_ACTIONS = "Дії" +PAGINATION_EDIT_HINT = "Редагувати" +PAGINATION_DELETE_HINT = "Видалити пагінацію" +PAGINATION_DEL_HINT = "Ви впевнені, що бажаєте видалити цей шаблон пагінації?" +PAGINATION_SAVED = "Шаблон пагінації успішно збережено" +PAGINATION_SAVED_ERR = "Не вдалося зберегти шаблон пагінації.
Спробуйте ще раз." +PAGINATION_ERROR = "Помилка" +PAGINATION_SUCCESS = "Виконано" + +pagination_name = "Найменування" +pagination_navigation_box = "Контейнер посторінкової навігації
Приклад: <ul class="pagination pagination-sm">%s</ul>" +pagination_link_box = "Контейнер для елемента
Приклад: <li>%s</li>" +pagination_active_link_box = "Контейнер для активного елемента
Приклад: <li class="active">%s</li>" +pagination_link_template = "Шаблон посилання елемента
[link] - посилання на сторінку
[page] - Номер сторінки для посилання
[name] - Номер сторінки
" +pagination_link_active_template = "Шаблон активного посилання елемента
[link] - посилання на сторінку
[page] - Номер сторінки для посилання
[name] - Номер сторінки
" +pagination_separator_box = "Контейнер для мітки про наявність сторінок
Приклад: <li>%s</li>" +pagination_separator_label = "Текст для мітки про наявність сторінок" +pagination_start_label = "Текст посилання “Перша”" +pagination_end_label = "Текст посилання “Остання”" +pagination_next_label = "Текст посилання “Наступна”" +pagination_prev_label = "Текст посилання “Попередня”" \ No newline at end of file diff --git a/admin/lang/pl/sysblocks.txt b/admin/lang/pl/sysblocks.txt new file mode 100644 index 0000000..6f103cc --- /dev/null +++ b/admin/lang/pl/sysblocks.txt @@ -0,0 +1,71 @@ +# Język polski 02,2017 duncan + +SYSBLOCK_HEAD = "Bloki systemowe" +SYSBLOCK_EDIT = "Kierowanie blokami systemowymi" +SYSBLOCK_EDIT_TIP = "Ta sekcja zawiera wszystkie bloki systemowe." +SYSBLOCK_ID = "id" +SYSBLOCK_NAME = "Nazwa bloku systemowego" +SYSBLOCK_HTML = "Kod bloku systemowego" +SYSBLOCK_TAGS = "Znacznik" +Tagi SYSBLOCK_TAGS_2 = "Znaczniki HTML" +SYSBLOCK_EXTERNAL = "Zezwólić zwracanie zewnętrzne za linkiem" +SYSBLOCK_EXTERNAL_H = "Zwracanie zewnętrzne za linkiem" +SYSBLOCK_EXTERNAL_GO = "Przejść" +SYSBLOCK_AJAX = "Zezwolić wykonywanie wyłącznie przez Ajax" +SYSBLOCK_AJAX_H = "wykonywane wyłącznie przez Ajax" +SYSBLOCK_VISUAL = "wizualny edytor" +SYSBLOCK_VISUAL_H = "wizualny edytor" +SYSBLOCK_MEDIAPATH = "Znacznik systemowy, drogi do folderu designu" +SYSBLOCK_BREADCRUMB = "Znacznik systemowy nawigacji okruszkowej" +SYSBLOCK_DOCID_INFO = "Znacznik systemowy, identyfiktor dokumentu" +SYSBLOCK_PATH = "Droga korzenna instalacji" +SYSBLOCK_HOME = "Link do strony głównej strony internetowej" +SYSBLOCK_AUTHOR = "Author" +SYSBLOCK_DATE = "Data stworzenia" +SYSBLOCK_TAG = "Znacznik systemowy" +SYSBLOCK_ACTIONS = "Działania" +SYSBLOCK_NO_ITEMS = " Wiadomość:
Obecnie nia ma zapisanych bloków systemowych." +SYSBLOCK_BUTTON_SAVE = "Zapisz zmiany" +SYSBLOCK_BUTTON_ADD = "Dodaj bloku systemowego" +SYSBLOCK_BUTTON_COPY = "Kopiuj" +SYSBLOCK_INSERT_H = "Dodawanie bloku systemowego" +SYSBLOCK_EDIT_H = "Edytuj bloku systemowego" +SYSBLOCK_INNAME = "Wprowadź nazwę bloku systemowego" +SYSBLOCK_ENTER_NAME = "Proszę podać bloku systemowego" +SYSBLOCK_INSERT = "Tutaj można dodać lub zmienić wybraną blok systemowy" +SYSBLOCK_LINK = "Blok systemowy dostępny jest pod adresem:" +SYSBLOCK_SAVE = "Dodaj" +SYSBLOCK_SAVEDIT = "Zapisz zmiany" +SYSBLOCK_SAVE_NEXT = "Dodać i kontynuować edycję" +SYSBLOCK_SAVEDIT_NEXT = "Zastosuj (CTRL + S)" +SYSBLOCK_INTEXT = "Blok systemowy" +SYSBLOCK_ADD = "Dodaj nowy blok systemowy" +SYSBLOCK_ADD_BUTTON = "Dodaj" +SYSBLOCK_EDIT_HINT = "Edytuj blok systemowy" +SYSBLOCK_DELETE_HINT = "Usunąć blok systemowy" +SYSBLOCK_DEL_HINT = "Czy na pewno chcesz usunąć blok systemowy?" +SYSBLOCK_LIST_LINK = "Lista bloków systemowych" +SYSBLOCK_FILE = "Plik szablonu" +SYSBLOCK_SAVED = "Blok systemowy pomyślnie sapisany." +SYSBLOCK_COPY_TITLE = "Kopiowanie bloku systemowego" +SYSBLOCK_COPY = "Kopiuj blok systemowy" +SYSBLOCK_COPY_TIP = "Proszę podać nazwę bloku systemowego" +SYSBLOCK_COPY_TIP2 = "Proszę podać nazwę bloku systemowego, który jest kopiowany" +SYSBLOCK_EXIST = "Niestety, ale blok systemowy o tej samej nazwie już istnieje" +SYSBLOCK_SQLUPDATE = "Zmieniono blok systemowy" +SYSBLOCK_SQLNEW = "Stworzono nowy blok systemowy" +SYSBLOCK_SQLDEL = "Usunięto blok systemowy" +SYSBLOCK_OR = "& nbsp; lub & nbsp;" +SYSBLOCK_SAVED = "Blok systemowy pomyślnie sapisany" +SYSBLOCK_SAVED_ERR = "Nie można zapisać blok systemowy.
Spróbuj ponownie." +SYSBLOCK_ERROR = "Błąd" +SYSBLOCK_SUCCESS = "Gotowe" + + +// v 3.2 +SYSBLOCK_DESCRIPTION = "Короткий опис" +SYSBLOCK_ALIAS = "Аліас" +SYSBLOCK_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:sysblock:alias] замість [tag:sysblock:id]. Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах цих блоків" +SYSBLOCK_ACCEPT = "Цей аліас можна використовувати" +SYSBLOCK_ER_SYN = "Неправильний аліас!
Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +SYSBLOCK_ER_EXISTS = "Неправильний аліас!
Такий аліас уже прив’язаний до іншого системного блока" diff --git a/admin/lang/pl/templates.txt b/admin/lang/pl/templates.txt new file mode 100644 index 0000000..1a3e47f --- /dev/null +++ b/admin/lang/pl/templates.txt @@ -0,0 +1,108 @@ +# Język polski 02,2017 duncan + +TEMPLATES_SUB_TITLE = "Zarządzanie szablonami" +TEMPLATES_TIP1 = "Tutaj znajduje się lista wszystkich szablonów używanych w systemie. Można usuwać, edytować lub skopiować szablon do tworzenia na jego podstawie nowy". +TEMPLATES_ID = "ID" +TEMPLATES_NAME = "Nazwa szablonu" +TEMPLATES_NAME2 = "Nazwa szablonu" +TEMPLATES_NAME3 = "Wprowadź nazwę szablonu" +TEMPLATES_AUTHOR = "Author" +TEMPLATES_DATE = "Utworzony" +TEMPLATES_ACTION = "Działania" +TEMPLATES_DATE_FORMAT = "%d.%m.%y r." +TEMPLATES_DATE_FORMAT2 = "%H:%M" +TEMPLATES_IN = "w" +TEMPLATES_EDIT = "Edytuj szablon" +TEMPLATES_NO_CHANGE = "Przepraszamy, ale nie masz praw do edycji szablonu" +TEMPLATES_DELETE = "Usuń szablon" +TEMPLATES_DELETE_CONF = "Czy na pewno chcesz usunąć ten szablon?" +TEMPLATES_NO_DELETE2 = "Przepraszamy, ale nie można usunąć ten szablon, który jest wykorzystywany przez rubrykik lub moduły" +TEMPLATES_NO_DELETE3 = "Przepraszamy, ale nie masz praw do usunięcia szablonu" +TEMPLATES_COPY = "Kopiuj szablon" +TEMPLATES_NO_COPY = "Przepraszamy, ale nie masz praw do kopiowania szablonu" +TEMPLATES_LEGEND = "Znaczenie piktogramów" +TEMPLATES_COPY_TITLE = "Kopiuj szablon" +TEMPLATES_TIP2 = "Proszę podać nazwę dla kopiowanego szablonu" +TEMPLATES_TIP3 = "Proszę podać nazwę dla szablonu" +TEMPLATES_BUTTON_COPY = "Kopiuj" +TEMPLATES_ZNACZNIK_INSERT = "Kliknij na nazwę znacznika systemowego, aby dodać go w pole szablonu" +TEMPLATES_TITLE_NEW = "Tworzenie nowego szablonu" +TEMPLATES_TITLE_EDIT = "Edytuj szablon" +TEMPLATES_WARNING1 = "Proszę być ostrożnym podczas edycji szablonu i pamiętać, że błędnie podany kod może zniszczyć zewnętrzną część strony internetowej" +TEMPLATES_WARNING2 = "Tutaj można utworzyć nowy szablon ręcznie i przesłać gotową strukturę szablonu z istniejącego pliku. Pamiętaj, że pliki z gotowej struktury powinny być umieszczone w katalogu /inc/data/prefabs/templates/" +TEMPLATES_HTML = "HTML kod szablonu" +TEMPLATES_USE_PHP = "Przepraszamy, ale nie masz praw do edycji szablonu, ponieważ używa on kodu PHP" +TEMPLATES_BUTTON_SAVE = "Zapisz zmiany" +TEMPLATES_BUTTON_SAVE_NEXT = "Zastosuj (CTRL + S)" +TEMPLATES_FILE_SAVED = "Plik zapisany pomyślnie" +TEMPLATES_BUTTON_ADD = "Dodaj szablon" +TEMPLATES_BUTTON_ADD_NEXT = "Dodać i kontynuować edycję" +TEMPLATES_BUTTON_LOAD = "Pobierz" +TEMPLATES_LOAD_INFO = "Wybierz z listy plik z gotową strukturą szablonu" +TEMPLATES_EXIST = "Niestety, ale szablon o tej nazwie już istnieje" +TEMPLATES_NO_NAME = "Proszę podać nazwę szablonu" +TEMPLATES_ALL = "Lista szablonów" +TEMPLATES_OR = "  lub  " +TEMPLATES_FILE_NAME = "Nazwa pliku" +TEMPLATES_CSS_FILES = "Lista plików css" +TEMPLATES_JS_FILES = "Lista plików js" +TEMPLATES_FILES = "Menedżer plików" +TEMPLATES_EDIT_FILE = "Edycja pliku" +TEMPLATES_DEL_FILE = "Usuń plik" +TEMPLATES_ZNACZNIKS = "Znacznik" +TEMPLATES_ZNACZNIK_DESC = "Opis znacznika" +TEMPLATES_THEME_FOLDER = "Nazwa szablonu (nazwa folderu z plikami dla tego szablonu)" +TEMPLATES_FOLDER = "Folder" +TEMPLATES_PAGENAME = "Nazwa strony internetowej" +TEMPLATES_FILENAME = "Nazwa pliku" +TEMPLATES_TITLE = "Tytuł strony" +TEMPLATES_KEYWORDS = "Słowa kluczowe (Meta - słowa kluczowe)" +TEMPLATES_DESCRIPTION = "Opis strony (Meta - Opis)" +TEMPLATES_INDEXFOLLOW = "Typ indeksowania" +TEMPLATES_CANONICAL = "Strona kanoniczna –to zalecana kopia z zestawu stron o bardzo podobnej treści." +TEMPLATES_PATH = "Ścieżka instalacji root" +TEMPLATES_MEDIAPATH = "Ścieżki do folderu z szablonem (Przykład: [znacznik:mediapath]images/logo.gif)" +TEMPLATES_CSS = "Kompresuje kilka css-plików w jednym. Zwraca ścieżkę.
FFF - nazwy plików oddzielone przecinkami
P - ścieżki do folderu z plikami, nie jest wymagane. Domyślne - [znacznik: mediapath] css / 
 Przykład: href ="[znacznik: CSS: reset.css, style.css]"" +TEMPLATES_JS = "Kompresuje kilka js-plików w jeden. Zwraca ścieżkę.
FFF - nazwy plików oddzielone przecinkami
P - ścieżki do folderu z plikami, nie jest wymagane. Domyślne - [znacznik:mediapath]js/
 Przykład: href ="[znacznik: JS: common.js, main.js] & quot;" +TEMPLATES_MEDIAPATH = "Ścieżki do folderu z szablonem (Przykład: [znacznik: mediapath]images/logo.gif)" +TEMPLATES_MAINCONTENT = "Znacznik dla głównej treści" +TEMPLATES_QUICKFINDER = "Menu kontekstowe szybkiej nawigacji" +TEMPLATES_DOCUMENT = "Link do bieżącego dokumentu" +TEMPLATES_ALIAS = "Link do bieżącego dokumentu (Alias)" +TEMPLATES_SYSBLOCK = "Znacznik systemowy bloków systemowych" +TEMPLATES_TEASER = " Znacznik systemowe teaserńw" +TEMPLATES_PRINTLINK = "Link do " Wersja od druku"" +TEMPLATES_HOME = "Link do strony głównej strony internetowej" +TEMPLATES_BREADCRUMB = "Znacznik systemowy nawigacji okruszkowej" +TEMPLATES_VERSION = "Wyświetlanie informacji o ochronie danych" +TEMPLATES_NAVIGATION = "Menu nawigacji (xxx - numer menu)" +TEMPLATES_IF_PRINT = "Zawartość będzie wyświetlana w wersji drukowanej". +TEMPLATES_DONOT_PRINT = " Zawartość nie pojawi się w wersji drukowanej" +TEMPLATES_RUBHEADER = "Ustawiany jest w szablonie rubryki
(Szablon projektu HEADER)" +TEMPLATES_NO_ITEMS = "Obecnie nie ma żadnych plików" +TEMPLATES_CACHE_SUCCESS = "Pamięć podręczna pomyślnie oczyszczona." +TEMPLATES_CACHE_SUCCESS_LOG = "Pamięć podręczna oczyszczona " +TEMPLATES_CSS_TITLE = "Proszę być ostrożnym podczas edycji plików i pamiętać, że błędnie podany kod może zniszczyć zewnętrzną część strony internetowej" +TEMPLATES_CSS_EDITOR = "Edytor plików CSS" +TEMPLATES_JS_TITLE = "Proszę być ostrożnym podczas edycji plików i pamiętać, że błędnie podany kod może zniszczyć zewnętrzną część strony internetowej" +TEMPLATES_JS_EDITOR = "Edytor plików CSS" +TEMPLATES_REPORT_NEW = "Utworzony szablon" +TEMPLATES_REPORT_CHANGE = "Zmieniono szablon" +TEMPLATES_REPORT_PHP = "Próba użycia kodu PHP w szablonie" +TEMPLATES_REPORT_PHP_CSS = "Próba użycia kodu PHP w pliku css" +TEMPLATES_REPORT_PHP_JS = "Próba użycia kodu PHP w pliku js" +TEMPLATES_REPORT_PHP_ERR = "Nie używaj kodu PHP" +TEMPLATES_REPORT_ID_ERR = "Próba oczyszczenia głównego szablonu" +TEMPLATES_REPORT_DELETE = "Usunięto szablon" +TEMPLATES_REPORT_FILE = "Edytowany plik" +TEMPLATES_REPORT_COPY = "Utworzono kopię szablonu" +TEMPLATES_REPORT_DEL_OK = "Plik został pomyślnie usunięty" +TEMPLATES_REPORT_DEL_ER = "Nie można usunąć pliku" +TEMPLATES_REPORT_ERROR_TEXT = "Kod HTML szablonu jest pusty " +TEMPLATES_REPORT_ERROR_TITLE = "Nie zapisana – nazwa szablonu" +TEMPLATES_SAVED = "Szablon pomyślnie zapisany" +TEMPLATES_SAVED_FILE = "Plik pomyślnie zapisany" +TEMPLATES_SAVED_ERR = "Nie można zapisać szablonu.
Spróbuj ponownie." +TEMPLATES_SAVED_ERR_FILE = "Nie można zapisać pliku.
Spróbuj ponownie." +TEMPLATES_ERROR = "Błąd" +TEMPLATES_SUCCESS = "Gotowe" diff --git a/admin/lang/pl/user.txt b/admin/lang/pl/user.txt new file mode 100644 index 0000000..603d606 --- /dev/null +++ b/admin/lang/pl/user.txt @@ -0,0 +1,92 @@ +# Język polski 02,2017 duncan + +[user] +USER_SUB_TITLE = "Zarządzanie użytkownikami" +USER_TIP1 = "Tutaj znajduje się lista wszystkich użytkowników w systemie. Można edytować ustawienia użytkownika, usunąć użytkownika i przenieść użytkownika do innej grupy." +USER_ID = "ID" +USER_NAME = "Imię i nazwisko użytkownika" +USER_NAME2 = "Imię użytkownika " +USER_GROUP = "Znajduje się w grupie" +USER_STATUS_WAIT = "Oczekuje aktywacji" +USER_LAST_VISIT = "Ostatnie logowanie" +USER_REGISTER_DATE = "Data rejestracji" +USER_ACTION = "Działania" +USER_DELETE = "Usuń użytkownika" +USER_EDIT = "Edycja użytkownika" +USER_DATE_FORMAT = "%d.%m.% Y% H:% M" +USER_NO_CHANGE = "Przepraszamy, ale nie masz praw do edycji użytkowników" +USER_DELETE_CONFIRM = "Czy na pewno chcesz usunąć tego użytkownika?" +USER_LEGEND = "Znaczenie piktogramów" +USER_BUTTON_SAVE = "Zapisz zmiany" +USER_ORDERS = "Historia zamówień" +USER_DOWNLOADS = " Historia zamówień PO" +USER_MARK_DELETE = "Zaznacz aby usunąć" +USER_NEW_TITLE = "Utwórz nowego użytkownika" +USER_NEW_TIP = "Aby dodać nowego użytkownika, należy wypełnić pola odpowiednimi informacjami. Należy uważać przy wyborze grupy dla tego użytkownika. Nieprawidłowa grupa może ograniczyć dostęp użytkownika do odpowiednich sekcji strony internetowej lub odwrotnie, umożliwić dostęp do sekcji zamkniętych." +USER_EDIT_TITLE = "Edycja użytkownika" +USER_EDIT_TIP = "Tutaj można edytować ustawienia użytkownika, a także zmienić hasło i grupę użytkownika ". +USER_ERRORS = "Błąd" +USER_FIRSTNAME = "Imię" +USER_FIRSTNAME_ADD = "Wprowadź imię użytkownika" +USER_LASTNAME = "Nazwisko" +USER_EMAIL ="Adres e-mail:" +USER_NICK = "Przydomek na forum" +USER_SIGNATURE = "Podpis na forum" +USER_AVATAR = "Avatar" +USER_TAX = "Opodatkować" +USER_COMPANY = "Spółka" +USER_HOUSE_STREET = "Ulica / Numer domu" +USER_ZIP_CODE = "Kod pocztowy" +USER_CITY = "Miasto zamieszkania" +User_password = "Hasło" +USER_PASSWORD_CHANGE = "Edycja" +USER_PASSWORD_SHOW = "Pokaż hasło" +USER_YES = "Tak" +USER_NO = "Nie" +USER_COUNTRY = "Kraj" +USER_PHONE = "Telefon" +USER_FAX = "Fax" +USER_BIRTHDAY = "Data urodzenia" +USER_BIRTHDAY_FORMAT = "W formacie (DD.MM.HHHH)" +USER_NOTICE = "Dodatkowe informacje" +USER_MAIN_GROUP = "Grupa główna" +USER_SECOND_GROUP = "Grupa dodatkowa" +USER_SECOND_INFO = "Wybierz kilka grup" +USER_STATUS = "Status użytkownika" +USER_ACTIVE = "Aktywny" +USER_INACTIVE = "Nieaktywny" +USER_BUTTON_ADD = "Dodaj użytkownika" +USER_SEND_INFO = "Poinformuj użytkownika przez mail’a" +USER_MESSAGE_SUBJECT = "Temat wiadomośći" +USER_MESSAGE_TEXT = "Tekst wiadomośći" +USER_EMAIL_EXIST = "Przepraszamy, ale podany adres e-mail jest już używany w systemie." +USER_ERROR_DATEFORMAT = "Data urodzenia wymieniona w nieodpowiednim formacie." +USER_PASSWORD_SHORT = "Podane hasło jest zbyt krótkie. Proszę użyć co najmniej 5 znaków." +USER_PASSWORD_ERROR = "Pole hasła zawiera nieprawidłowe znaki." +USER_NO_EMAIL = "Pole e-mail jest puste. Proszę podać adres e-mail." +USER_NO_PASSWORD = "Pole hasła jest puste. Proszę podać swoje hasło." +USER_EMAIL_ERROR = "Pole adresu e-mail zawiera nieprawidłowe znaki, sprawdź podany adres e-mail." +USER_NO_FIRSTNAME = "Pole użytkownika jest pusta. Proszę podać nazwę użytkownika." +USER_NO_USERNAME = "Pole login użytkownika jest puste. Proszę podać login użytkownika." +USER_ERROR_FIRSTNAME = "Pole imię użytkownika zawiera nieprawidłowe znaki." +USER_ERROR_USERNAME = "Pole login zawiera nieprawidłowe znaki." +USER_NO_LASTNAME = "Pole nazwisko użytkownika jest puste. Proszę podać nazwisko użytkownika" +USER_ERROR_LASTNAME = "Pole nazwisko użytkownika zawiera nieprawidłowe znaki." +USER_MAIL_BODY1 = "Witaj %USER%,% N %% N %" +USER_MAIL_BODY2 = "Twoje konto zostało aktywowane. Proszę używać hasła dostępu dla wejęćia na stronę intwrnetową %HOST%." +USER_MAIL_FOOTER = "%NN%% Z poważaniem, %HOMEPAGENAME%%%%NN%% HOST%" +USER_MAIL_SUBJECT = "Twoje konto zostało aktywowane" +USER_MAIL_PASSWORD = "Informacja o zmianię hasła" +USER_MAIL_PASSWORD2 = "Meldujemy o zresetowaniu hasła % N% N %% Nowe hasło: %NEWPASS%" +USER_NEW_ADD = "Utwórz nowe konto" +USER_ALL = "Lista użytkowników" +USER_LOGIN = "Logowanie w systemie" +SETTINGS_NAME = "Parametr" +SETTINGS_VALUE = "Znaczenie" +USER_LIST_EMPTY = "Brak użytkowników spełniających warunki wyszukiwania.
Spróbuj zmienić warunki wyszukiwania". +USER_REPORT_ADD = "Dodawanie użytkownika" +USER_REPORT_EDIT = "Edytowanie ustawień użytkownika" +USER_REPORT_DEL = "Usunieńcię użytkownika" +USER_REPORT_GROUP = "Zmieniono grupę dla użytkownika" +USER_YOUR_NOT_CHANGE = " Błąd! Przepraszamy, ale nie masz uprawnień do edytowania tego użytkownika." +USER_WARNING_TIP = " Uwaga! Bądź ostrożny podczas edycji tego użytkownika." diff --git a/admin/lang/ru/blocks.txt b/admin/lang/ru/blocks.txt new file mode 100644 index 0000000..4cebd00 --- /dev/null +++ b/admin/lang/ru/blocks.txt @@ -0,0 +1,69 @@ +BLOCK_HEAD = "Визуальные блоки" +BLOCK_EDIT = "Управление визуальными блоками" +BLOCK_EDIT_TIP = "В данном разделе предоставлены все визуальные блоки." +BLOCK_ID = "Id" +BLOCK_NAME = "Наименование визуального блока" +BLOCK_HTML = "Код визуального блока" +BLOCK_TAGS = "Тэг" +BLOCK_TAGS_2 = "HTML Tags" + + +BLOCK_VISUAL = "Визуальный редактор" +BLOCK_VISUAL_H = "Визуальный редактор" + +BLOCK_MEDIAPATH = "Системный тег, путь к папке дизайна" +BLOCK_BREADCRUMB = "Системный тег Хлебных крошек" +BLOCK_DOCID_INFO = "Системный тег, идентификатор документа" +BLOCK_PATH = "Корневой путь установки" +BLOCK_HOME = "Ссылка на главную страницу сайта" + +BLOCK_AUTHOR = "Автор" +BLOCK_DATE = "Дата создания" +BLOCK_TAG = "Системный тег" +BLOCK_ACTIONS = "Действия" +BLOCK_NO_ITEMS = "Сообщение:
В настоящий момент нет сохраненных визуальных блоков." +BLOCK_BUTTON_SAVE = "Сохранить изменения" +BLOCK_BUTTON_ADD = "Добавить визуальный блок" +BLOCK_BUTTON_COPY = "Копировать" +BLOCK_INSERT_H = "Добавление визуального блока" +BLOCK_EDIT_H = "Редактирование визуального блока" +BLOCK_INNAME = "Введите наименование визуального блока" +BLOCK_ENTER_NAME = "Пожалуйста, укажите наименование визуального блока" +BLOCK_INSERT = "Здесь вы можите добавить или изменить выбранный вами визуальный блок" + +BLOCK_SAVE = "Добавить" +BLOCK_SAVEDIT = "Сохранить изменения" +BLOCK_SAVE_NEXT = "Добавить и продолжить редактирование" +BLOCK_SAVEDIT_NEXT = "Применить (CTRL+S)" + +BLOCK_INTEXT = "Визуальный блок" +BLOCK_ADD = "Добавить новый визуальный блок" +BLOCK_ADD_BUTTON = "Добавить" +BLOCK_EDIT_HINT = "Редактировать визуальный блок" +BLOCK_DELETE_HINT = "Удалить блок" +BLOCK_DEL_HINT = "Вы уверены, что хотите удалить визуальный блок?" +BLOCK_LIST_LINK = "Список визуальных блоков" +BLOCK_FILE = "Файл шаблона" +BLOCK_SAVED = "Блок успешно сохранен." +BLOCK_COPY_TITLE = "Копирование визуального блока" +BLOCK_COPY = "Копировать визуальный блок" +BLOCK_COPY_TIP = "Пожалуйста, укажите наименование визуального блока" +BLOCK_COPY_TIP2 = "Пожалуйста, укажите наименование для копируемого визуального блока" +BLOCK_EXIST = "Извините, но визуальный блок с таким наименованием уже существует" +BLOCK_SQLUPDATE = "Изменил блок" +BLOCK_SQLNEW = "Создал новый визуальный блок" +BLOCK_SQLDEL = "Удалил визуальный блок" +BLOCK_OR = " или " + +BLOCK_SAVED = "Визуальный блок успешно сохранен" +BLOCK_SAVED_ERR = "Не удалось сохранить визуальный блок.
Попробуйте еще раз." +BLOCK_ERROR = "Ошибка" +BLOCK_SUCCESS = "Выполнено" + +// v 3.2 +BLOCK_DESCRIPTION = "Краткое описание" +BLOCK_ALIAS = "Алиас" +BLOCK_I = "Опционально. Алиас позволяет использовать легко запоминающийся тег [tag:BLOCK:alias] вместо [tag:BLOCK:id]. Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание, иметь длину не более 20 символов и быть уникальным в пределах данных блоков" +BLOCK_ACCEPT = "Этот алиас можно использовать" +BLOCK_ER_SYN = "Неверный алиас!
Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание и иметь длину не более 20 символов" +BLOCK_ER_EXISTS = "Неверный алиас!
Данный алиас уже привязан к другому визуальному блоку" \ No newline at end of file diff --git a/admin/lang/ru/dbactions.txt b/admin/lang/ru/dbactions.txt new file mode 100644 index 0000000..959a16a --- /dev/null +++ b/admin/lang/ru/dbactions.txt @@ -0,0 +1,48 @@ +DB_SUB_TITLE = "Управление базой данных" +DB_ACTION_WARNING = "Внимание!\nВсе действия по работе с базой данных Вы выполняете на свой страх и риск.\n\nПомните, что любые действия, проводимые с базой данных, могут повредить существующую информацию.\n\nВы уверены, что хотите продолжить?\n\n" +DB_ACTION_RESET = "Внимание!\nВы пытаетесь восстановить базу данных из резервной копии. Вся существующая информация будет удалена и перезаписана.\nПожалуйста, обратите внимание, что после восстановления базы данных, Вам потребуется выполнить авторизацию снова.\n\nВы уверены, что хотите продолжить?\n\n" +DB_OPTION_LIST = "Структура базы данных" +DB_BUTTON_ACTION = "Выполнить действие" +DB_OPTIMIZE_DATABASE = "Оптимизация базы данных" +DB_OPTIMIZE_INFO = "Данная возможность позволяет увеличить производительность и уменьшить размер Вашей базы данных. Рекомендуемый интервал между оптимизациями должнен быть не менее 1 раза в неделю." +DB_REPAIR_DATABASE = "Восстановление поврежденных таблиц" +DB_REPAIR_INFO = "Данная возможность позволяет выполнить попытку восстановления поврежденных таблиц в базе данных, в случае, некорректного вывода информации на страницах сайта." +DB_BACKUP_DATABASE = "Создание резервной копии" +DB_BACKUP_INFO = "Данная возможность позволяет выполнить резервную копию как всей базы данных, так и отдельных таблиц. Пожалуйста, выберите в списке слева таблицы, для которых Вы хотите выполнить резервную копию. Для выбора нескольких таблиц зажмите клавишу CTRL." +DB_RESTORE_TITLE = "Восстановление базы данных из резервной копии" +DB_RESTORE_FILE = "Восстановление базы данных из файла" +DB_BUTTON_RESTORE = "Восстановить" +DB_ACTION = "Выберите действие" +DB_TIPS = "Внимание! Все действия по работе с базой данных Вы выполняете на свой страх и риск. Помните, что любые действия, проводимые с базой данных, могут повредить существующую информацию." +DB_BACKUP_SERVER = "Сохранить резервную копию на сервере" +DB_SC = "Операция с базой данных успешно выполнена" + +DB_OPTIMIZE_DATABASE_SC = "Оптимизация базы данных успешно выполнена" +DB_REPAIR_DATABASE_SC = "Восстановление поврежденных таблиц успешно выполнено" + +DB_REPORT_DUMP = "Выполнил резервное копирование базы данных" +DB_REPORT_DUMP_RECOVER = "Выполнил восстановление базы данных из резервной копии" +DB_REPORT_DUMP_OPTIM = "Выполнил оптимизацию базы данных" +DB_REPORT_DUMP_TABLE = "Выполнил востановление таблиц базы данных" + +DB_FILE_DATA = "Дата создания" +DB_FILE_SIZE = "Размер" +DB_FILE_NAME = "Наименование файла" +DB_ACTIONS = "Дейтсвия" +DB_ACTIONS_EDIT = "Редактировать" +DB_ACTIONS_DEL = "Удалить" +DB_ACTIONS_RESTORE = "Востановить" +DB_ACTIONS_SAVE = "Сохранить на компьютер" + +DB_REPORT_DUMP_DEL_OK = "Удалил файл резервной копии базы данных" +DB_REPORT_DUMP_DEL_ER = "Не удалось удалить файл резервной копии базы данных" +DB_REPORT_DUMP_ER = "Ошибка: Импорт базы данных не выполнен, т.к. отсутсвует файл дампа или он поврежден." + +DB_ACTIONS_RESTORE_H = "Восстановить резеврную копию" +DB_ACTIONS_RESTORE_T = "Вы уверены что хотите восстановить резервную копию базы данных?" + +DB_ACTIONS_DELETE_H = "Удалить файл" +DB_ACTIONS_DELETE_T = "Вы уверены, что хотите удалить файл резервной копии базы данных?" + +DB_NO_FILES_MESS = "В настоящий момент, нет файлов резервных копий базы данных" +DB_BACKUP_FILE_NAME = "Имя файла:" \ No newline at end of file diff --git a/admin/lang/ru/docs.txt b/admin/lang/ru/docs.txt new file mode 100644 index 0000000..75ab868 --- /dev/null +++ b/admin/lang/ru/docs.txt @@ -0,0 +1,331 @@ +[docs] +DOC_SUB_TITLE = "Управление документами" +DOC_TIPS = "В данном разделе приведен список всех документов в системе. Здесь Вы можете выполнить основные операции с документами, такие как: Просмотр, Редактирование, Удаление документа, а также оставить заметку для какого-либо документа." +DOC_DATE_FORMAT = "%d.%m.%Y %H:%M" +DOC_LEGEND = "Значения пиктограмм" +DOC_LEGEND_EDIT = "Редактировать документ" +DOC_LEGEND_SHOW = "Просмотр страницы в новом окне" +DOC_LEGEND_ENABLE = "Сделать документ активным" +DOC_LEGEND_DISABLE = "Сделать документ неактивным" +DOC_LEGEND_TEMP_DELETE = "Временно удалить документ (в корзину)" +DOC_LEGEND_RESTORE = "Восстановить документ (из корзины)" +DOC_LEGEND_FINAL_DELETE = "Окончательно удалить документ" +DOC_CHOSE_RUB = "Выберите рубрику" +DOC_ID = "ID" +DOC_URL_RUB = "URL" +DOC_TITLE = "Название документа" +DOC_URL_TITLE = "Ссылка на документ" +DOC_IN_RUBRIK = "Рубрика" +DOC_IN_NEW = "Новый документ" +DOC_CREATED = "Опубликован" +DOC_EDIT = "Отредактирован" +DOC_PRINTED = "Распечатан" +DOC_CLICKS = "Просмотрен" +DOC_AUTHOR = "Автор" +DOC_ACTIONS = "Действия" +DOC_EDIT_TITLE = "Редактировать данный документ" +DOC_CHANGE_RUBRIC = "Перенести данный документ в дуругую рубрику" +DOC_CHANGE_AUTOR = "Сменить автора документа" +DOC_SHOW_TITLE = "Просмотр документа (ссылка без ЧПУ)" +DOC_SHOW2_TITLE = "Просмотр документа (ссылка c ЧПУ)" +DOC_SHOW3_TITLE = "Документ без названия" +DOC_CREATE_NOTICE_TITLE = "Оставить заметку" +DOC_REPLY_NOTICE_TITLE = "Посмотреть/ответить на заметку" +DOC_ENABLE_TITLE = "Опубликовать документ" +DOC_DISABLE_TITLE = "Снять документ с публикации" +DOC_TEMPORARY_DELETE = "Положить документ в корзину" +DOC_RESTORE_DELETE = "Восстановить документ из корзины" +DOC_FINAL_DELETE = "Удалить документ" +DOC_ICON_COMMENT = "Имеются заметки" +DOC_ICON_PUBLIC = "Документ снят с публикации" +DOC_ICON_RECYCLE = "Документ помещен в корзину" +DOC_SORT_TEXT = "Сортировать документы по:" +DOC_TEMPORARY_CONFIRM = "Вы уверены, что хотите положить в корзину данный документ?" +DOC_FINAL_CONFIRM = "Вы уверены, что хотите удалить данный документ?" +DOC_INSERT_LINK_TIP = "Для выбора нужного документа, нажмите по кнопке "Выбрать"" +DOC_BUTTON_INSERT_LINK = "Выбрать" +DOC_BUTTON_LINK_POPUP = "Выбрать в новом окне" +DOC_BUTTON_ADD_DOCUMENT = "Добавить документ" +DOC_BUTTON_ADD_DOCUMENT_NEXT = "Добавить и продолжить редактирование (Ctrl+S)" +DOC_BUTTON_EDIT_DOCUMENT = "Сохранить изменения" +DOC_BUTTON_EDIT_DOCUMENT_NEXT = "Применить (Ctrl+S)" +DOC_ADD_DOCUMENT = "Добавление нового документа" +DOC_EDIT_DOCUMENT = "Редактирование документа" +DOC_OPTIONS = "Параметры документа" +DOC_NAME = "Название документа:
(HTML <title>)" +DOC_URL = "Псевдоним документа:
(SEO alias)" +DOC_URL_LINK = "Подстановка Алиасов" +DOC_URL_INFO = "Чтобы ссылка на документ выглядела, например, так:
http://www.domain.tld/phone/samsung/
напишите в это поле: phone/samsung

Суффикс ссылки автоматически добавляется при выводе
в соответствии с настройками указанными в файле inc/config.php

В названии разрешено использовать:
a-z — латинские символы;
а-я — символы кириллицы (если разрешено);
/ — слэш;
- — знак тире;
_ — знак подчеркивания.

Название ссылки не должно содержать:
print/ или /print/ или /print;
page-XX/ или /page-XX/ или /page-XX;
apage-XX/ или /apage-XX/ или /apage-XX;
artpage-XX/ или /artpage-XX/ или /artpage-XX;
где XX - цифры" +DOC_URL_LOG = "Использовать историю алиасов, для редиректа" +DOC_URL_LOG_T = "Сохранять или нет историю алиасов документа, для последующего редиректа" +DOC_URL_LOG_RUBRIC = "Использовать настройки рубрики" +DOC_URL_LOG_USE = "Использовать всегда" +DOC_FIELD_G_UNKNOW = "Без группы" +DOC_PROPERTY = "Параметры документа" +DOC_URL_LOG_NOTUSE = "Не использовать" +DOC_QUERIES = "Доступные запросы:" +DOC_META_TITLE = "TITLE - это строка, которая будет выведена в заголовке окна браузера. Этот тег важен для поисковой оптимизации, поэтому система позволяет управлять им, как и некоторыми другими тегами." +DOC_META_KEYWORDS = "Ключевые слова:
(meta keywords)" +DOC_META_KEYWORDS_INFO = "Описывают содержание страницы, могут учитываться поисковыми системами.

Часть перечисленых ключевых слов должна присутствовать в тексте страницы." +DOC_META_DESCRIPTION = "Описание страницы:
(meta description)" +DOC_META_DESCRIPTION_INFO= "Небольшой текст, описывающий содержание страницы. Также может учитываться поисковыми системами, выводиться в качестве пояснения в результатах поиска или интернет-каталогах." +DOC_CAN_SEARCH = "Разрешить поиск по документу:
(для модуля Поиск)" +DOC_INDEX_TYPE = "Тип индексирования страницы:
(meta robots)" +DOC_INDEX_FOLLOW = "Индексировать и переходить по ссылкам" +DOC_INDEX_NOFOLLOW = "Индексировать, но не переходить по ссылкам" +DOC_NOINDEX_NOFOLLOW = "Не индексировать и не переходить по ссылкам" +DOC_SITEMAP_FREQ = "Частота обновления
sitemap.xml" +DOC_SITEMAP_FREQ_DOC = "Частота обновления страницы" +DOC_SITEMAP_ALWAYS = "Всегда" +DOC_SITEMAP_HOURLY = "Ежечасно" +DOC_SITEMAP_DAILY = "Ежедневно" +DOC_SITEMAP_WEEKLY = "Еженедельно" +DOC_SITEMAP_MONTHLY = "Ежемесячно" +DOC_SITEMAP_YEARLY = "Ежегодно" +DOC_SITEMAP_NEVER = "Никогда" +DOC_SITEMAP_PRIORITY = "Приоритет
sitemap.xml" +DOC_SITEMAP_PRIORITY_DOC = "Приоритет данной страницы относительно остальных страниц" +DOC_SITEMAP_PRIORITY_LOW = "Низший приоритет" +DOC_SITEMAP_PRIORITY_MID = "Средний приоритет" +DOC_SITEMAP_PRIORITY_HIG = "Высший приоритет" +DOC_START_PUBLICATION = "Начало публикации:" +DOC_END_PUBLICATION = "Окончание публикации:" +DOC_STATUS = "Статус документа:" +DOC_STATUS_ACTIVE = "Активный" +DOC_STATUS_INACTIVE = "Не активный" +DOC_ADD_IN_NAVIGATION = "Добавить подпункт меню:" +DOC_USE_NAVIGATION = "Связать с пунктом меню:" +DOC_USE_RUB_ALIAS = "Подстановки алиасов родительских документов, назначение родительского документа для хлебных крошек." +DOC_USE_BREADCRUMB = "Связать с документом
(можно использовать для хлебных крошек)" +DOC_USE_LANG_PACK = "Связать с документом из языковой группы" +DOC_NAVIGATION_INFO = "Для того, чтобы связать данный документ с пунктом меню, выберите из списка существующий пункт меню. Если Вы временно не хотите связывать данный документ с пунктом меню, оставьте поле пустым." +DOC_MAIN_CONTENT = "Основное содержимое документа" +DOC_MAIN_NOCONTENT = "Отсутвуют поля для документа" +DOC_AFTER_CREATE_TITLE = "Дальнейшие действия" +DOC_AFTER_CREATE_INFO = "Пожалуйста, выберите Ваше дальнейшее действие из списка ниже:" +DOC_EDIT_THIS_DOCUMENT = "Вернуться к редактированию данного документа" +DOC_INCLUDE_NAVIGATION = "Добавить созданный документ в меню навигации" +DOC_ADD_NEW_DOCUMENT = "Добавить новый документ в данную рубрику" +DOC_ADD_COPY_DOCUMENT = "Добавить копию документа в данную рубрику" +DOC_DISPLAY_NEW_WINDOW = "Просмотреть в новом окне (Ctrl+O)" +DOC_CLOSE_WINDOW = "Перейти к списку документов" +DOC_CLOSE_WINDOW_RUBRIC = "Перейти к списку документов данной рубрики" +DOC_TO_NAVI_TITLE = "Добавление документа в меню навигации" +DOC_NAVIGATION_POSITION = "Позиция в списке:" +DOC_NAVIGATION_TITLE = "Название пунтка меню:" +DOC_TARGET = "Открывать:" +DOC_TARGET_SELF = "в том же окне" +DOC_TARGET_BLANK = "в новом окне" +DOC_BUTTON_ADD_MENU = "Добавить в меню" +DOC_TOP_MENU_ITEM = "Новый пункт 1-го уровня" +DOC_NOTICE = "Заметки к документу" +DOC_NOTICE_NEW_LINK = "Добавить новую заметку" +DOC_NOTICE_AUTHOR = "Добавил: " +DOC_NOTICE_DELETE_LINK = "Удалить заметку" +DOC_ALLOW_NOTICE = "Разрешить комментарий заметок" +DOC_BUTTON_NOTICE = "Выполнить" +DOC_NOTICE_TITLE = "Заголовок:" +DOC_NOTICE_TEXT = "Заметка:" +DOC_BUTTON_ADD_NOTICE = "Добавить заметку" +DOC_SEND_NOTICE_INFO = "Для того, чтобы добавить новую заметку к документу, пожалуйста, заполните поля в форме ниже." +DOC_NEW_NOTICE_TITLE = "Добавить новую заметку" +DOC_MAIL_BODY_CHECK = "Пользователь %USER% добавил новый документ с названием '%TITLE%'.%N%Пожалуйста, проверьте данный документ перед публикацией." +DOC_MAIL_SUBJECT_CHECK = "Добавлен новый документ" +DOC_MAIL_BODY_USER = "Здравствуйте %USER%.%N%Созданный Вами документ успешно добавлен и Администратору отправлено уведомление, о проверке, После проверки документа он будет опубликован." +DOC_MAIL_SUBJECT_USER = "Ваш документ добавлен и ожидает проверки" +DOC_MAIL_BODY_NOTICE = "Пользователь %USER% добавил новую заметку к документу.%N%Авторизуйтесь в Панели управления и перейдите по ссылке ниже, чтобы посмотреть заметку:%N%%LINK%" +DOC_MAIL_SUBJECT_NOTICE = "Добавлена новая заметка к документу" +DOC_NEW_PAGE = "Добавить новую страницу" +DOC_CLOSE_HELP_WINDOW = "

" +DOC_HELP = "Помощь" +DOC_VIDEO_TYPE_HELP = "Вставка видео файла
При добавлении видео файла, Вы можете указать ширину и высоту окна для просмотра ролика. Первое значение определяет ширину окна, второе высоту.

Например:

video.avi|300|300
или
video.avi|100%|300" +DOC_FLASH_TYPE_HELP = "Вставка флэш ролика
При добавлении флэш ролика, Вы можете указать ширину и высоту окна при просмотре. Первое значение определяет ширину, второе высоту.

Например:

flash.swf|300|300
или
flash.swf|100%|300" +DOC_FILE_TYPE_HELP = "Вставка Файла
При добавлении файла, Вы можете задать имя ссылки. Для этого необходимо после названия файла указать разделительный знак | и после него ввести название ссылки.

Например:

file.zip|Скачать файл" +DOC_NO_PERMISSION = "Извините, но Вы не имеете прав для редактирования данного документа." +DOC_NO_PERMISSION_RUB = "Извините, но Вы не имеете прав для создание документа в данной рубрике." +DOC_NO_DEL_REVISION = "Извините, но Вы не имеете прав для удаления ревизии." +DOC_NO_RES_REVISION = "Извините, но Вы не имеете прав для востановления ревизии." +DOC_EDIT_RUB = "Перенести в другую рубрику" +DOC_RUBRIC = "Рубрика" +DOC_SORT_RUB = "Сортировать по рубрикам" +DOC_IMAGE = "Изображение в списке новостей" +DOC_IMAGE_MAX_W = "Максимальная ширина" +DOC_IMAGE_MAX_H = "Максимальная высота" +DOC_INTRO = "Тизер
(текст в списке новостей)" +DOC_ALIAS_CREATE = "Сформировать" +DOC_ENTER_NAME = "Пожалуйста, выберите рубрику в которую вы хотите добавить новый документ." +DOC_SORT_NAME = "Пожалуйста, выберите рубрику." +DOC_OR = " или " +DOC_NO_DOCS = "Документы, удовлетворяющие данные критерии поиска, отсутствуют." + +DOC_COPY = "Копировать документ" +DOC_COPY_DOCUMENT = "Копирование документа" +DOC_COPY_TIP = "Пожалуйста, укажите название для документа" + +DOC_ADD_NEW_LIGHT_TIP = "Для добавления нового документа, пожалйста выберите рубрику." +DOC_ADD_NEW_LIGHT_ADD = "Добавление документа" +DOC_ADD_NEW_LIGHT_BTN = "Добавить документ" + +DOC_CHANGE_TITLE = "Перенос документа в другую рубрику" +DOC_CHANGE_INFO = "Внимание! При изменении рубрики неперенесенные поля теряются!" +DOC_CHANGE_OLD_FIELD = "Поле документа" +DOC_CHANGE_NEW_FIELD = "Перенести в новое" +DOC_CHANGE_DROP_FIELD = "-- не переносить --" +DOC_CHANGE_CREATE_FIELD = "-- создать новое --" +DOC_CHANGE_BUTTON = "Изменить" + +DOC_CHANGE_AU_TITLE = "Смена автора документа" +DOC_CHANGE_AU_INFO = "Внимание! При смене автора, предыдущий автор может лишиться прав на редактирование этого документа." +DOC_CHANGE_BUTTON = "Сохранить" + +DOC_IN_MENU = "в меню" + +DOC_REVISSION = "История изменений" +DOC_REVISSION_DATA = "Дата и время изменения" +DOC_REVISSION_USER = "Автор" +DOC_REVISSION_VIEW = "Посмотреть версию" +DOC_REVISSION_RECOVER = "Востановить версию" +DOC_REVISSION_RECOVER_T = "Вы уверены, что хотите данную востановить версию?" +DOC_REVISSION_DELETE = "Удалить версию" +DOC_REVISSION_DELETE_T = "Вы уверены, что хотите удалить данную версию?" +DOC_REVISSIONS_DELETE = "Удалить все ревизии" +DOC_REVISSIONS_DELETE_T = "Вы уверены, что хотите удалить все ревизии?" +DOC_REVISSION_NO_ITEMS = "В настоящий момент нет данных" + +DOC_URL_ERROR_SYMBOL = "недопустимые символы" +DOC_URL_ERROR_START = "начинается c /" +DOC_URL_ERROR_END = "заканчивается на / (при этом суффикс URL начинается на /)" +DOC_URL_ERROR_SEGMENT = "недопустимые сегменты:" +DOC_URL_ERROR_EMTY = "нечего проверять" +DOC_URL_ERROR_DUPLICATES = "псевдоним уже используется" +DOC_URL_H_ERROR_DUPLICATES = "псевдоним уже используется в истории алиасов" +DOC_URL_CHECK_OK = "Данный URL можно использовать" +DOC_URL_CHECK_ER = "URL содержит ошибки:
" + +DOC_REQUEST_NOT_INFO = "Для данного запроса описания нет." + +DOC_REVISION_DELETE = "Удалил версию документа" +DOC_REVISION_RECOVER = "Восстановил версию документа" + +DOC_BREADCRUMB_BTN = "Выбрать" +DOC_BREADCRUMB_TITLE = "Название ссылки для хлебных крошек" +DOC_BREADCRUMB_WITH = "Связан с" + +DOC_DOCUMENT_OPEN = "Документ опубликован" +DOC_DOCUMENT_CLOSE = "Документ снят с публикации" + +DOC_DOCUMENT_DOC = "документ" +DOC_DOCUMENT_ACT = "Опубликовал" +DOC_DOCUMENT_DISACT = "Снял с публикации" + +DOC_DOCUMENT_OPEN_ERR = "Этот документ нельзя сделать неактивным!" +DOC_DOCUMENT_OPEN_PRIVE = "У вас недостаточно для этого прав!" + +DOC_ACTION_SELECT = "Действие с выбранными" +DOC_ACTION_SELECT_ACT = "Активный" +DOC_ACTION_SELECT_NACT = "Не активный" +DOC_ACTION_SELECT_TRASH = "Временно удалить" +DOC_ACTION_SELECT_OUTTRASH = "Восстановить" +DOC_ACTION_SELECT_DEL = "Удалить" +DOC_ACTION_BUTTON = "Сохранить изменения" + +DOC_CHOOSE_LANG = "Выбор языка документа" +DOC_LANG_VERSION = "Версия документа на других языках" +DOC_LINK_CHOOSE = "Выберите документ" +DOCUMENT_SAVED = "Документ успешно сохранен" + +DOC_REV_DELETED = "Ревизии документов успешно удалены" +DOC_REV_DELETED_ERR = "Не удалось удалить ревизии документов.
Попробуйте еще раз." +DOC_REV_ERROR = "Ошибка" +DOC_REV_SUCCESS = "Выполнено" +DOC_REV_UPDATE = "Удалил ревизии документов" + +DOC_ALIASES = "Управление редиректами документов" +DOC_ALIASES_LIST_NM = "Наименование документа" +DOC_ALIASES_LIST_RB = "Рубрика" +DOC_ALIASES_LIST_CH = "Изменено" +DOC_ALIASES_LIST_CR = "Кол-во" +DOC_ALIASES_LIST_AT = "Действия" +DOC_ALIASES_TITLE = "В данном разделе приведен список всех документов, у которых присутвуют внутренние редиректы.
Здесь Вы можете выполнить основные операции с документами, такие как: Просмотр, Редактирование, Удаление редиректа." +DOC_ALIASES_BREAD_RUB = "Рубрика:" +DOC_ALIASES_BREAD_DOC = "Документ:" +DOC_ALIASES_BREAD_URL = "Основной URL:" +DOC_ALIASES_DOC_LIST = "Список документов c редиректами" +DOC_ALIASES_ADD = "Добавить новый редирект" +DOC_ALIASES_ADD_VAL = "Значение редиректа" +DOC_ALIASES_LIST = "Список редиректов" +DOC_ALIASES_LIST_EMPT = "Список пуст" +DOC_ALIASES_TABL_H_URL = "Алиас редиректа" +DOC_ALIASES_TABL_H_ADD = "Добавлен" +DOC_ALIASES_TABL_H_AUT = "Автор" +DOC_ALIASES_TABL_CHECK = "Отметить данный пункт для удаления" +DOC_ALIASES_GO = "Перейти по ссылке" +DOC_ALIASES_DEL_T = "Удалить алиас" +DOC_ALIASES_DEL_C = "Вы уверены, что хотите удалить алиас?" +DOC_ALIASES_BUTT_DEL = "Удалить" +DOC_ALIASES_BUTT_CLO = "Закрыть окно" +DOC_ALIASES_BUTT_APP = "Применить" +DOC_ALIASES_BUTT_CNL = "Отменить" +DOC_ALIASES_BUTT_SAV = "Сохранить" +DOC_ALIASES_BUTT_ADD = "Добавить" +DOC_ALIASES_REP_OK = "Выполнено" +DOC_ALIASES_REP_OK_T = "Редирект успшно добавлен" +DOC_ALIASES_REP_OK_T_E = "Редирект успшно обновлен" +DOC_ALIASES_REP_ER = "Ошибка" +DOC_ALIASES_REP_ER_T = "Не удалось добавить редирект. Попробуйте еще раз." +DOC_ALIASES_REP_ER_T_E = "Не удалось обновить редирект. Попробуйте еще раз." + +DOC_RUBRIC_TMPLS = "Выбрать шаблон рубрики" +DOC_RUBRIC_TMPLS_HINT = "Вы можете задать документу, для вывода, любой шаблон из данной рубрики" + +DOC_SEARCH_FIELD = "Поле" +DOC_SEARCH_FIELD_SELECT = "Выберите поле" +DOC_SEARCH_FIELD_LIKE = "Содержит" +DOC_SEARCH_FIELD_EQ = "Равно" +DOC_SEARCH_FIELD_TEXT = "Значение" +DOC_TEMPLATE_DEFAULT = "Использовать по умолчанию" +DOC_SHOW_LANG = "Показать" + +// 3.2 +DOC_TABS_META = "Meta данные" +DOC_TABS_URL = "URL документа" +DOC_TABS_DATE = "Дата публикации" +DOC_TABS_OTHER = "Прочие параметры" + +DOC_WITHOUT_TITLE = "Документ без названия" +DOC_SAVE_ADD = "Добавил" +DOC_SAVE_EDIT = "Отредактировал" +DOC_SAVE_LOG_DOC = " документ" + +DOC_LANG = "Язык" +DOC_LANG_ID = "Язык документа:" +DOC_LANG_SELECT = "Выберите язык" + +// 3.25 +DOC_CLOSE_SEARCH_RUBRIC = "Вернуться в раздел, учитывая параметры поиска" + +// 3.26 +DOC_POSITION = "Позиция" +DOCUMENT_POSITION = "Позиция документа" +DOCUMENT_POSITION_ERR = "Не удалось сохранить позицию документа" +DOCUMENT_POSITION_ERROR = "Ошибка" +DOCUMENT_POSITION_OK = "Позиция документа успешно сохранена" +DOCUMENT_POSITION_SUCCESS = "Выполнено" + +DOC_SEARCH_PARAM = "Параметр документа" +DOC_SEARCH_PARAM_SELECT = "Выберите параметр" +DOC_SEARCH_PARAM_LIKE = "Содержит" +DOC_SEARCH_PARAM_EQ = "Равно" +DOC_SEARCH_PARAM_TEXT = "Значение" + +DOC_STATUS_SUCCESS = "Выполнено" +DOC_STATUS_ERROR = "Ошибка" + +DOC_STATUS_ON = "Документ опубликован" +DOC_STATUS_OFF = "Документ снят с публикации" + +DOC_RECYCLE_ON = "Документ восстановлен" +DOC_RECYCLE_OFF = "Документ помещен в корзину" + +DOC_REVISIONS_DEL_SUCCESS = "Успешно удалены все ревизии" +DOC_REVISIONS_DELETE = "Пользователь удалил все ревизии" \ No newline at end of file diff --git a/admin/lang/ru/groups.txt b/admin/lang/ru/groups.txt new file mode 100644 index 0000000..93b14bf --- /dev/null +++ b/admin/lang/ru/groups.txt @@ -0,0 +1,125 @@ +[groups] +UGROUP_TITLE = "Управление группами пользователей" +UGROUP_TITLE2 = "Управление группой пользователей" +UGROUP_TITLE_MENU = "Группы пользователей" +UGROUP_INFO = "В данном разделе приведен список всех групп пользователей в системе. Для каждой группы Вы можете назначить персональные права, которые разрешат или ограничат действия пользователей как в Панели управления, так и в Публичной части сайта." +UGROUP_ID = "ID" +UGROUP_NAME = "Название группы" +UGROUP_COUNT = "Пользователей в группе" +UGROUP_ACTIONS = "Действия" +UGROUP_IN_GROUP = "Просмотр списка пользователей, относящихся к данной группе" +UGROUP_EDIT = "Редактировать наименование и права группы" +UGROUP_NO_PERMISSION = "Извините, но у Вас недостаточно прав для редактирования" +UGROUP_DELETE = "Удалить данную группу" +UGROUP_USERS_IN_GROUP = "В настоящий момент Вы не можете удалить данную группу, т.к. есть пользователи состоящие в этой группе." +UGROUP_DELETE_CONFIRM = "Вы уверены, что хотите удалить данную группу?" +UGROUP_NO_DELETABLE = "Вы не можете удалить данную группу, т.к. она является системной." +UGROUP_NO_PERM_DELETE = "Извините, но у Вас недостаточно прав для удаления данной группы." +UGROUP_NEW_GROUP = "Добавить новую группу" +UGROUP_NEW_NAME = "Название группы:" +UGROUP_BUTTON_ADD = "Добавить" +UGROUP_LEGEND_LINK = "Значения пиктограмм" +UGROUP_LEGEND_EDIT = "Редактировать группу пользователей" +UGROUP_LEGEND_DELETE = "Удалить группу пользователей" +UGROUP_ENTER_NAME = "Пожалуйста, укажите название группы пользователей" +UGROUP_WARNING_TIP = "Внимание! Будьте предельно внимательны, при назначении тех или иных прав для данной группы пользователей. Помните, что разрешая доступ к некоторым разделам, Вы можете сделать систему уязвимой." +UGROUP_YOUR_NOT_CHANGE = "Ошибка! Извините, но Вы не имеете прав для редактирования данной группы пользователей." +UGROUP_NOT_EXIST = "Ошибка! Извините, но запрашиваемой Вами группы пользователей не существует." +UGROUP_NO_MODULES = "Нет установленных модулей" +UGROUP_MODULES_RIGHT = "Пожалуйста, укажите модули, к которым будет разрешен доступ для данной группы пользователей." +UGROUP_CONTROL_RIGHT = "Пожалуйста, укажите разделы Панели управления, к которым будет разрешен или ограничен доступ для данной группы пользователей." +UGROUP_BUTTON_SAVE = "Сохранить изменения" +UGROUP_BUTTON_SAVE_AJAX = "Применить (CTRL+S)" +UGROUP_SAVE_CONFIRM = "Вы уверены, что хотите сохранить права для данной группы пользователей?" +UGROUP_NAME_EDIT = "Редактировать наименование группы" +UGROUP_OR = "или" +UGROUP_SAVED = "Права для группы успешно сохранены" +UGROUP_SAVED_ERR = "Не удалось сохранить права для группы.
Попробуйте еще раз." +UGROUP_ERROR = "Ошибка" +UGROUP_SUCCESS = "Выполнено" +UGROUP_SAVE_MAIN = "Изменил права доступа для группы" + +UGROUP_REPORT_ADD = "Создал группу пользователей" +UGROUP_REPORT_DEL = "Удалил группу пользователей" + +alles = "Разрешить все права (Будьте предельно осторожны!)" +adminpanel = "Доступ к панели управления" + +gen_settings = "Доступ к управлению общими настройками системы" +gen_settings_more = "Доступ к управлению дополнительными настройками системы" +gen_settings_countries = "Доступ к управлению списку стран" +gen_settings_languages = "Доступ к управлению языками" +gen_settings_robots = "Доступ к редактированию файла robots.txt" +gen_settings_fcustom = "Доступ к редактированию файла func.custom.php" + +logs_view = "Доступ к просмотру системных сообщ" +logs_clear = "Доступ к удалению системных сообщений" + +db_actions = "Доступ к управлению базой данных (Резервное копирование, Восстановление, Оптимизация)" + +modules_view = "Доступ к списку модулей" +modules_admin = "Доступ к модулями (Настройка, Управление, Использование)" +modules_system = "Доступ к управлению модулями (Удаление, Установка)" + +navigation_view = "Доступ к списку меню навигаций" +navigation_edit = "Доступ к управлению меню навигацией (Создание, Редактирование, Удаление)" + +remark_view = "Доступ к списку заметок" +remark_edit = "Доступ к управлению заметками у документов (Создание, Редактирование, Удаление)" + +document_php = "Доступ к использованию PHP кода в документах (Будьте предельно осторожны!)" +document_view = "Доступ к списку документов (права доступа к документам зависят от настроек рубрики)" +document_revisions = "Доступ к удалению всех ревизий документов" + +rubric_view = "Доступ к просмотру списка рубрик" +rubric_edit = "Доступ к управлению рубриками (Создание, Редактирование, Удаление)" +rubric_php = "Доступ к использованию PHP кода в шаблонах рубрик (Будьте предельно осторожны!)" +rubric_perms = "Доступ к управлению правами доступа для документов рубрики" +rubric_code = "Доступ к исполняемому коду для рубрик (Будьте предельно осторожны!)" + +template_view = "Доступ к списку шаблонов" +template_edit = "Доступ к управлению шаблонами (Создание, Редактирование, Удаление)" +template_php = "Доступ к использованию PHP кода в шаблонах (Будьте предельно осторожны!)" + +request_view = "Доступ к списку запросов" +request_edit = "Доступ к управлению запросами (Создание, Редактирование, Удаление)" +request_php = "Доступ к использованию PHP кода в шаблонах запроса (Будьте предельно осторожны!)" + +blocks_view = "Доступ к просмотру списка визуальных блоков" +blocks_edit = "Доступ к управлению визуальными блоками (Создание, Редактирование, Удаление)" + +sysblocks_view = "Доступ к просмотру списка системных блоков" +sysblocks_edit = "Доступ к управлению системными блоками (Создание, Редактирование, Удаление)" + +user_view = "Доступ к списку пользователей" +user_edit = "Доступ к редактированию параметров пользователей" +user_perms = "Доступ к управлению правами пользователей" + +group_view = "Доступ к списку групп пользователей" +group_edit = "Доступ к управлению правами групп пользователей (Создание, Редактирование, Удаление)" + +mediapool_int = "Доступ к менеджеру файлов" +mediapool_add = "Доступ к добавлению новых файлов на сервер (в менеджере файлов)" +mediapool_del = "Доступ к удалению файлов с сервера (в менеджере файлов)" +mediapool_finder = "Доступ к Файловому менеджеру (elFinder)" + +cache_clear = "Доступ к удалению кеша" +cache_thumb = "Доступ к удалению превью изображений (thumbnail)" + +logs = "Системные сообщения" +cache = "Управление кешем" +gen = "Системные настройки" +db = "База данных" +blocks = "Визуальные блоки" +sysblocks = "Системные блоки" +rubric = "Рубрики" +document = "Документы" +modules = "Модули" +mediapool = "Файловые менеджеры" +navigation = "Навигация" +request = "Запросы" +template = "Шаблоны" +remark = "Заметки у документов" +document = "Документы" +user = "Пользователи" +group = "Группы пользователей" \ No newline at end of file diff --git a/admin/lang/ru/logs.txt b/admin/lang/ru/logs.txt new file mode 100644 index 0000000..85c2558 --- /dev/null +++ b/admin/lang/ru/logs.txt @@ -0,0 +1,53 @@ +[logs] +LOGS_SUB_TITLE = "Управление системными сообщениями" +LOGS_TITLE = "Журнал системных событий" +LOGS_TIP = "В данном разделе приведен список всех действий, осуществляемых в Панели управления." +LOGS_ID = "№" +LOGS_IP = "Ip-адрес" +LOGS_DATE = "Дата" +LOGS_USER = "Пользователь" +LOGS_ACTION = "Действие" +LOGS_BUTTON_DELETE = "Очистить журнал" +LOGS_DELETE_CONFIRM = "Вы уверены, что хотите очистить журнал системных сообщений?" +LOGS_BUTTON_EXPORT = "Экспорт журнала системных сообщений" +LOGS_BUTTON_EXPORT_404 = "Экспорт журнала ошибок 404" +LOGS_DATE_FORMAT = "%d.%m.%y г." +LOGS_DATE_FORMAT2 = "%H:%M" +LOGS_IN = "в" +LOGS_CLEAR = "Системные сообщения успешно удалены." +LOGS_CLEAN = "Очистил Журнал событий" +LOGS_EXPORT = "Экспортировал Журнал событий" + +LOGS_404_SUB_TITLE = "Журнал ошибок 404" +LOGS_404_TITLE = "Журнал ошибок 404" +LOGS_404_TIP = "В данном разделе приведен список всех ошибок 404." +LOGS_404_ID = "№" +LOGS_404_IP = "Ip-адрес" +LOGS_404_DATE = "Дата" +LOGS_404_ACTION = "Действие" +LOGS_404_BUTTON_DELETE = "Очистить журнал" +LOGS_404_DELETE_CONFIRM = "Вы уверены, что хотите очистить журнал ошибок 404?" +LOGS_404_BUTTON_EXPORT = "Экспорт журнала ошибок" +LOGS_404_DATE_FORMAT = "%d.%m.%y г." +LOGS_404_DATE_FORMAT2 = "%H:%M" +LOGS_404_IN = "в" +LOGS_404_CLEAR = "Системные сообщения успешно удалены." +LOGS_404_CLEAN = "Очистил Журнал ошибок 404" +LOGS_404_EXPORT = "Экспортировал Журнал ошибок 404" + +LOGS_SQL_SUB_TITLE = "Журнал MySQL ошибок" +LOGS_SQL_TITLE = "Журнал MySQL ошибок" +LOGS_SQL_TIP = "В данном разделе приведен список всех ошибок MySQL." +LOGS_SQL_ID = "№" +LOGS_SQL_IP = "Ip-адрес" +LOGS_SQL_DATE = "Дата" +LOGS_SQL_ACTION = "Действие" +LOGS_SQL_BUTTON_DELETE = "Очистить журнал MySQL ошибок" +LOGS_SQL_DELETE_CONFIRM = "Вы уверены, что хотите очистить журнал MySQL ошибок?" +LOGS_SQL_BUTTON_EXPORT = "Экспорт журнала MySQL ошибок" +LOGS_SQL_DATE_FORMAT = "%d.%m.%y г." +LOGS_SQL_DATE_FORMAT2 = "%H:%M" +LOGS_SQL_IN = "в" +LOGS_SQL_CLEAR = "Журнал ошибок MySQL успешно удален." +LOGS_SQL_CLEAN = "Очистил Журнал MySQL ошибок" +LOGS_SQL_EXPORT = "Экспортировал Журнал MySQL ошибок" \ No newline at end of file diff --git a/admin/lang/ru/main.txt b/admin/lang/ru/main.txt new file mode 100644 index 0000000..25b5e4f --- /dev/null +++ b/admin/lang/ru/main.txt @@ -0,0 +1,306 @@ +MAIN_WELCOME = "Добро пожаловать в Панель управления!" +MAIN_WELCOME_INFO = "На главной странице Вы можете выбрать одно из наиболее часто используемый действий." + +MAIN_PAGE = "Главная страница" + +MAIN_LOGIN_INTRO = "Авторизация" +MAIN_LOGIN_BACK_SITE = "Вернуться на сайт" +MAIN_LOGIN_NAME = "Логин:" +MAIN_LOGIN_PASSWORD = "Пароль:" +MAIN_LOGIN_BUTTON = "Войти" +MAIN_LOGIN_REGISTER = "Регистрация" +MAIN_LOGIN_LOST = "Забыли пароль?" +MAIN_LOGIN_HELP = "Помощь" +MAIN_LOGIN_REMEMBER = "Запомнить меня" +MAIN_LOGIN_CAP_CODE = "Код:" +MAIN_LOGIN_CAP_CODE_REF = "Обновить код:" +MAIN_LOGIN_CAP_CODE_REFR = "Обновить код" + +MAIN_LINK_HOME = "Главное меню" +MAIN_LINK_AUTHOR = "Сайт поддержки" +MAIN_LINK_DATABASE = "Управление базой данных" +MAIN_LINK_NAVIGATION = "Управление меню навигации" +MAIN_LINK_MODULES = "Управление модулями" +MAIN_LINK_MODULES_H = "Модули" +MAIN_LINK_SETTINGS = "Управление настройками" +MAIN_LINK_SETTINGS_H = "Настройки" +MAIN_LINK_USERS = "Управление пользователями" +MAIN_LINK_TEMPLATES = "Управление шаблонами" +MAIN_LINK_RUBRICS = "Управление рубриками" +MAIN_LINK_DOCUMENT = "Управление документами" +MAIN_LINK_QUERYES = "Управление запросами" +MAIN_LINK_GROUPS = "Управление группами" +MAIN_LINK_LANG = "Управление языками" + +MAIN_BUTTON_LOGIN = "Войти" +MAIN_BUTTON_ADD = "Добавить" +MAIN_BUTTON_LOGOUT = "Выход" + +MAIN_SETTINGS_EDIT_1 = "Общие настройки" +MAIN_SETTINGS_EDIT_2 = "Дополнительные настройки" +MAIN_SETTINGS_EDIT_3 = "Управление странами" +MAIN_SETTINGS_EDIT_4 = "Создать резервную копию БД" + +MAIN_LINK_DOC_TIPS = "В данном разделе приведен список всех документов в системе." +MAIN_LINK_RUBRIK_TIP = "В данном разделе приведен список всех рубрик в системе." +MAIN_LINK_REQUEST_TIP = "В данном разделе приведен список всех существующих запросов в системе." +MAIN_LINK_NAVI_TIP = "В данном разделе приведен список всех меню навигаций в системе." +MAIN_LINK_TEMPLATES_TIP = "В данном разделе приведен список всех шаблонов используемых в системе." +MAIN_LINK_MODULES_TIP = "В данном разделе приведен список всех доступных модулей в системе." +MAIN_LINK_SETTINGS_TIP = "В данном разделе приведены все глобальные параметры системы." +MAIN_LINK_DB_TIP = "В данном разделе вы можете работать с базой данных системы." +MAIN_LINK_USER_TIP = "В данном разделе приведен список всех пользователей в системе." +MAIN_LINK_UGROUP_TIP = "В данном разделе приведен cписок всех групп пользователей в системе." + +MAIN_PAGE_TITLE = "Панель Управления" +MAIN_LOGIN_TEXT = "Авторизация" +MAIN_LOGIN_TEXT2 = "Пожалуйста, укажите Ваши данные:" +MAIN_LOGIN_CAPTCHA = "Введите код:" +MAIN_SELECT_LANGUAGE = "Язык:" +MAIN_SELECT_THEME = "Тема оформления:" +MAIN_YOUR_EMAIL = "E-mail:" +MAIN_YOUR_LOGIN = "Логин или E-mail:" +MAIN_YOUR_PASSWORD = "Пароль:" + +MAIN_LINK_SITE = "Посмотреть сайт" +MAIN_LINK_HOME = "На главную" +MAIN_LINK_LOGOUT = "Выход из панели управления" +MAIN_LINK_LOGOUT_QUEST = "Вы уверены, что хотите выйти?" +MAIN_LINK_CACHE_CLEAR = "Очистка кэша" +MAIN_LINK_CACHE_CLEAR_QUEST = "Вы уверены, что хотите очистить кэш?" + +MAIN_LINK_SITE_ON = "Включить редактор" +MAIN_LINK_SITE_OFF = "Выключить редактор" + +MAIN_LINK_EDIT = "Редактировать на сайте" +MAIN_ADD_IN_RUB = "Добавить новый документ:" +MAIN_DOCUMENTS_ALL = "Список документов:" +MAIN_SEARCH_DOCUMENTS = "Поиск документов:" +MAIN_SORT_DOCUMENTS = "Быстрый отбор:" +MAIN_TIME_PERIOD = "Период публикации" +MAIN_TIME_START = "Начало" +MAIN_TIME_END = "Окончание" +MAIN_BUTTON_SEARCH = "Поиск" +MAIN_TITLE_SEARCH = "Название документа:" +MAIN_TITLE_DOC_NAME = "Название документа" +MAIN_TITLE_DOC_ID = "ID документа" +MAIN_SEARCH_HELP = Использование поиска

Используйте знак "+" для строгого включения слова в поиск.
Используйте знак "-" для исключения слова из поиска.

Обязательно используйте пробел перед знаками "+" и "-"." +MAIN_ID_SEARCH = "ID документа:" +MAIN_SELECT_RUBRIK = "В рубрике:" +MAIN_ALL_RUBRUKS = "Все рубрики" +MAIN_ALL_DOCUMENTS = "любой статус" +MAIN_DOCUMENT_STATUS = "Статус документа" +MAIN_DOCUMENT_ACTIVE = "только активный" +MAIN_DOCUMENT_INACTIVE = "только неактивный" +MAIN_TEMP_DELETE_DOCS = "временно удаленный" +MAIN_RESULTS_ON_PAGE = "Результатов на странице:" +MAIN_OPEN_MEDIAPATH = "Посмотреть на сервере" +MAIN_NAVI_UGROUPS = "Группы пользователей" +MAIN_UGROUP_EDIT = "Редактировать права группы" +MAIN_UGROUP_DELETE = "Удалить данную группу" +MAIN_LOGS = "Системные события" +MAIN_NAVI_MODULES = "Управление модулями" +MAIN_NAVIGATION = "Меню навигаций" +MAIN_NAVIGATION_NEW = "Добавить новое меню" +MAIN_QUERIES = "Запросы" +MAIN_REQUEST_NEW = "Добавить новый запрос" +MAIN_RUBRIKS = "Рубрики" +MAIN_RUBRIK_NEW = "Добавить новую рубрику" +MAIN_RUBRIK_EDIT_FIELDS = "Редактировать поля рубрики" +MAIN_RUBRIK_EDIT_TEMPL = "Редактировать шаблон рубрики" +MAIN_SETTINGS = "Системные настройки" +MAIN_COUNTRY_EDIT = "Управление странами" +MAIN_SYSBLOCKS = "Системные блоки" +MAIN_TEMPLATES = "Шаблоны" +MAIN_TEMPLATES_NEW = "Добавить новый шаблон" +MAIN_USERS = "Пользователи" +MAIN_DATABASE_INFO = "База данных" +MAIN_NAVI_DOCUMENTS = "Документы" +MAIN_BROWSE_DOCUMENTS = "Посмотреть в документах" +MAIN_USERS_LIST = "Список пользователей" +MAIN_USER_ADD = "Добавить нового пользователя" +MAIN_SEARCH_USERS = "Поиск пользователей по:" +MAIN_USER_PARAMS = "Имени, Id, E-mail, E-mail домену" +MAIN_USER_STATUS = "Со статусом:" +MAIN_USER_STATUS_ALL = "Любой статус" +MAIN_USER_STATUS_ACTIVE = "Активный" +MAIN_USER_STATUS_INACTIVE = "Ожидающий активации" +MAIN_USER_GROUP = "Состоит в группе:" +MAIN_USER_ONLINE = "Добро пожаловать," +MAIN_USER_PERM = "Статус:" +MAIN_ALL_USER_GROUP = "В любой" +MAIN_BUTTON_SEARCH_USER = "Найти пользователей по параметрам" +MAIN_NO_PERMISSION = "Извините, но вы не имеете прав доступа к данному разделу" +MAIN_LOGOUT_CONFIRM = "Вы уверены, что хотите выйти?" + +MAIN_START_DOC_TITLE = "Последние документы" +MAIN_START_DOC_ID = "id" +MAIN_START_DOC_NAME = "Наименование" +MAIN_START_DOC_RUBRIC = "Рубрика" +MAIN_START_DOC_DATE = "Опубликован" +MAIN_START_DOC_AUTOR = "Автор" + +MAIN_START_SEARCH = "Поиск:" +MAIN_START_SEARCH_T = "Искать документ" + +MAIN_START_LOGS_LOG = "Журнал операций" +MAIN_START_LOGS_404 = "Ошибки 404" +MAIN_START_LOGS_SQL = "Ошибки MySQL" + +MAIN_TABLE_SUCC = "Количество успешно загруженных таблиц: " +MAIN_TABLE_ERROR = "Количество таблиц с ошибками: " +MAIN_SQL_FILE_ERROR = "SQL-файл имеет неверный формат или содержит ошибки в структуре запросов." +MAIN_RESTORE_OK = "База данных успешно восстановлена" + +MAIN_NO_PERM_MODULES = "Извините, но у вас недостаточно прав для управления данным модулем" +MAIN_MP_FILE_DELETE = "Удалить файл" +MAIN_MP_DELETE_CONFIRM = "Вы уверены, что хотите удалить файл: " +MAIN_MP_DOC_FOLDER = "Список папок / файлов" +MAIN_MP_FILE_SIZE = "Размер файла" +MAIN_MP_FILE_DATE = "Дата создания" +MAIN_MP_ACTIONS = "Действия" +MAIN_MP_FILE_INFO = "Чтобы добавить файл, нажмите на его название, а потом на кнопку Вставить файл" +MAIN_MP_UP_LEVEL = "Вернуться на уровень выше" +MAIN_MP_CREATE_FOLDER = "Создать папку" +MAIN_MP_UPLOAD_FILE = "Закачать файл" +MAIN_MP_FILE_INSERT = "Вставить файл" +MAIN_MP_DIR_INSERT = "Выбрать папку" +MAIN_MP_SELECT_FILES = "Выберите файлы для загрузки" +MAIN_MP_IMAGE_RESIZE = "Изменить размер загружаемых изображений" +MAIN_MP_IMAGE_WIDTH = "Ширина" +MAIN_MP_IMAGE_HEIGHT = "Высота" +MAIN_BUTTON_UPLOAD = "Закачать" +MAIN_BUTTON_WAIT = "Пожалуйста, подождите..." +MAIN_MP_PLEASE_SELECT = "Пожалуйста, выберите файл" +MAIN_ADD_IN = "Выберите рубрику:" +MAIN_GROUP_DELETE_CONFIRM = "Вы уверены, что хотите удалить данную группу?" +MAIN_RUBRIKS_LIST = "Список рубрик" +MAIN_USER = "Пользователь:" +ButtonSave = "Сохранить" +MAIN_NEW_PAGE = "Добавить новую страницу" +MAIN_BUTTON_SORT = "Отобрать" +MAIN_QUICK_MODULE = "Управление модулями" +MAIN_STAT = "Статистика" +MAIN_STAT_SYSTEM_INFO = "Системная информация" +MAIN_STAT_DOCUMENTS = "Всего документов:" +MAIN_STAT_RUBRICS = "Всего рубрик:" +MAIN_STAT_QUERIES = "Всего запросов:" +MAIN_STAT_TEMPLATES = "Всего шаблонов:" +MAIN_STAT_MYSQL = "Размер базы данных:" +MAIN_STAT_CACHE = "Общий размер кеша:" +MAIN_STAT_CACHE_SHOW = "Показать" +MAIN_STAT_MODULES = "Установлено модулей:" +MAIN_STAT_MODULES_OFF = "Отключено модулей:" +MAIN_STAT_USERS = "Всего пользователей:" +MAIN_STAT_USERS_WAIT = "Ожидают активацию:" +MAIN_STAT_AVE = "AVE.cms" +MAIN_STAT_DOMEN = "Домен" +MAIN_STAT_PHP = "PHP версия:" +MAIN_STAT_MYSQL_VERSION = "MySQL версия:" +MAIN_STAT_CLEAR_CACHE = "Очистить кэш" +MAIN_STAT_CLEAR_CACHE_FULL= "Очистить кэш и сессии" +MAIN_STAT_CLEAR_THUMB = "Удалить миниатюры" +MAIN_STAT_CLEAR_REV = "Удалить ревизии" +MAIN_STAT_CLEAR_COUNT = "Обнулить подневный счетчик" +MAIN_ADD_FOLDER = "Пожалуйста, введите имя для новой папки:" +MAIN_NO_ADD_FOLDER = "Не указано имя папки или действие отменено!" +MAIN_NO_ADD_TEMPL = "Не указано наименование шаблона или действие отменено!" +MAIN_NO_ADD_GROUP = "Не указано наименование группы или действие отменено!" +MAIN_NO_ADD_RUB = "Не указано наименование рубрики или действие отменено!" +MAIN_NO_ADD_QUERY = "Не указано наименование запроса или действие отменено!" +MAIN_NO_ADD_NAV = "Не указано наименование навигации или действие отменено!" +MAIN_NO_ADD_BLOCK = "Не указано наименование системного блока или действие отменено!" +MAIN_NO_ADD_USER = "Не указано имя пользователя или действие отменено!" +MAIN_NO_ADD_DOCS = "Не указано название документа или действие отменено!" +MAIN_CLEAR_CACHE_OK = "Кэш очищен" +MAIN_FILE_MANAGER_TITLE = "Файловый менеджер" +MAIN_FILE_MANAGER_TIP = "Выберите нужный файл и нажмите по кнопке "Вставить файл"" + +MAIN_SVN_NEW = "Вышла новая версия" +MAIN_SVN_SAIT = "Перейти на сайт" +MAIN_SVN_REPOS = "Перейти на сайт репозитория" +MAIN_SVN_MAILTO = "Написать письмо" +MAIN_SVN_LOOK = "Посмотреть ревизию на сайте репозитория" +MAIN_SVN_RECOM = "Рекомендуется обновиться!" + +MAIN_FINDER = "Файловый менеджер" + +MAIN_ADD_NEW_GROUP = "Добавить новую группу" +MAIN_ADD_NEW_GROUP_NAME = "Наименование группы:" + +MAIN_ADD_NEW_USER = "Добавить нового пользователя" +MAIN_ADD_NEW_USER_NAME = "Имя пользователя:" + +MAIN_ADD_NEW_NAV = "Добавить новую навигацию" +MAIN_ADD_NEW_NAV_NAME = "Наименование навигации:" + +MAIN_ADD_NEW_TEMPL = "Добавить новый шаблон" +MAIN_ADD_NEW_TEMPL_NAME = "Наименование шаблона:" + +MAIN_ADD_NEW_REQUEST = "Добавить новый запрос" +MAIN_ADD_NEW_REQUEST_NAME = "Наименование запроса:" + +MAIN_ADD_NEW_RUB = "Добавить новую рубрику" +MAIN_ADD_NEW_RUB_NAME = "Наименование рубрики:" + +MAIN_ADD_NEW_BLOCK = "Добавить новый системный блок" +MAIN_ADD_NEW_BLOCK_NAME = "Наименование системного блока:" + +MAIN_USERS_LAST_TIME = "За последнее время были:" + +MAIN_LOGS_ID = "№" +MAIN_LOGS_IP = "Ip-адрес" +MAIN_LOGS_DATE = "Дата" +MAIN_LOGS_USER = "Пользователь" +MAIN_LOGS_ACTION = "Действие" + +MAIN_DOC_SHOW3_TITLE = "Документ без названия" +MAIN_DOC_EDIT_TITLE = "Редактировать данный документ" +MAIN_DOC_SHOW_TITLE = "Просмотр документа (ссылка без ЧПУ)" +MAIN_DOC_SHOW2_TITLE = "Просмотр документа (ссылка c ЧПУ)" + +MAIN_ADD_DOC = "Документ" +MAIN_ADD_RUB = "Рубрику" +MAIN_ADD_REQ = "Запрос" +MAIN_ADD_SYS = "Системный блок" +MAIN_ADD_TEM = "Шаблон" +MAIN_ADD_NAV = "Навигацию" +MAIN_ADD_USR = "Пользователя" +MAIN_ADD_GRP = "Группу" + +MAIN_BRANCHES = "Разделы" +MAIN_SHOWHIDE = "Показать/Скрыть меню" + +MAIN_CODEMIRROR_HELP = "Ctrl-F/Cmd-F (Искать) | Ctrl-G/Cmd-G (Искать далее) | Shift-Ctrl-G/Shift-Cmd-G (Найти предыдущее) | Shift-Ctrl-F/Cmd-Option-F (Заменить) | Shift-Ctrl-R / Shift-Cmd-Option-F (Заменить все) | F11 (На полный экран)" + +TEMPLATES_MESSAGE = "Сообщение:" +TEMPLATES_CACHE_SUCCESS = "Кеш успешно очищен." +TEMPLATES_CACHE_SUCCESS_LOG = "Очистил кэш" +TEMPLATES_CACHE_DB_SUCCESS = "Таблица _sessions успешно очищена." +TEMPLATES_CACHE_DB_SUCCESS_LOG = "Очистил таблицу _sessions." +TEMPLATES_CACHE_CT_SUCCESS = "Удалены скомпилированные шаблоны." +TEMPLATES_CACHE_CT_SUCCESS_LOG = "Удалил скомпилированные шаблоны" +TEMPLATES_CACHE_MC_SUCCESS = "Удалены скомпилированные шаблоны модулей." +TEMPLATES_CACHE_MC_SUCCESS_LOG = "Удалил скомпилированные шаблоны модулей" +TEMPLATES_CACHE_SU_SUCCESS = "Удалены сессии пользователей." +TEMPLATES_CACHE_SU_SUCCESS_LOG = "Удалил сессии пользователей" +TEMPLATES_CACHE_SC_SUCCESS = "Удален кэш sql запросов." +TEMPLATES_CACHE_SC_SUCCESS_LOG = "Удалил кэш sql запросов" +TEMPLATES_THUMBNAILS_SUCCESS = "Миниатюры успешно удалены." +TEMPLATES_THUMBNAILS_SUCCESS_LOG = "Удалил миниатюры" + +EXIT_ADMIN = "Закончил сеанс в Панели управления" +LOGIN_ADMIN = "Начал сеанс в Панели управления" +ERROR_ADMIN = "Ошибка при входе в Панель управления" + +WRONG_PASS = "Ошибка:
Имя пользователя или пароль не правильные!" +WRONG_CAPTCHA = "Ошибка:
Неправильный защитный код" + +oficial_site = "Официальный сайт" +support = "Служба технической поддержки" + +// 3.1.9 +MAIN_BLOCKS = "Визуальные блоки" + +// 3.27 +MAIN_SETTINGS_SHOWCACHE = "Подробные данные" \ No newline at end of file diff --git a/admin/lang/ru/modules.txt b/admin/lang/ru/modules.txt new file mode 100644 index 0000000..f369c20 --- /dev/null +++ b/admin/lang/ru/modules.txt @@ -0,0 +1,36 @@ +[modules] +MODULES_SUB_TITLE = "Управление модулями" +MODULES_TIP = "В данном разделе приведен список всех доступных модулей в системе. Здесь Вы можете установить, отключить, обновить любой из модулей, а также выполнить дополнительные, персональные настройки для любого из модулей." +MODULES_NAME = "Название модуля" +MODULES_INFO = "Информация" +MODULES_TEMPLATE = "Шаблон вывода" +MODULES_SYSTEM_TAG = "Системный тег" +MODULES_VERSION = "Версия" +MODULES_ACTIONS = "Действия" +MODULES_SETTINGS = "Параметры" +MODULES_SETTINGS_INFO = "Информация" +MODULES_DELETE = "Удалить модуль" +MODULES_DELETE_CONFIRM = "Помните, что удаляя модуль из системы, Вы удаляете его только на программном уровне. Таким образом, в последствии, Вы всегда можете его установить заново.
Вы уверены, что хотите удалить данный модуль?" +MODULES_INSTALL = "Установить модуль" +MODULES_REMOVE = "Удалить модуль с сервера" +MODULES_REINSTALL = "Переустановить модуль" +MODULES_REINSTALL_CONF = "Вы уверены, что хотите переустановить данный модуль?" +MODULES_UPDATE = "Обновить модуль" +MODULES_STOP = "Отключить модуль" +MODULES_START = "Включить модуль" +MODULES_BUTTON_SAVE = "Сохранить изменения" +MODULES_LEGEND = "Значения пиктограмм" +MODULES_AUTHOR = "Автор модуля" +MODULES_ERROR = "Возникла ошибка при загрузке модуля: " +MODULES_INSTALLED = "Установленные модули:" +MODULES_NOT_INSTALLED = "Неустановленные модули:" +MODULES_SETUP = "Перейти к управлению модулем" +MODULES_NO_INSTALL = "Сообщение:
Нет установленных модулей." +MODULES_NOT_INSTALL = "Сообщение:
Нет неустановленных модулей." +MODULES_ACTION_INSTALL = "Установил модуль" +MODULES_ACTION_ONLINE = "Включил модуль" +MODULES_ACTION_OFFLINE = "Отключил модуль" +MODULES_ACTION_REINSTALL = "Переустановил модуль" +MODULES_ACTION_UPDATE = "Обновил модуль" +MODULES_ACTION_DELETE = "Удалил модуль из системы" +MODULES_ACTION_REMOVE = "Удалил модуль с сервера" \ No newline at end of file diff --git a/admin/lang/ru/navigation.txt b/admin/lang/ru/navigation.txt new file mode 100644 index 0000000..9ecf20b --- /dev/null +++ b/admin/lang/ru/navigation.txt @@ -0,0 +1,130 @@ +[navi] +NAVI_ID = "ID" +NAVI_SUB_TITLE = "Управление меню навигации" +NAVI_SUB_TITLE2 = "Управление пунктами меню" +NAVI_SUB_TITLE3 = "Редактирование шаблона меню" +NAVI_SUB_TITLE4 = "Создание нового шаблона меню" +NAVI_TIP_TEMPLATE = "В данном разделе приведен список всех меню навигаций в системе. Здесь Вы можете изменить шаблон вывода любого из доступных меню, а также добавить или удалить пункты меню." +NAVI_TIP_TEMPLATE2 = "В данном разделе, используя язык разметки HTML, Вы можете создать шаблон оформления для данного меню навигации. Также, Вы можете выбрать группы пользователей, которым будет доступно данное меню навигации. Для выбора нескольких групп зажмите клавишу CTRL." +NAVI_ITEMS_TIP = "Создание нового пункта меню" +NAVI_NEW_MENU = "Создание нового меню" +NAVI_LIST_TIP = "Cписок ниже содержит все пункты, относящиеся к данному меню. Помните, что максимальный уровень вложенности не может быть более 2." +NAVI_LIST = "Список пунктов меню" +NAVI_EDIT_TEMPLATE = "Редактирование шаблона меню" +NAVI_EDIT_ITEMS = "Редактирование пунктов меню" +NAVI_OPEN_IN_THIS = "в текущем окне" +NAVI_OPEN_IN_NEW = "в новом окне" +NAVI_TARGET_WINDOW = "Открывать" +NAVI_POSITION = "Позиция" +NAVI_LINK_TO_DOCUMENT = "Ссылка на документ/файл" +NAVI_ENTRIES_NO_ITEMS = "Сообщение:
В настоящий момент нет пунктов меню." + +NAVI_LINK_TITLE = "Название пункта меню" +NAVI_LINK_SOLUT = "Описание для пункта меню:" +NAVI_LINK_IMGID = "Id изображения:" +NAVI_LINK_IMGTL = "Выбрать изображение:" +NAVI_LINK_IMAGE = "Изображение для пункта меню" +NAVI_TITLE = "Наименование меню навигации:" +NAVI_TITLE2 = "Введите название меню навигации:" +NAVI_BROWSE_DOCUMENTS = "Связать с существующим документом" +NAVI_ADD_SUBITEM = "Добавить новый подпункт" +NAVI_BUTTON_CHANGE = "Выбрать" +NAVI_BUTTON_OPTION = "Опции" +NAVI_BUTTON_SUBITEM = "+" +NAVI_BROWSE_MEDIAPOOL = "Связать с файлом на сервере" +NAVI_SYSTEM_TAG = "Системный тег" +NAVI_NAME = "Наименование меню" +NAVI_LINK_TARGET = "Тег, определяющий тип открытия документа (в новом или текущем окне)" +NAVI_LINK_URL = "Тег, определяющий адрес для перехода" +NAVI_LINK_NAME = "Тег, определяющий название ссылки, которое будет отображено в меню" +NAVI_LINK_ID = "Тег, определяющий уникальный идентификатор ссылки" +NAVI_LINK_INACTIVE = "Оформление неактивной ссылки:" +NAVI_LINK_ACTIVE = "Оформление активной ссылки:" +NAVI_HEADER_START = "Верхняя часть оформления:" +NAVI_FOOTER_END = "Нижняя часть оформления:" +NAVI_HEADER_TIP = "Например, заголовок
"Каталог товаров"
(не обязательное)" +NAVI_COPY_TEMPLATE = "Копировать шаблон меню" +NAVI_FOOTER_TIP = "Нижняя часть оформления меню
(не обязательное)" +NAVI_DELETE = "Удалить данное меню" +NAVI_DELETE_CONFIRM = "Вы уверены, что хотите удалить данное меню навигации?" +NAVI_HTML_START = "Начальный HTML код:" +NAVI_HTML_END = "Конечный HTML код:" +NAVI_LEVEL1 = "Шаблон оформления для главного (первого) уровня пунктов меню" +NAVI_LEVEL2 = "Шаблон оформления для первого уровня вложенных пунктов меню" +NAVI_LEVEL3 = "Шаблон оформления для второго уровня вложенных пунктов" +NAVI_MARK_DELETE = "Отметить данный пункт для удаления" +NAVI_MARK_ACTIVE = "Для того, чтобы временно отключить данный пункт меню, снимите выделение и нажмите "Сохранить изменения"" +NAVI_GROUPS = "Группы пользователей, которым будет доступно меню:" +NAVI_ACTIONS = "Действия" +NAVI_OR_BUTTON = " или " +NAVI_BUTTON_SAVE = "Сохранить изменения" +NAVI_BUTTON_SAVE_NEXT = "Применить (CTRL+S)" +NAVI_BUTTON_ADD = "Добавить пункт" +NAVI_BUTTON_ADD_MENU = "Создать меню" +NAVI_LEGEND = "Значения пиктограмм" +NAVI_ENTER_NAME = "Пожалуйста, укажите название меню навигации." +NAVI_ALL = "Список меню навигаций" +NAVI_PRINT_TYPE = "Тип вывода" +NAVI_EXPAND_ALL = "Полностью (раскрывать все уровни)" +NAVI_EXPAND_WAY = "Текущий и родительский уровни" +NAVI_EXPAND_LEVEL = "Только текущий уровень" +NAVI_MENU_NOT_FOUND = "Отсутствует меню id=" +NAVI_SAVE = "Шаблон навигации успешно сохранен" +NAVI_SORTED = "Порядок успешно сохранён" + +NAVI_REPORT_NEW = "Создал меню навигации" +NAVI_REPORT_COPY = "Создал копию меню навигации" +NAVI_REPORT_EDIT = "Изменил шаблон меню навигации" +NAVI_REPORT_DEL = "Удалил меню навигации" +NAVI_REPORT_ADDIT = "Добавил пункт меню навигации" +NAVI_REPORT_DELIT = "Удалил пункт меню навигации" +NAVI_REPORT_FLEV = "на первый уровень" +NAVI_REPORT_SLEV = "на второй уровень" +NAVI_REPORT_TLEV = "на третий уровень" +NAVI_REPORT_DEACT = "Деактивировал пункт меню навигации" +NAVI_REPORT_ACT = "Активировал пункт меню навигации" +NAVI_REPORT_SAVED = "Шаблон навигации успешно сохранен" +NAVI_REPORT_SAVED_ERR = "Не удалось шаблон навигации.
Попробуйте еще раз." +NAVI_REPORT_ERROR = "Ошибка" +NAVI_REPORT_SUCCESS = "Выполнено" + +NAVI_ITEM_ON_OFF = "Вкл/Выкл пункт меню" +NAVI_ITEM_EDIT = "Редактировать пункт меню" +NAVI_ITEM_DELETE = "Удалить данный пункт меню" +NAVI_ITEM_DELETE_CONFIRM = "Вы уверены, что хотите удалить данный пукт меню навигации?" + +// v 3.2 +NAVI_ALIAS = "Алиас" +NAVI_I = "Опционально. Алиас позволяет использовать легко запоминающийся тег [tag:sysblock:alias] вместо [tag:sysblock:id]. Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание, иметь длину не более 20 символов и быть уникальным в пределах модуля" +NAVI_ACCEPT = "Этот алиас можно использовать" +NAVI_ER_SYN = "Неверный алиас!
Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание и иметь длину не более 20 символов" +NAVI_ER_EXISTS = "Неверный алиас!
Данный алиас уже привязан к другому меню" + +//from templates +NAVI_NOLINK_DOC = "Нет связанного документа" +NAVI_EDIT_ITEM = "Редактирование пункта меню" +NAVI_LINK_FILEDOC = "Связать с документом/файлом" +NAVI_LINKED_DOC = "Связанный документ" +NAVI_DEL_LINKED_DOC = "Убрать связь с документом" +NAVI_LINK_DOC = "Связать с документом" +NAVI_LINK_FILE = "Связать с файлом" +NAVI_NO_LINK = "Нет связанного документа" +NAVI_STRUCTURE = "Структура" +NAVI_RETURN_TO_LIST = "Вернуться к списку" +NAVI_EDIT_TEMPLATE = "Редактировать шаблон" +NAVI_ITEM_ADD = "Добавить пункт меню" +NAVI_OPEN_ALL = "Раскрыть все" +NAVI_CLOSE_ALL = "Свернуть все" +NAVI_ITEM_DESCR = "Описание пункта меню" +NAVI_ITEM_IMAGE = "Изображение" +NAVI_ITEM_IMAGE_DESCR = "Изображение активное, в конце названия изображения должно быть _act" +NAVI_ITEM_IMAGE_ID = "Id изображения" +NAVI_PLACE_INSERT = "Место вставки подуровня" +NAVI_EXAMPLE = "Пример" +NAVI_ITEM_EVEN = "четный" +NAVI_ITEM_ODD = "нечетный" +NAVI_TAG = "Тег для вставки пунктов" +NAVI_LAVEL_TEMPL = "Шаблон уровня" +NAVI_CONDITIONS = "Условия" +NAVI_CLOSE = "Закрыть" +NAVI_ADD_AFTER = "Добавить после" \ No newline at end of file diff --git a/admin/lang/ru/request.txt b/admin/lang/ru/request.txt new file mode 100644 index 0000000..3cdc6cb --- /dev/null +++ b/admin/lang/ru/request.txt @@ -0,0 +1,215 @@ +[request] +REQUEST_ID = "ID" +REQUEST_DELETE = "Удалить запрос" +REQUEST_DELETE_CONFIRM = "Вы уверены, что хотите удалить данный запрос?" +REQUEST_TITLE = "Управление запросами" +REQUEST_NAME = "Наименование запроса" +REQUEST_NAME2 = "Наименование запроса:" +REQUEST_NAME3 = "Введите название запроса:" +REQUEST_CACHE = "Кешировать:" +REQUEST_CACHE_ELEMENTS = "Кешировать элементы запроса" +REQUEST_SETTINGS = "Параметры запроса" +REQUEST_TIP = "В данном разделе приведен список всех существующих запросов в системе. Для использования запроса разместите "Системный тег" в нужном месте Вашего шаблона или документа." +REQUEST_EDIT_TIP = "В данном разделе Вы можете отредактировать запрос, изменив рубрику для получения данных, шаблон вывода, а также условия выборки данных." +REQUEST_NEW = "Создание нового запроса" +REQUEST_EDIT = "Редактировать запрос" +REQUEST_EDIT2 = "Редактирование запроса" +REQUEST_SYSTEM_TAG = "Системный тег" +REQUEST_AUTHOR = "Автор" +REQUEST_DATE_CREATE = "Дата создания" +REQUEST_ACTIONS = "Действия" +REQUEST_NO_DESCRIPTION = "Запрос без описания" +REQUEST_NO_REQUST = "Запросы отсутсвуют." +REQUEST_DATE_FORMAT = "%d.%m.%y г." +REQUEST_DATE_FORMAT2 = "%d.%m.%y г. в %H:%M" +REQUEST_IN = "в" +REQUEST_COPY = "Копировать запрос" +REQUEST_COPY_FAILED = "Не удалось выполнить копирование запроса" +REQUEST_PLEASE_NAME = "Пожалуйста, укажите название для копируемого запроса" +REQUEST_CONDITION_EDIT = "Условия для запроса" +REQUEST_CONDITION_IF = "Условия" +REQUEST_PLEASE_SELECT = "Пожалуйста, выберите рубрику" +REQUEST_SELECT_RUBRIK = "Выберите рубрику:" +REQUEST_SELECT_INFO = "Вы уверены, что хотите изменить рубрику" +REQUEST_NEW_TIP = "Внимание! Прежде чем создать новый запрос Вы должны выбрать рубрику, из которой будут выводиться документы." +REQUEST_DESCRIPTION = "Описание запроса:" +REQUEST_INTERNAL_INFO = "(используется внутри системы)" +REQUEST_BUTTON_COND = "Добавить / Изменить" +REQUEST_CONDITION = "Условия запроса:" +REQUEST_ACTION_AFTER = "Вернуться к редактированию запроса после создания, чтобы добавить условия запроса." +REQUEST_SORT_BY = "Сортировать по параметру документа:" +REQUEST_SORT_BY_NAT = "Сортировать по полю документа:" +REQUEST_ASC_DESC = "В порядке:" +REQUEST_DESC = "убывания" +REQUEST_ASC = "возрастания" +REQUEST_BY_DATE = "Дате создания (публикации)" +REQUEST_BY_DATECHANGE = "Дате изменения (документа)" +REQUEST_BY_NAME = "Названию документов" +REQUEST_BY_EDIT = "Имени автора" +REQUEST_BY_PRINTED = "Количеству распечаток" +REQUEST_BY_VIEWS = "Количеству просмотров" +REQUEST_BY_RAND = "В случайном порядке (высокая нагрузка)" +REQUEST_DOC_PER_PAGE = "Количество запросов на одной странице:" +REQUEST_DOC_PER_PAGE_ALL = "Выводить все" +REQUEST_SHOW_NAVI = "Показывать навигацию:" +REQUEST_USE_LANG = "Только на языке пользователя:" +REQUEST_USE_QUERY = "Использовать GET запросы в постраничной навигации" +REQUEST_TEMPLATE_QUERY = "Основной шаблон оформления запроса" +REQUEST_MAIN_CONTENT = "Системный тег отвечающий за вывод элементов запроса, указанных в поле "Элементы запроса"" +REQUEST_DOC_COUNT = "Системный тег отвечающий за вывод количества элементов запроса" +REQUEST_DOCITEMNUM_INFO= "Системный тег отвечающий за вывод порядкового номера элемента запроса" +REQUEST_MAIN_NAVI = "Системный тег отвечающий за вывод постраничной навигации для запроса (< 1 2 3 >)" +REQUEST_MEDIAPATH = "Системный тег определяющий путь до папки с шаблоном (Например: [tag:mediapath]images/logo.gif)" +REQUEST_PATH = "Системный тег определяющий корень установки" +REQUEST_DOCDB = "Системный тег вывода поля документа из БД" +REQUEST_LANGFILE = "Системный тег для вывода языковой переменной из файла" +REQUEST_LANGUAGE = "Тег включает подгрузку языковых файлов. Желательно указывать данный тег, до основного шаблона" +REQUEST_LANG = "Содержимое будет показано если язык документа совпадает с указанным" + +REQUEST_TEMPLATE_ITEMS = "Шаблон оформления для элементов запроса" +REQUEST_TEMPLATE_INFO = "В данном поле, используя HTML-код, Вы можете указать оформление для внутренних элементов запроса (Например, оформление списка новостей). Все элементы, оформленные согласно данному шаблону будут циклически отображаться в "Основном шаблоне" запроса, пока количество элементов, будет соответствовать условиям запроса." +REQUEST_TEMPLATE_SAVED = "Запрос успешно сохранен" +REQUEST_SELECT_IN_LIST = "Пожалуйста, выберите поле рубрики из списка, приведенного ниже" +REQUEST_RUB_INFO = "Системный тег отвечающий за вывод содержимого поля рубрики. ID-номер поля. ХХХ-количество символов для отображения." +REQUEST_LINK_INFO = "Системный тег определяющий ссылку на документ. Например, < a href="[tag:link]">Ссылка < /a >" +REQUEST_RUBRIK_FIELD = "Системный тег поля" +REQUEST_THUMBNAIL = "Тег отвечает за создание миниатюрки (При условии что в шаблоне поля рубрики (шаблон для вывода в запросе) выбран вывод: [tag:parametr:0])
Использование:
Замените Х на один из параметров: c , r , f , t , s
например я хочу обрезать изображение до размеров 100х100 в рубрике Id которой = 10, тогда тег будет выглядеть так:
[tag:c100x100:[tag:rfld:10][150]]" +REQUEST_FIELD_NAME = "Название поля" +REQUEST_FIELD_TYPE = "Тип поля" +REQUEST_FIELD_G_UNKNOW = "Без группы" + +REQUEST_BUTTON_ADD = "Создать запрос" +REQUEST_BUTTON_ADD_NEXT = "Создать и продолжить" +REQUEST_BUTTON_SAVE = "Сохранить изменения" +REQUEST_BUTTON_SAVE_NEXT = "Применить (CTRL+S)" +REQUEST_BUTTON_CLOSE = "Закрыть окно" + +REQUEST_INSERT_INFO = "Нажмите на системный тег, чтобы добавить его в шаблон" +REQUEST_CONDITIONS = "Управление условиями запроса" +REQUEST_CONDITION_TIP = "В данном разделе Вы можете создать специальные условия выборки данных для запроса. Условия запроса позволяют наиболее точно определить вывод данных по тем или иным параметрам." +REQUEST_NEW_CONDITION = "Добавить новое условие" +REQUEST_FROM_FILED = "Выбрать из поля" +REQUEST_OPERATOR = "Где значение" +REQUEST_VALUE = "Значение" +REQUEST_COND_SELF = "Равно" +REQUEST_COND_NOSELF = "Не равно" +REQUEST_COND_USE = "Содержит значение" +REQUEST_COND_NOTUSE = "Не содержит значение" +REQUEST_COND_START = "Начинается с" +REQUEST_SMALL1 = "Меньше или равно" +REQUEST_BIG1 = "Больше или равно" +REQUEST_SMALL2 = "Меньше" +REQUEST_BIG2 = "Больше" +REQUEST_N_COND_SELF = "Число равно" +REQUEST_N_SMALL1 = "Число меньше или равно" +REQUEST_N_BIG1 = "Число больше или равно" +REQUEST_N_SMALL2 = "Число меньше" +REQUEST_N_BIG2 = "Число больше" +REQUEST_SEGMENT = "Принадлежит отрезку (через ,)" +REQUEST_INTERVAL = "Принадлежит интервалу (через ,)" +REQUEST_IN = "В списке (через ,)" +REQUEST_NOTIN = "Не в списке (через ,)" +REQUEST_ANY_NUM = "ОПАСНО!!! Число в запросе" +REQUEST_FREE = "ОПАСНО!!! Произвольное условие [field]={Значение}" +REQUEST_MARK_DELETE = "Отметить условие для удаления" +REQUEST_MARK_STATUS = "Активировать / Деактивировать условие" +REQUEST_CONR_AND = "И" +REQUEST_CONR_OR = "ИЛИ" +REQUEST_OR = " или " + +REQUEST_VIEWS_INFO = "Системный тег отображающий количество просмотров для документа" +REQUEST_CONTROL_SORT = "Системный тег отвечающий за вывод панели сортировок по дате публикации, наименованию и количеству просмотров результатов вывода запроса" +REQUEST_NO_DROPDOWN = "В выбранной рубрике нет полей типа выпадающий список" +REQUEST_ENTER_NAME = "Пожалуйста, укажите название запроса." +REQUEST_ALL = "Список запросов" +REQUEST_IF_EMPTY = "Парный системный тег, внутри которого можно указать шаблон вывода при отсутствии результатов работы запроса" +REQUEST_NOT_EMPTY = "Парный системный тег, внутри которого можно указать шаблон вывода при наличии результатов работы запроса" +REQUEST_DOCID_INFO = "Системный тег, соответствующий идентификатору документа" +REQUEST_DOCTITLE_INFO = "Системный тег, соответствующий имени документа" +REQUEST_CDOCID_INFO = "Системный тег, соответствующий идентификатору текущего документа(в котором выводится запрос)" +REQUEST_CDOCID_TITLE = "Системный тег, соответствующий названию текущего документа(в котором выводится запрос)" +REQUEST_DOCPARENT_INFO = "Системный тег, выводит ID родительского документа, если таковой имеется. Если нет, выведет 0." +REQUEST_DOCDATE_INFO = "Системный тег, соответствующий дате публикации документа" +REQUEST_CDOCDATE_INFO = "Системный тег, соответствующий дате публикации текущего документа(в котором выводится запрос)" +REQUEST_DOCTIME_INFO = "Системный тег, соответствующий дате и времени публикации документа" +REQUEST_CDOCTIME_INFO = "Системный тег, соответствующий дате и времени публикации текущего документа(в котором выводится запрос)" +REQUEST_COMMENTS_INFO = "Системный тег отображающий количество комментариев для документа. Внимание! Работает только при установленном модуле!" +REQUEST_DOMEN_INFO = "Системный тег вывода доменного имени" +REQUEST_DATE_INFO = "Системный тег, дата и время публикации документа - Настраиваемый вид.
Пример: [tag:date:d.m.Y]
Можно исрльзовать разделители (space - . /)" +REQUEST_CDATE_INFO = "Системный тег, дата и время публикации документа - Настраиваемый вид.
Пример: [tag:date:d.m.Y]
(в котором выводится запрос)
Можно исрльзовать разделители (space - . /)" +REQUEST_DOCAUTHOR_INFO = "Системный тег, соответствующий автору документа" +REQUEST_DOCAUTHOR_AVATAR = "Системный тег, соответствующий аватаре автора документа, параметр ХХХ означает размер изображения в пикселях." +REQUEST_CDOCAUTHOR_INFO = "Системный тег, соответствующий автору текущего документа(в котором выводится запрос)" +REQUEST_SAMPLE = "Пример" +REQUEST_HIDE_CURRENT = "Не показывать в запросе текущий документ" +REQUEST_ONLY_OWNER = "Только СВОИ (UserID) документы" +REQUEST_CONDITION_JOIN = "Оператор" +REQUEST_CONDITION_SAVE = "Сохранить условия" +REQUEST_CONDITION_ADD = "Добавить условие" + +REQUEST_SUCCESS = "Выполнено" +REQUEST_ERROR = "Ошибка" +REQUEST_CANCEL = "Отменить" + +REQUEST_SORTED = "Порядок успешно сохранён" +REQUEST_COND_MESSAGE = "Условия запроса отсутсвуют" +REQUEST_COND_VALUE_ERR = "Пустое поле Значение" +REQUEST_COND_NEW_ERR = "Не удалось добавить новое условие
Попробуйте еще раз" +REQUEST_COND_NEW_SUC = "Условие успешно добавлено" +REQUEST_COND_POST_OK = "Условия успешно сохранены" +REQUEST_COND_POST_ERR = "Не удалось сохранить условия запроса
Попробуйте еще раз" +REQUEST_COND_NO_POST = "Нет данных для сохранения
Попробуйте еще раз" + +REQUEST_COND_ADD_SUC = "Добавил условия запроса" +REQUEST_COND_CHA_SUC = "Изменил условия запроса" +REQUEST_COND_DEL_SUC = "Удалил условия запроса" +REQUEST_SAVE_CHA_SUC = "Отредактировал запрос" +REQUEST_ADD_NEW_SUC = "Добавил новый запрос" +REQUEST_DELETE_SUC = "Удалил запрос" +REQUEST_COPY_SUC = "Создал копию запроса" + +REQUEST_HEADER_SELF = "Основные параметры запроса" +REQUEST_HEADER_NAME = "Значение" +REQUEST_HEADER_PARAMETR = "Параметр" + +REQUEST_REPORT_ERR_TITLE = "Отсутствует наименование запроса" +REQUEST_REPORT_ERR_TEXT = "Отсутствует основной шаблон оформления запроса" +REQUEST_REPORT_ERR_PHP = "Запрещено использовать PHP код" +REQUEST_REPORT_ERR_PHP_N = "Попытка использования PHP кода в шаблоне запроса при создании запроса" +REQUEST_REPORT_ERR_PHP_E = "Попытка использования PHP кода в шаблоне запроса" +REQUEST_REPORT_ERR_RUBRIC= "Не выбрана рубрика" +REQUEST_BY_PARENT = "Родительскому документу" +REQUEST_SHOW_STAT = "Показать статистику" + +// v 3.1.9 +REQUEST_ALIAS = "Алиас" +REQUEST_I = "Опционально. Алиас позволяет использовать легко запоминающийся тег [tag:request:alias] вместо [tag:request:id]. Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание, иметь длину не более 20 символов и быть уникальным в пределах модуля" +REQUEST_ACCEPT = "Этот алиас можно использовать" +REQUEST_ER_SYN = "Неверный алиас!
Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание и иметь длину не более 20 символов" +REQUEST_ER_EXISTS = "Неверный алиас!
Данный алиас уже привязан к другому запросу" +REQUEST_HEADER_EXTERNAL = "Внешнее обращение" +REQUEST_EXTERNAL = "Разрешить внешнее обращение" +REQUEST_ONLY_AJAX = "Выполнять только по Ajax" + +// v 3.2 +REQUEST_PAGINATION = "Постраничная навигация" +REQUEST_NAVI_TPL = "Шаблон постраничной навигации" +REQUEST_OTHER = "Прочее" +REQUEST_SHOW_SQL = "Показать SQL запрос" +REQUEST_DOC_ON_PAGE = "Число элементов запроса на странице" +REQUEST_PAGES_CURENT = "Номер страницы пагинации" +REQUEST_PAGES_TOTAL = "Общее кол-во страниц пагинации" + +// v 3.24 +REQUEST_COUNT_ITEMS = "Выводить в тег [tag:doctotal] кол-во элементов, когда не используется постраничная навигация" + +// v 3.26 +REQUEST_BY_POSITION = "Позиция документа" + +// v 4.0 +REQUEST_SORT_TITEL = "Сортировка вывода запросов по параметрам или полям документа. Количество запросов на одной странице" +REQUEST_SORT_BY_I = "Сортировка по параметру документа возможна только тогда, когда в выпадающем списке 'Сортировать по полю документа' выбрано пустое значение." +REQUEST_SORT_BY_I_2 = "Сортировка по полю документа работает после выбора любого, кроме пустого значения, значение выбранное в выпадающем списке 'Сортировка по параметру документа' будет игнорироваться." +REQUEST_LINK = "Запрос доступен по ссылке: " +REQUEST_LINK_I = "Разрешив этот параметр, вы получите доступ к запросу по прямой ссылке. После сохранения, обновите страницу для получения ссылки к запросу." +REQUEST_CONTROL_FIELD = "Системный тег отвечающий за вывод в публичной части сайта панели управления запросом. Только для рубрик с полями типа выпадающий список. Использование:
Cоздайте в рубрике поле выпадающий список и в шаблоне поля установите значения по умолчанию через запятую, например 1,2,3 .
Создайте три документа , принадлежащим этой рубрике, и в каждом документе в поле выпадающий список выберете уникальное значение из этого списка для каждого документа.
Создайте запрос, использующий эту рубрику и в Основном шаблоне оформления запроса вставьте тег [tag:dropdown:ХХХ], параметр ХХХ это Id этого поля, он определится автоматически.
Теперь, при выводе запроса, вам станет досупен в публичной части выпадающий список, в котором будет доступен выбор вариантов 1,2,3 , которые в свою очередь выведут документы которым они принадлежат.
Шаблон публичной формы с выпадающим списком находится в корневом каталоге/templates/default/tpl/request/public.tpl" \ No newline at end of file diff --git a/admin/lang/ru/rubs.txt b/admin/lang/ru/rubs.txt new file mode 100644 index 0000000..31c66da --- /dev/null +++ b/admin/lang/ru/rubs.txt @@ -0,0 +1,326 @@ +[rubs] +RUBRIK_SUB_TITLE = "Управление рубриками" +RUBRIK_TIP = "В данном разделе приведен список всех рубрик в системе. Здесь вы можете отредактировать шаблон рубрики, права доступа, удалить рубрику, а также скопировать рубрику, чтобы создать на ее основе новую." +RUBRIK_ID = "ID" +RUBRIK_NAME = "Название рубрики" +RUBRIK_NAME2 = "Название рубрики:" +RUBRIK_TEMPLATE_OUT = "Использовать в шаблоне" +RUBRIK_TEMPLATE_OUT2 = "Использовать в шаблоне:" +RUBRIK_URL_PREFIX = "Префикс для ссылок" +RUBRIK_URL_PREFIX2 = "Префикс для ссылок:" +RUBRIK_DOCS_VI = "Отображать документы в списке" +RUBRIK_URL_PREFIX2 = "Префикс для ссылок:" +RUBRIK_COUNT_DOCS = "Кол-во документов" +RUBRIK_COUNT_FIELDS = "Кол-во полей" +RUBRIK_AUTHOR = "Автор" +RUBRIK_ACTION = "Действия" +RUBRIK_FORMAT = "Используйте" +RUBRIK_FORMAT_TIME = "для ссылок в формате времени" +RUBRIK_FORMAT_ID = "для вставки id документа" +RUBRIK_EDIT = "Редактировать поля и права рубрики" +RUBRIK_EDIT_TMPLS = "Дополнительные шаблоны" +RUBRIK_NO_VIEW = "Извините, но Вы не имеете прав на просмотр списка рубрик." +RUBRIK_NO_CHANGE1 = "Извините, но Вы не имеете прав на редактирование полей рубрики." +RUBRIK_NO_CHANGE2 = "Извините, но Вы не имеете прав на редактирование шаблона данной рубрики." +RUBRIK_NO_CHANGE3 = "Извините, но Вы не имеете прав на создание новых рубрик." +RUBRIK_EDIT_TEMPLATE = "Редактировать шаблон рубрики" +RUBRIK_EDIT_CODE = "Редактировать исполняемый код для рубрик" +RUBRIK_EDIT_CODE_T = "Редактирование исполняемого кода для рубрик" +RUBRIK_EDIT_CODE_NO = "Нет доступа для редактирования исполняемого кода" +RUBRIK_DELETE = "Удалить данную рубрику" +RUBRIK_DELETE_LEGEND = "Удалить рубрику" +RUBRIK_DELETE_CONFIRM = "Вы уверены, что хотите удалить данную рубрику?" +RUBRIK_NO_PERMISSION = "Извините, но вы не имеете прав на удаление рубрик." +RUBRIK_USE_DOCUMENTS = "Извините, но вы не можете удалить данную рубрику, т.к. в ней содержатся документы." +RUBRIK_MULTIPLY = "Копировать рубрику" +RUBRIK_NO_MULTIPLY = "Извините, но вы не имеете прав на копирование рубрик" +RUBRIK_BUTTON_SAVE = "Сохранить изменения" +RUBRIK_BUTTON_TEMPL = "Редактировать шаблон" +RUBRIK_BUTTON_FIELDS = "Редактировать поля" +RUBRIK_BUTTON_CODE = "Редактировать код рубрики" +RUBRIK_LEGEND = "Значения пиктограмм" +RUBRIK_NEW = "Создание новой рубрики" +RUBRIK_NEW_TIP = "В данном разделе вы можете создать новую рубрику. Пожалуйста, укажите название новой рубрики и выберите шаблон для вывода." +RUBRIK_BUTTON_NEW = "Создать рубрику" + +RUBRIK_DESCRIPTION = "Описание рубрики" +RUBRIK_NO_FIELDS = "Внимание! Вы не создали ни одного поля. Пожалуйста, добавьте хотя бы одно поле." +RUBRIK_FIELDS_INFO = "В данном разделе вы можете создать группу полей, которые будут использованы для документов в данной рубрике." +RUBRIK_MULTIPLY2 = "Копирование рубрики" +RUBRIK_MULTIPLY_TIP = "Пожалуйста, укажите название и префикс для ссылок новой рубрики" +RUBRIK_BUTTON_COPY = "Копировать" +RUBRIK_TEMPLATE_EDIT = "Редактирование шаблона рубрики" +RUBRIK_TEMPLATE_NEW = "Создание шаблона рубрики" +RUBRIK_TEMPLATE_SAVED = "Шаблон успешно сохранен" +RUBRIK_NO_FIELD = "В данной рубрике отсутсвуют поля" +RUBRIK_FIELD_NAME = "Название поля" +RUBRIK_FIELD_GROUP = "Группа" +RUBRIK_FIELD_GROUP_SEL = "Выберите группу" +RUBRIK_FIELD_ALIAS = "Алиас поля" +RUBRIK_FIELD_TYPE = "Тип поля" +RUBRIK_FIELD_UNKNOW = "Неизвестно" +RUBRIK_FIELD_G_UNKNOW = "Без группы" +RUBRIK_POSITION = "Позиция" +RUBRIK_NEW_FIELD = "Создание нового поля для рубрики" +RUBRIK_BUTTON_ADD = "Добавить поле" +RUBRIK_SET_PERMISSION = "Права доступа к документам для групп пользователей" +RUBRIK_USER_GROUP = "Группа" +RUBRIK_DOC_READ = "Просмотр" +RUBRIK_ALL_PERMISSION = "Все права" +RUBRIK_CREATE_DOC = "Создавать с проверкой" +RUBRIK_CREATE_DOC_NOW = "Создавать без проверки" +RUBRIK_EDIT_OWN = "Редактировать свои" +RUBRIK_EDIT_DELREV = "Управление ревизиями" +RUBRIK_EDIT_OTHER = "Редактировать все" +RUBRIK_VIEW_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей просмотр документов" +RUBRIK_ALL_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей выполнять любые действия с документами в данной рубрике." +RUBRIK_DOC_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей создавать документы.
Внимание!
Перед публикацией документа, он должен быть проверен Администратором" +RUBRIK_DOC_NOW_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей создавать документы.
Внимание!
Публикация документа будет осуществелена без проверки Администратора." +RUBRIK_OWN_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей редактировать только свои документы" +RUBRIK_OTHER_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей редактировать свои и чужие документы" +RUBRIK_DELREV_TIP = "Установите флажок, если вы хотите рарешить данной группе пользователей работать с ревизиями документов" +RUBRIK_BUTTON_PERM = "Сохранить права" +RUBRIK_FIELD_DEFAULT = "Значение по умолчанию" +RUBRIK_TEMPLATE_TIP = "В данном разделе, используя язык разметки HTML, вы должны создать шаблон оформления для документов при полном просмотре," +RUBRIK_HTML = "Шаблон оформления рубрики" +RUBRIK_HTML_2 = "Шаблон оформления HEADER" +RUBRIK_HTML_2_1 = "Шаблон оформления FOOTER" +RUBRIK_HTML_3 = "Шаблон оформления TEASER" +RUBRIK_HTML_4 = "Шаблон оформления ADMIN TEASER" +RUBRIK_PHP_DENIDED = "Ошибка!
Вы не имеете прав на редактирование шаблона рубрики, так как он используется PHP код, а вы не имеете прав на использование PHP кода." +RUBRIK_PHP_MESSAGE = "Запрещено использовать PHP код." +RUBRIK_EMPTY_MESSAGE = "Не задано наименование поля." +RUBRIK_INSERT_HELP = "Нажмите, чтобы добавить системный тег в шаблон" +RUBRIK_BUTTON_TPL = "Сохранить шаблон" +RUBRIK_BUTTON_TPL_NEXT = "Применить (CTRL+S)" +RUBRIK_BUTTON_TPL_CLOSE = "Закрыть" +RUBRIK_NO_RUBRIK = "Нет такой рубрики!" +RUBRIK_NO_NAME = "Пожалуйста, укажите название рубрики" +RUBRIK_NAME_EXIST = "Извините, но рубрика с таким названием уже существует. Пожалуйста, укажите другое название рубрики." +RUBRIK_PREFIX_EXIST = "Извините, но рубрика с таким URL-префиксом уже существует. Пожалуйста, укажите другой URL-префикс рубрики." +RUBRIK_VIEWS_INFO = "Системный тег, отображающий количество просмотров для документа" +RUBRIK_HIDE_INFO = "Системный тег, позволяющий скрыть текст для определенных групп пользователей, где Х - номер группы" +RUBRIK_THUMBNAIL = "Тег отвечает за создание миниатюрки (При условии что в шаблоне поля рубрики (шаблон для вывода в документе) выбран вывод: [tag:parametr:0])" +RUBRIK_LINK_HOME = "Ссылка на главную страницу сайта" +RUBRIK_MARK_DELETE = "Отметить данный пункт для удаления" +RUBRIK_MARK_DEL_ALL = "Отметить все" +RUBRIK_CHECK_SEARCH = "Искать по этому полю" +RUBRIK_CHECK_NUMERIC = "Числовое поле" +RUBRIK_SEARCH_TIP = "Отметьте поле, если хотите, чтобы по нему осуществлялся поиск (работает с модулем 'Поиск' версии 2.0.2 и выше)" +RUBRIK_NUMERIC_TIP = "Отметьте поле, если его значения всегда числовые. Используется в запросах для сортировки" +RUBRIK_ALL = "Список рубрик" +RUBRIK_EDIT_FIELDS_GROUPS = "Редактировать группы полей" +RUBRIK_FIELDS_GROUPS = "Группы полей" +RUBRIK_ENTER_NAME = "Пожалуйста, укажите название рубрики." +RUBRIK_TEMPLATE_HIDE = "Показать/свернуть шаблоны всех полей" +RUBRIK_FILED_TEMPLATE_H = "Редактировать шаблон и описание поля" +RUBRIK_FILED_TEMPLATE_DESCR = "Описание поля" +RUBRIK_FILED_TEMPLATE_F = "Шаблон поля" +RUBRIK_DOCID_INFO = "Системный тег, идентификатор документа" +RUBRIK_DOCDATE_INFO = "Системный тег, дата публикации документа" +RUBRIK_DOCTIME_INFO = "Системный тег, дата и время публикации документа" +RUBRIK_DATE_INFO = "Системный тег, дата и время публикации документа - Настраиваемый вид.
Пример: [tag:date:Y]" +RUBRIK_DOCAUTHOR_INFO = "Системный тег, автор документа" +RUBRIK_TITLE_INFO = "Системный тег, заголовка документа" +RUBRIK_PATH_INFO = "Системный тег, путь к корню установки" +RUBRIK_MEDIAPATH_INFO = "Системный тег, путь к папке дизайна" +RUBRIK_PREFIX_BAD_CHAR= "Недопустимые символы в префиксе" +RUBRIK_FIELDS_TITLE = "Поля рубрики" +RUBRIK_FIELDS_TPL = "Шаблон вывода поля в документе" +RUBRIK_RUBRIK_TPL = "Шаблон вывода поля в запросе" +RUBRIK_SORTED = "Порядок успешно сохранён" +RUBRIK_F_SORT_TIP = "Для упорядочивания полей нажмите на крестик и, удерживая его, перетащите поле" +RUBRIK_R_SORT_TIP = "Для упорядочивания рубрик нажмите на крестик и, удерживая его, перетащите поле" +RUBRIK_META_GEN_TIP = "Автоматически генерировать keywords, description для документа, на основе его контента" +RUBRIK_ALIAS_HISTORY_TIP = "Сохранять историю алиасов у документов" +RUBRIK_MOVE = "Переместить" +RUBRIK_REQUEST_TPL = "Шаблон вывода поля в запросе" +RUBRIK_BREADCRUMB = "Систменый тег Хлебных крошек" +RUBRIK_CODE = "Исполняемый код для рубрик" +RUBRIK_START_CODE = "Код, выполняемый перед показом документа в публичной части" +RUBRIK_CODE_START = "Код, выполняемый ПЕРЕД сохранением документа" +RUBRIK_CODE_END = "Код, выполняемый ПОСЛЕ сохранения документа" +RUBRIK_TAGS = "Тег" +RUBRIK_TAGS_ID = "Тег ID" +RUBRIK_TAGS_ALIAS = "Тег Алиас" +RUBRIK_HTML_T = "HTML код шаблона" +RUBRIK_TAG_DESC = "Описание тега" +RUBRIK_NEW_FIEL_TITLE = "Для полей Выпадающий список и Мульти список, Значение по умолчанию пишутся через запятую" +RUBRIK_LINK = "Связать рубрику" +RUBRIK_LINK_DESC = "Задавая связь между рубриками, при добавлении документов можно автоматически подставлять алиасы." +RUBRIK_NOLINK = "Не выбрано" +RUBRIK_OR = " или " + +RUBRIC_F_GROUP_TITLE = "Наименование группы" +RUBRIC_F_GROUP_DELETE = "Удалить группу" +RUBRIC_F_GROUP_DELETE_H = "Вы уверены, что хотите удалить группу?" +RUBRIC_NO_GROUPS = "В настоящий момент, для данной рубрики, нет групп полей" +RUBRIC_GROUP_ADD = "Добавить группу" +RUBRIK_NEW_GROUP = "Добавить новую группу" +RUBRIK_HEADER_GROUP = "Управление группами полей" + +RUBRIK_TEMPLATES_TAGS = "Тег" +RUBRIK_TEMPLATES_TAG_DESC = "Описание тега" +RUBRIK_TEMPLATES_THEME_FOLDER = "Наименование шаблона (Имя папки с файлами для данного шаблона)" +RUBRIK_TEMPLATES_PAGENAME = "Наименование сайта" +RUBRIK_TEMPLATES_TITLE = "Наименование страницы" +RUBRIK_TEMPLATES_KEYWORDS = "Ключевые слова (Meta - Keywords)" +RUBRIK_TEMPLATES_DESCRIPTION = "Описание страницы (Meta - Description)" +RUBRIK_TEMPLATES_INDEXFOLLOW = "Тип индексирования" +RUBRIK_TEMPLATES_PATH = "Корневой путь установки" +RUBRIK_TEMPLATES_MEDIAPATH = "Путь до папки с шаблоном (Пример: [tag:mediapath]images/logo.gif)" +RUBRIK_TEMPLATES_CSS = "Сжимает несколько css-файлов в один. Возвращает путь.
FFF - имена файлов через запятую
P - путь к папке с файлами, не обязательно. По умолчанию - [tag:mediapath]css/

Пример: href="[tag:css:reset.css,style.css]"" +RUBRIK_TEMPLATES_JS = "Сжимает несколько js-файлов в один. Возвращает путь.
FFF - имена файлов через запятую
P - путь к папке с файлами, не обязательно. По умолчанию - [tag:mediapath]js/

Пример: href="[tag:js:common.js,main.js]"" + +RUBRIK_RUB_INFO = "Системный тег отвечающий за вывод содержимого поля рубрики. ID-номер поля. ХХХ-количество символов для отображения." +RUBRIK_SELECT_IN_LIST = "Пожалуйста, выберите поле рубрики из списка, приведенного ниже" +RUBRIK_TEMPLATE_ITEMS = "Шаблон оформления для элементов запроса" +RUBRIK_DOCID_INFO = "Системный тег, соответствующий идентификатору документа" +RUBRIK_DOCTITLE_INFO = "Системный тег, соответствующий имени документа" +RUBRIK_CDOCID_INFO = "Системный тег, соответствующий идентификатору текущего документа(в котором выводится запрос)" +RUBRIK_DOCDATE_INFO = "Системный тег, соответствующий дате публикации документа" +RUBRIK_CDOCDATE_INFO = "Системный тег, соответствующий дате публикации текущего документа(в котором выводится запрос)" +RUBRIK_DOCTIME_INFO = "Системный тег, соответствующий дате и времени публикации документа" +RUBRIK_CDOCTIME_INFO = "Системный тег, соответствующий дате и времени публикации текущего документа(в котором выводится запрос)" +RUBRIK_DATE_INFO = "Системный тег, дата и время публикации документа - Настраиваемый вид.
Пример: [tag:date:d.m.Y]
Можно исрльзовать разделители (space - . /)" +RUBRIK_CDATE_INFO = "Системный тег, дата и время публикации документа - Настраиваемый вид.
Пример: [tag:date:d.m.Y]
(в котором выводится запрос)
Можно исрльзовать разделители (space - . /)" +RUBRIK_DOCAUTHOR_INFO = "Системный тег, соответствующий автору документа" +RUBRIK_DOCAUTHOR_AVATAR = "Системный тег, соответствующий аватаре автора документа" +RUBRIK_CDOCAUTHOR_INFO = "Системный тег, соответствующий автору текущего документа(в котором выводится запрос)" +RUBRIK_VIEWS_INFO = "Системный тег отображающий количество просмотров для документа" +RUBRIK_COMMENTS_INFO = "Системный тег отображающий количество комментариев для документа. Внимание! Работает только при установленном модуле!" +RUBRIK_PATH = "Системный тег определяющий корень установки" +RUBRIK_MEDIAPATH = "Системный тег определяющий путь до папки с шаблоном (Например: [tag:mediapath]images/logo.gif)" +RUBRIK_THUMBNAIL = "Тег отвечает за создание миниатюрки (При условии что в шаблоне поля рубрики (шаблон для вывода в запросе) выбран вывод: [tag:parametr:0])" + +RUBRIK_ALIAS_HEAD = "Назначение алиса для поля" +RUBRIK_ALIAS_HEAD_T = "Можно использовать только латинские символы и цифры!
Пример: header" +RUBRIK_ALIAS_HEAD_R = "Рубрика:" +RUBRIK_ALIAS_HEAD_F = "Поле:" +RUBRIK_ALIAS_ALIAS = "Алиас поля" +RUBRIK_ALIAS_NAME = "Наименование алиаса" +RUBRIK_ALIAS_BUTT = "Сохранить" + +RUBRIK_ALIAS_ERROR = "Ошибка:" +RUBRIK_ALIAS_RUBID = "Неверно указана рубрика" +RUBRIK_ALIAS_FIELDID = "Неверно указано поле" +RUBRIK_ALIAS_MATCH = "Неверно указано значение" +RUBRIK_ALIAS_USED = "Данное значение уже используется" + +RUBRIK_REPORT_QUICKSAVE = "Выполнил быстрое сохранение настроек рубрик" +RUBRIK_REPORT_SORTE = "Выполнил сортировку рубрик" +RUBRIK_REPORT_SORTE_FIELDS = "Выполнил сортировку полей рубрики" +RUBRIK_REPORT_PERMISION = "Изменил права доступа к документам рубрики" +RUBRIK_REPORT_COPY = "Создал копию рубрики" +RUBRIK_REPORT_TEMPL_RUB = "Отредактировал шаблон рубрики" +RUBRIK_REPORT_FIELD_EDIT = "Отредактировал поле" +RUBRIK_REPORT_FIELD_DEL = "Удалил поле" +RUBRIK_REPORT_RUB = "рубрики" + +RUBRIK_REP_QUICKSAVE_H = "Выполнено" +RUBRIK_REP_QUICKSAVE_T = "Настройки рубрик успешно сохранены" + +RUBRIK_REPORT_ADD = "Добавил рубрику" +RUBRIK_REPORT_SAVE_TPL = "Сохранил шаблон оформления рубрики" + +RUBRIK_CODE_SAVED = "Исполняемый код для рубрики успешно сохранен" +RUBRIK_CODE_SAVED_ERR = "Не удалось сохранить исполняемый код для рубрики.
Попробуйте еще раз." +RUBRIK_CODE_ERROR = "Ошибка" +RUBRIK_CODE_SUCCESS = "Выполнено" +RUBRIK_CODE_UPDATE = "Изменил исполняемый код для рубрики" + +RUBRIK_LOG_NEW_FIELD = "Добавил поле рубрики" +RUBRIK_LOG_DEL_RUBRIC = "Удалил рубрику" +RUBRIK_LOG_NEW_RUBRIC = "Создал рубрику" + +RUBRIK_FILDS_SAVED = "Успешно сохранено" +RUBRIK_FILD_SAVED = "Поле успешно добавлено" +RUBRIK_FILDS_REPORT = "Сохранил поля рубирки" +RUBRIK_FILDS_ERROR = "Ошибка" +RUBRIK_FILDS_SUCCESS = "Выполнено" + +RUBRIC_ERROR = "Ошибка" +RUBRIC_SUCCESS = "Выполнено" +RUBRIC_SAVED_PHP_ERR = "Запрещено использовать в шаблонах PHP код" +RUBRIC_SAVED_TPL_ERR = "Не удалось сохранить шаблон рубрики.
Попробуйте еще раз." +RUBRIC_SAVED_TPL = "Шаблон рубрики успешно сохранен." +RUBRIC_SAVED_FLDTPL = "Шаблон поля успешно сохранен." +RUBRIK_TAG_SYSBLOCK = "Системный тег вывода системного блока" +RUBRIK_TAG_TEASER = "Системный тег вывода тизера" +RUBRIK_TAG_ALIAS = "Системный тег вывода алиаса документа" +RUBRIK_TAG_REQUEST = "Системный тег вывода запроса" +RUBRIC_SAVED_PERMS = "Права доступа к документам успешно сохранены " +RUBRIK_IFELSE = "Условия" +RUBRIK_IFELSE_1 = "выводим если поле непустое" +RUBRIK_IFELSE_2 = "иначе выводим если поле пустое" +RUBRIK_SAMPLE = "Пример" +RUBRIK_TAG_DOCDB = "Системный тег вывода поля документа из БД" +RUBRIK_TAG_LANGFILE = "Системный тег для вывода языковой переменной из файла" + +RUBRIC_TMPLS_BUTTON = "Дополнительные шаблоны рубрики" +RUBRIC_TMPLS_HEAD = "Список дополнительных шаблонов рубрики" +RUBRIC_TMPLS_ADD = "Добавить новый шаблон" +RUBRIC_TMPLS_ID = "id" +RUBRIC_TMPLS_NAME = "Наименование" +RUBRIC_TMPLS_NAME_FULL = "Наименование шаблона оформления рубрики" +RUBRIC_TMPLS_AUTHOR = "Автор" +RUBRIC_TMPLS_DATE = "Дата" +RUBRIC_TMPLS_COUNT_DOCS = "Кол-во документов" +RUBRIC_TMPLS_ACTIONS = "Действия" +RUBRIC_TMPLS_COPY = "Копировать шаблон" +RUBRIC_TMPLS_COPY_TIP = "Пожалуйста, укажите наименование шаблона" +RUBRIC_TMPLS_COPY_TIP2 = "Пожалуйста, укажите наименование для копируемого шаблона" +RUBRIC_TMPLS_EDIT = "Редактировать" +RUBRIC_TMPLS_DELETE = "Удалить" +RUBRIC_TMPLS_DELETE_C = "Вы уверены, что хотите удалить шаблон?" +RUBRIC_TMPLS_TIP = "Вы можете создавать неограниченное кол-во шаблонов для одной рубрики" +RUBRIC_TMPLS_NO_ITEMS = "Сообщение:
В настоящий момент нет дополнительных шаблонов." +RUBRIC_TMPLS_FROM = "Создать копию основного шаблона" +RUBRIC_TMPLS_INNAME = "Введите наименование шаблона" +RUBRIC_TEMPL_REPORT = "Отредактировал дополнительный шаблон рубрики" +RUBRIC_TMPLS_LOG_DEL = "Удалил дополнительный шаблон рубрики" + +// 3.24 +RUBRIC_WARNING_TIP = "Внимание! Пожалуйста, будьте предельно внимательны и помните, что неверные параметры могут сделать систему неработоспособной." + +RUBRIK_EDIT_FIELDS = "Управление полями" +RUBRIK_EDIT_RULES = "Управление правами доступа к рубрике" + +RUBRIC_TABLE_BTN_FIELDS = "Поля рубрики" +RUBRIC_TABLE_BTN_FTEMPLATES = "Шаблоны полей" +RUBRIC_TABLE_BTN_FGROUPS = "Группы полей" +RUBRIC_TABLE_BTN_TEMPLATES = "Шаблон рубрики" +RUBRIC_TABLE_BTN_CODE = "Исполняемый код" +RUBRIC_TABLE_BTN_RULES = "Права доступа" + +RUBRIK_EDIT_CODE_TIP = "Внимание! Пожалуйста, будьте предельно внимательны и помните, что неверные параметры могут сделать систему неработоспособной." +RUBRIK_EDIT_CODE_LOAD_TIP = "Доступ к данным:
$this->curentdoc - Данные документа, перед подстановкой их в шаблон вывода" +RUBRIK_EDIT_CODE_BEF_TIP = "Доступ к данным:
$data - Все данные документа
$data['feld'] - Данные полей документа
$rubric_id - ID рубрики" +RUBRIK_EDIT_CODE_AFT_TIP = "Доступ к данным:
$data - Все данные документа
$rubric_id - ID рубрики
$document_id - ID документа - Число или False" + +RUBRIK_FIELDS_TEMPLATES_H1 = "Управление шаблонами полей" +RUBRIK_FIELDS_TEMPLATES_H2 = "Шаблоны полей" +RUBRIK_FIELDS_TEMPLATES_T1 = "Создавать/Редактировать/Удалять шаблоны полей (tpl)" +RUBRIK_FIELDS_TEMPLATES_T2 = "Редактировать шаблоны вывода полей" +RUBRIK_FIELDS_TEMPLATES_LIST = "Список типов полей используемых в рубрике" +RUBRIK_FIELDS_TEMPLATES_FNAME = "Наименование поля" +RUBRIK_FIELDS_TEMPLATES_FFUNC = "Функция" +RUBRIK_FIELDS_TEMPLATES_FTEMP = "Шаблон .tpl (по умолчанию)" +RUBRIK_FIELDS_TEMPLATES_FTEMPL = "Шаблон .tpl по ID поля" +RUBRIK_FIELDS_TEMPLATES_PANEL = "Панель" +RUBRIK_FIELDS_TEMPLATES_DOC = "Документ" +RUBRIK_FIELDS_TEMPLATES_REQ = "Запрос" +RUBRIK_FIELDS_TEMPLATES_DB = "База данных" +RUBRIK_FIELDS_TEMPLATES_BACK = "К списку типов полей" +RUBRIK_FIELDS_NO_TEMPLATES = "Нет шаблона" +RUBRIK_FIELDS_EDIT_RUBRIC = "Рубрика" +RUBRIK_FIELDS_EDIT_FIELD = "Поле:" +RUBRIK_FIELDS_EDIT_TYPE = "Тип:" +RUBRIK_FIELDS_EDIT_TPL_ADM = "Шаблон для панели" +RUBRIK_FIELDS_EDIT_TPL_DOC = "Шаблона вывода в документе" +RUBRIK_FIELDS_EDIT_TPL_REQ = "Шаблона вывода в запросе" +RUBRIK_FIELDS_EDIT_TPL_CREAT = "Создание шаблона из основного файла" +RUBRIK_FIELDS_EDIT_TPL_EDIT = "Редактирование шаблона" +RUBRIK_FIELDS_EDIT_NO_TPL = "Отсутсвует основной файл шаблона" +RUBRIC_TMPLS_CREAT = "Создать" +RUBRIC_TMPLS_DELETE = "Удалить" \ No newline at end of file diff --git a/admin/lang/ru/scripts.js b/admin/lang/ru/scripts.js new file mode 100644 index 0000000..499182e --- /dev/null +++ b/admin/lang/ru/scripts.js @@ -0,0 +1,64 @@ +var logoutTitle = "Выход из панели управления"; +var logoutConfirm = "Вы уверены, что хотите выйти?"; +var clearCacheTitle = "Очистка кэша"; +var clearCacheConfirm = "Вы уверены, что хотите очистить кэш?"; +var clearCacheSessTitle = "Очистка кэша и сессий"; +var clearCacheSessConfirm = "Вы уверены, что хотите очистить кэш и сессии?"; +var clearThumbTitle = "Удаление миниатюр"; +var clearThumbConfirm = "Вы уверены, что хотите удалить все миниатюры изображений
из директории для хранения файлов (UPLOAD_DIR)?"; +var clearRevTitle = "Удаление ревизий документов"; +var clearRevConfirm = "Вы уверены, что хотите удалить все ревизии документов?"; +var clearCountTitle = "Обнулить подневный счетчик документов"; +var clearCountConfirm = "Вы уверены, что хотите обнулить подневный счетчик документов?"; +var cacheShowTitle = "Показать размер кеша"; +var cacheShowConfirm = "Вы уверены, что хотите посмотреть размер кэша?
Это может занять какое-то время."; +var docsShowTitle = "Показать количество документов"; +var docsShowConfirm = "Вы уверены, что хотите посмотреть количество документов?
Это может занять какое-то время."; +var ajaxErrorStatus = "Нет соеденения.
Проверьте свое подключение."; +var ajaxErrorStatus404 = "Запрашиваемая страница не найдена. [404]"; +var ajaxErrorStatus401 = "Запрос не может быть выполнен.
Ошибка авторизации для выполнения этого запроса. [401]"; +var ajaxErrorStatus500 = "Произошла внутреняя ошибка.
Попробуйте повторить свой запрос позже. [500]"; +var ajaxErrorStatusJSON = "Некорректный ответ сервера
Данные не в формате JSON."; +var ajaxErrorStatusTimeOut = "Вермя запроса вышло."; +var ajaxErrorStatusAbort = "Ajax запрос прерван."; +var ajaxErrorStatusMess = "Ошибка:
"; +var delCascadTitle = "Удалить изображение"; +var delCascadConfirm = "Вы уверены что хотите удалить?"; +var saveMessageOk = "Данные сохранены"; + +//===== Date & Time Pickers =====// +$.datepicker.regional['ru'] = { + closeText: 'Закрыть', + prevText: '<Пред', + nextText: 'След>', + currentText: 'Сегодня', + monthNames: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', + 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' + ], + monthNamesShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', + 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек' + ], + dayNames: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'], + dayNamesShort: ['вск', 'пнд', 'втр', 'срд', 'чтв', 'птн', 'сбт'], + dayNamesMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], + weekHeader: 'Не', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: '' +}; +$.datepicker.setDefaults($.datepicker.regional['ru']); + +$.timepicker.regional['ru'] = { + timeOnlyTitle: 'Выберите время', + timeText: 'Время', + hourText: 'Часы', + minuteText: 'Минуты', + secondText: 'Секунды', + millisecText: 'миллисекунды', + currentText: 'Теперь', + closeText: 'Закрыть', + ampm: false +}; +$.timepicker.setDefaults($.timepicker.regional['ru']); \ No newline at end of file diff --git a/admin/lang/ru/settings.txt b/admin/lang/ru/settings.txt new file mode 100644 index 0000000..bee7f45 --- /dev/null +++ b/admin/lang/ru/settings.txt @@ -0,0 +1,188 @@ +[settings] +SETTINGS_COUNTRIES = "Управление странами" +SETTINGS_COUNTRIES_ALL = "Список стран" +SETTINGS_COUNTRY_TIP = "Пожалуйста, выберите страны, которые будут доступны для выбора при регистрации новых пользователей в системе. Помните, что выбранный вами список стран может быть использован другими модулями в системе." +SETTINGS_ACTIVE = "Активна?" +SETTINGS_COUNTRY_NAME = "Название страны" +SETTINGS_IN_EC = "Относится к ЕС?" +SETTINGS_YES = "Да" +SETTINGS_NO = "Нет" +SETTINGS_BUTTON_SAVE = "Сохранить изменения" +SETTINGS_BUTTON_SAVE_AJAX = "Применить (CTRL+S)" +SETTINGS_OR = "или" +SETTINGS_MAIN_TITLE = "Общие настройки системы" +SETTINGS_CASE_TITLE = "Дополнительные настройки" +SETTINGS_MAIN = "Общие настройки системы" +SETTINGS_SAVED = "Настройки системы успешно сохранены" +SETTINGS_SAVED_ERR = "Не удалось сохранить настройки.
Попробуйте еще раз." +SETTINGS_SAVE_INFO = "В данном разделе вы можете отредактировать глобальные параметры системы. Пожалуйста, будьте предельно внимательны и помните, что неверные параметры могут сделать систему неработоспособной." +SETTINGS_SAVE_CONFIRM = "Вы уверены, что хотите сохранить параметры системы?" +SETTINGS_SITE_NAME = "Название cайта:" +SETTINGS_SITE_COUNTRY = "Страна сайта:" +SETTINGS_EMAIL_SENDER = "E-mail отправителя:" +SETTINGS_EMAIL_NAME = "Имя отправителя E-mail:" +SETTINGS_MAIL_TRANSPORT = "Метод отправки почты:" +SETTINGS_MAIL = "mail" +SETTINGS_SENDMAIL = "sendmail" +SETTINGS_SMTP = "smtp" +SETTINGS_SMTP_SERVER = "Сервер SMTP:" +SETTINGS_MAIL_PORT = "Порт SMTP:" +SETTINGS_SMTP_NAME = "Пользователь:" +SETTINGS_SMTP_PASS = "Пароль:" +SETTINGS_SMTP_ENCRYPT = "Шифрование" +SETTINGS_SMTP_NOENCRYPT = "нет" +SETTINGS_MAIL_PATH = "Путь до папки sendmail:" +SETTINGS_SYMBOL_BREAK = "Принудительный перенос после (знаков):" +SETTINGS_SYMBOL_BREAK_INFO = "Не более 1000 согласно RFC 2822" +SETTINGS_SYMBOLS = "символов" +SETTINGS_TEXT_EMAIL = "Cообщение пользователю после создания аккаунта, где:" +SETTINGS_TEXT_INFO = "%NAME% - Имя пользователя
%HOST% - Cсылка на сайт
%PASSWORD% - Пароль
%EMAIL% - E-mail пользователя
%EMAILSIGNATURE% - Подпись сообщения" +SETTINGS_EMAIL_FOOTER = "Текст подписи:" +SETTINGS_ERROR_PAGE = "Страница с ошибкой HTTP 404: Page not found" +SETTINGS_PAGE_DEFAULT = "(по умолчанию Id:2)" +SETTINGS_TEXT_PERM = "Текст сообщения, если пользователь не имеет прав:" +SETTINGS_HIDDEN_TEXT = "Текст сообщения при отсутствии прав для просмотра информации скрытой тегом [tag:hide:X,X]...[/tag:hide]" + +SETTINGS_NAVI_BOX = "Контейнер постраничной навигации:
Пример: <ul>%s</ul>" +SETTINGS_LINK_BOX = "Контейнер для элементов постраничной навигации:
Пример: <li>%s</li>" +SETTINGS_TOTAL_BOX = "Контейнер для текста перед номерами страниц:
Пример: <span>%s</span>" +SETTINGS_ACTIVE_LINK_BOX= "Контейнер для активного элемента:
Пример: <span class="active">%s</span>" +SETTINGS_PAGE_SEPAR = "Контейнер для метки о наличии страниц:
Пример: <li>%s</li>" +SETTINGS_PAGE_BEFORE = "Текст перед номерами страниц:
Пример: Страница %d из %d" +SETTINGS_PAGE_START = "Текст ссылки "Первая":" +SETTINGS_PAGE_END = "Текст ссылки "Последняя":" +SETTINGS_PAGE_SEPARATOR = "Текст метки о наличии страниц кроме видимых:" +SETTINGS_PAGE_NEXT = "Текст ссылки "Следующая":" +SETTINGS_PAGE_PREV = "Текст ссылки "Предыдущая":" + +SETTINGS_MAIN_BREADCRUMBS = "Настройка вывода «хлебных крошек»" +SETTINGS_BREAD_BOX = "Контейнер «хлебных крошек»:
Пример: <ul class="breadcrumb">%s</ul>" +SETTINGS_BREAD_MAIN = "Показывать первый элемент: Главная страница:
Да/Нет" +SETTINGS_BREAD_HOST = "Добавлять адрес хоста в url:
Да/Нет" +SETTINGS_BREAD_SEPPARATOR = "Разделитель между ссылками:
Пример: <li> → </li>" +SETTINGS_BREAD_SEPP_USE = "Показывать:
Да/Нет" +SETTINGS_BREAD_BOX_LINK = "Контейнер для ссылки:
Пример: <li>%s</li>" +SETTINGS_BREAD_LINK_TPL = "Шаблон ссылки
Используются теги: [name], [link], [count]" +SETTINGS_BREAD_BOX_LASTLINK = "Показывать последний элемент:
Да/Нет" +SETTINGS_BREAD_SELF_BOX = "Контейнер для последнего элемента:
Пример: <li class="active">%s</li>" + + +SETTINGS_DATE_FORMAT = "Формат даты:" +SETTINGS_TIME_FORMAT = "Формат даты и времени:" +SETTINGS_CLEAR_CACHE = "Очистить кэш" +SETTINGS_USE_DOCTIME = "Использовать дату публикации документов" +SETTINGS_INFO = "Дополнительно" +SETTINGS_MAIN_SETTINGS = "Общие настройки системы" +SETTINGS_MAIN_MAIL = "Настройки почты" +SETTINGS_MAIN_PAGENAVI = "Настройки вывода постраничной навигации" +SETTINGS_NAME = "Параметр" +SETTINGS_VALUE = "Значение" +SETTINGS_EDITOR_CKEDITOR = "CKEditor" + +SETTINGS_ERROR = "Ошибка" +SETTINGS_SUCCESS = "Выполнено" + +SETTINGS_SAVE_DOP = "Изменил дополнительные настройки системы" +SETTINGS_SAVE_MAIN = "Изменил общие настройки системы" +SETTINGS_SAVE_COUNTRY = "Изменил настройки стран" + +SETTINGS_LANG_EDIT = "Управление языками" +SETTINGS_LANG_TITLE = "Внимание! Настройка языков должна происходить, строго перед наполнение сайта!" +SETTINGS_LANG_AEDIT = "Редактировать" +SETTINGS_LANG_AON = "Включить" +SETTINGS_LANG_AOFF = "Выключить" +SETTINGS_LANG_ADEFAULT = "Сделать по умолчанию" +SETTINGS_LANG_ADEFAULT_HINT = "" +SETTINGS_LANG_ID = "Id" +SETTINGS_LANG_FLAG = "Флаг" +SETTINGS_LANG_SYSTEM = "Системное" +SETTINGS_LANG_PREFIX = "Префикс" +SETTINGS_LANG_NAME = "Наименование" +SETTINGS_LANG_DEFAULT = "По умолчанию" +SETTINGS_LANG_ACTION = "Действия" +SETTINGS_LANG_ADD = "Добавить язык" +SETTINGS_LANG_SAVE = "Сохранить изменения" + +SETTINGS_REV_DELETED = "Ревизии документов успешно удалены" +SETTINGS_REV_DELETED_ERR = "Не удалось удалить ревизии документов.
Попробуйте еще раз." +SETTINGS_REV_UPDATE = "Удалил ревизии документов" +SETTINGS_COUNT_DELETED = "Подневный счетчик документов
успешно обнулён." +SETTINGS_COUNT_DELETED_ERR = "Не удалось обнулить подневный
счетчик документов.
Попробуйте еще раз." +SETTINGS_COUNT_UPDATE = "Обнулили подневный счетчик документов" +SETTINGS_CACHE_LIFETIME = "Внимание!!! Включено кеширование запроса к настройкам системы. Изменения вступят в силу, только после окончания времени жизни кеша или отключения кеширования" + +// v3.2 +SETTINGS_PAGINATION = "Настройка пагинации" +PAGINATION_ADD = "Создать шаблон пагинации" +PAGINATION_NAME = "Наименование" +PAGINATION_ACTIONS = "Действия" +PAGINATION_EDIT_HINT = "Редактирвать" +PAGINATION_DELETE_HINT = "Удалить пагинацию" +PAGINATION_DEL_HINT = "Вы уверены, что хотите удалить данный шаблон пагинацию?" +PAGINATION_SAVED = "Шаблон пагинации успешно сохранен" +PAGINATION_SAVED_ERR = "Не удалось сохранить шаблон пагинации.
Попробуйте еще раз." +PAGINATION_ERROR = "Ошибка" +PAGINATION_SUCCESS = "Выполнено" + +pagination_name = "Наименование" +pagination_navigation_box = "Контейнер постраничной навигации
Пример: <ul class="pagination pagination-sm">%s</ul>" +pagination_link_box = "Контейнер для элемента
Пример: <li>%s</li>" +pagination_active_link_box = "Контейнер для активного элемента
Пример: <li class="active">%s</li>" +pagination_link_template = "Шаблон ссылки элемента
[link] - ссылка на страницу
[page] - Номер страницы для ссылки
[name] - Номер страницы
" +pagination_link_active_template = "Шаблон активной ссылки элемента
[link] - ссылка на страницу
[page] - Номер страницы для ссылки
[name] - Номер страницы
" +pagination_separator_box = "Контейнер для метки о наличии страниц
Пример: <li>%s</li>" +pagination_separator_label = "Текст для метки о наличии страниц" +pagination_start_label = "Текст ссылки "Первая"" +pagination_end_label = "Текст ссылки "Последняя"" +pagination_next_label = "Текст ссылки "Следующая"" +pagination_prev_label = "Текст ссылки "Предыдущая"" + +// v3.24 +SETTINGS_SAVED_ERR_FILE = "Ошибка при сохранении файла. Попробуйте снова." +SETTINGS_SAVED_FILE = "Файл успешно сохранен." +SETTINGS_FILE_EDIT_H = "Редактирование файла" +SETTINGS_FILE_CONTENT = "Содержимое файла:" +SETTINGS_FILE_ROBOTS = "Файл robots.txt" +SETTINGS_FILE_CUSTOM = "Файл func.custom.php" + +// v3.25 +_const_auth = "Авторизация" +_const_url = "Формирование URL" +_const_themes = "Оформление" +_const_folders = "Папки" +_const_thumbs = "Генерация миниатюр" +_const_watermarks = "Водяные знаки" +_const_sessions = "Session и Cookie" +_const_dev = "Разработка" +_const_smarty = "Настройки Smarty" +_const_cache = "Кеширование SQL" +_const_compression = "Компрессия" +_const_memcached = "Memcached" +_const_request = "Запросы" +_const_database = "База данных" +_const_other = "Прочее" + +// 3.27 +SETTINGS_CACHE_TITLE = "Работа с кешем" +SETTINGS_SHOWCACHE = "Управление кешем" +SETTINGS_CACHE_H_TITLE = "Тип кеша" +SETTINGS_CACHE_H_SHOW = "Показать размер" +SETTINGS_CACHE_SHOW = "Показать" +SETTINGS_CACHE_CLEAR = "Очистить" +SETTINGS_CACHE_SUCCESS = "Удачно" +SETTINGS_CACHE_SUCCESS_T = "Кеш удачно удален" +SETTINGS_CACHE_ERROR = "Ошибка" +SETTINGS_CACHE_ERROR_T = "Произошла ошибка. Попробуйте повторить операцию еще раз" +SETTINGS_CACHE_T_SMARTY = "Шаблоны Smarty" +SETTINGS_CACHE_T_BLOCKS = "Данные визуальных блоков" +SETTINGS_CACHE_T_SYSBLOKS = "Данные системных блоков" +SETTINGS_CACHE_T_SETTINGS = "Данные системных настроек" +SETTINGS_CACHE_T_SESSIONS = "Данные сессий" +SETTINGS_CACHE_T_PAGINATION = "Данные постраничной навигации" +SETTINGS_CACHE_T_RUBRICS = "Данные рубрик" +SETTINGS_CACHE_T_NAVI = "Данные навигации" +SETTINGS_CACHE_T_MODULES = "Данные модулей" +SETTINGS_CACHE_T_QUERIES = "Данные запросов" +SETTINGS_CACHE_T_DOCS = "Данные документов" + +SETTINGS_CACHE_T_COMPILED = "Данные скомпилированных документов" \ No newline at end of file diff --git a/admin/lang/ru/sysblocks.txt b/admin/lang/ru/sysblocks.txt new file mode 100644 index 0000000..5febec6 --- /dev/null +++ b/admin/lang/ru/sysblocks.txt @@ -0,0 +1,94 @@ +SYSBLOCK_HEAD = "Системные блоки" +SYSBLOCK_EDIT = "Управление системными блоками" +SYSBLOCK_EDIT_TIP = "В данном разделе предоставлены все системные блоки." +SYSBLOCK_ID = "Id" +SYSBLOCK_NAME = "Наименование системного блока" +SYSBLOCK_HTML = "Код системного блока" +SYSBLOCK_TAGS = "Тэг" +SYSBLOCK_TAGS_2 = "HTML Tags" +SYSBLOCK_EXTERNAL = "Разрешить внешнее обращение по ссылке" +SYSBLOCK_EXTERNAL_H = "Внешнее обращение по ссылке" +SYSBLOCK_EXTERNAL_GO = "Перейти" +SYSBLOCK_AJAX = "Разрешать выполняться только по Ajax" +SYSBLOCK_AJAX_H = "Выполняться только по Ajax" + +SYSBLOCK_VISUAL = "Визуальный редактор" +SYSBLOCK_VISUAL_H = "Визуальный редактор" + +SYSBLOCK_MEDIAPATH = "Системный тег, путь к папке дизайна" +SYSBLOCK_BREADCRUMB = "Системный тег Хлебных крошек" +SYSBLOCK_DOCID_INFO = "Системный тег, идентификатор документа" +SYSBLOCK_PATH = "Корневой путь установки" +SYSBLOCK_HOME = "Ссылка на главную страницу сайта" + +SYSBLOCK_AUTHOR = "Автор" +SYSBLOCK_DATE = "Дата создания" +SYSBLOCK_TAG = "Системный тег" +SYSBLOCK_ACTIONS = "Действия" +SYSBLOCK_NO_ITEMS = "Сообщение:
В настоящий момент нет сохраненных системных блоков." +SYSBLOCK_BUTTON_SAVE = "Сохранить изменения" +SYSBLOCK_BUTTON_ADD = "Добавить системный блок" +SYSBLOCK_BUTTON_COPY = "Копировать" +SYSBLOCK_INSERT_H = "Добавление системного блока" +SYSBLOCK_EDIT_H = "Редактирование системного блока" +SYSBLOCK_INNAME = "Введите наименование системного блока" +SYSBLOCK_ENTER_NAME = "Пожалуйста, укажите наименование системного блока" +SYSBLOCK_INSERT = "Здесь вы можите добавить или изменить выбранный вами системный блок" + +SYSBLOCK_LINK = "Системный блок доступен по ссылке:" + +SYSBLOCK_SAVE = "Добавить" +SYSBLOCK_SAVEDIT = "Сохранить изменения" +SYSBLOCK_SAVE_NEXT = "Добавить и продолжить редактирование" +SYSBLOCK_SAVEDIT_NEXT = "Применить (CTRL+S)" + +SYSBLOCK_INTEXT = "Системный блок" +SYSBLOCK_ADD = "Добавить новый системный блок" +SYSBLOCK_ADD_BUTTON = "Добавить" +SYSBLOCK_EDIT_HINT = "Редактировать системный блок" +SYSBLOCK_DELETE_HINT = "Удалить системный блок" +SYSBLOCK_DEL_HINT = "Вы уверены, что хотите удалить системный блок?" +SYSBLOCK_LIST_LINK = "Список системных блоков" +SYSBLOCK_FILE = "Файл шаблона" +SYSBLOCK_SAVED = "Системный блок успешно сохранен." +SYSBLOCK_COPY_TITLE = "Копирование системного блока" +SYSBLOCK_COPY = "Копировать системный блок" +SYSBLOCK_COPY_TIP = "Пожалуйста, укажите наименование системного блока" +SYSBLOCK_COPY_TIP2 = "Пожалуйста, укажите наименование для копируемого системного блока" +SYSBLOCK_EXIST = "Извините, но системный блок с таким наименованием уже существует" +SYSBLOCK_SQLUPDATE = "Изменил системный блок" +SYSBLOCK_SQLNEW = "Создал новый системный блок" +SYSBLOCK_SQLDEL = "Удалил системный блок" +SYSBLOCK_OR = " или " + +SYSBLOCK_SAVED = "Системный блок успешно сохранен" +SYSBLOCK_SAVED_ERR = "Не удалось сохранить системный блок.
Попробуйте еще раз." +SYSBLOCK_ERROR = "Ошибка" +SYSBLOCK_SUCCESS = "Выполнено" + + +// v 3.2 +SYSBLOCK_DESCRIPTION = "Краткое описание" +SYSBLOCK_ALIAS = "Алиас" +SYSBLOCK_I = "Опционально. Алиас позволяет использовать легко запоминающийся тег [tag:sysblock:alias] вместо [tag:sysblock:id]. Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание, иметь длину не более 20 символов и быть уникальным в пределах модуля" +SYSBLOCK_ACCEPT = "Этот алиас можно использовать" +SYSBLOCK_ER_SYN = "Неверный алиас!
Алиас не должен являться числом, может содержать только цифры, латинские буквы, дефис, подчёркивание и иметь длину не более 20 символов" +SYSBLOCK_ER_EXISTS = "Неверный алиас!
Данный алиас уже привязан к другоому системному блоку" + +// v 3.26 +SYSBLOCK_EVAL = "Выполнять PHP перед возвращением результата" +SYS_GROUP_NO_TITLE = "Без группы" +SYS_GROUP_NO_DESCRIPTION = "Описание отсутвует" +SYS_GROUP_PLEASE_SELECT = "Выберите группу" +SYS_GROUP_TITLE = "Наименование группы" +SYS_GROUP_DESCRIPTION = "Описание группы" +SYS_GROUP_BTN = "Добавить группу" +SYS_GROUPS = "Список групп" +SYS_GROUPS_SORT_TIP = "Для упорядочивания полей нажмите на крестик и, удерживая его, перетащите поле" +SYS_GROUPS_GROUP_TITLE = "Наименование группы" +SYS_GROUPS_TIP = "Список групп для системных блоков" +SYS_NO_GROUPS = "В настоящий момент, нет групп для системных блоков" +SYS_GROUPS_DELETE = "Удалить группу" +SYS_GROUPS_DELETE_H = "Вы уверены, что хотите удалить группу?" +SYS_GROUPS_NEW = "Добавить новую группу" +SYSBLOCK_COPY_LOG = "создал копию системного блока" \ No newline at end of file diff --git a/admin/lang/ru/templates.txt b/admin/lang/ru/templates.txt new file mode 100644 index 0000000..aa091c8 --- /dev/null +++ b/admin/lang/ru/templates.txt @@ -0,0 +1,121 @@ +TEMPLATES_SUB_TITLE = "Управление шаблонами" +TEMPLATES_TIP1 = "В данном разделе приведен список всех шаблонов используемых в системе. Здесь вы можете удалить, отредактировать или скопировать шаблон, чтобы создать на его основе новый." +TEMPLATES_ID = "ID" +TEMPLATES_NAME = "Наименование шаблона" +TEMPLATES_NAME2 = "Наименование шаблона:" +TEMPLATES_NAME3 = "Укажите название шаблона:" +TEMPLATES_AUTHOR = "Автор" +TEMPLATES_DATE = "Дата создания" +TEMPLATES_ACTION = "Действия" +TEMPLATES_DATE_FORMAT = "%d.%m.%y г." +TEMPLATES_DATE_FORMAT2 = "%H:%M" +TEMPLATES_IN = "в" +TEMPLATES_EDIT = "Редактировать шаблон" +TEMPLATES_NO_CHANGE = "Извините, но у вас недостаточно прав для редактирования шаблона" +TEMPLATES_DELETE = "Удалить шаблон" +TEMPLATES_DELETE_CONF = "Вы уверены, что хотите удалить данный шаблон?" +TEMPLATES_NO_DELETE2 = "Извините, но вы не можете удалить данный шаблон, т.к. он используется рубриками или модулями" +TEMPLATES_NO_DELETE3 = "Извините, но у вас недостаточно прав для удаления шаблона" +TEMPLATES_COPY = "Копировать шаблон" +TEMPLATES_NO_COPY = "Извините, но у вас недостаточно прав для копирования шаблона" +TEMPLATES_LEGEND = "Значения пиктограмм" +TEMPLATES_COPY_TITLE = "Копирование шаблона" +TEMPLATES_TIP2 = "Пожалуйста, укажите название для копируемого шаблона" +TEMPLATES_TIP3 = "Пожалуйста, укажите название для шаблона" +TEMPLATES_BUTTON_COPY = "Копировать" +TEMPLATES_TAG_INSERT = "Нажмите на название системного тега, чтобы добавить его в поле шаблона" +TEMPLATES_TITLE_NEW = "Создание нового шаблона" +TEMPLATES_TITLE_EDIT = "Редактирование шаблона" +TEMPLATES_WARNING1 = "Пожалуйста, будьте предельно внимательны при редактировании шаблона и помните, что неверно указанный код может испортить внешнее оформление сайта" +TEMPLATES_WARNING2 = "В данном разделе вы можете создать новый шаблон в ручную, а также загрузить готовую структуру шаблона из существующего файла. Помните, что файлы с готовой структурой должны быть расположены в директории /inc/data/prefabs/templates/" +TEMPLATES_HTML = "HTML код шаблона" +TEMPLATES_USE_PHP = "Извините, но у вас недостаточно прав для редактирования шаблона, т.к. он использует PHP код" +TEMPLATES_BUTTON_SAVE = "Сохранить изменения" +TEMPLATES_BUTTON_SAVE_NEXT = "Применить (CTRL+S)" +TEMPLATES_FILE_SAVED = "Файл успешно сохранен" +TEMPLATES_BUTTON_ADD = "Добавить шаблон" +TEMPLATES_BUTTON_ADD_NEXT = "Добавить и продолжить редактирование" +TEMPLATES_BUTTON_LOAD = "Загрузить" +TEMPLATES_LOAD_INFO = "Пожалуйста, выберите из списка файл с готовой структурой шаблона" +TEMPLATES_EXIST = "Извините, но шаблон с таким названием уже существует" +TEMPLATES_NO_NAME = "Пожалуйста, укажите название шаблона" +TEMPLATES_ALL = "Список шаблонов" +TEMPLATES_OR = " или " + +TEMPLATES_FILE_NAME = "Наименование файла" +TEMPLATES_CSS_FILES = "Список css файлов" +TEMPLATES_JS_FILES = "Список js файлов" +TEMPLATES_FILES = "Файловый менеджер" +TEMPLATES_EDIT_FILE = "Редактировать файл" +TEMPLATES_DEL_FILE = "Удалить файл" + +TEMPLATES_TAGS = "Тег" +TEMPLATES_TAG_DESC = "Описание тега" +TEMPLATES_THEME_FOLDER = "Наименование шаблона (Имя папки с файлами для данного шаблона)" +TEMPLATES_FOLDER = "Папка:" +TEMPLATES_PAGENAME = "Наименование сайта" +TEMPLATES_FILENAME = "Наименование файла" +TEMPLATES_TITLE = "Наименование страницы" +TEMPLATES_KEYWORDS = "Ключевые слова (Meta - Keywords)" +TEMPLATES_DESCRIPTION = "Описание страницы (Meta - Description)" +TEMPLATES_INDEXFOLLOW = "Тип индексирования" +TEMPLATES_CANONICAL = "Каноническая страница – это рекомендуемый экземпляр из набора страниц с очень похожим содержанием." +TEMPLATES_PATH = "Корневой путь установки" +TEMPLATES_MEDIAPATH = "Путь до папки с шаблоном (Пример: [tag:mediapath]images/logo.gif)" + +TEMPLATES_CSS = "Сжимает несколько css-файлов в один. Возвращает путь.
FFF - имена файлов через запятую
P - путь к папке с файлами, не обязательно. По умолчанию - [tag:mediapath]css/

Пример: href="[tag:css:reset.css,style.css]"" + +TEMPLATES_JS = "Сжимает несколько js-файлов в один. Возвращает путь.
FFF - имена файлов через запятую
P - путь к папке с файлами, не обязательно. По умолчанию - [tag:mediapath]js/

Пример: href="[tag:js:common.js,main.js]"" + +TEMPLATES_MEDIAPATH = "Путь до папки с шаблоном (Пример: [tag:mediapath]images/logo.gif)" +TEMPLATES_MAINCONTENT = "Тег для главного содержания" +TEMPLATES_ALIAS = "Ссылка на текущий документ (Alias)" +TEMPLATES_SYSBLOCK = "Систменый тег Системных блоков" +TEMPLATES_TEASER = "Систменый тег Тизеров" +TEMPLATES_PRINTLINK = "Ссылка на "Версия для печати"" +TEMPLATES_HOME = "Ссылка на главную страницу сайта" +TEMPLATES_BREADCRUMB = "Систменый тег Хлебных крошек" +TEMPLATES_VERSION = "Показ информации о защите информации" +TEMPLATES_NAVIGATION = "Меню навигации (ххх - номер меню)" +TEMPLATES_IF_PRINT = "Содержимое будет показано при печати." +TEMPLATES_DONOT_PRINT = "Содержание не будет показано при печати" +TEMPLATES_RUBHEADER = "Настраивается в шаблоне рубрики
(Шаблон оформления HEADER)" +TEMPLATES_RUBFOOTER = "Настраивается в шаблоне рубрики
(Шаблон оформления FOOTER)" +TEMPLATES_NO_ITEMS = "В настоящий момент нет файлов" +TEMPLATES_DOMAIN = "Системный тег вывода доменного имени" +TEMPLATES_DOCDB = "Системный тег вывода поля документа из БД" +TEMPLATES_LANGFILE = "Системный тег для вывода языковой переменной из файла" +TEMPLATES_LANGUAGE = "Тег включает подгрузку языковых файлов. Желательно указывать данный тег, до основного шаблона" +TEMPLATES_LANG = "Содержимое будет показано если язык документа совпадает с указанным" + +TEMPLATES_CACHE_SUCCESS = "Кеш успешно очищен." +TEMPLATES_CACHE_SUCCESS_LOG = "Очистил кэш" + +TEMPLATES_CSS_TITLE = "Пожалуйста, будьте предельно внимательны при редактировании файлов и помните, что неверно указанный код может испортить внешнее оформление сайта" +TEMPLATES_CSS_EDITOR = "Редактор файлов CSS" + +TEMPLATES_JS_TITLE = "Пожалуйста, будьте предельно внимательны при редактировании файлов и помните, что неверно указанный код может испортить внешнее оформление сайта" +TEMPLATES_JS_EDITOR = "Редактор файлов CSS" + +TEMPLATES_REPORT_NEW = "Создал шаблон" +TEMPLATES_REPORT_CHANGE = "Изменил шаблон" +TEMPLATES_REPORT_PHP = "Попытка использования PHP кода в шаблоне" +TEMPLATES_REPORT_PHP_CSS = "Попытка использования PHP кода в css файле" +TEMPLATES_REPORT_PHP_JS = "Попытка использования PHP кода в js файле" +TEMPLATES_REPORT_PHP_ERR = "Запрещено использовать PHP код" +TEMPLATES_REPORT_ID_ERR = "Попытка удаления основного шаблона" +TEMPLATES_REPORT_DELETE = "Удалил шаблон" +TEMPLATES_REPORT_FILE = "Отредактировал файл" +TEMPLATES_REPORT_COPY = "Создал копию шаблона" +TEMPLATES_REPORT_DEL_OK = "Файл успешно удален" +TEMPLATES_REPORT_DEL_ER = "Не удалось удалить файл" + +TEMPLATES_REPORT_ERROR_TEXT = "HTML код шаблона пустой" +TEMPLATES_REPORT_ERROR_TITLE = "Не заполнено - Наименование щаблона" + +TEMPLATES_SAVED = "Шаблон успешно сохранен" +TEMPLATES_SAVED_FILE = "Файл успешно сохранен" +TEMPLATES_SAVED_ERR = "Не удалось сохранить шаблон.
Попробуйте еще раз." +TEMPLATES_SAVED_ERR_FILE = "Не удалось сохранить файл.
Попробуйте еще раз." +TEMPLATES_ERROR = "Ошибка" +TEMPLATES_SUCCESS = "Выполнено" \ No newline at end of file diff --git a/admin/lang/ru/user.txt b/admin/lang/ru/user.txt new file mode 100644 index 0000000..081e579 --- /dev/null +++ b/admin/lang/ru/user.txt @@ -0,0 +1,90 @@ +[user] +USER_SUB_TITLE = "Управление пользователями" +USER_TIP1 = "В данном разделе приведен список всех пользователей в системе. Здесь вы можете отредактировать параметры пользователя, удалить пользователя, а также перенести пользователя в другую группу." +USER_ID = "ID" +USER_NAME = "Имя и фамилия пользователя" +USER_NAME2 = "Имя пользователя" +USER_GROUP = "Состоит в группе" +USER_STATUS_WAIT = "Ожидает активации" +USER_LAST_VISIT = "Последний вход" +USER_REGISTER_DATE = "Дата регистрации" +USER_ACTION = "Действия" +USER_DELETE = "Удалить пользователя" +USER_EDIT = "Редактировать пользователя" +USER_DATE_FORMAT = "%d.%m.%Y %H:%M" +USER_NO_CHANGE = "Извините, но у вас недостаточно прав для редактирования пользователей" +USER_DELETE_CONFIRM = "Вы уверены, что хотите удалить данного пользователя?" +USER_LEGEND = "Значения пиктограмм" +USER_BUTTON_SAVE = "Сохранить изменения" +USER_ORDERS = "История заказов" +USER_DOWNLOADS = "История заказов ПО" +USER_MARK_DELETE = "Отметить для удаления" +USER_NEW_TITLE = "Создание нового пользователя" +USER_NEW_TIP = "Чтобы добавить нового пользователя, заполните поля соответствующими данными. Пожалуйста, будьте предельно внимательны при выборе группы для данного пользователя. Неверно указанная группа может ограничить доступ пользователя к определенным разделам сайта или наоборот, разрешить доступ к закрытым разделам." +USER_EDIT_TITLE = "Редактирование пользователя" +USER_EDIT_TIP = "В данном разделе вы можете отредактировать параметры пользователя, а также изменить пароль и группу пользователя." +USER_ERRORS = "Ошибка:" +USER_FIRSTNAME = "Имя:" +USER_FIRSTNAME_ADD = "Введите имя пользователя:" +USER_LASTNAME = "Фамилия:" +USER_EMAIL = "E-mail адрес:" +USER_NICK = "Ник на форуме:" +USER_SIGNATURE = "Подпись на форуме:" +USER_AVATAR = "Аватар:" +USER_TAX = "Облагать налогом:" +USER_COMPANY = "Компания:" +USER_HOUSE_STREET = "Улица / Номер дома:" +USER_ZIP_CODE = "Почтовый индекс:" +USER_CITY = "Город проживания:" +USER_PASSWORD = "Пароль:" +USER_PASSWORD_CHANGE = "изменить" +USER_PASSWORD_SHOW = "Показать пароль" +USER_YES = "Да" +USER_NO = "Нет" +USER_COUNTRY = "Страна:" +USER_PHONE = "Контактный телефон:" +USER_FAX = "Факс:" +USER_BIRTHDAY = "Дата рождения:" +USER_BIRTHDAY_FORMAT = " в формате (ДД.ММ.ГГГГ)" +USER_NOTICE = "Дополнительная информация:" +USER_MAIN_GROUP = "Основная группа:" +USER_SECOND_GROUP = "Дополнительная группа:" +USER_SECOND_INFO = "Выбор нескольких групп" +USER_STATUS = "Статус пользователя:" +USER_ACTIVE = "Активный" +USER_INACTIVE = "Неактивный" +USER_BUTTON_ADD = "Добавить пользователя" +USER_SEND_INFO = "Проинформировать пользователя по почте" +USER_MESSAGE_SUBJECT = "Тема сообщения:" +USER_MESSAGE_TEXT = "Текст сообщения:" +USER_EMAIL_EXIST = "Извините. но указанный E-mail адрес уже используется в системе." +USER_ERROR_DATEFORMAT = "Дата рождения указана в неверном формате." +USER_PASSWORD_SHORT = "Указанный пароль слишком короткий. Пожалуйста, используйте минимум 5 символов." +USER_PASSWORD_ERROR = "Поле Пароль содержит недопустимые символы." +USER_NO_EMAIL = "Поле E-mail не заполнено. Пожалуйста, укажите E-Mail адрес." +USER_NO_PASSWORD = "Поле Пароль не заполнено. Пожалуйста, укажите пароль." +USER_EMAIL_ERROR = "Поле E-mail адрес содержит недопустимые символы, Пожалуйста, проверьте указанный E-mail адрес." +USER_NO_FIRSTNAME = "Поле Имя пользователя не заполнено. Пожалуйста, укажите Имя пользователя." +USER_NO_USERNAME = "Поле Логин не заполнено. Пожалуйста, укажите Логин пользователя." +USER_ERROR_FIRSTNAME = "Поле Имя пользователя содержит недопустимые символы." +USER_ERROR_USERNAME = "Поле Логин содержит недопустимые символы." +USER_NO_LASTNAME = "Поле Фамилия пользователя не заполнено. Пожалуйста, укажите Фамилию пользователя," +USER_ERROR_LASTNAME = "Поле Фамилия пользователя содержит недопустимые символы." +USER_MAIL_BODY1 = "Здравствуйте %USER%,%N%%N%" +USER_MAIL_BODY2 = "Ваш аккаунт успешно активирован. Пожалуйста, используйте Ваши регистрационные данные для входа на сайт %HOST%." +USER_MAIL_FOOTER = "%N%%N%С уважением, %HOMEPAGENAME%%N%%N%%HOST%" +USER_MAIL_SUBJECT = "Ваш аккаунт активирован" +USER_MAIL_PASSWORD = "Информация о смене пароля" +USER_MAIL_PASSWORD2 = "Сообщаем Вам о смене пароля.%N%%N%Ваш новый пароль: %NEWPASS%" +USER_NEW_ADD = "Создание нового пользователя" +USER_ALL = "Список пользователей" +USER_LOGIN = "Логин в системе:" +SETTINGS_NAME = "Параметр" +SETTINGS_VALUE = "Значение" +USER_LIST_EMPTY = "Нет пользователей соответствующих заданным условиям поиска.
Попробуйте изменить условия поиска." +USER_REPORT_ADD = "Добавил пользователя" +USER_REPORT_EDIT = "Отредактировал параметры пользователя" +USER_REPORT_DEL = "Удалил пользователя" +USER_REPORT_GROUP = "Изменил группу для пользователя" +USER_YOUR_NOT_CHANGE = "Ошибка! Извините, но Вы не имеете прав для редактирования данного пользователя." +USER_WARNING_TIP = "Внимание! Будьте предельно внимательны, при редактировании данного пользователя." \ No newline at end of file diff --git a/admin/lang/ua/blocks.txt b/admin/lang/ua/blocks.txt new file mode 100644 index 0000000..eb919b9 --- /dev/null +++ b/admin/lang/ua/blocks.txt @@ -0,0 +1,68 @@ +BLOCK_HEAD = "Візуальні блоки" +BLOCK_EDIT = "Керування візуальними блоками" +BLOCK_EDIT_TIP = "У цьому розділі надані усі візуальні блоки." +BLOCK_ID = "Id" +BLOCK_NAME = "Назва візуального блока" +BLOCK_HTML = "Код візуального блока" +BLOCK_TAGS = "Тег" +BLOCK_TAGS_2 = "HTML Tags" + + +BLOCK_VISUAL = "Візуальний редактор" +BLOCK_VISUAL_H = "Візуальний редактор" + +BLOCK_MEDIAPATH = "Системний тег, шлях до папки дизайна" +BLOCK_BREADCRUMB = "Системний тег хлібних крихт" +BLOCK_DOCID_INFO = "Системний тег, ідентифікатор документа" +BLOCK_PATH = "Кореневий шлях установки" +BLOCK_HOME = "Посилання на головну сторінку сайта" + +BLOCK_AUTHOR = "Автор" +BLOCK_DATE = "Дата створення" +BLOCK_TAG = "Системний тег" +BLOCK_ACTIONS = "Дія" +BLOCK_NO_ITEMS = "Повідомлення:
На даний час немає збережених візуальних блоків." +BLOCK_BUTTON_SAVE = "Зберегти зміни" +BLOCK_BUTTON_ADD = "Додати візуальний блок" +BLOCK_BUTTON_COPY = "Копіювати" +BLOCK_INSERT_H = "Додавання візуального блока" +BLOCK_EDIT_H = "Редагування візуального блока" +BLOCK_INNAME = "Введіть назву візуального блока" +BLOCK_ENTER_NAME = "Будь ласка, вкажіть назву візуального блока" +BLOCK_INSERT = "Тут Ви можете додати або змінити обраний Вами візуальний блок" + +BLOCK_SAVE = "Додати" +BLOCK_SAVEDIT = "Зберегти зміни" +BLOCK_SAVE_NEXT = "Додати та продовжити редагування" +BLOCK_SAVEDIT_NEXT = "Примінити (CTRL+S)" + +BLOCK_INTEXT = "Візуальний блок" +BLOCK_ADD = "Додати новый візуальний блок" +BLOCK_ADD_BUTTON = "Додати" +BLOCK_EDIT_HINT = "Редагувати візуальний блок" +BLOCK_DELETE_HINT = "Видалити блок" +BLOCK_DEL_HINT = "Ви впевнені, що бажаєте видалити візуальний блок?" +BLOCK_LIST_LINK = "Список візуальних блоків" +BLOCK_FILE = "Файл шаблона" +BLOCK_SAVED = "Блок успішно збережено." +BLOCK_COPY_TITLE = "Копіювання візуального блока" +BLOCK_COPY = "Копіювати візуальний блок" +BLOCK_COPY_TIP = "Будь ласка, вкажіть назву візуального блока" +BLOCK_COPY_TIP2 = "Будь ласка, вкажіть назву для зкопійованого візуального блока" +BLOCK_EXIST = "Даруйте, але візуальний блок з такою назвою уже існує" +BLOCK_SQLUPDATE = "Змінив блок" +BLOCK_SQLNEW = "Створив новий візуальний блок" +BLOCK_SQLDEL = "Видалив візуальний блок" +BLOCK_OR = " або " + +BLOCK_SAVED = "Візуальний блок успіщно збережено" +BLOCK_SAVED_ERR = "Не вдалося зберегти візуальний блок.
Спробуйте ще раз." +BLOCK_ERROR = "Помилка" +BLOCK_SUCCESS = "Виконано" + +BLOCK_DESCRIPTION = "Короткий опис" +BLOCK_ALIAS = "Аліас" +BLOCK_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:BLOCK:alias] замість [tag:BLOCK:id]. Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах цих блоків" +BLOCK_ACCEPT = "Цей аліас можна використовувати" +BLOCK_ER_SYN = "Неправильний аліас!
Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +BLOCK_ER_EXISTS = "Неправильний аліас!
Такий аліас уже прив’язаний до іншого візкального блока" \ No newline at end of file diff --git a/admin/lang/ua/dbactions.txt b/admin/lang/ua/dbactions.txt new file mode 100644 index 0000000..b94a265 --- /dev/null +++ b/admin/lang/ua/dbactions.txt @@ -0,0 +1,49 @@ +# солов’їна))) 01,2017 duncan + +DB_SUB_TITLE = "Керування базою даних" +DB_ACTION_WARNING = "Увага!\nУсі дії по роботі з базою даних Ви чините на свій страх та ризик.\n\nПам’ятайте, що будь-які дії, які виконуються з базою даних, можуть пошкодити існуючу інформацію.\n\nВи впевнені, що бажаєте продовжити?\n\n" +DB_ACTION_RESET = "Увага!\nВи намагаєтеся відновити базу даних з резервної копії. Вся існуюча інформація буде видалена та перезаписана.\nБудь ласка, зверніть увагу, що після відновлення бази даних, Вам необхідно буде виконати авторизацію знову.\n\nВи впевнені, що бажаєте продовжити?\n\n" +DB_OPTION_LIST = "Структура бази даних" +DB_BUTTON_ACTION = "Виконати дію" +DB_OPTIMIZE_DATABASE = "Оптимізація бази даних" +DB_OPTIMIZE_INFO = "Ця можливість дозволяє збільшити продуктивність та зменшити розмір Вашої бази даних. Рекомендований інтервал між оптимізаціями має бути не менше 1 раза на тиждень." +DB_REPAIR_DATABASE = "Відновлення пошкоджених таблиць" +DB_REPAIR_INFO = "Ця можливість дозволяє виконати спробу відновлення пошкоджених таблиць у базі даних, у випадку, некоректного виводу інформації на сторінках cайту." +DB_BACKUP_DATABASE = "Створення резервної копії" +DB_BACKUP_INFO = "Ця можливість дозволяє створити резервну копію як усієї бази даних, так і окремих таблиць. Будь ласка, оберіть у списку зліва таблиці, для яких Ви бажаєте виконати резервне копіювання. Для вибору декількох таблиць затисніть кнопку CTRL." +DB_RESTORE_TITLE = "Відновлення бази даних з резервної копії" +DB_RESTORE_FILE = "Відновлення бази даних з файла" +DB_BUTTON_RESTORE = "Відновити" +DB_ACTION = "Оберіть дію" +DB_TIPS = "Увага! Усі дії по роботі з базою даних Ви чините на свій страх та ризик. Пам’ятайте, що будь-які дії, які виконуються з базою даних, можуть пошкодити існуючу інформацію." +DB_BACKUP_SERVER = "Зберегти резервну копію на сервері" +DB_SC = "Операцію з базою даних успішно виконано" + +DB_OPTIMIZE_DATABASE_SC = "Оптимізацію бази даних успішно виконано" +DB_REPAIR_DATABASE_SC = "Відновлення пошкоджених таблиць успішно виконано" + +DB_REPORT_DUMP = "Виконав резервне копіювання бази даних" +DB_REPORT_DUMP_RECOVER = "Виконав відновлення бази даних з резервної копії" +DB_REPORT_DUMP_OPTIM = "Виконав оптимізацію бази даних" +DB_REPORT_DUMP_TABLE = "Виконав відновлення таблиць бази даних" + +DB_FILE_DATA = "Дата створення" +DB_FILE_SIZE = "Розмір" +DB_FILE_NAME = "Назва файла" +DB_ACTIONS = "Дія" +DB_ACTIONS_EDIT = "Редагувати" +DB_ACTIONS_DEL = "Видалити" +DB_ACTIONS_RESTORE = "Відновити" +DB_ACTIONS_SAVE = "Зберегти на комп’ютер" + +DB_REPORT_DUMP_DEL_OK = "Видалив файл резервної копії бази даних" +DB_REPORT_DUMP_DEL_ER = "Не вдалося видалити файл резервної копії бази даних" +DB_REPORT_DUMP_ER = "Помилка: Імпорт бази даних не виконано, оскільки відсутній файл дампа або він пошкоджений." + +DB_ACTIONS_RESTORE_H = "Відновити резервну копію" +DB_ACTIONS_RESTORE_T = "Ви впевнені що бажаєте відновити резервну копію бази даних?" + +DB_ACTIONS_DELETE_H = "Видалити файл" +DB_ACTIONS_DELETE_T = "Ви впевнені, що бажаєте видалити файл резервної копії бази даних?" + +DB_NO_FILES_MESS = "На даний час, немає файлів резервних копій бази даних" diff --git a/admin/lang/ua/docs.txt b/admin/lang/ua/docs.txt new file mode 100644 index 0000000..fda6198 --- /dev/null +++ b/admin/lang/ua/docs.txt @@ -0,0 +1,320 @@ +# солов’їна))) 01,2017 duncan + +[docs] +DOC_SUB_TITLE = "Керування документами" +DOC_TIPS = "У цьому розділі наведено список усіх документів у системі. Тут Ви можете виконати основні операції з документами, такі як: перегляд, редагування, видалення документа, а також залишити примітку для якого-небудь документа." +DOC_DATE_FORMAT = "%d.%m.%Y %H:%M" +DOC_LEGEND = "Значення піктограм" +DOC_LEGEND_EDIT = "Редагувати документ" +DOC_LEGEND_SHOW = "перегляд сторінки у новому вікні" +DOC_LEGEND_ENABLE = "зробити документ активним" +DOC_LEGEND_DISABLE = "зробити документ неактивним" +DOC_LEGEND_TEMP_DELETE = "Тимчасово видалити документ (у кошик)" +DOC_LEGEND_RESTORE = "Відновити документ (з кошика)" +DOC_LEGEND_FINAL_DELETE = "Остаточно видалити документ" +DOC_CHOSE_RUB = "Оберіть рубрику" +DOC_ID = "ID" +DOC_URL_RUB = "URL" +DOC_TITLE = "Назва документа" +DOC_URL_TITLE = "Посилання на документ" +DOC_IN_RUBRIK = "Рубрика" +DOC_IN_NEW = "Новий документ" +DOC_CREATED = "Опубліковано" +DOC_EDIT = "Відредаговано" +DOC_PRINTED = "Роздруковано" +DOC_CLICKS = "переглядів" +DOC_AUTHOR = "Автор" +DOC_ACTIONS = "Дії" +DOC_EDIT_TITLE = "Редагувати цей документ" +DOC_CHANGE_RUBRIC = "Перенести цей документ в іншу рубрику" +DOC_CHANGE_AUTOR = "Поміняти автора документа" +DOC_SHOW_TITLE = "перегляд документа (Посилання без ЧПУ)" +DOC_SHOW2_TITLE = "перегляд документа (Посилання з ЧПУ)" +DOC_SHOW3_TITLE = "Документ без назви" +DOC_CREATE_NOTICE_TITLE = "залишити примітку" +DOC_REPLY_NOTICE_TITLE = "Подивитися/відповісти на примітку" +DOC_ENABLE_TITLE = "Опублікувати документ" +DOC_DISABLE_TITLE = "Зняти документ з публікації" +DOC_TEMPORARY_DELETE = "Покласти документ у кошик" +DOC_RESTORE_DELETE = "Відновити документ з кошика" +DOC_FINAL_DELETE = "видалити документ" +DOC_ICON_COMMENT = "Є Примітки" +DOC_ICON_PUBLIC = "Документ знято з публікації" +DOC_ICON_RECYCLE = "Документ переміщено у кошик" +DOC_SORT_TEXT = "Сортувати документи за:" +DOC_TEMPORARY_CONFIRM = "Ви впевнені, що бажаєте покласти у кошик цей документ?" +DOC_FINAL_CONFIRM = "Ви впевнені, що бажаєте видалити цей документ?" +DOC_INSERT_LINK_TIP = "Для вибору потрібного документа, натисніть на кнопку "Вибрати"" +DOC_BUTTON_INSERT_LINK = "Вибрати" +DOC_BUTTON_LINK_POPUP = "Вибрати у новому вікні" +DOC_BUTTON_ADD_DOCUMENT = "Додати документ" +DOC_BUTTON_ADD_DOCUMENT_NEXT = "Додати та продовжити редагування (Ctrl+S)" +DOC_BUTTON_EDIT_DOCUMENT = "Зберегти зміни" +DOC_BUTTON_EDIT_DOCUMENT_NEXT = "Примінити (Ctrl+S)" +DOC_ADD_DOCUMENT = "Додавання нового документа" +DOC_EDIT_DOCUMENT = "редагування документа" +DOC_OPTIONS = "Параметри документа" +DOC_NAME = "Назва документа:
(HTML <title>)" +DOC_URL = "Псевдонім документа:
(SEO alias)" +DOC_URL_LINK = "Підстановка аліасів" +DOC_URL_INFO = "Щоби посилання на документ виглядало, наприклад, так:
http://www.domain.tld/phone/samsung/
напишіть у це поле: phone/samsung

Суфікс посилання автоматично додається при виводі
відповідно до налаштувань, що вказані у файлі inc/config.php

У назві дозволено використовувати:
a-z — латинські символи;
а-я — символи кирилиці (якщо дозволено);
/ — слеш;
- — знак тире;
_ — знак підкреслення.

Назва посилання не повинна містити:
print/ або /print/ або /print;
page-XX/ або /page-XX/ або /page-XX;
apage-XX/ або /apage-XX/ або /apage-XX;
artpage-XX/ або /artpage-XX/ або /artpage-XX;
где XX - цифри" +DOC_URL_LOG = "Використовувати історію аліасів, для редиректа" +DOC_URL_LOG_T = "Зберігати або не зберігати історію аліасів документа, для наступного редиректа" +DOC_URL_LOG_RUBRIC = "Використовувати налаштування рубрики" +DOC_URL_LOG_USE = "Використовувати завжди" +DOC_FIELD_G_UNKNOW = "Без групи" +DOC_PROPERTY = "Параметри документа" +DOC_URL_LOG_NOTUSE = "Не використовувати" +DOC_QUERIES = "доступні запити:" +DOC_META_TITLE = "TITLE - це рядок, який буде виведений у заголовку вікна браузера, цей тег важливий для пошукової оптимизації, тому система дозволяє керувати ним, як і деякими іншими тегами." +DOC_META_KEYWORDS = "Ключові слова:
(meta keywords)" +DOC_META_KEYWORDS_INFO = "Описують вміст сторінки, можуть враховуватися пошуковими системами.

Частина перелічених ключових слів має бути присутня в тексті сторінки." +DOC_META_DESCRIPTION = "Опис сторінки:
(meta description)" +DOC_META_DESCRIPTION_INFO= "Невеликий текст, який описує вміст сторінки, також може враховуватися пошуковими системами, виводиться в якості пояснення в результатах пошука або інтернет-каталогах." +DOC_CAN_SEARCH = "Дозволити пошук по документу:
(для модуля пошук)" +DOC_INDEX_TYPE = "Тип індексування сторінки:
(meta robots)" +DOC_INDEX_FOLLOW = "Індексувати та переходити за посиланнями" +DOC_INDEX_NOFOLLOW = "Індексувати, але не переходити за посиланнями" +DOC_NOINDEX_NOFOLLOW = "Не індексувати та не переходити за посиланнями" +DOC_SITEMAP_FREQ = "Частота оновлення
sitemap.xml" +DOC_SITEMAP_FREQ_DOC = "Частота оновлення сторінки" +DOC_SITEMAP_ALWAYS = "Завжди" +DOC_SITEMAP_HOURLY = "Щогодини" +DOC_SITEMAP_DAILY = "Щоденно" +DOC_SITEMAP_WEEKLY = "Щотижня" +DOC_SITEMAP_MONTHLY = "Щомісяця" +DOC_SITEMAP_YEARLY = "Щорічно" +DOC_SITEMAP_NEVER = "Ніколи" +DOC_SITEMAP_PRIORITY = "Пріоритет
sitemap.xml" +DOC_SITEMAP_PRIORITY_DOC = "Пріоритет цієї сторінки щодо інших сторінок" +DOC_SITEMAP_PRIORITY_LOW = "Найнижчий пріоритет" +DOC_SITEMAP_PRIORITY_MID = "Середній пріоритет" +DOC_SITEMAP_PRIORITY_HIG = "Найвищий пріоритет" +DOC_START_PUBLICATION = "Початок публікації:" +DOC_END_PUBLICATION = "Кінець публікації:" +DOC_STATUS = "Статус документа:" +DOC_STATUS_ACTIVE = "Активний" +DOC_STATUS_INACTIVE = "Не активний" +DOC_ADD_IN_NAVIGATION = "Додати підпункт меню:" +DOC_USE_NAVIGATION = "Зв’язати з пунктом меню:" +DOC_USE_RUB_ALIAS = "Підстановки аліасів батьківських документів, призначення батьківського документа для хлібних крихт." +DOC_USE_BREADCRUMB = "Зв’язати з документом
(можна використовувати для хлібних крихт)" +DOC_USE_LANG_PACK = "Зв’язати з документом з мовної групи" +DOC_NAVIGATION_INFO = "Для того, щоб зв’язати цей документ з пунктом меню, оберіть зі списку існуючий пункт меню, якщо Ви тимчасово не бажаєте зв’язувати цей документ з пунктом меню, залиште поле порожнім." +DOC_MAIN_CONTENT = "Основний вміст документа" +DOC_MAIN_NOCONTENT = "Відсутні поля для документа" +DOC_AFTER_CREATE_TITLE = "Подальші дії" +DOC_AFTER_CREATE_INFO = "Будь ласка, оберіть Ваші подальші дії зі списку нижче:" +DOC_EDIT_THIS_DOCUMENT = "Повернутися до редагування цього документа" +DOC_INCLUDE_NAVIGATION = "Додати створений документ в меню навигації" +DOC_ADD_NEW_DOCUMENT = "Додати новий документ в цю рубрику" +DOC_ADD_COPY_DOCUMENT = "Додати копію документа в цю рубрику" +DOC_DISPLAY_NEW_WINDOW = "переглянути у новому вікні (Ctrl+O)" +DOC_CLOSE_WINDOW = "Перейти до списку документів" +DOC_CLOSE_WINDOW_RUBRIC = "Перейти до списку документів цієї рубрики" +DOC_TO_NAVI_TITLE = "Додавання документа в меню навигації" +DOC_NAVIGATION_POSITION = "Позиція у списку:" +DOC_NAVIGATION_TITLE = "Назва пунтка меню:" +DOC_TARGET = "Відкривати:" +DOC_TARGET_SELF = "у тому ж вікні" +DOC_TARGET_BLANK = "у новому вікні" +DOC_BUTTON_ADD_MENU = "Додати в меню" +DOC_TOP_MENU_ITEM = "Новий пункт 1-го рівня" +DOC_NOTICE = "Примітки до документа" +DOC_NOTICE_NEW_LINK = "Додати нову примітку" +DOC_NOTICE_AUTHOR = "Додати: " +DOC_NOTICE_DELETE_LINK = "видалити примітку" +DOC_ALLOW_NOTICE = "Дозволити коментар приміток" +DOC_BUTTON_NOTICE = "Виконати" +DOC_NOTICE_TITLE = "Заголовок:" +DOC_NOTICE_TEXT = "Примітка:" +DOC_BUTTON_ADD_NOTICE = "Додати примітку" +DOC_SEND_NOTICE_INFO = "Для того, щоб додати нову примітку до документу, будь ласка, заповніть поля в формі нижче." +DOC_NEW_NOTICE_TITLE = "Додати нову примітку" +DOC_MAIL_BODY_CHECK = "Користувач %USER% додав новий документ з назвою '%TITLE%'.%N%Будь ласка, перевірте цей документ перед публікацією." +DOC_MAIL_SUBJECT_CHECK = "Додано новий документ" +DOC_MAIL_BODY_USER = "Вітання %USER%.%N%Створений Вами документ успішно додано, Адміністратору надіслано сповіщення, про проверку, після перевірки документа його буде опубліковано." +DOC_MAIL_SUBJECT_USER = "Ваш документ додано, очікує на перевірку" +DOC_MAIL_BODY_NOTICE = "Користувач %USER% додав нову примітку до документу.%N%Авторизуйтеся у Панелі керування та перейдіть за посиланням нижче, щоб подивитися примітку:%N%%LINK%" +DOC_MAIL_SUBJECT_NOTICE = "Додано нову примітку до документа" +DOC_NEW_PAGE = "Додати нову сторінку" +DOC_CLOSE_HELP_WINDOW = "

" +DOC_HELP = "Допомога" +DOC_VIDEO_TYPE_HELP = "Вставка відео файла
При додаванні відео файла, Ви можете вказати ширину та висоту вікна для перегляду ролика. Перше значення визначає ширину вікна, друге висоту.

наприклад:

video.avi|300|300
або
video.avi|100%|300" +DOC_FLASH_TYPE_HELP = "Вставка флеш ролика
При додаванні флеш ролика, Ви можете вказати ширину та висоту вікна при перегляді. Перше значення визначає ширину, друге висоту.

наприклад:

flash.swf|300|300
або
flash.swf|100%|300" +DOC_FILE_TYPE_HELP = "Вставка Файла
При додаванні файла, Ви можете задати ім’я посилання. Для цього необхідно після назви файла вказати розподілюючий знак | та після нього ввести назву посилання.

наприклад:

file.zip|Завантажити файл" +DOC_NO_PERMISSION = "Даруйте, але Ви не маєте прав для редагування цього документа." +DOC_NO_PERMISSION_RUB = "Даруйте, але Ви не маєте прав для створення документа у цій рубриці." +DOC_NO_DEL_REVISION = "Даруйте, але Ви не маєте прав для видалення ревізії." +DOC_NO_RES_REVISION = "Даруйте, але Ви не маєте прав для відновлення ревізії." +DOC_EDIT_RUB = "Перенести в іншу рубрику" +DOC_RUBRIC = "Рубрика" +DOC_SORT_RUB = "Сортувати за рубриками" +DOC_IMAGE = "Зображення у списку новин" +DOC_IMAGE_MAX_W = "Максимальна ширина" +DOC_IMAGE_MAX_H = "Максимальна висота" +DOC_INTRO = "Тизер
(текст у списку новин)" +DOC_ALIAS_CREATE = "Сформувати" +DOC_ENTER_NAME = "Будь ласка, оберіть рубрику, в яку Ви бажаєте додати новий документ." +DOC_SORT_NAME = "Будь ласка, оберіть рубрику." +DOC_OR = " або " +DOC_NO_DOCS = "Документи, які відповідають цим критеріям пошука, відсутні." + +DOC_COPY = "Копіювати документ" +DOC_COPY_DOCUMENT = "копіювання документа" +DOC_COPY_TIP = "Будь ласка, вкажіть назву для документа" + +DOC_ADD_NEW_LIGHT_TIP = "Для додавання нового документа, будь ласка, оберіть рубрику." +DOC_ADD_NEW_LIGHT_ADD = "Додавання документа" +DOC_ADD_NEW_LIGHT_BTN = "Додати документ" + +DOC_CHANGE_TITLE = "Перенесення документа в іншу рубрику" +DOC_CHANGE_INFO = "Увага! При зміні рубрики поля, які не були перенесені, буде втрачено!" +DOC_CHANGE_OLD_FIELD = "Поле документа" +DOC_CHANGE_NEW_FIELD = "Перенести в нове" +DOC_CHANGE_DROP_FIELD = "-- не переносити --" +DOC_CHANGE_CREATE_FIELD = "-- створити нове --" +DOC_CHANGE_BUTTON = "змінити" + +DOC_CHANGE_AU_TITLE = "Зміна автора документа" +DOC_CHANGE_AU_INFO = "Увага! При зміні автора, попереднього автора може бути позбавлено прав на редагування цього документа." +DOC_CHANGE_BUTTON = "Зберегти" + +DOC_IN_MENU = "в меню" + +DOC_REVISSION = "Історія змін" +DOC_REVISSION_DATA = "Дата та час зміни" +DOC_REVISSION_USER = "Автор" +DOC_REVISSION_VIEW = "Подивитися версію" +DOC_REVISSION_RECOVER = "Відновити версію" +DOC_REVISSION_RECOVER_T = "Ви впевнені, що бажаєте відновити цю версію?" +DOC_REVISSION_DELETE = "видалити версію" +DOC_REVISSION_DELETE_T = "Ви впевнені, що бажаєте видалити цю версію?" +DOC_REVISSION_NO_ITEMS = "На цей час немає даних" + +DOC_URL_ERROR_SYMBOL = "Недопустимі символи" +DOC_URL_ERROR_START = "починається з /" +DOC_URL_ERROR_END = "закінчується на / (при цьому суфікс URL починається на /)" +DOC_URL_ERROR_SEGMENT = "Недопустимі сегменти:" +DOC_URL_ERROR_EMTY = "Немає що перевіряти" +DOC_URL_ERROR_DUPLICATES = "Псевдонім уже використовується" +DOC_URL_H_ERROR_DUPLICATES = "Псевдонім уже використовується в історії аліасів" +DOC_URL_CHECK_OK = "Цей URL можна використовувати" +DOC_URL_CHECK_ER = "URL містить помилки:
" + +DOC_REQUEST_NOT_INFO = "Для цього запиту опису немає." + +DOC_REVISION_DELETE = "Видалив версію документа" +DOC_REVISION_RECOVER = "Відновив версію документа" + +DOC_BREADCRUMB_BTN = "Вибрати" +DOC_BREADCRUMB_TITLE = "Назва посилання для хлібних крихт" +DOC_BREADCRUMB_WITH = "Пов’язаний з" + +DOC_DOCUMENT_OPEN = "Документ опубліковано" +DOC_DOCUMENT_CLOSE = "Документ знято з публікації" + +DOC_DOCUMENT_DOC = "Документ" +DOC_DOCUMENT_ACT = "Опублікував" +DOC_DOCUMENT_DISACT = "Зняв з публікації" + +DOC_DOCUMENT_OPEN_ERR = "Цей документ не можна зробити неактивним!" +DOC_DOCUMENT_OPEN_PRIVE = "У вас недостатньо для цього прав!" + +DOC_ACTION_SELECT = "Дії з обраними" +DOC_ACTION_SELECT_ACT = "Активний" +DOC_ACTION_SELECT_NACT = "Не активний" +DOC_ACTION_SELECT_TRASH = "Тимчасово видалити" +DOC_ACTION_SELECT_OUTTRASH = "Відновити" +DOC_ACTION_SELECT_DEL = "Видалити" +DOC_ACTION_BUTTON = "Зберегти зміни" + +DOC_CHOOSE_LANG = "Вибір мови документа" +DOC_LANG_VERSION = "Версія документа іншими мовами" +DOC_LINK_CHOOSE = "Оберіть документ" +DOCUMENT_SAVED = "Документ успішно збережено" + +DOC_REV_DELETED = "Ревізії документів успішно видалено" +DOC_REV_DELETED_ERR = "Не вдалося видалити ревізії документів.
Спробуйте ще раз." +DOC_REV_ERROR = "Помилка" +DOC_REV_SUCCESS = "Виконано" +DOC_REV_UPDATE = "Видалив ревізії документів" + +DOC_ALIASES = "Керування редиректами документів" +DOC_ALIASES_LIST_NM = "Назва документа" +DOC_ALIASES_LIST_RB = "Рубрика" +DOC_ALIASES_LIST_CH = "Змінено" +DOC_ALIASES_LIST_CR = "Кіль-ть" +DOC_ALIASES_LIST_AT = "Дії" +DOC_ALIASES_TITLE = "У цьому розділі наведено список усіх документів, в яких присутні внутрішні редиректи.
Тут Ви можете виконати основні операції з документами, такі як: перегляд, редагування, видалення редиректа." +DOC_ALIASES_BREAD_RUB = "Рубрика:" +DOC_ALIASES_BREAD_DOC = "Документ:" +DOC_ALIASES_BREAD_URL = "Основний URL:" +DOC_ALIASES_DOC_LIST = "Список документів з редиректами" +DOC_ALIASES_ADD = "Додати новий редирект" +DOC_ALIASES_ADD_VAL = "Значення редиректа" +DOC_ALIASES_LIST = "Список редиректів" +DOC_ALIASES_LIST_EMPT = "Список порожній" +DOC_ALIASES_TABL_H_URL = "Аліас редиректа" +DOC_ALIASES_TABL_H_ADD = "Додано" +DOC_ALIASES_TABL_H_AUT = "Автор" +DOC_ALIASES_TABL_CHECK = "Відмітити цей пункт для видалення" +DOC_ALIASES_GO = "Перейти за посиланням" +DOC_ALIASES_DEL_T = "Видалити аліас" +DOC_ALIASES_DEL_C = "Ви впевнені, що бажаєте видалити аліас?" +DOC_ALIASES_BUTT_DEL = "Видалити" +DOC_ALIASES_BUTT_CLO = "Закрити вікно" +DOC_ALIASES_BUTT_APP = "Примінити" +DOC_ALIASES_BUTT_CNL = "Відмінити" +DOC_ALIASES_BUTT_SAV = "Зберегти" +DOC_ALIASES_BUTT_ADD = "Додати" +DOC_ALIASES_REP_OK = "Виконано" +DOC_ALIASES_REP_OK_T = "Редирект успішно додано" +DOC_ALIASES_REP_OK_T_E = "Редирект успішно обновлено" +DOC_ALIASES_REP_ER = "Помилка" +DOC_ALIASES_REP_ER_T = "Не вдалося додати редирект. Спробуйте ще раз." +DOC_ALIASES_REP_ER_T_E = "Не вдалося оновити редирект. Спробуйте ще раз." + +DOC_RUBRIC_TMPLS = "Вибрати шаблон рубрики" +DOC_RUBRIC_TMPLS_HINT = "Ви можете задати документу, для виводу, будь-який шаблон з цієї рубрики" + + +DOC_SEARCH_FIELD = "Оберіть поле" +DOC_SEARCH_FIELD_LIKE = "Містить" +DOC_SEARCH_FIELD_EQ = "Дорівнює" +DOC_SEARCH_FIELD_TEXT = "Значення" +DOC_TEMPLATE_DEFAULT = "Використовувати по замовчуванню" +DOC_SHOW_LANG = "Показати" + +// 3.2 +DOC_TABS_META = "Meta дані" +DOC_TABS_URL = "URL документа" +DOC_TABS_DATE = "Дата публікації" +DOC_TABS_OTHER = "Інші параметри" + +DOC_WITHOUT_TITLE = "Документ без назви" +DOC_SAVE_ADD = "Додав" +DOC_SAVE_EDIT = "Відредагував" +DOC_SAVE_LOG_DOC = " документ" + +/* new */ +DOC_LANG = "Мова" +DOC_LANG_ID = "Мова документа:" +DOC_LANG_SELECT = "Оберіть мову" + +// 3.25 +DOC_CLOSE_SEARCH_RUBRIC = "Повернутися у розділ, враховуючи параметри пошуку" + +// 3.26 +DOC_POSITION = "Позиція" +DOCUMENT_POSITION = "Позиція документа" +DOCUMENT_POSITION_ERR = "Не вдалося зберегти позицію документа" +DOCUMENT_POSITION_ERROR = "Помилка" +DOCUMENT_POSITION_OK = "Позицію документа успішно збережено" +DOCUMENT_POSITION_SUCCESS = "Виконано" + +DOC_SEARCH_PARAM = "Параметр документа" +DOC_SEARCH_PARAM_SELECT = "Оберіть параметр" +DOC_SEARCH_PARAM_LIKE = "Містить" +DOC_SEARCH_PARAM_EQ = "Дорівнює" +DOC_SEARCH_PARAM_TEXT = "Значення" diff --git a/admin/lang/ua/groups.txt b/admin/lang/ua/groups.txt new file mode 100644 index 0000000..84a1597 --- /dev/null +++ b/admin/lang/ua/groups.txt @@ -0,0 +1,125 @@ +# солов’їна))) 01,2017 duncan + +[groups] +UGROUP_TITLE = "Керування групами користувачів" +UGROUP_TITLE2 = "Керування групою користувачів" +UGROUP_TITLE_MENU = "Групи користувачів" +UGROUP_INFO = "У цьому розділі наведено cписок усіх груп користувачів у системі. Для кожної групи Ви можете назначити персональні права, які дозволять або обмежать дії користувачів як в Панелі керування, так і в Публічній частині cайту." +UGROUP_ID = "ID" +UGROUP_NAME = "Назва групи" +UGROUP_COUNT = "Користувачів в групі" +UGROUP_ACTIONS = "Дії" +UGROUP_IN_GROUP = "Перегляд списку користувачів, які відносяться до цієї групи" +UGROUP_EDIT = "Редагувати назву та права групи" +UGROUP_NO_PERMISSION = "Даруйте, але у Вас недостатньо прав для редагування" +UGROUP_DELETE = "Видалити цю групу" +UGROUP_USERS_IN_GROUP = "На цей час Ви не можете видалити цю групу, оскільки є користувачі, які перебувають у цій групі." +UGROUP_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити цю групу?" +UGROUP_NO_DELETABLE = "Ви не можете видалити цю групу, оскільки вона є системною." +UGROUP_NO_PERM_DELETE = "Даруйте, але у Вас недостатньо прав для видалення цієї групи." +UGROUP_NEW_GROUP = "Додати нову групу" +UGROUP_NEW_NAME = "Назва групи:" +UGROUP_BUTTON_ADD = "Додати" +UGROUP_LEGEND_LINK = "Значення піктограм" +UGROUP_LEGEND_EDIT = "Редагувати групу користувачів" +UGROUP_LEGEND_DELETE = "Видалити групу користувачів" +UGROUP_ENTER_NAME = "Будь ласка, вкажіть назву групи користувачів" +UGROUP_WARNING_TIP = "Увага! Будьте уважні при призначені тих або інших прав для цієї групи користувачів. Пам’ятайте, що даючи доступ до певних розділів, Ви можете зробити систему вразливою." +UGROUP_YOUR_NOT_CHANGE = "Помилка! Даруйте, але Ви не маєте прав для редагування цієї групи користувачів." +UGROUP_NOT_EXIST = "Помилка! Даруйте, але групи користувачів, яку Ви шукаєте, не існує." +UGROUP_NO_MODULES = "Немає встановлених модулів" +UGROUP_MODULES_RIGHT = "Будь ласка, вкажіть модулі, до яких буде дозволено доступ для цієї групи користувачів." +UGROUP_CONTROL_RIGHT = "Будь ласка, вкажіть розділи Панелі керування, до яких буде дозволено або обмежено доступ для цієї групи користувачів." +UGROUP_BUTTON_SAVE = "Зберегти зміни" +UGROUP_BUTTON_SAVE_AJAX = "Примінити (CTRL+S)" +UGROUP_SAVE_CONFIRM = "Ви впевнені, що бажаєте зберегти права для цієї групи користувачів?" +UGROUP_NAME_EDIT = "Редагувати назву групи" +UGROUP_OR = "або" +UGROUP_SAVED = "Права для групи успішно збережено" +UGROUP_SAVED_ERR = "Не вдалося зберегти права для групи.
Спробуйте ще раз." +UGROUP_ERROR = "Помилка" +UGROUP_SUCCESS = "Виконано" +UGROUP_SAVE_MAIN = "Змінив права доступу для групи" + +UGROUP_REPORT_ADD = "Створив групу користувачів" +UGROUP_REPORT_DEL = "Видалив групу користувачів" + +alles = "Дозволити усі права (Будьте уважні!)" +adminpanel = "Доступ до Панелі керування" + +gen_settings = "Доступ до керування загальними налаштуваннями системи" +gen_settings_more = "Доступ до керування додатковими налаштуваннями системи" +gen_settings_countries = "Доступ до керування списком країн" +gen_settings_languages = "Доступ до керування мовами" + +logs_view = "Доступ до перегляду системних повід." +logs_clear = "Доступ до видалення системних повідомлень" + +db_actions = "Доступ до керування базою даних (Резервне копіювання, відновлення, оптимізація)" + +modules_view = "Доступ до списку модулів" +modules_admin = "Доступ до модулів (Налаштування, керування, використання)" +modules_system = "Доступ до керування модулями (видалення, установка)" + +navigation_view = "Доступ до списку меню навигацій" +navigation_edit = "Доступ до керування меню навигацій (Створення, редагування, видалення)" + +remark_view = "Доступ до списку приміток" +remark_edit = "Доступ до керування примітками у документів (Створення, редагування, видалення)" + +document_php = "Доступ до використання PHP коду в документах (Будьте уважні!)" +document_view = "Доступ до списку документів (права доступу до документів залежать від налаштувань рубрики)" +document_revisions = "Доступ до видалення усіх ревізій документів" + +rubric_view = "Доступ до перегляду списку рубрик" +rubric_edit = "Доступ до керування рубриками (Створення, редагування, видалення)" +rubric_php = "Доступ до використання PHP коду в шаблонах рубрик (Будьте уважні!)" +rubric_perms = "Доступ до керування правами доступу для документів рубрики" +rubric_code = "Доступ до виконуваного коду для рубрик (Будьте уважні!)" + +template_view = "Доступ до списку шаблонів" +template_edit = "Доступ до керування шаблонами (Створення, редагування, видалення)" +template_php = "Доступ до використання PHP коду в шаблонах (Будьте уважні!)" + +request_view = "Доступ до списку запитів" +request_edit = "Доступ до керування запитами (Створення, редагування, видалення)" +request_php = "Доступ до використання PHP коду в шаблонах запиту (Будьте уважні!)" + +blocks_view = "Доступ до перегляду списку візуальних блоків" +blocks_edit = "Доступ до керування візуальними блоками (Створення, редагування, видалення)" + +sysblocks_view = "Доступ до перегляду списку системних блоків" +sysblocks_edit = "Доступ до керування системними блоками (Створення, редагування, видалення)" + +user_view = "Доступ до списку користувачів" +user_edit = "Доступ до редагування параметрів користувачів" +user_perms = "Доступ до керування правами користувачів" + +group_view = "Доступ до списку груп користувачів" +group_edit = "Доступ до керування правами груп користувачів (Створення, редагування, видалення)" + +mediapool_int = "Доступ до менеджеру файлів" +mediapool_add = "Доступ до додавання нових файлів на сервер (у менеджері файлів)" +mediapool_del = "Доступ до видалення файлів зі сервера (у менеджері файлів)" +mediapool_finder = "Доступ до файлового менеджера (elFinder)" + +cache_clear = "Доступ до видалення кеша" +cache_thumb = "Доступ до видалення прев’ю зображень (thumbnail)" + +logs = "Системні повідомлення" +cache = "Керування кешем" +gen = "Системні налаштування" +db = "База даних" +blocks = "Візуальні блоки" +sysblocks = "Системні блоки" +rubric = "Рубрики" +document = "Документи" +modules = "Модулі" +mediapool = "Файлові менеджери" +navigation = "Навігація" +request = "Запити" +template = "Шаблони" +remark = "Примітки у документів" +document = "Документи" +user = "Користувачі" +group = "Групи користувачів" \ No newline at end of file diff --git a/admin/lang/ua/logs.txt b/admin/lang/ua/logs.txt new file mode 100644 index 0000000..dfd5504 --- /dev/null +++ b/admin/lang/ua/logs.txt @@ -0,0 +1,55 @@ +# солов’їна))) 01,2017 duncan + +[logs] +LOGS_SUB_TITLE = "Керування системними повідомленнями" +LOGS_TITLE = "Журнал системних подій" +LOGS_TIP = "У цьому розділі наведено список усіх дій, які здійснюються в Панелі керування." +LOGS_ID = "№" +LOGS_IP = "Ip-адреса" +LOGS_DATE = "Дата" +LOGS_USER = "Користувач" +LOGS_ACTION = "Дії" +LOGS_BUTTON_DELETE = "Очистити журнал" +LOGS_DELETE_CONFIRM = "Ви впевнені, що бажаєте очистити журнал системних повідомлень?" +LOGS_BUTTON_EXPORT = "Експорт журналу системних повідомлень" +LOGS_BUTTON_EXPORT_404 = "Експорт журналу помилок 404" +LOGS_DATE_FORMAT = "%d.%m.%y г." +LOGS_DATE_FORMAT2 = "%H:%M" +LOGS_IN = "в" +LOGS_CLEAR = "Системні повідомлення успішно видалено." +LOGS_CLEAN = "Очистив журнал подій" +LOGS_EXPORT = "Експортував журнал подій" + +LOGS_404_SUB_TITLE = "Журнал помилок 404" +LOGS_404_TITLE = "Журнал помилок 404" +LOGS_404_TIP = "У цьому розділі наведено список усіх помилок 404." +LOGS_404_ID = "№" +LOGS_404_IP = "Ip-адреса" +LOGS_404_DATE = "Дата" +LOGS_404_ACTION = "Дії" +LOGS_404_BUTTON_DELETE = "Очистити журнал" +LOGS_404_DELETE_CONFIRM = "Ви впевнені, що бажаєте очистити журнал помилок 404?" +LOGS_404_BUTTON_EXPORT = "Експорт журналу помилок" +LOGS_404_DATE_FORMAT = "%d.%m.%y г." +LOGS_404_DATE_FORMAT2 = "%H:%M" +LOGS_404_IN = "в" +LOGS_404_CLEAR = "Системні повідомлення успішно видалено." +LOGS_404_CLEAN = "Очистив журнал помилок 404" +LOGS_404_EXPORT = "Експортував журнал помилок 404" + +LOGS_SQL_SUB_TITLE = "Журнал MySQL помилок" +LOGS_SQL_TITLE = "Журнал MySQL помилок" +LOGS_SQL_TIP = "У цьому розділі наведено список усіх помилок MySQL." +LOGS_SQL_ID = "№" +LOGS_SQL_IP = "Ip-адреса" +LOGS_SQL_DATE = "Дата" +LOGS_SQL_ACTION = "Дії" +LOGS_SQL_BUTTON_DELETE = "Очистити журнал MySQL помилок" +LOGS_SQL_DELETE_CONFIRM = "Ви впевнені, що бажаєте очистити журнал MySQL помилок?" +LOGS_SQL_BUTTON_EXPORT = "Експорт журналу MySQL помилок" +LOGS_SQL_DATE_FORMAT = "%d.%m.%y г." +LOGS_SQL_DATE_FORMAT2 = "%H:%M" +LOGS_SQL_IN = "в" +LOGS_SQL_CLEAR = "Журнал помилок MySQL успішно видалено." +LOGS_SQL_CLEAN = "Очистив журнал MySQL помилок" +LOGS_SQL_EXPORT = "Експортував журнал MySQL помилок" \ No newline at end of file diff --git a/admin/lang/ua/main.txt b/admin/lang/ua/main.txt new file mode 100644 index 0000000..03d7372 --- /dev/null +++ b/admin/lang/ua/main.txt @@ -0,0 +1,305 @@ +# солов’їна))) 01,2017 duncan + +MAIN_WELCOME = "Ласкаво просимо в Панель керування!" +MAIN_WELCOME_INFO = "На головній сторінці Ви можете вибрати одну з найбільш часто виконуваних дій." + +MAIN_PAGE = "Головна сторінка" + +MAIN_LOGIN_INTRO = "Авторизація" +MAIN_LOGIN_BACK_SITE = "Повернутися на сайт" +MAIN_LOGIN_NAME = "Логін:" +MAIN_LOGIN_PASSWORD = "Пароль:" +MAIN_LOGIN_BUTTON = "Увійти" +MAIN_LOGIN_REGISTER = "Реєстрація" +MAIN_LOGIN_LOST = "Забули пароль?" +MAIN_LOGIN_HELP = "Допомога" +MAIN_LOGIN_REMEMBER = "Запам’ятати мене" +MAIN_LOGIN_CAP_CODE = "Код:" +MAIN_LOGIN_CAP_CODE_REF = "Оновити код:" +MAIN_LOGIN_CAP_CODE_REFR = "Оновити код" + +MAIN_LINK_HOME = "Головне меню" +MAIN_LINK_AUTHOR = "Сайт підтримки" +MAIN_LINK_DATABASE = "Керування базою даних" +MAIN_LINK_NAVIGATION = "Керування меню навігації" +MAIN_LINK_MODULES = "Керування модулями" +MAIN_LINK_MODULES_H = "Модулі" +MAIN_LINK_SETTINGS = "Керування налаштуваннями" +MAIN_LINK_SETTINGS_H = "Налаштування" +MAIN_LINK_USERS = "Керування користувачами" +MAIN_LINK_TEMPLATES = "Керування шаблонами" +MAIN_LINK_RUBRICS = "Керування рубриками" +MAIN_LINK_DOCUMENT = "Керування документами" +MAIN_LINK_QUERYES = "Керування запитами" +MAIN_LINK_GROUPS = "Керування групами" +MAIN_LINK_LANG = "Керування мовами" + +MAIN_BUTTON_LOGIN = "Увійти" +MAIN_BUTTON_ADD = "Додати" +MAIN_BUTTON_LOGOUT = "Вихід" + +MAIN_SETTINGS_EDIT_1 = "Загальні налаштування" +MAIN_SETTINGS_EDIT_2 = "Додаткові налаштування" +MAIN_SETTINGS_EDIT_3 = "Керування країнами" +MAIN_SETTINGS_EDIT_4 = "Створити резервну копію БД" + +MAIN_LINK_DOC_TIPS = "У цьому розділі наведено список усіх документів у системі." +MAIN_LINK_RUBRIK_TIP = "У цьому розділі наведено список усіх рубрик у системі." +MAIN_LINK_REQUEST_TIP = "У цьому розділі наведено список усіх існуючих запитів у системі." +MAIN_LINK_NAVI_TIP = "У цьому розділі наведено список усіх меню навігацій у системі." +MAIN_LINK_TEMPLATES_TIP = "У цьому розділі наведено список усіх шаблонів, які використовуються у системі." +MAIN_LINK_MODULES_TIP = "У цьому розділі наведено список усіх доступних модулів у системі." +MAIN_LINK_SETTINGS_TIP = "У цьому розділі наведено усі глобальні параметри системи." +MAIN_LINK_DB_TIP = "У цьому розділі Ви можете працювати з базою даних системи." +MAIN_LINK_USER_TIP = "У цьому розділі наведено список усіх користувачів у системі." +MAIN_LINK_UGROUP_TIP = "У цьому розділі наведено cписок усіх груп користувачів у системі." + +MAIN_PAGE_TITLE = "Панель керування" +MAIN_LOGIN_TEXT = "Авторизація" +MAIN_LOGIN_TEXT2 = "Будь ласка, вкажіть Ваші дані:" +MAIN_LOGIN_CAPTCHA = "Введіть код:" +MAIN_SELECT_LANGUAGE = "Мову:" +MAIN_SELECT_THEME = "Тема оформлення:" +MAIN_YOUR_EMAIL = "E-mail:" +MAIN_YOUR_LOGIN = "Логін або E-mail:" +MAIN_YOUR_PASSWORD = "Пароль:" + +MAIN_LINK_SITE = "Подивитися сайт" +MAIN_LINK_HOME = "На головну" +MAIN_LINK_LOGOUT = "Вихід з Панелі керування" +MAIN_LINK_LOGOUT_QUEST = "Ви впевнені, що бажаєте вийти?" +MAIN_LINK_CACHE_CLEAR = "Очистка кеша" +MAIN_LINK_CACHE_CLEAR_QUEST = "Ви впевнені, що бажаєте очистити кеш?" + +MAIN_LINK_SITE_ON = "Увімкнути редактор" +MAIN_LINK_SITE_OFF = "Вимкнути редактор" + +MAIN_LINK_EDIT = "Редагувати на сайті" +MAIN_ADD_IN_RUB = "Додати новий документ:" +MAIN_DOCUMENTS_ALL = "Список документів:" +MAIN_SEARCH_DOCUMENTS = "Пошук документів:" +MAIN_SORT_DOCUMENTS = "Швидкий відбір:" +MAIN_TIME_PERIOD = "Період публікації" +MAIN_TIME_START = "Початок" +MAIN_TIME_END = "Кінець" +MAIN_BUTTON_SEARCH = "Пошук" +MAIN_TITLE_SEARCH = "Назва документа:" +MAIN_TITLE_DOC_NAME = "Назва документа" +MAIN_TITLE_DOC_ID = "ID документа" +MAIN_SEARCH_HELP = Використання пошука

Використовуйте знак "+" для чіткого включения слова в пошук.
Використовуйте знак "-" для виключення слова з пошука.

Обов’язково використовуйте пробіл перед знаками "+" та "-"." +MAIN_ID_SEARCH = "ID документа:" +MAIN_SELECT_RUBRIK = "В рубриці:" +MAIN_ALL_RUBRUKS = "Усі рубрики" +MAIN_ALL_DOCUMENTS = "Будь-який статус" +MAIN_DOCUMENT_STATUS = "Статус документа" +MAIN_DOCUMENT_ACTIVE = "Тільки активний" +MAIN_DOCUMENT_INACTIVE = "Тільки неактивний" +MAIN_TEMP_DELETE_DOCS = "Тимчасово видалений" +MAIN_RESULTS_ON_PAGE = "Результатів на сторінці:" +MAIN_OPEN_MEDIAPATH = "Подивитися на сервері" +MAIN_NAVI_UGROUPS = "Групи користувачів" +MAIN_UGROUP_EDIT = "Редагувати права групи" +MAIN_UGROUP_DELETE = "Видалити цю групу" +MAIN_LOGS = "Системні події" +MAIN_NAVI_MODULES = "Керування модулями" +MAIN_NAVIGATION = "Меню навігацій" +MAIN_NAVIGATION_NEW = "Додати нове меню" +MAIN_QUERIES = "Запити" +MAIN_REQUEST_NEW = "Додати новий запит" +MAIN_RUBRIKS = "Рубрики" +MAIN_RUBRIK_NEW = "Додати нову рубрику" +MAIN_RUBRIK_EDIT_FIELDS = "Редагувати поля рубрики" +MAIN_RUBRIK_EDIT_TEMPL = "Редагувати шаблон рубрики" +MAIN_SETTINGS = "Системні налаштування" +MAIN_COUNTRY_EDIT = "Керування країнами" +MAIN_SYSBLOCKS = "Системні блоки" +MAIN_TEMPLATES = "Шаблони" +MAIN_TEMPLATES_NEW = "Додати новий шаблон" +MAIN_USERS = "Користувачі" +MAIN_DATABASE_INFO = "База даних" +MAIN_NAVI_DOCUMENTS = "Документи" +MAIN_BROWSE_DOCUMENTS = "Подивитися в документах" +MAIN_USERS_LIST = "Список користувачів" +MAIN_USER_ADD = "Додати нового користувача" +MAIN_SEARCH_USERS = "Пошук користувачів за:" +MAIN_USER_PARAMS = "Іменем, Id, E-mail, E-mail домену" +MAIN_USER_STATUS = "Зі статусом:" +MAIN_USER_STATUS_ALL = "Будь-який статус" +MAIN_USER_STATUS_ACTIVE = "Активний" +MAIN_USER_STATUS_INACTIVE = "Очікує активації" +MAIN_USER_GROUP = "Перебуває в групі:" +MAIN_USER_ONLINE = "Ласкаво просимо," +MAIN_USER_PERM = "Статус:" +MAIN_ALL_USER_GROUP = "У будь-який" +MAIN_BUTTON_SEARCH_USER = "Найти користувачів по параметрах" +MAIN_NO_PERMISSION = "Даруйте, але Ви не маєте прав доступу до такого розділу" +MAIN_LOGOUT_CONFIRM = "Ви впевнені, що бажаєте вийти?" + +MAIN_START_DOC_TITLE = "Останні документи" +MAIN_START_DOC_ID = "id" +MAIN_START_DOC_NAME = "Назва" +MAIN_START_DOC_RUBRIC = "Рубрика" +MAIN_START_DOC_DATE = "Опубліковано" +MAIN_START_DOC_AUTOR = "Автор" + +MAIN_START_SEARCH = "Пошук:" +MAIN_START_SEARCH_T = "Шукати документ" + +MAIN_START_LOGS_LOG = "Журнал операцій" +MAIN_START_LOGS_404 = "Помилки 404" +MAIN_START_LOGS_SQL = "Помилки MySQL" + +MAIN_TABLE_SUCC = "Кількість успішно завантажених таблиць: " +MAIN_TABLE_ERROR = "Кількість таблиць з помилками: " +MAIN_SQL_FILE_ERROR = "SQL-файл має неправильний формат або містить помилки в структурі запитів." +MAIN_RESTORE_OK = "Базу даних успішно відновлено" + +MAIN_NO_PERM_MODULES = "Даруйте, але у вас недостатньо прав для керування таким модулем" +MAIN_MP_FILE_DELETE = "Видалити файл" +MAIN_MP_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити файл: " +MAIN_MP_DOC_FOLDER = "Список папок / файлів" +MAIN_MP_FILE_SIZE = "Розмір файла" +MAIN_MP_FILE_DATE = "Дата створення" +MAIN_MP_ACTIONS = "Дії" +MAIN_MP_FILE_INFO = "Щоби додати файл, натисніть на його назву, а потом на кнопку вставити файл" +MAIN_MP_UP_LEVEL = "Повернутися на рівень вище" +MAIN_MP_CREATE_FOLDER = "Створити папку" +MAIN_MP_UPLOAD_FILE = "Завантажити файл" +MAIN_MP_FILE_INSERT = "Вставити файл" +MAIN_MP_DIR_INSERT = "Вибрати папку" +MAIN_MP_SELECT_FILES = "Оберіть файли для завантаження" +MAIN_MP_IMAGE_RESIZE = "Змінити розмір завантажених зображень" +MAIN_MP_IMAGE_WIDTH = "Ширина" +MAIN_MP_IMAGE_HEIGHT = "Висота" +MAIN_BUTTON_UPLOAD = "Завантажити" +MAIN_BUTTON_WAIT = "Будь ласка, зачекайте..." +MAIN_MP_PLEASE_SELECT = "Будь ласка, оберіть файл" +MAIN_ADD_IN = "Оберіть рубрику:" +MAIN_GROUP_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити цю групу?" +MAIN_RUBRIKS_LIST = "Список рубрик" +MAIN_USER = "Користувач:" +ButtonSave = "Зберегти" +MAIN_NEW_PAGE = "Додати нову сторінку" +MAIN_BUTTON_SORT = "Відібрати" +MAIN_QUICK_MODULE = "Керування модулями" +MAIN_STAT = "Статистика" +MAIN_STAT_SYSTEM_INFO = "Системна інформація" +MAIN_STAT_DOCUMENTS = "Усього документів:" +MAIN_STAT_RUBRICS = "Усього рубрик:" +MAIN_STAT_QUERIES = "Усього запитів:" +MAIN_STAT_TEMPLATES = "Усього шаблонів:" +MAIN_STAT_MYSQL = "Розмір бази даних:" +MAIN_STAT_CACHE = "Загальний розмір кеша:" +MAIN_STAT_CACHE_SHOW = "Показати" +MAIN_STAT_MODULES = "Встановлено модулів:" +MAIN_STAT_MODULES_OFF = "Вимкнено модулів:" +MAIN_STAT_USERS = "Усього користувачів:" +MAIN_STAT_USERS_WAIT = "Очікують активацію:" +MAIN_STAT_AVE = "AVE.cms" +MAIN_STAT_DOMEN = "Домен" +MAIN_STAT_PHP = "PHP Версія:" +MAIN_STAT_MYSQL_VERSION = "MySQL Версія:" +MAIN_STAT_CLEAR_CACHE = "Очистити кеш" +MAIN_STAT_CLEAR_CACHE_FULL= "Очистити кеш та сесії" +MAIN_STAT_CLEAR_THUMB = "Видалити мініатюри" +MAIN_STAT_CLEAR_REV = "Видалити ревізії" +MAIN_STAT_CLEAR_COUNT = "Обнулити поденний лічильник" +MAIN_ADD_FOLDER = "Будь ласка, введіть ім’я для нової папки:" +MAIN_NO_ADD_FOLDER = "Не вказано ім’я папки або дію відмінено!" +MAIN_NO_ADD_TEMPL = "Не вказано назву шаблона або дію відмінено!" +MAIN_NO_ADD_GROUP = "Не вказано назву групи або дію відмінено!" +MAIN_NO_ADD_RUB = "Не вказано назву рубрики або дію відмінено!" +MAIN_NO_ADD_QUERY = "Не вказано назву запиту або дію відмінено!" +MAIN_NO_ADD_NAV = "Не вказано назву навигації або дію відмінено!" +MAIN_NO_ADD_BLOCK = "Не вказано назву системного блока або дію відмінено!" +MAIN_NO_ADD_USER = "Не вказано ім’я користувача або дію відмінено!" +MAIN_NO_ADD_DOCS = "Не вказано назву документа або дію відмінено!" +MAIN_CLEAR_CACHE_OK = "Кеш очищено" +MAIN_FILE_MANAGER_TITLE = "Файловий менеджер" +MAIN_FILE_MANAGER_TIP = "Оберіть потрібний файл та натисніть на кнопку "вставити файл"" + +MAIN_SVN_NEW = "Вийшла новая версія" +MAIN_SVN_SAIT = "Перейти на сайт" +MAIN_SVN_REPOS = "Перейти на сайт репозиторія" +MAIN_SVN_MAILTO = "Написати лист" +MAIN_SVN_LOOK = "Подивитися ревізію на сайті репозиторія" +MAIN_SVN_RECOM = "Рекомендовано оновитися!" + +MAIN_FINDER = "Файловий менеджер" + +MAIN_ADD_NEW_GROUP = "Додати нову групу" +MAIN_ADD_NEW_GROUP_NAME = "Назва групи:" + +MAIN_ADD_NEW_USER = "Додати нового користувача" +MAIN_ADD_NEW_USER_NAME = "Ім’я користувача:" + +MAIN_ADD_NEW_NAV = "Додати нову навігацію" +MAIN_ADD_NEW_NAV_NAME = "Назва навигації:" + +MAIN_ADD_NEW_TEMPL = "Додати новий шаблон" +MAIN_ADD_NEW_TEMPL_NAME = "Назва шаблона:" + +MAIN_ADD_NEW_REQUEST = "Додати новий запит" +MAIN_ADD_NEW_REQUEST_NAME = "Назва запиту:" + +MAIN_ADD_NEW_RUB = "Додати нову рубрику" +MAIN_ADD_NEW_RUB_NAME = "Назва рубрики:" + +MAIN_ADD_NEW_BLOCK = "Додати новий системний блок" +MAIN_ADD_NEW_BLOCK_NAME = "Назва системного блока:" + +MAIN_USERS_LAST_TIME = "За останній час було:" + +MAIN_LOGS_ID = "№" +MAIN_LOGS_IP = "Ip-адреса" +MAIN_LOGS_DATE = "Дата" +MAIN_LOGS_USER = "Користувач" +MAIN_LOGS_ACTION = "Дії" + +MAIN_DOC_SHOW3_TITLE = "Документ без назви" +MAIN_DOC_EDIT_TITLE = "Редагувати цей документ" +MAIN_DOC_SHOW_TITLE = "Перегляд документа (Посилання без ЧПУ)" +MAIN_DOC_SHOW2_TITLE = "Перегляд документа (Посилання з ЧПУ)" + +MAIN_ADD_DOC = "Документ" +MAIN_ADD_RUB = "Рубрику" +MAIN_ADD_REQ = "Запит" +MAIN_ADD_SYS = "Системний блок" +MAIN_ADD_TEM = "Шаблон" +MAIN_ADD_NAV = "Навігацію" +MAIN_ADD_USR = "Користувача" +MAIN_ADD_GRP = "Групу" + +MAIN_BRANCHES = "Розділи" +MAIN_SHOWHIDE = "Показати/приховати меню" + +MAIN_CODEMIRROR_HELP = "Ctrl-F/Cmd-F (Шукати) | Ctrl-G/Cmd-G (Шукати далі) | Shift-Ctrl-G/Shift-Cmd-G (Найти попереднє) | Shift-Ctrl-F/Cmd-Option-F (Замінити) | Shift-Ctrl-R / Shift-Cmd-Option-F (Замінити усі) | F11 (На повний екран)" + +TEMPLATES_MESSAGE = "Повідомлення:" +TEMPLATES_CACHE_SUCCESS = "Кеш успішно очищено." +TEMPLATES_CACHE_SUCCESS_LOG = "Очистив кеш" +TEMPLATES_CACHE_DB_SUCCESS = "Таблиця _sessions успішно очищена." +TEMPLATES_CACHE_DB_SUCCESS_LOG = "Очистив таблицю _sessions." +TEMPLATES_CACHE_CT_SUCCESS = "Видалено скомпільовані шаблони." +TEMPLATES_CACHE_CT_SUCCESS_LOG = "Видалив скомпільовані шаблони" +TEMPLATES_CACHE_MC_SUCCESS = "Видалено скомпільовані шаблони модулів." +TEMPLATES_CACHE_MC_SUCCESS_LOG = "Видалив скомпільовані шаблони модулів" +TEMPLATES_CACHE_SU_SUCCESS = "Видалено сесії користувачів." +TEMPLATES_CACHE_SU_SUCCESS_LOG = "Видалив сесії користувачів" +TEMPLATES_CACHE_SC_SUCCESS = "Видалено кеш sql запитів." +TEMPLATES_CACHE_SC_SUCCESS_LOG = "Видалив кеш sql запитів" +TEMPLATES_THUMBNAILS_SUCCESS = "Мініатюри успішно видалено." +TEMPLATES_THUMBNAILS_SUCCESS_LOG = "Видалив мініатюри" + +EXIT_ADMIN = "Закінчив сеанс у Панелі керування" +LOGIN_ADMIN = "ПОчав сеанс у Панелі керування" +ERROR_ADMIN = "Помилка при вході до Панелі керування" + +WRONG_PASS = "Помилка:
Ім’я користувача або пароль неправильні!" +WRONG_CAPTCHA = "Помилка:
Неправильний захисний код" + +oficial_site = "Офіційний сайт" +support = "Служба технічної підтримки" + +// 3.1.9 +MAIN_BLOCKS = "Візуальні блоки" diff --git a/admin/lang/ua/modules.txt b/admin/lang/ua/modules.txt new file mode 100644 index 0000000..ffd650b --- /dev/null +++ b/admin/lang/ua/modules.txt @@ -0,0 +1,38 @@ +# солов’їна))) 01,2017 duncan + +[modules] +MODULES_SUB_TITLE = "Керування модулями" +MODULES_TIP = "У цьому розділі наведено список усіх доступних модулів у системі. Тут Ви можете встановити, відключити, оновити будь-який з модулів, а також виконати додаткові персональні налаштування для будь-якого з модулів." +MODULES_NAME = "Назва модуля" +MODULES_INFO = "Інформація" +MODULES_TEMPLATE = "Шаблон виводу" +MODULES_SYSTEM_TAG = "Системний тег" +MODULES_VERSION = "Версія" +MODULES_ACTIONS = "Дії" +MODULES_SETTINGS = "Параметри" +MODULES_SETTINGS_INFO = "Інформація" +MODULES_DELETE = "Видалити модуль" +MODULES_DELETE_CONFIRM = "Пам’ятайте, що видаляючи модуль з системи, Ви видаляєте його тільки на програмному рівні. Таким чином, в майбутньому, Ви завжди можете його встановити заново.
Ви впевнені, що бажаєте видалити цей модуль?" +MODULES_INSTALL = "Встановити модуль" +MODULES_REMOVE = "Видалити модуль з сервера" +MODULES_REINSTALL = "Перевстановити модуль" +MODULES_REINSTALL_CONF = "Ви впевнені, що бажаєте перевстановити цей модуль?" +MODULES_UPDATE = "Оновити модуль" +MODULES_STOP = "Відключити модуль" +MODULES_START = "Увімкнути модуль" +MODULES_BUTTON_SAVE = "Зберегти зміни" +MODULES_LEGEND = "Значення піктограм" +MODULES_AUTHOR = "Автор модуля" +MODULES_ERROR = "Возникла помилка при завантаженні модуля: " +MODULES_INSTALLED = "Встановлені модулі:" +MODULES_NOT_INSTALLED = "Невстановлені модулі:" +MODULES_SETUP = "Перейти до керування модулем" +MODULES_NO_INSTALL = "Повідомлення:
Немає встановлених модулів." +MODULES_NOT_INSTALL = "Повідомлення:
Немає невстановлених модулів." +MODULES_ACTION_INSTALL = "Встановив модуль" +MODULES_ACTION_ONLINE = "Включив модуль" +MODULES_ACTION_OFFLINE = "Відключив модуль" +MODULES_ACTION_REINSTALL = "Перевстановив модуль" +MODULES_ACTION_UPDATE = "Оновив модуль" +MODULES_ACTION_DELETE = "Видалив модуль зі системи" +MODULES_ACTION_REMOVE = "Видалив модуль зі сервера" \ No newline at end of file diff --git a/admin/lang/ua/navigation.txt b/admin/lang/ua/navigation.txt new file mode 100644 index 0000000..61f7a72 --- /dev/null +++ b/admin/lang/ua/navigation.txt @@ -0,0 +1,134 @@ +# солов’їна))) 01,2017 duncan + +[navi] +NAVI_ID = "ID" +NAVI_SUB_TITLE = "Керування меню навігації" +NAVI_SUB_TITLE2 = "Керування пунктами меню" +NAVI_SUB_TITLE3 = "Редагування шаблона меню" +NAVI_SUB_TITLE4 = "Створення нового шаблона меню" +NAVI_TIP_TEMPLATE = "У цьому розділі наведено список усіх меню навігацій у системі. Тут Ви можете змінити шаблон виводу будь-якого з доступних меню, а також додати або видалити пункти меню." +NAVI_TIP_TEMPLATE2 = "У цьому розділі, використовуючи мову розмітки HTML, Ви можете створити шаблон оформлення для цього меню навігації. також, Ви можете вибрати групи користувачів, для яких буде доступне це меню навігації. Для вибору декількох груп затисніть кнопку CTRL." +NAVI_ITEMS_TIP = "Створення нового пункта меню" +NAVI_NEW_MENU = "Створення нового меню" +NAVI_LIST_TIP = "Cписок нижче містить усі пункти, які стосуються цього меню. Пам’ятайте, що максимальний рівень вкладень не може бути більше 2." +NAVI_LIST = "Список пунктів меню" +NAVI_EDIT_TEMPLATE = "Редагування шаблона меню" +NAVI_EDIT_ITEMS = "Редагування пунктів меню" +NAVI_OPEN_IN_THIS = "У поточному вікні" +NAVI_OPEN_IN_NEW = "у новому вікні" +NAVI_TARGET_WINDOW = "Відкривати" +NAVI_POSITION = "Позиція" +NAVI_LINK_TO_DOCUMENT = "Посилання на документ/файл" +NAVI_ENTRIES_NO_ITEMS = "Повідомлення:
На цей час немає пунктів меню." + +NAVI_LINK_TITLE = "Назва пункта меню" +NAVI_LINK_SOLUT = "Опис для пункта меню:" +NAVI_LINK_IMGID = "Id зображення:" +NAVI_LINK_IMGTL = "Вибрати зображення:" +NAVI_LINK_IMAGE = "Зображення для пункта меню" +NAVI_TITLE = "Назва меню навігації:" +NAVI_TITLE2 = "Введіть назву меню навігації:" +NAVI_BROWSE_DOCUMENTS = "Зв’язати з існуючим документом" +NAVI_ADD_SUBITEM = "Додати новий підпункт" +NAVI_BUTTON_CHANGE = "Вибрати" +NAVI_BUTTON_OPTION = "Опції" +NAVI_BUTTON_SUBITEM = "+" +NAVI_BROWSE_MEDIAPOOL = "Зв’язати з файлом на сервері" +NAVI_SYSTEM_TAG = "Системний тег" +NAVI_NAME = "Назва меню" +NAVI_LINK_TARGET = "Тег, який визначає тип відкриття документа (у новому або поточному вікні)" +NAVI_LINK_URL = "Тег, який визначає адресу для переходу" +NAVI_LINK_NAME = "Тег, який визначає назву посилання, яке буде відображене в меню" +NAVI_LINK_ID = "Тег, який визначає унікальний ідентифікатор посилання" +NAVI_LINK_INACTIVE = "Оформлення неактивного посилання:" +NAVI_LINK_ACTIVE = "Оформлення активного посилання:" +NAVI_HEADER_START = "Верхня частина оформлення:" +NAVI_FOOTER_END = "Нижня частина оформлення:" +NAVI_HEADER_TIP = "Наприклад, заголовок
"Каталог товарів"
(не обов’язкове)" +NAVI_COPY_TEMPLATE = "Копіювати шаблон меню" +NAVI_FOOTER_TIP = "Нижня частина оформлення меню
(не обов’язкове)" +NAVI_DELETE = "Видалити це меню" +NAVI_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити це меню навігації?" +NAVI_HTML_START = "Початковий HTML код:" +NAVI_HTML_END = "Кінцевий HTML код:" +NAVI_LEVEL1 = "Шаблон оформлення для головного (першого) рівня пунктів меню" +NAVI_LEVEL2 = "Шаблон оформлення для першого рівня вкладених пунктів меню" +NAVI_LEVEL3 = "Шаблон оформлення для другого рівня вкладених пунктів" +NAVI_MARK_DELETE = "Відмітити цей пункт для видалення" +NAVI_MARK_ACTIVE = "Для того, щоб тимчасово відключити цей пункт меню, зніміть виділення та натисніть "Зберегти зміни"" +NAVI_GROUPS = "Групи користувачів, яких буде доступно меню:" +NAVI_ACTIONS = "Дії" +NAVI_OR_BUTTON = " або " +NAVI_BUTTON_SAVE = "Зберегти зміни" +NAVI_BUTTON_SAVE_NEXT = "Примінити (CTRL+S)" +NAVI_BUTTON_ADD = "Додати пункт" +NAVI_BUTTON_ADD_MENU = "Створити меню" +NAVI_LEGEND = "Значення піктограм" +NAVI_ENTER_NAME = "Будь ласка, вкажіть назву меню навігації." +NAVI_ALL = "Список меню навігацій" +NAVI_PRINT_TYPE = "Тип виводу" +NAVI_EXPAND_ALL = "Повністю (розкривати усі рівні)" +NAVI_EXPAND_WAY = "поточний та батьківський рівні" +NAVI_EXPAND_LEVEL = "Тільки поточний рівень" +NAVI_MENU_NOT_FOUND = "Відсутнє меню id=" +NAVI_SAVE = "Шаблон навігації успішно збережено" +NAVI_SORTED = "Порядок успішно збережено" + +NAVI_REPORT_NEW = "Створив меню навігації" +NAVI_REPORT_COPY = "Створив копію меню навігації" +NAVI_REPORT_EDIT = "Змінив шаблон меню навігації" +NAVI_REPORT_DEL = "Видалив меню навігації" +NAVI_REPORT_ADDIT = "Додати пункт меню навігації" +NAVI_REPORT_DELIT = "Видалив пункт меню навігації" +NAVI_REPORT_FLEV = "На перший рівень" +NAVI_REPORT_SLEV = "На другий рівень" +NAVI_REPORT_TLEV = "На третій рівень" +NAVI_REPORT_DEACT = "Деактивував пункт меню навігації" +NAVI_REPORT_ACT = "Активував пункт меню навігації" +NAVI_REPORT_SAVED = "Шаблон навігації успішно збережено" +NAVI_REPORT_SAVED_ERR = "Не вдалося зберегти шаблон навігації.
Спробуйте ще раз." +NAVI_REPORT_ERROR = "Помилка" +NAVI_REPORT_SUCCESS = "Виконано" + +NAVI_ITEM_ON_OFF = "Вкл/Викл пункт меню" +NAVI_ITEM_EDIT = "Редагувати пункт меню" +NAVI_ITEM_DELETE = "Видалити цей пункт меню" +NAVI_ITEM_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити цей пукт меню навігації?" + + +// v 3.2 +NAVI_ALIAS = "Аліас" +NAVI_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:sysblock:alias] замість [tag:sysblock:id]. Аліас не може бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах модуля" +NAVI_ACCEPT = "Цей аліас можна використовувати" +NAVI_ER_SYN = "Неправильний аліас!
Аліас не може бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +NAVI_ER_EXISTS = "Неправильний аліас!
Цей аліас уже прив’язаний до іншого меню" + +//from templates +NAVI_NOLINK_DOC = "Немає зв’язаного документа" +NAVI_EDIT_ITEM = "Редагування пункта меню" +NAVI_LINK_FILEDOC = "Зв’язати з документом/файлом" +NAVI_LINKED_DOC = "Зв’язаний документ" +NAVI_DEL_LINKED_DOC = "Вилучити зв’язок з документом" +NAVI_LINK_DOC = "Зв’язати з документом" +NAVI_LINK_FILE = "Зв’язати з файлом" +NAVI_NO_LINK = "Немає зв’язаного документа" +NAVI_STRUCTURE = "Структура" +NAVI_RETURN_TO_LIST = "Повернутися до списку" +NAVI_EDIT_TEMPLATE = "Редагувати шаблон" +NAVI_ITEM_ADD = "Додати пункт меню" +NAVI_OPEN_ALL = "Розкрити усе" +NAVI_CLOSE_ALL = "Згоргути усе" +NAVI_ITEM_DESCR = "Опис пункта меню" +NAVI_ITEM_IMAGE = "Зображення" +NAVI_ITEM_IMAGE_DESCR = "Зображення активне, у кінці назви зображення має бути _act" +NAVI_ITEM_IMAGE_ID = "Id зображення" +NAVI_PLACE_INSERT = "Місце вставки підрівня" +NAVI_EXAMPLE = "Приклад" +NAVI_ITEM_EVEN = "парний" +NAVI_ITEM_ODD = "непарний" +NAVI_TAG = "Тег для вставки пунктів" +NAVI_LAVEL_TEMPL = "Шаблон рівня" +NAVI_CONDITIONS = "Умови" +/**/ +NAVI_CLOSE = "Закрити" +NAVI_ADD_AFTER = "Додати після" diff --git a/admin/lang/ua/request.txt b/admin/lang/ua/request.txt new file mode 100644 index 0000000..1509812 --- /dev/null +++ b/admin/lang/ua/request.txt @@ -0,0 +1,203 @@ +# солов’їна))) 01,2017 duncan + +[request] +REQUEST_ID = "ID" +REQUEST_DELETE = "Видалити запит" +REQUEST_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити цей запит?" +REQUEST_TITLE = "Керування запитами" +REQUEST_NAME = "Назва запиту" +REQUEST_NAME2 = "Назва запиту:" +REQUEST_NAME3 = "Введіть назву запиту:" +REQUEST_CACHE = "Кешувати:" +REQUEST_CACHE_ELEMENTS = "Кешувати елементи запиту" +REQUEST_SETTINGS = "Параметри запиту" +REQUEST_TIP = "У цьому розділі наведено список усіх існуючих запитів у системі. Для використання запиту розмістіть "Системний тег" у потрібному місці Вашого шаблона або документа." +REQUEST_EDIT_TIP = "У цьому розділі Ви можете відредагувати запит, змінивши рубрику для отримання даних, шаблон виводу, а також умови вибірки даних." +REQUEST_NEW = "Створення нового запиту" +REQUEST_EDIT = "Редагувати запит" +REQUEST_EDIT2 = "Редагування запиту" +REQUEST_SYSTEM_TAG = "Системний тег" +REQUEST_AUTHOR = "Автор" +REQUEST_DATE_CREATE = "Дата створення" +REQUEST_ACTIONS = "Дії" +REQUEST_NO_DESCRIPTION = "Запит без опису" +REQUEST_NO_REQUST = "Запити відсутні." +REQUEST_DATE_FORMAT = "%d.%m.%y г." +REQUEST_DATE_FORMAT2 = "%d.%m.%y г. в %H:%M" +REQUEST_IN = "в" +REQUEST_COPY = "Копіювати запит" +REQUEST_COPY_FAILED = "Не вдалося виконати копіювання запиту" +REQUEST_PLEASE_NAME = "Будь ласка, вкажіть назву для скопійованого запиту" +REQUEST_CONDITION_EDIT = "Умови для запиту" +REQUEST_CONDITION_IF = "Умови" +REQUEST_PLEASE_SELECT = "Будь ласка, оберіть рубрику" +REQUEST_SELECT_RUBRIK = "Оберіть рубрику:" +REQUEST_SELECT_INFO = "Ви впевнені, що бажаєте змінити рубрику" +REQUEST_NEW_TIP = "Увага! Перед тим, як створити новий запит, Ви повинні обрати рубрику, з якої будуть виводитися документи." +REQUEST_DESCRIPTION = "Опис запиту:" +REQUEST_INTERNAL_INFO = "(використовується всередині системи)" +REQUEST_BUTTON_COND = "Додати / змінити" +REQUEST_CONDITION = "Умови запиту:" +REQUEST_ACTION_AFTER = "Повернутися до редагування запиту після створення, щоб додати умови запиту." +REQUEST_SORT_BY = "Сортувати по параметру документа:" +REQUEST_SORT_BY_NAT = "Сортувати за полем документа:" +REQUEST_ASC_DESC = "В порядку:" +REQUEST_DESC = "спадання" +REQUEST_ASC = "зростання" +REQUEST_BY_DATE = "Даті створення (публікації)" +REQUEST_BY_DATECHANGE = "Даті зміни (документа)" +REQUEST_BY_NAME = "Назві документів" +REQUEST_BY_EDIT = "Імені автора" +REQUEST_BY_PRINTED = "Кількості роздруківок" +REQUEST_BY_VIEWS = "Кількості переглядів" +REQUEST_BY_RAND = "У випадковому порядку (високе навантаження)" +REQUEST_DOC_PER_PAGE = "Кількість на сторінці:" +REQUEST_DOC_PER_PAGE_ALL = "виводити усі" +REQUEST_SHOW_NAVI = "Показувати навігацію:" +REQUEST_USE_LANG = "Тільки мовою користувача:" +REQUEST_USE_QUERY = "Використовувати GET запити в посторінковій навігації" +REQUEST_TEMPLATE_QUERY = "Основний шаблон оформлення запиту" +REQUEST_MAIN_CONTENT = "Системний тег, що відповідає за вивід елементів запиту, вказаних в полі "елементи запиту"" +REQUEST_DOC_COUNT = "Системний тег, що відповідає за вивід кількості елементів запиту" +REQUEST_DOCITEMNUM_INFO= "Системний тег, що відповідає за вивід порядкового номера елемента запиту" +REQUEST_MAIN_NAVI = "Системний тег, що відповідає за вивід посторінкової навігації для запиту (< 1 2 3 >)" +REQUEST_MEDIAPATH = "Системний тег, який визначає шляхи до папки з шаблоном (наприклад: [tag:mediapath]images/logo.gif)" +REQUEST_PATH = "Системний тег, який визначає корінь установки" +REQUEST_TEMPLATE_ITEMS = "Шаблон оформлення для елементів запиту" +REQUEST_TEMPLATE_INFO = "У цьому полі, використовуючи HTML-код, Ви можете вказати оформлення для внутрішніх елементів запиту (наприклад, оформлення списку новин). Усі елементи, оформлені згідно такого шаблону, будуть циклічно відображатися в "Основному шаблоні" запиту, допоки кількість елементів, буде відповідати умовам запиту." +REQUEST_TEMPLATE_SAVED = "Запит успішно збережено" +REQUEST_SELECT_IN_LIST = "Будь ласка, оберіть поле рубрики зі списка, наведеного нижче" +REQUEST_RUB_INFO = "Системний тег, що відповідає за вивід вмісту поля рубрики. ID-номер поля. ХХХ-кількість символів для відображення." +REQUEST_LINK_INFO = "Системний тег, який визначає посилання на документ. Наприклад, < a href="[tag:link]">посилання < /a >" +REQUEST_RUBRIK_FIELD = "Системний тег поля" +REQUEST_THUMBNAIL = "Тег відповідає за створення мініатюрки (За умови що у шаблоні поля рубрики (шаблон для виводу в запиті) обрано вивід: [tag:parametr:0])" +REQUEST_FIELD_NAME = "Назва поля" +REQUEST_FIELD_TYPE = "Тип поля" +REQUEST_FIELD_G_UNKNOW = "Без групи" + +REQUEST_BUTTON_ADD = "Створити запит" +REQUEST_BUTTON_ADD_NEXT = "Створити та продовжити" +REQUEST_BUTTON_SAVE = "Зберегти зміни" +REQUEST_BUTTON_SAVE_NEXT = "Примінити (CTRL+S)" +REQUEST_BUTTON_CLOSE = "Закрити вікно" + +REQUEST_INSERT_INFO = "Натисніть на системний тег, щоб додати його в шаблон" +REQUEST_CONDITIONS = "Керування умовими запиту" +REQUEST_CONDITION_TIP = "У цьому розділі Ви можете створити спеціальні умови вибірки даних для запиту. Умови запиту дозволяють найбільш точно визначити вивід даних за тими або іншими параметрами." +REQUEST_NEW_CONDITION = "Додати нову умову" +REQUEST_FROM_FILED = "Вибрати з поля" +REQUEST_OPERATOR = "Де значення" +REQUEST_VALUE = "Значення" +REQUEST_COND_SELF = "Дорівнює" +REQUEST_COND_NOSELF = "Не дорівнює" +REQUEST_COND_USE = "Містить значення" +REQUEST_COND_NOTUSE = "Не містить значення" +REQUEST_COND_START = "Починається з" +REQUEST_SMALL1 = "Менше або дорівнює" +REQUEST_BIG1 = "Більше або дорівнює" +REQUEST_SMALL2 = "Менше" +REQUEST_BIG2 = "Більше" +REQUEST_N_COND_SELF = "Число дорівнює" +REQUEST_N_SMALL1 = "Число менше або дорівнює" +REQUEST_N_BIG1 = "Число більше або дорівнює" +REQUEST_N_SMALL2 = "Число менше" +REQUEST_N_BIG2 = "Число більше" +REQUEST_SEGMENT = "Належить відрізку (через ,)" +REQUEST_INTERVAL = "Належить інтервалу (через ,)" +REQUEST_IN = "у списку (через ,)" +REQUEST_NOTIN = "Не у списку (через ,)" +REQUEST_ANY_NUM = "НЕБЕЗПЕКА!!! Число в запиті" +REQUEST_FREE = "НЕБЕЗПЕКА!!! Довільна умова [field]={Значення}" +REQUEST_MARK_DELETE = "Відмітити умову для видалення" +REQUEST_CONR_AND = "І" +REQUEST_CONR_OR = "Або" +REQUEST_OR = " або " + +REQUEST_VIEWS_INFO = "Системний тег, який показує кількість переглядів для документа" +REQUEST_COMMENTS_INFO = "Системний тег, який показує кількість коментарів для документа. Увага! працює тільки при встановленому модулі!" +REQUEST_CONTROL_FIELD = "Системний тег, що відповідає за вивід панелі керування запитом. Тільки для рубрик з полями типу випадаючий список" +REQUEST_CONTROL_SORT = "Системний тег, що відповідає за вивід панелі сортувань по даті публікації, назві та кількості переглядів результатів виводу запиту" +REQUEST_NO_DROPDOWN = "В вибраній рубриці немає полів типу випадаючий список" +REQUEST_ENTER_NAME = "Будь ласка, вкажіть назву запиту." +REQUEST_ALL = "Список запитів" +REQUEST_IF_EMPTY = "Парний системний тег, всередині якого можна вказати шаблон виводу за відсутності результатів работи запиту" +REQUEST_NOT_EMPTY = "Парний системний тег, всередині якого можна вказати шаблон виводу за наявності результатів работи запиту" +REQUEST_DOCID_INFO = "Системний тег, який відповідає ідентифікатору документа" +REQUEST_DOCTITLE_INFO = "Системний тег, який відповідає імені документа" +REQUEST_CDOCID_INFO = "Системний тег, який відповідає ідентифікатору поточного документа(в якому виводиться запит)" +REQUEST_DOCDATE_INFO = "Системний тег, який відповідає даті публікації документа" +REQUEST_CDOCDATE_INFO = "Системний тег, який відповідає даті публікації поточного документа(в якому виводиться запит)" +REQUEST_DOCTIME_INFO = "Системний тег, який відповідає даті та часу публікації документа" +REQUEST_CDOCTIME_INFO = "Системний тег, який відповідає даті та часу публікації поточного документа(в якому виводиться запит)" +REQUEST_DATE_INFO = "Системний тег, дата та час публікації документа - налаштовуваний вигляд.
Приклад: [tag:date:d.m.Y]
можна використовувати розподілювачі (space - . /)" +REQUEST_CDATE_INFO = "Системний тег, дата та час публікації документа - налаштовуваний вигляд.
Приклад: [tag:date:d.m.Y]
(в якому виводиться запит)
можна використовувати розподілювачі (space - . /)" +REQUEST_DOCAUTHOR_INFO = "Системний тег, який відповідає автору документа" +REQUEST_DOCAUTHOR_AVATAR = "Системний тег, який відповідає аватару автора документа" +REQUEST_CDOCAUTHOR_INFO = "Системний тег, який відповідає автору поточного документа(в якому виводиться запит)" +REQUEST_SAMPLE = "Приклад" +REQUEST_HIDE_CURRENT = "Не показувати в запиті поточний документ" +REQUEST_ONLY_OWNER = "Тільки свої (UserID) документи" +REQUEST_CONDITION_JOIN = "Оператор" +REQUEST_CONDITION_SAVE = "Зберегти умови" +REQUEST_CONDITION_ADD = "Додати умову" + +REQUEST_SUCCESS = "Виконано" +REQUEST_ERROR = "Помилка" +REQUEST_CANCEL = "Відмінити" + +REQUEST_SORTED = "Порядок успішно збережено" +REQUEST_COND_MESSAGE = "Умови запиту відсутні" +REQUEST_COND_VALUE_ERR = "Порожнє поле значення" +REQUEST_COND_NEW_ERR = "Не вдалося додати нову умову
Спробуйте ще раз" +REQUEST_COND_NEW_SUC = "Умову успішно додано" +REQUEST_COND_POST_OK = "Умови успішно збережено" +REQUEST_COND_POST_ERR = "Не вдалося зберегти умови запиту
Спробуйте ще раз" +REQUEST_COND_NO_POST = "Немає даних для збереження
Спробуйте ще раз" + +REQUEST_COND_ADD_SUC = "Додати умови запиту" +REQUEST_COND_CHA_SUC = "Змінив умови запиту" +REQUEST_COND_DEL_SUC = "Видалив умови запиту" +REQUEST_SAVE_CHA_SUC = "Відредагував запит" +REQUEST_ADD_NEW_SUC = "Додати новий запит" +REQUEST_DELETE_SUC = "Видалив запит" +REQUEST_COPY_SUC = "Створив копію запиту" + +REQUEST_HEADER_SELF = "Основні параметри запиту" +REQUEST_HEADER_NAME = "Значення" +REQUEST_HEADER_PARAMETR = "Параметр" + +REQUEST_REPORT_ERR_TITLE = "Відсутня назва запиту" +REQUEST_REPORT_ERR_TEXT = "Відсутній основний шаблон оформлення запиту" +REQUEST_REPORT_ERR_PHP = "Заборонено використовувати PHP код" +REQUEST_REPORT_ERR_PHP_N = "Спроба використання PHP коду у шаблоні запиту при створенні запиту" +REQUEST_REPORT_ERR_PHP_E = "Спроба використання PHP коду у шаблоні запиту" +REQUEST_REPORT_ERR_RUBRIC= "Не обрано рубрику" +REQUEST_BY_PARENT = "Батьківському документу" +REQUEST_SHOW_STAT = "Показати статистику" + + + +// v 3.1.9 +REQUEST_ALIAS = "Аліас" +REQUEST_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:request:alias] замість [tag:request:id]. Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах модуля" +REQUEST_ACCEPT = "Цей Аліас можна використовувати" +REQUEST_ER_SYN = "Неправильний Аліас!
Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +REQUEST_ER_EXISTS = "Неправильний Аліас!
Цей Аліас уже прив’язано до іншого запиту" +REQUEST_HEADER_EXTERNAL = "Зовнішнє звернення" +REQUEST_EXTERNAL = "Дозволити зовнішнє звернення" +REQUEST_ONLY_AJAX = "Виконувати тільки по Ajax" + +// v 3.2 +REQUEST_PAGINATION = "Посторінкова навігація" +REQUEST_NAVI_TPL = "Шаблон посторінкової навігації" +REQUEST_OTHER = "Інше" +REQUEST_SHOW_SQL = "Показати SQL запит" +REQUEST_DOC_ON_PAGE = "Число елементів запиту на сторінці" +REQUEST_PAGES_CURENT = "Номер сторінки пагінації" +REQUEST_PAGES_TOTAL = "Загальна кількість сторінок пагінації" + +// v 3.24 +REQUEST_COUNT_ITEMS = "Отримувати кількість елементів (якщо не використовується посторінкова навігація)" + +// v 3.26 +REQUEST_BY_POSITION = "Позиція документа" diff --git a/admin/lang/ua/rubs.txt b/admin/lang/ua/rubs.txt new file mode 100644 index 0000000..d4aa8c2 --- /dev/null +++ b/admin/lang/ua/rubs.txt @@ -0,0 +1,325 @@ +# солов’їна))) 01,2017 duncan + +[rubs] +RUBRIK_SUB_TITLE = "Керування рубриками" +RUBRIK_TIP = "У цьому розділі наведено список усіх рубрик у системі. Тут Ви можете відредагувати шаблон рубрики, права доступу, видалити рубрику, а також скопіювати рубрику, щоб створити на її базі нову." +RUBRIK_ID = "ID" +RUBRIK_NAME = "Назва рубрики" +RUBRIK_NAME2 = "Назва рубрики:" +RUBRIK_TEMPLATE_OUT = "Використовувати у шаблоні" +RUBRIK_TEMPLATE_OUT2 = "Використовувати у шаблоні:" +RUBRIK_URL_PREFIX = "Префікс для посилань" +RUBRIK_URL_PREFIX2 = "Префікс для посилань:" +RUBRIK_DOCS_VI = "Відображати документи у списку" +RUBRIK_URL_PREFIX2 = "Префікс для посилань:" +RUBRIK_COUNT_DOCS = "Кіль-ть документів" +RUBRIK_COUNT_FIELDS = "Кіль-ть полів" +RUBRIK_AUTHOR = "Автор" +RUBRIK_ACTION = "Дії" +RUBRIK_FORMAT = "Використовуйте" +RUBRIK_FORMAT_TIME = "для посилань у форматі часу" +RUBRIK_FORMAT_ID = "для вставки id документа" +RUBRIK_EDIT = "Редагувати поля та права рубрики" +RUBRIK_EDIT_TMPLS = "Додаткові шаблони" +RUBRIK_NO_VIEW = "Даруйте, але Ви не маєте прав на перегляд списку рубрик." +RUBRIK_NO_CHANGE1 = "Даруйте, але Ви не маєте прав на редагування полів рубрики." +RUBRIK_NO_CHANGE2 = "Даруйте, але Ви не маєте прав на редагування шаблона цієї рубрики." +RUBRIK_NO_CHANGE3 = "Даруйте, але Ви не маєте прав на створення нових рубрик." +RUBRIK_EDIT_TEMPLATE = "Редагувати шаблон рубрики" +RUBRIK_EDIT_CODE = "Редагувати виконуваний код для рубрик" +RUBRIK_EDIT_CODE_T = "редагування виконуваного коду для рубрик" +RUBRIK_EDIT_CODE_NO = "Немає доступу для редагування виконуваного коду" +RUBRIK_DELETE = "Видалити цю рубрику" +RUBRIK_DELETE_LEGEND = "Видалити рубрику" +RUBRIK_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити цю рубрику?" +RUBRIK_NO_PERMISSION = "Даруйте, але Ви не маєте прав на видалення рубрик." +RUBRIK_USE_DOCUMENTS = "Даруйте, але Ви не можете видалити цю рубрику, оскільки в ній містяться документи." +RUBRIK_MULTIPLY = "Копіювати рубрику" +RUBRIK_NO_MULTIPLY = "Даруйте, але Ви не маєте прав на копіювання рубрик" +RUBRIK_BUTTON_SAVE = "Зберегти зміни" +RUBRIK_BUTTON_TEMPL = "Редагувати шаблон" +RUBRIK_BUTTON_FIELDS = "Редагувати поля" +RUBRIK_BUTTON_CODE = "Редагувати код рубрики" +RUBRIK_LEGEND = "Значення піктограм" +RUBRIK_NEW = "Створення нової рубрики" +RUBRIK_NEW_TIP = "У цьому розділі Ви можете створити нову рубрику. Будь ласка, вкажіть назву нової рубрики та оберіть шаблон для виводу." +RUBRIK_BUTTON_NEW = "Створити рубрику" +RUBRIK_EDIT_FIELDS = "Керування полями та правами доступу до рубрики" +RUBRIK_DESCRIPTION = "Опис рубрики" +RUBRIK_NO_FIELDS = "Увага! Ви не створено жодного поля. Будь ласка, додайте хоча би одне поле." +RUBRIK_FIELDS_INFO = "У цьому розділі Ви можете створити групу полів, які будути використані для документів у цій рубриці." +RUBRIK_MULTIPLY2 = "Копіювання рубрики" +RUBRIK_MULTIPLY_TIP = "Будь ласка, вкажіть назву та префікс для посилань нової рубрики" +RUBRIK_BUTTON_COPY = "Копіювати" +RUBRIK_TEMPLATE_EDIT = "Редагування шаблона рубрики" +RUBRIK_TEMPLATE_NEW = "Створення шаблона рубрики" +RUBRIK_TEMPLATE_SAVED = "Шаблон успішно збережено" +RUBRIK_NO_FIELD = "У цієї рубрики відсутні поля" +RUBRIK_FIELD_NAME = "Назва поля" +RUBRIK_FIELD_GROUP = "Група" +RUBRIK_FIELD_GROUP_SEL = "Оберіть групу" +RUBRIK_FIELD_ALIAS = "Аліас поля" +RUBRIK_FIELD_TYPE = "Тип поля" +RUBRIK_FIELD_UNKNOW = "Невідомо" +RUBRIK_FIELD_G_UNKNOW = "Без групи" +RUBRIK_POSITION = "Позиція" +RUBRIK_NEW_FIELD = "Створення нового поля для рубрики" +RUBRIK_BUTTON_ADD = "Додати поле" +RUBRIK_SET_PERMISSION = "Права доступу до документів для груп користувачів" +RUBRIK_USER_GROUP = "Група" +RUBRIK_DOC_READ = "Перегляд" +RUBRIK_ALL_PERMISSION = "Усі права" +RUBRIK_CREATE_DOC = "Створювати з перевіркою" +RUBRIK_CREATE_DOC_NOW = "Створювати без перевірки" +RUBRIK_EDIT_OWN = "Редагувати свої" +RUBRIK_EDIT_DELREV = "Керування ревізіями" +RUBRIK_EDIT_OTHER = "Редагувати усі" +RUBRIK_VIEW_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів перегляд документів" +RUBRIK_ALL_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів виконувати будь-які дії з документами в цій рубриці." +RUBRIK_DOC_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів створювати документи.
Увага!
Перед публікацією документа, його має бути перевірено Адміністратором" +RUBRIK_DOC_NOW_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів створювати документи.
Увага!
Публікацію документа буде виконано без перевірки Адміністратором." +RUBRIK_OWN_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів редагувати тільки свої документи" +RUBRIK_OTHER_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів редагувати свої та чужі документи" +RUBRIK_DELREV_TIP = "Встановіть прапорець, якщо Ви бажаєте дозволити цій групі користувачів працювати з ревізіями документів" +RUBRIK_BUTTON_PERM = "Зберегти права" +RUBRIK_FIELD_DEFAULT = "Значення по замовчуванню" +RUBRIK_TEMPLATE_TIP = "У цьому розділі, використовуючи мову розмітки HTML, Ви повинні створити шаблон оформлення для документів при повному перегляді," +RUBRIK_HTML = "Шаблон оформлення рубрики" +RUBRIK_HTML_2 = "Шаблон оформлення HEADER" +RUBRIK_HTML_3 = "Шаблон оформлення TEASER" +RUBRIK_HTML_4 = "Шаблон оформлення ADMIN TEASER" +RUBRIK_PHP_DENIDED = "Помилка!
Ви не маєте прав на редагування шаблона рубрики, оскільки тут використовується PHP код, а Ви не маєте прав на використання PHP коду." +RUBRIK_PHP_MESSAGE = "Заборонено використовувати PHP код." +RUBRIK_EMPTY_MESSAGE = "Не задано назву поля." +RUBRIK_INSERT_HELP = "Натисніть, щоб додати системний тег у шаблон" +RUBRIK_BUTTON_TPL = "Зберегти шаблон" +RUBRIK_BUTTON_TPL_NEXT = "Примінити (CTRL+S)" +RUBRIK_BUTTON_TPL_CLOSE = "Закрити" +RUBRIK_NO_RUBRIK = "Немає такої рубрики!" +RUBRIK_NO_NAME = "Будь ласка, вкажіть назву рубрики" +RUBRIK_NAME_EXIST = "Даруйте, але рубрика з такою назвою уже існує. Будь ласка, вкажіть іншу назву рубрики." +RUBRIK_PREFIX_EXIST = "Даруйте, але рубрика з таким URL-префіксом уже існує. Будь ласка, вкажіть інший URL-префікс рубрики." +RUBRIK_VIEWS_INFO = "Системний тег, який показує кількість переглядів для документа" +RUBRIK_HIDE_INFO = "Системний тег, який дозволяє приховати текст для певних груп користувачів, де Х - номер групи" +RUBRIK_THUMBNAIL = "Тег відповідає за створення мініатюрки (За умови що у шаблоні поля рубрики (шаблон для виводу в документі) обрано вивід: [tag:parametr:0])" +RUBRIK_LINK_HOME = "Посилання на головну сторінку cайту" +RUBRIK_MARK_DELETE = "Відмітити цей пункт для видалення" +RUBRIK_MARK_DEL_ALL = "Відмітити усі" +RUBRIK_CHECK_SEARCH = "Шукати по цьому полю" +RUBRIK_CHECK_NUMERIC = "Числове поле" +RUBRIK_SEARCH_TIP = "Відмітьте поле, якщо бажаєте, щоб по ньому здійснювався пошук (працює з модулем “пошук” версії 2.0.2 та вище)" +RUBRIK_NUMERIC_TIP = "Відмітьте поле, якщо його значення завжди числові. Використовується в запитах для сортування" +RUBRIK_ALL = "Список рубрик" +RUBRIK_EDIT_FIELDS_GROUPS = "Редагувати групи полів" +RUBRIK_FIELDS_GROUPS = "Групи полів" +RUBRIK_ENTER_NAME = "Будь ласка, вкажіть назву рубрики." +RUBRIK_TEMPLATE_HIDE = "Показати/згорнути шаблони усіх полів" +RUBRIK_FILED_TEMPLATE_H = "Редагувати шаблон та опис поля" +RUBRIK_FILED_TEMPLATE_DESCR = "Опис поля" +RUBRIK_FILED_TEMPLATE_F = "Шаблон поля" +RUBRIK_DOCID_INFO = "Системний тег, ідентифікатор документа" +RUBRIK_DOCDATE_INFO = "Системний тег, дата публікації документа" +RUBRIK_DOCTIME_INFO = "Системний тег, дата та час публікації документа" +RUBRIK_DATE_INFO = "Системний тег, дата та час публікації документа - налаштовуваний вигляд.
Приклад: [tag:date:Y]" +RUBRIK_DOCAUTHOR_INFO = "Системний тег, автор документа" +RUBRIK_TITLE_INFO = "Системний тег, заголовок документа" +RUBRIK_PATH_INFO = "Системний тег, шляхи до кореня установки" +RUBRIK_MEDIAPATH_INFO = "Системний тег, шляхи до папки дизайна" +RUBRIK_PREFIX_BAD_CHAR= "Недопустимі символи у префіксі" +RUBRIK_FIELDS_TITLE = "Поля рубрики" +RUBRIK_FIELDS_TPL = "Шаблон виводу поля в документі" +RUBRIK_RUBRIK_TPL = "Шаблон виводу поля в запиті" +RUBRIK_SORTED = "Порядок успішно збережено" +RUBRIK_F_SORT_TIP = "Для впорядкування полів натисніть на хрестик та, утримуючи його, перетягніть поле" +RUBRIK_R_SORT_TIP = "Для впорядкування рубрик натисніть на хрестик и, утримуючи його, перетягніть поле" +RUBRIK_META_GEN_TIP = "Автоматично генерувати keywords, description для документа, на базі його контенту" +RUBRIK_ALIAS_HISTORY_TIP = "Зберігати історію аліасів у документів" +RUBRIK_MOVE = "Перемістити" +RUBRIK_REQUEST_TPL = "Шаблон виводу поля в запиті" +RUBRIK_BREADCRUMB = "Систмений тег хлібних крихт" +RUBRIK_CODE = "Виконуваний код для рубрик" +RUBRIK_START_CODE = "Код, який виконується перед завантаженням документа" +RUBRIK_CODE_START = "Код, який виконується перед збереженням документа" +RUBRIK_CODE_END = "Код, який виконується після збереження документа" +RUBRIK_TAGS = "Тег" +RUBRIK_TAGS_ID = "Тег ID" +RUBRIK_TAGS_ALIAS = "Тег Аліас" +RUBRIK_HTML_T = "HTML код шаблона" +RUBRIK_TAG_DESC = "Опис тега" +RUBRIK_NEW_FIEL_TITLE = "Для полів Випадаючий список та Мульти список, значення по замовчуванню пишуться через кому" +RUBRIK_LINK = "Зв’язати рубрику" +RUBRIK_LINK_DESC = "Задаючи зв’язок між рубриками, при додаванні документів можна автоматично підставляти аліаси." +RUBRIK_NOLINK = "Не вибрано" +RUBRIK_OR = " або " + +RUBRIC_F_GROUP_TITLE = "Назва групи" +RUBRIC_F_GROUP_DELETE = "Видалити групу" +RUBRIC_F_GROUP_DELETE_H = "Ви впевнені, що бажаєте видалити групу?" +RUBRIC_NO_GROUPS = "На даний час, для цієї рубрики, немає груп полів" +RUBRIC_GROUP_ADD = "Додати групу" +RUBRIK_NEW_GROUP = "Додати нову групу" +RUBRIK_HEADER_GROUP = "Керування групами полів" + +RUBRIK_TEMPLATES_TAGS = "Тег" +RUBRIK_TEMPLATES_TAG_DESC = "Опис тега" +RUBRIK_TEMPLATES_THEME_FOLDER = "Назва шаблона (Ім’я папки з файлами для цього шаблона)" +RUBRIK_TEMPLATES_PAGENAME = "Назва cайту" +RUBRIK_TEMPLATES_TITLE = "Назва сторінки" +RUBRIK_TEMPLATES_KEYWORDS = "Ключові слова (Meta - Keywords)" +RUBRIK_TEMPLATES_DESCRIPTION = "Опис сторінки (Meta - Description)" +RUBRIK_TEMPLATES_INDEXFOLLOW = "Тип індексування" +RUBRIK_TEMPLATES_PATH = "Кореневий шляхи установки" +RUBRIK_TEMPLATES_MEDIAPATH = "Шляхи до папки з шаблоном (Приклад: [tag:mediapath]images/logo.gif)" +RUBRIK_TEMPLATES_CSS = "Стискає декілька css-файлів в один. Повертає шлях.
FFF - імена файлів через кому
P - шляхи до папки з файлами, не обов’язково. По замовчуванню - [tag:mediapath]css/

Приклад: href="[tag:css:reset.css,style.css]"" +RUBRIK_TEMPLATES_JS = "Стискає декілька js-файлів в один. Повертає шлях.
FFF - імена файлів через кому
P - шляхи до папки з файлами, не обов’язково. По замовчуванню - [tag:mediapath]js/

Приклад: href="[tag:js:common.js,main.js]"" + +RUBRIK_RUB_INFO = "Системний тег що відповідає за вивід вмісту поля рубрики. ID-номер поля. ХХХ-кількість символів для відображення." +RUBRIK_SELECT_IN_LIST = "Будь ласка, оберіть поле рубрики зі списку, наведеного нижче" +RUBRIK_TEMPLATE_ITEMS = "Шаблон оформлення для елементів запиту" +RUBRIK_DOCID_INFO = "Системний тег, який відповідає ідентифікатору документа" +RUBRIK_DOCTITLE_INFO = "Системний тег, який відповідає імені документа" +RUBRIK_CDOCID_INFO = "Системний тег, який відповідає ідентифікатору поточного документа(в якому виводиться запит)" +RUBRIK_DOCDATE_INFO = "Системний тег, який відповідає даті публікації документа" +RUBRIK_CDOCDATE_INFO = "Системний тег, який відповідає даті публікації поточного документа(в якому виводиться запит)" +RUBRIK_DOCTIME_INFO = "Системний тег, який відповідає даті та часу публікації документа" +RUBRIK_CDOCTIME_INFO = "Системний тег, який відповідає даті та часу публікації поточного документа(в якому виводиться запит)" +RUBRIK_DATE_INFO = "Системний тег, дата та час публікації документа - налаштовуваний вигляд.
Приклад: [tag:date:d.m.Y]
можна використовувати розподілювачі (space - . /)" +RUBRIK_CDATE_INFO = "Системний тег, дата та час публікації документа - налаштовуваний вигляд.
Приклад: [tag:date:d.m.Y]
(в якому виводиться запит)
можна використовувати розподілювачі (space - . /)" +RUBRIK_DOCAUTHOR_INFO = "Системний тег, який відповідає автору документа" +RUBRIK_DOCAUTHOR_AVATAR = "Системний тег, який відповідає аватару автора документа" +RUBRIK_CDOCAUTHOR_INFO = "Системний тег, який відповідає автору поточного документа(в якому виводиться запит)" +RUBRIK_VIEWS_INFO = "Системний тег, який показує кількість переглядів для документа" +RUBRIK_COMMENTS_INFO = "Системний тег, який показує кількість коментарів для документа. Увага! працює тільки при встановленому модулі!" +RUBRIK_PATH = "Системний тег, який визначає корінь установки" +RUBRIK_MEDIAPATH = "Системний тег, який визначає шляхи до папки з шаблоном (Приклад: [tag:mediapath]images/logo.gif)" +RUBRIK_THUMBNAIL = "Тег відповідає за створення мініатюрки (За умови що у шаблоні поля рубрики (шаблон для виводу в запиті) обрано вивід: [tag:parametr:0])" + +RUBRIK_ALIAS_HEAD = "Призначення аліаса для поля" +RUBRIK_ALIAS_HEAD_T = "Можна використовувати тільки латинські символи та цифри!
Приклад: header" +RUBRIK_ALIAS_HEAD_R = "Рубрика:" +RUBRIK_ALIAS_HEAD_F = "Поле:" +RUBRIK_ALIAS_ALIAS = "Аліас поля" +RUBRIK_ALIAS_NAME = "Назва аліаса" +RUBRIK_ALIAS_BUTT = "Зберегти" + +RUBRIK_ALIAS_ERROR = "Помилка:" +RUBRIK_ALIAS_RUBID = "Неправильно вказано рубрику" +RUBRIK_ALIAS_FIELDID = "Неправильно вказане поле" +RUBRIK_ALIAS_MATCH = "Неправильно вказано значення" +RUBRIK_ALIAS_USED = "Це значення вже використовується" + +RUBRIK_REPORT_QUICKSAVE = "Виконав швидке збереження налаштувань рубрик" +RUBRIK_REPORT_SORTE = "Виконав сортування рубрик" +RUBRIK_REPORT_SORTE_FIELDS = "Виконав сортування полів рубрики" +RUBRIK_REPORT_PERMISION = "Змінив права доступу до документів рубрики" +RUBRIK_REPORT_COPY = "Створив копію рубрики" +RUBRIK_REPORT_TEMPL_RUB = "Відредагував шаблон рубрики" +RUBRIK_REPORT_FIELD_EDIT = "Відредагував поле" +RUBRIK_REPORT_FIELD_DEL = "Видалив поле" +RUBRIK_REPORT_RUB = "Рубрики" + +RUBRIK_REP_QUICKSAVE_H = "Виконано" +RUBRIK_REP_QUICKSAVE_T = "Налаштування рубрик успішно збережено" + +RUBRIK_REPORT_ADD = "Додав рубрику" +RUBRIK_REPORT_SAVE_TPL = "Зберіг шаблон оформлення рубрики" + +RUBRIK_CODE_SAVED = "Виконуваний код для рубрики успішно збережено" +RUBRIK_CODE_SAVED_ERR = "Не вдалося зберегти виконуваний код для рубрики.
Спробуйте ще раз." +RUBRIK_CODE_ERROR = "Помилка" +RUBRIK_CODE_SUCCESS = "Виконано" +RUBRIK_CODE_UPDATE = "Змінив виконуваний код для рубрики" + +RUBRIK_LOG_NEW_FIELD = "Додав поле рубрики" +RUBRIK_LOG_DEL_RUBRIC = "Видалив рубрику" +RUBRIK_LOG_NEW_RUBRIC = "Створив рубрику" + +RUBRIK_FILDS_SAVED = "Успішно збережено" +RUBRIK_FILD_SAVED = "Поле успішно додано" +RUBRIK_FILDS_REPORT = "Зберіг поля рубирки" +RUBRIK_FILDS_ERROR = "Помилка" +RUBRIK_FILDS_SUCCESS = "Виконано" + +RUBRIC_ERROR = "Помилка" +RUBRIC_SUCCESS = "Виконано" +RUBRIC_SAVED_PHP_ERR = "Заборонено використовувати в шаблонах PHP код" +RUBRIC_SAVED_TPL_ERR = "Не вдалося зберегти шаблон рубрики.
Спробуйте ще раз." +RUBRIC_SAVED_TPL = "Шаблон рубрики успішно збережено." +RUBRIC_SAVED_FLDTPL = "Шаблон поля успішно збережено." +RUBRIK_TAG_SYSBLOCK = "Системний тег виводу системного блока" +RUBRIK_TAG_TEASER = "Системний тег виводу тизера" +RUBRIK_TAG_ALIAS = "Системний тег виводу аліаса документа" +RUBRIK_TAG_REQUEST = "Системний тег виводу запиту" +RUBRIC_SAVED_PERMS = "Права доступу до документів успішно збережено " +RUBRIK_IFELSE = "Умови" +RUBRIK_IFELSE_1 = "Виводимо якщо поле не порожнє" +RUBRIK_IFELSE_2 = "Інакше виводимо якщо поле порожнє" +RUBRIK_SAMPLE = "Приклад" + +RUBRIC_TMPLS_BUTTON = "Додаткові шаблони рубрики" +RUBRIC_TMPLS_HEAD = "Список додаткових шаблонів рубрики" +RUBRIC_TMPLS_ADD = "Додати новий шаблон" +RUBRIC_TMPLS_ID = "id" +RUBRIC_TMPLS_NAME = "Назва" +RUBRIC_TMPLS_NAME_FULL = "Назва шаблона оформлення рубрики" +RUBRIC_TMPLS_AUTHOR = "Автор" +RUBRIC_TMPLS_DATE = "Дата" +RUBRIC_TMPLS_COUNT_DOCS = "Кіль-ть документів" +RUBRIC_TMPLS_ACTIONS = "Дії" +RUBRIC_TMPLS_COPY = "Копіювати шаблон" +RUBRIC_TMPLS_COPY_TIP = "Будь ласка, вкажіть назву шаблона" +RUBRIC_TMPLS_COPY_TIP2 = "Будь ласка, вкажіть назву для шаблона, який копіюється" +RUBRIC_TMPLS_EDIT = "Редагувати" +RUBRIC_TMPLS_DELETE = "Видалити" +RUBRIC_TMPLS_DELETE_C = "Ви впевнені, що бажаєте видалити шаблон?" +RUBRIC_TMPLS_TIP = "Ви можете створювати необмежену кіль-ть шаблонів для однієї рубрики" +RUBRIC_TMPLS_NO_ITEMS = "Повідомлення:
На даний час немає додаткових шаблонів." +RUBRIC_TMPLS_FROM = "Створити копію основного шаблона" +RUBRIC_TMPLS_INNAME = "Введіть назву шаблона" +RUBRIC_TEMPL_REPORT = "Відредагував додатковий шаблон рубрики" +RUBRIC_TMPLS_LOG_DEL = "Видалив додатковий шаблон рубрики" + +// 3.24 +RUBRIC_WARNING_TIP = "Увага! Будь ласка, будьте максимально уважні та пам'ятайте, що неправильні параметри можуть зробити систему непрацеспроможною." + +RUBRIK_EDIT_FIELDS = "Керування полями" +RUBRIK_EDIT_RULES = "Керування правами доступів до рубрики" + +RUBRIC_TABLE_BTN_FIELDS = "Поля рубрики" +RUBRIC_TABLE_BTN_FTEMPLATES = "Шаблони полів" +RUBRIC_TABLE_BTN_FGROUPS = "Групи полів" +RUBRIC_TABLE_BTN_TEMPLATES = "Шаблон рубрики" +RUBRIC_TABLE_BTN_CODE = "Виконуваний код" +RUBRIC_TABLE_BTN_RULES = "Права доступів" + +RUBRIK_EDIT_CODE_TIP = "Увага! Будь ласка, будьте максимально уважні та пам'ятайте, що неправильні параметри можуть зробити систему непрацеспроможною." +RUBRIK_EDIT_CODE_LOAD_TIP = "Доступ до даних:
$this->curentdoc - Дані документа, перед підстановкою їх у шаблон виводу" +RUBRIK_EDIT_CODE_BEF_TIP = "Доступ до даних:
$data - Усі дані документа
$data['feld'] - Дані полів документа
$rubric_id - ID рубрики" +RUBRIK_EDIT_CODE_AFT_TIP = "Доступ до даних:
$data - Усі дані документа
$rubric_id - ID рубрики
$document_id - ID документа - Число або False" + +RUBRIK_FIELDS_TEMPLATES_H1 = "Керування шаблонами полів" +RUBRIK_FIELDS_TEMPLATES_H2 = "Шаблони полів" +RUBRIK_FIELDS_TEMPLATES_T1 = "Створювати/Редагувати/Видаляти шаблони полів (tpl)" +RUBRIK_FIELDS_TEMPLATES_T2 = "Редагувати шаблони виводу полів" +RUBRIK_FIELDS_TEMPLATES_LIST = "Список типів полів, які використовуються у рубриці" +RUBRIK_FIELDS_TEMPLATES_FNAME = "Назва поля" +RUBRIK_FIELDS_TEMPLATES_FFUNC = "Функція" +RUBRIK_FIELDS_TEMPLATES_FTEMP = "Шаблон .tpl (по дефолту)" +RUBRIK_FIELDS_TEMPLATES_FTEMPL = "Шаблон .tpl за ID поля" +RUBRIK_FIELDS_TEMPLATES_PANEL = "Панель" +RUBRIK_FIELDS_TEMPLATES_DOC = "Документ" +RUBRIK_FIELDS_TEMPLATES_REQ = "Запит" +RUBRIK_FIELDS_TEMPLATES_DB = "База даних" +RUBRIK_FIELDS_TEMPLATES_BACK = "До списку типів полів" +RUBRIK_FIELDS_NO_TEMPLATES = "Немає шаблона" +RUBRIK_FIELDS_EDIT_RUBRIC = "Рубрика" +RUBRIK_FIELDS_EDIT_FIELD = "Поле:" +RUBRIK_FIELDS_EDIT_TYPE = "Тип:" +RUBRIK_FIELDS_EDIT_TPL_ADM = "Шаблон для панелі" +RUBRIK_FIELDS_EDIT_TPL_DOC = "Шаблон виводу в документі" +RUBRIK_FIELDS_EDIT_TPL_REQ = "Шаблон виводу в запиті" +RUBRIK_FIELDS_EDIT_TPL_CREAT = "Створення шаблону з основного файлу" +RUBRIK_FIELDS_EDIT_TPL_EDIT = "Редагування шаблону" +RUBRIK_FIELDS_EDIT_NO_TPL = "Відсутній основний файл шаблону" +RUBRIC_TMPLS_CREAT = "Створити" +RUBRIC_TMPLS_DELETE = "Видалити" diff --git a/admin/lang/ua/scripts.js b/admin/lang/ua/scripts.js new file mode 100644 index 0000000..98c7979 --- /dev/null +++ b/admin/lang/ua/scripts.js @@ -0,0 +1,64 @@ +// солов’їна))) 01,2017 duncan + +var logoutTitle = "Вихід з панелі керування"; +var logoutConfirm = "Ви впевнені, що бажаєте вийти?"; +var clearCacheTitle = "Очистка кеша"; +var clearCacheConfirm = "Ви впевнені, що бажаєте очистити кеш?"; +var clearCacheSessTitle = "Очистка кеша та сесій"; +var clearCacheSessConfirm = "Ви впевнені, що бажаєте очистити кеш та сесії?"; +var clearThumbTitle = "Видалення мініатюр"; +var clearThumbConfirm = "Ви впевнені, що бажаєте видалити всі мініатюри зображень
з директорії для збереження файлів (UPLOAD_DIR)?"; +var clearRevTitle = "Видалення ревізій документів"; +var clearRevConfirm = "Ви впевнені, що бажаєте видалити все ревізії документів?"; +var clearCountTitle = "Обнулити щоденний лічильник документів"; +var clearCountConfirm = "Ви впевнені, що бажаєте обнулити щоденний лічильник документів?"; +var cacheShowTitle = "Показати розмір кеша"; +var cacheShowConfirm = "Ви впевнені, що бажаєте подивитися розмір кеша?
це може зайняти якийсь час."; +var ajaxErrorStatus = "Немає з’єднання.
Перевірте своє підключення."; +var ajaxErrorStatus404 = "Сторінку, яку шукаєте, не знайдено. [404]"; +var ajaxErrorStatus401 = "Запит не може бути виконано.
Помилка авторизації для виконання цього запиту. [401]"; +var ajaxErrorStatus500 = "Сталася внутрішня помилка.
Спробуйте повторити свій запит пізніше. [500]"; +var ajaxErrorStatusJSON = "Некоректна відповідь сервера
Дані не в форматі JSON."; +var ajaxErrorStatusTimeOut = "Час запиту вийшов."; +var ajaxErrorStatusAbort = "Ajax запит перервано."; +var ajaxErrorStatusMess = "Помилка:
"; +var delCascadTitle = "видалити зображення"; +var delCascadConfirm = "Ви впевнені, що бажаєте видалити?"; +var saveMessageOk = "Дані збережено"; + +//===== Date & Time Pickers =====// +$.datepicker.regional['ua'] = { + closeText: 'Закрити', + prevText: '<Назад', + nextText: 'Вперед>', + currentText: 'Нині', + monthNames: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', + 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень' + ], + monthNamesShort: ['Січ', 'Лют', 'Бер', 'Кві', 'Тра', 'Чер', + 'Лип', 'Сер', 'Вер', 'Жов', 'Лис', 'Гру' + ], + dayNames: ['Неділя', 'понеділок', 'вівторок', 'середа', 'четвер', 'п’ятница', 'субота'], + dayNamesShort: ['нед', 'пон', 'вів', 'сер', 'чет', 'пят', 'суб'], + dayNamesMin: ['Нд', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], + weekHeader: 'Не', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: '' +}; +$.datepicker.setDefaults($.datepicker.regional['ua']); + +$.timepicker.regional['ua'] = { + timeOnlyTitle: 'Оберіть час', + timeText: 'Час', + hourText: 'Години', + minuteText: 'Хвилини', + secondText: 'Секунди', + millisecText: 'мілісекунди', + currentText: 'Зараз', + closeText: 'Закрити', + ampm: false +}; +$.timepicker.setDefaults($.timepicker.regional['ua']); \ No newline at end of file diff --git a/admin/lang/ua/settings.txt b/admin/lang/ua/settings.txt new file mode 100644 index 0000000..b9ea87c --- /dev/null +++ b/admin/lang/ua/settings.txt @@ -0,0 +1,160 @@ +# солов’їна))) 01,2017 duncan + +[settings] +SETTINGS_COUNTRIES = "Керування країнами" +SETTINGS_COUNTRIES_ALL = "Список країн" +SETTINGS_COUNTRY_TIP = "Будь ласка, оберіть країни, які будуть доступні для вибору при реєстрації нових користувачів у системі. Пам’ятайте, що обраноний Вами список країн може бути використаний іншими модулями у системі." +SETTINGS_ACTIVE = "Активна?" +SETTINGS_COUNTRY_NAME = "Назва країни" +SETTINGS_IN_EC = "Відноситься до ЄС?" +SETTINGS_YES = "Так" +SETTINGS_NO = "Ні" +SETTINGS_BUTTON_SAVE = "Зберегти зміни" +SETTINGS_BUTTON_SAVE_AJAX = "Примінити (CTRL+S)" +SETTINGS_OR = "або" +SETTINGS_MAIN_TITLE = "Керування загальними налаштуваннями системи" +SETTINGS_CASE_TITLE = "Додаткові налаштування" +SETTINGS_MAIN = "Загальні налаштування системи" +SETTINGS_SAVED = "Налаштування системи успішно збережені" +SETTINGS_SAVED_ERR = "Не вдалося зберегти налаштування.
Спробуйте ще раз." +SETTINGS_SAVE_INFO = "У цьому розділі Ви можете відредагувати глобальні параметри системи. Будь ласка, будьте максимально уважні та пам’ятайте, що неправильні параметри можуть зробити систему неробочою." +SETTINGS_SAVE_CONFIRM = "Ви впевнені, що бажаєте зберегти параметри системи?" +SETTINGS_SITE_NAME = "Назва cайту:" +SETTINGS_SITE_COUNTRY = "Країна сайту:" +SETTINGS_EMAIL_SENDER = "E-mail відправника:" +SETTINGS_EMAIL_NAME = "Ім’я відправника E-mail:" +SETTINGS_MAIL_TRANSPORT = "Метод надсилання пошти:" +SETTINGS_MAIL = "mail" +SETTINGS_SENDMAIL = "sendmail" +SETTINGS_SMTP = "smtp" +SETTINGS_SMTP_SERVER = "Сервер SMTP:" +SETTINGS_MAIL_PORT = "Порт SMTP:" +SETTINGS_SMTP_NAME = "Користувач:" +SETTINGS_SMTP_PASS = "Пароль:" +SETTINGS_SMTP_ENCRYPT = "Шифрування" +SETTINGS_SMTP_NOENCRYPT = "Ні" +SETTINGS_MAIL_PATH = "Шляхи до папки sendmail:" +SETTINGS_SYMBOL_BREAK = "Примусовий перенос після (знаків):" +SETTINGS_SYMBOL_BREAK_INFO = "Не більше 1000 згідно RFC 2822" +SETTINGS_SYMBOLS = "символів" +SETTINGS_TEXT_EMAIL = "Повідомлення користувачеві після створення аккаунта, де:" +SETTINGS_TEXT_INFO = "%NAME% - Ім’я користувача
%HOST% - Посилання на сайт
%PASSWORD% - Пароль
%EMAIL% - E-mail користувача
%EMAILSIGNATURE% - Підпис повідомлення" +SETTINGS_EMAIL_FOOTER = "Текст підпису:" +SETTINGS_ERROR_PAGE = "Сторінка з помилкою HTTP 404: Page not found" +SETTINGS_PAGE_DEFAULT = "(по замовчуванню Id:2)" +SETTINGS_TEXT_PERM = "Текст повідомлення, якщо користувач не має прав:" +SETTINGS_HIDDEN_TEXT = "Текст повідомлення при відсутності прав для перегляду інформації прихованої тегом [tag:hide:X,X]...[/tag:hide]" + +SETTINGS_NAVI_BOX = "Контейнер посторінкової навигації:
Приклад: <ul>%s</ul>" +SETTINGS_LINK_BOX = "Контейнер для елементів посторінкової навигації:
Приклад: <li>%s</li>" +SETTINGS_TOTAL_BOX = "Контейнер для текста перед номерами сторінок:
Приклад: <span>%s</span>" +SETTINGS_ACTIVE_LINK_BOX= "Контейнер для активного елемента:
Приклад: <span class="active">%s</span>" +SETTINGS_PAGE_SEPAR = "Контейнер для мітки про наявність сторінок:
Приклад: <li>%s</li>" +SETTINGS_PAGE_BEFORE = "Текст перед номерами сторінок:
Приклад: сторінка %d з %d" +SETTINGS_PAGE_START = "Текст посилання "Перша":" +SETTINGS_PAGE_END = "Текст посилання "Остання":" +SETTINGS_PAGE_SEPARATOR = "Текст мітки про наявність сторінок за винятком видимих:" +SETTINGS_PAGE_NEXT = "Текст посилання "Натсупна":" +SETTINGS_PAGE_PREV = "Текст посилання "Попередня":" + +SETTINGS_MAIN_BREADCRUMBS = "Налаштування виводу “хлібних крихт”" +SETTINGS_BREAD_BOX = "Контейнер “хлібних крихт”:" +SETTINGS_BREAD_SEPPARATOR = "Розподілювач між посиланнями:" +SETTINGS_BREAD_BOX_LINK = "Контейнер для посилання:" +SETTINGS_BREAD_BOX_LASTLINK = "Показувати останній елемент:" +SETTINGS_BREAD_SELF_BOX = "Контейнер для останнього елемента:" + +SETTINGS_DATE_FORMAT = "Формат дати:" +SETTINGS_TIME_FORMAT = "Формат дати та часу:" +SETTINGS_CLEAR_CACHE = "Очистити кеш" +SETTINGS_USE_DOCTIME = "Використовувати дату публікації документів" +SETTINGS_INFO = "Додатково" +SETTINGS_MAIN_SETTINGS = "Загальні налаштування системи" +SETTINGS_MAIN_MAIL = "Налаштування пошти" +SETTINGS_MAIN_PAGENAVI = "Налаштування виводу посторінкової навигації" +SETTINGS_NAME = "Параметр" +SETTINGS_VALUE = "Значення" +SETTINGS_EDITOR_CKEDITOR = "CKEditor" + +SETTINGS_ERROR = "Помилка" +SETTINGS_SUCCESS = "Виконано" + +SETTINGS_SAVE_DOP = "Змінив додаткові налаштування системи" +SETTINGS_SAVE_MAIN = "Змінив загальні налаштування системи" +SETTINGS_SAVE_COUNTRY = "Змінив налаштування країн" + +SETTINGS_LANG_EDIT = "Керування мовами" +SETTINGS_LANG_TITLE = "Увага! Налаштування мов має відбуватися, чітко перед наповненням cайту!" +SETTINGS_LANG_AEDIT = "Редагувати" +SETTINGS_LANG_AON = "Увімкнути" +SETTINGS_LANG_AOFF = "Вимкнути" +SETTINGS_LANG_ADEFAULT = "Зробити по замовчуванню" +SETTINGS_LANG_ADEFAULT_HINT = "" +SETTINGS_LANG_ID = "Id" +SETTINGS_LANG_FLAG = "Прапорець" +SETTINGS_LANG_SYSTEM = "Системне" +SETTINGS_LANG_PREFIX = "Префікс" +SETTINGS_LANG_NAME = "Назва" +SETTINGS_LANG_DEFAULT = "По замовчуванню" +SETTINGS_LANG_ACTION = "Дії" +SETTINGS_LANG_ADD = "Додати мову" +SETTINGS_LANG_SAVE = "Зберегти зміни" + +SETTINGS_REV_DELETED = "Ревізії документів успішно видалено" +SETTINGS_REV_DELETED_ERR = "Не вдалося видалити ревізії документів.
Спробуйте ще раз." +SETTINGS_REV_UPDATE = "Видалив ревізії документів" +SETTINGS_COUNT_DELETED = "Поденний лічильник документів
успішно обнулений." +SETTINGS_COUNT_DELETED_ERR = "Не вдалося обнулити поденний
лічильник документів.
Спробуйте ще раз." +SETTINGS_COUNT_UPDATE = "Обнулено поденний лічильник документів" +SETTINGS_CACHE_LIFETIME = "Увага!!! Увімкнено кешування запиту до налаштувань системи. Зміни набудуть чинності, тільки після закінчення часу життя кеша або відключення кешування" + +// v3.2 +SETTINGS_PAGINATION = "Налаштування пагінації" +PAGINATION_ADD = "Створити шаблон пагінації" +PAGINATION_NAME = "Найменування" +PAGINATION_ACTIONS = "Дії" +PAGINATION_EDIT_HINT = "Редагувати" +PAGINATION_DELETE_HINT = "Видалити пагінацію" +PAGINATION_DEL_HINT = "Ви впевнені, що бажаєте видалити цей шаблон пагінації?" +PAGINATION_SAVED = "Шаблон пагінації успішно збережено" +PAGINATION_SAVED_ERR = "Не вдалося зберегти шаблон пагінації.
Спробуйте ще раз." +PAGINATION_ERROR = "Помилка" +PAGINATION_SUCCESS = "Виконано" + +pagination_name = "Найменування" +pagination_navigation_box = "Контейнер посторінкової навігації
Приклад: <ul class="pagination pagination-sm">%s</ul>" +pagination_link_box = "Контейнер для елемента
Приклад: <li>%s</li>" +pagination_active_link_box = "Контейнер для активного елемента
Приклад: <li class="active">%s</li>" +pagination_link_template = "Шаблон посилання елемента
[link] - посилання на сторінку
[page] - Номер сторінки для посилання
[name] - Номер сторінки
" +pagination_link_active_template = "Шаблон активного посилання елемента
[link] - посилання на сторінку
[page] - Номер сторінки для посилання
[name] - Номер сторінки
" +pagination_separator_box = "Контейнер для мітки про наявність сторінок
Приклад: <li>%s</li>" +pagination_separator_label = "Текст для мітки про наявність сторінок" +pagination_start_label = "Текст посилання “Перша”" +pagination_end_label = "Текст посилання “Остання”" +pagination_next_label = "Текст посилання “Наступна”" +pagination_prev_label = "Текст посилання “Попередня”" + +// v3.24 +SETTINGS_SAVED_ERR_FILE = "Помилка при збереженні файлу. Спробуйте ще раз." +SETTINGS_SAVED_FILE = "Файл успішно збережено." +SETTINGS_FILE_EDIT_H = "Редагування файлу" +SETTINGS_FILE_CONTENT = "Вміст файлу:" +SETTINGS_FILE_ROBOTS = "Файл robots.txt" +SETTINGS_FILE_CUSTOM = "Файл func.custom.php" + +// v3.25 +_const_auth = "Авторизація" +_const_url = "Формування URL" +_const_themes = "Оформлення" +_const_folders = "Папки" +_const_thumbs = "Генерація мініатюр" +_const_watermarks = "Водяні знаки" +_const_sessions = "Session та Cookie" +_const_dev = "Розробка" +_const_smarty = "Налаштування Smarty" +_const_cache = "Кешування SQL" +_const_compression = "Компресія" +_const_memcached = "Memcached" +_const_request = "Запити" +_const_database = "База даних" +_const_other = "Інше" diff --git a/admin/lang/ua/sysblocks.txt b/admin/lang/ua/sysblocks.txt new file mode 100644 index 0000000..2178553 --- /dev/null +++ b/admin/lang/ua/sysblocks.txt @@ -0,0 +1,95 @@ +# солов’їна))) 01,2017 duncan + +SYSBLOCK_HEAD = "Системні блоки" +SYSBLOCK_EDIT = "Керування системними блоками" +SYSBLOCK_EDIT_TIP = "У цьому розділі представлені усі системні блоки." +SYSBLOCK_ID = "Id" +SYSBLOCK_NAME = "Назва системного блока" +SYSBLOCK_HTML = "Код системного блока" +SYSBLOCK_TAGS = "Тег" +SYSBLOCK_TAGS_2 = "HTML Tags" +SYSBLOCK_EXTERNAL = "Дозволити зовнішнє звертання за посиланням" +SYSBLOCK_EXTERNAL_H = "зовнішнє звертання за посиланням" +SYSBLOCK_EXTERNAL_GO = "Перейти" +SYSBLOCK_AJAX = "Дозволяти виконуватися тільки по Ajax" +SYSBLOCK_AJAX_H = "виконуватися тільки по Ajax" + +SYSBLOCK_VISUAL = "Візуальний редактор" +SYSBLOCK_VISUAL_H = "Візуальний редактор" + +SYSBLOCK_MEDIAPATH = "Системний тег, шляхи до папки дизайну" +SYSBLOCK_BREADCRUMB = "Системний тег хлібних крихт" +SYSBLOCK_DOCID_INFO = "Системний тег, ідентифікатор документа" +SYSBLOCK_PATH = "Кореневий шлях установки" +SYSBLOCK_HOME = "Посилання на головну сторінку cайту" + +SYSBLOCK_AUTHOR = "Автор" +SYSBLOCK_DATE = "Дата створення" +SYSBLOCK_TAG = "Системний тег" +SYSBLOCK_ACTIONS = "Дії" +SYSBLOCK_NO_ITEMS = "Повідомлення:
На цей час немає збереженоних системних блоків." +SYSBLOCK_BUTTON_SAVE = "Зберегти зміни" +SYSBLOCK_BUTTON_ADD = "Додати системний блок" +SYSBLOCK_BUTTON_COPY = "Копіювати" +SYSBLOCK_INSERT_H = "Додавання системного блока" +SYSBLOCK_EDIT_H = "редагування системного блока" +SYSBLOCK_INNAME = "Введіть назву системного блока" +SYSBLOCK_ENTER_NAME = "Будь ласка, вкажіть назву системного блока" +SYSBLOCK_INSERT = "Тут Ви можете додати або змінити обраний Вами системний блок" + +SYSBLOCK_LINK = "Системний блок є доступний за посиланням:" + +SYSBLOCK_SAVE = "Додати" +SYSBLOCK_SAVEDIT = "Зберегти зміни" +SYSBLOCK_SAVE_NEXT = "Додати та продовжити редагування" +SYSBLOCK_SAVEDIT_NEXT = "Примінити (CTRL+S)" + +SYSBLOCK_INTEXT = "Системний блок" +SYSBLOCK_ADD = "Додати новий системний блок" +SYSBLOCK_ADD_BUTTON = "Додати" +SYSBLOCK_EDIT_HINT = "Редагувати системний блок" +SYSBLOCK_DELETE_HINT = "видалити системний блок" +SYSBLOCK_DEL_HINT = "Ви впевнені, що бажаєте видалити системний блок?" +SYSBLOCK_LIST_LINK = "Список системних блоків" +SYSBLOCK_FILE = "Файл шаблона" +SYSBLOCK_SAVED = "Системний блок успішно збережено." +SYSBLOCK_COPY_TITLE = "копіювання системного блока" +SYSBLOCK_COPY = "Копіювати системний блок" +SYSBLOCK_COPY_TIP = "Будь ласка, вкажіть назву системного блока" +SYSBLOCK_COPY_TIP2 = "Будь ласка, вкажіть назву для системного блока, що копіюється" +SYSBLOCK_EXIST = "Даруйте, але системний блок з такою назвою уже існує" +SYSBLOCK_SQLUPDATE = "Змінив системний блок" +SYSBLOCK_SQLNEW = "Створив новий системний блок" +SYSBLOCK_SQLDEL = "Видалив системний блок" +SYSBLOCK_OR = " або " + +SYSBLOCK_SAVED = "Системний блок успішно збережено" +SYSBLOCK_SAVED_ERR = "Не вдалося зберегти системний блок.
Спробуйте ще раз." +SYSBLOCK_ERROR = "Помилка" +SYSBLOCK_SUCCESS = "Виконано" + +// v 3.2 +SYSBLOCK_DESCRIPTION = "Короткий опис" +SYSBLOCK_ALIAS = "Аліас" +SYSBLOCK_I = "Опціонально. Аліас дозволяє використовувати легкий для запам’ятовування тег [tag:sysblock:alias] замість [tag:sysblock:id]. Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення, мати довжину не більше 20 символів та бути унікальним у межах цих блоків" +SYSBLOCK_ACCEPT = "Цей аліас можна використовувати" +SYSBLOCK_ER_SYN = "Неправильний аліас!
Аліас не повинен бути числом, може містити тільки цифри, латинські літери, дефіс, підкреслення та мати довжину не більше 20 символів" +SYSBLOCK_ER_EXISTS = "Неправильний аліас!
Такий аліас уже прив’язаний до іншого системного блока" + +// v 3.26 +SYSBLOCK_EVAL = "Виконувати PHP перед поверненням результату" +SYS_GROUP_NO_TITLE = "Без групи" +SYS_GROUP_NO_DESCRIPTION = "Опис відсутній" +SYS_GROUP_PLEASE_SELECT = "Оберіть групу" +SYS_GROUP_TITLE = "Назва групи" +SYS_GROUP_DESCRIPTION = "Опис групи" +SYS_GROUP_BTN = "Додати групу" +SYS_GROUPS = "Список груп" +SYS_GROUPS_SORT_TIP = "Для впорядкування полів натисніть на хрестик та, утримуючи його, перетягніть поле" +SYS_GROUPS_GROUP_TITLE = "Назва групи" +SYS_GROUPS_TIP = "Список груп для системних блоків" +SYS_NO_GROUPS = "В даний час, немає груп для системних блоків" +SYS_GROUPS_DELETE = "Видалити групу" +SYS_GROUPS_DELETE_H = "Ви впевнені, що бажаєте видалити групу?" +SYS_GROUPS_NEW = "Додати нову групу" +SYSBLOCK_COPY_LOG = " створив копію системного блоку" diff --git a/admin/lang/ua/templates.txt b/admin/lang/ua/templates.txt new file mode 100644 index 0000000..f5bf640 --- /dev/null +++ b/admin/lang/ua/templates.txt @@ -0,0 +1,119 @@ +# солов’їна))) 01,2017 duncan + +TEMPLATES_SUB_TITLE = "Керування шаблонами" +TEMPLATES_TIP1 = "У цьому розділі наведено список усіх шаблонів, які використовуються у системі. Тут Ви можете видалити, відредагувати або скопіювати шаблон, щоб створити на його базі новий." +TEMPLATES_ID = "ID" +TEMPLATES_NAME = "Назва шаблона" +TEMPLATES_NAME2 = "Назва шаблона:" +TEMPLATES_NAME3 = "вкажіть назву шаблона:" +TEMPLATES_AUTHOR = "Автор" +TEMPLATES_DATE = "Дата створення" +TEMPLATES_ACTION = "Дії" +TEMPLATES_DATE_FORMAT = "%d.%m.%y г." +TEMPLATES_DATE_FORMAT2 = "%H:%M" +TEMPLATES_IN = "в" +TEMPLATES_EDIT = "Редагувати шаблон" +TEMPLATES_NO_CHANGE = "Даруйте, але у Вас недостатньо прав для редагування шаблона" +TEMPLATES_DELETE = "видалити шаблон" +TEMPLATES_DELETE_CONF = "Ви впевнені, що бажаєте видалити цей шаблон?" +TEMPLATES_NO_DELETE2 = "Даруйте, але Ви не можете видалити цей шаблон, оскільки він використовується рубриками або модулями" +TEMPLATES_NO_DELETE3 = "Даруйте, але у вас недостатньо прав для видалення шаблона" +TEMPLATES_COPY = "Копіювати шаблон" +TEMPLATES_NO_COPY = "Даруйте, але у вас недостатньо прав для копіювання шаблона" +TEMPLATES_LEGEND = "Значення піктограм" +TEMPLATES_COPY_TITLE = "копіювання шаблона" +TEMPLATES_TIP2 = "Будь ласка, вкажіть назву для скопійованого шаблона" +TEMPLATES_TIP3 = "Будь ласка, вкажіть назву для шаблона" +TEMPLATES_BUTTON_COPY = "Копіювати" +TEMPLATES_TAG_INSERT = "Натисніть на назву системного тега, щоб додати його в поле шаблона" +TEMPLATES_TITLE_NEW = "Створення нового шаблона" +TEMPLATES_TITLE_EDIT = "редагування шаблона" +TEMPLATES_WARNING1 = "Будь ласка, будьте уважні при редагуванні шаблона та пам’ятайте, що неправильно указанний код може зіпсувати зовнішнє оформлення cайту" +TEMPLATES_WARNING2 = "У цьому розділі Ви можете створити новий шаблон вручну, а також завантажити готову структуру шаблона з існуючого файла. Пам’ятайте, що файли з готовою структурою повинні бути розміщені в директорії /inc/data/prefabs/templates/" +TEMPLATES_HTML = "HTML код шаблона" +TEMPLATES_USE_PHP = "Даруйте, але у Вас недостатньо прав для редагування шаблона, оскільки він використовує PHP код" +TEMPLATES_BUTTON_SAVE = "Зберегти зміни" +TEMPLATES_BUTTON_SAVE_NEXT = "Примінити (CTRL+S)" +TEMPLATES_FILE_SAVED = "Файл успішно збережено" +TEMPLATES_BUTTON_ADD = "Додати шаблон" +TEMPLATES_BUTTON_ADD_NEXT = "Додати та продовжити редагування" +TEMPLATES_BUTTON_LOAD = "завантажити" +TEMPLATES_LOAD_INFO = "Будь ласка, оберіть зі списку файл з готовою структурою шаблона" +TEMPLATES_EXIST = "Даруйте, але шаблон з такою назвою уже існує" +TEMPLATES_NO_NAME = "Будь ласка, вкажіть назву шаблона" +TEMPLATES_ALL = "Список шаблонів" +TEMPLATES_OR = " або " + +TEMPLATES_FILE_NAME = "Назва файла" +TEMPLATES_CSS_FILES = "Список css файлів" +TEMPLATES_JS_FILES = "Список js файлів" +TEMPLATES_FILES = "Файловий менеджер" +TEMPLATES_EDIT_FILE = "Редагувати файл" +TEMPLATES_DEL_FILE = "видалити файл" + +TEMPLATES_TAGS = "Тег" +TEMPLATES_TAG_DESC = "Опис тега" +TEMPLATES_THEME_FOLDER = "Назва шаблона (Ім’я папки з файлами для цього шаблона)" +TEMPLATES_FOLDER = "Папка:" +TEMPLATES_PAGENAME = "Назва cайту" +TEMPLATES_FILENAME = "Назва файла" +TEMPLATES_TITLE = "Назва сторінки" +TEMPLATES_KEYWORDS = "Ключові слова (Meta - Keywords)" +TEMPLATES_DESCRIPTION = "Опис сторінки (Meta - Description)" +TEMPLATES_INDEXFOLLOW = "Тип індексування" +TEMPLATES_CANONICAL = "Канонічна сторінка – це рекомендований екземпляр з набора сторінок з дуже схожим вмістом." +TEMPLATES_PATH = "Кореневий шляхи установки" +TEMPLATES_MEDIAPATH = "Шляхи до папки з шаблоном (Приклад: [tag:mediapath]images/logo.gif)" + +TEMPLATES_CSS = "Стискає декілька css-файлів в один. Повертає шлях.
FFF - імена файлів через кому
P - шляхи до папки з файлами, не обов’язково. По замовчуванню - [tag:mediapath]css/

Приклад: href="[tag:css:reset.css,style.css]"" + +TEMPLATES_JS = "Стискає декілька js-файлів в один. Повертає шлях.
FFF - імена файлів через кому
P - шляхи до папки з файлами, не обов’язково. По замовчуванню - [tag:mediapath]js/

Приклад: href="[tag:js:common.js,main.js]"" + +TEMPLATES_MEDIAPATH = "Шляхи до папки з шаблоном (Приклад: [tag:mediapath]images/logo.gif)" +TEMPLATES_MAINCONTENT = "Тег для головного вмісту" +TEMPLATES_QUICKFINDER = "Випадаюче меню швидкої навигації" +TEMPLATES_DOCUMENT = "Посилання на поточний документ" +TEMPLATES_ALIAS = "Посилання на поточний документ (Alias)" +TEMPLATES_SYSBLOCK = "Системний тег системних блоків" +TEMPLATES_TEASER = "Системний тег тизерів" +TEMPLATES_PRINTLINK = "Посилання на "Версія для друку"" +TEMPLATES_HOME = "Посилання на головну сторінку cайту" +TEMPLATES_BREADCRUMB = "Системний тег хлібних крихт" +TEMPLATES_VERSION = "Показ інформації про захист інформації" +TEMPLATES_NAVIGATION = "Меню навигації (ххх - номер меню)" +TEMPLATES_IF_PRINT = "Вміст буде показано при друці." +TEMPLATES_DONOT_PRINT = "Вміст не буде показано при друці" +TEMPLATES_RUBHEADER = "Налаштовується у шаблоні рубрики
(Шаблон оформлення HEADER)" +TEMPLATES_NO_ITEMS = "На цей час немає файлів" + +TEMPLATES_CACHE_SUCCESS = "Кеш успішно очищено." +TEMPLATES_CACHE_SUCCESS_LOG = "Очистив кеш" + +TEMPLATES_CSS_TITLE = "Будь ласка, будьте уважні при редагуванні файлів та пам’ятайте, що неправильно указанний код може зіпсувати зовнішнє оформлення cайту" +TEMPLATES_CSS_EDITOR = "Редактор файлів CSS" + +TEMPLATES_JS_TITLE = "Будь ласка, будьте уважні при редагуванні файлів та пам’ятайте, що неправильно указанний код може зіпсувати зовнішнє оформлення cайту" +TEMPLATES_JS_EDITOR = "Редактор файлів CSS" + +TEMPLATES_REPORT_NEW = "Створив шаблон" +TEMPLATES_REPORT_CHANGE = "Змінив шаблон" +TEMPLATES_REPORT_PHP = "Спроба використання PHP коду у шаблоні" +TEMPLATES_REPORT_PHP_CSS = "Спроба використання PHP коду в css файлі" +TEMPLATES_REPORT_PHP_JS = "Спроба використання PHP коду в js файлі" +TEMPLATES_REPORT_PHP_ERR = "Заборонено використовувати PHP код" +TEMPLATES_REPORT_ID_ERR = "Спроба видалення основного шаблона" +TEMPLATES_REPORT_DELETE = "Видалив шаблон" +TEMPLATES_REPORT_FILE = "Відредагував файл" +TEMPLATES_REPORT_COPY = "Створив копію шаблона" +TEMPLATES_REPORT_DEL_OK = "Файл успішно видалено" +TEMPLATES_REPORT_DEL_ER = "Не вдалося видалити файл" + +TEMPLATES_REPORT_ERROR_TEXT = "HTML код шаблона пустий" +TEMPLATES_REPORT_ERROR_TITLE = "Не заповнено - назва шаблона" + +TEMPLATES_SAVED = "Шаблон успішно збережено" +TEMPLATES_SAVED_FILE = "Файл успішно збережено" +TEMPLATES_SAVED_ERR = "Не вдалося зберегти шаблон.
Спробуйте ще раз." +TEMPLATES_SAVED_ERR_FILE = "Не вдалося зберегти файл.
Спробуйте ще раз." +TEMPLATES_ERROR = "Помилка" +TEMPLATES_SUCCESS = "Виконано" diff --git a/admin/lang/ua/user.txt b/admin/lang/ua/user.txt new file mode 100644 index 0000000..701331b --- /dev/null +++ b/admin/lang/ua/user.txt @@ -0,0 +1,92 @@ +# солов’їна))) 01,2017 duncan + +[user] +USER_SUB_TITLE = "Керування користувачами" +USER_TIP1 = "У цьому розділі наведено список усіх користувачів у системі. Тут Ви можете відредагувати параметри користувача, видалити користувача, а також перенести користувача в іншу групу." +USER_ID = "ID" +USER_NAME = "Ім’я та прізвище користувача" +USER_NAME2 = "Ім’я користувача" +USER_GROUP = "Перебуває в групі" +USER_STATUS_WAIT = "Очікує активацію" +USER_LAST_VISIT = "Останній вхід" +USER_REGISTER_DATE = "Дата реєстрації" +USER_ACTION = "Дії" +USER_DELETE = "Видалити користувача" +USER_EDIT = "Редагувати користувача" +USER_DATE_FORMAT = "%d.%m.%Y %H:%M" +USER_NO_CHANGE = "Даруйте, але у вас недостатньо прав для редагування користувачів" +USER_DELETE_CONFIRM = "Ви впевнені, що бажаєте видалити цього користувача?" +USER_LEGEND = "Значення піктограм" +USER_BUTTON_SAVE = "Зберегти зміни" +USER_ORDERS = "Історія замовлень" +USER_DOWNLOADS = "Історія замовлень ПО" +USER_MARK_DELETE = "Відмітити для видалення" +USER_NEW_TITLE = "Створення нового користувача" +USER_NEW_TIP = "Щоби додати нового користувача, заповніть поля з відповідними даними. Будь ласка, будьте уважні при виборі групи для цього користувача. Неправильно вказана група може обмежити доступ користувача до відповідних розділів cайту або навпаки, дозволити доступ до закритих розділів." +USER_EDIT_TITLE = "Редагування користувача" +USER_EDIT_TIP = "У цьому розділі Ви можете відредагувати параметри користувача, а також змінити пароль та групу користувача." +USER_ERRORS = "Помилка:" +USER_FIRSTNAME = "Ім’я:" +USER_FIRSTNAME_ADD = "Введіть ім’я користувача:" +USER_LASTNAME = "Прізвище:" +USER_EMAIL = "E-mail адреса:" +USER_NICK = "Нікнейм на форумі:" +USER_SIGNATURE = "Підпис на форумі:" +USER_AVATAR = "Аватар:" +USER_TAX = "Обкладати податком:" +USER_COMPANY = "Компанія:" +USER_HOUSE_STREET = "Вулиця / Номер будинку:" +USER_ZIP_CODE = "Поштовий індекс:" +USER_CITY = "Місто проживання:" +USER_PASSWORD = "Пароль:" +USER_PASSWORD_CHANGE = "Змінити" +USER_PASSWORD_SHOW = "Показати пароль" +USER_YES = "Так" +USER_NO = "Ні" +USER_COUNTRY = "Країна:" +USER_PHONE = "Контактний телефон:" +USER_FAX = "Факс:" +USER_BIRTHDAY = "Дата народження:" +USER_BIRTHDAY_FORMAT = " у форматі (ДД.ММ.ГГГГ)" +USER_NOTICE = "Додаткова інформація:" +USER_MAIN_GROUP = "Основна група:" +USER_SECOND_GROUP = "Додаткова група:" +USER_SECOND_INFO = "Вибір декількох груп" +USER_STATUS = "Статус користувача:" +USER_ACTIVE = "Активний" +USER_INACTIVE = "Неактивний" +USER_BUTTON_ADD = "Додати користувача" +USER_SEND_INFO = "Проінформувати користувача поштою" +USER_MESSAGE_SUBJECT = "Тема повідомлення:" +USER_MESSAGE_TEXT = "Текст повідомлення:" +USER_EMAIL_EXIST = "Даруйте, але указана E-mail адреса уже використовується у системі." +USER_ERROR_DATEFORMAT = "Дата народження указана в неправильному форматі." +USER_PASSWORD_SHORT = "Указанний пароль надто короткий. Будь ласка, використовуйте мінімум 5 символів." +USER_PASSWORD_ERROR = "Поле пароль містить недопустимі символи." +USER_NO_EMAIL = "Поле E-mail не заповнено. Будь ласка, вкажіть E-Mail адресу." +USER_NO_PASSWORD = "Поле пароль не заповнено. Будь ласка, вкажіть пароль." +USER_EMAIL_ERROR = "Поле E-mail адрес містить недопустимі символи, Будь ласка, перевірте указану E-mail адресу." +USER_NO_FIRSTNAME = "Поле ім’я користувача не заповнено. Будь ласка, вкажіть ім’я користувача." +USER_NO_USERNAME = "Поле логін не заповнено. Будь ласка, вкажіть логін користувача." +USER_ERROR_FIRSTNAME = "Поле ім’я користувача містить недопустимі символи." +USER_ERROR_USERNAME = "Поле логін містить недопустимі символи." +USER_NO_LASTNAME = "Поле прізвище користувача не заповнено. Будь ласка, вкажіть прізвище користувача," +USER_ERROR_LASTNAME = "Поле прізвище користувача містить недопустимі символи." +USER_MAIL_BODY1 = "Вітання %USER%,%N%%N%" +USER_MAIL_BODY2 = "Ваш аккаунт успішно активовано. Будь ласка, використовуйте Ваші реєстраційні дані для входу на сайт %HOST%." +USER_MAIL_FOOTER = "%N%%N%З повагою, %HOMEPAGENAME%%N%%N%%HOST%" +USER_MAIL_SUBJECT = "Ваш аккаунт активовано" +USER_MAIL_PASSWORD = "інформація про зміну пароля" +USER_MAIL_PASSWORD2 = "Повідомляємо Вас про зміну пароля.%N%%N%Ваш новий пароль: %NEWPASS%" +USER_NEW_ADD = "Створення нового користувача" +USER_ALL = "Список користувачів" +USER_LOGIN = "Логін у системі:" +SETTINGS_NAME = "Параметр" +SETTINGS_VALUE = "Значення" +USER_LIST_EMPTY = "Немає користувачів, які відповідають таким умовам пошука.
Спробуйте змінити умови пошука." +USER_REPORT_ADD = "Додав користувача" +USER_REPORT_EDIT = "Відредагував параметри користувача" +USER_REPORT_DEL = "Видалив користувача" +USER_REPORT_GROUP = "Змінив групу для користувача" +USER_YOUR_NOT_CHANGE = "Помилка! Даруйте, але Ви не маєте прав для редагування цього користувача." +USER_WARNING_TIP = "Увага! Будьте уважні, при редагуванні цього користувача." \ No newline at end of file diff --git a/admin/logs.php b/admin/logs.php new file mode 100644 index 0000000..7be9432 --- /dev/null +++ b/admin/logs.php @@ -0,0 +1,92 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/logs.txt', 'logs'); + +switch ($_REQUEST['action']) +{ + case '': + if (check_permission_acp('logs_view')) + { + $AVE_Logs->logList(); + } + break; + + case 'log404': + if (check_permission_acp('logs_view')) + { + $AVE_Logs->List404(); + } + break; + + case 'logsql': + if (check_permission_acp('logs_view')) + { + $AVE_Logs->ListSql(); + } + break; + + case 'delete': + if (check_permission_acp('logs_clear')) + { + $AVE_Logs->logDelete(); + } + break; + + case 'deletesql': + if (check_permission_acp('logs_clear')) + { + $AVE_Logs->DeleteSql(); + } + break; + + case 'delete404': + if (check_permission_acp('logs_clear')) + { + $AVE_Logs->Delete404(); + } + break; + + case 'export': + if (check_permission_acp('logs_view')) + { + $AVE_Logs->logExport(); + } + break; + + case 'export404': + if (check_permission_acp('logs_view')) + { + $AVE_Logs->Export404(); + } + break; + + case 'exportsql': + if (check_permission_acp('logs_view')) + { + $AVE_Logs->ExportSql(); + } + break; +} + +?> \ No newline at end of file diff --git a/admin/modules.php b/admin/modules.php new file mode 100644 index 0000000..0ab7fcb --- /dev/null +++ b/admin/modules.php @@ -0,0 +1,102 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/modules.txt', 'modules'); + + if (! empty($_REQUEST['moduleaction'])) + { + if (! check_permission('mod_' . $_REQUEST['mod'])) + { + echo $AVE_Template->get_config_vars('MAIN_NO_PERM_MODULES'); + exit; + } + } + + if (! empty($_REQUEST['module'])) + { + $module_path = preg_replace('/[^\w]/', '', $_REQUEST['module']); + + if (! empty($module_path)) + define('MODULE_PATH', $module_path); + } + + switch($_REQUEST['action']) + { + case '': + if (check_permission_acp('modules_view')) + { + $AVE_Module->moduleList(); + } + break; + + case 'quicksave': + if (check_permission_acp('modules_system')) + { + $AVE_Module->moduleOptionsSave(); + } + break; + + case 'install': + case 'reinstall': + if (check_permission_acp('modules_system')) + { + $AVE_Module->moduleInstall(); + } + break; + + case 'update': + if (check_permission_acp('modules_system')) + { + $AVE_Module->moduleUpdate(); + } + break; + + case 'delete': + if (check_permission_acp('modules_system')) + { + $AVE_Module->moduleDelete(); + } + break; + + case 'onoff': + if (check_permission_acp('modules_system')) + { + $AVE_Module->moduleStatusChange(); + } + break; + + case 'modedit': + if (check_permission_acp('modules_admin')) + { + $mod_path = preg_replace('/[^\w]/', '', $_REQUEST['mod']); + $mod_path = BASE_DIR . '/modules/' . $mod_path . '/module.php'; + + if (is_file($mod_path)) + include($mod_path); + } + break; + + case 'remove': + if (check_permission_acp('modules_system')) + { + $AVE_Module->moduleRemove($_REQUEST['module']); + } + break; + } +?> \ No newline at end of file diff --git a/admin/navigation.php b/admin/navigation.php new file mode 100644 index 0000000..28ce69a --- /dev/null +++ b/admin/navigation.php @@ -0,0 +1,136 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/navigation.txt', 'navi'); + + switch ($_REQUEST['action']) + { + case '': + if (check_permission_acp('navigation_view')) + { + $AVE_Navigation->navigationList(); + } + break; + + case 'new': + if (check_permission_acp('navigation_edit')) + { + require(BASE_DIR . '/class/class.user.php'); + $AVE_User = new AVE_User; + $AVE_Navigation->navigationNew(); + } + break; + + case 'copy': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationCopy((int)$_REQUEST['navigation_id']); + } + break; + + case 'delete': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationDelete((int)$_REQUEST['navigation_id']); + } + break; + + case 'templates': + if (check_permission_acp('navigation_edit')) + { + require(BASE_DIR . '/class/class.user.php'); + $AVE_User = new AVE_User; + $AVE_Navigation->navigationEdit($_REQUEST['navigation_id']); + } + break; + + case 'entries': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemList((int)$_REQUEST['navigation_id']); + } + break; + + case 'sorting': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationSort((int)$_REQUEST['navigation_id']); + } + break; + + case 'itemedit': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemEdit((int)$_REQUEST['navigation_item_id']); + } + break; + + case 'itemeditid': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->getDocumentById((int)$_REQUEST['doc_id']); + } + break; + + case 'saveitem': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemSave((int)$_REQUEST['navigation_item_id']); + } + break; + + case 'itemnew': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemNew((int)$_REQUEST['navigation_id']); + } + break; + + case 'itemestatus': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemStatus((int)$_REQUEST['navigation_item_id'], $_REQUEST['status']); + } + break; + + case 'getitem': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemGet((int)$_REQUEST['navigation_item_id']); + } + break; + + case 'itemdelete': + if (check_permission_acp('navigation_edit')) + { + $AVE_Navigation->navigationItemDelete((int)$_REQUEST['navigation_item_id']); + } + break; + + case 'alias': + if (check_permission_acp('navigation_edit')) + { + echo $AVE_Navigation->navigationValidate($_REQUEST['alias'], (int)$_REQUEST['id']); + } + exit; + } +?> diff --git a/admin/request.php b/admin/request.php new file mode 100644 index 0000000..6abf11d --- /dev/null +++ b/admin/request.php @@ -0,0 +1,102 @@ +rubricPermissionFetch(); + +$AVE_Template->config_load(BASE_DIR . "/admin/lang/" . $_SESSION['admin_language'] . "/request.txt", 'request'); + +switch ($_REQUEST['action']) +{ + case '': + if(check_permission_acp('request')) + { + $AVE_Request->requestListShow(); + } + break; + + case 'edit': + if(check_permission_acp('request_edit')) + { + $AVE_Rubric->rubricTemplateShow(0, 1); + $AVE_Request->requestEdit((int)$_REQUEST['Id']); + } + break; + + case 'copy': + if(check_permission_acp('request')) + { + $AVE_Request->requestCopy((int)$_REQUEST['Id']); + } + break; + + case 'new': + if(check_permission_acp('request_new')) + { + $AVE_Rubric->rubricTemplateShow(0, 1); + $AVE_Request->requestNew(); + } + break; + + case 'delete_query': + if(check_permission_acp('request_del')) + { + $AVE_Request->requestDelete((int)$_REQUEST['Id']); + } + break; + + case 'conditions': + if(check_permission_acp('request_edit')) + { + $AVE_Rubric->rubricTemplateShow(0, 1); + $AVE_Request->requestConditionEdit((int)$_REQUEST['Id']); + } + break; + + case 'change': + if(check_permission_acp('request_edit')) + { + switch($_REQUEST['sub']) + { + case '': + $AVE_Rubric->rubricTemplateShow(0, 1); + $AVE_Request->conditionFieldChange((int)$_REQUEST['field_id'], (int)$_REQUEST['cond_id']); + break; + + case 'save': + $AVE_Rubric->rubricTemplateShow(0, 1); + $AVE_Request->conditionFieldChangeSave((int)$_REQUEST['field_id'], (int)$_REQUEST['cond_id']); + break; + } + } + break; + + case 'alias': + if (check_permission_acp('request_edit')) + { + echo $AVE_Request->requestValidate($_REQUEST['alias'], (int)$_REQUEST['id']); + } + exit; +} + +?> \ No newline at end of file diff --git a/admin/rubs.php b/admin/rubs.php new file mode 100644 index 0000000..554f5dc --- /dev/null +++ b/admin/rubs.php @@ -0,0 +1,670 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/rubs.txt', 'rubs'); + + switch($_REQUEST['action']) + { + case '' : + if(check_permission('rubric_view')) + { + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case 'quicksave': + $AVE_Rubric->quickSave(); + break; + } + } + $AVE_Rubric->rubricList(); + $AVE_Template->assign('templates', get_all_templates()); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/list.tpl')); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_VIEW')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'new': + if(check_permission('rubric_edit')) + { + $AVE_Template->assign('templates', get_all_templates()); + $AVE_Rubric->rubricNew(); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE3')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'template': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + $AVE_Rubric->rubricTemplateShow(); + break; + + case 'save': + + $Rtemplate = $_POST['rubric_template']; + $Htemplate = $_POST['rubric_header_template']; + $Ftemplate = $_POST['rubric_footer_template']; + $Ttemplate = $_POST['rubric_teaser_template']; + $Atemplate = $_POST['rubric_admin_teaser_template']; + + $check_code = strtolower($Rtemplate.$Htemplate.$Ttemplate.$Atemplate.$Ftemplate); + + $ok = true; + + if ((is_php_code($check_code)) && !check_permission('rubric_php') ) + { + $AVE_Template->assign('php_forbidden', 1); + + $ok = false; + } + + if (! $ok) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_PHP_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIC_ERROR'); + $theme = 'error'; + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + else + { + $AVE_Rubric->rubricTemplateShow(1); + } + } + else + { + $AVE_Rubric->rubricTemplateSave($Rtemplate, $Htemplate, $Ttemplate, $Atemplate, $Ftemplate); + } + break; + } + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE2')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'delete': + if(check_permission('rubric_edit')) + { + $AVE_Rubric->rubricDelete(); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'multi': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case 'save': + $AVE_Rubric->rubricCopy(); + break; + } + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/multi.tpl')); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_MULTIPLY')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'edit': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + switch($_REQUEST['submit']) + { + case 'saveperms': + if (check_permission('rubric_perms')){ + $AVE_Rubric->rubricPermissionSave((int)$_REQUEST['Id']); + } + break; + + case 'save': + $AVE_Rubric->rubricFieldSave((int)$_REQUEST['Id']); + break; + + case 'linked_rubric': + $AVE_Rubric->rubricShow(1); + break; + + case 'code': + if (check_permission('rubric_code')){ + $AVE_Rubric->rubricCode((int)$_REQUEST['Id']); + } + break; + + case 'description': + $AVE_Rubric->rubricDesc((int)$_REQUEST['Id']); + break; + } + } + $AVE_Rubric->rubricFieldShow((int)$_REQUEST['Id'], null); + break; + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE1')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'alias_add': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricAliasAdd(); + } + break; + + case 'code': + if (check_permission('rubric_code')) + { + $AVE_Rubric->rubricCodeEdit($_REQUEST['Id']); + } + break; + + case 'field_template': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldTemplate(); + } + break; + + case 'field_template_save': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldTemplateSave((int)$_REQUEST['field_id'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'fieldssort': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldsSort((array)$_REQUEST['sort']); + } + exit; + + case 'rubssort': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricsSort((array)$_REQUEST['sort']); + } + exit; + + case 'alias_check': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricAliasCheck((int)$_REQUEST['rubric_id'],(int)$_REQUEST['field_id'], $_REQUEST['rubric_field_alias']); + } + break; + + case 'newfield': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldNew((int)$_REQUEST['Id'], $_REQUEST['ajax']); + } + break; + + case 'fields': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldShow((int)$_REQUEST['Id'], $_REQUEST['ajax']); + } + break; + + case 'change': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldChange((int)$_REQUEST['field_id'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'changesave': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldChangeSave((int)$_REQUEST['field_id'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'changegroup': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldGroupChange((int)$_REQUEST['field_id'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'changegroupsave': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldGroupChangeSave((int)$_REQUEST['field_id'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'fieldsgroups': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldsGroups((int)$_REQUEST['Id']); + } + break; + + case 'newfieldsgroup': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricNewGroupFields((int)$_REQUEST['Id']); + } + break; + + case 'savefieldsgroup': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricEditGroupFields((int)$_REQUEST['Id']); + } + break; + + case 'delfieldsgroup': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricDelGroupFields((int)$_REQUEST['Id'], (int)$_REQUEST['rubric_id']); + } + break; + + case 'fieldsgroupssort': + if(check_permission_acp('rubric_edit')) + { + $AVE_Rubric->rubricFieldsGroupsSort((array)$_REQUEST['sort']); + } + exit; + + case 'tmpls': + if (check_permission_acp('rubric_edit')) + { + $AVE_Rubric->tmplsList(); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/tmpls.tpl')); + } + break; + + case 'tmpls_edit': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + $AVE_Rubric->tmplsEdit(); + break; + + case 'save': + + $title = $_POST['template_title']; + $template = $_POST['rubric_template']; + + $check_code = strtolower($template); + + $ok = true; + + if((is_php_code($check_code)) && !check_permission('rubric_php') ) + { + $AVE_Template->assign('php_forbidden', 1); + + $ok = false; + } + + if(! $ok) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_PHP_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIC_ERROR'); + $theme = 'error'; + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + else + { + $AVE_Rubric->tmplsEdit(); + } + } + else + { + $AVE_Rubric->tmplsSave($template, $title); + } + break; + } + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE2')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'tmpls_new': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + $AVE_Rubric->tmplsEdit(); + break; + + case 'save': + + $title = $_POST['template_title']; + $template = $_POST['rubric_template']; + + $check_code = strtolower($template); + + $ok = true; + + if((is_php_code($check_code)) && !check_permission('rubric_php') ) + { + $AVE_Template->assign('php_forbidden', 1); + + $ok = false; + } + + if(! $ok) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_PHP_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIC_ERROR'); + $theme = 'error'; + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + else + { + $AVE_Rubric->tmplsEdit(); + } + } + else + { + $AVE_Rubric->tmplsSave($template, $title); + } + break; + } + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE2')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'tmpls_from': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + $AVE_Rubric->tmplsEdit(); + break; + + case 'save': + + $title = $_POST['template_title']; + $template = $_POST['rubric_template']; + + $check_code = strtolower($template); + + $ok = true; + + if((is_php_code($check_code)) && !check_permission('rubric_php') ) + { + $AVE_Template->assign('php_forbidden', 1); + + $ok = false; + } + + if(! $ok) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_PHP_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIC_ERROR'); + $theme = 'error'; + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + else + { + $AVE_Rubric->tmplsEdit(); + } + } + else + { + $AVE_Rubric->tmplsSave($template, $title); + } + break; + } + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE2')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'tmpls_copy': + if(check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + $AVE_Rubric->tmplsEdit(); + break; + + case 'save': + + $title = $_POST['template_title']; + $template = $_POST['rubric_template']; + + $check_code = strtolower($template); + + $ok = true; + + if((is_php_code($check_code)) && !check_permission('rubric_php') ) + { + $AVE_Template->assign('php_forbidden', 1); + + $ok = false; + } + + if(! $ok) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_PHP_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIC_ERROR'); + $theme = 'error'; + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + else + { + $AVE_Rubric->tmplsEdit(); + } + } + else + { + $AVE_Rubric->tmplsSave($template, $title); + } + break; + } + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE2')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'tmpls_del': + if(check_permission('rubric_edit')) + { + $AVE_Rubric->tmplsDelete(); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'rules': + if (check_permission('rubric_edit')) + { + switch($_REQUEST['sub']) + { + case '': + switch($_REQUEST['submit']) + { + case 'saveperms': + if (check_permission('rubric_perms')) + $AVE_Rubric->rubricPermissionSave((int)$_REQUEST['Id']); + break; + } + } + $AVE_Rubric->rubricRulesShow((int)$_REQUEST['Id'], null); + break; + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_CHANGE1')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'ftlist': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->ShowFields(); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'ftshowfield': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->ShowFieldsByType($_REQUEST['type']); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + + case 'ftcreate': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->EditFieldTpl((int)$_REQUEST['id'], $_REQUEST['fld'], $_REQUEST['type']); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'ftedit': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->EditFieldTpl((int)$_REQUEST['id'], $_REQUEST['fld'], $_REQUEST['type']); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'ftempledit': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->EditFieldTpl('', $_REQUEST['fld'], $_REQUEST['type']); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + case 'ftsave': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->SaveFieldTpl((int)$_REQUEST['field_id'], $_REQUEST['field_name'], $_REQUEST['field_type'], $_REQUEST['func']); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + + + case 'ftdelete': + if (check_permission('rubric_edit')) + { + $AVE_Rubric->DeleteFieldTpl((int)$_REQUEST['id'], $_REQUEST['fld'], $_REQUEST['type'], $_REQUEST['func']); + } + else + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('RUBRIK_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + } +?> \ No newline at end of file diff --git a/admin/settings.php b/admin/settings.php new file mode 100644 index 0000000..685c4ea --- /dev/null +++ b/admin/settings.php @@ -0,0 +1,212 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/settings.txt','settings'); + + switch($_REQUEST['action']) + { + case '': + switch ($_REQUEST['sub']) + { + case '': + if (check_permission_acp('gen_settings')) + $AVE_Settings->settingsShow(); + break; + + case 'case': + if(check_permission_acp('gen_settings_more')) + $AVE_Settings->settingsCase(); + break; + + case 'save': + if (isset($_REQUEST['more'])) + { + if (check_permission_acp('gen_settings_more')) + $AVE_Settings->settingsCase(); + } + else + { + if (check_permission_acp('gen_settings')) + $AVE_Settings->settingsSave(); + } + break; + + case 'countries': + if (check_permission_acp('gen_settings_countries')) + { + if (isset($_REQUEST['save']) && $_REQUEST['save'] == 1) + { + $AVE_Settings->settingsCountriesSave(); + + header('Location:index.php?do=settings&sub=countries&cp=' . SESSION); + exit; + } + $AVE_Settings->settingsCountriesList(); + } + break; + + case 'language': + if(check_permission_acp('gen_settings_languages')) + { + if (isset($_REQUEST['func'])) + { + switch($_REQUEST['func']) + { + case 'default': + if(isset($_REQUEST['Id'])) + { + $exists = $AVE_DB->Query("SELECT Id FROM ".PREFIX."_settings_lang WHERE Id=".(int)$_REQUEST['Id'])->GetCell(); + + if ($exists) + { + $AVE_DB->Query("UPDATE ".PREFIX."_settings_lang SET lang_default=0"); + $AVE_DB->Query("UPDATE ".PREFIX."_settings_lang SET lang_default=1 WHERE Id=".(int)$_REQUEST['Id']." LIMIT 1"); + } + } + header('Location:index.php?do=settings&sub=language&cp=' . SESSION); + exit; + + case 'on': + if (isset($_REQUEST['Id'])) + $AVE_DB->Query("UPDATE ".PREFIX."_settings_lang SET lang_status=1 WHERE Id=".(int)$_REQUEST['Id']); + + header('Location:index.php?do=settings&sub=language&cp=' . SESSION); + exit; + + case 'off': + if (isset($_REQUEST['Id'])) + $AVE_DB->Query("UPDATE ".PREFIX."_settings_lang SET lang_status=0 WHERE Id=".(int)$_REQUEST['Id']); + + header('Location:index.php?do=settings&sub=language&cp=' . SESSION); + exit; + + case 'save': + $AVE_Settings->settingsLanguageEditSave(); + exit; + } + } + else + { + $AVE_Settings->settingsLanguageList(); + } + } + break; + + case 'editlang': + if (check_permission_acp('gen_settings_languages')) + $AVE_Settings->settingsLanguageEdit(); + break; + + case 'clearcache': + if (check_permission_acp('cache_clear')) + { + $AVE_Template->CacheClear(); + exit; + } + break; + + case 'clearthumb': + if (check_permission_acp('cache_thumb')) + { + $AVE_Template->ThumbnailsClear(); + exit; + } + break; + + case 'clearrevision': + if (check_permission_acp('document_revisions')) + { + $AVE_Document->documentsRevisionsClear(); + exit; + } + break; + + case 'clearcounter': + if (check_permission_acp('gen_settings')) + { + $AVE_Document->documentCounterClear(); + exit; + } + break; + + case 'showcache': + cacheShow(); + exit; + + case 'showcountdocs': + $rubric_id = isset($_REQUEST['rubric_id']) ? $_REQUEST['rubric_id'] : null; + countDocuments($rubric_id); + exit; + } + break; + + //-- v3.2 + case 'paginations': + $AVE_Settings->settingsPaginationsList(); + break; + + case 'new_paginations': + $AVE_Settings->settingsPaginationsNew(); + break; + + case 'edit_paginations': + $AVE_Settings->settingsPaginationsEdit(); + break; + + case 'save_paginations': + $AVE_Settings->settingsPaginationsSave(); + break; + + case 'del_paginations': + $AVE_Settings->settingsPaginationsDel(); + break; + //-- v3.2 + + //-- v3.24 + case 'robots': + $AVE_Settings->editRobots(); + break; + + case 'custom': + $AVE_Settings->editCustom(); + break; + //-- v3.24 + + //-- v3.27 + case 'showcache': + $AVE_Settings->showCache(); + break; + + case 'showsize': + $AVE_Settings->showCacheSize(); + break; + + case 'cacheclear': + $AVE_Settings->clearCache(); + break; + //-- v3.27 + } +?> \ No newline at end of file diff --git a/admin/start.php b/admin/start.php new file mode 100644 index 0000000..e74459b --- /dev/null +++ b/admin/start.php @@ -0,0 +1,33 @@ +assign('php_version', (@PHP_VERSION != '') ? @PHP_VERSION : 'unknow'); + $AVE_Template->assign('domain', $_SERVER["HTTP_HOST"]); + $AVE_Template->assign('mysql_version', $GLOBALS['AVE_DB']->mysql_version()); + $AVE_Template->assign('mysql_size', get_mysql_size()); + $AVE_Template->assign('navi', $AVE_Template->fetch('navi/navi.tpl')); + $AVE_Template->assign('navi_top', $AVE_Template->fetch('navi/navi_top.tpl')); + $AVE_Template->assign('content', $AVE_Template->fetch('start.tpl')); +?> \ No newline at end of file diff --git a/admin/sysblocks.php b/admin/sysblocks.php new file mode 100644 index 0000000..487ae3e --- /dev/null +++ b/admin/sysblocks.php @@ -0,0 +1,117 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/sysblocks.txt', 'sysblocks'); + + switch ($_REQUEST['action']) + { + // Список системных блоков + case '': + if (check_permission_acp('sysblocks_view')) + { + Sysblocks::startPage(); + } + break; + + // Список групп системных блоков + case 'groups': + if (check_permission_acp('sysblocks_view')) + { + Sysblocks::listGroups(); + } + break; + + // Сортировка списока групп + case 'groupssort': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::groupsSort(); + } + break; + + // Новая группа + case 'newgroup': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::newGroup(); + } + break; + + // Удаление группы + case 'delgroup': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::delGroup(); + } + break; + + // Создать новый системный блок + case 'new': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::newBlock(); + } + break; + + // Редактировать системный блок + case 'edit': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::editBlock(); + } + break; + + // Сохранить системный блок + case 'save': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::saveBlock(); + } + break; + + // Удалить системный блок + case 'del': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::delBlock(); + } + break; + + // Проверка алиаса + case 'alias': + if (check_permission_acp('sysblocks_edit')) + { + echo Sysblocks::aliasValidate($_REQUEST['alias'], (int)$_REQUEST['id']); + } + exit; + + // Копирование системного блока + case 'multi': + if (check_permission_acp('sysblocks_edit')) + { + Sysblocks::multiBlock(); + } + } +?> \ No newline at end of file diff --git a/admin/templates.php b/admin/templates.php new file mode 100644 index 0000000..0c47bf6 --- /dev/null +++ b/admin/templates.php @@ -0,0 +1,91 @@ +config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/templates.txt'); + + switch ($_REQUEST['action']) + { + case '': + if (check_permission_acp('template_view')) + { + AVE_Templates::templatesList(); + } + break; + + + case 'new': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesNew(); + } + break; + + + case 'edit': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesEdit(); + } + break; + + + case 'save': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesSave(); + } + break; + + + case 'delete': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesDelete(); + } + break; + + + case 'multi': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesMulti(); + } + break; + + + case 'edit_css': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesEditCss(); + } + break; + + case 'edit_js': + if (check_permission_acp('template_edit')) + { + AVE_Templates::templatesEditJs(); + } + break; + } +?> \ No newline at end of file diff --git a/admin/templates/blocks/form.tpl b/admin/templates/blocks/form.tpl new file mode 100644 index 0000000..7f88d5e --- /dev/null +++ b/admin/templates/blocks/form.tpl @@ -0,0 +1,203 @@ + + +
+
{#BLOCK_INSERT_H#}
+
+ +
+
{#BLOCK_INSERT#}
+
+ + + +
+
+
+
{if $smarty.request.id != ''}{#BLOCK_EDIT_H#}{else}{#BLOCK_INSERT_H#}{/if}
+
+ + + + + + + + + + + + + + + + + +
{#BLOCK_NAME#} +
+ +
+
{#BLOCK_DESCRIPTION#} + +
+
+ [?] {#BLOCK_ALIAS#}: +
+
+
+   + + + + +
+
+
+
+
+
{#BLOCK_HTML#}
+
+ + + + + + +
+ {$block_text} +
+ +
+
+ {if $smarty.request.id != ''} + + + {else} + + {/if} + + {if $smarty.request.action == 'edit'} + + {/if} +
+
+ +
+
+{literal} + +{/literal} + +{if $smarty.request.action != 'new'} + +{/if} \ No newline at end of file diff --git a/admin/templates/blocks/list.tpl b/admin/templates/blocks/list.tpl new file mode 100644 index 0000000..b4a9a11 --- /dev/null +++ b/admin/templates/blocks/list.tpl @@ -0,0 +1,231 @@ + + +
+
{#BLOCK_EDIT#}
+
+ +
+
+ {#BLOCK_EDIT_TIP#} +
+
+ + + + +
+ + +
+
+ + + + + + + + + + + + + {if $vis_blocks} + + + + + + + + {if check_permission('blocks_edit')}{/if} + + + + + {foreach from=$vis_blocks item=block} + + + + + + + + + + + + {if check_permission('blocks_edit')} + + + + + + {/if} + + {/foreach} + {else} + + + + {/if} + +
{#BLOCK_ID#}{#BLOCK_NAME#}{#BLOCK_AUTHOR#}{#BLOCK_DATE#}{#BLOCK_TAG#}{#BLOCK_ACTIONS#}
{$block->id} + {if check_permission('blocks_edit')} + + {$block->block_name|escape} + + {if $block->block_description} +
{$block->block_description|escape} + {/if} + {else} + {$block->block_name|escape} + {/if} +
{$block->block_author_id|escape} + {$block->block_created|date_format:$TIME_FORMAT|pretty_date} + +
+ + + + +
+
+ + + + + +
+
    +
  • {#BLOCK_NO_ITEMS#}
  • +
+
+
+ {if check_permission('blocks_edit')} + + {/if} +
+
+
+ +{literal} + +{/literal} \ No newline at end of file diff --git a/admin/templates/blocks/multi.tpl b/admin/templates/blocks/multi.tpl new file mode 100644 index 0000000..01755ff --- /dev/null +++ b/admin/templates/blocks/multi.tpl @@ -0,0 +1,37 @@ +
{#BLOCK_COPY_TITLE#}
+ +
+
+ {#BLOCK_COPY_TIP2#} +
+
+ + + + {foreach from=$errors item=e} + {assign var=message value=$e} +
    +
  • Ошибка: {$message}
  • +
+ {/foreach} + +
+
{#BLOCK_COPY_TITLE#}
+
+
+ + +
 
+
+ +
+
+
diff --git a/admin/templates/blocks/nav.tpl b/admin/templates/blocks/nav.tpl new file mode 100644 index 0000000..3461178 --- /dev/null +++ b/admin/templates/blocks/nav.tpl @@ -0,0 +1 @@ +
  • {#MAIN_BLOCKS#}
  • \ No newline at end of file diff --git a/admin/templates/browser/browser.tpl b/admin/templates/browser/browser.tpl new file mode 100644 index 0000000..63d8c35 --- /dev/null +++ b/admin/templates/browser/browser.tpl @@ -0,0 +1,187 @@ + + + + + + + + {#MAIN_PAGE_TITLE#} - {*#SUB_TITLE#*} ({$smarty.session.user_name|escape}) + + + + + + + + + + + + + + + {include file="../scripts.tpl"} + + + + + + + + + + +
    + + {if $dir != '/'} +
    +
    +
    + +
    +
    + {/if} + + {foreach from=$dirs item=dir_link key=dir_name} +
    +
    +
    +
    {$dir_name}
    +
    +
    + {/foreach} + + {if $smarty.request.type != 'directory'}{/if} + {foreach from=$files item=file key=file_name} +
    +
    +
    + {if !$recycled} + {if check_permission('mediapool_del')} +
    + +
    + {/if} + {/if} + +
    {$file_name|truncate:20}
    + +
    + {if $recycled} + + {else} +
    + {/if} +
    + +
    {$file.filesize} Кб
    + +
    {$file.moddate}
    + +
    +
    + {/foreach} + +
    + + + + + + + + + \ No newline at end of file diff --git a/admin/templates/browser/browser_2frames.tpl b/admin/templates/browser/browser_2frames.tpl new file mode 100644 index 0000000..42e717b --- /dev/null +++ b/admin/templates/browser/browser_2frames.tpl @@ -0,0 +1,247 @@ + + + + + + + + {#MAIN_PAGE_TITLE#} - {*#SUB_TITLE#*} ({$smarty.session.user_name|escape}) + + + + + + + + + + + + + + + {include file="../scripts.tpl"} + + + + + + + + + + + + + + + +
    + +
    + +
    +
    {#MAIN_FILE_MANAGER_TITLE#}
    +
    +
    + {#MAIN_FILE_MANAGER_TIP#} +
    +
    + +
    +
    + + + + + {if check_permission('mediapool_add')} + + {/if} + + + + +
    + +
    + +
    + + {if $smarty.request.type!=''} + + +
    + +
    + + {/if} +
    +
    +
    +   + + {#MAIN_MP_UPLOAD_FILE#} +
    + +
    +
    +
    + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/admin/templates/browser/browser_upload.tpl b/admin/templates/browser/browser_upload.tpl new file mode 100644 index 0000000..309449e --- /dev/null +++ b/admin/templates/browser/browser_upload.tpl @@ -0,0 +1,69 @@ + + + +
    +
    +
    + + +
    +
    +
    {#MAIN_MP_SELECT_FILES#}
    +
    +
    +

    You browser doesn't have Flash, Silverlight, Gears, BrowserPlus or HTML5 support.

    +
    +
    + +
    + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/admin/templates/browser/onlycontent.tpl b/admin/templates/browser/onlycontent.tpl new file mode 100644 index 0000000..ce0fc1b --- /dev/null +++ b/admin/templates/browser/onlycontent.tpl @@ -0,0 +1 @@ +{$content} \ No newline at end of file diff --git a/admin/templates/css/browser.css b/admin/templates/css/browser.css new file mode 100644 index 0000000..60839f2 --- /dev/null +++ b/admin/templates/css/browser.css @@ -0,0 +1,99 @@ +/*-------------------- FileManager -------------------------*/ +#files {} + +.imageBlock0 { + float:left; + padding:0; + margin:5px; + width:200px; + height:200px; + margin:3px; + background-color:#fcfcfc; + border: solid 1px #eaeaea; + -moz-border-radius:5px; + -webkit-border-radius:5px; + position:relative; + cursor: pointer; +} +.imageBlock1 { + font-size: 11px; +} +.imageBlock { + margin:36px auto 0 auto; + width: 128px; + height: 128px; + vertical-align: middle; +} +.imageBlock div { + text-align:center; /* horizontal in all browsers */ + display:table-cell; vertical-align:middle; /* ~= valign=center in CSS2 browsers */ + height: 128px; + width: 128px; +} + +.imageBlock img { + vertical-align: middle; +} + +.imageName { + padding:2px; + font-weight:bold; + font-family:Tahoma, Verdana, Arial, Geneva; + font-size: 10px; + line-height: 14px; +} + +.imageBlockHover { + background-color:#eff8fd; + border: solid 1px #d8f0fa; + -moz-border-radius:5px; -webkit-border-radius:5px; +} + +.imageBlockAct { + background-color:#def1fb; + border: solid 1px #b3e4f9; + -moz-border-radius:5px; -webkit-border-radius:5px; +} + +.imageBlockActHover { + background-color:#d5effc; + border: solid 1px #a7e0f8; + -moz-border-radius:5px; -webkit-border-radius:5px; +} + +.mb_name { + position:absolute; + color:#516E48; + top: 5px; + left: 25px; + font-weight:bold; + display:inline; + font-size: 10px; + line-height: 14px; +} +.mb_icon_file { + position:absolute; + top: 5px; + left: 5px; + display:inline; +} +.mb_icon_delete { + position:absolute; + top: 5px; + right: 5px; + display:inline; +} + +a img { + border:0; +} + +.mb_time { + color:#7e7e7e; + font-style:italic; + text-align:center; + font-size: 10px; + line-height: 14px; +} + +.tipsy-inner { padding: 8px 14px 8px 14px; background-color: black; color: white; max-width: 150px; line-height: 14px; } \ No newline at end of file diff --git a/admin/templates/css/color_default.css b/admin/templates/css/color_default.css new file mode 100644 index 0000000..95054a2 --- /dev/null +++ b/admin/templates/css/color_default.css @@ -0,0 +1,1193 @@ +/* ========== General styles ========== */ +body { + background:#f2f4f8; +} + +.wrapper { + margin:0 35px; + clear:both; +} + +.img { + border:1px solid #d5d5d5; +} + +a { + color:#177bbb; +} + +a:hover { + color:#245269; +} + +/* ===== Top navigation ===== */ +.fixed { + background:#12131a; + color:#fff; +} + +/* ===== Top navigation ===== */ +.userNav .lastNav { + width:2px; + height:36px; + background:#12131a; + position:absolute; + top:0; + right:0; +} + +.userNav ul li ul { + border:none; +} + +.userNav ul li span { + padding:10px 12px 8px 8px; +} + +.userNav ul li ul li:hover,.userNav ul li ul li a.active { + background:#177bbb; + color:#fff; +} + +.userNav ul li.dropdown > a { + height:35px; +} + +/* ===== Left navigation ===== */ +.leftNav { + width:180px; + max-width:36%; + margin-top:-1px; + float:left; + margin-bottom:80px; + margin-right:21px; +} + +.leftNav ul li a { + color:#fafafa; + font-size:13px; + display:block; + background:#373840; + margin-top:1px; + text-decoration:none; + border:0; + transition:all 100ms ease-in-out; + -webkit-transition:all 100ms ease-in-out; + -moz-transition:all 100ms ease-in-out; + -o-transition:all 100ms ease-in-out; +} + +.leftNav ul li a:hover { + background:#12131a; + border:0; +} + +.leftNav ul li a.active { + background:#177bbb; + border:0; +} + +#leftNav_show { + position:fixed; + left:0; + top:55px; + width:30px; + height:33px; + background:url(theme_color_default/left-menu-show.png) right top no-repeat; +} + +#leftNav_show #toggle-LeftMenu span { + background-image:url(theme_color_default/left-menu-show.png); +} + +/* ===== navigation subnav ===== */ +ul.sub { + border:none; +} + +ul.sub li { + padding:1px; + margin:1px 0 0; + background:#fff url(../images/leftNavSub.png) repeat; +} + +ul.sub li.active { + border:1px solid #d9dee9; + background:#f1f4f8; +} + +ul.sub li.active a { + color:#484848; +} + +ul.sub li a { + background:url(../images/arrow.gif) no-repeat 7px 11px; + border:none; + color:#ccc; + font-size:11px; +} + +ul.sub li a:hover,.sub li a:active { + font-style:normal; + border:none; + color:#484848; + background:url(../images/arrow.gif) no-repeat 7px 11px; +} + +/* ========== Left navigation subnav + docs ========== */ +ul.sub li a.numberRight { + margin:0; + position:absolute; + top:7px; + right:10px; + float:none; + background:#177bbb; + padding:3px!important; + z-index:100; +} + +ul.sub li a.numberRight:hover { + background-position:0 -42px; +} + +/* ===== Right side content ===== */ +.widget { + margin-top:20px; + border:1px solid #cbd5dd; + display:block; + background:#fff; + clear:both; + -webkit-box-shadow:0 1px 1px rgba(0,0,0,.05); + box-shadow:0 1px 1px rgba(0,0,0,.05); + border-radius:3px; +} + +.widgetS { + margin-top:20px; + border:1px solid #cbd5dd; + display:block; + background:#fff; + border-top:none; + min-width:25%; + float:left; + margin-right:40px; + -webkit-box-shadow:0 1px 1px rgba(0,0,0,.05); + box-shadow:0 1px 1px rgba(0,0,0,.05); +} + +.widgets .left { + float:left; + width:49%; + margin-right:2%; +} + +.widgets .right { + float:right; + width:49%; +} + +.title .num a.basicNum { + background:#177bbb; + border:1px solid #177bbb; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.title .num a.basicNum:hover { + background:#146ca4; + border:1px solid #146ca4; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.basicNum { + background:#177bbb; + border:1px solid #177bbb; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.basicNum:hover { + background:#146ca4; + border:1px solid #146ca4; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.basicNum:active { + background:#146ca4; + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.widget .num a.greenNum { + background:#1aae88; + border:1px solid #1aae88; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.greenNum:hover { + background:#179877; + border:1px solid #179877; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.greenNum:active { + background:#179877; + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.widget .num a.redNum { + background:#e33244; + border:1px solid #e33244; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.redNum:hover { + background:#dd1e32; + border:1px solid #dd1e32; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.widget .num a.redNum:active { + background:#dd1e32; + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.widget .num { + margin:8px 12px 0 0; +} + +.head { + background:#373840; + height:32px; + border-top:none; + border-bottom:none; + position:relative; + color:#fff; + border-top:none; + border-radius:3px; +} + +/* ========== buttons ========== */ +a.button,span.button { + padding:4px 7px; +} + +.basicBtn { + background:#177bbb; + border:1px solid #177bbb; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.basicBtn:hover { + background:#146ca4; + border:1px solid #146ca4; + color:#fff; +} + +.basicBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.blackBtn { + background:#242E42; + border:1px solid #242E42; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.blackBtn:hover { + background:#07090d; + border:1px solid #07090d; + color:#fff; +} + +.blackBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.greenBtn { + background:#1aae88; + border:1px solid #1aae88; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.greenBtn:hover { + background:#179877; + border:1px solid #179877; + color:#fff; +} + +.greenBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.redBtn { + background:#e33244; + border:1px solid #e33244; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.redBtn:hover { + background:#dd1e32; + border:1px solid #dd1e32; + color:#fff; +} + +.redBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.blueBtn { + background:#177bbb; + border:1px solid #177bbb; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.blueBtn:hover { + background:#146ca4; + border:1px solid #146ca4; + color:#fff; +} + +.blueBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.whiteBtn { + background:#fcfcfd; + border:1px solid #d2dae1; + color:#8c91b7; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.whiteBtn:hover { + background:#ebeef4; + border:1px solid #8c91b7; + color:#8c91b7; +} + +.whiteBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#8c91b7; +} + +.greyishBtn { + background:#6F7883; + border:1px solid #6F7883; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.greyishBtn:hover { + background:#5F6A76; + border:1px solid #5F6A76; + color:#fff; +} + +.greyishBtn:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#8c91b7; +} + +/* ===== Table ===== */ +.tableStatic thead td { + padding:3px 0; + text-align:center; + border-left:1px solid #C7D6E6; + border-top:1px solid #C7D6E6; + background:#D5E0EC; + border-bottom:none; + font-size:11px; + font-weight:100; + color:#373840; + vertical-align:middle; + line-height:16px; +} + +.tableStatic thead td:first-child { + border-left:none; +} + +.tableStatic thead td a { + color:#6086AB; +} + +.tableStatic thead td img { + vertical-align:middle; + margin:0 5px; +} + +.tableStatic tbody tr { + border-top:1px solid #d9dee9; + background:#fff; +} + +.tableStatic tbody tr:nth-child(even) { + background:#EDF2F7; +} + +.tableStatic tbody tr:hover { + background:#E3EBF2; +} + +.tableStatic tbody td { + border-left:1px solid #d9dee9; + padding:6px 10px; + vertical-align:middle; +} + +.tableStatic tbody td.actions a { + border:1px solid #d9dee9; + background:#fff; + padding:0; +} + +.tableStatic tbody td.actions a:hover { + border:1px solid #d9dee9; + background:#f9fafc; + padding:0; +} + +.tableStatic tbody tr.header,.tableStatic tbody tr.header:hover { + font-weight:700!important; + background:#373840!important; + color:#fff!important; +} + +/* ========== Pagination ========== */ +.pagination { + margin:auto; + width:auto; + text-align:center; + margin-top:40px; +} + +.pages { +} + +.pages li.prev { + margin-right:15px; +} + +.pages li.next { + margin-left:15px; +} + +.pages li { + display:inline; + margin:0 2px; +} + +.pages li a { + height:25px; + padding:4px 8px; + text-decoration:none; + color:#898fb3; + font-weight:700; + background:#fcfcfd; + border:1px solid #d2dae1; + font-size:11px; +} + +.pages li a:hover { + background:#ebeef4; +} + +.pages li span.active { + background:#ebeef4; + font-size:11px; + color:#898fb3; + border:1px solid #d2dae1; +} + +.pages li .active { + background:#ebeef4; + color:#898fb3; + border-color:#d2dae1; + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); +} + +.pages li .active:hover { + background:#d2dae1; +} + +/* ========== Numbers notifications ========== */ +.numberTop,.numberMiddle,.numberLeft,a.numberLeft { + text-align:center; + display:inline-block; + padding:1px 5px; + color:#fff; + float:right; + margin:10px 15px 10px -5px; + font-size:11px; + line-height:14px; + -moz-border-radius:3px; + -webkit-border-radius:3px; + -khtml-border-radius:3px; + border-radius:3px; +} + +.content .title { + background:#373840; + height:36px; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; +} + +.content .title h5 { + float:left; + color:#fafafa; + font-weight:400; + display:block; + padding:0 0 0 15px; + line-height:36px; +} + +/* ===== PopUp ===== */ +#popup_container { + min-width:300px; + max-width:600px; + background:url(theme_color_default/alert-opacity-overlay.png) repeat; + -moz-border-radius:5px; + -webkit-border-radius:5px; + border-radius:5px; + -moz-box-shadow:0 0 5px #000; + -webkit-box-shadow:0 0 5px #000; + box-shadow:0 0 5px #000; +} + +#popup_title { + text-align:center; + background:#373840; + border-bottom:1px solid #d5d5d5; + cursor:default; + height:32px; + line-height:32px; + color:#fff; +} + +#popup_content { + background:#fafafa; + padding:1em 1.75em; + margin:0; +} + +#popup_message { + text-align:center; +} + +#popup_panel { + text-align:center; + margin:1em 0 0; +} + +#popup_message input[type=text] { + background:#fcfcfc; + border:1px solid #e1e6ef; + padding:5px; + width:258px; +} + +#popup_prompt { + margin:.5em 0; +} + +.breadCrumbHolder.module { + border:solid 1px #e1e6ef; + background:#fff; + margin-top:20px; + -webkit-box-shadow:0 1px 1px rgba(0,0,0,.05); + box-shadow:0 1px 1px rgba(0,0,0,.05); +} + +/* Selects */ +.jqTransformSelectWrapper ul a.selected { + background:#177bbb; + color:#fff; +} + +/* ===== Growl notifications ===== */ +div.jGrowl div.jGrowl-notification,div.jGrowl div.jGrowl-closer { + background-color:#177bbb; +} + +/* ===== Tabs ===== */ +ul.tabs { + background:#373840; + height:32px; + border-bottom:none; + border-top:none; +} + +ul.tabs li { + float:left; + height:32px; + line-height:32px; + border-left:none; + overflow:hidden; + position:relative; + background:none; + font-size:15px; +} + +ul.tabs li a { + text-decoration:none; + display:block; + padding:0 12px; + outline:none; + color:#797979; +} + +ul.tabs li a:hover { + color:#fff; +} + +html ul.tabs li.activeTab { + height:32px; +} + +.tabsRight { + position:relative; +} + +.tabsRight ul.tabs { + float:right; + background:#373840; + height:38px; + border-bottom:1px solid #595959; + position:absolute; + top:0; + right:0; +} + +ul.inact_tabs { + background:#373840; + height:32px; + border-bottom:none; + border-top:none; +} + +ul.inact_tabs li { + float:left; + height:32px; + line-height:32px; + border-left:none; + overflow:hidden; + position:relative; + background:none; + font-size:15px; +} + +ul.inact_tabs li a { + text-decoration:none; + display:block; + padding:0 12px; + outline:none; + color:#797979; +} + +ul.inact_tabs li a:hover { + color:#fff; +} + +html ul.inact_tabs li.activeTab { + background-color:#fafafa; + height:32px; +} + +html ul.inact_tabs li.activeTab a { + color:#373840; +} + +.rowElem:hover { + background:url(../images/backgrounds/grey.png) repeat scroll 0 0 #e9edf4; +} + +.formRight { + margin:12px 12px 12px 2%; +} + +.docaction .actions a { + background:#177bbb; +} + +.mainForm input[type=text],.mainForm input[type=password],.mainForm textarea { + font-size:11px; + background:#FFF; + border:1px solid #d9dee9; + color:#656565; + width:100%; + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + padding:4px 6px; + display:table-cell; +} + +.mainForm input[type=text]:hover,.mainForm input[type=password]:hover,.mainForm textarea:hover { + border-color:#afbcd4; +} + +.mainForm input[type=text]:focus,.mainForm input[type=password]:focus,.mainForm textarea:focus { + background:#fff; + border-color:#afbcd4; +} + +.mainForm input[readonly],.mainForm input[disabled] { + background:#f5f5f5; + border:1px solid #dadada; + color:#aaa; +} + +.mainForm input[readonly]:hover,.mainForm input[disabled]:hover { + background:#f5f5f5; + border:1px solid #aaa; + color:#656565; +} + +.mainForm input[readonly]:focus,.mainForm input[disabled]:focus { + background:#f5f5f5; + border:1px solid #aaa; + color:#656565; +} + +.mainForm .select, .mainForm select { + font-size:11px; + background:#fff; + border:1px solid #d9dee9; + width:100%; + font-family: Arial,Helvetica,sans-serif; + color:#656565; + padding: 3px 5px; +} + +.mainForm .select:hover, .mainForm select:hover { + border:1px solid #afbcd4; +} + +.mainForm .select option, .mainForm select option { + font-size:11px; + padding: 3px 5px; +} + + +div.jGrowl div.error { + background-color:red; +} + +div.jGrowl div.accept { + background-color:#0c0; +} + +/* ===== Page scrolling ===== */ +#toTop { + background:#177bbb url(theme_color_default/ui-to-top.png) no-repeat left top; + border-radius:3px; +} + +#toTopHover { + background:#177bbb url(theme_color_default/ui-to-top.png) no-repeat left -22px; +} + +/* ========== CMS Stats ========== */ +.cmsStats { + color:#177bbb; + border:1px solid #c9f7f8; + background:#edfcfd; +} + +.cmsStatsAlert { + color:red; + border:1px solid red; + background:#ffb9b9; +} + +/* ===== Messages page ===== */ +.messagesOne .by_user .messageArea { + background:#f7fdfd; + border-color:#c9f7f8; + margin-left:60px; +} + +.by_user .name > strong { + color:#177bbb; +} + +.messagesOne .by_user .aro { + background:url(theme_color_default/message-arrow-left.png) no-repeat; + left:-8px; +} + +.code { + background-color:#e0e6f0; + box-sizing:border-box; + border:1px solid #d9dee9; + color:#177bbb!important; + padding:3px 5px; + border-radius:3px; + -moz-border-radius:3px; + -webkit-border-radius:3px; +} + +.code > a { + color:#177bbb!important; +} + +.code.green { + background-color:#1aae88; + + border:1px solid #199875; + color:#fff!important; +} + +.code.green > a { + color:#fff!important; +} + + +.code.red { + background-color:#dd1e32; + + border:1px solid #ce1e31; + color:#fff!important; +} + +.code.red > a { + color:#fff!important; +} + + +.code.yellow { + background-color: #dda70e; + + border:1px solid #db9a01; + color:#fff!important; +} + +.code.yellow > a { + color:#fff!important; +} + +.docaction .code { + background-color:#f2f4f8; + color:#7f88b4!important; + padding:0 5px; + border-radius:3px; + -moz-border-radius:3px; + -webkit-border-radius:3px; +} + +.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active { + background:#177bbb; + font-weight:400; + color:#fff; +} + +.ui-datepicker .ui-datepicker-header { + position:relative; + padding:.2em 0; + background:#177bbb; +} + +.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus { + background:#177bbb; + font-weight:400; + color:#fff; +} + +.ui-state-hover a,.ui-state-hover a:hover { + color:#797979; + text-decoration:none; +} + +.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active { + background:#177bbb; + font-weight:400; + color:#fff; +} + +.ac_results { + padding:0; + border:none; + background-color:#fff; + overflow:hidden; + z-index:99999; +} + +.ac_odd { + background-color:#edfcfd; +} + +.ac_over { + background-color:#e1e6ef; + color:#484848; +} + +.ac_results li { + border:1px solid #e1e6ef; + border-top:none; +} + +.ac_results li strong { + border-bottom:1px dotted; + background-color:#e1e6ef; +} + +.jq-selectbox__select { + overflow:hidden; + height:20px; + border-radius:0; + background-color:#fff; + background-clip:padding-box; + border:1px solid #d9dee9; + -webkit-box-shadow:none; + -moz-box-shadow:none; + box-shadow:none; + color:#444; + text-decoration:none; + white-space:nowrap; + font-size:11px; + line-height:20px; + padding:0 20px 0 10px; +} + +.jq-selectbox__select:hover { + border:1px solid #afbcd4; +} + +.jq-selectbox li:hover { + background:#177bbb; + color:#fff; +} + +/* ===== UI ===== */ +.ui-dialog .ui-dialog-titlebar { + position:relative; + background:#12131a; + border:none; + border-bottom:0; + height:32px; + color:#fafafa; +} + +.ui-widget .title { + background:#373840; + height:32px; + -moz-box-shadow:0 1px 0 #fff; + -webkit-box-shadow:0 1px 0 #fff; + box-shadow:0 1px 0 #fff; +} + +.ui-widget .title h5 { + float:left; + color:#fafafa; + font-weight:400; + display:block; + line-height:32px; + padding:0 0 0 15px; +} + +.ui-widget-header .ui-icon { + background-image:url(../images/jquery_ui/ui-icons_ffffff_256x240.png); +} + +.ui-state-hover .ui-icon,.ui-state-focus .ui-icon { + background-image:url(../images/jquery_ui/ui-icons_888888_256x240.png); +} + +.ui-datepicker .ui-datepicker-title { + margin:0 2.3em; + line-height:1.8em; + text-align:center; + color:#fff; +} + +/* ===== PLUPLOAD ===== */ +.plupload_button { + font-size:10px; + font-weight:700; + text-transform:uppercase; + color:#fff; + line-height:10px; + margin-top:3px; +} + +.plupload_add { + margin-right:10px; + float:left; + background:#177bbb; + border:1px solid #177bbb; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.plupload_add:hover { + background:#146ca4; + border:1px solid #146ca4; + color:#fff; +} + +.plupload_add:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.plupload_disabled,a.plupload_disabled:hover { + background:#f5f5f5!important; + border:1px solid #dadada!important; + color:#aaa!important; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.plupload_start { + background:#1aae88; + border:1px solid #1aae88; + color:#fff; + -moz-box-shadow:none; + -webkit-box-shadow:none; + box-shadow:none; + border-radius:3px; +} + +.plupload_start:hover { + background:#179877; + border:1px solid #179877; + color:#fff; +} + +.plupload_start:active { + -webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + box-shadow:inset 0 3px 5px rgba(0,0,0,.125); + color:#fff; +} + +.CodeMirror { + font-family:'Consolas','Inconsolas',monospace,Arial!important; + font-size:12px!important; +} + +a.jqTransformCheckbox { + background:transparent url(theme_color_default/checkbox.png) no-repeat 0 0; +} + +a.jqTransformChecked { + background-position:0 bottom; +} + +a.jqTransformCheckedDisable { + background:transparent url(theme_color_default/checkbox2.png) no-repeat 0 0; +} + +a.jqTransformCheckedDisableCheck { + background:transparent url(theme_color_default/checkbox2.png) no-repeat; + background-position:center bottom; +} + +.jqTransformRadio { + background:transparent url(theme_color_default/radio.png) no-repeat 0 1px; + vertical-align:middle; + height:16px; + width:16px; + display:block; +} + +.input-error { + border-color:red!important; +} + +.input-accept { + border-color:#0c0!important; +} + +.ajax-dialog { + background:#f2f4f8!important; +} + +#popup_alert_overlay,.ui-widget-overlay { + background:url(../images/jquery_ui/ui-bg_diagonals-thick_20_666666_40x40.png)!important; +} + +#footer { + background:#12131a; +} + +#fancybox-content { + background:url(theme_color_default/fancy.png); +} + +.cascad_item .image { + background:transparent url(theme_color_default/field.png); +} diff --git a/admin/templates/css/data_table.css b/admin/templates/css/data_table.css new file mode 100644 index 0000000..88dcf61 --- /dev/null +++ b/admin/templates/css/data_table.css @@ -0,0 +1,155 @@ +/* ===== Dynamic tables ===== */ + +.paging_two_button .ui-button { float: left; cursor: pointer; * cursor: hand; } +.paging_full_numbers .ui-button { padding: 2px 6px; /*margin: 0;*/ cursor: pointer; * cursor: hand; } +.dataTables_paginate .ui-button { margin-right: -0.1em !important; } +.dataTables_wrapper .ui-toolbar { padding: 5px; } + +.dataTables_paginate { width: auto; } +.dataTables_info { padding: 7px 0 0 80px; color: #878787; } + +table.display thead th { padding: 4px 0px 3px 10px; cursor: pointer; * cursor: hand; font-size: 11px; background: #efefef url(../images/NavBg.png) repeat-x; } + +div.dataTables_wrapper .ui-widget-header { font-weight: normal; background: #efefef url(../images/NavBg.png) repeat-x; border-top: 1px solid #D5D5D5; margin-top: -1px; border-right: none; } + + +table.display thead th div.DataTables_sort_wrapper { position: relative; padding-right: 20px; color: #878787; } +table.display thead th div.DataTables_sort_wrapper span { position: absolute; top: 50%; margin-top: -8px; right: 5px; } + + +/* ===== Datatable styles ===== */ + +.dataTables_wrapper { position: relative; _height: 302px; clear: both; } +.dataTables_processing { position: absolute; top: 0px; left: 50%; width: 250px; margin-left: -125px; border: 1px solid #ddd; text-align: center; color: #999; font-size: 11px; padding: 2px 0; } +.dataTables_length { float: left; color: #878787; margin: 7px 5px 0 5px; } +.dataTables_length label { padding-top: 10px; font-size: 11px; } +.dataTables_length select { font-size: 11px; margin: 0 5px; } +.dataTables_filter { text-align: left; margin: 6px 8px 2px 10px; position: absolute; right: 0; top: -34px; color: #878787; font-size: 11px; } +.dataTables_filter input[type="text"] { padding: 3px 5px; border: 1px solid #D5D5D5; width: 200px; position: relative; margin-left: 6px; -moz-border-radius: 2px; -webkit-border-radius: 2px; -khtml-border-radius: 2px; border-radius: 2px; color: #878787; } +.dataTables_filter .srch { position: absolute; right: 6px; top: 7px; background: url(../images/searchSmall.png) no-repeat 0 0; border: none; width: 9px; height: 9px; } +.dataTables_info { float: left; } +.dataTables_paginate { text-align: right; margin: 6px; } + + +/* Pagination nested */ +.paginate_disabled_previous, .paginate_enabled_previous, .paginate_disabled_next, .paginate_enabled_next { height: 19px; width: 19px; margin-left: 3px; float: left; } +.paginate_disabled_previous { background-image: url(../images/back_disabled.jpg); } +.paginate_enabled_previous { background-image: url(../images/back_enabled.jpg); } +.paginate_disabled_next { background-image: url(../images/forward_disabled.jpg); } +.paginate_enabled_next { background-image: url(../images/forward_enabled.jpg); } + + +/* DataTables display */ +table.display { margin: 0 auto; width: 100%; clear: both; border-collapse: collapse; } +table.display tfoot th { padding: 3px 0px 3px 10px; font-weight: bold; font-weight: normal; } +table.display tr.heading2 td { border-bottom: 1px solid #aaa; } +table.display td { padding: 8px 10px; } +table.display td.center { text-align: center; } + + +/* DataTables sorting */ +.sorting_asc { background: url(../images/sort_asc.png) no-repeat center right; } +.sorting_desc { background: url(../images/sort_desc.png) no-repeat center right; } +.sorting { background: url(../images/sort_both.png) no-repeat center right; } +.sorting_asc_disabled { background: url(../images/sort_asc_disabled.png) no-repeat center right; } +.sorting_desc_disabled { background: url(../images/sort_desc_disabled.png) no-repeat center right; } + + +/* DataTables row classes*/ +table.display tr.odd.gradeA { background-color: #ddffdd; } +table.display tr.even.gradeA { background-color: #eeffee; } +table.display tr { border-bottom: 1px solid #D5D5D5; } +table.display td { border-left: 1px solid #D5D5D5; vertical-align: middle; } +table.display td:first-child { border-left: none; } +table.display tr.odd.gradeA { background-color: #fafafa; } +table.display tr.even.gradeA { background-color: #f5f5f5; } +table.display tr.odd.gradeC { background-color: #ddddff; } +table.display tr.even.gradeC { background-color: #eeeeff; } +table.display tr.odd.gradeX { background-color: #ffdddd; } +table.display tr.even.gradeX { background-color: #ffeeee; } +table.display tr.odd.gradeU { background-color: #ddd; } +table.display tr.even.gradeU { background-color: #eee; } + +tr.odd { background-color: #E2E4FF; } +tr.even { background-color: white; } + + +/* Misc */ +.dataTables_scroll { clear: both; } +.top, .bottom { padding: 15px; background-color: #F5F5F5; border: 1px solid #CCCCCC; } +.top .dataTables_info { float: none; } +.clear { clear: both; } +.dataTables_empty { text-align: center; } + +tfoot input { margin: 0.5em 0; width: 100%; color: #444; } +tfoot input.search_init { color: #999; } + +td.group { background-color: #d1cfd0; border-bottom: 2px solid #A19B9E; border-top: 2px solid #A19B9E; } +td.details { background-color: #d1cfd0; border: 2px solid #A19B9E; } + +.example_alt_pagination div.dataTables_info { width: 40%; } +.paging_full_numbers span.paginate_button, .paging_full_numbers span.paginate_active { border: 1px solid #aaa; -webkit-border-radius: 5px; -moz-border-radius: 5px; padding: 2px 5px; margin: 0 3px; cursor: pointer; *cursor: hand; } +.paging_full_numbers span.paginate_button { background-color: #ddd; } +.paging_full_numbers span.paginate_button:hover { background-color: #ccc; } +.paging_full_numbers span.paginate_active { background-color: #99B3FF; } + +table.display tr.even.row_selected td { background-color: #B0BED9; } +table.display tr.odd.row_selected td { background-color: #9FAFD1; } + + +/* Sorting classes for columns. For the standard odd/even */ +tr.odd td.sorting_1 { background-color: #D3D6FF; } +tr.odd td.sorting_2 { background-color: #DADCFF; } +tr.odd td.sorting_3 { background-color: #E0E2FF; } + +tr.even td.sorting_1 { background-color: #EAEBFF; } +tr.even td.sorting_2 { background-color: #F2F3FF; } +tr.even td.sorting_3 { background-color: #F9F9FF; } + + +/* For the Conditional-CSS grading rows */ +/* + Colour calculations (based off the main row colours) + Level 1: + dd > c4 + ee > d5 + Level 2: + dd > d1 + ee > e2 + */ +tr.odd.gradeA td.sorting_1 { background-color: #f4f4f4; } +tr.odd.gradeA td.sorting_2 { background-color: #d1ffd1; } +tr.odd.gradeA td.sorting_3 { background-color: #d1ffd1; } + +tr.even.gradeA td.sorting_1 { background-color: #efefef; } +tr.even.gradeA td.sorting_2 { background-color: #e2ffe2; } +tr.even.gradeA td.sorting_3 { background-color: #e2ffe2; } + +tr.odd.gradeC td.sorting_1 { background-color: #c4c4ff; } +tr.odd.gradeC td.sorting_2 { background-color: #d1d1ff; } +tr.odd.gradeC td.sorting_3 { background-color: #d1d1ff; } + +tr.even.gradeC td.sorting_1 { background-color: #d5d5ff; } +tr.even.gradeC td.sorting_2 { background-color: #e2e2ff; } +tr.even.gradeC td.sorting_3 { background-color: #e2e2ff; } + +tr.odd.gradeX td.sorting_1 { background-color: #ffc4c4; } +tr.odd.gradeX td.sorting_2 { background-color: #ffd1d1; } +tr.odd.gradeX td.sorting_3 { background-color: #ffd1d1; } + +tr.even.gradeX td.sorting_1 { background-color: #ffd5d5; } +tr.even.gradeX td.sorting_2 { background-color: #ffe2e2; } +tr.even.gradeX td.sorting_3 { background-color: #ffe2e2; } + +tr.odd.gradeU td.sorting_1 { background-color: #c4c4c4; } +tr.odd.gradeU td.sorting_2 { background-color: #d1d1d1; } +tr.odd.gradeU td.sorting_3 { background-color: #d1d1d1; } + +tr.even.gradeU td.sorting_1 { background-color: #d5d5d5; } +tr.even.gradeU td.sorting_2 { background-color: #e2e2e2; } +tr.even.gradeU td.sorting_3 { background-color: #e2e2e2; } + + +/* Row highlighting example */ +.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted { background-color: #ECFFB3; } +.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted { background-color: #E6FF99; } \ No newline at end of file diff --git a/admin/templates/css/jquery-ui.css b/admin/templates/css/jquery-ui.css new file mode 100644 index 0000000..f9c9ce0 --- /dev/null +++ b/admin/templates/css/jquery-ui.css @@ -0,0 +1,566 @@ +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } +/* + * jQuery UI Accordion 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } +/* + * jQuery UI Autocomplete 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * jQuery UI Menu 1.8.16 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} +/* + * jQuery UI Button 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ +/* + * jQuery UI Datepicker 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* + * jQuery UI Dialog 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* + * jQuery UI Progressbar 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* + * jQuery UI Resizable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* + * jQuery UI Selectable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } +/* + * jQuery UI Slider 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* + * jQuery UI Tabs 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/ + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } +.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } +.ui-widget-content a { color: #222222/*{fcContent}*/; } +.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } +.ui-widget-header a { color: #222222/*{fcHeader}*/; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url('../images/jquery_ui/ui-bg_glass_75_e6e6e6_1x400.png')/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } +.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } + +/* Overlays */ +.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } +.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } \ No newline at end of file diff --git a/admin/templates/css/jquery-ui_custom.css b/admin/templates/css/jquery-ui_custom.css new file mode 100644 index 0000000..0edb3e8 --- /dev/null +++ b/admin/templates/css/jquery-ui_custom.css @@ -0,0 +1,531 @@ +/* + * jQuery UI CSS Framework @VERSION + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute; left: -99999999px; } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + +.ui-widget .title { + background: url(../images/titleBg.png) repeat-x; + height: 36px; + -moz-box-shadow: 0 1px 0 #fff; + -webkit-box-shadow: 0 1px 0 #fff; + box-shadow: 0 1px 0 #fff; +} + +.ui-widget .title h5 { + float: left; + color: #fafafa; + font-weight: normal; + display: block; + padding: 0 0 0 15px; + line-height: 36px; +} + +#ajax-dialog { + background: #FFF8F2 url('../images/backgrounds/blueprint.png') !important; +} + +/* + * jQuery UI CSS Framework @VERSION + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + */ + + +/* Component containers +----------------------------------*/ +.ui-widget .ui-widget { font-size: 1em; } +/*.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }*/ +.ui-widget-content { } +.ui-widget-content a { /*color: #d5d5d5;*/ } +.ui-widget-header { font-weight: bold; } +.ui-widget-header a { color: #222222; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border-left: 1px solid #d5d5d5; font-weight: normal; border-bottom: 1px solid #D5D5D5; } +th.ui-state-default:first-child { border-left: none; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; } +/*.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { background: url(../images/titleBg.png) repeat-x 0 -39px; font-weight: normal; color: #d5d5d5; }*/ +.ui-state-hover a, .ui-state-hover a:hover { color: #797979; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { background: url(../images/titleBg.png) repeat-x 0 -39px; font-weight: normal; color: #fff; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #797979; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(../images/jquery_ui/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +/*.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }*/ +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(../images/jquery_ui/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(../images/jquery_ui/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(../images/jquery_ui/ui-icons_222222_256x240.png); } +.ui-state-default .ui-icon { background-image: url(../images/jquery_ui/ui-icons_888888_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(../images/jquery_ui/ui-icons_222222_256x240.png); } +.ui-state-active .ui-icon {background-image: url(../images/jquery_ui/ui-icons_454545_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(../images/jquery_ui/ui-icons_2e83ff_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(../images/jquery_ui/ui-icons_cd0a0a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +.ui-corner-tl { -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; border-top-left-radius: 2px; } +.ui-corner-tr { -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; border-top-right-radius: 2px; } +.ui-corner-bl { -moz-border-radius-bottomleft: 2px; -webkit-border-bottom-left-radius: 2px; border-bottom-left-radius: 2px; } +.ui-corner-br { -moz-border-radius-bottomright: 2px; -webkit-border-bottom-right-radius: 2px; border-bottom-right-radius: 2px; } +.ui-corner-top { -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; border-top-left-radius: 2px; -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; border-top-right-radius: 2px; } +.ui-corner-bottom { -moz-border-radius-bottomleft: 2px; -webkit-border-bottom-left-radius: 2px; border-bottom-left-radius: 2px; -moz-border-radius-bottomright: 2px; -webkit-border-bottom-right-radius: 2px; border-bottom-right-radius: 2px; } +.ui-corner-right { -moz-border-radius-topright: 2px; -webkit-border-top-right-radius: 2px; border-top-right-radius: 2px; -moz-border-radius-bottomright: 2px; -webkit-border-bottom-right-radius: 2px; border-bottom-right-radius: 2px; } +.ui-corner-left { -moz-border-radius-topleft: 2px; -webkit-border-top-left-radius: 2px; border-top-left-radius: 2px; -moz-border-radius-bottomleft: 2px; -webkit-border-bottom-left-radius: 2px; border-bottom-left-radius: 2px; } +.ui-corner-all { -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; } + +/* Overlays */ +.ui-widget-overlay { background: #000; opacity: 0.4; filter:Alpha(Opacity=40); } +.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(../images/jquery_ui/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } + + +/* ===== UI resizable ===== */ + +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} + +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } + +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; float: left; } +.ui-menu .ui-menu { margin-top: -3px; } +.ui-menu .ui-menu-item { margin:0; padding: 0; zoom: 1; float: left; clear: left; width: 100%; } +.ui-menu .ui-menu-item a { text-decoration:none; display:block; padding:.2em .4em; line-height:1.5; zoom:1; } +.ui-menu .ui-menu-item a.ui-state-hover, .ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; +} + + + +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 5px; } +.ui-buttonset .ui-button { margin: 0 3px; background: #FAFAFA; border: 1px solid #D5D5D5; line-height: 14px; font-size: 11px; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ + + + +/* ===== UI Dialog ===== */ + +.ui-dialog { position: absolute; padding: 5px; width: auto; background: url(../images/alertOpacityOverlay.png) repeat; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; -moz-box-shadow: 0 0 5px #000; -webkit-box-shadow: 0 0 5px #000; box-shadow: 0 0 5px #000; } +.ui-dialog input[type=text] { /*width: 96%!important;*/ margin: 12px 0 10px 0; } +/*.ui-dialog form { text-align: center; }*/ +.ui-dialog .icon { padding: 1px 6px 0 0; float: left; } +.ui-dialog p { padding: 0!important; } +.ui-dialog .ui-dialog-titlebar { position: relative; background: url(../images/titleBg.png) repeat-x; border: 1px solid #24272B; border-bottom: 0; height: 32px; color: #FAFAFA; } +.ui-dialog .ui-dialog-title { float: left; height: 32px; font-size: 16px; padding: 0 12px 0 12px; line-height: 32px; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: 6px; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; opacity: 0.6; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 1px; background: transparent; } +.ui-dialog .ui-dialog-content { position: relative; overflow: auto; zoom: 1; padding: 10px 12px; background: url(../images/widgetBg.png) repeat; border: 1px solid #121212; border-top: none; } +.ui-dialog .ui-dialog-buttonpane { padding: 0 12px; font-size: .9em; background: url(../images/titleBg.png) repeat-x; border: 1px solid #24272B; border-top: none; height: 36px; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { /*float: right;*/ text-align: center; margin: 0 2px; } +.ui-dialog .ui-dialog-buttonpane button { font-size: 10px; font-weight: bold; text-transform: uppercase; padding: 3px 12px 4px 12px; cursor: pointer; font-family: Arial, Helvetica, sans-serif; border: 1px solid #292D2F; color: #fafafa; margin: 7px 0 5px 0; background: url(../images/ui/basicBtn.png) repeat-x 0 0; } +.ui-dialog .ui-dialog-buttonpane button:hover { background-position: 0 -27px; } +.ui-dialog .ui-dialog-buttonpane button:active { background-position: 0 -54px; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 5px; bottom: 5px; opacity: 0.3; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } + + + +/* ===== UI Slider ===== */ + +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 16px; height: 16px; cursor: default; background: url(../images/ui/handle.png) no-repeat !important; border: none; cursor: pointer; } +.ui-slider .ui-slider-handle:hover { background: url(../images/ui/handle_hover.png) no-repeat !important;} +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background: url(../images/ui/sliderOverlay.png) repeat-x !important; -moz-border-radius: 4px; -webkit-border-radius: 4px; -khtml-border-radius: 4px; border-radius: 4px; } + +.ui-slider-horizontal { height: 6px; background: url(../images/ui/sliderBg.png) repeat-x; clear: both; margin-top: 10px; -moz-box-shadow: 0 1px 0 #363B3E; -webkit-box-shadow: 0 1px 0 #363B3E; box-shadow: 0 1px 0 #363B3E; } +.ui-slider-horizontal .ui-slider-handle { top: -5px; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: 6px; height: 100px; background: url(../images/ui/sliderBgVert.png) repeat-y; -moz-box-shadow: 0 0 1px #363B3E; -webkit-box-shadow: 0 0 1px #363B3E; box-shadow: 0 0 1px #363B3E; } +.ui-slider-vertical .ui-slider-handle { left: -5px; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; background: url(../images/ui/sliderOverlayVert.png) repeat-y; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; } + + + +/* ===== UI Tabs ===== */ + +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } + + + + +/* ===== UI Datepicker ===== */ + +.datepicker { width: 58px!important; } +.ui-datepicker { width: 17em; padding: .2em .2em 0; border: 1px solid #1E2226; background: url(../images/darkBg.png) repeat; margin-top: 1px; z-index: 9999 !important; display: none; } +.ui-datepicker-append { margin-left: 10px; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; background: url(../images/titleBg.png) repeat-x 0 -39px; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 2px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; background: none!important; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; background: none!important; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker table .ui-state-default { border: none; -moz-border-radius: 2px; -webkit-border-radius: 2px; -khtml-border-radius: 2px; border-radius: 2px;} +.ui-datepicker table tbody { font-size: 11px; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; color: #fff; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: 2px 6px 2px 0; text-align: right; text-decoration: none; background: url(../images/widgetBg.png) repeat-x; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; width:auto; overflow:visible; border: 0; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; } + + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + + + +/* ===== UI Progress bar ===== */ + +.ui-progressbar { position:relative; height: 16px; text-align: left; margin-top: 5px; background: url(../images/ui/progress.png) repeat-x;} +.ui-progressbar .ui-progressbar-value { margin: -1px 0 0 -1px; height:100%; overflow: hidden; display: block; background: url(../images/ui/progressOverlay.png) repeat-x; border-right: 1px solid #3c95d8; } + +.ui-progressbar .text { position:absolute; top:0; right:0; bottom:0; left:0; color:#424242; text-align:center; text-shadow: 1px 1px 2px #fff; z-index:10; font-weight:bold } + +.pbar .ui-progressbar-value {display:block !important} +.pbar { overflow: hidden; background: url(../images/ui/progress.png) repeat-x;} +.percent { position: relative; text-align: right; margin-bottom: 5px; font-size: 11px; } +.elapsed { position: relative; text-align: right; margin-top: 5px; font-size: 11px;} + +.ui-timepicker-div { color: #D5D5D5; } +.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } +.ui-timepicker-div dl { text-align: left; } +.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } +.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } +.ui-timepicker-div td { font-size: 90%; } +.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } + +.ui-draggable-dragging {opacity: 0.5; box-shadow: none !important} +/*.ui-draggable-dragging .ui-dialog-content {display: none !important}*/ + +.fixed-dialog{ + position: fixed; +} + +.ui-datepicker-calendar a { + color: #fff; +} +.ajax-dialog input[type=text] { + margin: 0 !important; +} \ No newline at end of file diff --git a/admin/templates/css/jquery.fancybox.css b/admin/templates/css/jquery.fancybox.css new file mode 100644 index 0000000..e8fa2cd --- /dev/null +++ b/admin/templates/css/jquery.fancybox.css @@ -0,0 +1,359 @@ +/* + * FancyBox - jQuery Plugin + * Simple and fancy lightbox alternative + * + * Examples and documentation at: http://fancybox.net + * + * Copyright (c) 2008 - 2010 Janis Skarnelis + * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated. + * + * Version: 1.3.4 (11/11/2010) + * Requires: jQuery v1.3+ + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + */ + +#fancybox-loading { + position: fixed; + top: 50%; + left: 50%; + width: 40px; + height: 40px; + margin-top: -20px; + margin-left: -20px; + cursor: pointer; + overflow: hidden; + z-index: 1104; + display: none; +} + +#fancybox-loading div { + position: absolute; + top: 0; + left: 0; + width: 40px; + height: 480px; + background-image: url('../images/fancybox/fancybox.png'); +} + +#fancybox-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + z-index: 1100; + display: none; +} + +#fancybox-tmp { + padding: 0; + margin: 0; + border: 0; + overflow: auto; + display: none; +} + +#fancybox-wrap { + position: absolute; + top: 0; + left: 0; + padding: 20px; + z-index: 1101; + outline: none; + display: none; +} + +#fancybox-outer { + position: relative; + width: 100%; + height: 100%; + background: #fff; +} + +#fancybox-content { + width: 0; + height: 0; + padding: 0; + outline: none; + position: relative; + overflow: hidden; + z-index: 1102; + border: 0px solid #fff; +} + +#fancybox-hide-sel-frame { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: transparent; + z-index: 1101; +} + +#fancybox-close { + position: absolute; + top: -15px; + right: -15px; + width: 30px; + height: 30px; + background: transparent url('../images/fancybox/fancybox.png') -40px 0px; + cursor: pointer; + z-index: 1103; + display: none; +} + +#fancybox-error { + color: #444; + font: normal 12px/20px Arial; + padding: 14px; + margin: 0; +} + +#fancybox-img { + width: 100%; + height: 100%; + padding: 0; + margin: 0; + border: none; + outline: none; + line-height: 0; + vertical-align: top; +} + +#fancybox-frame { + width: 100%; + height: 100%; + border: none; + display: block; +} + +#fancybox-left, #fancybox-right { + position: absolute; + bottom: 0px; + height: 100%; + width: 35%; + cursor: pointer; + outline: none; + background: transparent url('../images/fancybox/blank.gif'); + z-index: 1102; + display: none; +} + +#fancybox-left { + left: 0px; +} + +#fancybox-right { + right: 0px; +} + +#fancybox-left-ico, #fancybox-right-ico { + position: absolute; + top: 50%; + left: -9999px; + width: 30px; + height: 30px; + margin-top: -15px; + cursor: pointer; + z-index: 1102; + display: block; +} + +#fancybox-left-ico { + background-image: url('../images/fancybox/fancybox.png'); + background-position: -40px -30px; +} + +#fancybox-right-ico { + background-image: url('../images/fancybox/fancybox.png'); + background-position: -40px -60px; +} + +#fancybox-left:hover, #fancybox-right:hover { + visibility: visible; /* IE6 */ +} + +#fancybox-left:hover span { + left: 20px; +} + +#fancybox-right:hover span { + left: auto; + right: 20px; +} + +.fancybox-bg { + position: absolute; + padding: 0; + margin: 0; + border: 0; + width: 20px; + height: 20px; + z-index: 1001; +} + +#fancybox-bg-n { + top: -20px; + left: 0; + width: 100%; + background-image: url('../images/fancybox/fancybox-x.png'); +} + +#fancybox-bg-ne { + top: -20px; + right: -20px; + background-image: url('../images/fancybox/fancybox.png'); + background-position: -40px -162px; +} + +#fancybox-bg-e { + top: 0; + right: -20px; + height: 100%; + background-image: url('../images/fancybox/fancybox-y.png'); + background-position: -20px 0px; +} + +#fancybox-bg-se { + bottom: -20px; + right: -20px; + background-image: url('../images/fancybox/fancybox.png'); + background-position: -40px -182px; +} + +#fancybox-bg-s { + bottom: -20px; + left: 0; + width: 100%; + background-image: url('../images/fancybox/fancybox-x.png'); + background-position: 0px -20px; +} + +#fancybox-bg-sw { + bottom: -20px; + left: -20px; + background-image: url('../images/fancybox/fancybox.png'); + background-position: -40px -142px; +} + +#fancybox-bg-w { + top: 0; + left: -20px; + height: 100%; + background-image: url('../images/fancybox/fancybox-y.png'); +} + +#fancybox-bg-nw { + top: -20px; + left: -20px; + background-image: url('../images/fancybox/fancybox.png'); + background-position: -40px -122px; +} + +#fancybox-title { + font-family: Helvetica; + font-size: 12px; + z-index: 1102; +} + +.fancybox-title-inside { + padding-bottom: 10px; + text-align: center; + color: #333; + background: #fff; + position: relative; +} + +.fancybox-title-outside { + padding-top: 10px; + color: #fff; +} + +.fancybox-title-over { + position: absolute; + bottom: 0; + left: 0; + color: #FFF; + text-align: left; +} + +#fancybox-title-over { + padding: 10px; + background-image: url('../images/fancybox/fancy_title_over.png'); + display: block; +} + +.fancybox-title-float { + position: absolute; + left: 0; + bottom: -20px; + height: 32px; +} + +#fancybox-title-float-wrap { + border: none; + border-collapse: collapse; + width: auto; +} + +#fancybox-title-float-wrap td { + border: none; + white-space: nowrap; +} + +#fancybox-title-float-left { + padding: 0 0 0 15px; + background: url('../images/fancybox/fancybox.png') -40px -90px no-repeat; +} + +#fancybox-title-float-main { + color: #FFF; + line-height: 29px; + font-weight: bold; + padding: 0 0 3px 0; + background: url('../images/fancybox/fancybox-x.png') 0px -40px; +} + +#fancybox-title-float-right { + padding: 0 0 0 15px; + background: url('../images/fancybox/fancybox.png') -55px -90px no-repeat; +} + +/* IE6 */ + +.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_close.png', sizingMethod='scale'); } + +.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_nav_left.png', sizingMethod='scale'); } +.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_nav_right.png', sizingMethod='scale'); } + +.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; } +.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_title_left.png', sizingMethod='scale'); } +.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_title_main.png', sizingMethod='scale'); } +.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_title_right.png', sizingMethod='scale'); } + +.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame { + height: expression(this.parentNode.clientHeight + "px"); +} + +#fancybox-loading.fancybox-ie6 { + position: absolute; margin-top: 0; + top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px'); +} + +#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_loading.png', sizingMethod='scale'); } + +/* IE6, IE7, IE8 */ + +.fancybox-ie .fancybox-bg { background: transparent !important; } + +.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_n.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_ne.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_e.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_se.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_s.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_sw.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_w.png', sizingMethod='scale'); } +.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file diff --git a/admin/templates/css/login.css b/admin/templates/css/login.css new file mode 100644 index 0000000..31c6db1 --- /dev/null +++ b/admin/templates/css/login.css @@ -0,0 +1,203 @@ +/* For IE */ +@font-face { + font-family: "Cuprum"; + src: url('../fonts/cuprum.eot'); +} +/* For SAFARI */ +@font-face { + font-family: 'Cuprum'; + font-style: normal; + font-weight: normal; + src: local('Cuprum'), url('../fonts/cuprum.ttf') format('truetype'); +} +/* Other browsers */ +@font-face { + font-family: 'Cuprum'; + font-style: normal; + font-weight: normal; + src: local('Cuprum'), url('../fonts/cuprum.woff') format('woff'); +} + +html { height: 100%; } +* html body { height: 100%; } +body { margin: 0; padding: 0; font-size: 11px; color: #424242; font-family: Arial, Helvetica, sans-serif; line-height: 18px; min-height: 100%; position: relative; } + +/* ========== General styles ========== */ + +.wrapper { margin: 0 5%; clear: both; } +.img { border: 1px solid #d5d5d5; } + +/* ========== Typo ========== */ + +h1, h2, h3, h4, h5, h6, ul.tabs li a, .leftNav ul li a, .stats ul li span, .userLink, .errorPage p, .ui-dialog .ui-dialog-title { font-family: 'Cuprum', sans-serif; font-weight: normal; } +h1 { font-size: 24px; } +h2 { font-size: 22px; } +h3 { font-size: 20px; } +h4 { font-size: 18px; } +h5 { font-size: 16px; } +h6 { font-size: 14px; } + +blockquote { border : 1px solid #d5d5d5; margin-top: 40px; padding: 15px 10px; quotes: "\201C" "\201D"; background: #fafafa; text-align: center; font-style: italic; font-size: 12px; border-left: 4px solid #d5d5d5; } +blockquote:before { content: open-quote; font-weight: bold; } +blockquote:after { content: close-quote; font-weight: bold; } + +.red { color: #B55D5C; } +.green { color: #2a8827; } + +p { padding: 12px 0 0 0; } +.p12 { padding: 12px; } +.pt12 { padding-top: 12px; } + +.legendLabel span { display: block; margin: 0 5px; } +.legendColorBox { padding-left: 10px; } + + +/* ========== Additional reset classes ========== */ + +.mt40 { margin-top: 40px; } +.nomargin { margin: 0!important; } +.nopadding { padding: 0!important; } +.noborder { border: none!important; } +.nobg { background: none!important; } +.floatleft { display: block; float: left; } +.floatright { display: block; float: right; } +.aligncenter { text-align: center; } +.fix { clear: both; } +.first { margin-top: 22px!important; } +.inactive { margin-top: 0px; color: #2B6893; } + +.ml122 { margin-left: 122px; } +.w40 { width: 40%; } + +/* ===== Top navigation ===== */ + +#topNav { height: 36px; display: block; } +.fixed { position: fixed; background: url(../images/topNav.jpg) repeat; width: 100%; color: #eeeeee; border-bottom: 1px solid #4a4f51; z-index: 999; } + +.welcome { float: left; } +.welcome img { float: left; margin: 8px 8px 8px 0 } +.welcome span { padding: 8px 5px; display: block; white-space: nowrap; float: left; font-size: 11px; } + +.userNav { float: right; z-index: 6000; position: relative; font-size: 11px; } +.userNav .lastNav { width: 2px; height: 36px; background: url(../images/navSep.png) repeat-y; position: absolute; top: 0; right: 0; } +.userNav ul { margin-right: 2px; } +.userNav ul li { display: inline; float: left; position: relative; cursor: pointer; border-right: 1px solid #3F3F3F; } +.userNav ul li:first-child { border-left: 1px solid #3F3F3F; } +.userNav ul li a { color: #eeeeee; text-decoration: none; display: block; float: left; } +.userNav ul li:hover, .selected { background: #212121; } +.userNav ul li span { display: block; padding: 8px 12px 8px 8px; float: left; } +.userNav ul li img { float: left; display: block; margin: 13px 2px 11px 14px; } + +/* ===== Widgets ===== */ +.twoOne { width: 50%; } +.widget, .content .title, .count, .widget .num a, a.count1, .table, .breadCrumb, .earnings, .leftNav ul li a, .listData .cNote, .pages li a, .errorPage, .btn14, .btn55, .loginPanel, .customfile { -moz-border-radius: 2px; -webkit-border-radius: 2px; -khtml-border-radius: 2px; border-radius: 2px; } + +.widgets { clear: both; } +.widgets .left { float: left; /*width: 344px;*/ width: 48%; margin-right: 4%; } +.widgets .right { float: right; /*width: 344px;*/ width: 48%; } + +.content { padding-bottom: 80px; overflow: hidden; } +.content .title { background: url(../images/darkBg.jpg) repeat-x; height: 36px; -moz-box-shadow: 0 1px 0 #fff; -webkit-box-shadow: 0 1px 0 #fff; box-shadow: 0 1px 0 #fff; } +.content .title h5 { float: left; color: #fafafa; font-weight: normal; display: block; padding: 7px 15px; } + +/* ===== Right side content ===== */ +.widget { /*width: 342px;*/ /*width: 100%;*/ margin-top: 40px; border: 1px solid #d5d5d5; display: block; background: #fafafa; clear: both; border-top: none; } +.widgetS { /*width: 342px;*/ /*width: 100%;*/ margin-top: 40px; border: 1px solid #d5d5d5; display: block; background: #fafafa; border-top: none; min-width: 25%; float: left; margin-right: 40px; } + +.widget .body { padding: 12px 14px; } + +.userLink { font-size: 16px; padding-top: 3px; display: block; margin-left: 25px; white-space: nowrap; } +.userWidget { padding: 6px 12px 0 12px; display: block; float: left; } + +/* ===== Forms ===== */ + +.mainForm label { /*margin-right: 15px;*/ display: block; float:left; padding: 4px 10px; } +.rowElem { clear: both; border-top: 1px solid #e7e7e7; padding: 10px 14px; position: relative; } +.rowElem:first-child { border-top: none; } +.rowElem > label { padding: 15px 0; width: 14%; } +.rowElem .topLabel { padding: 5px 12px 12px 0; width: 100%; } + +#valid input { position: relative; } + +/* Inputs */ +.jqTransformInputWrapper { float: left; } +.jqTransformInputWrapper > div { width: 550px; } + +.mainForm input[type=text], .mainForm textarea, .mainForm input[type=password] { background: #fff; width: 100%; border: 1px solid #d5d5d5; padding: 5px; font-size: 11px; font-family: Arial, Helvetica, sans-serif; } +.mainForm input[type=text]:hover, .mainForm input[type=password]:hover, .mainForm textarea:hover { background: #fcfcfc; border: 1px solid #d1d1d1; } +.mainForm input[type=text]:focus, .mainForm input[type=password]:focus, .mainForm textarea:focus { border: 1px solid #bbc1c9; background: #fff; } + +.submitForm { float: right; margin: 1px 14px 22px 14px; } + +.jqTransformInputWrapper_hover input{ background: #f6f6f6; } +.jqTransformInputWrapper_focus input { background: #f6f6f6; border: 1px solid #cad1d4; } + +.jqTransformSafari .jqTransformInputInner div { position: relative; overflow: hidden; margin:0px 8px; } +.jqTransformSafari .jqTransformInputInner div input { background: none; position: absolute; top: -10px; left: -2px; height: 42px; padding-left: 4px; } + +/* Checkboxes */ +span.jqTransformCheckboxWrapper{ display:block;float:left; margin-top:6px; } +a.jqTransformCheckbox { background: transparent url(../images/forms/checkbox.png) no-repeat 0 0px ; vertical-align: middle; height: 15px; width: 15px; display:block;/*display: -moz-inline-block;*/ } + +a.jqTransformChecked { background-position: center bottom;} /* Checked - Used for both Radio and Checkbox */ + +.jqTransformHidden {display: none;} /* used to hide the original form elements */ + + + +/* ========== Buttons ========== */ +input[type=submit], input[type=reset], input[type=button], button, .button { + font-size: 10px; + font-weight: bold; + text-transform: uppercase; + padding: 4px 12px 4px 12px; + cursor: pointer; + font-family: Arial, Helvetica, sans-serif; + line-height: 12px; +} +.mainForm input[type="text"], .mainForm input[type="password"] { + padding: 0px 27px 0px 5px; +} + +.mainForm .loginEmail { background: #fff url(../images/icons/loginEmail.png) no-repeat 180px 3px !important; } +.mainForm .loginPassword { background: #fff url(../images/icons/loginLock.png) no-repeat 180px 3px !important; } + +.basicBtn { background: url(../images/ui/blueBtn.png) repeat-x 0 0; border: 1px solid #336699; color: #fff; -moz-box-shadow: 0 0 2px #336699; -webkit-box-shadow: 0 0 2px #336699; box-shadow: 0 0 2px #336699; } +.basicBtn:hover { background-position: 0 -25px; } +.basicBtn:active { background-position: 0 -50px; } + + +/* ========== Login page ========== */ +.loginPanel { width: 342px; background: #fafafa; border: 1px solid #d5d5d5; border-top: 0; display: block;} +.loginWrapper { margin: -156px 0 0 -160px; position: absolute; top: 50%; left: 50%; } +.loginLogo { position: absolute; width: 190px; height: 44px; display: block; top: -80px; left: 50%; margin-left: -95px; } +.loginPanel h5 { font-weight: normal; padding: 7px 12px 7px 12px; float: left; } + + + +.loginPanel label { width: 80px; } +.rememberMe { margin-left: 12px; } +.rememberMe label { padding: 4px 12px!important; width: auto; } +.loginInput { width: 200px; float: left; margin-left: 14px; } +.loginRow { border-top: 1px solid #e7e7e7; padding: 15px 0; position: relative; } +.loginRow:first-child { border-top: none; } +.loginRowError{ border-top: none; position: relative; padding-top:5px } + +.backTo a:hover { background: #212121; } +.backTo span { padding: 8px 14px 8px 8px; display: block; float: left; } +.backTo img { margin: 13px 2px 11px 14px; float: left; display: block; } +.backTo a { float: left; color: #eeeeee; font-size: 11px; border-right: 1px solid #3F3F3F; border-left: 1px solid #3F3F3F; } + +/* ===== Error messages ===== */ +.messages{list-style:none;font:11px/11px Verdana, Arial, Tahoma; padding:0;} +.messages li{-moz-box-shadow:0 1px 1px rgba(0,0,0,.05);-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);position:relative;margin:0;} +.highlight{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:8px;} +.highlight.grey{background:#fff url(../images/backgrounds/grey.png);border:1px solid #a8adb5;color:#a8adb5;} +.highlight.green{background:#d3f3c0 url(../images/backgrounds/grey.png);border:1px solid #a5d985;color:#557143;} +.highlight.yellow{background:#fff3c5 url(../images/backgrounds/grey.png);border:1px solid #ffe075;color:#937f38;} +.highlight.red{background:#ffe3e2 url(../images/backgrounds/grey.png);border:1px solid #efb1af;color:#c00;} + +/* ===== Footer ===== */ +#footer { clear: both; /*height: 36px;*/ background: url(../images/topNav.jpg) repeat; width: 100%; color: #eeeeee; margin-top: 42px; position: absolute; bottom: 0; } +#footer span { color: #696969; padding: 9px 5px; display: block; font-size: 11px; } +#footer span a { color: #eeeeee; } \ No newline at end of file diff --git a/admin/templates/css/main.css b/admin/templates/css/main.css new file mode 100644 index 0000000..20db152 --- /dev/null +++ b/admin/templates/css/main.css @@ -0,0 +1,1506 @@ +/* For IE */ +@font-face { + font-family: "Cuprum"; + src: url('../fonts/cuprum.eot'); +} +/* For SAFARI */ +@font-face { + font-family: 'Cuprum'; + font-style: normal; + font-weight: normal; + src: local('Cuprum'), url('../fonts/cuprum.ttf') format('truetype'); +} +/* Other browsers */ +@font-face { + font-family: 'Cuprum'; + font-style: normal; + font-weight: normal; + src: local('Cuprum'), url('../fonts/cuprum.woff') format('woff'); +} +::before, ::after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { height: 100%; } +* html body { height: 100%; } +body { margin: 0; padding: 0; background: url(../images/backgrounds/blueprint.png) repeat; font-size: 11px!important; color: #424242; font-family: Arial, Helvetica, sans-serif; line-height: 16px; min-height: 100%; position: relative; } + +/* ========== General styles ========== */ +.wrapper { margin: 0 3%; clear: both; } +.wrapper_fixed { width: 980px; margin: auto; } +.img { border: 1px solid #d5d5d5; } +.help { cursor:help; } +.pointer { cursor:pointer; } + +/* ========== CodeMirror ========== */ +.CodeMirror-fullscreen { position: fixed !important; top: 0; right: 0; bottom: 0; left: 0; width: 100% !important; height: 100% !important; z-index: 9999; } +.CodeMirror {font-size: 12px;} + +/* ========== Typo ========== */ +h1, h2, h3, h4, h5, h6, ul.tabs li a, ul.inact_tabs li a, .leftNav ul li a, .middleNav ul li a, .stats ul li span, .userLink, .errorPage p, .ui-dialog .ui-dialog-title { font-family: 'Cuprum', sans-serif; font-weight: normal; } + +h1 { font-size: 24px; } +h2 { font-size: 22px; } +h3 { font-size: 20px; } +h4 { font-size: 18px; } +h5 { font-size: 15px; } +h6 { font-size: 14px; } + +blockquote { border : 1px solid #272C30; margin-top: 40px; padding: 15px 10px; quotes: "\201C" "\201D"; background: url(../images/widgetBg.png) repeat; text-align: center; font-style: italic; font-size: 12px; border-left: 4px solid #272C30; } +blockquote:before { content: open-quote; font-weight: bold; } +blockquote:after { content: close-quote; font-weight: bold; } + +.red { color: #e0a5a5; } +.green { color: #72c66f; } +.dgrey, .dgrey a { color: #687282; } +.white {color: #fff;} + +.docname:hover { border-bottom: 1px dotted} +.doclink {font-size: 11px; font-style: italic; border-bottom: 1px dotted} +.doclink:hover { border: none;} + +.link {border-bottom: 1px dotted;} +.link:hover { border: none;} + +.dotted {border-bottom: 1px dotted;} + +a { color: #336699; } + +.date_text { font-size: 10px; font-style: italic;} + +p { padding: 12px 0 0 0; } + +.legendLabel span { display: block; margin: 0 5px; } +.legendColorBox { padding-left: 10px; } +/* +#contentPage a:hover { text-decoration: underline; } +*/ +.zindex1 {z-index: 1500;} +.zindex2 {z-index: 1000;} +.zindex3 {z-index: 500;} + + +/* ========== Additional reset classes ========== */ +.mt5 { margin-top: 5px; } +.mt40 { margin-top: 40px; } +.ml10 { margin-left: 10px; } +.ml20 { margin-left: 20px; } +.minmarg {margin: 2px 0;} +.mrl5 {margin: 0px 10px;} +.p12 { padding: 12px; } +.pt12 { padding-top: 12px; } +.pr12 { +/*padding-right: 12px;*/ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + position: relative; + display: table; + border-collapse: separate; + width: 100%; +} +.span-form { + display: table-cell; + width: 1%; + vertical-align: middle; + white-space: nowrap; + text-align: left; +} +.pl12 { padding-left: 12px; } +.arrow {font-size: 13px;} +.nomargin { margin: 0!important; } +.nopadding { padding: 0!important; } +.noborder { border: none!important; } +.nobg { background: none!important; } +.floatleft { display: block; float: left; } +.floatright { display: block; float: right; } +.aligncenter { text-align: center; } +.fix { clear: both; } +.first { margin-top: 22px!important; } +.inactive { margin-top: 0px; color: #656565; } +.btext { font-weight: bold; } +.hidden { display: none !important;} +.rounded { -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;} +select { overflow: auto; } +.bordLeft { border-top-left-radius: 3px; -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; } +.bordRight { border-top-right-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; } + + +/* ===== Header ===== */ +#header { height: 20px; clear: both; } +.logo .box{ width: 180px; height: 64px; display: block; background: url(../images/loginLogo.png) no-repeat; margin: 0 0 12px 0;} + +.middleNav { float: right; margin-right: 1px; margin-top: 20px;} +.middleNav ul { margin-top: 20px; } +.middleNav ul li { height: 55px; text-align: center; display: block; float: left; margin-left: 5px; position: relative; } +.middleNav ul li:first-child { margin: 0; } +.middleNav ul li a { font-size: 12px; display: block; background: url(../images/titleBg.png) repeat-x 0 0; border: 1px solid #464A55; margin-top: 1px; position: relative; color: #fafafa; text-shadow: 0 1px 0 #687282;-moz-border-radius: 2px;-webkit-border-radius: 2px;-khtml-border-radius: 2px;border-radius: 2px; } +.middleNav ul li a span { display: block; padding: 5px 15px} +.middleNav ul li a:hover { background-position: 0 -78px; border: 1px solid #353E47; } +.middleNav ul li a.active { background-position: 0 -39px; border: 1px solid #336699; text-shadow: 0 1px 0 #336699; } + + +/* ===== Top navigation ===== */ +#topNav { height: 36px; display: block; } +.fixed { position: fixed; background: url(../images/topNav.jpg) repeat; width: 100%; color: #fff; z-index: 999; } + +.welcome { float: left; } +.welcome img { float: left; margin: 9px 8px 0 0; -moz-border-radius: 2px;-webkit-border-radius: 2px;-khtml-border-radius: 2px;border-radius: 2px; } +.welcome img.avatar { float: left; margin: 6px 8px 0 0; -moz-border-radius: 2px;-webkit-border-radius: 2px;-khtml-border-radius: 2px;border-radius: 2px; } +.welcome span { padding: 0px 5px; display: block; white-space: nowrap; float: left; line-height: 36px; } + +.userNav { float: right; z-index: 10000; position: relative; font-size: 11px; } +.userNav .lastNav { width: 2px; height: 30px; position: absolute; top: 0; right: 0; } +.userNav > ul { margin-right: 2px; } +.userNav > ul > li { display: inline; float: left; position: relative; cursor: pointer; border-left: 1px solid #3F3F3F; } +.userNav > ul > li:last-child { border-right: 1px solid #3F3F3F; } +.userNav > ul > li a { color: #eeeeee; text-decoration: none; display: block; float: left; } +.userNav > ul > li:hover, .selected { background: #212121; } +.userNav > ul > li span { display: block; padding: 8px 12px 8px 8px; float: left; } +.userNav > ul > li img { float: left; display: block; margin: 13px 2px 11px 14px; } + +.userNav > ul > li > ul { position: absolute; left: -1px; display: none; top: 35px; margin-top: 0px; background: #2f2f2f; padding: 0 1px 1px 1px; border: 1px solid #1d1d1d; z-index: 100; } +.userNav > ul > li > ul > li { display: block; float: none; border-top: 1px solid #2f2f2f; background: #212121; border-right: none; } +.userNav > ul > li > ul > li:first-child { border-left: none!important; } +.userNav > ul > li > ul > li a { width: 162px; padding: 6px 10px 6px 15px; font-size: 11px; text-transform: none; color: #a4a4a4; font-weight: normal; background: none; float: none; } +.userNav > ul > li > ul > li a:hover { background: none; font-weight: normal; color: #fff; } +.userNav > ul > li > ul > li:hover { background: url(../images/titleBg.png) repeat-x; background-position: 0 -39px; } +.userNav > ul > li > ul > li span { display: block; padding: 0; float: none; } +.userNav > ul > li > ul > li a.active {background: url(../images/titleBg.png) repeat-x; background-position: 0 -39px; color: #fff;} + +#menu {width: 180px;} +/* ===== Left navigation ===== */ +.leftNav { width: 180px; max-width: 36%; margin-top: -1px; float: left; margin-bottom: 80px; margin-right: 41px; } + +/*.leftNav { width: 212px; max-width: 36%; margin-top: -1px; float: left; margin-bottom: 80px; margin-right: 41px; }*/ +.leftNav .last { border-bottom: none; } + +.leftNav ul li { position: relative; } +.leftNav ul li a { color: #fafafa; font-size: 13px; display: block; background: url(../images/titleBg.png) repeat-x 0 0; border: 1px solid #464A55; margin-top: 1px; } +.leftNav ul li a:hover { background-position: 0 -78px; border: 1px solid #353E47; } +.leftNav ul li a.active { background-position: 0 -39px; border: 1px solid #336699; } + +.leftNav ul li a span { padding: 7px 0 7px 15px; display: block; } + +#leftNav_show {position: fixed; left: 0px;top: 57px; width: 30px; height: 33px; background: url(../images/left_menu_show.png) right top no-repeat;} +#leftNav_show #toggle-LeftMenu * { cursor: pointer;} +#leftNav_show #toggle-LeftMenu span{ display:block; width:17px; height:17px; overflow: hidden; margin:7px 0 0 4px; background:url(../images/left_menu_show.png) 0px -20px no-repeat;} +#leftNav_show #toggle-LeftMenu span.close{ background-position: -17px -20px;} + +/* Left navigation subnav */ +ul.sub { border: none; } +ul.sub li { border: 1px solid #d5d5d5; padding: 1px; margin: 1px 0 0 0; background: #fff url(../images/leftNavSub.png) repeat; } +ul.sub li a { background: url(../images/arrow.gif) no-repeat 8px 15px; border: none; font-family: Arial, Helvetica, sans-serif; color: #494949; font-size: 11px; padding: 5px 10px 5px 18px;} +ul.sub li a:hover, .sub li a:active { font-style: normal; border: none; color: #676767; background: url(../images/arrow.gif) no-repeat 8px 15px; } + +/* ========== Left navigation subnav + docs ========== */ +ul.sub li a.numberRight { margin: 0; position: absolute; top: 11px; right: 10px; float: none; background: url(../images/ui/numDataBg.png) repeat-x; padding: 3px 3px!important; z-index: 100;} +ul.sub li a.numberRight:hover { background-position: 0px -42px; } + +/* ===== Right side content ===== */ +.widget { /*width: 342px;*/ /*width: 100%;*/ margin-top: 40px; border: 1px solid #d5d5d5; display: block; background: #fafafa; clear: both; border-top: none; } +.widgetS { /*width: 342px;*/ /*width: 100%;*/ margin-top: 40px; border: 1px solid #d5d5d5; display: block; background: #fafafa; border-top: none; min-width: 25%; float: left; margin-right: 40px; } + +.head { background: #efefef url(../images/NavBg.png) repeat-x; height: 32px; border-top: 1px solid #d5d5d5; border-bottom: 1px solid #d5d5d5; position: relative; color: #464A55 } +.widget .head h5, .table h5, .title h5 { font-weight: normal; padding: 0px 15px; float: left; line-height: 32px; } + +.widget .body { padding: 12px 14px; } +.widget .normal h5, .accordion-close h5 { background: url(../images/accordion_on.png) no-repeat 15px 12px; padding: 0px 15px 0px 32px!important } +.widget .inactive h5, .accordion-open h5 { background: url(../images/accordion_off.png) no-repeat 12px 14px; padding: 0px 15px 0px 32px!important; } + +.widget .num { float: right; display: inline-block; text-align: center; margin: 7px 12px 0 0; font-size: 11px; } +.title .num { float: right; display: inline-block; text-align: center; margin: 10px 10px 0 0; font-size: 11px; } +.widget .num span, .title .num .span { margin-right: 10px; } +.widget .num a, .title .num a { background: url(../images/ui/numDataBg.png) repeat-x; height: 19px; padding: 3px 10px; color: #fefefe; } + +.widget .num a.basicNum { background-position: 0 0; border: 1px solid #336699; color: #fff; -moz-box-shadow: 0 0 2px #336699; -webkit-box-shadow: 0 0 2px #336699; box-shadow: 0 0 2px #336699;} +.widget .num a.basicNum:hover { background-position: 0 -21px; } +.widget .num a.basicNum:active { background-position: 0 -42px; } + +.widget .num a.blueNum { background: url(../images/ui/redBtn.png) repeat-x; border: 1px solid #4f5a68; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454;} +.widget .num a.blueNum:hover { background-position: 0 -21px; } +.widget .num a.blueNum:active { background-position: 0 -42px; } + +.widget .num a.redNum { background-position: 0 -63px; border: 1px solid #8F0000; color: #fff; -moz-box-shadow: 0 0 2px #660000; -webkit-box-shadow: 0 0 2px #660000; box-shadow: 0 0 2px #660000;} +.widget .num a.redNum:hover { background-position: 0 -84px; } +.widget .num a.redNum:active { background-position: 0 -105px; } + +.widget .num a.greenNum { background-position: 0 -126px; border: 1px solid #557639; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.widget .num a.greenNum:hover { background-position: 0 -147px; } +.widget .num a.greenNum:active { background-position: 0 -168px; } + +.title .num a.basicNum { background-position: 0 0; border: 1px solid #336699; color: #fff; -moz-box-shadow: 0 0 2px #336699; -webkit-box-shadow: 0 0 2px #336699; box-shadow: 0 0 2px #336699;} +.title .num a.basicNum:hover { background-position: 0 -21px; } +.title .num a.basicNum:active { background-position: 0 -42px; } + +.widget .loader { float: right; margin: 14px 12px 0 0; } + +.title { position: relative; } +.title .lang { float: right; display: inline-block; text-align: center; margin: 10px 12px 0 0; font-size: 11px; } +.title .lang .icon_off { opacity: 0.5; } +.title .lang .icon_off:hover { opacity: 0.9; } + +.oneTwo { width: 49%; display: inline; float: right; } +.oneTwo:first-child { float: left; } +.oneThree { width: 32%; display: inline; float: left; margin-left: 2%; } +.oneThree:first-child { margin-left: 0; float: left; } + +.twoOne { width: 66%; float: right; margin-left: 2%; } +.twoOne:first-child { margin-left: 0; float: left; } + +.oneFour { width: 23.5%; float: left; margin-left: 2%; } +.oneFour:first-child { margin-left: 0; } + + +.userLink { font-size: 16px; padding-top: 3px; display: block; margin-left: 25px; white-space: nowrap; } +.userWidget { padding: 6px 12px 0 12px; display: block; float: left; } + +.questions { background: url(../images/ui/orangeBtn.png) repeat-x 0 0; border: 1px solid #CE5300; color: #fff; -moz-box-shadow: 0 0 2px #9B3E00; -webkit-box-shadow: 0 0 2px #9B3E00; box-shadow: 0 0 2px #9B3E00; padding: 2px 6px;} +.questions:hover { background-position: 0 -25px; } +.questions:active { background-position: 0 -50px; } + + +ul#doclinks {margin:0; padding: 25px 0pt 0px 0px;} +ul#doclinks li {line-height:16px; padding:0 0 0 18px; list-style:none; margin-top:5px; text-align:left;} +ul#doclinks a:link, ul#doclinks a:visited {text-decoration:none;} +ul#doclinks a:hover {color: #777; border-bottom: 1px dotted #777;} + + +/* ===== Table ===== */ +.tableStatic thead td { padding: 3px 0; text-align: center; border-left: 1px solid #ddd; background: #efefef url(../images/leftNavBg.png) repeat-x; border-bottom: 1px solid #ddd; font-size: 11px; color: #878787; vertical-align: middle; line-height: 16px; } +.tableStatic thead td:first-child { border-left: none; } +.tableStatic thead td a {color: #424242;} + +.tableStatic thead td img {vertical-align: middle; margin: 0 5px;} + +.tableStatic tbody tr { border-top: 1px solid #ddd; } +.tableStatic tbody tr:nth-child(even) { background-color: #eee; } + +.tableStatic tbody tr:hover { background-color: #e8f2ff; } + +.tableStatic tbody tr.header, .tableStatic tbody tr.header:hover { font-weight: bold!important; background: #efefef url(../images/leftNavBg.png) repeat-x!important; } + +.tableStatic tbody td { border-left: 1px solid #ddd; padding: 6px 10px; vertical-align: middle; } +.tableStatic tbody td:first-child { border-left: none; } +.tableStatic tbody td small { font-size: 11px; color: #777777; } +.tableStatic tbody td small ul { padding: 0; margin-left:15px; list-style: square outside; } +.tableStatic tbody td small ul li { padding: 0; margin: 0; } + +.tableStatic tbody td .level1 {background:transparent url(../images/nav_level_2.gif) 10px 0px no-repeat; padding-left:35px;} +.tableStatic tbody td .level2 {background:transparent url(../images/nav_level_2.gif) 30px 0px no-repeat; padding-left:55px;} +.tableStatic tbody td .level3 {background:transparent url(../images/nav_level_2.gif) 50px 0px no-repeat; padding-left:75px;} +.tableStatic tbody td .level4 {background:transparent url(../images/nav_level_2.gif) 70px 0px no-repeat; padding-left:95px;} +.tableStatic tbody td .level5 {background:transparent url(../images/nav_level_2.gif) 90px 0px no-repeat; padding-left:115px;} +.tableStatic tbody td .level6 {background:transparent url(../images/nav_level_2.gif) 110px 0px no-repeat; padding-left:135px;} +.tableStatic tbody td .level7 {background:transparent url(../images/nav_level_2.gif) 130px 0px no-repeat; padding-left:155px;} +.tableStatic tbody td .level8 {background:transparent url(../images/nav_level_2.gif) 150px 0px no-repeat; padding-left:175px;} +.tableStatic tbody td .level9 {background:transparent url(../images/nav_level_2.gif) 170px 0px no-repeat; padding-left:195px;} +.tableStatic tbody td .level10 {background:transparent url(../images/nav_level_2.gif) 190px 0px no-repeat; padding-left:215px;} + +.tableStatic hr { color:#ddd; background-color:#ddd; border:0px none; height:1px; clear:both; } + +.tableStatic tr.red+tr { border-top-color:#efb1af !important; } +.tableStatic tr.dred+tr { border-top-color:#efb1af !important; } +.tableStatic tr.green+tr { border-top-color:#a5d985 !important; } +.tableStatic tr.dgreen+tr { border-top-color:#a5d985 !important; } +.tableStatic tr.lgreen+tr { border-top-color:#a5d985 !important; } +.tableStatic tr.yellow+tr { border-top-color:#ffe075 !important; } +.tableStatic tr.dyellow+tr { border-top-color:#ffe075 !important; } +.tableStatic tr.grey+tr { border-top-color:#c4c4c4 !important; } +.tableStatic tr.dgrey+tr { border-top-color:#c4c4c4 !important; } +.tableStatic tr.lgrey+tr { border-top-color:#c4c4c4 !important; } + +.tableStatic tr.red { border-color:#efb1af !important; } +.tableStatic tr.red td { background:#ffe3e2 url(../images/backgrounds/grey.png) !important; border-color:#efb1af !important;color:#c00 !important; } + +.tableStatic tr.green { border-color:#a5d985 !important; } +.tableStatic tr.green td { background:#d3f3c0 url(../images/backgrounds/grey.png) !important; border-color:#a5d985 !important;color:#557143 !important; } + +.tableStatic tr.lgreen { border-color:#a5d985 !important; } +.tableStatic tr.lgreen td { background:#e0ffce url(../images/backgrounds/grey.png) !important; border-color:#a5d985 !important;color:#557143 !important; } + +.tableStatic tr.dgreen { border-color:#a5d985 !important; } +.tableStatic tr.dgreen td { background:#c9e5b9 url(../images/backgrounds/grey.png) !important; border-color:#a5d985 !important;color:#557143 !important; } + +.tableStatic tr.yellow { border-color:#ffe075 !important; } +.tableStatic tr.yellow td { background:#fff3c5 url(../images/backgrounds/grey.png) !important; border-color:#ffe075 !important;color:#937f38 !important; } + +.tableStatic tr.grey { border-color:#c4c4c4 !important; } +.tableStatic tr.grey td { background:#d5d8db url(../images/backgrounds/grey.png) !important; border-color:#c4c4c4 !important; color:#9198a0 !important; } + +.tableStatic tr.dgrey { border-color:#c4c4c4 !important; } +.tableStatic tr.dgrey td { background:#c9cbcb url(../images/backgrounds/grey.png) !important; border-color:#c4c4c4 !important; color:#9198a0 !important; } + +.tableStatic tr.lgrey { border-color:#c4c4c4 !important; } +.tableStatic tr.lgrey td { background:#f5f5f5 url(../images/backgrounds/grey.png) !important; border-color:#c4c4c4 !important; color:#9198a0 !important; } + +.tableStatic tr.blank td { background: url(../images/backgrounds/grey.png) !important; } + +.tableStatic tbody td.actions a { border: 1px; -moz-border-radius: 3px;-webkit-border-radius: 3px;-khtml-border-radius: 3px;border-radius: 3px;} + +.tableStatic td.green { background: #d3f3c0 url(../images/backgrounds/grey.png) !important; color:#557143 !important; } +.tableStatic td.yellow { background: #fff3c5 url(../images/backgrounds/grey.png) !important; color:#937f38 !important; } +.tableStatic td.red { background: #ffe3e2 url(../images/backgrounds/grey.png) !important; color:#c00 !important; } +.tableStatic td.grey { background: #d5d8db url(../images/backgrounds/grey.png) !important; color:#c4c4c4 !important; } +.tableStatic td.lgrey { background: #f5f5f5 url(../images/backgrounds/grey.png) !important; color:#c4c4c4 !important; } +.tableStatic td.blank { background: url(../images/backgrounds/grey.png) !important; } + +/* ========== Buttons ========== */ +input[type="submit"], input[type="reset"], input[type="button"], button, .button { + font-size: 10px; + font-weight: bold; + text-transform: uppercase; + padding: 0px 6px; + cursor: pointer; + font-family: Arial, Helvetica, sans-serif; + line-height: 20px; + height: 22px; +} +input, textarea { box-sizing:border-box; } + +.basicBtn { background: url(../images/ui/blueBtn.png) repeat-x 0 0; border: 1px solid #336699; color: #fff; -moz-box-shadow: 0 0 2px #336699; -webkit-box-shadow: 0 0 2px #336699; box-shadow: 0 0 2px #336699; } +.basicBtn:hover { background-position: 0 -25px; } +.basicBtn:active { background-position: 0 -50px; } + +.redBtn { background: url(../images/ui/redBtn.png) repeat-x 0 0; border: 1px solid #9d342a; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.redBtn:hover { background-position: 0 -25px; } +.redBtn:active { background-position: 0 -50px; } + +.seaBtn { background: url(../images/ui/seaBtn.png) repeat-x 0 0; border: 1px solid #306873; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.seaBtn:hover { background-position: 0 -25px; } +.seaBtn:active { background-position: 0 -50px; } + +.blackBtn { background: url(../images/ui/blackBtn.png) repeat-x 0 0; border: 1px solid #353535; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.blackBtn:hover { background-position: 0 -25px; } +.blackBtn:active { background-position: 0 -50px; } + +.greyishBtn { background: url(../images/ui/greyishBtn.png) repeat-x 0 0; border: 1px solid #4f5a68; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.greyishBtn:hover { background-position: 0 -25px; } +.greyishBtn:active { background-position: 0 -50px; } + +.greenBtn { background: url(../images/ui/greenBtn.png) repeat-x 0 0; border: 1px solid #418d4f; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.greenBtn:hover { background-position: 0 -25px; } +.greenBtn:active { background-position: 0 -50px; } + +.orangeBtn { background: url(../images/ui/orangeBtn.png) repeat-x 0 0; border: 1px solid #CE5300; color: #fff; -moz-box-shadow: 0 0 2px #9B3E00; -webkit-box-shadow: 0 0 2px #9B3E00; box-shadow: 0 0 2px #9B3E00;} +.orangeBtn:hover { background-position: 0 -25px; } +.orangeBtn:active { background-position: 0 -50px; } + +.whiteBtn { background: url(../images/ui/whiteBtn.png) repeat-x 0 0; border: 1px solid #B7B7B7; color: #525252; -moz-box-shadow: 0 0 2px #D5D5D5; -webkit-box-shadow: 0 0 2px #D5D5D5; box-shadow: 0 0 2px #D5D5D5;} +.whiteBtn:hover { background-position: 0 -25px; } +.whiteBtn:active { background-position: 0 -50px; } + +.dualBtn { padding: 7px 8px; cursor: pointer; line-height: 12px; background: url(../images/ui/blueBtn.png) repeat-x 0 0; border: 1px solid #3581c1; color: #fff; -moz-box-shadow: 0 0 2px #545454; -webkit-box-shadow: 0 0 2px #545454; box-shadow: 0 0 2px #545454; } +.dualBtn:hover { background-position: 0 -25px; } +.dualBtn:active { background-position: 0 -50px; } + +.btn14 { border: 1px solid #24272B; background: url(../images/titleBg.png) repeat-x 0 0; padding: 6px 8px; display: inline-block; -moz-box-shadow: 0 1px 0 #363B3E; -webkit-box-shadow: 0 1px 0 #363B3E; box-shadow: 0 1px 0 #363B3E; } +.btn14:hover { background-position: 0 -39px; } +.btn14:active { background: #557a8e; } + +.btn55 { background: #3b5867 url(../images/middlebg.png) repeat-x 0 0; border: 1px solid #292D2F; padding: 7px 6px 0px 6px; display: inline-block; -moz-box-shadow: 0 1px 0 #363B3E; -webkit-box-shadow: 0 1px 0 #363B3E; box-shadow: 0 1px 0 #363B3E; } +.btn55:hover { background-position: 0 -56px; } +.btn55:active { background-position: 0 -112px; } +.btn55 span { display: block; padding: 5px 5px 0 5px; color: #eaeaea; } + +.btnIconLeft { border: 1px solid #292D2F; background: url(../images/titleBg.png) repeat-x 0 0; display: inline-block; color: #fafafa; text-decoration: none; } +.btnIconLeft:hover { background-position: 0 -39px; border: 1px solid #292D2F; } +.btnIconLeft:active { background: #557a8e; } +.btnIconLeft .icon { float: left; border-right: 1px solid #292D2F; padding: 8px; } +.btnIconLeft span { display: block; float: left; padding: 5px 10px; font-weight: bold; } + +a.btn{font-size: 10px;font-weight: bold;text-transform: uppercase;padding: 4px 12px;cursor: pointer;font-family: Arial, Helvetica, sans-serif;line-height: 12px;} +a.button, span.button { padding: 4px 10px; } + +.topBtn { + width: 100%; + display: block; + padding: 4px 0 !important; + text-align: center; + height: 22px; + line-height: 22px; + border: none !important; +} + +.tableButtons td { + padding: 0 10px; +} + +/* ========== Pagination ========== */ +.pagination { margin: auto; width: auto; text-align: center; margin-top: 40px; } + +.pages span.pages { float:left; font-family: 'Cuprum', sans-serif; font-weight: normal; letter-spacing: 1px; font-size: 12px; } +.pages li.prev { margin-right: 15px; } +.pages li.next { margin-left: 15px; } +.pages li { display: inline; margin: 0 2px; } +.pages li a { height: 25px; padding: 4px 8px; text-decoration: none; color: #666; font-weight: bold; background: url(../images/ui/pagination.png) repeat-x 0 0; border: 1px solid #d5d5d5; font-size: 11px; } +.pages li a:hover { background: #efefef; } +.pages li span.active { height: 25px; padding: 4px 8px; text-decoration: none; color: #666; font-weight: bold; background: url(../images/ui/pagination.png) repeat-x 0 -26px; font-size: 11px; color: #fff; border-color: #666; } + + +/* ========== Numbers notifications ========== */ +.numberTop, .numberMiddle, .numberLeft, a.numberLeft { text-align: center; display: inline-block; padding: 1px 5px; color: #fff; float: right; margin: 10px 15px 10px -5px; font-size: 11px; line-height: 14px;-moz-border-radius: 3px;-webkit-border-radius: 3px;-khtml-border-radius: 3px;border-radius: 3px;} +.numberTop, .numberMiddle { margin: 9px 15px 8px -5px; padding: 1px 5px!important; background: url(../images/ui/numDataBg.png) repeat-x; border: 1px solid #CC6600;} +.numberMiddle { margin: 0; position: absolute; top: -7px; right: -7px; font-size: 11px; background: url(../images/ui/numDataBg.png) repeat-x; } +.numberLeft { margin: 0; position: absolute; top: 10px; right: 0px; font-size: 11px; font-family: Arial, Helvetica, sans-serif; float: none; background: url(../images/ui/numDataBg.png) repeat-x!important; padding: 2px 6px!important;} + + +/* ===== Widgets ===== */ +.twoOne { width: 50%; } +.widget, .content .title, .count, .widget .num a, a.count1, .table, .breadCrumb, .earnings, .leftNav ul li a, ul.sub li, .listData .cNote, .pages li a, .pages li span.active, .errorPage, .btn14, .btn55, .loginPanel, .customfile, .title .num a { -moz-border-radius: 2px; -webkit-border-radius: 2px; -khtml-border-radius: 2px; border-radius: 2px; } + +.widgets { clear: both; } +.widgets .left { float: left; /*width: 344px;*/ width: 48%; margin-right: 4%; } +.widgets .right { float: right; /*width: 344px;*/ width: 48%; } + +.content { overflow: hidden; padding-bottom: 120px; } +.content .title { background: url(../images/titleBg.png) repeat-x; height: 36px; -moz-box-shadow: 0 1px 0 #fff; -webkit-box-shadow: 0 1px 0 #fff; box-shadow: 0 1px 0 #fff; } +.content .title h5 { float: left; color: #fafafa; font-weight: normal; display: block; padding: 7px 15px; } + +/* Search */ +.searchWidget { position: relative; margin-top: 40px; } +.searchWidget input[type=text] { background: #fafafa; border: 1px solid #d5d5d5; padding: 10px; width: 100%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box; } +.searchWidget input[type=submit] { background: url(../images/forms/searchBtn.png) no-repeat 0 0; position: absolute; top: 0; right: 0; border: none; width: 36px; height: 36px; } + +/* ===== PopUps ===== */ +#popup_container { min-width: 300px; max-width: 600px; background: url(../images/alertOpacityOverlay.png) repeat; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; } +#popup_title { text-align: center; background: url(../images/leftNavBg.png) repeat-x; border-bottom: 1px solid #d5d5d5; cursor: default; height: 32px; line-height: 32px; } +#popup_content { background: #fafafa; padding: 1em 1.75em; margin: 0em; } +#popup_message { text-align: center; } +#popup_panel { text-align: center; margin: 1em 0em 0em 0em; } +#popup_message input[type=text] { background: #FCFCFC; border: 1px solid #D1D1D1; padding: 5px; width: 258px; } +#popup_prompt { margin: .5em 0em; } + + +/* ===== Forms ===== */ +.mainForm label { /*margin-right: 15px; line-height: 22px; vertical-align: middle;*/ display: block; float:left; padding: 0px 10px; } +.mainForm label.inline { display: inline-block; padding: 0px 10px; } +.mainForm label small { font-size: 11px; color: #777777; } + +.datepicker { width: 58px!important; cursor: pointer; } + +.multiple { width: 100%; padding: 5px; border: 1px solid #d5d5d5; } + +.moreFields ul li { float: left; width: 8%; margin: 0 10px 0 0; } +.moreFields ul li input { width: 98%!important; } +.moreFields ul li.sep { padding: 3px 5px 3px 6px; display: block; margin: 0; width: auto; color: #d5d5d5; } +.moreFields ul li span { display: block; padding: 3px 12px; white-space: nowrap; } + +.itemDisabled { color: #b7b7b7; } + +.rowElem { clear: both; border-top: 1px solid #e7e7e7; padding: 8px 10px; position: relative; /*width: 100%;*/ white-space: nowrap;} +.rowElem:first-child { border-top: none; } +.tableStatic + .rowElem { border-top: 1px solid #ddd; } + +.rowElem:hover { background: none repeat scroll 0 0 #e8f2ff;} + +.formRight { float: right; width: 76%; margin: 12px 12px 12px 2%; display: block; position: relative; } +.formBottom { /*width: 688px;*/ margin: 12px 12px 12px 0; } +.rowElem > label { padding: 15px 0; width: 20%; } +.rowElem .topLabel { padding: 5px 12px 12px 0; width: 100%; } + +#valid input { position: relative; } + + +/* Inputs */ +.jqTransformInputWrapper { float: left; } +.jqTransformInputWrapper > div { width: 550px; } + +.mainForm input[type=text], .mainForm input[type=password], .mainForm textarea { font-size: 11px; padding: 4px 6px; background: white; border: 1px solid #DCE7EF; font-family: Arial, Helvetica, sans-serif; color: #656565; } +.mainForm input[type=text]:hover, .mainForm input[type=password]:hover, .mainForm textarea:hover { border-color: #DCE7EF; background: #fdfdfd; } +.mainForm input[type=text]:focus, .mainForm input[type=password]:focus, .mainForm textarea:focus { border-color: #DCE7EF; background: #fff; -webkit-box-shadow: 0 0 0 2px #F1F4FA; box-shadow: 0 0 0 2px #F1F4FA; -moz-box-shadow: 0 0 0 2px #F1F4FA; } + +.mainForm input[readonly], .mainForm input[disabled], .mainForm textarea[readonly], .mainForm textarea[disabled], .mainForm button[disabled] { background: #f5f5f5; border: 1px solid #DADADA; color: #aaa; } +.mainForm input[readonly]:hover, .mainForm input[disabled]:hover, .mainForm textarea[readonly]:hover, .mainForm textarea[disabled]:hover, .mainForm button[disabled]:hover { background: #f5f5f5; border: 1px solid #aaa; color: #aaa; cursor: not-allowed} +.mainForm input[readonly]:focus, .mainForm input[disabled]:focus, .mainForm textarea[readonly]:focus, .mainForm textarea[disabled]:focus, .mainForm button[disabled]:focus { background: #f5f5f5; border: 1px solid #aaa; color: #aaa; cursor: not-allowed} + +.mainForm input[type=text], .mainForm input[type=password], .mainForm textarea {width: 100%; box-sizing: content-box;} + +.multiple { width: 100%; padding: 5px; } + +.mainForm .select { font-size: 11px; background: white; border: 1px solid #DDD; width: 100%; font-family: Arial, Helvetica, sans-serif; box-shadow: 0 0 0 2px #f4f4f4; -webkit-box-shadow: 0 0 0 2px #f4f4f4; -moz-box-shadow: 0 0 0 2px #f4f4f4; color: #656565; } + +.submitForm { float: right; margin: 1px 14px 22px 14px; } + +.catalog_field {display: block; height: 30px; margin: 3px 0;} + + +.jqTransformInputWrapper_hover input{ background: #f6f6f6; } +.jqTransformInputWrapper_focus input { background: #f6f6f6; border: 1px solid #cad1d4; } + +.jqTransformSafari .jqTransformInputInner div { position: relative; overflow: hidden; margin:0px 8px; } +.jqTransformSafari .jqTransformInputInner div input { background: none; position: absolute; top: -10px; left: -2px; height: 42px; padding-left: 4px; } + +/* Radios */ +.jqTransformRadioWrapper {display:block; /*margin-top:5px; */ float: left; } +.jqTransformRadioWrapperNoFloat{ display:block; /*margin-top:6px;*/} +.jqTransformRadio { background: transparent url(../images/forms/radio.png) no-repeat 0 1px; vertical-align: middle; height: 16px; width: 16px; display: block; } + +/* Checkboxes */ +span.jqTransformCheckboxWrapper{ display:block; /*margin-top:6px;*/ } +span.jqTransformCheckboxWrapperFloat{ display:block; /*margin-top:6px;*/ float: left; } +a.jqTransformCheckbox { background: transparent url(../images/forms/checkbox.png) no-repeat 0 0px ; vertical-align: middle; height: 15px; width: 15px; display:block;/*display: -moz-inline-block;*/ } +a.jqTransformChecked { background-position: 0 bottom;} /* Checked - Used for both Radio and Checkbox */ +a.jqTransformCheckedDisable { background: transparent url(../images/forms/checkbox2.png) no-repeat 0 0px ;} /* Checked - Used for both Radio and Checkbox */ +a.jqTransformCheckedDisableCheck { background: transparent url(../images/forms/checkbox2.png) no-repeat; background-position: center bottom;} /* Checked - Used for both Radio and Checkbox */ + +.jqTransformHidden {display: none;} /* used to hide the original form elements */ + + +/* ===== List styles ===== */ +.list { } +.list .legend { display: block; font-weight: bold; padding-bottom: 4px; } +.list ul li { padding: 0 0 0 15px; } +.arrow2Grey ul li { background: url(../images/ui/arrow2Grey.png) no-repeat 1px 6px; } + +/* ===== Document actions ===== */ +.docaction {position: relative;} +.docaction .actions { position: absolute; top: 0px; right: 0px; display: none; } +.docaction .actions a { color: #fff; font-size: 11px; display: block; margin: 1px 2px; padding: 1px 1px; float: left; opacity: 0.5; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;} +.docaction .actions a:first-child { padding-right: 0; } + +.docaction .actions a.remarks { background: #ff0000; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; cursor: help; } +.docaction .actions a.public { background: #d90000; } +.docaction .actions a.recylce { background: #8c0000; } + +.doc_message { position: absolute; top: 0; left: 0;} +.doc_message .remarks { background: #ff0000; float: left; margin: 0 2px 0 0; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; cursor: help; } +.doc_message .public { background: #d90000; float: left; margin: 0 2px 0 0; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; cursor: help; } +.doc_message .recylce { background: #8c0000; float: left; margin: 0 2px 0 0; -webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px; cursor: help; } + +/* ===== Tooltip ===== */ +.tipsy { padding: 4px; font-size: 11px; position: absolute; z-index: 100000; opacity: 0.99; filter: alpha(opacity=99); } +.tipsy-inner { padding: 8px 14px 8px 14px; background-color: black; color: white; max-width: 250px; line-height: 14px; } +.tipsy-inner { border-radius: 3px; -moz-border-radius:3px; -webkit-border-radius:3px; } +.tipsy-arrow { position: absolute; background: url('../images/tipsy.gif') no-repeat top left; width: 9px; height: 5px; } +.tipsy-n .tipsy-arrow { top: 0; left: 50%; margin-left: -4px; } +.tipsy-nw .tipsy-arrow { top: 0; left: 10px; } +.tipsy-ne .tipsy-arrow { top: 0; right: 10px; } +.tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -4px; background-position: bottom left; } +.tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; background-position: bottom left; } +.tipsy-se .tipsy-arrow { bottom: 0; right: 10px; background-position: bottom left; } +.tipsy-e .tipsy-arrow { top: 50%; margin-top: -4px; right: 0; width: 5px; height: 9px; background-position: top right; } +.tipsy-w .tipsy-arrow { top: 50%; margin-top: -4px; left: 0; width: 5px; height: 9px; } + +/* ===== Messages page ===== */ +.messagesOne li { position: relative; min-height: 36px; margin: 0 18px 20px 18px; } +.messagesOne li:first-child { margin-top: 20px; } +.messagesOne > li.divider { border-top: 1px solid #DFDFDF!important; margin: 20px 0 20px 0!important; min-height: 0; } +.messagesOne > li.divider > span { background-color: #f5f5f5!important; } +.messagesOne .messageRow a { display: block; width: 37px; height: 36px; } + +.messagesOne .by_user > a, .messagesOne .by_me > a { position: absolute; top: 0; display: block; } +.messagesOne .by_user > a { left: 0; } +.messagesOne .by_me > a { right: 0; } + +.messagesOne .by_user .aro, .messagesOne .by_me .aro { width: 8px; height: 9px; position: absolute; top: 12px; } +.messagesOne .by_user .aro { background: url(../images/ui/messageArrow_left.png) no-repeat; left: -8px; } +.messagesOne .by_me .aro { background: url(../images/ui/messageArrow_right.png) no-repeat; right: -8px; } + +.messagesOne .by_user .messageArea, .messagesOne .by_me .messageArea { box-sizing: border-box; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -ms-box-sizing: border-box; padding: 8px 12px; position: relative; border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border: 1px solid; } +.messagesOne .by_user .messageArea { background: #fafeff; border-color: #b5cdd7; margin-left: 60px; } +.messagesOne .by_me .messageArea { background: #fefefe; border-color: #dcdcdc; margin-right: 60px; } + +.by_user .name > strong { color: #2c596d; } +.by_me .name > strong { color: #393939; } + +.infoRow { font-size: 11px; color: #949494; margin-bottom: 6px; margin-top: -2px; } +.infoRow > .time { float: right; } +.infoRow > .name { float: left; } + +/* ===== Dynamic table headers ===== */ +.table { margin-top: 40px; border: 1px solid #d5d5d5; border-top: none; } +.headTitle { background: #efefef url(../images/leftNavBg.png) repeat-x; height: 37px; border-bottom: 1px solid #d5d5d5; } + + +/* ===== Growl notifications ===== */ +div.jGrowl { z-index: 10; color: #fff; font-size: 11px; } + +div.ie6.top-right { + right: auto; + bottom: auto; + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.top-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.bottom-right { + left: expression( ( 0 - jGrowl.offsetWidth + ( document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.bottom-left { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 - jGrowl.offsetHeight + ( document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); +} + +div.ie6.center { + left: expression( ( 0 + ( ignoreMe2 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); + top: expression( ( 0 + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) ) + 'px' ); + width: 100%; +} + +/** Normal Style Positions **/ +div.jGrowl { position: absolute; } +body > div.jGrowl { position: fixed; z-index: 10000;} +div.jGrowl.top-left { left: 0px; top: 0px; } +div.jGrowl.top-right { right: 0px; top: 50px; } +div.jGrowl.bottom-left { left: 0px; bottom: 0px; } +div.jGrowl.bottom-right { right: 0px; bottom: 0px; } +div.jGrowl.center { top: 0px; width: 50%; left: 25%; } + +/** Cross Browser Styling **/ +div.center div.jGrowl-notification, div.center div.jGrowl-closer { margin-left: auto; margin-right: auto; } +div.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer { + background-color: #336699; + opacity: .95; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=85)"; + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=85); + zoom: 1; + min-width: 235px; + /*width: 235px;*/ + max-width: 500px; + padding: 10px; + margin-top: 5px; + margin-bottom: 5px; + font-family: Tahoma,Arial,Helvetica,sans-serif; + font-size: 1em; + text-align: left; + display: none; +} + +div.jGrowl div.error { background: #FF0000 url(../images/backgrounds/grey.png) !important;} +div.jGrowl div.accept { background: #00CC00 url(../images/backgrounds/grey.png) !important;} + +div.jGrowl div.jGrowl-notification { min-height: 25px; } +div.jGrowl div.jGrowl-notification, div.jGrowl div.jGrowl-closer { margin: 10px; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; -khtml-border-radius: 5px; } +div.jGrowl div.jGrowl-notification div.jGrowl-header { font-weight: normal; font-size: 1.3em; font-family: 'Cuprum', Arial, sans-serif; } +div.jGrowl div.jGrowl-notification div.jGrowl-close { z-index: 999; float: right; font-weight: bold; font-size: 1em; cursor: pointer; } +div.jGrowl div.jGrowl-closer { padding-top: 4px; padding-bottom: 4px; cursor: pointer; font-size: .9em; font-weight: bold; text-align: center; color: #fff;} + + +/** Hide jGrowl when printing **/ +@media print { div.jGrowl { display: none; } } + + +/* ===== Page scrolling ===== */ +#toTop { display:none; text-decoration:none; position:fixed; bottom:10px; right:10px; overflow:hidden; width:21px; height:21px; border:none; text-indent:-999px; background:url(../images/ui.totop.png) no-repeat left top; } +#toTopHover { background:url(../images/ui.totop.png) no-repeat left -22px; width:21px; height:21px; display:block; overflow:hidden; float:left; opacity: 0; -moz-opacity: 0; filter:alpha(opacity=0); } +#toTop:active, #toTop:focus { outline:none; } + + +/* ===== Single file input ===== */ +.feat { background: url(../images/forms/addFiles.png) no-repeat 0 0; width: 22px; height: 26px; margin: -1px 0 0px 5px !important; } +.feat:hover { background-position: 0 -27px; } +.feat:active { background-position: 0 -54px; } +.fileInput { background: #fff; font-size: 11px; font-family: Arial, Helvetica, sans-serif; padding: 4px 6px; border: 1px solid #B9CFDF; color: #656565; box-sizing: content-box; +-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 2px #F1F4FA; +-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 2px #F1F4FA; +box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 2px #F1F4FA; +} +.fileInput:hover { background: #fcfcfc; border: 1px solid #d1d1d1; } +.fileInput:focus { border: 1px solid #bbc1c9; background: #fff; } + + +/* ===== Error messages ===== */ +.messages{list-style:none;font:11px/11px Verdana, Arial, Tahoma;margin:0;padding:0;} +.messages li{-moz-box-shadow:0 1px 1px rgba(0,0,0,.05);-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05);position:relative;} +.highlight{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:8px;} +.highlight.grey{background:#fff url(../images/backgrounds/grey.png);border:1px solid #a8adb5;color:#a8adb5;} +.highlight.green{background:#d3f3c0 url(../images/backgrounds/grey.png);border:1px solid #a5d985;color:#557143;} +.highlight.yellow{background:#fff3c5 url(../images/backgrounds/grey.png);border:1px solid #ffe075;color:#937f38;} +.highlight.red{background:#ffe3e2 url(../images/backgrounds/grey.png);border:1px solid #efb1af;color:#c00;} + + +/* ===== Tabs ===== */ +ul.tabs { background: url(../images/leftNavBg.png) repeat-x; height: 36px; border-bottom: 1px solid #d5d5d5; border-top: 1px solid #d5d5d5; } +ul.tabs li { float: left; height: 36px; line-height: 36px; border-left: none; overflow: hidden; position: relative; background: url(../images/tabsSep.png) repeat-y 100% 0; font-size: 15px; } +ul.tabs li a { text-decoration: none; display: block; padding: 0px 12px; outline: none; color: #424242; } +ul.tabs li a:hover { color: #797979; } +html ul.tabs li.activeTab { background-color: #fafafa; height: 37px; } +html ul.tabs li.activeTab a { color: #797979; } + +.tab_container { /*overflow: hidden;*/ clear: both; float: left; width: 100%; } +.tab_content { padding: 0px 0px; } + +.tabsRight { position: relative; } +.tabsRight ul.tabs { float: right; background: url(../images/leftNavBg.png) repeat-x; height: 38px; border-bottom: 1px solid #d5d5d5; position: absolute; top: 0; right: 0; } + +ul.inact_tabs { background: url(../images/leftNavBg.png) repeat-x; height: 36px; border-bottom: 1px solid #d5d5d5; border-top: 1px solid #d5d5d5; } +ul.inact_tabs li { float: left; height: 36px; line-height: 36px; border-left: none; overflow: hidden; position: relative; background: url(../images/tabsSep.png) repeat-y 100% 0; font-size: 15px; } +ul.inact_tabs li a { text-decoration: none; display: block; padding: 0px 12px; outline: none; color: #424242; } +ul.inact_tabs li a:hover { color: #797979; } +html ul.inact_tabs li.activeTab { background-color: #fafafa; height: 37px; } +html ul.inact_tabs li.activeTab a { color: #797979; } + + +/* ===== Breadcrumbs ===== */ +.module:after { clear: both; content: "."; display: block; height: 0; visibility: hidden; } +* html .module { height: 1%; overflow: visible; } +* + html .module { min-height: 1%; } + +.breadCrumbHolder.module { border: solid 1px #D5D5D5; background: #FAFAFA; margin-top: 20px; } +.breadCrumb { float: left; display: block; height: 21px; overflow: hidden; width: 100%; padding: 5px; } +.breadCrumb ul { margin: 0; padding: 0; height: 21px; display: block; } +.breadCrumb ul li { display: block; float: left; position: relative; height: 21px; overflow: hidden; line-height: 21px; margin: 0px 6px 0px 0; padding: 0px 12px 0px 2px; /*font-size: .9167em; */background: url(../images/chevron.gif) no-repeat 100% 0; } +.breadCrumb ul li div.chevronOverlay { position: absolute; right: 0; top: 0; z-index: 2; } +.breadCrumb ul li span { display: block; overflow: hidden; } +.breadCrumb ul li > a { display: block; position: relative; height: 21px; line-height: 21px; overflow: hidden; float: left; } +.breadCrumb ul li.firstB a { height: 16px !important; text-indent:-1000em; width:16px; padding: 0; margin-top: 2px; overflow: hidden; background:url(../images/IconHome.gif) no-repeat 0 0; } +.breadCrumb ul li.firstB a:hover { background-position: 0 -16px; } +.breadCrumb ul li.lastB { background: none; margin-right: 0; padding-right: 0; } + +.grey_bg {background: url(../images/backgrounds/grey.png)} + +/* ========== Classes for collapsing ========== */ +.normal, .inactive { cursor: pointer; } +.normal, .accordion-close { border-bottom: none; } + +.standalone { float: left; width: 300px; margin-left: 40px; } +.standalone:first-child { margin-left: 0; } + + +/* ========== CMS Stats ========== */ +.cmsStats { font-size: 11px; font-weight: bold; padding: 2px 5px; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -khtml-border-radius: 3px;} +.cmsStatsAlert { font-size: 11px; font-weight: bold; padding: 2px 5px; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -khtml-border-radius: 3px;} + +/* ===== File uploader ===== */ +.plupload_button { font-size: 10px; font-weight: bold; text-transform: uppercase; color: #fff; line-height: 12px; margin-top: 3px; } + +.plupload_start { float: left; background: url(../images/ui/greenBtn.png) repeat-x 0 0; border: 1px solid #418d4f; } +.plupload_start span { background: url(../images/upload.png) no-repeat 10px; padding: 5px 13px 6px 26px; display: block; } +.plupload_start:hover { background-position: 0 -25px; } +.plupload_start:active { background-position: 0 -50px; } + +.plupload_disabled, a.plupload_disabled:hover { color: #a6a6a6; border: 1px solid #e9e9e9; background: url(../images/ui/uploadDisabled.png) repeat-x; cursor: default; } +.plupload_disabled span { padding: 5px 13px 6px 13px; } + +.plupload_add { margin-right: 10px; background: url(../images/ui/greyishBtn.png) repeat-x 0 0; border: 1px solid #4F5A68; float: left; } +.plupload_add span { background: url(../images/add.png) no-repeat 10px; padding: 5px 13px 6px 26px; display: block; } +.plupload_add:hover { background-position: 0 -25px; } +.plupload_add:active { background-position: 0 -50px; } + +.plupload_wrapper { font-size: 11px;; width: 100%; } + +.plupload_container { } +.plupload_container input { border: 1px solid #DDD; font-size: 11px; width: 98%; } + +.plupload_filelist { margin: 0; padding: 0; list-style: none; } +.plupload_scroll .plupload_filelist { height: 185px; background: #fafafa; overflow-y: scroll; } +.plupload_filelist li { padding: 10px 12px; background: whiteSmoke; border-bottom: 1px solid #E7E7E7; } +.plupload_filelist li:hover { background: #fdfdfd; } + +.plupload_filelist_header, .plupload_filelist_footer { background: #EFEFEF url(../images/leftNavBg.png) repeat-x; padding: 3px 12px; color: #878787; } +.plupload_filelist_header { border-bottom: 1px solid #d5d5d5; } + +.plupload_filelist_footer { border-top: 1px solid #D5D5D5; height: 31px; line-height: 30px; vertical-align: middle; } +.plupload_file_name { float: left; overflow: hidden; } +.plupload_file_status { color: #777; } +.plupload_file_status span {} +.plupload_file_size, .plupload_file_status, .plupload_progress { float: right; width: 80px; } +.plupload_file_size, .plupload_file_status, .plupload_file_action { text-align: right; } +.plupload_filelist .plupload_file_name { width: 205px; } +.plupload_file_action { float: right; width: 14px; margin-top: 3px; height: 14px; margin-left: 15px; } +.plupload_file_action * { display: none; width: 14px; height: 14px; } + +li.plupload_uploading { } +li.plupload_done { color: #AAA; } +li.plupload_delete a { background: url(../images/uploader/deleteFile.png) no-repeat 0; } +li.plupload_failed a { background: url(../images/uploader/error.png) no-repeat 0; cursor: default; } +li.plupload_done a { background: url(../images/uploader/uploaded.png) no-repeat 0; cursor: default; } + +.plupload_progress, .plupload_upload_status { display: none; } +.plupload_progress_container { margin-top: 10px; border: 1px solid #CCC; background: #FFF; padding: 1px; } +.plupload_progress_bar { width: 0px; height: 7px; background: #CDEB8B; } +.plupload_scroll .plupload_filelist_header .plupload_file_action, .plupload_scroll .plupload_filelist_footer .plupload_file_action { margin-right: 17px; } + +/* Floats */ + +.plupload_clear,.plupload_clearer { clear: both; } +.plupload_clearer, .plupload_progress_bar { display: block; font-size: 0; line-height: 0; } + +li.plupload_droptext { background: transparent; text-align: center; vertical-align: middle; border: 0; line-height: 165px; } + +/* ========== Sprite Icons ========== */ +.icon_sprite {display: block; width: 14px; height: 14px; background: url(../images/sprites.gif) no-repeat; margin: 2px; padding: 0px;} + +.ico_blanc {background-position: 0px 0px; background-repeat:no-repeat;} + +.ico_add {background-position: -14px 0px; background-repeat:no-repeat;} +.ico_ok {background-position: 0px -14px; background-repeat:no-repeat;} + +.ico_ok_green {background-position: -42px 0px; background-repeat:no-repeat;} + +.ico_install {background-position: -28px -28px; background-repeat:no-repeat;} +.ico_globus {background-position: -28px 0px; background-repeat:no-repeat;} +.ico_globus_no {background-position: -42px -112px; background-repeat:no-repeat;} +.ico_look {background-position: -28px -168px; background-repeat:no-repeat;} +.ico_photo {background-position: -42px -98px; background-repeat:no-repeat;} +.ico_query {background-position: -28px -56px; background-repeat:no-repeat;} +.ico_query_no {background-position: -42px -70px; background-repeat:no-repeat;} +.ico_reinstall {background-position: -28px -70px; background-repeat:no-repeat;} +.ico_start {background-position: -28px -98px; background-repeat:no-repeat;} +.ico_stop {background-position: -28px -112px; background-repeat:no-repeat;} +.ico_list {background-position: -28px -140px; background-repeat:no-repeat;} +.ico_attach {background-position: -42px -140px; background-repeat:no-repeat;} +.ico_lines {background-position: -28px -154px; background-repeat:no-repeat;} + +.ico_copy {background-position: 0px -42px; background-repeat:no-repeat;} +.ico_copy_no {background-position: -14px -42px; background-repeat:no-repeat;} + +.ico_delete {background-position: 0px -56px; background-repeat:no-repeat;} +.ico_delete_no {background-position: -14px -56px; background-repeat:no-repeat;} + +.ico_edit {background-position: 0px -69px; background-repeat:no-repeat;} +.ico_edit_no {background-position: -14px -69px; background-repeat:no-repeat;} + +.ico_comment {background-position: 0px -28px; background-repeat:no-repeat;} +.ico_comment_no {background-position: -14px -28px; background-repeat:no-repeat;} + +.ico_info {background-position: 0px -84px; background-repeat:no-repeat;} +.ico_info_no {background-position: -14px -84px; background-repeat:no-repeat;} + +.ico_lock {background-position: 0px -98px; background-repeat:no-repeat;} +.ico_lock_no {background-position: -14px -98px; background-repeat:no-repeat;} + +.ico_navigation {background-position: 0px -112px; background-repeat:no-repeat;} +.ico_navigation_no {background-position: -14px -112px; background-repeat:no-repeat;} + +.ico_setting {background-position: 0px -126px; background-repeat:no-repeat;} +.ico_setting_no {background-position: -14px -126px; background-repeat:no-repeat;} + +.ico_shop {background-position: 0px -140px; background-repeat:no-repeat;} +.ico_shop_no {background-position: -14px -140px; background-repeat:no-repeat;} + +.ico_template {background-position: 0px -154px; background-repeat:no-repeat;} +.ico_template_no {background-position: -14px -154px; background-repeat:no-repeat;} + +.ico_log {background-position: -28px -154px; background-repeat:no-repeat;} + +.ico_unlock {background-position: 0px -168px; background-repeat:no-repeat;} +.ico_unlock_no {background-position: -14px -168px; background-repeat:no-repeat;} + +.ico_recylce {background-position: 0px -182px; background-repeat:no-repeat;} +.ico_recylce_on {background-position: -14px -182px; background-repeat:no-repeat;} +.ico_recylce_no {background-position: -28px -182px; background-repeat:no-repeat;} + +.ico_move {background-position: 0px -211px; background-repeat:no-repeat;} +.ico_move_no {background-position: -14px -211px; background-repeat:no-repeat;} + +.icon_sprite_doc {display: block; width: 16px; height: 16px; background: url(../images/sprites_doc.png) no-repeat; padding: 0px;} + +.icon_copy {background-position: 0px -48px; background-repeat:no-repeat;} +.icon_edit {background-position: 0px 0px; background-repeat:no-repeat;} +.icon_delete {background-position: -16px -32px; background-repeat:no-repeat;} +.icon_comment {background-position: -16px 0px; background-repeat:no-repeat;} +.icon_public {background-position: 0px -112px; background-repeat:no-repeat;} +.icon_public_on {background-position: -16px -112px; background-repeat:no-repeat;} +.icon_recylce {background-position: 0px -96px; background-repeat:no-repeat;} +.icon_recylce_on {background-position: -16px -96px; background-repeat:no-repeat;} + +.image_field {max-width: 128px; max-height: 128px; margin: 10px 0;} + +/* ===== Footer ===== */ +#footer { clear: both; /*height: 36px;*/ background: url(../images/topNav.jpg) repeat; width: 100%; color: #eeeeee; margin-top: 42px; position: absolute; bottom: 0; } +#footer span { color: #696969; padding: 9px 5px; display: block; font-size: 11px; } +#footer span a { color: #eeeeee; } + +/* ===== Form validation ===== */ +.inputContainer { position: relative; float: left; } +.formError { position: absolute; top: 300px; left: 280px; display: block; z-index: 5000; cursor: pointer; } +.ajaxSubmit { padding: 20px; background: #55ea55; border: 1px solid #999; display: none; } + +#customWidget { position: relative; height: 36px; } + +.code { background-color: #e8f2ff; color: rgba(0, 0, 0, 0.75); padding: 1px 3px; } +.code_red { background-color: #ff0000; color: rgba(255, 255, 255, 0.75); padding: 1px 5px; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px;} + +.ac_results { padding: 0px; border: 1px solid black; background-color: white; overflow: hidden; z-index: 99999; } +.ac_results ul { width: 100%; list-style-position: outside; list-style: none; padding: 0; margin: 0; } +.ac_results li { margin: 0px; padding: 2px 5px; cursor: default; display: block; overflow: hidden; line-height: 14px; } +.ac_loading { background: white url('../images/loading.gif') right center no-repeat!important; } +.ac_odd { background-color: #eee; } +.ac_over { background-color: #336699; color: white; } +.ac_results li span.name { display: block; } +.ac_results li span.login { display: block; } +.ac_results li span.email { display: block; } +.ac_results li strong { border-bottom: 1px dotted; } + +/* == Dialog == */ +#jboxOverlay{width:100%;height:100%;position:fixed;top:0;left:0;z-index:1000;background: -moz-linear-gradient(rgba(11,11,11,0.1), rgba(11,11,11,0.6)) repeat-x rgba(11,11,11,0.2);background:-webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(11,11,11,0.1)), to(rgba(11,11,11,0.6))) repeat-x rgba(11,11,11,0.2);filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a6000000', endColorstr='#a6000000',GradientType=0 )} +#jboxInner{background:#fafafa;border-radius:5px;box-shadow:0 1px 3px rgba(0,0,0,.2);border:4px solid #444;position:fixed;min-width:200px;min-height:50px;max-width:95%;max-height:95%;color:#333;overflow:auto} +#jboxInner .title{background-color: #e5e5e5;background-image:-webkit-gradient(linear, left top, left bottom, from(rgb(235, 235, 235)), to(rgb(229, 229, 229)));background-image: -webkit-linear-gradient(top, rgb(235, 235, 235), rgb(229, 229, 229));background-image: -moz-linear-gradient(top, rgb(235, 235, 235), rgb(229, 229, 229)); background-image: -o-linear-gradient(top, rgb(235, 235, 235), rgb(229, 229, 229)); background-image: -ms-linear-gradient(top, rgb(235, 235, 235), rgb(229, 229, 229)); background-image: linear-gradient(top, rgb(235, 235, 235), rgb(229, 229, 229)); filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#ebebeb', EndColorStr='#e5e5e5');border-top: 1px solid #fafafa; border-top-left-radius: 1px; border-top-right-radius: 1px; padding:8px 10px;font-size:16px;text-shadow:0px 1px 0px #fff; cursor: move;font-family:MavenProRegular} +#jboxInner .body{color:#333;padding:10px} +#jboxInnerButtons{ text-align:center; padding-top: 10px; padding-right: 0; padding-bottom: 10px; padding-left: 0; } +#jboxInner .button{border-radius:3px; -moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.5); -webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.5); box-shadow:inset 0 1px 0 rgba(255,255,255,0.5); cursor:pointer; display:inline-block; outline:none!important; text-align:center; text-decoration:none; -moz-box-sizing:border-box!important; line-height:16px; font-family:MavenProRegular, Arial, Helvetica, sans-serif; font-size:13px; text-shadow:1px -1px 0 rgba(000,000,000,0.3); box-shadow:inset 0px 1px 0px 0px #ffffff; background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #f9f9f9), color-stop(1, #e9e9e9) ); background:-moz-linear-gradient( center top, #f9f9f9 5%, #e9e9e9 100% ); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f9f9f9', endColorstr='#e9e9e9');background-color:#f9f9f9; border:1px solid #bbb; color:#666; text-shadow:1px 1px 0px #fff; margin-right: 5px; margin-left: 5px; padding-top: 5px; padding-right: 15px; padding-bottom: 5px; padding-left: 15px} +#jboxInner .button:hover{background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #e9e9e9), color-stop(1, #f9f9f9) );background:-moz-linear-gradient( center top, #e9e9e9 5%, #f9f9f9 100% );filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e9e9e9', endColorstr='#f9f9f9');background-color:#e9e9e9;text-decoration:none;} +#jboxInner .button.yes{color:#fef4e9;border:solid 1px #da7c0c;background-color:#f78d1d;background:-webkit-gradient(linear, left top, left bottom, from(#faa51a), to(#f47a20));background:-moz-linear-gradient(top, #faa51a, #f47a20);text-decoration:none;text-shadow:1px -1px 0 rgba(000,000,000,0.3); filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#faa51a', endColorstr='#f47a20')} +#jboxInner .button.yes:hover,#jboxInner .button.yes:focus{background-color:#f47c20;background:-webkit-gradient(linear, left top, left bottom, from(#f88e11), to(#f06015));background:-moz-linear-gradient(top, #f88e11, #f06015);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f88e11', endColorstr='#f06015');text-decoration:none;color:#fff} +#jboxInner .button.yes.last{margin-left:55px} + +.fixedBtn { position:fixed; bottom: 0; background: #fff; -webkit-box-shadow: 0px -3px 5px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px -3px 5px 0px rgba(0, 0, 0, 0.2); padding: 8px 9px; margin-left: -10px; z-index: 1000;} + +.jq-selectbox +{ + cursor:pointer; + vertical-align: top; +} + +.jq-selectbox__select +{ + behavior:url(/PIE.php); + padding: 0 20px 0 10px; + overflow: hidden; + height: 20px; + border-radius: 0px; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #B9CFDF; + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 2px #F1F4FA; + -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 2px #F1F4FA; + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 0 2px #F1F4FA; + color: #444; + text-decoration: none; + white-space: nowrap; + font-size: 11px; + line-height: 20px; +} + +.jq-selectbox__select:hover +{ + background-color:#E6E6E6; + background-position:0 -10px; +} + +.jq-selectbox__select:active +{ + background:#F5F5F5; +} + +.jq-selectbox.focused .jq-selectbox__select +{ + border:1px solid #5794BF; +} + +.jq-selectbox.disabled .jq-selectbox__select +{ + border-color:#CCC; + background:#F5F5F5; + color:#888; +} + +.jq-selectbox__select-text +{ + display:block; + width:100%; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + min-width: 30px; +} + +.jq-selectbox__trigger +{ + position:absolute; + top:0; + right:0; + width:24px; + height:100%; +} + +.jq-selectbox__trigger-arrow +{ + position:absolute; + top:10px; + right:12px; + width:0; + height:0; + overflow:hidden; + border-top:3px solid #000; + border-right:3px solid transparent; + border-left:3px solid transparent; + opacity:.3; + filter:alpha(opacity=30); +} + +.jq-selectbox:hover .jq-selectbox__trigger-arrow +{ + opacity:1; + filter:alpha(opacity=100); +} + +.jq-selectbox.disabled .jq-selectbox__trigger-arrow +{ + opacity:.3; + filter:alpha(opacity=30); +} + +.jq-selectbox__dropdown +{ + behavior:url(/PIE.php); + z-index:5000; + top:22px; + margin:0; + padding:0; + width: 100%; + /*border:1px solid #C6CBD0;*/ + background:#FFF; + font-size: 11px; + line-height: 20px; + box-shadow: 0 2px 10px rgba(0,0,0,0.2); + max-height: 120px !important; +} + +.jq-selectbox ul +{ + margin:0; + padding:0; +} + +.jq-selectbox li +{ + padding: 2px 8px; + text-decoration: none; + color: #333; + background-color: #fff; + font-size: 11px; + +} + +.jq-selectbox li.selected +{ + background:#666666; + color:#FFF; +} + +.jq-selectbox li:hover +{ + background:#336699; + color:#FFF; +} + +.jq-selectbox li.disabled +{ + color:#AAA; +} + +.jq-selectbox li.disabled:hover +{ + background:none; +} + +.jq-selectbox li.optgroup +{ + font-weight:700; +} + +.jq-selectbox li.optgroup:hover +{ + background:none; + color:#231F20; + cursor:default; +} + +.jq-selectbox li.option +{ + padding-left:25px; +} + + +.jq-select-multiple { + -moz-box-sizing: border-box; + box-sizing: border-box; + padding: 1px; + border: 1px solid #CCC; + border-bottom-color: #B3B3B3; + border-radius: 4px; + box-shadow: inset 1px 1px #F1F1F1, 0 1px 2px rgba(0,0,0,0.1); + background: #FFF; + color: #333; + font: 14px/18px Arial, sans-serif; + cursor: default; +} +.jq-select-multiple.focused { + border: 1px solid #5794BF; +} +.jq-select-multiple.disabled { + border-color: #CCC; + background: #F5F5F5; + box-shadow: none; + color: #888; +} +.jq-select-multiple ul { + margin: 0; + padding: 0; +} +.jq-select-multiple li { + padding: 3px 9px 4px; + list-style: none; +} +.jq-select-multiple li:first-child { + border-radius: 3px 3px 0 0; +} +.jq-select-multiple li:last-child { + border-radius: 0 0 3px 3px; +} +.jq-select-multiple li.selected { + background: #08C; + color: #FFF; +} +.jq-select-multiple li.disabled { + color: #AAA; +} +.jq-select-multiple.disabled li.selected, +.jq-select-multiple li.selected.disabled { + background: #CCC; + color: #FFF; +} +.jq-select-multiple li.optgroup { + font-weight: bold; +} +.jq-select-multiple li.option { + padding-left: 25px; +} +.jq-select-multiple li.first { + margin-top: 0px !important; +} + + +/* +.NFI-wrapper {} +.NFI-button {} +.NFI-button:hover {} +.NFI-filename {} +.NFI-current {} +*/ + +.nice { + font-family: arial; + font-size: 12px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +.nice .NFI-button { + -moz-border-radius-topleft: 3px; + -moz-border-radius-bottomleft: 3px; + -webkit-border-top-left-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + + background-color: #0192DD; + + background-image: linear-gradient(bottom, #1774A3 0%, #0194DD 56%); + background-image: -o-linear-gradient(bottom, #1774A3 0%, #0194DD 56%); + background-image: -moz-linear-gradient(bottom, #1774A3 0%, #0194DD 56%); + background-image: -webkit-linear-gradient(bottom, #1774A3 0%, #0194DD 56%); + background-image: -ms-linear-gradient(bottom, #1774A3 0%, #0194DD 56%); + background-image: -webkit-gradient( + linear, + left bottom, + left top, + color-stop(0, #1774A3), + color-stop(0.56, #0194DD) + ); + text-shadow: 0px -1px 0px #0172bd; + border: solid #0172bd 1px; + border-bottom: solid #00428d 1px; + + -webkit-box-shadow: inset 0px 1px 0px rgba(255,255,255,.2); + -moz-box-shadow: inset 0px 1px 0px rgba(255,255,255,.2); + box-shadow: inset 0px 1px 0px rgba(255,255,255,.2); + + color: #fff; + width: 100px; + height: 24px; + line-height: 24px; +} + +.nice .NFI-button:hover { + background: #333; + text-shadow: 0px -1px 0px #111; + border: solid #000 1px; +} + +.nice .NFI-filename { + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + + width: 200px !important; + border: solid #777 1px; + border-left: none; + height: 24px; + line-height: 24px; + + background: #fff; + -webkit-box-shadow: inset 0px 2px 0px rgba(0,0,0,.05); + -moz-box-shadow: inset 0px 2px 0px rgba(0,0,0,.05); + box-shadow: inset 0px 2px 0px rgba(0,0,0,.05); + + color: #777; + text-shadow: 0px 1px 0px #fff; + box-sizing: none; +} + +/* Make clicks pass-through */ +#nprogress { + pointer-events: none; +} + +#nprogress .bar { + background: #0194DD; + + position: fixed; + z-index: 1031; + top: 0; + left: 0; + + width: 100%; + height: 2px; +} + +/* Fancy blur effect */ +#nprogress .peg { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #0194DD, 0 0 5px #0194DD; + opacity: 1.0; + + -webkit-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} + +/* Remove these to get rid of the spinner */ +#nprogress .spinner { + display: block; + position: fixed; + z-index: 1031; + top: 10px; + right: 10px; +} + +#nprogress .spinner-icon { + width: 18px; + height: 18px; + box-sizing: border-box; + + border: solid 2px transparent; + border-top-color: #0194DD; + border-left-color: #0194DD; + border-radius: 50%; + + -webkit-animation: nprogress-spinner 400ms linear infinite; + animation: nprogress-spinner 400ms linear infinite; +} + +@-webkit-keyframes nprogress-spinner { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } +} +@keyframes nprogress-spinner { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +.position { + display: inline-block ! important; +} + +.position_value { + display: inline-block ! important; + width: 40px ! important; + text-align: center ! important; +} + +.q_buttons{ + float: right; + display: inline-block; + width: 22px; + height: 24px; + margin-left: 0; + position: relative; + z-index: 1; +} + +.q_button{ + display: block; + width: 10px; + height: 10px; + vertical-align: middle; + line-height: 10px; + text-align: center; + border: 1px solid #cccccc; + border-radius: 1px; + font-size: 8px; + cursor: pointer; + color: #000000; + background: #ffffff; + position: relative; + z-index: 1; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.q_submit{ + display: block; + float: right; + width: 26px; + text-indent: 0; + padding: 0; + height: 22px; + vertical-align: middle; + line-height: 21px; + text-align: center; + border: 1px solid #cccccc; + border-radius: 1px; + font-size: 8px; + cursor: pointer; + color: #000000; + background: #ffffff; + position: absolute; + z-index: 2; + top: 0; + left: 20px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +.q_loading{ + background: url('../images/loader2.gif') center center no-repeat; + display: block; + float: right; + width: 26px; + text-indent: 0; + padding: 0; + height: 22px; + vertical-align: middle; + line-height: 21px; + text-align: center; + border: 1px solid transparent; + border-radius: 1px; + font-size: 8px; + cursor: pointer; + color: #000000; + position: absolute; + z-index: 1; + top: 0; + left: 12px; +} + +.q_button:hover, .q_submit:hover{ + background: #595959; + color: #ffffff; +} + +.q_button:active, .q_submit:active{ + background: #ffffff; + color: #000000; +} + +.jq-selectbox__search { + margin: 5px; +} + +.jq-selectbox__search { + margin: 5px; +} + +.jq-selectbox__search input { + box-sizing: border-box; + width: 100%; + margin: 0; + padding: 5px 27px 6px 8px; + border: 1px solid #CCC; + border-radius: 3px; + outline: none; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAAGXRFW…V6u2aoSqBZD/lDrNWRJynLK2qpBn4rc6K2XB9/Nb8EGABtf1thzY6X2AAAAABJRU5ErkJggg==) no-repeat 100% 50%; + box-shadow: inset 1px 1px #F1F1F1; + color: #333; +} + +.jq-selectbox, +.jq-select-multiple { + position: relative; + display: inline-block; +} +.jq-selectbox select, +.jq-select-multiple select { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + opacity: 0; +} +.jq-selectbox li, +.jq-select-multiple li { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + white-space: nowrap; +} +.jq-selectbox { + z-index: 10; +} +.jq-selectbox__select { + position: relative; +} +.jq-selectbox__select-text { + overflow: hidden; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + white-space: nowrap; + text-overflow: ellipsis; +} +.jq-selectbox__dropdown { + position: absolute; +} +.jq-selectbox__search input { + -webkit-appearance: textfield; +} +.jq-selectbox__search input::-webkit-search-cancel-button, +.jq-selectbox__search input::-webkit-search-decoration { + -webkit-appearance: none; +} +.jq-selectbox__dropdown ul { + position: relative; + overflow: auto; + overflow-x: hidden; + list-style: none; + -webkit-overflow-scrolling: touch; +} +.jq-select-multiple ul { + position: relative; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; +} \ No newline at end of file diff --git a/admin/templates/css/nestable.css b/admin/templates/css/nestable.css new file mode 100644 index 0000000..89a6088 --- /dev/null +++ b/admin/templates/css/nestable.css @@ -0,0 +1,228 @@ +/** + * Nestable + */ + +.dd { position: relative; display: block; margin: 0; padding: 0; max-width: 100%; list-style: none; line-height: 20px; } + +.dd-list { display: block; position: relative; margin: 0; padding: 0; list-style: none; } +.dd-list .dd-list { padding-left: 30px; } +.dd-collapsed .dd-list { display: none; } + +.dd-item, +.dd-empty, +.dd-placeholder { display: block; position: relative; margin: 0; padding: 0; min-height: 20px; line-height: 20px; } + +.dd-handle { display: block; height: 30px; margin: 5px 0; padding: 5px 10px; color: #333; text-decoration: none; border: 1px solid #ccc; + background: #fafafa; + background: -webkit-linear-gradient(top, #fafafa 0%, #eee 100%); + background: -moz-linear-gradient(top, #fafafa 0%, #eee 100%); + background: linear-gradient(top, #fafafa 0%, #eee 100%); + -webkit-border-radius: 3px; + border-radius: 3px; + box-sizing: border-box; -moz-box-sizing: border-box; +} +.dd-handle:hover { color: #2ea8e5; background: #fff; } + +.dd-item > button { display: block; position: relative; cursor: pointer; float: left; width: 25px; height: 20px; margin: 5px 0; padding: 0; text-indent: 100%; white-space: nowrap; overflow: hidden; border: 0; background: transparent; font-size: 12px; line-height: 1; text-align: center; font-weight: bold; } +.dd-item > button:before { content: '+'; display: block; position: absolute; width: 100%; text-align: center; text-indent: 0; } +.dd-item > button[data-action="collapse"]:before { content: '-'; } + +.dd-placeholder, +.dd-empty { margin: 5px 0; padding: 0; min-height: 30px; background: #f2fbff; border: 1px dashed #b6bcbf; box-sizing: border-box; -moz-box-sizing: border-box; } +.dd-empty { border: 1px dashed #bbb; min-height: 100px; background-color: #e5e5e5; + background-image: -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), + -webkit-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); + background-image: -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), + -moz-linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); + background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), + linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); + background-size: 60px 60px; + background-position: 0 0, 30px 30px; +} + +.dd-dragel { position: absolute; pointer-events: none; z-index: 9999; } +.dd-dragel > .dd-item .dd-handle { margin-top: 0; } +.dd-dragel .dd-handle { + -webkit-box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1); + box-shadow: 2px 4px 6px 0 rgba(0,0,0,.1); +} + +/** + * Nestable Extras + */ + +.nestable-lists { display: block; clear: both; padding: 30px 0; width: 100%; border: 0; border-top: 2px solid #ddd; border-bottom: 2px solid #ddd; } + +#nestable-menu { padding: 0; margin: 20px 0; } + +#nestable-output, +#nestable2-output { width: 100%; height: 7em; font-size: 0.75em; line-height: 1.333333em; font-family: Consolas, monospace; padding: 5px; box-sizing: border-box; -moz-box-sizing: border-box; } + +#nestable2 .dd-handle { + color: #fff; + border: 1px solid #999; + background: #edf2f7; + background: -webkit-linear-gradient(top, #edf2f7 0%, #999 100%); + background: -moz-linear-gradient(top, #edf2f7 0%, #999 100%); + background: linear-gradient(top, #edf2f7 0%, #999 100%); +} +#nestable2 .dd-handle:hover { background: #edf2f7; } +#nestable2 .dd-item > button:before { color: #fff; } + +@media only screen and (min-width: 700px) { + + .dd { float: left; width: 100%; } + .dd + .dd { margin-left: 2%; } + +} + +.dd-hover > .dd-handle { background: #edf2f7 !important; } + +/** + * Nestable Draggable Handles + */ + +.dd3-content { display: block; height: 30px; margin: 5px 0; padding: 4px 10px 5px 40px; color: #333; text-decoration: none; font-weight: normal; border: 1px solid #d9dee9; + background: #edf2f7; + -webkit-border-radius: 3px; + border-radius: 3px; + box-sizing: border-box; -moz-box-sizing: border-box; +} +.dd3-content:hover { color: #2ea8e5; background: #fff; } + +.dd3-content .action { + position: absolute; + width: 40px; + z-index: 100; + top: 6px; + right: 10px; + border-left: 1px solid #e3e3e3; + height: 18px; + overflow: hidden; + position: absolute; + padding-left: 10px; +} + +.dd3-content .status { + position: absolute; + width: 40px; + z-index: 100; + top: 6px; + right: 50px; + border-left: 1px solid #e3e3e3; + height: 18px; + overflow: hidden; + position: absolute; + padding-left: 10px; +} + +.dd3-content .url { + position: absolute; + width: 40px; + z-index: 100; + top: 6px; + right: 90px; + border-left: 1px solid #e3e3e3; + height: 18px; + overflow: hidden; + position: absolute; + padding-left: 10px; +} + + +.dd3-content .document { + position: absolute; + width: 350px; + z-index: 100; + top: 6px; + right: 150px; + border-left: 1px solid #e3e3e3; + height: 18px; + overflow: hidden; + position: absolute; + padding-left: 10px; +} + +.dd3-content .document_id { + position: absolute; + width: 50px; + z-index: 100; + top: 6px; + right: 700px; + border-left: 1px solid #e3e3e3; + height: 18px; + overflow: hidden; + position: absolute; + padding-left: 10px; +} + +.dd3-content .icon_sprite { + display: inline-block; +} + +.dd3-content.level-1 { + background: #e3ebf2 url(../images/backgrounds/grey.png) !important; + border-color: #d9dee9 !important; + color: #6086AB !important +} + +.dd3-content.level-3 { + background:#fff3c5 url(../images/backgrounds/grey.png) !important; + border-color:#ffe075 !important; + color:#937f38 !important; +} + +.dd3-content.level-2 { + background: #c9e5b9 url(../images/backgrounds/grey.png) !important; + border-color: #a5d985 !important; + color: #557143 !important +} + +.dd3-content.level-3 { + background:#fff3c5 url(../images/backgrounds/grey.png) !important; + border-color:#ffe075 !important; + color:#937f38 !important; +} + +.dd3-content.red { + background:#ffe3e2 url(../images/backgrounds/grey.png) !important; + border-color:#efb1af !important; + color:#c00 !important; +} + +.dd3-content.green { + background:#d3f3c0 url(../images/backgrounds/grey.png) !important; + border-color:#a5d985 !important; + color:#557143 !important; +} + +.dd3-content.yellow { + background:#ffe075 url(../images/backgrounds/grey.png) !important; + border-color:#ffe075 !important; + color:#937f38 !important; +} + +.dd3-content.grey { + background:#ffe3e2 url(../images/backgrounds/grey.png) !important; + border-color:#efb1af !important; + color:#c00 !important; +} + +.dd-dragel > .dd3-item > .dd3-content { margin: 0; } + +.dd3-item > button { margin-left: 30px; } + +.dd3-handle { position: absolute; margin: 0; left: 0; top: 0; cursor: pointer; width: 30px; text-indent: 100%; white-space: nowrap; overflow: hidden; + border: 1px solid #373840; + background: #373840; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + color: #696969; +} +.dd3-handle:before { content: '≡'; display: block; position: absolute; left: 0; top: 3px; width: 100%; text-align: center; text-indent: 0; font-size: 20px; font-weight: normal; } +.dd3-handle:hover { background: #373840; color: #fff;} + + +ol.dd-list li ol.dd-list { + background:transparent url(../images/level.png) 1px 0px repeat-y; +} diff --git a/admin/templates/css/reset.css b/admin/templates/css/reset.css new file mode 100644 index 0000000..936b784 --- /dev/null +++ b/admin/templates/css/reset.css @@ -0,0 +1,133 @@ + +/* ===== CSS reset ===== */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } +ol, ul { list-style: none; } +blockquote, q { quotes: none; } +blockquote:before, blockquote:after, +q:before, q:after { content: ''; content: none; } +/* remember to define focus styles! */ +:focus { outline: 0; } +/* remember to highlight inserts somehow! padding: 9px 17px 9px 17px; */ +ins { text-decoration: none; } +del { text-decoration: line-through; } +/* tables still need 'cellspacing="0"' in the markup */ +table { border-collapse: collapse; } +*, * focus { + outline: none; + margin: 0; + padding: 0; +} +textarea { overflow: auto; } +textarea, input[type=text], input[type=password] { font-family: Arial, Helvetica, sans-serif; font-size: 11px; } +button, input[type=submit] { font-family: Arial, Helvetica, sans-serif; } + +img { border: 0; } +ul { list-style: none; margin: 0; padding: 0; } +p { margin: 0; padding: 0; } +:focus { outline: 0; } +a { text-decoration: none; } + +.normal { font-style: normal; } +.normalFont { font-style: normal; font-weight: normal; } + + +/* ========== Correction classes ========== */ +.mt40 { margin-top: 40px; } + +.nomargin { margin: 0!important; } + +/* + Correction margins + */ +.m10 { margin: 10px 0; } +.m15 { margin: 15px 0; } +.m20 { margin: 20px 0; } + +.mr5 { margin-right: 5px; } +.mr10 { margin-right: 10px; } +.mr15 { margin-right: 15px; } +.mr20 { margin-right: 20px; } +.mr25 { margin-right: 25px; } +.mr30 { margin-right: 30px; } + +.mb0 { margin-bottom: 0; } +.mb5 { margin-bottom: 5px; } +.mb10 { margin-bottom: 10px; } +.mb15 { margin-bottom: 15px; } +.mb20 { margin-bottom: 20px; } +.mb22 { margin-bottom: 22px!important; } +.mb25 { margin-bottom: 25px; } +.mb30 { margin-bottom: 30px; } +.mb40 { margin-bottom: 40px; } + + +.mt0 { margin-top: 0; } +.mt5 { margin-top: 5px; } +.mt10 { margin-top: 10px; } +.mt12 { margin-top: 12px; } +.mt15 { margin-top: 15px; } +.mt20 { margin-top: 20px; } +.mt22 { margin-top: 22px!important; } +.mt25 { margin-top: 25px; } +.mt30 { margin-top: 30px; } + + +.ml5 { margin-left: 5px; } +.ml10 { margin-left: 10px; } +.ml15 { margin-left: 15px; } +.ml20 { margin-left: 20px; } +.ml25 { margin-left: 25px; } +.ml30 { margin-left: 30px; } + + +.mr5 { margin-right: 5px; } +.mr10 { margin-right: 10px; } +.mr15 { margin-right: 15px; } +.mr20 { margin-right: 20px; } +.mr25 { margin-right: 25px; } +.mr30 { margin-right: 30px; } + + + +/* + Correction paddings + */ +.pb0 { padding-bottom: 0!important; } +.pb5 { padding-bottom: 5px; } +.pb10 { padding-bottom: 10px; } +.pb15 { padding-bottom: 15px; } +.pb20 { padding-bottom: 20px; } +.pb25 { padding-bottom: 25px; } +.pb30 { padding-bottom: 30px; } + +.pt0 { padding-top: 0; } +.pt5 { padding-top: 5px; } +.pt10 { padding-top: 10px; } +.pt15 { padding-top: 15px; } +.pt20 { padding-top: 20px; } +.pt25 { padding-top: 25px; } +.pt30 { padding-top: 30px; } + + +input::-moz-focus-inner /*Remove button padding in FF*/ +{ + border: 0; + padding: 0; +} + +button::-moz-focus-inner /*Remove button padding in FF*/ +{ + border: 0; + padding: 0; +} + +a.button::-moz-focus-inner /*Remove button padding in FF*/ +{ + border: 0; + padding-top: 20px; +} \ No newline at end of file diff --git a/admin/templates/css/theme_color_default/alert-opacity-overlay.png b/admin/templates/css/theme_color_default/alert-opacity-overlay.png new file mode 100644 index 0000000..ffc7286 Binary files /dev/null and b/admin/templates/css/theme_color_default/alert-opacity-overlay.png differ diff --git a/admin/templates/css/theme_color_default/checkbox.png b/admin/templates/css/theme_color_default/checkbox.png new file mode 100644 index 0000000..80656e5 Binary files /dev/null and b/admin/templates/css/theme_color_default/checkbox.png differ diff --git a/admin/templates/css/theme_color_default/checkbox2.png b/admin/templates/css/theme_color_default/checkbox2.png new file mode 100644 index 0000000..053fb16 Binary files /dev/null and b/admin/templates/css/theme_color_default/checkbox2.png differ diff --git a/admin/templates/css/theme_color_default/fancy.png b/admin/templates/css/theme_color_default/fancy.png new file mode 100644 index 0000000..72fe62a Binary files /dev/null and b/admin/templates/css/theme_color_default/fancy.png differ diff --git a/admin/templates/css/theme_color_default/field.png b/admin/templates/css/theme_color_default/field.png new file mode 100644 index 0000000..0a9dba4 Binary files /dev/null and b/admin/templates/css/theme_color_default/field.png differ diff --git a/admin/templates/css/theme_color_default/left-menu-show.png b/admin/templates/css/theme_color_default/left-menu-show.png new file mode 100644 index 0000000..b90b1d7 Binary files /dev/null and b/admin/templates/css/theme_color_default/left-menu-show.png differ diff --git a/admin/templates/css/theme_color_default/message-arrow-left.png b/admin/templates/css/theme_color_default/message-arrow-left.png new file mode 100644 index 0000000..45f5250 Binary files /dev/null and b/admin/templates/css/theme_color_default/message-arrow-left.png differ diff --git a/admin/templates/css/theme_color_default/radio.png b/admin/templates/css/theme_color_default/radio.png new file mode 100644 index 0000000..812f828 Binary files /dev/null and b/admin/templates/css/theme_color_default/radio.png differ diff --git a/admin/templates/css/theme_color_default/ui-to-top.png b/admin/templates/css/theme_color_default/ui-to-top.png new file mode 100644 index 0000000..f9ce577 Binary files /dev/null and b/admin/templates/css/theme_color_default/ui-to-top.png differ diff --git a/admin/templates/dbactions/actions.tpl b/admin/templates/dbactions/actions.tpl new file mode 100644 index 0000000..54a7758 --- /dev/null +++ b/admin/templates/dbactions/actions.tpl @@ -0,0 +1,225 @@ +
    {#DB_SUB_TITLE#}
    + +
    +
    + {#DB_TIPS#} +
    +
    + + + +
    +
    +
    {#DB_OPTION_LIST#}
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + +

    {#DB_OPTIMIZE_DATABASE#}

    +

    {#DB_OPTIMIZE_INFO#}

    +
    + + +

    {#DB_REPAIR_DATABASE#}

    +

    {#DB_REPAIR_INFO#}

    +
    + + +

    {#DB_BACKUP_DATABASE#}

    +
    +
    + {#DB_BACKUP_FILE_NAME#} + + +
    +
    + {#MAIN_STAT_MYSQL#} {$db_size} +
    +
    +
    + +
    +
    +
    + +
    +
    + +{if $msg} +
      + {$msg} +
    +{/if} + +
    + + + +
    +
    + +
    + + + + + + + +
    + +
    + + +
    +
    +
    + + +
    +
    +
    + + + \ No newline at end of file diff --git a/admin/templates/dbactions/nav.tpl b/admin/templates/dbactions/nav.tpl new file mode 100644 index 0000000..08b3872 --- /dev/null +++ b/admin/templates/dbactions/nav.tpl @@ -0,0 +1 @@ +
  • {#MAIN_DATABASE_INFO#}
  • \ No newline at end of file diff --git a/admin/templates/documents/alias_doc.tpl b/admin/templates/documents/alias_doc.tpl new file mode 100644 index 0000000..40b870e --- /dev/null +++ b/admin/templates/documents/alias_doc.tpl @@ -0,0 +1,398 @@ +
    +
    {#DOC_ALIASES#}
    +
    + + + +
    + +
    +
    {#DOC_ALIASES_LIST#}
    +
    +
    + + + + + + + + + + + + + + + + + + {if $aliases} + {foreach from=$aliases item=alias} + + + + + + + + + {/foreach} + + + + {else} + + + + + + + {/if} + +
    {#DOC_ALIASES_TABL_H_URL#}{#DOC_ALIASES_TABL_H_ADD#}{#DOC_ALIASES_TABL_H_AUT#}{#DOC_ACTIONS#}
    + + + + + {$alias->document_alias_changed|date_format:$DATE_FORMAT|pretty_date} + + {$alias->document_alias_author_name} + + + + +
    + +   + {#DOC_ALIASES_BUTT_CLO#} +
    +
      +
    • {#DOC_ALIASES_LIST_EMPT#}
    • +
    +
    + {#DOC_ALIASES_BUTT_CLO#} +
    +
    +
    + +
    +
    +
    {#DOC_ALIASES_ADD#}
    +
    + + + + + + + + + + + + +
    {#DOC_ALIASES_ADD_VAL#}
    +
    + + + + +
    +
    +
    + + + + + \ No newline at end of file diff --git a/admin/templates/documents/alias_doc_list.tpl b/admin/templates/documents/alias_doc_list.tpl new file mode 100644 index 0000000..7b99857 --- /dev/null +++ b/admin/templates/documents/alias_doc_list.tpl @@ -0,0 +1,75 @@ +
    + + + + + + + + + + + + + + + + + + {if $aliases} + {foreach from=$aliases item=alias} + + + + + + + + + {/foreach} + + + + {else} + + + + + + + {/if} + +
    {#DOC_ALIASES_TABL_H_URL#}{#DOC_ALIASES_TABL_H_ADD#}{#DOC_ALIASES_TABL_H_AUT#}{#DOC_ACTIONS#}
    + + + + + {$alias->document_alias_changed|date_format:$DATE_FORMAT|pretty_date} + + {$alias->document_alias_author_name} + + + + +
    + +   + {#DOC_ALIASES_BUTT_CLO#} +
    +
      +
    • {#DOC_ALIASES_LIST_EMPT#}
    • +
    +
    + {#DOC_ALIASES_BUTT_CLO#} +
    +
    + + \ No newline at end of file diff --git a/admin/templates/documents/alias_list.tpl b/admin/templates/documents/alias_list.tpl new file mode 100644 index 0000000..56dd854 --- /dev/null +++ b/admin/templates/documents/alias_list.tpl @@ -0,0 +1,92 @@ +
    +
    {#DOC_ALIASES#}
    +
    + +
    +
    + {#DOC_ALIASES_TITLE#} +
    +
    + + + +
    + +
    +
    {#DOC_ALIASES_DOC_LIST#}
    +
    + + + + + + + + + + + + + + + + + + + + {if $documents} + {foreach from=$documents item=document} + + + + + + + + + + {/foreach} + {else} + + + + {/if} + +
    {#DOC_ALIASES_LIST_NM#}{#DOC_ALIASES_LIST_RB#}{#DOC_ALIASES_LIST_CH#}{#DOC_ALIASES_LIST_CR#}{#DOC_ALIASES_LIST_AT#}
    + {$document.document_title} +
    + url:  + + {$document.document_alias} + +
    + {$document.rubric_title} + + {$document.document_alias_changed|date_format:$DATE_FORMAT|pretty_date} + + {$document.count} + + + + + + +
    +
      +
    • {#DOC_ALIASES_LIST_EMPT#}
    • +
    +
    + +
    \ No newline at end of file diff --git a/admin/templates/documents/change.tpl b/admin/templates/documents/change.tpl new file mode 100644 index 0000000..289d9c8 --- /dev/null +++ b/admin/templates/documents/change.tpl @@ -0,0 +1,76 @@ +{if check_permission('documents')} + + + +
    + +
    {#DOC_CHANGE_TITLE#}
    + +
    +
    + {#DOC_CHANGE_INFO#} +
    +
    + + + +
    + +
    + + + + +
    + +
    +
    +
    + +
    + + + + + + + + + + {foreach from=$fields item=field key=Id} + + + + + {/foreach} + + + + +
    {#DOC_CHANGE_OLD_FIELD#}{#DOC_CHANGE_NEW_FIELD#}
    {$field.title} + {html_options name=$Id options=$field.Options selected=$field.Selected} +
    + +
    + +
    +
    + +{/if} \ No newline at end of file diff --git a/admin/templates/documents/doc_search.tpl b/admin/templates/documents/doc_search.tpl new file mode 100644 index 0000000..8f7c258 --- /dev/null +++ b/admin/templates/documents/doc_search.tpl @@ -0,0 +1,162 @@ + \ No newline at end of file diff --git a/admin/templates/documents/docs.tpl b/admin/templates/documents/docs.tpl new file mode 100644 index 0000000..6cfc1a2 --- /dev/null +++ b/admin/templates/documents/docs.tpl @@ -0,0 +1,489 @@ + + +
    +
    {#DOC_SUB_TITLE#}
    +
    + +
    +
    + {#DOC_TIPS#} +
    +
    + + + +{if check_permission('document_view')} + +
    + + + + + + + + + + + + + + + + +
    {#MAIN_ADD_IN_RUB#}{#MAIN_SORT_DOCUMENTS#}
    +
    + + + + +   + +
    +
    +
    + + + +   + +
    +
    +
    +{/if} + +{include file='documents/doc_search.tpl'} + +
    +
    +
    {#MAIN_DOCUMENTS_ALL#}
    + +
    +
    +
    + {#DOC_SORT_TEXT#} + + + {if $smarty.request.sort=='id'}{elseif $smarty.request.sort=='id_desc'}{/if} + {#DOC_ID#} + + + + {if $smarty.request.sort=='position'}{elseif $smarty.request.sort=='position_desc'}{/if} + {#DOC_POSITION#} + + + + {if $smarty.request.sort=='title'}{elseif $smarty.request.sort=='title_desc'}{/if} + {#DOC_TITLE#} + + + + {if $smarty.request.sort=='alias'}{elseif $smarty.request.sort=='alias_desc'}{/if} + {#DOC_URL_RUB#} + + + + {if $smarty.request.sort=='rubric'}{elseif $smarty.request.sort=='rubric_desc'}{/if} + {#DOC_IN_RUBRIK#} + + + + {if $smarty.request.sort=='published'}{elseif $smarty.request.sort=='published_desc'}{/if} + {#DOC_CREATED#} + + + + {if $smarty.request.sort=='changed'}{elseif $smarty.request.sort=='changed_desc'}{/if} + {#DOC_EDIT#} + + + + {if $smarty.request.sort=='author'}{elseif $smarty.request.sort=='author_desc'}{/if} + {#DOC_AUTHOR#} + + + + {if $smarty.request.sort=='lang'}{elseif $smarty.request.sort=='lang_desc'}{/if} + {#DOC_LANG#} + +
    + + + + + + + + + {if !$smarty.const.ADMIN_EDITMENU}{/if} + + {if $docs} + + + + + + + + + {if !$smarty.const.ADMIN_EDITMENU} + + {/if} + + + {/if} + + + {if $docs} + {foreach from=$docs item=item} + document_deleted==1}class="red"{/if}{if $item->document_status!=1}class="yellow"{/if}> + + + + + + + + + + + + + {if !$smarty.const.ADMIN_EDITMENU} + + {/if} + + {/foreach} + {else} + + + + {/if} + {if $docs} + + + + + + + + + {if !$smarty.const.ADMIN_EDITMENU}{/if} + + + {/if} + +
    +
    + +
    +
    + {#DOC_ID#} + + {#DOC_TITLE#} | {#DOC_URL_RUB#} + + {#DOC_IN_RUBRIK#} + + {#DOC_POSITION#} + + {#DOC_CREATED#} | {#DOC_EDIT#} + + {#DOC_ACTIONS#} +
    cantEdit!=1 || $item->canOpenClose!=1 || $item->canEndDel!=1) && ($item->Id == 1 || $item->Id == $PAGE_NOT_FOUND_ID)}disabled{/if} class="checkbox" />{$item->Id} +
    + {if $item->cantEdit==1} + + {if $item->rubric_admin_teaser_template != ""} + {$item->rubric_admin_teaser_template} + {else} + + + {if $item->document_breadcrum_title != ""} + {$item->document_breadcrum_title|stripslashes}{elseif $item->document_title != ""}{$item->document_title|stripslashes}{else}{#DOC_SHOW3_TITLE#} + {/if} + + +
    + + {$item->document_lang} + url:  + + {$item->document_alias} + +  |  + {#DOC_CLICKS#}: {$item->document_count_view} + {/if} + + + + {else} + + {if $item->document_breadcrum_title != ""} + {$item->document_breadcrum_title|stripslashes}{elseif $item->document_title != ""}{$item->document_title|stripslashes}{else}{#DOC_SHOW3_TITLE#} + {/if} + +
    + url:  + + {$item->document_alias} + +  |  + {#DOC_CLICKS#}: {$item->document_count_view} + {/if} +
    +
    + {if $item->cantEdit==1} + + {foreach from=$rubrics item=rubric} + {if $item->rubric_id == $rubric->Id} + + {$rubric->rubric_title|escape} + +
    + {if $smarty.const.UGROUP == 1} + {#DOC_AUTHOR#}: {$item->document_author|escape} + {else} + {#DOC_AUTHOR#}: {$item->document_author|escape} + {/if} + {/if} + {/foreach} + + {else} + {foreach from=$rubrics item=rubric} + {if $item->rubric_id == $rubric->Id} + {$rubric->rubric_title|escape} +
    + {#DOC_AUTHOR#}: {$item->document_author|escape} + {/if} + {/foreach} + {/if} +
    + {if $item->cantEdit==1} +
    + + +
    + {/if} +
    +
    +
    + {if $item->ist_remark!='0'} +
    + +
    + {/if} +
    + + {$item->document_published|date_format:$TIME_FORMAT|pretty_date} +
    + {$item->document_changed|date_format:$TIME_FORMAT|pretty_date} +
    +
    +
    + {if check_permission("remarks")} + {if $item->ist_remark=='0'} + + {else} + + {/if} + {else} + {**} + {/if} + + {if $item->cantEdit==1 && $item->Id != 1 && $item->Id != $PAGE_NOT_FOUND_ID} + + {else} + {**} + {/if} + + {if $item->cantEdit==1} + + {else} + {**} + {/if} + + {if $item->document_deleted==1} + {**} + {else} + {if $item->document_status==1} + {if $item->canOpenClose==1 && $item->Id != 1 && $item->Id != $PAGE_NOT_FOUND_ID} + + {else} + {if $item->cantEdit==1 && $item->Id != 1 && $item->Id != $PAGE_NOT_FOUND_ID} + {**} + {else} + {**} + {/if} + {/if} + {else} + {if $item->canOpenClose==1} + + {else} + {if $item->cantEdit==1 && $item->Id != 1 && $item->Id != $PAGE_NOT_FOUND_ID} + {**} + {else} + {**} + {/if} + {/if} + {/if} + {/if} + + {if $item->document_deleted==1} + + {else} + {if $item->canDelete==1} + + {else} + {**} + {/if} + {/if} + + {if $item->canEndDel==1 && $item->Id != 1 && $item->Id != $PAGE_NOT_FOUND_ID} + + {else} + {**} + {/if} +
    +
      +
    • {#DOC_NO_DOCS#}
    • +
    +
    {#DOC_ID#} + {#DOC_TITLE#} | {#DOC_URL_RUB#} + {#DOC_IN_RUBRIK#}{#DOC_POSITION#}{#DOC_CREATED#} | {#DOC_EDIT#}{#DOC_ACTIONS#}
    + +{if check_permission('alle')} +
    +
    + +    +
    +
    +{/if} + +
    +
    + +{if $page_nav} + +{/if} + + + + \ No newline at end of file diff --git a/admin/templates/documents/docs_add_new.tpl b/admin/templates/documents/docs_add_new.tpl new file mode 100644 index 0000000..5301240 --- /dev/null +++ b/admin/templates/documents/docs_add_new.tpl @@ -0,0 +1,59 @@ + +
    + +
    {#MAIN_ADD_IN_RUB#}
    + +
    +
    + {#DOC_ADD_NEW_LIGHT_TIP#} +
    +
    + + + +
    +
    {#MAIN_ADD_IN_RUB#}
    +
    + +
    + + + + + + + + + + + + + + + +
    {#DOC_NAME#} +
    +
    {#DOC_CHOSE_RUB#} + +
    +
    + +
    +
    \ No newline at end of file diff --git a/admin/templates/documents/docs_simple.tpl b/admin/templates/documents/docs_simple.tpl new file mode 100644 index 0000000..3d65caa --- /dev/null +++ b/admin/templates/documents/docs_simple.tpl @@ -0,0 +1,134 @@ + + +
    + +
    {#DOC_SUB_TITLE#}
    + +
    +
    + {#DOC_INSERT_LINK_TIP#} +
    +
    + + + +{include file='documents/doc_search.tpl'} + +
    +
    + + + + + + + + + + + + + + + + + {foreach from=$docs item=item} + + + + + + + + {/foreach} + +
    {#DOC_ID#} {#DOC_TITLE#}{#DOC_IN_RUBRIK#} 
    {$item->Id} + {if $item->document_published < $smarty.now && ($item->document_expire == '0' || $item->document_expire > $smarty.now)} + + {else} + + {/if} + {if $item->document_breadcrum_title != ""}{$item->document_breadcrum_title|stripslashes}{elseif $item->document_title != ""}{$item->document_title|stripslashes}{else}{#DOC_SHOW3_TITLE#}{/if}
    {$item->document_alias}
    {$item->RubName|escape} + {if $smarty.request.idonly == 1} + + {elseif $smarty.request.idtitle == 1} + document_breadcrum_title|stripslashes}{elseif $item->document_title != ""}{$item->document_title|stripslashes}{else}{#DOC_SHOW3_TITLE#}{/if}'{rdelim});" class="whiteBtn" type="button" value="{#DOC_BUTTON_INSERT_LINK#}" /> + {elseif $smarty.request.selurl == 1} + + {elseif $smarty.request.selecturl == 1} + + {elseif $smarty.request.alias == 1} + + {elseif $smarty.request.function == 1} + + {else} + document_breadcrum_title|stripslashes}{elseif $item->document_title != ""}{$item->document_title|stripslashes}{else}{#DOC_SHOW3_TITLE#}{/if}',{$smarty.request.document_alias|escape}:'{$item->document_alias}'{rdelim});" class="whiteBtn" type="button" value="{#DOC_BUTTON_INSERT_LINK#}" /> + {/if} +
    +
    +
    + +
    + +{if $page_nav} + +{/if} + +
    + + + + \ No newline at end of file diff --git a/admin/templates/documents/form.tpl b/admin/templates/documents/form.tpl new file mode 100644 index 0000000..b3bad04 --- /dev/null +++ b/admin/templates/documents/form.tpl @@ -0,0 +1,594 @@ + + + + +{if $smarty.request.action=='edit'} +
    +
    {#DOC_EDIT_DOCUMENT#} ID: {$smarty.request.Id}
    +
    + {foreach from=$smarty.session.accept_langs key=lang_id item=lang} + {if $document->lang_pack[$lang_id]>''} + {$lang_id} + {else} + {$lang_id} + {/if} + {/foreach} +
    +
    +{elseif $smarty.request.action=='copy'} +
    {#DOC_COPY_DOCUMENT#}
    +{else} +
    {#DOC_ADD_DOCUMENT#}
    +
    + {foreach from=$smarty.session.accept_langs key=lang_id item=lang} + {if $document->lang_pack[$lang_id]>''} + {$lang_id} + {else} + {$lang_id} + {/if} + {/foreach} +
    +
    +{/if} + + + + +
    + + + + {if ($smarty.request.Id == 1 || $smarty.request.Id == $PAGE_NOT_FOUND_ID) && $smarty.request.action != 'new' && $smarty.request.action != 'copy'} + {assign var=dis value = 'disabled'} + {/if} + +
    + + + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {#DOC_NAME#} [?]
    {#DOC_META_KEYWORDS#} [?] +
    + +
    +
    {#DOC_META_DESCRIPTION#} [?] +
    + +
    +
    {#DOC_INDEX_TYPE#} + +
    {#DOC_SITEMAP_FREQ#} [?] + + {#DOC_SITEMAP_PRIORITY#} [?] + +
    +
    + + + + + + + + + + +
    + +
    +
    + + +
    +
    +
    {#DOC_MAIN_CONTENT#}
    +
    + + + + + + {if $document->fields} + {foreach from=$document->fields item=document_field_group} + + {if $document->count_groups > 1} + + + + {/if} + + {foreach from=$document_field_group.fields item=field} + + + + + + {/foreach} + + {/foreach} + {else} + + + + {/if} + +
    {if $document_field_group.group_title}{$document_field_group.group_title}{else}{#DOC_FIELD_G_UNKNOW#}{/if}
    + {$field.Id} + + {$field.rubric_field_title|escape} + {if $field.rubric_field_description} +
    + {$field.rubric_field_description} + {/if} +
    {$field.result}
    +
      +
    • {#DOC_MAIN_NOCONTENT#}
    • +
    +
    + +
    +
    + {if $smarty.request.action == 'edit'} +
    + +   + +
    + +
    + {elseif $smarty.request.action == 'copy'} + +   + + {else} + +   + + {/if} +
    +
    + +
    +
    + +
    + +
    +
    +
    {#DOC_REVISSION#}
    + +
    + + + + {if $document->canDelRev == 1} + + + + {else} + + {/if} + + + + + + + + + + + {if $document_rev} + {foreach from=$document_rev item=doc_rev} + + + + + {if $document->canDelRev == 1} + + + {/if} + + {/foreach} + {else} + + + + {/if} + +
    {#DOC_REVISSION_DATA#}{#DOC_REVISSION_USER#}{#DOC_ACTIONS#}
    + {$doc_rev->doc_revision|date_format:$TIME_FORMAT|pretty_date} + + {$doc_rev->user_id} + + + + + + +
    +
      +
    • {#DOC_REVISSION_NO_ITEMS#}
    • +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/admin/templates/documents/form_after.tpl b/admin/templates/documents/form_after.tpl new file mode 100644 index 0000000..5fc3d70 --- /dev/null +++ b/admin/templates/documents/form_after.tpl @@ -0,0 +1,96 @@ +
    {#DOC_AFTER_CREATE_TITLE#}
    + +
    +
    + {#DOC_AFTER_CREATE_INFO#} +
    +
    + + + +{if $innavi} +
    + +
    +{/if} + +{literal} + +{/literal} \ No newline at end of file diff --git a/admin/templates/documents/nav.tpl b/admin/templates/documents/nav.tpl new file mode 100644 index 0000000..a37ade7 --- /dev/null +++ b/admin/templates/documents/nav.tpl @@ -0,0 +1,15 @@ +
  • + {#MAIN_NAVI_DOCUMENTS#} + {if $smarty.request.do=='docs'} +
      + {foreach from=$rubrics item=rubric} + {if $rubric->Show==1 && $rubric->rubric_docs_active==1} +
    • Id==$smarty.request.rubric_id}class="active"{/if}> + {$rubric->rubric_title|escape} + +
    • + {/if} + {/foreach} +
    + {/if} +
  • \ No newline at end of file diff --git a/admin/templates/documents/nav_top.tpl b/admin/templates/documents/nav_top.tpl new file mode 100644 index 0000000..5fc8da6 --- /dev/null +++ b/admin/templates/documents/nav_top.tpl @@ -0,0 +1 @@ +
  • {#MAIN_NAVI_DOCUMENTS#}
  • \ No newline at end of file diff --git a/admin/templates/documents/newremark.tpl b/admin/templates/documents/newremark.tpl new file mode 100644 index 0000000..0fa31b1 --- /dev/null +++ b/admin/templates/documents/newremark.tpl @@ -0,0 +1,80 @@ +{if check_permission("remark_view")} +
    + +
    {#DOC_NOTICE#}
    + + + + +{if $answers} +
    +
      + {foreach from=$answers item=answer} +
    • + {if $answer.remark_avatar}{else}{/if} +
      + +
      + {$answer.remark_author} пишет: {$answer.remark_title} + {if check_permission("remark_edit")} + + {else} + + {/if} + {$answer.remark_published|date_format:$TIME_FORMAT|pretty_date} +
      +
      + {$answer.remark_text} +
      +
      +
    • + {/foreach} +
    +
    + + {if check_permission("remark_edit")} +
    +
    + + + + + + + +
    +   +
    + +
    +
    +
    + {/if} + +{/if} + +{if $page_nav} + +{/if} + + +{/if} +{if check_permission("remark_edit")} + {if $reply==1} + {if $remark_status==1 || $new ==1} + {include file='documents/replyform.tpl'} + {/if} + {/if} +{/if} diff --git a/admin/templates/documents/replyform.tpl b/admin/templates/documents/replyform.tpl new file mode 100644 index 0000000..906c5d9 --- /dev/null +++ b/admin/templates/documents/replyform.tpl @@ -0,0 +1,31 @@ +
    +
    {#DOC_NEW_NOTICE_TITLE#}
    +
    + {#DOC_SEND_NOTICE_INFO#} +
    + +
    + + + + + + + + + + + + + + +
    {#DOC_NOTICE_TITLE#} +
    +
    {#DOC_NOTICE_TEXT#} +
    +
    + + {#DOC_NOTICE_DELETE_ALL#} +
    +
    +
    diff --git a/admin/templates/documents/user.tpl b/admin/templates/documents/user.tpl new file mode 100644 index 0000000..c4b99bb --- /dev/null +++ b/admin/templates/documents/user.tpl @@ -0,0 +1,107 @@ +{if check_permission('documents')} + + +
    + +
    {#DOC_CHANGE_AU_TITLE#}
    + +
    +
    + {#DOC_CHANGE_AU_INFO#} +
    +
    + + + +
    + +
    + + + + + + + +
    +
    + + + +
    +
    + +
    +
    +
    +
    + +{/if} \ No newline at end of file diff --git a/admin/templates/error.tpl b/admin/templates/error.tpl new file mode 100644 index 0000000..d76c851 --- /dev/null +++ b/admin/templates/error.tpl @@ -0,0 +1,5 @@ +
      +
    • + {$erorr} +
    • +
    \ No newline at end of file diff --git a/admin/templates/finder/finder.tpl b/admin/templates/finder/finder.tpl new file mode 100644 index 0000000..a33d5eb --- /dev/null +++ b/admin/templates/finder/finder.tpl @@ -0,0 +1,22 @@ + + + + + + + +
    {#MAIN_FINDER#}
    + + + +
    +
    finder
    +
    +
    diff --git a/admin/templates/finder/nav.tpl b/admin/templates/finder/nav.tpl new file mode 100644 index 0000000..259eba7 --- /dev/null +++ b/admin/templates/finder/nav.tpl @@ -0,0 +1 @@ +
  • {#MAIN_FILE_MANAGER_TITLE#}
  • \ No newline at end of file diff --git a/admin/templates/fonts/cuprum.eot b/admin/templates/fonts/cuprum.eot new file mode 100644 index 0000000..c8473cd Binary files /dev/null and b/admin/templates/fonts/cuprum.eot differ diff --git a/admin/templates/fonts/cuprum.ttf b/admin/templates/fonts/cuprum.ttf new file mode 100644 index 0000000..124a73c Binary files /dev/null and b/admin/templates/fonts/cuprum.ttf differ diff --git a/admin/templates/fonts/cuprum.woff b/admin/templates/fonts/cuprum.woff new file mode 100644 index 0000000..c0363f6 Binary files /dev/null and b/admin/templates/fonts/cuprum.woff differ diff --git a/admin/templates/groups/groups.tpl b/admin/templates/groups/groups.tpl new file mode 100644 index 0000000..1cbe439 --- /dev/null +++ b/admin/templates/groups/groups.tpl @@ -0,0 +1,139 @@ + + +
    {#UGROUP_TITLE#}
    + +
    +
    + {#UGROUP_INFO#} +
    +
    + + + +
    + + + +
    +
    + + + + + + + + + + + + {foreach from=$ugroups item=g} + + + + + + + + + + + + {/foreach} + +
    {#UGROUP_ID#}{#UGROUP_NAME#}{#UGROUP_COUNT#}{#UGROUP_ACTIONS#}
    {$g->user_group} + {if check_permission('group_edit')} + {if $g->user_group > 2} + {$g->user_group_name|escape} + {else} + {$g->user_group_name|escape} + {/if} + {else} + {$g->user_group_name|escape} + {/if} + {if check_permission('user_view')}{if $g->user_group==2 || $g->UserCount < 1} - {else}{$g->UserCount}{/if}{else}{$g->UserCount}{/if} + {if check_permission('group_edit')} + {if $g->user_group > 2} + + {else} + + {/if} + {else} + + {/if} + + {if check_permission('group_edit')} + {if $g->user_group > 2} + {if $g->UserCount > 0} + + {else} + + {/if} + {else} + + {/if} + {else} + + {/if} +
    +
    + + {if check_permission('group_edit')} + + {/if} +
    + +
    +
    diff --git a/admin/templates/groups/nav.tpl b/admin/templates/groups/nav.tpl new file mode 100644 index 0000000..806de22 --- /dev/null +++ b/admin/templates/groups/nav.tpl @@ -0,0 +1 @@ +
  • {#MAIN_NAVI_UGROUPS#}
  • \ No newline at end of file diff --git a/admin/templates/groups/perms.tpl b/admin/templates/groups/perms.tpl new file mode 100644 index 0000000..f28bed2 --- /dev/null +++ b/admin/templates/groups/perms.tpl @@ -0,0 +1,170 @@ +
    {#UGROUP_TITLE2#}
    + +
    +
    + {#UGROUP_WARNING_TIP#} +
    +
    + +{if $own_group} +
      +
    • • {#UGROUP_YOUR_NOT_CHANGE#}
    • +
    +{elseif $no_group} +
      +
    • • {#UGROUP_NOT_EXIST#}
    • +
    +{/if} + +{if !$no_group && !$own_group} + +
    +
    + + + +
    +
    {$g_name|escape}
    + +
    + +
    +
    +
    + + + + + + + + + + + {if !$modules} + + + + {else} + + + + + {/if} + + {foreach from=$g_all_permissions item=perm} + {assign var="header" value="_"|explode:$perm} + + {if $header.0!="$headers"} + {assign var="headers" value=$header.0} + + + + {/if} + + + + + + + {/foreach} + + +
    Модули
    {#UGROUP_MODULES_RIGHT#}
    +
      +
    • • {#UGROUP_NO_MODULES#}
    • +
    +
    + {foreach from=$modules item=module} + {if $module.ModuleStatus == 1 && $module.ModuleIsFunction == 1} + +
    + {/if} + {/foreach} +
    {$smarty.config.$headers}
    + + + {$smarty.config.$perm} +
    + +
    +
    +  {#UGROUP_OR#}  +
    +
    + + +
    +
    +
    + +{/if} + + + \ No newline at end of file diff --git a/admin/templates/images/IconHome.gif b/admin/templates/images/IconHome.gif new file mode 100644 index 0000000..0ab9e10 Binary files /dev/null and b/admin/templates/images/IconHome.gif differ diff --git a/admin/templates/images/NavBg.png b/admin/templates/images/NavBg.png new file mode 100644 index 0000000..0b8a67d Binary files /dev/null and b/admin/templates/images/NavBg.png differ diff --git a/admin/templates/images/accordion_off.png b/admin/templates/images/accordion_off.png new file mode 100644 index 0000000..d2b01d6 Binary files /dev/null and b/admin/templates/images/accordion_off.png differ diff --git a/admin/templates/images/accordion_on.png b/admin/templates/images/accordion_on.png new file mode 100644 index 0000000..5946ece Binary files /dev/null and b/admin/templates/images/accordion_on.png differ diff --git a/admin/templates/images/add.png b/admin/templates/images/add.png new file mode 100644 index 0000000..3832636 Binary files /dev/null and b/admin/templates/images/add.png differ diff --git a/admin/templates/images/alertOpacityOverlay.png b/admin/templates/images/alertOpacityOverlay.png new file mode 100644 index 0000000..ffc7286 Binary files /dev/null and b/admin/templates/images/alertOpacityOverlay.png differ diff --git a/admin/templates/images/arrow.gif b/admin/templates/images/arrow.gif new file mode 100644 index 0000000..58cf7e9 Binary files /dev/null and b/admin/templates/images/arrow.gif differ diff --git a/admin/templates/images/backgrounds/blueprint.png b/admin/templates/images/backgrounds/blueprint.png new file mode 100644 index 0000000..759caf2 Binary files /dev/null and b/admin/templates/images/backgrounds/blueprint.png differ diff --git a/admin/templates/images/backgrounds/darkwood.jpg b/admin/templates/images/backgrounds/darkwood.jpg new file mode 100644 index 0000000..f026936 Binary files /dev/null and b/admin/templates/images/backgrounds/darkwood.jpg differ diff --git a/admin/templates/images/backgrounds/grey.png b/admin/templates/images/backgrounds/grey.png new file mode 100644 index 0000000..5fa8db7 Binary files /dev/null and b/admin/templates/images/backgrounds/grey.png differ diff --git a/admin/templates/images/backgrounds/wood.jpg b/admin/templates/images/backgrounds/wood.jpg new file mode 100644 index 0000000..6ca663c Binary files /dev/null and b/admin/templates/images/backgrounds/wood.jpg differ diff --git a/admin/templates/images/blanc.gif b/admin/templates/images/blanc.gif new file mode 100644 index 0000000..35d42e8 Binary files /dev/null and b/admin/templates/images/blanc.gif differ diff --git a/admin/templates/images/chevron.gif b/admin/templates/images/chevron.gif new file mode 100644 index 0000000..ef42331 Binary files /dev/null and b/admin/templates/images/chevron.gif differ diff --git a/admin/templates/images/chosen-sprite.png b/admin/templates/images/chosen-sprite.png new file mode 100644 index 0000000..3611ae4 Binary files /dev/null and b/admin/templates/images/chosen-sprite.png differ diff --git a/admin/templates/images/chosen-sprite@2x.png b/admin/templates/images/chosen-sprite@2x.png new file mode 100644 index 0000000..ffe4d7d Binary files /dev/null and b/admin/templates/images/chosen-sprite@2x.png differ diff --git a/admin/templates/images/clippy.svg b/admin/templates/images/clippy.svg new file mode 100644 index 0000000..e1b1703 --- /dev/null +++ b/admin/templates/images/clippy.svg @@ -0,0 +1,3 @@ + + + diff --git a/admin/templates/images/darkBg.jpg b/admin/templates/images/darkBg.jpg new file mode 100644 index 0000000..8449171 Binary files /dev/null and b/admin/templates/images/darkBg.jpg differ diff --git a/admin/templates/images/darkBg.png b/admin/templates/images/darkBg.png new file mode 100644 index 0000000..976cad3 Binary files /dev/null and b/admin/templates/images/darkBg.png differ diff --git a/admin/templates/images/fancybox/blank.gif b/admin/templates/images/fancybox/blank.gif new file mode 100644 index 0000000..35d42e8 Binary files /dev/null and b/admin/templates/images/fancybox/blank.gif differ diff --git a/admin/templates/images/fancybox/fancy_close.png b/admin/templates/images/fancybox/fancy_close.png new file mode 100644 index 0000000..0703530 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_close.png differ diff --git a/admin/templates/images/fancybox/fancy_loading.png b/admin/templates/images/fancybox/fancy_loading.png new file mode 100644 index 0000000..2503017 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_loading.png differ diff --git a/admin/templates/images/fancybox/fancy_nav_left.png b/admin/templates/images/fancybox/fancy_nav_left.png new file mode 100644 index 0000000..ebaa6a4 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_nav_left.png differ diff --git a/admin/templates/images/fancybox/fancy_nav_right.png b/admin/templates/images/fancybox/fancy_nav_right.png new file mode 100644 index 0000000..873294e Binary files /dev/null and b/admin/templates/images/fancybox/fancy_nav_right.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_e.png b/admin/templates/images/fancybox/fancy_shadow_e.png new file mode 100644 index 0000000..2eda089 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_e.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_n.png b/admin/templates/images/fancybox/fancy_shadow_n.png new file mode 100644 index 0000000..69aa10e Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_n.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_ne.png b/admin/templates/images/fancybox/fancy_shadow_ne.png new file mode 100644 index 0000000..79f6980 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_ne.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_nw.png b/admin/templates/images/fancybox/fancy_shadow_nw.png new file mode 100644 index 0000000..7182cd9 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_nw.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_s.png b/admin/templates/images/fancybox/fancy_shadow_s.png new file mode 100644 index 0000000..d8858bf Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_s.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_se.png b/admin/templates/images/fancybox/fancy_shadow_se.png new file mode 100644 index 0000000..541e3ff Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_se.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_sw.png b/admin/templates/images/fancybox/fancy_shadow_sw.png new file mode 100644 index 0000000..b451689 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_sw.png differ diff --git a/admin/templates/images/fancybox/fancy_shadow_w.png b/admin/templates/images/fancybox/fancy_shadow_w.png new file mode 100644 index 0000000..8a4e4a8 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_shadow_w.png differ diff --git a/admin/templates/images/fancybox/fancy_title_left.png b/admin/templates/images/fancybox/fancy_title_left.png new file mode 100644 index 0000000..6049223 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_title_left.png differ diff --git a/admin/templates/images/fancybox/fancy_title_main.png b/admin/templates/images/fancybox/fancy_title_main.png new file mode 100644 index 0000000..8044271 Binary files /dev/null and b/admin/templates/images/fancybox/fancy_title_main.png differ diff --git a/admin/templates/images/fancybox/fancy_title_over.png b/admin/templates/images/fancybox/fancy_title_over.png new file mode 100644 index 0000000..d9f458f Binary files /dev/null and b/admin/templates/images/fancybox/fancy_title_over.png differ diff --git a/admin/templates/images/fancybox/fancy_title_right.png b/admin/templates/images/fancybox/fancy_title_right.png new file mode 100644 index 0000000..e36d9db Binary files /dev/null and b/admin/templates/images/fancybox/fancy_title_right.png differ diff --git a/admin/templates/images/fancybox/fancybox-x.png b/admin/templates/images/fancybox/fancybox-x.png new file mode 100644 index 0000000..c2130f8 Binary files /dev/null and b/admin/templates/images/fancybox/fancybox-x.png differ diff --git a/admin/templates/images/fancybox/fancybox-y.png b/admin/templates/images/fancybox/fancybox-y.png new file mode 100644 index 0000000..7ef399b Binary files /dev/null and b/admin/templates/images/fancybox/fancybox-y.png differ diff --git a/admin/templates/images/fancybox/fancybox.png b/admin/templates/images/fancybox/fancybox.png new file mode 100644 index 0000000..d7a8363 Binary files /dev/null and b/admin/templates/images/fancybox/fancybox.png differ diff --git a/admin/templates/images/file.gif b/admin/templates/images/file.gif new file mode 100644 index 0000000..2c9630b Binary files /dev/null and b/admin/templates/images/file.gif differ diff --git a/admin/templates/images/folder.gif b/admin/templates/images/folder.gif new file mode 100644 index 0000000..56380b0 Binary files /dev/null and b/admin/templates/images/folder.gif differ diff --git a/admin/templates/images/folder_up.gif b/admin/templates/images/folder_up.gif new file mode 100644 index 0000000..8f72d87 Binary files /dev/null and b/admin/templates/images/folder_up.gif differ diff --git a/admin/templates/images/forms/addFiles.png b/admin/templates/images/forms/addFiles.png new file mode 100644 index 0000000..afbfbd9 Binary files /dev/null and b/admin/templates/images/forms/addFiles.png differ diff --git a/admin/templates/images/forms/checkbox.png b/admin/templates/images/forms/checkbox.png new file mode 100644 index 0000000..05b429c Binary files /dev/null and b/admin/templates/images/forms/checkbox.png differ diff --git a/admin/templates/images/forms/checkbox2.png b/admin/templates/images/forms/checkbox2.png new file mode 100644 index 0000000..99de5be Binary files /dev/null and b/admin/templates/images/forms/checkbox2.png differ diff --git a/admin/templates/images/forms/radio.png b/admin/templates/images/forms/radio.png new file mode 100644 index 0000000..1fe59b1 Binary files /dev/null and b/admin/templates/images/forms/radio.png differ diff --git a/admin/templates/images/forms/searchBtn.png b/admin/templates/images/forms/searchBtn.png new file mode 100644 index 0000000..51a6da3 Binary files /dev/null and b/admin/templates/images/forms/searchBtn.png differ diff --git a/admin/templates/images/forms/select_left.png b/admin/templates/images/forms/select_left.png new file mode 100644 index 0000000..a2cee52 Binary files /dev/null and b/admin/templates/images/forms/select_left.png differ diff --git a/admin/templates/images/forms/select_right.png b/admin/templates/images/forms/select_right.png new file mode 100644 index 0000000..16dd829 Binary files /dev/null and b/admin/templates/images/forms/select_right.png differ diff --git a/admin/templates/images/forms/spinnerBg.png b/admin/templates/images/forms/spinnerBg.png new file mode 100644 index 0000000..7540735 Binary files /dev/null and b/admin/templates/images/forms/spinnerBg.png differ diff --git a/admin/templates/images/forms/spinnerBottom.png b/admin/templates/images/forms/spinnerBottom.png new file mode 100644 index 0000000..78d5b75 Binary files /dev/null and b/admin/templates/images/forms/spinnerBottom.png differ diff --git a/admin/templates/images/forms/spinnerTop.png b/admin/templates/images/forms/spinnerTop.png new file mode 100644 index 0000000..6534f87 Binary files /dev/null and b/admin/templates/images/forms/spinnerTop.png differ diff --git a/admin/templates/images/forms/spinnerUpDown.png b/admin/templates/images/forms/spinnerUpDown.png new file mode 100644 index 0000000..7950c0d Binary files /dev/null and b/admin/templates/images/forms/spinnerUpDown.png differ diff --git a/admin/templates/images/icons/add.png b/admin/templates/images/icons/add.png new file mode 100644 index 0000000..e02c512 Binary files /dev/null and b/admin/templates/images/icons/add.png differ diff --git a/admin/templates/images/icons/add2.png b/admin/templates/images/icons/add2.png new file mode 100644 index 0000000..5476fda Binary files /dev/null and b/admin/templates/images/icons/add2.png differ diff --git a/admin/templates/images/icons/cog.png b/admin/templates/images/icons/cog.png new file mode 100644 index 0000000..4f163cc Binary files /dev/null and b/admin/templates/images/icons/cog.png differ diff --git a/admin/templates/images/icons/cog2.png b/admin/templates/images/icons/cog2.png new file mode 100644 index 0000000..e40224d Binary files /dev/null and b/admin/templates/images/icons/cog2.png differ diff --git a/admin/templates/images/icons/cog3.png b/admin/templates/images/icons/cog3.png new file mode 100644 index 0000000..218459b Binary files /dev/null and b/admin/templates/images/icons/cog3.png differ diff --git a/admin/templates/images/icons/contact.png b/admin/templates/images/icons/contact.png new file mode 100644 index 0000000..f1cc728 Binary files /dev/null and b/admin/templates/images/icons/contact.png differ diff --git a/admin/templates/images/icons/help.png b/admin/templates/images/icons/help.png new file mode 100644 index 0000000..80e5bd1 Binary files /dev/null and b/admin/templates/images/icons/help.png differ diff --git a/admin/templates/images/icons/loginEmail.png b/admin/templates/images/icons/loginEmail.png new file mode 100644 index 0000000..394f17f Binary files /dev/null and b/admin/templates/images/icons/loginEmail.png differ diff --git a/admin/templates/images/icons/loginLock.png b/admin/templates/images/icons/loginLock.png new file mode 100644 index 0000000..ef1c4b0 Binary files /dev/null and b/admin/templates/images/icons/loginLock.png differ diff --git a/admin/templates/images/icons/logout.png b/admin/templates/images/icons/logout.png new file mode 100644 index 0000000..f9664d6 Binary files /dev/null and b/admin/templates/images/icons/logout.png differ diff --git a/admin/templates/images/icons/mainWebsite.png b/admin/templates/images/icons/mainWebsite.png new file mode 100644 index 0000000..387efd9 Binary files /dev/null and b/admin/templates/images/icons/mainWebsite.png differ diff --git a/admin/templates/images/icons/messages.png b/admin/templates/images/icons/messages.png new file mode 100644 index 0000000..0687de6 Binary files /dev/null and b/admin/templates/images/icons/messages.png differ diff --git a/admin/templates/images/icons/preview.png b/admin/templates/images/icons/preview.png new file mode 100644 index 0000000..063912c Binary files /dev/null and b/admin/templates/images/icons/preview.png differ diff --git a/admin/templates/images/icons/profile.png b/admin/templates/images/icons/profile.png new file mode 100644 index 0000000..944f911 Binary files /dev/null and b/admin/templates/images/icons/profile.png differ diff --git a/admin/templates/images/icons/register.png b/admin/templates/images/icons/register.png new file mode 100644 index 0000000..18a7720 Binary files /dev/null and b/admin/templates/images/icons/register.png differ diff --git a/admin/templates/images/icons/settings.png b/admin/templates/images/icons/settings.png new file mode 100644 index 0000000..e955a57 Binary files /dev/null and b/admin/templates/images/icons/settings.png differ diff --git a/admin/templates/images/icons/subAdd.png b/admin/templates/images/icons/subAdd.png new file mode 100644 index 0000000..a87d780 Binary files /dev/null and b/admin/templates/images/icons/subAdd.png differ diff --git a/admin/templates/images/icons/subInbox.png b/admin/templates/images/icons/subInbox.png new file mode 100644 index 0000000..63caf3d Binary files /dev/null and b/admin/templates/images/icons/subInbox.png differ diff --git a/admin/templates/images/icons/subOutbox.png b/admin/templates/images/icons/subOutbox.png new file mode 100644 index 0000000..159bc91 Binary files /dev/null and b/admin/templates/images/icons/subOutbox.png differ diff --git a/admin/templates/images/icons/subTrash.png b/admin/templates/images/icons/subTrash.png new file mode 100644 index 0000000..9f8c38e Binary files /dev/null and b/admin/templates/images/icons/subTrash.png differ diff --git a/admin/templates/images/icons/tasks.png b/admin/templates/images/icons/tasks.png new file mode 100644 index 0000000..38dc3aa Binary files /dev/null and b/admin/templates/images/icons/tasks.png differ diff --git a/admin/templates/images/icons/upload.png b/admin/templates/images/icons/upload.png new file mode 100644 index 0000000..a947156 Binary files /dev/null and b/admin/templates/images/icons/upload.png differ diff --git a/admin/templates/images/icons/user.png b/admin/templates/images/icons/user.png new file mode 100644 index 0000000..d51cccf Binary files /dev/null and b/admin/templates/images/icons/user.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_diagonals-thick_18_b81900_40x40.png b/admin/templates/images/jquery_ui/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000..954e22d Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_diagonals-thick_20_666666_40x40.png b/admin/templates/images/jquery_ui/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000..64ece57 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_flat_0_aaaaaa_40x100.png b/admin/templates/images/jquery_ui/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000..5b5dab2 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_flat_10_000000_40x100.png b/admin/templates/images/jquery_ui/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000..abdc010 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_flat_10_000000_40x100.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_glass_100_f6f6f6_1x400.png b/admin/templates/images/jquery_ui/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 0000000..9b383f4 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_glass_100_fdf5ce_1x400.png b/admin/templates/images/jquery_ui/ui-bg_glass_100_fdf5ce_1x400.png new file mode 100644 index 0000000..a23baad Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_glass_100_fdf5ce_1x400.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_glass_65_ffffff_1x400.png b/admin/templates/images/jquery_ui/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000..42ccba2 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_glass_75_e6e6e6_1x400.png b/admin/templates/images/jquery_ui/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 0000000..86c2baa Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_glass_95_fef1ec_1x400.png b/admin/templates/images/jquery_ui/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 0000000..4443fdc Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_gloss-wave_35_f6a828_500x100.png b/admin/templates/images/jquery_ui/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100644 index 0000000..39d5824 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_gloss-wave_35_f6a828_500x100.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_highlight-soft_100_eeeeee_1x100.png b/admin/templates/images/jquery_ui/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000..f127367 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/admin/templates/images/jquery_ui/ui-bg_highlight-soft_75_ffe45c_1x100.png b/admin/templates/images/jquery_ui/ui-bg_highlight-soft_75_ffe45c_1x100.png new file mode 100644 index 0000000..359397a Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-bg_highlight-soft_75_ffe45c_1x100.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_222222_256x240.png b/admin/templates/images/jquery_ui/ui-icons_222222_256x240.png new file mode 100644 index 0000000..ee039dc Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_222222_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_228ef1_256x240.png b/admin/templates/images/jquery_ui/ui-icons_228ef1_256x240.png new file mode 100644 index 0000000..a641a37 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_228ef1_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_2e83ff_256x240.png b/admin/templates/images/jquery_ui/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000..45e8928 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_2e83ff_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_454545_256x240.png b/admin/templates/images/jquery_ui/ui-icons_454545_256x240.png new file mode 100644 index 0000000..7ec70d1 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_454545_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_888888_256x240.png b/admin/templates/images/jquery_ui/ui-icons_888888_256x240.png new file mode 100644 index 0000000..5ba708c Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_888888_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_cd0a0a_256x240.png b/admin/templates/images/jquery_ui/ui-icons_cd0a0a_256x240.png new file mode 100644 index 0000000..7930a55 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_cd0a0a_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_ef8c08_256x240.png b/admin/templates/images/jquery_ui/ui-icons_ef8c08_256x240.png new file mode 100644 index 0000000..85e63e9 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_ef8c08_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_ffd27a_256x240.png b/admin/templates/images/jquery_ui/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000..e117eff Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_ffd27a_256x240.png differ diff --git a/admin/templates/images/jquery_ui/ui-icons_ffffff_256x240.png b/admin/templates/images/jquery_ui/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000..42f8f99 Binary files /dev/null and b/admin/templates/images/jquery_ui/ui-icons_ffffff_256x240.png differ diff --git a/admin/templates/images/leftNavBg.png b/admin/templates/images/leftNavBg.png new file mode 100644 index 0000000..d06ee9d Binary files /dev/null and b/admin/templates/images/leftNavBg.png differ diff --git a/admin/templates/images/leftNavSub.png b/admin/templates/images/leftNavSub.png new file mode 100644 index 0000000..019d965 Binary files /dev/null and b/admin/templates/images/leftNavSub.png differ diff --git a/admin/templates/images/left_menu_show.png b/admin/templates/images/left_menu_show.png new file mode 100644 index 0000000..3f72567 Binary files /dev/null and b/admin/templates/images/left_menu_show.png differ diff --git a/admin/templates/images/level.png b/admin/templates/images/level.png new file mode 100644 index 0000000..8c4f706 Binary files /dev/null and b/admin/templates/images/level.png differ diff --git a/admin/templates/images/loader2.gif b/admin/templates/images/loader2.gif new file mode 100644 index 0000000..1effbdf Binary files /dev/null and b/admin/templates/images/loader2.gif differ diff --git a/admin/templates/images/loader3.gif b/admin/templates/images/loader3.gif new file mode 100644 index 0000000..084834f Binary files /dev/null and b/admin/templates/images/loader3.gif differ diff --git a/admin/templates/images/loading.gif b/admin/templates/images/loading.gif new file mode 100644 index 0000000..2cbec38 Binary files /dev/null and b/admin/templates/images/loading.gif differ diff --git a/admin/templates/images/loginLogo.png b/admin/templates/images/loginLogo.png new file mode 100644 index 0000000..98d4c87 Binary files /dev/null and b/admin/templates/images/loginLogo.png differ diff --git a/admin/templates/images/logosmall.png b/admin/templates/images/logosmall.png new file mode 100644 index 0000000..4b03a95 Binary files /dev/null and b/admin/templates/images/logosmall.png differ diff --git a/admin/templates/images/mediapool/attach.gif b/admin/templates/images/mediapool/attach.gif new file mode 100644 index 0000000..ef155e8 Binary files /dev/null and b/admin/templates/images/mediapool/attach.gif differ diff --git a/admin/templates/images/mediapool/avi.gif b/admin/templates/images/mediapool/avi.gif new file mode 100644 index 0000000..1e09115 Binary files /dev/null and b/admin/templates/images/mediapool/avi.gif differ diff --git a/admin/templates/images/mediapool/blank.gif b/admin/templates/images/mediapool/blank.gif new file mode 100644 index 0000000..a3b9078 Binary files /dev/null and b/admin/templates/images/mediapool/blank.gif differ diff --git a/admin/templates/images/mediapool/bmp.gif b/admin/templates/images/mediapool/bmp.gif new file mode 100644 index 0000000..e7bb5d7 Binary files /dev/null and b/admin/templates/images/mediapool/bmp.gif differ diff --git a/admin/templates/images/mediapool/doc.gif b/admin/templates/images/mediapool/doc.gif new file mode 100644 index 0000000..80082f5 Binary files /dev/null and b/admin/templates/images/mediapool/doc.gif differ diff --git a/admin/templates/images/mediapool/exe.gif b/admin/templates/images/mediapool/exe.gif new file mode 100644 index 0000000..29bd588 Binary files /dev/null and b/admin/templates/images/mediapool/exe.gif differ diff --git a/admin/templates/images/mediapool/gif.gif b/admin/templates/images/mediapool/gif.gif new file mode 100644 index 0000000..9cba87e Binary files /dev/null and b/admin/templates/images/mediapool/gif.gif differ diff --git a/admin/templates/images/mediapool/jpe.gif b/admin/templates/images/mediapool/jpe.gif new file mode 100644 index 0000000..d2feb2b Binary files /dev/null and b/admin/templates/images/mediapool/jpe.gif differ diff --git a/admin/templates/images/mediapool/jpeg.gif b/admin/templates/images/mediapool/jpeg.gif new file mode 100644 index 0000000..d2feb2b Binary files /dev/null and b/admin/templates/images/mediapool/jpeg.gif differ diff --git a/admin/templates/images/mediapool/jpg.gif b/admin/templates/images/mediapool/jpg.gif new file mode 100644 index 0000000..d2feb2b Binary files /dev/null and b/admin/templates/images/mediapool/jpg.gif differ diff --git a/admin/templates/images/mediapool/mp3.gif b/admin/templates/images/mediapool/mp3.gif new file mode 100644 index 0000000..54f7e5d Binary files /dev/null and b/admin/templates/images/mediapool/mp3.gif differ diff --git a/admin/templates/images/mediapool/pdf.gif b/admin/templates/images/mediapool/pdf.gif new file mode 100644 index 0000000..4940522 Binary files /dev/null and b/admin/templates/images/mediapool/pdf.gif differ diff --git a/admin/templates/images/mediapool/php.gif b/admin/templates/images/mediapool/php.gif new file mode 100644 index 0000000..3167a72 Binary files /dev/null and b/admin/templates/images/mediapool/php.gif differ diff --git a/admin/templates/images/mediapool/png.gif b/admin/templates/images/mediapool/png.gif new file mode 100644 index 0000000..34fb938 Binary files /dev/null and b/admin/templates/images/mediapool/png.gif differ diff --git a/admin/templates/images/mediapool/psd.gif b/admin/templates/images/mediapool/psd.gif new file mode 100644 index 0000000..1d40b70 Binary files /dev/null and b/admin/templates/images/mediapool/psd.gif differ diff --git a/admin/templates/images/mediapool/rar.gif b/admin/templates/images/mediapool/rar.gif new file mode 100644 index 0000000..29e3543 Binary files /dev/null and b/admin/templates/images/mediapool/rar.gif differ diff --git a/admin/templates/images/mediapool/rtf.gif b/admin/templates/images/mediapool/rtf.gif new file mode 100644 index 0000000..0a439e5 Binary files /dev/null and b/admin/templates/images/mediapool/rtf.gif differ diff --git a/admin/templates/images/mediapool/swf.gif b/admin/templates/images/mediapool/swf.gif new file mode 100644 index 0000000..e60d007 Binary files /dev/null and b/admin/templates/images/mediapool/swf.gif differ diff --git a/admin/templates/images/mediapool/tif.gif b/admin/templates/images/mediapool/tif.gif new file mode 100644 index 0000000..ed8c142 Binary files /dev/null and b/admin/templates/images/mediapool/tif.gif differ diff --git a/admin/templates/images/mediapool/txt.gif b/admin/templates/images/mediapool/txt.gif new file mode 100644 index 0000000..1df2eaa Binary files /dev/null and b/admin/templates/images/mediapool/txt.gif differ diff --git a/admin/templates/images/mediapool/webp.gif b/admin/templates/images/mediapool/webp.gif new file mode 100644 index 0000000..2d2b0a8 Binary files /dev/null and b/admin/templates/images/mediapool/webp.gif differ diff --git a/admin/templates/images/mediapool/wmv.gif b/admin/templates/images/mediapool/wmv.gif new file mode 100644 index 0000000..1e09115 Binary files /dev/null and b/admin/templates/images/mediapool/wmv.gif differ diff --git a/admin/templates/images/mediapool/xls.gif b/admin/templates/images/mediapool/xls.gif new file mode 100644 index 0000000..6103f63 Binary files /dev/null and b/admin/templates/images/mediapool/xls.gif differ diff --git a/admin/templates/images/mediapool/zip.gif b/admin/templates/images/mediapool/zip.gif new file mode 100644 index 0000000..29e3543 Binary files /dev/null and b/admin/templates/images/mediapool/zip.gif differ diff --git a/admin/templates/images/middlebg.png b/admin/templates/images/middlebg.png new file mode 100644 index 0000000..8647c6f Binary files /dev/null and b/admin/templates/images/middlebg.png differ diff --git a/admin/templates/images/nav_level_2.gif b/admin/templates/images/nav_level_2.gif new file mode 100644 index 0000000..18dc44b Binary files /dev/null and b/admin/templates/images/nav_level_2.gif differ diff --git a/admin/templates/images/nav_level_3.gif b/admin/templates/images/nav_level_3.gif new file mode 100644 index 0000000..1d0cb7c Binary files /dev/null and b/admin/templates/images/nav_level_3.gif differ diff --git a/admin/templates/images/numberTop.png b/admin/templates/images/numberTop.png new file mode 100644 index 0000000..cbaad94 Binary files /dev/null and b/admin/templates/images/numberTop.png differ diff --git a/admin/templates/images/ref.png b/admin/templates/images/ref.png new file mode 100644 index 0000000..bdcd6be Binary files /dev/null and b/admin/templates/images/ref.png differ diff --git a/admin/templates/images/searchSmall.png b/admin/templates/images/searchSmall.png new file mode 100644 index 0000000..5182c30 Binary files /dev/null and b/admin/templates/images/searchSmall.png differ diff --git a/admin/templates/images/sprites.gif b/admin/templates/images/sprites.gif new file mode 100644 index 0000000..014338a Binary files /dev/null and b/admin/templates/images/sprites.gif differ diff --git a/admin/templates/images/sprites_doc.png b/admin/templates/images/sprites_doc.png new file mode 100644 index 0000000..4088cce Binary files /dev/null and b/admin/templates/images/sprites_doc.png differ diff --git a/admin/templates/images/table_level.png b/admin/templates/images/table_level.png new file mode 100644 index 0000000..1b39936 Binary files /dev/null and b/admin/templates/images/table_level.png differ diff --git a/admin/templates/images/tabsSep.png b/admin/templates/images/tabsSep.png new file mode 100644 index 0000000..82b93e1 Binary files /dev/null and b/admin/templates/images/tabsSep.png differ diff --git a/admin/templates/images/tipsy.gif b/admin/templates/images/tipsy.gif new file mode 100644 index 0000000..74eebae Binary files /dev/null and b/admin/templates/images/tipsy.gif differ diff --git a/admin/templates/images/titleBg.png b/admin/templates/images/titleBg.png new file mode 100644 index 0000000..fa86b95 Binary files /dev/null and b/admin/templates/images/titleBg.png differ diff --git a/admin/templates/images/topNav.jpg b/admin/templates/images/topNav.jpg new file mode 100644 index 0000000..b1aa198 Binary files /dev/null and b/admin/templates/images/topNav.jpg differ diff --git a/admin/templates/images/ui.totop.png b/admin/templates/images/ui.totop.png new file mode 100644 index 0000000..130cab4 Binary files /dev/null and b/admin/templates/images/ui.totop.png differ diff --git a/admin/templates/images/ui/arrow2Grey.png b/admin/templates/images/ui/arrow2Grey.png new file mode 100644 index 0000000..4b98c1f Binary files /dev/null and b/admin/templates/images/ui/arrow2Grey.png differ diff --git a/admin/templates/images/ui/basicBtn.png b/admin/templates/images/ui/basicBtn.png new file mode 100644 index 0000000..c6a98b5 Binary files /dev/null and b/admin/templates/images/ui/basicBtn.png differ diff --git a/admin/templates/images/ui/blackBtn.png b/admin/templates/images/ui/blackBtn.png new file mode 100644 index 0000000..0f48ad6 Binary files /dev/null and b/admin/templates/images/ui/blackBtn.png differ diff --git a/admin/templates/images/ui/blueBtn.png b/admin/templates/images/ui/blueBtn.png new file mode 100644 index 0000000..bcba4db Binary files /dev/null and b/admin/templates/images/ui/blueBtn.png differ diff --git a/admin/templates/images/ui/greenBtn.png b/admin/templates/images/ui/greenBtn.png new file mode 100644 index 0000000..da085c9 Binary files /dev/null and b/admin/templates/images/ui/greenBtn.png differ diff --git a/admin/templates/images/ui/greyishBtn.png b/admin/templates/images/ui/greyishBtn.png new file mode 100644 index 0000000..6e0d908 Binary files /dev/null and b/admin/templates/images/ui/greyishBtn.png differ diff --git a/admin/templates/images/ui/handle.png b/admin/templates/images/ui/handle.png new file mode 100644 index 0000000..44c6454 Binary files /dev/null and b/admin/templates/images/ui/handle.png differ diff --git a/admin/templates/images/ui/handle_hover.png b/admin/templates/images/ui/handle_hover.png new file mode 100644 index 0000000..91b9266 Binary files /dev/null and b/admin/templates/images/ui/handle_hover.png differ diff --git a/admin/templates/images/ui/leftNavSub.png b/admin/templates/images/ui/leftNavSub.png new file mode 100644 index 0000000..74f70b7 Binary files /dev/null and b/admin/templates/images/ui/leftNavSub.png differ diff --git a/admin/templates/images/ui/messageArrow_left.png b/admin/templates/images/ui/messageArrow_left.png new file mode 100644 index 0000000..cf0e99f Binary files /dev/null and b/admin/templates/images/ui/messageArrow_left.png differ diff --git a/admin/templates/images/ui/messageArrow_right.png b/admin/templates/images/ui/messageArrow_right.png new file mode 100644 index 0000000..6478330 Binary files /dev/null and b/admin/templates/images/ui/messageArrow_right.png differ diff --git a/admin/templates/images/ui/numDataBg.png b/admin/templates/images/ui/numDataBg.png new file mode 100644 index 0000000..94bec43 Binary files /dev/null and b/admin/templates/images/ui/numDataBg.png differ diff --git a/admin/templates/images/ui/orangeBtn.png b/admin/templates/images/ui/orangeBtn.png new file mode 100644 index 0000000..7d4bf53 Binary files /dev/null and b/admin/templates/images/ui/orangeBtn.png differ diff --git a/admin/templates/images/ui/pagination.png b/admin/templates/images/ui/pagination.png new file mode 100644 index 0000000..d11e3d4 Binary files /dev/null and b/admin/templates/images/ui/pagination.png differ diff --git a/admin/templates/images/ui/progress.png b/admin/templates/images/ui/progress.png new file mode 100644 index 0000000..fa3580a Binary files /dev/null and b/admin/templates/images/ui/progress.png differ diff --git a/admin/templates/images/ui/progressOverlay.png b/admin/templates/images/ui/progressOverlay.png new file mode 100644 index 0000000..2eed7a2 Binary files /dev/null and b/admin/templates/images/ui/progressOverlay.png differ diff --git a/admin/templates/images/ui/purpleBtn.png b/admin/templates/images/ui/purpleBtn.png new file mode 100644 index 0000000..d0cdc9c Binary files /dev/null and b/admin/templates/images/ui/purpleBtn.png differ diff --git a/admin/templates/images/ui/redBtn.png b/admin/templates/images/ui/redBtn.png new file mode 100644 index 0000000..7f62bb7 Binary files /dev/null and b/admin/templates/images/ui/redBtn.png differ diff --git a/admin/templates/images/ui/seaBtn.png b/admin/templates/images/ui/seaBtn.png new file mode 100644 index 0000000..e1b5d6b Binary files /dev/null and b/admin/templates/images/ui/seaBtn.png differ diff --git a/admin/templates/images/ui/sliderBg.png b/admin/templates/images/ui/sliderBg.png new file mode 100644 index 0000000..fa27d7f Binary files /dev/null and b/admin/templates/images/ui/sliderBg.png differ diff --git a/admin/templates/images/ui/sliderOverlay.png b/admin/templates/images/ui/sliderOverlay.png new file mode 100644 index 0000000..caa7820 Binary files /dev/null and b/admin/templates/images/ui/sliderOverlay.png differ diff --git a/admin/templates/images/ui/uploadDisabled.png b/admin/templates/images/ui/uploadDisabled.png new file mode 100644 index 0000000..bc1fc94 Binary files /dev/null and b/admin/templates/images/ui/uploadDisabled.png differ diff --git a/admin/templates/images/ui/whiteBtn.png b/admin/templates/images/ui/whiteBtn.png new file mode 100644 index 0000000..d4f16b7 Binary files /dev/null and b/admin/templates/images/ui/whiteBtn.png differ diff --git a/admin/templates/images/upload.png b/admin/templates/images/upload.png new file mode 100644 index 0000000..a947156 Binary files /dev/null and b/admin/templates/images/upload.png differ diff --git a/admin/templates/images/uploader/deleteFile.png b/admin/templates/images/uploader/deleteFile.png new file mode 100644 index 0000000..3865ccd Binary files /dev/null and b/admin/templates/images/uploader/deleteFile.png differ diff --git a/admin/templates/images/uploader/error.png b/admin/templates/images/uploader/error.png new file mode 100644 index 0000000..2fa47b3 Binary files /dev/null and b/admin/templates/images/uploader/error.png differ diff --git a/admin/templates/images/uploader/uploaded.png b/admin/templates/images/uploader/uploaded.png new file mode 100644 index 0000000..feff985 Binary files /dev/null and b/admin/templates/images/uploader/uploaded.png differ diff --git a/admin/templates/images/user.png b/admin/templates/images/user.png new file mode 100644 index 0000000..4c0c656 Binary files /dev/null and b/admin/templates/images/user.png differ diff --git a/admin/templates/images/userPic.png b/admin/templates/images/userPic.png new file mode 100644 index 0000000..7be2fcc Binary files /dev/null and b/admin/templates/images/userPic.png differ diff --git a/admin/templates/images/widgetBg.png b/admin/templates/images/widgetBg.png new file mode 100644 index 0000000..f011293 Binary files /dev/null and b/admin/templates/images/widgetBg.png differ diff --git a/admin/templates/js/docs.js b/admin/templates/js/docs.js new file mode 100644 index 0000000..46a4d43 --- /dev/null +++ b/admin/templates/js/docs.js @@ -0,0 +1,667 @@ +var AveDocs = { + + initialized: false, + + init: function () { + + if (this.initialized) + return; + + this.initialized = true; + }, + + + // + list: function () { + this.addDocument(); + this.documentCopy(); + this.selectAllDocuments(); + this.documentAction(); + this.documentPublish(); + this.documentRecycle(); + }, + + + // + edit: function () { + this.revisionDelete(); + this.revisionRecover(); + this.revisionsDelete(); + this.translitURL(); + this.checkURLInput(); + this.editDateTime(); + this.linkSelect(); + this.metaKeywords(); + this.documentLanguage(); + this.saveEditBtn(); + this.editMousetrap(); + this.windowOnLoadCKEditor(); + }, + + + // + search: function () { + this.searchDateTime(); + this.searchCollapsible(); + }, + + + // + addDocument: function () { + $(".AddDocument").on('click', function (event) { + event.preventDefault(); + + let rubricId = $('#addDocRub #rubricId').fieldValue(); + + if (rubricId == '') { + jAlert(add_doc_text, add_doc_title); + } else { + $.alerts._overlay('show'); + $("#addDocRub").submit(); + } + }); + }, + + + // + selectAllDocuments: function () { + $('#selectAll').on('change', function (event) { + event.preventDefault(); + + if ($('#selectAll').is(':checked')) { + $('#docs .checkbox').attr('checked', 'checked').addClass('jqTransformChecked'); + $("#docs a.jqTransformCheckbox").addClass("jqTransformChecked"); + } else { + $('#docs .checkbox').removeClass('jqTransformChecked').removeAttr('checked'); + $("#docs a.jqTransformCheckbox").removeClass("jqTransformChecked"); + } + }); + }, + + + // + documentPublish: function () { + $(".documentPublish").on('click', function (event) { + event.preventDefault(); + + let link = $(this); + let doc_id = link.data('id'); + + $.ajax({ + type: 'POST', + url: 'index.php?do=docs&action=publish&cp=' + sess, + data: { + 'doc_id': doc_id + }, + dataType: 'JSON', + beforeSend: function () { + $.alerts._overlay('show'); + }, + success: function (data) { + $.alerts._overlay('hide'); + + if (data.success) { + + (data.status != 1) + ? link.closest('tr').addClass('yellow') + : link.closest('tr').removeClass('yellow'); + + (data.status != 1) + ? link.addClass('public') + : link.removeClass('public'); + + link.attr('title', data.text); + + AveAdmin.tooltip(); + } + + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + }); + }); + }, + + + // + documentRecycle: function () { + $(".documentRecycle").on('click', function (event) { + event.preventDefault(); + + let link = $(this); + let link_tr = link.closest('tr'); + let link_publish = link_tr.find('.documentPublish'); + let doc_id = link.data('id'); + + $.ajax({ + type: 'POST', + url: 'index.php?do=docs&action=recycle&cp=' + sess, + data: { + 'doc_id': doc_id + }, + dataType: 'JSON', + beforeSend: function () { + $.alerts._overlay('show'); + }, + success: function (data) { + $.alerts._overlay('hide'); + + if (data.success) { + + (data.status == 1) + ? link_tr.removeClass('yellow').addClass('red') + : link_tr.removeClass('red'); + + (data.status == 1) + ? link.addClass('recylce') + : link.removeClass('recylce'); + + (data.status == 1) + ? link_publish.addClass('hidden') + : link_publish.removeClass('hidden'); + + if (data.status == 0 && link_publish.hasClass('public')) { + link_tr.addClass('yellow') + } + + link.attr('title', data.text); + + AveAdmin.tooltip(); + } + + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + }); + }); + }, + + + // + documentCopy: function () { + $(".documentCopy").on('click', function (event) { + event.preventDefault(); + + let href = $(this).attr('href'); + + jPrompt(copy_doc_text, '', copy_doc_title, function (data) { + if (data) { + $.alerts._overlay('show'); + window.location = href + '&document_title=' + data; + } else { + $.jGrowl(copy_doc_no, {theme: 'error'}); + } + }); + }); + }, + + + // + documentAction: function () { + $(".docaction").hover( + function () { $(this).children(".actions").show("fade", 10); }, + function() { $(this).children(".actions").hide("fade", 10); } + ); + }, + + + // + searchDateTime: function () { + $('#document_published').datepicker({ + changeMonth: true, + changeYear: true, + + onClose: function (dateText, inst) { + var endDateTextBox = $('#document_expire'); + if (endDateTextBox.val() != '') { + var testStartDate = new Date(dateText); + var testEndDate = new Date(endDateTextBox.val()); + if (testStartDate > testEndDate) + endDateTextBox.val(dateText); + } + else { + endDateTextBox.val(dateText); + } + }, + onSelect: function (selectedDateTime) { + var start = $(this).datetimepicker('getDate'); + $('#document_expire').datetimepicker('option', 'minDate', new Date(start.getTime())); + } + }); + + $('#document_expire').datepicker({ + changeMonth: true, + changeYear: true, + + onClose: function (dateText, inst) { + var startDateTextBox = $('#document_published'); + if (startDateTextBox.val() != '') { + var testStartDate = new Date(startDateTextBox.val()); + var testEndDate = new Date(dateText); + if (testStartDate > testEndDate) + startDateTextBox.val(dateText); + } + else { + startDateTextBox.val(dateText); + } + }, + onSelect: function (selectedDateTime) { + var end = $(this).datetimepicker('getDate'); + $('#document_published').datetimepicker('option', 'maxDate', new Date(end.getTime())); + } + }); + }, + + + // + searchCollapsible: function () { + $('.collapsible').collapsible({ + defaultOpen: 'opened', + cssOpen: 'inactive', + cssClose: 'normal', + cookieName: 'collaps_doc', + cookieOptions: { + expires: 7, + domain: '' + }, + speed: 5, + loadOpen: function (elem, opts) { + elem.next().show(); + }, + loadClose: function (elem, opts) { + elem.next().hide(); + } + }); + + $('.collapsible').on('click', function () { + setTimeout(function () { + AveAdmin.sticky_panel_refresh(); + AveAdmin.select_form(); + }, 10); + }); + }, + + + // + revisionRecover: function () { + $(".recoverRevision").on('click', function (event) { + event.preventDefault(); + + let href = $(this).attr('href'), + title = $(this).data('title'), + confirm = $(this).data('confirm'); + + jConfirm( + confirm, + title, + function (success) { + if (success) { + $.alerts._overlay('show'); + window.location = href; + } + } + ); + }); + }, + + + // + revisionDelete: function () { + $(".deleteRevision").on('click', function (event) { + event.preventDefault(); + + let revission = $(this).data('rev'), + href = $(this).attr('href'), + title = $(this).data('title'), + confirm = $(this).data('confirm'); + + jConfirm( + confirm, + title, + function (success) { + if (success) { + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + $.ajax({ + url: ave_path + 'admin/' + href + '&ajax=run', + type: 'POST', + success: function (data) { + $.alerts._overlay('hide'); + + $.jGrowl(revission, { theme: 'accept' }); + + $("#" + revission).remove(); + } + }); + } + } + ); + }); + }, + + + // + revisionsDelete: function () { + $(".deleteRevisions").on('click', function (event) { + event.preventDefault(); + + let href = $(this).attr('href'), + title = $(this).data('title'), + confirm = $(this).data('confirm'); + + jConfirm( + confirm, + title, + function (success) { + if (success) { + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + $.ajax({ + url: ave_path + 'admin/' + href, + type: 'POST', + dataType: 'JSON', + success: function (data) { + $.alerts._overlay('hide'); + + $.jGrowl(data.message, { theme: 'accept' }); + + $('#tableRevisions').find('tbody').html(''); + } + }); + } + } + ); + }); + }, + + + // + checkURL: function () { + + let alias = $("#document_alias").val(), + doc_id = $('#formDoc').data('id'); + + $.ajax({ + beforeSend: function () { + }, + url: 'index.php', + data: ({ + 'action': 'checkurl', + 'do': 'docs', + 'check': false, + 'cp': sess, + 'id': doc_id, + 'alias': alias + }), + timeout: 3000, + dataType: 'JSON', + success: + function (data) { + $.jGrowl(data[0], {theme: data[1]}); + } + }); + }, + + + // + translitURL: function () { + $("#translit").on('click', function () { + + let alias = $("#document_alias").val(), + title = $("#document_title").val(), + prefix = $('#formDoc').data('prefix'); + + $.ajax({ + beforeSend: function () { + $("#checkResult").html(''); + }, + url: 'index.php', + data: ({ + 'action': 'translit', + 'do': 'docs', + 'cp': sess, + 'alias': alias, + 'title': title, + 'prefix': prefix + }), + timeout: 3000, + success: function (data) { + $("#document_alias").val(data); + AveDocs.checkURL(); + } + }); + }); + }, + + + // + checkURLInput: function () { + $("#document_alias").on('change', function () { + if ($(this).val() != '') + AveDocs.checkURL(); + }); + }, + + + // + editDateTime: function () { + $('#document_published').datetimepicker({ + changeMonth: true, + changeYear: true, + stepHour: 1, + stepMinute: 1, + + onClose: function (dateText, inst) { + var endDateTextBox = $('#document_expire'); + if (endDateTextBox.val() != '') { + var testStartDate = new Date(dateText); + var testEndDate = new Date(endDateTextBox.val()); + if (testStartDate > testEndDate) + endDateTextBox.val(dateText); + } + else { + endDateTextBox.val(dateText); + } + } + }); + + $('#document_expire').datetimepicker({ + changeMonth: true, + changeYear: true, + + stepHour: 1, + stepMinute: 1, + + onClose: function (dateText, inst) { + var startDateTextBox = $('#document_published'); + if (startDateTextBox.val() != '') { + var testStartDate = new Date(startDateTextBox.val()); + var testEndDate = new Date(dateText); + if (testStartDate > testEndDate) + startDateTextBox.val(dateText); + } + else { + startDateTextBox.val(dateText); + } + }, + onSelect: function (selectedDateTime) { + var end = $(this).datetimepicker('getDate'); + $('#document_published').datetimepicker('option', 'maxDate', new Date(end.getTime())); + } + }); + }, + + + // + linkSelect: function () { + $(".linkSelect").on('change', function() { + let link = $(this).val(), + parent = $(this).find('option:selected').attr("data-id"), + prefix = $('#formDoc').data('prefix'); + + if (prefix == '') { + $("#document_alias").val(link); + } else { + $("#document_alias").val(link + '/' + prefix); + } + + $("#document_parent").val(parent); + + return false; + }); + }, + + + // + metaKeywords: function () { + $("#document_meta_keywords").autocomplete("index.php?do=docs&action=keywords&ajax=run&cp=" + sess, { + max: 20, + width: 300, + highlight: false, + multiple: true, + multipleSeparator: ", ", + autoFill: true, + scroll: true, + scrollHeight: 180 + }); + }, + + + // + documentLanguage: function () { + $('#document_lang').on('change', function () { + + let lang = $('#document_lang option:selected').val(), + alias = $('#document_alias').val().split('/'), + languages = []; + + $('#document_lang option').each(function () { + languages.push($(this).attr('value')); + }); + + if ($.inArray(alias[0], languages) > -1) { + alias.splice(0, 1); + } + + if ((lang == defaultLang) || (lang == noneLanguage)) { + $('#document_alias').val(alias.join('/')); + } else { + if (alias[0] != "") { + $('#document_alias').val(lang + '/' + alias.join('/')); + } else { + $('#document_alias').val(lang); + } + } + }); + + $('#lang_block').hide(); + + $('#show_lang').on('click', function (event) { + event.preventDefault(); + + $('#lang_block').show(); + $('#show_lang').hide(); + }); + }, + + + // + documentSaveFunction: function () { + let form = $('#formDoc'); + + form.ajaxSubmit({ + url: form.attr('action'), + dataType: 'JSON', + beforeSubmit: function () { + $.alerts._overlay('show'); + }, + success: function (data) { + $.alerts._overlay('hide'); + + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + }); + }, + + + // + saveDocument: function () { + let form = $('#formDoc'); + + if (window.CKEDITOR) + for (var instanceName in CKEDITOR.instances) + CKEDITOR.instances[instanceName].updateElement(); + + if (form.data('id') > 0) { + AveDocs.documentSaveFunction(); + } else { + form.submit(); + } + }, + + + // + documentSee: function () { + let form = $('#formDoc'), + doc_id = form.data('id'); + + if (doc_id > 0) { + window.open('/index.php?id=' + doc_id, '_blank'); + } else { + jAlert(alert_none_id, alert_none_id_t); + } + }, + + + // + saveEditBtn: function () { + $('.SaveEdit').on('click', function (event) { + event.preventDefault(); + if (window.CKEDITOR) + for (var instanceName in CKEDITOR.instances) + CKEDITOR.instances[instanceName].updateElement(); + + AveDocs.saveDocument(); + return false; + }); + }, + + + // + editMousetrap: function () { + Mousetrap.bind(['ctrl+s', 'command+s'], function (event) { + event.preventDefault(); + if (window.CKEDITOR) + for (var instanceName in CKEDITOR.instances) + CKEDITOR.instances[instanceName].updateElement(); + + AveDocs.saveDocument(); + return false; + }); + + Mousetrap.bind(['ctrl+o', 'command+o'], function (event) { + event.preventDefault(); + AveDocs.documentSee(); + return false; + }); + }, + + + // + windowOnLoadCKEditor: function () { + window.onload = function () { + if (window.CKEDITOR) { + CKEDITOR.on('instanceReady', function (event) { + event.editor.setKeystroke(CKEDITOR.CTRL + 83 /*S*/, 'savedoc'); + }); + } + } + } +}; \ No newline at end of file diff --git a/admin/templates/js/filemanager.js b/admin/templates/js/filemanager.js new file mode 100644 index 0000000..47f97f9 --- /dev/null +++ b/admin/templates/js/filemanager.js @@ -0,0 +1,51 @@ +$().ready(function() { + + // отдельный файловый менеджер + $('#finder').elfinder({ + url : ave_path+'lib/redactor/elfinder/php/connector.php', + lang : 'ru', + height : 500, + title : 'Файловый менеджер' + }).elfinder('instance'); + + + // диалог выбора изображений + $('.dialog_images').click(function() { + var id = $(this).attr("rel"); + $('
    ').dialogelfinder({ + url : ave_path+'lib/redactor/elfinder/php/connector.php', + lang : 'ru', + width : 1100, + height: 600, + modal : true, + title : 'Файловый менеджер', + getFileCallback : function(files, fm) { + $("#image__"+id).val('/'+files['url'].slice(1)); + $("#images_feld_"+id).html(""); + }, + commandsOptions : { + getfile : { + oncomplete : 'destroy', + folders : false + } + } + }) + }); + + + $('#elFinder a').hover( + function () { + $('#elFinder a').animate({ + 'background-position' : '0 -45px' + }, 300); + }, + function () { + $('#elFinder a').delay(400).animate({ + 'background-position' : '0 0' + }, 300); + } + ); + + + +}); diff --git a/admin/templates/js/filemanager_template.js b/admin/templates/js/filemanager_template.js new file mode 100644 index 0000000..3819291 --- /dev/null +++ b/admin/templates/js/filemanager_template.js @@ -0,0 +1,22 @@ +$(function() { + // отдельный файловый менеджер + $('#finder').elfinder({ + url : ave_path+'lib/redactor/elfinder/php/connector_template.php', + lang : 'ru', + height : 500, + title : 'Файловый менеджер' + }).elfinder('instance'); + + $('#elFinder a').hover( + function () { + $('#elFinder a').animate({ + 'background-position' : '0 -45px' + }, 300); + }, + function () { + $('#elFinder a').delay(400).animate({ + 'background-position' : '0 0' + }, 300); + } + ); +}); diff --git a/admin/templates/js/login.js b/admin/templates/js/login.js new file mode 100644 index 0000000..99a1749 --- /dev/null +++ b/admin/templates/js/login.js @@ -0,0 +1,4 @@ +$(document).ready(function(){ + $("form.mainForm").jqTransform({imgPath:"../images"}); + $("#captcha-ref").click(function() { $("#captcha img").attr("src", '../inc/captcha.php?refresh=' + new Date().getTime()); }); +}); \ No newline at end of file diff --git a/admin/templates/js/main.js b/admin/templates/js/main.js new file mode 100644 index 0000000..3f24a11 --- /dev/null +++ b/admin/templates/js/main.js @@ -0,0 +1,1101 @@ +/* + * jQuery windowResizeFix + * + */ +(function($) { + + if (document.windowResizeFixFired) { + return; + } + document.windowResizeFixFired = true; + + var $window = $(window), + _wWidth = $window.width(), + _wHeight = $window.height(); + + $window.on('resize', + + function(event) { + var _nWidth = $window.width(), + _nHeight = $window.height(); + + if (_wWidth == _nWidth && _wHeight == _nHeight) { + event.preventDefault(); + event.stopImmediatePropagation(); + return; + } + _wWidth = _nWidth; + _wHeight = _nHeight; + }); + +})(jQuery); + +function browse_uploads(target, width, height, scrollbar) { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.8; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.8; + if (typeof scrollbar == 'undefined') var scrollbar = 0; + let targetVal = document.getElementById(target).value; + if (!(document.getElementById(target).value).length && (document.getElementById(target).dataset.default).length) { + targetVal = document.getElementById(target).dataset.default; + } + let left = (screen.width - width) / 2; + let top = (screen.height - height) / 2; + window.open('index.php?do=browser&type=image&target=' + target + '&tval=' + targetVal, 'imgpop', 'left=' + left + ',top=' + top + ',width=' + width + ',height=' + height + ',scrollbars=' + scrollbar + ',resizable=1'); +} + +function browse_dirs(target, width, height, scrollbar) { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.8; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.8; + if (typeof scrollbar == 'undefined') var scrollbar = 0; + var left = (screen.width - width) / 2; + var top = (screen.height - height) / 2; + window.open('index.php?do=browser&type=directory&target=' + target, 'imgpop', 'left=' + left + ',top=' + top + ',width=' + width + ',height=' + height + ',scrollbars=' + scrollbar + ',resizable=1'); +} + +function windowOpen(url, width, height, scrollbar, winname) { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.8; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.8; + if (typeof scrollbar == 'undefined') var scrollbar = 1; + if (typeof winname == 'undefined') var winname = 'pop'; + var left = (screen.width - width) / 2; + var top = (screen.height - height) / 2; + window.open(url, winname, 'left=' + left + ',top=' + top + ',width=' + width + ',height=' + height + ',scrollbars=' + scrollbar + ',resizable=1').focus(); +} + +function openLinkWindow(target, doc, document_alias) { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.6; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.6; + if (typeof doc == 'undefined') var doc = 'Title'; + if (typeof scrollbar == 'undefined') var scrollbar = 1; + var left = (screen.width - width) / 2; + var top = (screen.height - height) / 2; + window.open('index.php?doc=' + doc + '&target=' + target + '&document_alias=' + document_alias + '&do=docs&action=showsimple&cp=' + sess + '&pop=1', 'pop', 'left=' + left + ',top=' + top + ',width=' + width + ',height=' + height + ',scrollbars=' + scrollbar + ',resizable=1'); +} + +function openFileWindow(target, id, document_alias) { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.6; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.6; + if (typeof doc == 'undefined') var doc = 'Title'; + if (typeof scrollbar == 'undefined') var scrollbar = 1; + var left = (screen.width - width) / 2; + var top = (screen.height - height) / 2; + window.open('index.php?do=browser&id=' + id + '&type=file&target=navi&cp=' + sess, 'pop', 'left=' + left + ',top=' + top + ',width=' + width + ',height=' + height + ',scrollbars=' + scrollbar + ',resizable=1'); +} + +// Функция-плагин для включения tipsy сразу для всех классов внутри элемента +(function($) { + $.fn.addTipsy = function() { + this.find(' .topDir').tipsy({ + fade: false, + gravity: 's', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .topleftDir').tipsy({ + fade: false, + gravity: 'se', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .toprightDir').tipsy({ + fade: false, + gravity: 'sw', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .botDir').tipsy({ + fade: false, + gravity: 'n', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .bottomDir').tipsy({ + fade: false, + gravity: 'n', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .botleftDir').tipsy({ + fade: false, + gravity: 'ne', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .botrightDir').tipsy({ + fade: false, + gravity: 'nw', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .leftDir').tipsy({ + fade: false, + gravity: 'e', + opacity: 0.9, + live: true, + delayOut: 0 + }); + this.find(' .rightDir').tipsy({ + fade: false, + gravity: 'w', + opacity: 0.9, + live: true, + delayOut: 0 + }); + }; +})(jQuery); + +/** + * Плагин для подключения сортировки к таблице + * + * @param mixed items селектор для сортируемых элементов default: 'tr' + * @param mixed handle селектор для элемента, который активирует перетаскивание default: '.ico_move' + * @param string url адрес, куда будет отправлена последовательность элементов + * @param string key имя массива $_GET[key] default: 'sort' + * @param string attr имя аттрибута, по которому считываются id элементов default: 'data-id' + * @param string success текст, которые показывает всплывашка в случае успеха default: 'Порядок сохранён' + */ +(function($) { + $.fn.tableSortable = function(options) { + options = $.extend({}, $.fn.tableSortable.defaults, options); + this.sortable({ + items: options.items, + axis: 'y', + cursor: 'move', + tolerance: 'pointer', + handle: options.handle, + helper: 'clone', + placeholder: 'sortable-placeholder', + start: function(event, ui) { + // задаём placeholder + $(this).find(' .sortable-placeholder').html(ui.item.html()).css({ + 'opacity': 0.2 + }); + // назначаем колонкам ширину + origTd = $(this).find(' .sortable-placeholder td'); + ui.helper.find(' td').each(function(index, element) { + $(element).width(origTd.eq(index).width()); + }); + }, + stop: function(event, ui) { + // удаляем ширину колонок + ui.item.find(' tr:first td').each(function(index, element) { + $(element).width(''); + }); + + $('.tipsy').remove(); + }, + update: function(event, ui) { + // отправляем результаты сортировки + sorted = $(this).sortable('serialize', { + key: options.key + '[]', + attribute: options.attr + }); + $.ajax({ + url: options.url + '&' + sorted, + dataType: 'json', + success: function(data) { + if (options.success == true) { + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + } + }); + } + }); + }; + + $.fn.tableSortable.defaults = { + items: 'tr', + handle: '.ico_move', + url: 'index.php?', + key: 'sort', + attr: 'data-id', + success: false + }; + +})(jQuery); + +//===== Tabs =====// +$.fn.simpleTabs = function() +{ + $("ul.tabs li").click(function() + { + $(this).parent().parent().find("ul.tabs li").removeClass("activeTab"); + $(this).addClass("activeTab"); + $(this).parent().parent().find(".tab_content").hide(); + + var activeTab = $(this).find("a").attr("href"); + + $(activeTab).show(); + + $('.CodeMirror').each(function(i, el) + { + el.CodeMirror.refresh(); + }); + + AveAdmin.select_form(); + AveAdmin.sticky_panel_refresh(); + + return false; + }); +}; + + +$.fn.extend({ + limit: function(limit, element) { + var interval, f; + var self = $(this); + $(this).focus(function() { + interval = window.setInterval(substring, 100) + }); + $(this).blur(function() { + clearInterval(interval); + substring() + }); + substringFunction = "function substring(){ var val = $(self).val();var length = val.length;if(length > limit){$(self).val($(self).val().substring(0,limit));}"; + if (typeof element != 'undefined') substringFunction += "if($(element).html() != limit-length){$(element).html((limit-length<=0)?'0':limit-length);}"; + substringFunction += "}"; + eval(substringFunction); + substring() + } +}); + + +// Запускаем после загрузки документа +$(function() { + $(document) + .ajaxStart(function() { + NProgress.start(); + }) + .ajaxStop(function() { + NProgress.done(); + }); + // настройка аякса + $.ajaxSetup({ + cache: false, + error: function(jqXHR, exception) { + if (jqXHR.status === 0) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus, { + theme: 'error' + }); + } else if (jqXHR.status == 404) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus404, { + theme: 'error' + }); + } else if (jqXHR.status == 401) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus401, { + theme: 'error' + }); + } else if (jqXHR.status == 500) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus500, { + theme: 'error' + }); + } else if (exception === 'parsererror') { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusJSON, { + theme: 'error' + }); + } else if (exception === 'timeout') { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusTimeOut, { + theme: 'error' + }); + } else if (exception === 'abort') { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusAbort, { + theme: 'error' + }); + } else { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusMess + jqXHR.responseText, { + theme: 'error' + }); + } + } + }); + + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.7; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.7; + + //===== Dynamic Tables =====// + oTable = $('#dinamTable').dataTable({ + "bJQueryUI": true, + "sPaginationType": "full_numbers", + "aaSorting": [ + [0, "desc"] + ], + "sDom": '<""f>t<"F"lp>' + }); + + //===== Information boxes =====// + $(".hideit").click(function() { + $(this).fadeOut(400); + }); + + $("div[class^='widget']").simpleTabs(); //Run function on any div with class name of "Simple Tabs" + +}); + +var AveAdmin = { + + initialized: false, + + initialize: function() { + + if (this.initialized) return; + this.initialized = true; + + this.build(); + this.events(); + + }, + + build: function() { + this.toggleMenu(); + this.clear_cache(); + this.clear_cache_sess(); + this.clear_cache_thumb(); + this.clear_revisions(); + this.clear_counter(); + this.cache_show(); + this.docs_show(); + this.main_form(); + this.select_form(); + this.sticky_panel(); + this.customInput(); + this.fancy_box(); + this.fancy_frame(); + this.tooltip(); + this.place_holder(); + this.collapsible_elements(); + this.docPosition(); + }, + + events: function() { + this.a_actions(); + this.drop_down(); + this.collapsible_select(); + this.confirm_logout(); + this.confirm_delete(); + this.ui_totop(); + this.modalDialog(); + this.trim(); + }, + + ajax: function() { + this.select_form(); + this.main_form(); + this.place_holder(); + //this.modalDialog(); + }, + + //UItoTop + ui_totop: function() { + + $().UItoTop({ + easingType: 'easeOutQuart' + }); + }, + + toggleMenu: function() { + if ($("[id^='toggle']").length) { + $.each(["LeftMenu"], function(key, value) { + //Считываем cookie + var toggle = $.cookie(value); + //Проверяем cookie + if (toggle == 'hidden') { + $(".leftNav").addClass("hidden"); + $(".dd_page").css("display", ""); + } else { + $("#leftNav_show span").addClass("close"); + $(".dd_page").css("display", "none"); + } + + $("[id='toggle-" + this + "']").click(function() { + if ($(".leftNav").hasClass('hidden')) { + $(".dd_page").css("display", "none"); + $(".leftNav").removeClass('hidden').addClass('visible'); + $("#leftNav_show span").addClass("close"); + $.cookie(value, 'visible'); + } else { + $(".dd_page").css("display", ""); + $(".leftNav").removeClass('visible').addClass('hidden'); + $("#leftNav_show span").removeClass("close"); + $.cookie(value, 'hidden'); + } + }); + }); + } + }, + + //Окно очистки кэша + clear_cache: function() { + + $(".clearCache").click(function(event) { + event.preventDefault(); + var title = clearCacheTitle; + var confirm = clearCacheConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=clearcache&ajax=run', + type: 'POST', + dataType: "json", + data: ({ + templateCache: 1, + templateCompiledTemplate: 1, + moduleCache: 1, + sqlCache: 1 + }), + success: function(data) { + $.alerts._overlay('hide'); + $.jGrowl(data[0], { + theme: data[1] + }); + $('#cachesize').html('0 Kb'); + $('.cachesize').html('0 Kb'); + } + }); + + } + } + ); + }); + + }, + + //Collapsible elements management + collapsible_elements: function() { + + var width = $("div.content").width(); + + $('.opened').collapsible({ + defaultOpen: 'opened', + cssOpen: 'inactive', + cssClose: 'normal', + speed: 5, + loadOpen: function(elem, opts) { + elem.next().show(); + }, + loadClose: function(elem, opts) { + elem.next().hide(); + } + }); + + $('.closed').collapsible({ + defaultOpen: '', + cssOpen: 'inactive', + cssClose: 'normal', + speed: 5, + loadOpen: function(elem, opts) { + elem.next().show(); + }, + loadClose: function(elem, opts) { + elem.next().hide(); + } + }); + + setTimeout(function() { + AveAdmin.sticky_panel_refresh(); + AveAdmin.select_form(); + }, 10); + }, + + //Окно очистки кэша + Сессий + clear_cache_sess: function() { + + $(".clearCacheSess").click(function(event) { + event.preventDefault(); + var title = clearCacheSessTitle; + var confirm = clearCacheSessConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=clearcache&ajax=run', + type: 'POST', + dataType: "json", + data: ({ + templateCache: 1, + templateCompiledTemplate: 1, + moduleCache: 1, + sqlCache: 1, + sessionUsers: 1 + }), + success: function(data) { + $.alerts._overlay('hide'); + $.jGrowl(data[0], { + theme: data[1] + }); + $('#cachesize').html('0 Kb'); + $('.cachesize').html('0 Kb'); + } + }); + } + } + ); + }); + + }, + + //Окно очистки ревизий документов + clear_revisions: function() { + + $(".clearRev").click(function(event) { + event.preventDefault(); + var title = clearRevTitle; + var confirm = clearRevConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=clearrevision&ajax=run', + type: 'POST', + dataType: "json", + success: function(data) { + $.alerts._overlay('hide'); + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + }); + } + } + ); + }); + }, + + //Окно очистки ревизий документов + clear_counter: function() { + + $(".clearCount").click(function(event) { + event.preventDefault(); + var title = clearCountTitle; + var confirm = clearCountConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=clearcounter&ajax=run', + type: 'POST', + dataType: "json", + success: function(data) { + $.alerts._overlay('hide'); + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + }); + } + } + ); + }); + }, + + //Окно очистки миниатюр изображений + clear_cache_thumb: function() { + + $(".clearThumb").click(function(event) { + event.preventDefault(); + var title = clearThumbTitle; + var confirm = clearThumbConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=clearthumb&ajax=run', + type: 'POST', + dataType: "json", + success: function(data) { + $.alerts._overlay('hide'); + $.jGrowl(data[0], { + theme: data[1] + }); + } + }); + } + } + ); + }); + }, + + //Показать размер кэша + cache_show: function() { + + $("#cacheShow").click(function(event, x) { + event.preventDefault(); + var title = cacheShowTitle; + var confirm = cacheShowConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=showcache&ajax=run', + type: 'POST', + dataType: "json", + data: ({ + showCache: 1 + }), + success: function(data) { + $.alerts._overlay('hide'); + $('#cachesize').html(data[0]); + } + }); + } + } + ); + }); + + }, + + + //Показать размер кэша + docs_show: function() { + + $('.showDocs').click(function(event, x) { + event.preventDefault(); + + var title = docsShowTitle; + var confirm = docsShowConfirm; + + var rubric_id = $(this).attr('data-rubric-id'); + + var block = $(this); + + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + $.ajax({ + url: ave_path + 'admin/index.php?do=settings&sub=showcountdocs', + type: 'POST', + data: ({ + rubric_id: rubric_id + }), + success: function(data) { + $.alerts._overlay('hide'); + block.before(data).remove(); + } + }); + } + } + ); + }); + + }, + + //Окно удаления едемента + confirm_delete: function() { + + $(document).on('click' , '.ConfirmDelete', function(event) { + event.preventDefault(); + var href = $(this).attr('href'); + var title = $(this).attr('dir'); + var confirm = $(this).attr('name'); + jConfirm( + confirm, + title, + function(b) { + if (b) { + $.alerts._overlay('show'); + window.location = href; + } + } + ); + }); + + }, + + //Выход + confirm_logout: function() { + + $(".ConfirmLogOut").click(function(event) { + event.preventDefault(); + var href = $(this).attr('href'); + var title = logoutTitle; + var confirm = logoutConfirm; + jConfirm( + confirm, + title, + function(b) { + if (b) window.location = href; + } + ); + }); + + }, + + //Прилипающая панель с кнопками + sticky_panel_refresh: function() { + + if ($("#saveBtn").length > 0) { + + $("#saveBtn").trigger('refresh'); + + var offset = $('#saveBtn').offset(); //Положение кнопок на странице + var width = $("div.content").width(); //ширина + + if ($(document).scrollTop() < offset.top - $(window).height()) { + $('.saveBtn').addClass('fixedBtn').css({ + "width": width - 20 + }); + } else { + $('.saveBtn').removeClass('fixedBtn').removeAttr('style'); + } + } + + }, + + //Прилипающая панель с кнопками + sticky_panel: function() { + + if ($("#saveBtn").length > 0) { + + var offset = $('#saveBtn').offset(); //Положение кнопок на странице + var width = $("div.content").width(); //ширина + + if ($(document).scrollTop() < offset.top - $(window).height()) { + $('.saveBtn').addClass('fixedBtn').css({ + "width": width - 20 + }); + } + + $(window).scroll(function() { + + var offset = $('#saveBtn').offset(); //Положение кнопок на странице + var scroll_top = $(document).scrollTop(); //высота прокрученной области + var window_height = $(window).height(); //высота окна браузера + var width = $("div.content").width(); //ширина + + if (scroll_top < offset.top - window_height) { + $('.saveBtn').addClass('fixedBtn').css({ + "width": width - 20 + }); + } else { + $('.saveBtn').removeClass('fixedBtn').removeAttr('style'); + } + }); + + $(window).on( + 'resize', + function() { + $(window).resize(function() { + var width = $("div.content").width(); //ширина + $('.saveBtn').css({ + "width": width - 20 + }); + }); + } + ); + + } + + }, + + //Custom single file input + customInput: function() { + $("input[type=file].input_file").nicefileinput({ + label: 'Выбрать...' + }); + }, + + // jQuery UI Dialog + modalDialog: function() { + $('a.openDialog').on('click', function(event) { + event.preventDefault(); + var idDialog = ($(this).attr('data-dialog')) ? $(this).attr('data-dialog') : ''; + var ajaxDialog = $('').appendTo('body'); + var dialogTitle = ($(this).attr('data-title')) ? $(this).attr('data-title') : 'Modal'; + var dialogModal = ($(this).attr('data-modal')) ? $(this).attr('data-modal') : false; + var dialogHref = ($(this).attr('href')) ? $(this).attr('href') : 'index.php'; + var dialogWidth = ($(this).attr('data-width')) ? $(this).attr('data-width') : undefined; + var dialogHeight = ($(this).attr('data-height')) ? $(this).attr('data-height') : undefined; + var dialogTemplate = ($(this).attr('data-template')) ? $(this).attr('data-template') : '&onlycontent=1'; + + if (typeof dialogWidth == 'undefined' || dialogWidth == '') var dialogWidth = $(window).width() * 0.9; + if (typeof dialogHeight == 'undefined' || dialogHeight == '') var dialogHeight = $(window).height() * 0.8; + + ajaxDialog.dialog({ + autoOpen: false, + modal: dialogModal, + dialogClass: 'fixed-dialog', + close: function(event, ui) { + $(this).dialog('destroy').remove(); + } + }); + + $('#' + ajaxDialog.attr('id')).load(dialogHref + dialogTemplate, function() { + ajaxDialog.dialog("option", "title", dialogTitle); + if (typeof(dialogWidth) !== "undefined") { + ajaxDialog.dialog("option", "width", dialogWidth); + ajaxDialog.dialog("option", "height", dialogHeight); + } + ajaxDialog.dialog("open"); + }); + return false; + }); + }, + + //функция-аналог trim в php + trim: function() { + + if (!String.prototype.trim) { + String.prototype.trim = function() { + return this.replace(/^\s+|\s+$/g, ''); + }; + } + }, + + //Tooltip + tooltip: function() { + $('body').addTipsy(); + }, + + // Fancybox + fancy_box: function() { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.8; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.7; + $("a.fancy").fancybox({ + padding: 0, + margin: '30px', + autoScale: true, + speedIn: 100, + speedOut: 100, + overlayOpacity: 0.5, + overlayColor: "#000", + centerOnScroll: true, + width: width, + height: height + }); + }, + + // Fancybox + fancy_frame: function() { + if (typeof width == 'undefined' || width == '') var width = screen.width * 0.8; + if (typeof height == 'undefined' || height == '') var height = screen.height * 0.7; + $("a.iframe").fancybox({ + padding: 0, + margin: 0, + width: width, + height: height, + autoScale: true, + speedIn: 100, + speedOut: 100, + overlayOpacity: 0.5, + overlayColor: "#000", + centerOnScroll: true + }); + }, + + select_form: function() { + setTimeout(function() { + $(".mainForm select").styler({ + selectVisibleOptions: 5, + selectSearch: false + }); + + $(".mainForm select").trigger('refresh'); + }, 100); + }, + + collapsible_select: function () { + $('.head.closed').on('click', function(){ + AveAdmin.select_form(); + }); + }, + + // Преобразование форм + main_form: function() { + $(".mainForm").jqTransform({ + imgPath: "../images" + }); + }, + + // Placeholder for all browsers + place_holder: function() { + $('input[placeholder], textarea[placeholder]').placeholder(); + }, + + // A transactions + a_actions: function() { + $('.actions a').hover(function() { + $(this).animate({ + opacity: 1.0 + }, 100); + }, function() { + $(this).animate({ + opacity: 0.5 + }, 100); + }); + }, + + // DropDown menu + drop_down: function() { + $(".dropdown").on("mouseenter mouseleave", function(event) { + var ul = $(this).children("ul"); + ul.stop(true, true); + if (event.type === "mouseenter") { + ul.slideToggle(10); + } else { + ul.hide(10); + } + }); + }, + + docPosition: function () { + $('.position').each(function(i,item) { + + var q_buttons = $('').prependTo($(item)); + var q_up = $('+').appendTo($(q_buttons)); + var q_down = $('-').appendTo($(q_buttons)); + + $(q_up).on('click',function(event) { + + event.preventDefault(); + + $(q_submit).css({'display':'block'}); + + value = parseInt($(item).find('.position_value').val()); + value += 1; + + $(item).find('.position_value').val(value); + }); + + $(q_down).on('click',function(event){ + + event.preventDefault(); + + $(q_submit).css({'display':'block'}); + + value = parseInt($(item).find('.position_value').val()); + + value = (value < 1 ? 0 : value-1); + + $(item).find('.position_value').val(value); + }); + + if ($(item).hasClass('nosubmit')) { + + $(item).off('submit'); + + } else { + var q_submit = $('OK').appendTo($(q_buttons)); + var q_loading = $('').appendTo($(q_buttons)); + + $(q_submit).css({'display':'none'}); + $(q_loading).css({'display':'none'}); + + $(item).find('.position_value').on('change',function(){ + $(q_submit).css({'display':'block'}); + return false; + }); + + $(item).find('.position_value').on('focus',function(){ + $(q_submit).css({'display':'block'}); + }); + + $(item).on('blur',function(){ + $(q_submit).css({'display':'none'}); + }); + + $(item).on('submit',function(){ + $(q_submit).css({'display':'none'}); + $(q_loading).css({'display':'block'}); + + var dataForm = { + 'action': 'changepos', + 'id':$(this).find('input[name=id]').val(), + 'value':$(this).find('input[name=document_position]').val() + }; + + $.ajax({ + url: ave_path + 'admin/index.php?do=docs', + type: 'POST', + dataType: 'json', + data: dataForm, + success: function(data) { + $(q_loading).css({'display':'none'}); + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + } + }); + + return false; + }); + + $(q_submit).on('click',function(event){ + event.preventDefault(); + + $(item).submit(); + + return false; + }); + } + + }); + } + +}; + +$(document).keydown(function(event) { + + var numberOfOptions = $("#rubric_id > option").length; + var selectedIndex = $("#rubric_id option:selected").val(); + + switch (event.keyCode) { + case 38: // UP Key + if (selectedIndex > 0) { + $("#rubric_id").val(parseInt($("#rubric_id option:selected").val()) - 1); + } + break; + case 40: // DOWN Key + if (selectedIndex < numberOfOptions - 1) { + $("#rubric_id").val(parseInt($("#rubric_id option:selected").val()) + 1); + } + break; + } + +}); + +$(document).ready(function() { + AveAdmin.initialize(); +}); \ No newline at end of file diff --git a/admin/templates/login.tpl b/admin/templates/login.tpl new file mode 100644 index 0000000..309fe51 --- /dev/null +++ b/admin/templates/login.tpl @@ -0,0 +1,131 @@ + + + + + + + {#MAIN_LOGIN_TEXT#} + + + + + + + + + + + + + + + + + {include file='login_scripts.tpl'} + + + + + + + +
    + +
    +
    +
    {#MAIN_LOGIN_INTRO#}
    +
    +
    + +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    + {if $captcha} +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + {/if} +
    +
    + + +
    + +
    +
    +
    +
    + {if $error} +
    +
      +
    • {$error}
    • +
    +
    + {/if} +
    + + + + \ No newline at end of file diff --git a/admin/templates/login_scripts.tpl b/admin/templates/login_scripts.tpl new file mode 100644 index 0000000..be1c7e7 --- /dev/null +++ b/admin/templates/login_scripts.tpl @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/admin/templates/logs/404.tpl b/admin/templates/logs/404.tpl new file mode 100644 index 0000000..80ee4dc --- /dev/null +++ b/admin/templates/logs/404.tpl @@ -0,0 +1,92 @@ + + + +
    {#LOGS_404_SUB_TITLE#}
    + +
    +
    + {#LOGS_404_TIP#} +
    +
    + + + +
    + + + + + + + + + + + + + + + + {foreach from=$logs key=k item=log} + + + + + + + {/foreach} + +
    {#LOGS_404_ID#}{#LOGS_404_IP#}{#LOGS_404_DATE#}{#LOGS_404_ACTION#}
    {$k}{$log.log_ip}{$log.log_time|date_format:$TIME_FORMAT|pretty_date} + REQUEST_URI: {$log.log_request_uri|urldecode} +
    + Полная информация об ошибке + + +
    +
    + {if check_permission('logs_clear')}{/if} + +
    +
    \ No newline at end of file diff --git a/admin/templates/logs/logs.tpl b/admin/templates/logs/logs.tpl new file mode 100644 index 0000000..b30dddc --- /dev/null +++ b/admin/templates/logs/logs.tpl @@ -0,0 +1,85 @@ + + + +
    {#LOGS_SUB_TITLE#}
    + +
    +
    + {#LOGS_TIP#} +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + {foreach from=$logs key=k item=log} + + + + + + + + {/foreach} + +
    {#LOGS_ID#}{#LOGS_IP#}{#LOGS_USER#}{#LOGS_DATE#}{#LOGS_ACTION#}
    {$k}{$log.log_ip}{if check_permission('user_edit')}{$log.log_user_name}{else}{$log.log_user_name}{/if}{$log.log_time|date_format:$TIME_FORMAT|pretty_date} + {$log.log_text} +
    + url: {$log.log_url} +
    +
    + {if check_permission('logs_clear')} + + {/if} + +
    +
    \ No newline at end of file diff --git a/admin/templates/logs/nav.tpl b/admin/templates/logs/nav.tpl new file mode 100644 index 0000000..01fb58a --- /dev/null +++ b/admin/templates/logs/nav.tpl @@ -0,0 +1 @@ +
  • {#MAIN_LOGS#}
  • diff --git a/admin/templates/logs/sql.tpl b/admin/templates/logs/sql.tpl new file mode 100644 index 0000000..1b72d2e --- /dev/null +++ b/admin/templates/logs/sql.tpl @@ -0,0 +1,111 @@ + + + +
    {#LOGS_SQL_SUB_TITLE#}
    + +
    +
    + {#LOGS_SQL_TIP#} +
    +
    + + + +
    + + + + + + + + + + + + + + + + {foreach from=$logs key=key item=log} + + + + + + + {/foreach} + +
    {#LOGS_SQL_ID#}{#LOGS_SQL_IP#}{#LOGS_SQL_DATE#}{#LOGS_SQL_ACTION#}
    {$key}{$log.log_ip} + {$log.log_time|date_format:$TIME_FORMAT|pretty_date} +
    + {$log.log_user_name} +
    + ERROR: + {$log.log_text.sql_error} +
    + Полная информация об ошибке + + +
    + +
    + {if check_permission('logs_clear')} + + {/if} + +
    +
    \ No newline at end of file diff --git a/admin/templates/main.tpl b/admin/templates/main.tpl new file mode 100644 index 0000000..a25c013 --- /dev/null +++ b/admin/templates/main.tpl @@ -0,0 +1,301 @@ + + + + + + + + {#MAIN_PAGE_TITLE#} - {*#SUB_TITLE#*} ({$smarty.session.user_name|escape}) + + + + + + + + + + + + + + + + + + + + + {include file='scripts.tpl'} + + + + + + + + + + +
    + +
    + + +
    +
    +
    +
    + {if $user_avatar} + {$smarty.session.user_name|escape} + {else} + + {/if} + {#MAIN_USER_ONLINE#} {$smarty.session.user_name|escape} +
    +
    + +
    +
    +
    +
    +
    + + + + + +
    + + +
    + +
    + + +
    + {$content} +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/admin/templates/modules/modules.tpl b/admin/templates/modules/modules.tpl new file mode 100644 index 0000000..c1ed028 --- /dev/null +++ b/admin/templates/modules/modules.tpl @@ -0,0 +1,237 @@ +{if check_permission('modules_admin')} + +{/if} + +
    {#MODULES_SUB_TITLE#}
    + +
    +
    + {#MODULES_TIP#} +
    +
    + +{if isset($errors)} +
      + {foreach from=$errors item=message} +
    • {$message}
    • + {/foreach} +
    +{/if} + + + +
    + + + +
    +
    + +{if check_permission('modules_system')} +
    +{/if} + +{if $installed_modules} + + + + + + + + + {if check_permission('modules_system')} + + {/if} + + + +{foreach from=$installed_modules item=module} + {if check_permission('modules_view')} + + + + + + + + + + + + {if check_permission('modules_system')} + + + + + + {/if} + + {/if} + {/foreach} + + {if check_permission('modules_system')} + + + + {/if} + + +
    ?{#MODULES_NAME#}{#MODULES_TEMPLATE#}{#MODULES_SYSTEM_TAG#}{#MODULES_VERSION#}{#MODULES_ACTIONS#}
    + + + {if check_permission('modules_admin')} + {if $module.ModuleAdminEdit && $module.ModuleStatus && $module.permission} + {$module.ModuleName} + {if (isset($module.ModuleTagLink) && $module.ModuleTagLink != "")} +
    {$module.ModuleTagLink} + {/if} + {else} + {$module.ModuleName} + {/if} + {else if check_permission('modules_view')} + {$module.ModuleName} + {/if} +
    + {if $module.template} + {assign var=module_id value=$module.id} + {if $module.ModuleStatus && $module.permission} + {html_options name=Template[$module_id] options=$all_templates selected=$module.template style="width: 200px"} + {else} + {html_options name=Template[$module_id] options=$all_templates selected=$module.template style="width: 200px" disabled="disabled"} + {/if} + {else} +   + {/if} + {if $module.ModuleTag != ""}{/if}{$module.ModuleVersion|escape|default:''} + {if $module.ModuleStatus} + + {else} + + {/if} + + {if $module.ModuleStatus} + + {else} + + {/if} + + {if $module.need_update} + + {else} + + {/if} +
    + {if check_permission('modules_system')} +
    + {/if} + +{else} + + + + + + + +
    +
      +
    • {#MODULES_NO_INSTALL#}
    • +
    +
    +{/if} + +
    + + +
    +
    +
    \ No newline at end of file diff --git a/admin/templates/modules/nav.tpl b/admin/templates/modules/nav.tpl new file mode 100644 index 0000000..6ff3757 --- /dev/null +++ b/admin/templates/modules/nav.tpl @@ -0,0 +1 @@ +
  • {#MAIN_NAVI_MODULES#}
  • diff --git a/admin/templates/navi/navi.tpl b/admin/templates/navi/navi.tpl new file mode 100644 index 0000000..6d395b6 --- /dev/null +++ b/admin/templates/navi/navi.tpl @@ -0,0 +1,55 @@ +{if check_permission('document_view')} + {include file='documents/nav.tpl'} +{/if} + +{if check_permission('rubric_view')} + {include file='rubs/nav.tpl'} +{/if} + +{if check_permission('request_view')} + {include file='request/nav.tpl'} +{/if} + +{if check_permission('navigation_view')} + {include file='navigation/nav.tpl'} +{/if} + +{if check_permission('blocks_view')} + {include file='blocks/nav.tpl'} +{/if} + +{if check_permission('sysblocks_view')} + {include file='sysblocks/nav.tpl'} +{/if} + +{if check_permission('template_view')} + {include file='templates/nav.tpl'} +{/if} + +{if check_permission('mediapool_finder')} + {include file='finder/nav.tpl'} +{/if} + +{if check_permission('modules_view')} + {include file='modules/nav.tpl'} +{/if} + +{if check_permission('user_view')} + {include file='user/nav.tpl'} +{/if} + +{if check_permission('group_view')} + {include file='groups/nav.tpl'} +{/if} + +{if check_permission('gen_settings')} + {include file='settings/nav.tpl'} +{/if} + +{if check_permission('db_actions')} + {include file='dbactions/nav.tpl'} +{/if} + +{if check_permission('logs_view')} + {include file='logs/nav.tpl'} +{/if} diff --git a/admin/templates/navi/navi_top.tpl b/admin/templates/navi/navi_top.tpl new file mode 100644 index 0000000..c9eaf05 --- /dev/null +++ b/admin/templates/navi/navi_top.tpl @@ -0,0 +1,55 @@ +{if check_permission('document_view')} + {include file='documents/nav_top.tpl'} +{/if} + +{if check_permission('rubric_view')} + {include file='rubs/nav.tpl'} +{/if} + +{if check_permission('request_view')} + {include file='request/nav.tpl'} +{/if} + +{if check_permission('navigation_view')} + {include file='navigation/nav.tpl'} +{/if} + +{if check_permission('blocks_view')} + {include file='blocks/nav.tpl'} +{/if} + +{if check_permission('sysblocks_view')} + {include file='sysblocks/nav.tpl'} +{/if} + +{if check_permission('template_view')} + {include file='templates/nav.tpl'} +{/if} + +{if check_permission('mediapool_finder')} + {include file='finder/nav.tpl'} +{/if} + +{if check_permission('modules_view')} + {include file='modules/nav.tpl'} +{/if} + +{if check_permission('user_view')} + {include file='user/nav.tpl'} +{/if} + +{if check_permission('group_view')} + {include file='groups/nav.tpl'} +{/if} + +{if check_permission('gen_settings')} + {include file='settings/nav.tpl'} +{/if} + +{if check_permission('db_actions')} + {include file='dbactions/nav.tpl'} +{/if} + +{if check_permission('logs_view')} + {include file='logs/nav.tpl'} +{/if} diff --git a/admin/templates/navigation/item.tpl b/admin/templates/navigation/item.tpl new file mode 100644 index 0000000..ea190a7 --- /dev/null +++ b/admin/templates/navigation/item.tpl @@ -0,0 +1,48 @@ +
    + + +
    + +
    + +
    + {if $item.document_title} + {$item.document_title|escape} (ID: {$item.document_id|escape}) + {else} + {#NAVI_NOLINK_DOC#} + {/if} +
    + +
    + {if $item.alias} + {if $item.status == 1} + + {else} + + {/if} + {else} + {if $item.status == 1} + + {else} + + {/if} + {/if} +
    + +
    + + +
    +
    + + {if $smarty.request.sub == 'new'} + + {/if} \ No newline at end of file diff --git a/admin/templates/navigation/item_edit.tpl b/admin/templates/navigation/item_edit.tpl new file mode 100644 index 0000000..c0fc3cf --- /dev/null +++ b/admin/templates/navigation/item_edit.tpl @@ -0,0 +1,191 @@ +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {#NAVI_LINK_TITLE#}
    +
    + +
    +
    {#NAVI_LINK_TO_DOCUMENT#}
    +
    + +
    +
    {#NAVI_LINKED_DOC#}
    + {if $item->document_id} + {$item->document_title|escape} (ID: {$item->document_id|escape}) + {else} + {#NAVI_NO_LINK#} + {/if} +
    {#NAVI_LINK_FILEDOC#}
    +
    + +   + +
    +
    {#NAVI_LINK_SOLUT#}
    +
    + +
    +
    {#NAVI_LINK_IMAGE#}
    +
    +   +
    +
    STYLE
    +
    + +
    +
    CLASSID
    +
    + +
    +
    +
    + +
    +
    {#NAVI_TARGET_WINDOW#}
    + +
    +
    + +
    +
    +
    + + {if $smarty.request.sub == 'edit'} + + + {/if} + {if $smarty.request.pop} + + {/if} +
    +
    +
    +
    + \ No newline at end of file diff --git a/admin/templates/navigation/item_new.tpl b/admin/templates/navigation/item_new.tpl new file mode 100644 index 0000000..45c7fa4 --- /dev/null +++ b/admin/templates/navigation/item_new.tpl @@ -0,0 +1,206 @@ +
    +
    + + + + + + + + + + + + + + + + + + + {if $items} + + + + + + + + + + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {#NAVI_LINK_TITLE#}
    +
    + +
    +
    {#NAVI_ADD_AFTER#}:
    +
    + +
    +
    {#NAVI_LINK_TO_DOCUMENT#}
    +
    + +
    +
    {#NAVI_LINKED_DOC#}
    + {#NAVI_NO_LINK#} +
    {#NAVI_LINK_FILEDOC#}
    +
    + +   + +
    +
    {#NAVI_LINK_SOLUT#}
    +
    + +
    +
    {#NAVI_LINK_IMAGE#}
    +
    +   +
    +
    STYLE
    +
    + +
    +
    CLASSID
    +
    + +
    +
    +
    + +
    +
    {#NAVI_TARGET_WINDOW#}
    + +
    +
    + +
    +
    +
    + + + + +
    +
    +
    +
    + \ No newline at end of file diff --git a/admin/templates/navigation/items.tpl b/admin/templates/navigation/items.tpl new file mode 100644 index 0000000..42faae9 --- /dev/null +++ b/admin/templates/navigation/items.tpl @@ -0,0 +1,264 @@ +
    +
    {#NAVI_SUB_TITLE2#}
    +
    + + + +
    +
    +
    Структура
    + + +
    + + + +
    + {if $items} + {include file="$nestable_tpl" items=$items} + {else} +
      + {/if} +
      +
      + + \ No newline at end of file diff --git a/admin/templates/navigation/list.tpl b/admin/templates/navigation/list.tpl new file mode 100644 index 0000000..9aaf09d --- /dev/null +++ b/admin/templates/navigation/list.tpl @@ -0,0 +1,214 @@ + + + +
      +
      {#NAVI_SUB_TITLE#}
      +
      + +
      +
      + {#NAVI_TIP_TEMPLATE#} +
      +
      + + + + +
      + + +
      +
      +
      + + + + + + + + + + + {foreach from=$navigations item=item} + + + + + + + + + + {/foreach} + +
      {#NAVI_ID#}{#NAVI_NAME#}{#NAVI_SYSTEM_TAG#}{#NAVI_ACTIONS#}
      {$item->navigation_id} + + {if check_permission('navigation_edit')} + {$item->title|escape:html|stripslashes} + {else} + {$item->navigation_title|escape:html|stripslashes} + {/if} + + +
      + + + + +
      +
      + {if check_permission('navigation_edit')} + + {else} + + {/if} + + {if check_permission('navigation_edit')} + + {else} + + {/if} + + {if check_permission('navigation_edit')} + + {else} + + {/if} + + {if $item->navigation_id == 1} + + {else} + {if check_permission('navigation_edit')} + + {else} + + {/if} + {/if} +
      +
      + +
      + {if check_permission('navigation_edit')} + + {/if} +
      +
      +
      + +{literal} + +{/literal} \ No newline at end of file diff --git a/admin/templates/navigation/nav.tpl b/admin/templates/navigation/nav.tpl new file mode 100644 index 0000000..8815c00 --- /dev/null +++ b/admin/templates/navigation/nav.tpl @@ -0,0 +1 @@ +
    1. {#MAIN_NAVIGATION#}
    2. \ No newline at end of file diff --git a/admin/templates/navigation/nestable.tpl b/admin/templates/navigation/nestable.tpl new file mode 100644 index 0000000..470428e --- /dev/null +++ b/admin/templates/navigation/nestable.tpl @@ -0,0 +1,52 @@ + {if $items} +
        + {foreach from=$items key=key item=item} +
      1. +
        +
        + + +
        + {if $item.alias|escape == '/'} + + {else} + + {/if} +
        + +
        + {if $item.document_title} + {$item.document_title|escape} (ID: {$item.document_id|escape}) + {else} + {#NAVI_NOLINK_DOC#} + {/if} +
        + +
        + {if $item.alias} + {if $item.status == 1} + + {else} + + {/if} + {else} + {if $item.status == 1} + + {else} + + {/if} + {/if} +
        + +
        + + +
        +
        + {include file="$nestable_tpl" items=$item.children level=$level+1} +
      2. + {/foreach} +
      + {/if} diff --git a/admin/templates/navigation/select.tpl b/admin/templates/navigation/select.tpl new file mode 100644 index 0000000..749976b --- /dev/null +++ b/admin/templates/navigation/select.tpl @@ -0,0 +1,12 @@ +{if $items} + {foreach from=$items item=item} + {$item.level} + + {include file="$select_tpl" items=$item.children} + {/foreach} +{/if} \ No newline at end of file diff --git a/admin/templates/navigation/template.tpl b/admin/templates/navigation/template.tpl new file mode 100644 index 0000000..3ac2902 --- /dev/null +++ b/admin/templates/navigation/template.tpl @@ -0,0 +1,764 @@ + + +{if $smarty.request.action == 'new'} +
      +
      {#NAVI_SUB_TITLE4#}
      +
      +{else} +
      +
      {#NAVI_SUB_TITLE3#}
      +
      +{/if} + +
      +
      {#NAVI_TIP_TEMPLATE2#}
      +
      + + + + +{literal} + +{/literal} + +{if $smarty.request.action != 'new'} + +{/if} + +{include file="$codemirror_connect"} + +{include file="$codemirror_editor" conn_id="_1_1" textarea_id='level1_tpl' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} +{include file="$codemirror_editor" conn_id="_1_2" textarea_id='level1' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} +{include file="$codemirror_editor" conn_id="_1_3" textarea_id='level1_active' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} + +{include file="$codemirror_editor" conn_id="_2_1" textarea_id='level2_tpl' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} +{include file="$codemirror_editor" conn_id="_2_2" textarea_id='level2' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} +{include file="$codemirror_editor" conn_id="_2_3" textarea_id='level2_active' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} + +{include file="$codemirror_editor" conn_id="_3_1" textarea_id='level3_tpl' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} +{include file="$codemirror_editor" conn_id="_3_2" textarea_id='level3' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} +{include file="$codemirror_editor" conn_id="_3_3" textarea_id='level3_active' ctrls='$("#navigation_template").ajaxSubmit(sett_options);' height=200} diff --git a/admin/templates/navigation/tree.tpl b/admin/templates/navigation/tree.tpl new file mode 100644 index 0000000..01cee87 --- /dev/null +++ b/admin/templates/navigation/tree.tpl @@ -0,0 +1,12 @@ +{if $document->document_linked_navi_id} + {assign var="navigation_item_selected" value=$document->document_linked_navi_id scope="global"} +{/if} + + diff --git a/admin/templates/navigation/tree_docform.tpl b/admin/templates/navigation/tree_docform.tpl new file mode 100644 index 0000000..b8e9678 --- /dev/null +++ b/admin/templates/navigation/tree_docform.tpl @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/admin/templates/noperm.tpl b/admin/templates/noperm.tpl new file mode 100644 index 0000000..b8a96ef --- /dev/null +++ b/admin/templates/noperm.tpl @@ -0,0 +1,19 @@ + + + + + + {#SUB_TITLE#} ({$smarty.session.user_name|escape}) + + + + + + + + + + +

      Извините, но Вы не имеете доступа к данному разделу!

      + + \ No newline at end of file diff --git a/admin/templates/onlycontent.tpl b/admin/templates/onlycontent.tpl new file mode 100644 index 0000000..ce0fc1b --- /dev/null +++ b/admin/templates/onlycontent.tpl @@ -0,0 +1 @@ +{$content} \ No newline at end of file diff --git a/admin/templates/pop.tpl b/admin/templates/pop.tpl new file mode 100644 index 0000000..894a06e --- /dev/null +++ b/admin/templates/pop.tpl @@ -0,0 +1,65 @@ + + + + + + + {#MAIN_PAGE_TITLE#} - {*#SUB_TITLE#*} ({$smarty.session.user_name|escape}) + + + + + + + + + + + + + + + + + + + + {include file='scripts.tpl'} + + + + + + + + + + +
      + + +
      + {$content} +
      + +
      +
      + + + + + + + + \ No newline at end of file diff --git a/admin/templates/request/change.tpl b/admin/templates/request/change.tpl new file mode 100644 index 0000000..1671bbe --- /dev/null +++ b/admin/templates/request/change.tpl @@ -0,0 +1,39 @@ +{if $smarty.request.sub == ''} +
      + +   + + +
      +{else} + {foreach from=$fields_list item=field_group} + + {foreach from=$field_group.fields item=field} + {if $field_id == $field.Id} + + {/if} + {/foreach} + + {/foreach} +{/if} diff --git a/admin/templates/request/cond_list.tpl b/admin/templates/request/cond_list.tpl new file mode 100644 index 0000000..f7ff5c3 --- /dev/null +++ b/admin/templates/request/cond_list.tpl @@ -0,0 +1,112 @@ +
      + + + + + + + + + + + + + + + + + + + + + + {if $conditions} + + {foreach name=cond from=$conditions item=condition} + + + + + + + + + + + + + + {/foreach} + + {else} + + + + {/if} + +
      {#REQUEST_FROM_FILED#}{#REQUEST_OPERATOR#}{#REQUEST_CONDITION_JOIN#}{#REQUEST_VALUE#}
      condition_status ==1}checked{/if} class="toprightDir float" /> + {foreach from=$fields_list item=field_group} + + {foreach from=$field_group.fields item=field} + {if $condition->condition_field_id == $field.Id} + + {/if} + {/foreach} + + {/foreach} + + + + +
      +
        +
      • {#REQUEST_COND_MESSAGE#}
      • +
      +
      + + {if $conditions} +
      + + + {#REQUEST_OR#} +   + {if $smarty.request.pop} + + {/if} +
      +
      + {/if} +
      + + {if $conditions} + + {/if} diff --git a/admin/templates/request/conditions.tpl b/admin/templates/request/conditions.tpl new file mode 100644 index 0000000..cab902b --- /dev/null +++ b/admin/templates/request/conditions.tpl @@ -0,0 +1,391 @@ + + +
      +
      {#REQUEST_CONDITIONS#}
      +
      + +
      +
      + {#REQUEST_CONDITION_TIP#} +
      +
      + + + +
      + +
      + +
      +
      {#REQUEST_NEW_CONDITION#}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#REQUEST_FROM_FILED#}{#REQUEST_OPERATOR#}{#REQUEST_CONDITION_JOIN#}{#REQUEST_VALUE#}
      + + + + + + +
      +
      + +
      +
      +
      +
      + +
      +
      +
      {#REQUEST_CONDITION#}
      + {if !$smarty.request.pop} + + {/if} +
      + +
      + + + + + + + + + + + + + + + + + + + + + + {if $conditions} + + {foreach name=cond from=$conditions item=condition} + + + + + + + + + + + + + {/foreach} + + {else} + + + + {/if} + +
      {#REQUEST_FROM_FILED#}{#REQUEST_OPERATOR#}{#REQUEST_CONDITION_JOIN#}{#REQUEST_VALUE#}
      condition_status ==1}checked{/if} class="toprightDir float"/> + + {foreach from=$fields_list item=field_group} + + {foreach from=$field_group.fields item=field} + {if $condition->condition_field_id == $field.Id} + + {/if} + {/foreach} + + {/foreach} + + + + + +
      +
        +
      • {#REQUEST_COND_MESSAGE#}
      • +
      +
      + {if $conditions} +
      +
      + + {#REQUEST_OR#} +   + {if $smarty.request.pop} + + {/if} +
      +
      + {/if} + +
      + +
      +
      + +
      + + \ No newline at end of file diff --git a/admin/templates/request/form.tpl b/admin/templates/request/form.tpl new file mode 100644 index 0000000..8ad869c --- /dev/null +++ b/admin/templates/request/form.tpl @@ -0,0 +1,779 @@ + + +{if $smarty.request.action=='edit'} +
      +
      {#REQUEST_EDIT2#}
      + +
      +
      +
      {#REQUEST_EDIT_TIP#}
      +
      +{else} +
      +
      {#REQUEST_NEW#}
      +
      +
      +
      {#REQUEST_NEW_TIP#}
      +
      +{/if} + + + +{if $errors} +
        + {foreach from=$errors item=e} +
      • + {assign var=message value=$e} + • {$message}
        +
      • + {/foreach} +
      +{/if} + +{if !check_permission('request_php')} +
        +
      • + {#REQUEST_REPORT_ERR_PHP#} +
      • +
      +{/if} + +{if $smarty.request.Id == ''} + {assign var=iframe value='no'} +{/if} + +{if $smarty.request.action == 'new' && $smarty.request.rubric_id == ''} + {assign var=dis value='disabled'} +{/if} + +{if $smarty.request.action=='new' && $smarty.request.rubric_id==''} +
        +
      • + {#REQUEST_PLEASE_SELECT#} +
      • +
      +{/if} + + +
      + + + + +
      + +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if $row->request_external == '1'} + + + + {/if} + +
      {#REQUEST_HEADER_SELF#}
      {#REQUEST_NAME2#}
      +
      + [?] {#REQUEST_ALIAS#}: +
      +
      +
      +   + + + + +
      +
      {#REQUEST_CACHE#}{#REQUEST_CACHE_ELEMENTS#}request_cache_elements}checked="checked"{/if}/>
      {#REQUEST_SELECT_RUBRIK#} + + +
      {#REQUEST_DESCRIPTION#}
      {#REQUEST_INTERNAL_INFO#}
      {#REQUEST_CONDITION#} + {if $iframe == 'no'} + + {/if} + {if $iframe != 'no'} + {#REQUEST_BUTTON_COND#} + {/if} +
      {#REQUEST_HEADER_NAME#}{#REQUEST_HEADER_PARAMETR#}{#REQUEST_HEADER_NAME#}{#REQUEST_HEADER_PARAMETR#}
      {#REQUEST_HIDE_CURRENT#}request_hide_current}checked="checked"{/if}/>{#REQUEST_ONLY_OWNER#}request_only_owner}checked="checked"{/if}/>
      +
      + [?] {#REQUEST_SORT_BY#}: +
      +
      + + +
      + [?] {#REQUEST_SORT_BY_NAT#}: +
      +
      + +
      {#REQUEST_ASC_DESC#} + + {#REQUEST_DOC_PER_PAGE#} + +
      {#REQUEST_PAGINATION#}
      {#REQUEST_SHOW_NAVI#}request_show_pagination=='1'} checked="checked"{/if} />{#REQUEST_NAVI_TPL#} + +
      {#REQUEST_COUNT_ITEMS#}request_count_items == '1'} checked="checked"{/if} />{#REQUEST_USE_QUERY#}request_use_query == '1'} checked="checked"{/if} />
      {#REQUEST_OTHER#}
      {#REQUEST_USE_LANG#}request_lang == '1'} checked="checked"{/if} />
      {#REQUEST_SHOW_STAT#}request_show_statistic == '1'} checked="checked"{/if} />{#REQUEST_SHOW_SQL#}request_show_sql == '1'} checked="checked"{/if} />
      {#REQUEST_HEADER_EXTERNAL#}
      +
      + [?] {#REQUEST_EXTERNAL#} +
      +
      request_external == '1'} checked="checked"{/if} />{#REQUEST_ONLY_AJAX#}request_ajax == '1'} checked="checked"{/if} />
      + +
      +
      +
      + + + + + +
      +
      +
      +
      + {if $smarty.request.action=='edit'} + + {else} + + {/if} + {#REQUEST_OR#} + {if $smarty.request.action=='edit'} + + {else} + + {/if} + {#REQUEST_CANCEL#} +
      +
      + +
      + + +
      + + + +
      + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" conn_id="" textarea_id='request_template_main' ctrls='$("#RequestTpl").ajaxSubmit(sett_options);' height=480} +{include file="$codemirror_editor" conn_id="2" textarea_id='request_template_item' ctrls='$("#RequestTpl").ajaxSubmit(sett_options);' height=440} + + +{literal} + +{/literal} + +{if $smarty.request.action !='new' && $smarty.request.rubric_id !=''} + +{/if} \ No newline at end of file diff --git a/admin/templates/request/nav.tpl b/admin/templates/request/nav.tpl new file mode 100644 index 0000000..7754227 --- /dev/null +++ b/admin/templates/request/nav.tpl @@ -0,0 +1 @@ +
    3. {#MAIN_QUERIES#}
    4. \ No newline at end of file diff --git a/admin/templates/request/request.tpl b/admin/templates/request/request.tpl new file mode 100644 index 0000000..e3ef687 --- /dev/null +++ b/admin/templates/request/request.tpl @@ -0,0 +1,297 @@ + + +
      {#REQUEST_TITLE#}
      + +
      +
      + {#REQUEST_TIP#} +
      +
      + + +
      + +
      +
      +
      + + {if $items} + + + + + + + + + + + + {foreach from=$items item=item} + + + + + + + + + + + + + + + + + + {/foreach} {else} + + + + {/if} + +
      {#REQUEST_ID#}{#REQUEST_NAME#}{#REQUEST_AUTHOR#}{#REQUEST_DATE_CREATE#}{#REQUEST_SYSTEM_TAG#}{#REQUEST_ACTIONS#}
      {$item->Id} + {if check_permission('request_edit')} + + {$item->request_title|escape} + + {else} + {$item->request_title|escape} + {/if} {if $item->request_description != ''} +
      + {$item->request_description|escape|default:#REQUEST_NO_DESCRIPTION#} {/if} +
      {$item->request_author|escape} + {$item->request_created|date_format:$TIME_FORMAT|pretty_date} + +
      + + + + +
      +
      + {if check_permission('request_edit')} + + {else} + + {/if} + + {if check_permission('request_edit')} + + {else} + + {/if} + + {if check_permission('request_new')} + + {else} + + {/if} + + {if check_permission('request_del')} + + {else} + + {/if} +
      +
        +
      • {#REQUEST_NO_REQUST#}
      • +
      +
      +
      +
      + + {if check_permission('request_new')} + + + + {/if} +
      +
      +
      + +{literal} + +{/literal} {if $page_nav} + +{/if} \ No newline at end of file diff --git a/admin/templates/rubs/_field_code.tpl b/admin/templates/rubs/_field_code.tpl new file mode 100644 index 0000000..6ff32f2 --- /dev/null +++ b/admin/templates/rubs/_field_code.tpl @@ -0,0 +1,137 @@ +
      +
      {#RUBRIK_FIELDS_TEMPLATES_H2#}
      +
      + + + +{if $code_text} +
      + +
      +
      +
      {if $params.func == 'new'}{#RUBRIK_FIELDS_EDIT_TPL_CREAT#}{else}{#RUBRIK_FIELDS_EDIT_TPL_EDIT#}{/if}
      +
      + +
      + +
      +
      + +
      + +   + {#RUBRIK_BUTTON_TPL_CLOSE#} +
      +
      + +
      + + + + {if $params.id} + + {/if} + + + +
      + +{include file="$codemirror_editor" conn_id="ftpl" textarea_id='code_text' ctrls='$("#code_templ").ajaxSubmit(sett_options);' height=400 mode='smartymixed'} + + + +{else} + +
      +
      +
      + {$main.name} -  + {if $params.type == 'adm'} + {#RUBRIK_FIELDS_EDIT_TPL_ADM#} + {elseif $params.type == 'doc'} + {#RUBRIK_FIELDS_EDIT_TPL_DOC#}{ + elseif $params.type == 'req'} + {#RUBRIK_FIELDS_EDIT_TPL_REQ#} + {/if} +
      +
      +
      + +
        +
      • + {#RUBRIK_FIELDS_EDIT_NO_TPL#} +
      • +
      + +{/if} \ No newline at end of file diff --git a/admin/templates/rubs/_field_list.tpl b/admin/templates/rubs/_field_list.tpl new file mode 100644 index 0000000..b83ab11 --- /dev/null +++ b/admin/templates/rubs/_field_list.tpl @@ -0,0 +1,142 @@ + + +
      +
      {#RUBRIK_FIELDS_TEMPLATES_H2#}
      +
      + +
      +
      +
        +
      • {#RUBRIK_FIELDS_TEMPLATES_T1#}
      • +
      • {#RUBRIK_FIELDS_TEMPLATES_T2#}
      • +
      +
      +
      + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {#RUBRIC_TABLE_BTN_TEMPLATES#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + + {foreach from=$rubrics item=rubric} +
      +
      +
      {$main.name} ({$main.id})
      + +
      + + + + + + + + + + + + + + + + + + + + + + {foreach from=$rubric.fields item=field} + + + + + + + + + {/foreach} + +
      Id{#RUBRIK_FIELDS_TEMPLATES_FNAME#}{#RUBRIK_FIELDS_TEMPLATES_FTEMPL#}{#RUBRIK_FIELDS_TEMPLATES_DB#}
      {#RUBRIK_FIELDS_TEMPLATES_PANEL#}{#RUBRIK_FIELDS_TEMPLATES_DOC#}{#RUBRIK_FIELDS_TEMPLATES_REQ#}
      {$field.id}{$field.title} + {if $field.adm_main} + {if $field.adm_tpl} + {#RUBRIC_TMPLS_EDIT#} +
      + {#RUBRIC_TMPLS_DELETE#} + {else} + {#RUBRIC_TMPLS_CREAT#} + {/if} + {else} + {#RUBRIK_FIELDS_NO_TEMPLATES#} + {/if} +
      + {if $field.doc_main} + {if $field.doc_tpl} + {#RUBRIC_TMPLS_EDIT#} +
      + {#RUBRIC_TMPLS_DELETE#} + {else} + {#RUBRIC_TMPLS_CREAT#} + {/if} + {else} + {#RUBRIK_FIELDS_NO_TEMPLATES#} + {/if} +
      + {if $field.req_main} + {if $field.req_tpl} + {#RUBRIC_TMPLS_EDIT#} +
      + {#RUBRIC_TMPLS_DELETE#} + {else} + {#RUBRIC_TMPLS_CREAT#} + {/if} + {else} + {#RUBRIK_FIELDS_NO_TEMPLATES#} + {/if} +
      + +
      +
      + {/foreach} + +{include file="$codemirror_connect"} \ No newline at end of file diff --git a/admin/templates/rubs/_fields_list.tpl b/admin/templates/rubs/_fields_list.tpl new file mode 100644 index 0000000..a7f8199 --- /dev/null +++ b/admin/templates/rubs/_fields_list.tpl @@ -0,0 +1,136 @@ + + +
      +
      {#RUBRIK_FIELDS_TEMPLATES_H2#}
      +
      + +
      +
      +
        +
      • {#RUBRIK_FIELDS_TEMPLATES_T1#}
      • +
      • {#RUBRIK_FIELDS_TEMPLATES_T2#}
      • +
      +
      +
      + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {#RUBRIC_TABLE_BTN_TEMPLATES#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + +
      +
      +
      {#RUBRIK_FIELDS_TEMPLATES_LIST#}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$fields item=field key=number} + {if in_array($field.id, $enable)} + + + + + + + + + + {/if} + {/foreach} + +
      {#RUBRIK_FIELDS_TEMPLATES_FNAME#}{#RUBRIK_FIELDS_TEMPLATES_FFUNC#}{#RUBRIK_FIELDS_TEMPLATES_FTEMP#}
      {#RUBRIK_FIELDS_TEMPLATES_PANEL#}{#RUBRIK_FIELDS_TEMPLATES_DOC#}{#RUBRIK_FIELDS_TEMPLATES_REQ#}
      + {$field.name} + + {$field.id} + + {foreach from=$exists item=exist key=key} + {if $field.id == $key} + {if $exist.adm} + {#RUBRIC_TMPLS_EDIT#} + {/if} + {/if} + {/foreach} + + {foreach from=$exists item=exist key=key} + {if $field.id == $key} + {if $exist.doc} + {#RUBRIC_TMPLS_EDIT#} + {/if} + {/if} + {/foreach} + + {foreach from=$exists item=exist key=key} + {if $field.id == $key} + {if $exist.req} + {#RUBRIC_TMPLS_EDIT#} + {/if} + {/if} + {/foreach} +
      +
      + +{include file="$codemirror_connect"} \ No newline at end of file diff --git a/admin/templates/rubs/alias.tpl b/admin/templates/rubs/alias.tpl new file mode 100644 index 0000000..c26fee9 --- /dev/null +++ b/admin/templates/rubs/alias.tpl @@ -0,0 +1,92 @@ +
      + +{if $errors} +
        + {foreach from=$errors item=error}
      • {#RUBRIK_ALIAS_ERROR#} {$error}
      • {/foreach} +
      +{/if} + +
      +
      {#RUBRIK_ALIAS_HEAD_T#}
      +
      + + + + +
      +
      +
      +
      {#RUBRIK_ALIAS_ALIAS#}
      +
      + + + + + + + + + + + + + +
      {#RUBRIK_ALIAS_NAME#} +
      + +
      +
      + +
      + +
      +
      + + +
      + diff --git a/admin/templates/rubs/change.tpl b/admin/templates/rubs/change.tpl new file mode 100644 index 0000000..44b08a0 --- /dev/null +++ b/admin/templates/rubs/change.tpl @@ -0,0 +1,23 @@ +{if $smarty.request.action == 'change'} +
      +
      + +   + +
      + + +
      +{else} +
      + {section name=field loop=$fields} + {if $rf.rubric_field_type == $fields[field].id}{$fields[field].name}{/if} + {/section} +
      +{/if} diff --git a/admin/templates/rubs/code.tpl b/admin/templates/rubs/code.tpl new file mode 100644 index 0000000..0988502 --- /dev/null +++ b/admin/templates/rubs/code.tpl @@ -0,0 +1,174 @@ + + +
      +
      {#RUBRIK_EDIT_CODE_T#}
      +
      + +
      +
      + {#RUBRIK_EDIT_CODE_TIP#} +
      +
      + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FTEMPLATES#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {#RUBRIC_TABLE_BTN_TEMPLATES#} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + +{if check_permission('rubric_edit') && check_permission('rubric_code')} +
      +
      +
      +
      {#RUBRIK_START_CODE#}
      +
      +
      + + + + + + + + + + + + + + + +
      {#RUBRIK_START_CODE#}
      +
      + +
      +
      + {#RUBRIK_EDIT_CODE_LOAD_TIP#} +
      +
      +
      +
      +
      +
      {#RUBRIK_CODE#}
      +
      + + + + + + + + + + + + + + + + + + + + +
      {#RUBRIK_CODE_START#}{#RUBRIK_CODE_END#}
      +
      + +
      +
      +
      + +
      +
      + {#RUBRIK_EDIT_CODE_BEF_TIP#} + + {#RUBRIK_EDIT_CODE_AFT_TIP#} +
      +
      +
      + +   + +
      +
      +
      +
      +{/if} + + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" conn_id="rsc" textarea_id='rubric_start_code' ctrls='$("#code").ajaxSubmit(sett_options);' height=300} +{include file="$codemirror_editor" conn_id="rcs" textarea_id='rubric_code_start' ctrls='$("#code").ajaxSubmit(sett_options);' height=300} +{include file="$codemirror_editor" conn_id="rce" textarea_id='rubric_code_end' ctrls='$("#code").ajaxSubmit(sett_options);' height=300} + + \ No newline at end of file diff --git a/admin/templates/rubs/field_template.tpl b/admin/templates/rubs/field_template.tpl new file mode 100644 index 0000000..dd8da92 --- /dev/null +++ b/admin/templates/rubs/field_template.tpl @@ -0,0 +1,268 @@ + + +{if $errors} +
        + {foreach from=$errors item=error}
      • {#RUBRIK_ALIAS_ERROR#} {$error}
      • {/foreach} +
      +{/if} + +
      + +
      + + + + + + + + + + + + + + + + + +
      {#RUBRIK_FIELD_DEFAULT#}{#RUBRIK_FILED_TEMPLATE_DESCR#}
      +
      + +
      +
      +
      + +
      +
      INT, STRING, JSON + |  + DIV |  + OL |  + UL |  + LI |  + P |  + B |  + I |  + SPAN |  + BR +  | +
      +
      + +
      +
      {#RUBRIK_FILED_TEMPLATE_F#}
      + + + + + + + + + + + + + + + + + + + + + + +
      + {#RUBRIK_FIELDS_TPL#} + + {#RUBRIK_REQUEST_TPL#} +
      +
      + +
      +
      +
      + +
      +
      + |  + [tag:parametr:XXX] |  + [tag:X000x000:[tag:parametr:XXX]] |  + [tag:path] |  + [tag:docid] |  + +
      + |  + [tag:if_empty] [/tag:if_empty] |  + [tag:if_notempty] [/tag:if_notempty] +  | +  | +
      + |  + DIV |  + OL |  + UL |  + LI |  + P |  + B |  + I |  + H1 |  + H2 |  + H3 |  + H4 |  + H5 |  + A |  + IMG |  + SPAN |  + PRE |  + BR |  + TAB +  | +
      + |  + [tag:parametr:XXX] |  + [tag:X000x000:[tag:parametr:XXX]] |  + [tag:path] |  + [tag:docid] |  + +
      + |  + [tag:if_empty] [/tag:if_empty] |  + [tag:if_notempty] [/tag:if_notempty] +  | +  | +
      + |  + DIV |  + OL |  + UL |  + LI |  + P |  + B |  + I |  + H1 |  + H2 |  + H3 |  + H4 |  + H5 |  + A |  + IMG |  + SPAN |  + PRE |  + BR |  + TAB +  | +
      + +   + +   + {#RUBRIK_BUTTON_TPL_CLOSE#} +
      + + + +
      +
      + + + +{include file="$codemirror_editor" conn_id="rftd" textarea_id='rubric_field_description' ctrls='$(".SaveEditFieldTemplate").trigger("click");' height=120} +{include file="$codemirror_editor" conn_id="rftdf" textarea_id='rubric_field_default' ctrls='$(".SaveEditFieldTemplate").trigger("click");' height=120} +{include file="$codemirror_editor" conn_id="rft" textarea_id='rubric_field_template' ctrls='$(".SaveEditFieldTemplate").trigger("click");' height=180} +{include file="$codemirror_editor" conn_id="rftr" textarea_id='rubric_field_template_request' ctrls='$(".SaveEditFieldTemplate").trigger("click");' height=180} \ No newline at end of file diff --git a/admin/templates/rubs/fields.tpl b/admin/templates/rubs/fields.tpl new file mode 100644 index 0000000..bc58128 --- /dev/null +++ b/admin/templates/rubs/fields.tpl @@ -0,0 +1,186 @@ +{if $fields_list} +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$fields_list item=field_group} + + + {if $groups_count > 1} + + + + {/if} + + {foreach from=$field_group.fields item=field} + + + + + + + + + + + + + + {/foreach} + + {/foreach} +
      +
      + +
      +
      [?][?][?]{#RUBRIK_ID#}{#RUBRIK_FIELD_ALIAS#}{#RUBRIK_FIELD_NAME#}{#RUBRIK_FIELD_TYPE#}{#RUBRIK_FIELD_GROUP#}
      {if $field_group.group_title}{$field_group.group_title}{else}{#RUBRIK_FIELD_G_UNKNOW#}{/if}
      + + + + + + + + + + {$field.Id} + +   + ... + +
      + +
      +
      +
      + {assign var="unknow" value="true"} + + {section name=field loop=$fields} + {if $field.rubric_field_type == $fields[field].id} + {assign var="unknow" value=""} + {$fields[field].name} + {/if} + {/section} + + {if $unknow} + {#RUBRIK_FIELD_UNKNOW#} + {/if} + + {assign var="unknow" value=""} +
      +
      +
      + {assign var="unknow_group" value="true"} + {foreach from=$fields_groups item=group} + {if $field.rubric_field_group == $group->Id} + {assign var="unknow_group" value=""} + {$group->group_title} + {/if} + {/foreach} + + {if $unknow_group} + {#RUBRIK_FIELD_G_UNKNOW#} + {/if} +
      +
      + +
      + + +
      +
      + + +   + +   + {#RUBRIK_BUTTON_TEMPL#} +
      +
      + + +
      + +{else} + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      + +
      +
      [?][?][?]{#RUBRIK_ID#}{#RUBRIK_FIELD_ALIAS#}{#RUBRIK_FIELD_NAME#}{#RUBRIK_FIELD_TYPE#}{#RUBRIK_FIELD_GROUP#}
      +
        +
      • {#RUBRIK_NO_FIELDS#}
      • +
      +
      +
      + +{/if} diff --git a/admin/templates/rubs/fields_groups.tpl b/admin/templates/rubs/fields_groups.tpl new file mode 100644 index 0000000..f6b5dd7 --- /dev/null +++ b/admin/templates/rubs/fields_groups.tpl @@ -0,0 +1,195 @@ + + +
      +
      {#RUBRIK_FIELDS_GROUPS#}
      +
      + +
      +
      + {#RUBRIK_FIELDS_GROUPS_TIP#} +
      +
      + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FTEMPLATES#} + + {#RUBRIC_TABLE_BTN_TEMPLATES#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + +{if $groups} + +
      + +
      + +
      +
      {#RUBRIK_FIELDS_GROUPS#}
      +
      + +
      + + + + + + + + + + + + + + + + + {foreach from=$groups item=group} + = 2} data-id="group_{$group->Id}" class="group_tbody"{/if}> + + + + + + {/foreach} + +
      ID[?]{#RUBRIC_F_GROUP_TITLE#}
      + {$group->Id} + + + + + + +
      +
      +
      + +
      +
      +
      +
      +
      + +{else} + +
      + +
      +
      {#RUBRIK_FIELDS_GROUPS#}
      +
      + +
      + + + + + + + + + + + + + + + + + + +
      +
        +
      • {#RUBRIC_NO_GROUPS#}
      • +
      +
      + +
      +
      + +{/if} + +{* Новое Группа *} +
      + +
      +
      {#RUBRIK_NEW_GROUP#}
      +
      + +
      +
      + + + + + + + + + + + + +
      {#RUBRIC_F_GROUP_TITLE#}
      +
      + +
      +
      +
      + +
      +
      +
      +
      + + + diff --git a/admin/templates/rubs/fields_list.tpl b/admin/templates/rubs/fields_list.tpl new file mode 100644 index 0000000..f58a7f2 --- /dev/null +++ b/admin/templates/rubs/fields_list.tpl @@ -0,0 +1,620 @@ + + +
      +
      {#RUBRIK_EDIT_FIELDS#}
      +
      + +{if !$fields_list} +
      +
      {#RUBRIK_NO_FIELDS#}
      +
      +{else} +
      +
      {#RUBRIK_FIELDS_INFO#}
      +
      +{/if} + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_TEMPLATES#} + + {#RUBRIC_TABLE_BTN_FTEMPLATES#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + +
      +
      +
      +
      {#RUBRIK_DESCRIPTION#}
      +
      + + + + +
      +
      + +
      +
      +
      + + +
      +
      +
      + +{if $fields_list} + +
      +
      + +
      +
      {#RUBRIK_FIELDS_TITLE#}
      +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$fields_list item=field_group} + + {if $groups_count > 1} + + + + {/if} + + {foreach from=$field_group.fields item=field} + + + + + + + + + + + + + + {/foreach} + + {/foreach} +
      +
      + +
      +
      [?][?][?]{#RUBRIK_ID#}{#RUBRIK_FIELD_ALIAS#}{#RUBRIK_FIELD_NAME#}{#RUBRIK_FIELD_TYPE#}{#RUBRIK_FIELD_GROUP#}
      {if $field_group.group_title}{$field_group.group_title}{else}{#RUBRIK_FIELD_G_UNKNOW#}{/if}
      + + + + + + + + + + {$field.Id} + +   + ... + +
      + +
      +
      +
      + {assign var="unknow" value="true"} + + {section name=field loop=$fields} + {if $field.rubric_field_type == $fields[field].id} + {assign var="unknow" value=""} + {$fields[field].name} + {/if} + {/section} + + {if $unknow} + {#RUBRIK_FIELD_UNKNOW#} + {/if} + + {assign var="unknow" value=""} +
      +
      +
      + {assign var="unknow_group" value="true"} + {foreach from=$fields_groups item=group} + {if $field.rubric_field_group == $group->Id} + {assign var="unknow_group" value=""} + {$group->group_title} + {/if} + {/foreach} + + {if $unknow_group} + {#RUBRIK_FIELD_G_UNKNOW#} + {/if} +
      +
      + +
      + + +
      +
      + + +   + +   + {#RUBRIK_BUTTON_TEMPL#} +
      +
      +
      +
      +
      +{else} +
      +
      +
      +
      {#RUBRIK_FIELDS_TITLE#}
      + +
      +
      + + + + + + + +
      +
        +
      • {#RUBRIK_NO_FIELDS#}
      • +
      +
      +
      +
      +
      +{/if} + +{* Новое поле *} +
      +
      +
      {#RUBRIK_NEW_FIELD#}
      +
      +
      +
      {#RUBRIK_NEW_FIEL_TITLE#}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + +
      [?][?]{#RUBRIK_FIELD_NAME#}{#RUBRIK_FIELD_TYPE#}{#RUBRIK_FIELD_GROUP#}
      +
      + +
      +
      + + + +
      +
      + +
      +
      +
      +
      + + +{* Связать рубрику *} +
      +
      +
      {#RUBRIK_LINK#}
      +
      +
      +
      + + + + + + + + + +
      +
      {#RUBRIK_LINK_DESC#}
      +
      +
      + {foreach from=$rubs item=rub} + {if $rub->Id != $smarty.request.Id} +
      + Id, $rubric->rubric_linked_rubric)}checked="checked"{/if} name="rubric_linked[]" value="{$rub->Id}" /> + +
      + {/if} + {/foreach} +
      +
      +
      + + +
      +
      +
      +
      + +{include file="$codemirror_connect"} + + diff --git a/admin/templates/rubs/form.tpl b/admin/templates/rubs/form.tpl new file mode 100644 index 0000000..504aaf1 --- /dev/null +++ b/admin/templates/rubs/form.tpl @@ -0,0 +1,997 @@ +{if $smarty.request.action=='new'} +
      +
      {#RUBRIK_TEMPLATE_NEW#}
      +
      +{else} +
      +
      {#RUBRIK_TEMPLATE_EDIT#}
      + +
      +{/if} + +
      +
      {#RUBRIK_TEMPLATE_TIP#}
      +
      + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FTEMPLATES#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + +{if $php_forbidden == 1} +
        +
      • {#RUBRIK_PHP_DENIDED#}
      • +
      +{/if} + +{if $errors} +{foreach from=$errors item=e} +{assign var=message value=$e} +
        +
      • {$message}
      • +
      +{/foreach} +{/if} + +
      + +
      + + + +
      + +
      + + {if !check_permission('rubric_php')} +
      +
        +
      • + {#RUBRIK_PHP_MESSAGE#} +
      • +
      +
      +
      + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#RUBRIK_TAGS#}{#RUBRIK_HTML_T#}
      + {#RUBRIK_IFELSE#} + + |  + [tag:lang:XX] +  |  + [tag:/lang] +  |  + [tag:if_notempty:fld:XXX] +  |  + [tag:if_empty:fld:XXX] +  |  + [tag:if:else] +  |  + [tag:/if] +  |  + {#RUBRIK_SAMPLE#} +  | +
      + [tag:docid] + + +
        +
      • + {#MAIN_CODEMIRROR_HELP#} +
      • +
      +
      + [tag:doc:XXX] +
      + [tag:alias] +
      + [tag:docdate] +
      + [tag:doctime] +
      + [tag:date:XXX] +
      + [tag:docauthor] +
      [tag:docauthoravatar:XXX]
      + [tag:docviews] +
      + [tag:title] +
      + [tag:path] +
      [tag:home]
      + [tag:mediapath] +
      + [tag:request:XXX] +
      + [tag:sysblock:XXX] +
      + [tag:teaser:XXX] +
      + [tag:breadcrumb] +
      + [tag:hide:X,X][/tag:hide] +
      [tag:X000x000:[tag:fld:YYY]]
      [tag:langfile:XXX]
      HTML Tags + |  + OL |  + UL |  + LI |  + P |  + B |  + I |  + H1 |  + H2 |  + H3 |  + H4 |  + H5 |  + DIV |  + A |  + IMG |  + SPAN |  + PRE |  + BR |  + TAB | +
      + + + + + + + + + + + + + + + + + + + + {foreach from=$fields_list item=field_group} + + {if $groups_count > 1} + + + + {/if} + + {foreach from=$field_group.fields item=field} + + + + + + + + + {/foreach} + + {/foreach} + + +
      {#RUBRIK_ID#}{#RUBRIK_FIELD_NAME#}{#RUBRIK_TAGS_ID#}{#RUBRIK_TAGS_ALIAS#}{#RUBRIK_FIELD_ALIAS#}{#RUBRIK_FIELD_TYPE#}
      {if $field_group.group_title}{$field_group.group_title}{else}{#RUBRIK_FIELD_G_UNKNOW#}{/if}
      + {$field.Id} + + {$field.rubric_field_title} + + [tag:fld:{$field.Id}] + + {if $field.rubric_field_alias} + [tag:fld:{$field.rubric_field_alias}] + {/if} + + {if $field.rubric_field_alias}{$field.rubric_field_alias}{/if} + + {section name=field_name loop=$field_array} + {if $field.rubric_field_type == $field_array[field_name].id}{$field_array[field_name].name}{/if} + {/section} +
      + +
      + +
      + + + + + + + + + + + + + + +
      + +
      + +
      +
      + + + {#RUBRIK_OR#} + +
      +
      + +
      + +
      + +
      + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" conn_id="" textarea_id='rubric_template' ctrls='$("#RubricTpl").ajaxSubmit(sett_options);' height=500} +{include file="$codemirror_editor" conn_id="2" textarea_id='rubric_header_template' ctrls='$("#RubricTpl").ajaxSubmit(sett_options);' height=420} +{include file="$codemirror_editor" conn_id="2_1" textarea_id='rubric_footer_template' ctrls='$("#RubricTpl").ajaxSubmit(sett_options);' height=420} +{include file="$codemirror_editor" conn_id="3" textarea_id='rubric_teaser_template' ctrls='$("#RubricTpl").ajaxSubmit(sett_options);' height=420} +{include file="$codemirror_editor" conn_id="4" textarea_id='rubric_admin_teaser_template' ctrls='$("#RubricTpl").ajaxSubmit(sett_options);' height=420} + + diff --git a/admin/templates/rubs/groups.tpl b/admin/templates/rubs/groups.tpl new file mode 100644 index 0000000..ce5f636 --- /dev/null +++ b/admin/templates/rubs/groups.tpl @@ -0,0 +1,26 @@ +{if $smarty.request.action == 'changegroup'} + +
      +
      + +   + +
      + + + +
      +{else} + + + +{/if} diff --git a/admin/templates/rubs/list.tpl b/admin/templates/rubs/list.tpl new file mode 100644 index 0000000..6566a8e --- /dev/null +++ b/admin/templates/rubs/list.tpl @@ -0,0 +1,331 @@ + + +
      +
      {#RUBRIK_SUB_TITLE#}
      +
      + +
      +
      {#RUBRIK_TIP#}
      +
      + + + +
      + +
      +
      +
      + {#RUBRIK_FORMAT#}
      + %d-%m-%Y - {#RUBRIK_FORMAT_TIME#}
      + %id - {#RUBRIK_FORMAT_ID#} +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$rubrics item=rubric} + + + + + + + + + + + + + + + + + + + {/foreach} + +
      {#RUBRIK_ID#}[?][?][?]{#RUBRIK_NAME#}{#RUBRIK_URL_PREFIX#}{#RUBRIK_TEMPLATE_OUT#} +
      + [?] +
      +
      {#RUBRIK_ACTION#}
      + {if $rubric->rubric_description} + [{$rubric->Id}] + {else} + {$rubric->Id} + {/if} + + {if check_permission('rubric_edit')} + + {else} + + {/if} + + {if check_permission('rubric_edit')} + rubric_meta_gen}checked="checked"{/if} /> + {else} + rubric_meta_gen}checked="checked"{/if} disabled="disabled" /> + {/if} + + {if check_permission('rubric_edit')} + rubric_alias_history}checked="checked"{/if} /> + {else} + rubric_alias_history}checked="checked"{/if} disabled="disabled" /> + {/if} + + {if check_permission('rubric_edit')} +
      + +
      + {else} + {$rubric->rubric_title|escape} + {/if} +
      + {if check_permission('rubric_edit')} +
      + +
      + {else} +
      + +
      + {/if} +
      + {if check_permission('rubric_edit')} + + {else} + + {/if} + {#MAIN_STAT_CACHE_SHOW#} + {if check_permission('rubric_edit')} + rubric_docs_active == 1}checked="checked"{/if}> + {else} + rubric_docs_active == 1}checked="checked"{/if} disabled="disabled"> + {/if} + {$rubric->fld_count} + {if check_permission('rubric_edit')} + + {else} + + {/if} + + {if check_permission('rubric_edit')} + + {else} + + {/if} + + {if check_permission('rubric_edit')} + + {else} + + {/if} + + {if check_permission('rubric_edit') && check_permission('rubric_code')} + + {else} + + {/if} + + {if check_permission('rubric_edit')} + + {else} + + {/if} + + {if $rubric->Id != 1} + {if check_permission('rubric_edit')} + {if $rubric->doc_count==0} + + {else} + + {/if} + {else} + + {/if} + {else} + + {/if} +
      + {if check_permission('rubric_edit')} +
      + + {#RUBRIK_OR#} + +
      + {/if} +
      +
      + {if check_permission('rubric_edit')} + + {/if} +
      +
      +
      + + + + + +{if $page_nav} + +{/if} +
      +
      +
      diff --git a/admin/templates/rubs/multi.tpl b/admin/templates/rubs/multi.tpl new file mode 100644 index 0000000..8884026 --- /dev/null +++ b/admin/templates/rubs/multi.tpl @@ -0,0 +1,52 @@ +
      +
      {#RUBRIK_MULTIPLY2#}
      +
      {#RUBRIK_MULTIPLY_TIP#}
      + + + + +{if $errors} +
        + {foreach from=$errors item=error}
      • Ошибка: {$error}
      • {/foreach} +
      +{/if} + + +
      + +
      +
      {#RUBRIK_MULTIPLY2#}
      + + + + + + + + + + + + + + + + + + + +
      {#RUBRIK_NAME#}
      {#RUBRIK_URL_PREFIX#}
      + +
      + + +
      +
      \ No newline at end of file diff --git a/admin/templates/rubs/nav.tpl b/admin/templates/rubs/nav.tpl new file mode 100644 index 0000000..5938d17 --- /dev/null +++ b/admin/templates/rubs/nav.tpl @@ -0,0 +1 @@ +
    5. {#MAIN_RUBRIKS#}
    6. \ No newline at end of file diff --git a/admin/templates/rubs/rubnew.tpl b/admin/templates/rubs/rubnew.tpl new file mode 100644 index 0000000..9090d8c --- /dev/null +++ b/admin/templates/rubs/rubnew.tpl @@ -0,0 +1,55 @@ +
      {#RUBRIK_NEW#}
      +
      {#RUBRIK_NEW_TIP#}
      + + + + +{if $errors} +
        + {foreach from=$errors item=error}
      • Ошибка: {$error}
      • {/foreach} +
      +{/if} + +
      + +
      +
      {#RUBRIK_NEW#}
      + + + + + + + + + + + + + + + + + + + + +
      {#RUBRIK_NAME2#}
      {#RUBRIK_URL_PREFIX2#}
      {#RUBRIK_TEMPLATE_OUT2#} + +
      + +
      +
      \ No newline at end of file diff --git a/admin/templates/rubs/rules.tpl b/admin/templates/rubs/rules.tpl new file mode 100644 index 0000000..2731bb0 --- /dev/null +++ b/admin/templates/rubs/rules.tpl @@ -0,0 +1,240 @@ + + +
      +
      {#RUBRIK_EDIT_RULES#}
      +
      + +
      +
      {#RUBRIC_WARNING_TIP#}
      +
      + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FTEMPLATES#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {#RUBRIC_TABLE_BTN_TEMPLATES#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} +
      + + + +{if check_permission('rubric_edit') && check_permission('rubric_perms')} +
      +
      +
      {#RUBRIK_SET_PERMISSION#}
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$groups item=group} + {assign var=doall value=$group->doall} + + + + + + + + + + + {/foreach} + +
      {#RUBRIK_USER_GROUP#} + {#RUBRIK_DOC_READ#} [?] + + {#RUBRIK_ALL_PERMISSION#} [?] + + {#RUBRIK_CREATE_DOC#} [?] + + {#RUBRIK_CREATE_DOC_NOW#} [?] + + {#RUBRIK_EDIT_OWN#} [?] + + {#RUBRIK_EDIT_OTHER#} [?] + + {#RUBRIK_EDIT_DELREV#} [?] +
      {$group->user_group_name|escape:html} permissions) || in_array('alles', $group->permissions)} class="yellow"{/if}> + {if $group->doall_h==1} + + + {else} + permissions) || in_array('alles', $group->permissions)} checked="checked"{/if} /> + {/if} + permissions)} class="yellow"{/if}> + {if $group->doall_h==1} + + + {else} + permissions)} checked="checked"{/if}{if $group->user_group==2} disabled="disabled"{/if} /> + {/if} + permissions) || in_array('alles', $group->permissions)} class="yellow"{/if}> + + {if $group->doall_h==1} + + + {else} + permissions) || in_array('alles', $group->permissions)} checked="checked"{/if}{if $group->user_group==2} disabled="disabled"{/if} /> + {/if} + permissions) || in_array('alles', $group->permissions)} class="yellow"{/if}> + + {if $group->doall_h==1} + + + {else} + permissions) || in_array('alles', $group->permissions)} checked="checked"{/if}{if $group->user_group==2} disabled="disabled"{/if} /> + {/if} + permissions) || in_array('alles', $group->permissions)} class="yellow"{/if}> + {if $group->doall_h==1} + + + {else} + permissions) || in_array('alles', $group->permissions)} checked="checked"{/if}{if $group->user_group==2} disabled="disabled"{/if} /> + {/if} + permissions) || in_array('alles', $group->permissions)} class="yellow"{/if}> + {if $group->doall_h==1} + + {else} + permissions) || in_array('alles', $group->permissions)} checked="checked"{/if}{if $group->user_group==2} disabled="disabled"{/if} /> + {/if} + permissions) || in_array('alles', $group->permissions)} class="yellow"{/if}> + {if $group->doall_h==1} + + + {else} + permissions) || in_array('alles', $group->permissions)} checked="checked"{/if}{if $group->user_group==2} disabled="disabled"{/if} /> + {/if} +
      +
      + +   + +
      +
      +
      +
      +{/if} + + diff --git a/admin/templates/rubs/tmpls.tpl b/admin/templates/rubs/tmpls.tpl new file mode 100644 index 0000000..b421610 --- /dev/null +++ b/admin/templates/rubs/tmpls.tpl @@ -0,0 +1,194 @@ + + +
      +
      {#RUBRIC_TMPLS_HEAD#}
      + +
      + +
      +
      + {#RUBRIC_TMPLS_TIP#} +
      +
      + + + + + + + + + + + + + + + +
      + {#RUBRIC_TABLE_BTN_FIELDS#} + + {#RUBRIC_TABLE_BTN_FTEMPLATES#} + + {#RUBRIC_TABLE_BTN_FGROUPS#} + + {if check_permission('rubric_code')} + {#RUBRIC_TABLE_BTN_CODE#} + {/if} + + {#RUBRIC_TABLE_BTN_RULES#} +
      + + + +
      + +
      +
      + + + + + + + + + + + {if $templates} + + + + + + + {if check_permission('rubric_edit')}{/if} + + + + + {foreach from=$templates item=template} + + + + + + + + + + {if check_permission('rubric_edit')} + + + + + + {/if} + + {/foreach} + {else} + + + + {/if} + +
      {#RUBRIC_TMPLS_ID#}{#RUBRIC_TMPLS_NAME#}{#RUBRIC_TMPLS_AUTHOR#}{#RUBRIC_TMPLS_DATE#}{#RUBRIC_TMPLS_ACTIONS#}
      {$template->id} + {if check_permission('rubric_edit')} + + {$template->title|escape} + + {else} + {$template->title|escape} + {/if} + {$template->author_id|escape} + {$template->created|date_format:$TIME_FORMAT|pretty_date} + + + + + + {if check_permission('rubric_edit')} + {if $template->doc_count==0} + + {else} + + {/if} + {else} + + {/if} +
      +
        +
      • {#RUBRIC_TMPLS_NO_ITEMS#}
      • +
      +
      +
      + {if check_permission('rubric_edit')} + + {/if} +
      +
      +
      \ No newline at end of file diff --git a/admin/templates/rubs/tmpls_form.tpl b/admin/templates/rubs/tmpls_form.tpl new file mode 100644 index 0000000..d87728b --- /dev/null +++ b/admin/templates/rubs/tmpls_form.tpl @@ -0,0 +1,373 @@ +
      + {if $smarty.request.action !='tmpls_edit'} +
      {#RUBRIK_TEMPLATE_NEW#}
      + {else} +
      {#RUBRIK_TEMPLATE_EDIT#}
      + {/if} +
      + {#RUBRIC_TMPLS_BUTTON#} +   + {#RUBRIK_EDIT#} +   + {if check_permission('rubric_code')} + {#RUBRIK_EDIT_CODE#} + {/if} +
      +
      + +
      +
      {#RUBRIK_TEMPLATE_TIP#}
      +
      + + + +{if $php_forbidden == 1} +
        +
      • {#RUBRIK_PHP_DENIDED#}
      • +
      +{/if} + +{if $errors} +{foreach from=$errors item=e} +{assign var=message value=$e} +
        +
      • {$message}
      • +
      +{/foreach} +{/if} + +
      + +
      +
      +
      {#RUBRIC_TMPLS_NAME_FULL#}
      +
      + +
      + +
      + +
      +
      +
      +
      + +
      +
      +
      {#RUBRIK_HTML#}
      +
      + + {if !check_permission('rubric_php')} +
      +
        +
      • + {#RUBRIK_PHP_MESSAGE#} +
      • +
      +
      +
      + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#RUBRIK_TAGS#}{#RUBRIK_HTML_T#}
      + {#RUBRIK_IFELSE#} + + |  + [tag:lang:XX] +  |  + [tag:/lang] +  |  + [tag:if_notempty:fld:XXX] +  |  + [tag:if_empty:fld:XXX] +  |  + [tag:if:else] +  |  + [tag:/if] +  |  + {#RUBRIK_SAMPLE#} +  | +
      + [tag:docid] + + +
        +
      • + {#MAIN_CODEMIRROR_HELP#} +
      • +
      +
      + [tag:doc:XXX] +
      + [tag:alias] +
      + [tag:docdate] +
      + [tag:doctime] +
      + [tag:date:XXX] +
      + [tag:docauthor] +
      [tag:docauthoravatar:XXX]
      + [tag:docviews] +
      + [tag:title] +
      + [tag:path] +
      [tag:home]
      + [tag:mediapath] +
      + [tag:request:XXX] +
      + [tag:sysblock:XXX] +
      + [tag:teaser:XXX] +
      + [tag:breadcrumb] +
      + [tag:hide:X,X][/tag:hide] +
      [tag:X000x000:[tag:fld:YYY]]
      [tag:langfile:XXX]
      HTML Tags + |  + OL |  + UL |  + LI |  + P |  + B |  + I |  + H1 |  + H2 |  + H3 |  + H4 |  + H5 |  + DIV |  + A |  + IMG |  + SPAN |  + PRE |  + BR |  + TAB | +
      + + + + + + + + + + + + + + + + + + + + + {foreach from=$fields_list item=field_group} + + {if $groups_count > 1} + + + + {/if} + + {foreach from=$field_group.fields item=field} + + + + + + + + + {/foreach} + + {/foreach} + + +
      {#RUBRIK_ID#}{#RUBRIK_FIELD_NAME#}{#RUBRIK_TAGS_ID#}{#RUBRIK_TAGS_ALIAS#}{#RUBRIK_FIELD_ALIAS#}{#RUBRIK_FIELD_TYPE#}
      {if $field_group.group_title}{$field_group.group_title}{else}{#RUBRIK_FIELD_G_UNKNOW#}{/if}
      + {$field.Id} + + {$field.rubric_field_title} + + [tag:fld:{$field.Id}] + + {if $field.rubric_field_alias} + [tag:fld:{$field.rubric_field_alias}] + {/if} + + {if $field.rubric_field_alias}{$field.rubric_field_alias}{/if} + + {section name=field_name loop=$field_array} + {if $field.rubric_field_type == $field_array[field_name].id}{$field_array[field_name].name}{/if} + {/section} +
      + +
      + +
      +
      + + + {if $smarty.request.action == 'tmpls_edit'} + {#RUBRIK_OR#} + + {/if} +
      +
      + +
      + +
      + +
      + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" conn_id="" textarea_id='rubric_template' ctrls='$("#RubricTpl").ajaxSubmit(sett_options);' height=500} + +{if $smarty.request.action =='tmpls_edit'} + +{/if} \ No newline at end of file diff --git a/admin/templates/scripts.tpl b/admin/templates/scripts.tpl new file mode 100644 index 0000000..720c774 --- /dev/null +++ b/admin/templates/scripts.tpl @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/admin/templates/settings/edit_file.tpl b/admin/templates/settings/edit_file.tpl new file mode 100644 index 0000000..2ee5eaf --- /dev/null +++ b/admin/templates/settings/edit_file.tpl @@ -0,0 +1,78 @@ +
      +
      {#SETTINGS_FILE_EDIT_H#} {$file_name}
      +
      + +
      +
      +
      {#SETTINGS_FILE_CONTENT#} {$file_name}
      +
      + +
      +
      + +
      +
      + +
      + +  {#SETTINGS_OR#}  + +
      +
      +
      + +
      + + + +{include file="$codemirror_editor" conn_id="file" textarea_id='code_text' ctrls='$("#code_form").ajaxSubmit(sett_options);' height=450} \ No newline at end of file diff --git a/admin/templates/settings/nav.tpl b/admin/templates/settings/nav.tpl new file mode 100644 index 0000000..a23b432 --- /dev/null +++ b/admin/templates/settings/nav.tpl @@ -0,0 +1 @@ +
    7. {#MAIN_SETTINGS#}
    8. \ No newline at end of file diff --git a/admin/templates/settings/pagination_edit.tpl b/admin/templates/settings/pagination_edit.tpl new file mode 100644 index 0000000..74462e4 --- /dev/null +++ b/admin/templates/settings/pagination_edit.tpl @@ -0,0 +1,243 @@ + + +
      +
      {#SETTINGS_PAGINATION#}
      +
      + +
      +
      + {#SETTINGS_SAVE_INFO#} +
      +
      + + + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      + + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_NAME#}{#SETTINGS_VALUE#}{#SETTINGS_NAME#}{#SETTINGS_VALUE#}
      + {#pagination_name#} + +
      + +
      +
      + {#pagination_navigation_box#} + +
      + +
      +
      + {#pagination_link_box#} + +
      + +
      +
      + {#pagination_active_link_box#} + +
      + +
      +
      + {#pagination_link_template#} + +
      + +
      +
      + {#pagination_link_active_template#} + +
      + +
      +
      + {#pagination_separator_box#} + +
      + +
      +
      + {#pagination_separator_label#} + +
      + +
      +
      + {#pagination_start_label#} + +
      + +
      +
      + {#pagination_end_label#} + +
      + +
      +
      + {#pagination_next_label#} + +
      + +
      +
      + {#pagination_prev_label#} + +
      + +
      +
      +
      +
      + {if isset($smarty.request.id) && $smarty.request.id > 0} + + {/if} + + + {if $smarty.request.action == 'edit_paginations'} + + {/if} +
      +
      +
      +
      + +{if $smarty.request.action != 'new_paginations'} + +{/if} + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" conn_id="1" textarea_id='pagination_box' ctrls='$("#paginations").ajaxSubmit(sett_options);' height='60'} +{include file="$codemirror_editor" conn_id="2" textarea_id='pagination_link_box' ctrls='$("#paginations").ajaxSubmit(sett_options);' height='40'} +{include file="$codemirror_editor" conn_id="3" textarea_id='pagination_active_link_box' ctrls='$("#paginations").ajaxSubmit(sett_options);' height='40'} +{include file="$codemirror_editor" conn_id="4" textarea_id='pagination_link_template' ctrls='$("#paginations").ajaxSubmit(sett_options);' height='60'} +{include file="$codemirror_editor" conn_id="5" textarea_id='pagination_link_active_template' ctrls='$("#paginations").ajaxSubmit(sett_options);' height='60'} \ No newline at end of file diff --git a/admin/templates/settings/settings_cache.tpl b/admin/templates/settings/settings_cache.tpl new file mode 100644 index 0000000..366734c --- /dev/null +++ b/admin/templates/settings/settings_cache.tpl @@ -0,0 +1,263 @@ + + +
      +
      {#SETTINGS_CACHE_TITLE#}
      +
      + +
      +
      + {#SETTINGS_SAVE_INFO#} +
      +
      + + + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_CACHE_H_TITLE#}{#SETTINGS_CACHE_H_SHOW#}{#SETTINGS_CACHE_CLEAR#}
      + {#SETTINGS_CACHE_T_SMARTY#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_DOCS#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_COMPILED#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_QUERIES#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_MODULES#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_NAVI#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_RUBRICS#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_PAGINATION#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_SESSIONS#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_BLOCKS#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_SYSBLOKS#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      + {#SETTINGS_CACHE_T_SETTINGS#} + + {#SETTINGS_CACHE_SHOW#} + + {#SETTINGS_CACHE_CLEAR#} +
      +
      + + +{literal} + +{/literal} diff --git a/admin/templates/settings/settings_case.tpl b/admin/templates/settings/settings_case.tpl new file mode 100644 index 0000000..5f5199d --- /dev/null +++ b/admin/templates/settings/settings_case.tpl @@ -0,0 +1,162 @@ +
      {#SETTINGS_CASE_TITLE#}
      + +
      +
      + {#SETTINGS_SAVE_INFO#} +
      +
      + + + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      +
      +
      + + + + + + +
      +
      + +{foreach from=$CMS_CONFIG item=category key=type} +{assign var="header" value=$type|strtolower} +
      +
      +
      {$smarty.config.$header}
      +
      + + + + + + + + + + + {foreach from=$category item=def key=_var} + + + + + {/foreach} + +
      {#SETTINGS_NAME#}
      {#SETTINGS_VALUE#}
      + {$_var}
      + {$def.DESCR} +
      + {if $def.TYPE=="dropdown"} + + {/if} + {if $def.TYPE=="string"} + + {/if} + {if $def.TYPE=="integer"} + + {/if} + {if $def.TYPE=="bool"} + _tpl_vars['_var']) ? 'checked' : "");{/php} /> + _tpl_vars['_var']) ? '' : "checked");{/php} /> + {/if} +
      +
      +{/foreach} + + +
      +
      +  {#SETTINGS_OR#}  +
      +
      + +
      + + +{include file="$codemirror_connect"} \ No newline at end of file diff --git a/admin/templates/settings/settings_countries.tpl b/admin/templates/settings/settings_countries.tpl new file mode 100644 index 0000000..e79a393 --- /dev/null +++ b/admin/templates/settings/settings_countries.tpl @@ -0,0 +1,140 @@ +
      {#SETTINGS_COUNTRIES#}
      + +
      +
      + {#SETTINGS_COUNTRY_TIP#} +
      +
      + + + + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      +
      +
      + + + + + + + + + + + {foreach from=$countries item=land name=l} + + + + + + + + {/foreach} + +
      {#SETTINGS_COUNTRY_NAME#}{#SETTINGS_ACTIVE#}{#SETTINGS_IN_EC#}
      + + + + + + + +
      + +
      +
      +  {#SETTINGS_OR#}  +
      +
      +
      +
      +
      + + +{if $page_nav} + +{/if} + +
      + + +{include file="$codemirror_connect"} \ No newline at end of file diff --git a/admin/templates/settings/settings_lang.tpl b/admin/templates/settings/settings_lang.tpl new file mode 100644 index 0000000..cf2cea6 --- /dev/null +++ b/admin/templates/settings/settings_lang.tpl @@ -0,0 +1,105 @@ +
      {#SETTINGS_LANG_EDIT#}
      + +
      +
      + {#SETTINGS_LANG_TITLE#} +
      +
      + + + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      + + + + +++++++++++ + + + + + + + + + + + + + {foreach from=$language item=lang name=l} + + + + + + + + + + + + + {/foreach} + +
      {#SETTINGS_LANG_ID#}{#SETTINGS_LANG_FLAG#}{#SETTINGS_LANG_SYSTEM#}{#SETTINGS_LANG_PREFIX#}{#SETTINGS_LANG_NAME#}{#SETTINGS_LANG_DEFAULT#} {#SETTINGS_LANG_ACTION#}
      {$lang.Id}{$lang.lang_key}{$lang.lang_alias_pref}{$lang.lang_name}{if $lang.lang_default==1}{/if} + + + {if $lang.lang_default!=1} + {if $lang.lang_status==1} + + {else} + + {/if} + {else} + + {/if} + + {if $lang.lang_default!=1 && $lang.lang_status==1} + + {else} + + {/if} +
      + +
      + +
      + +
      +{include file="$codemirror_connect"} \ No newline at end of file diff --git a/admin/templates/settings/settings_lang_edit.tpl b/admin/templates/settings/settings_lang_edit.tpl new file mode 100644 index 0000000..ef6cba1 --- /dev/null +++ b/admin/templates/settings/settings_lang_edit.tpl @@ -0,0 +1,52 @@ +
      + +
      {#SETTINGS_LANG_EDIT#}
      + +
      +
      + {#SETTINGS_LANG_TITLE#} +
      +
      + + + +
      + +
      + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_LANG_SYSTEM#}{#SETTINGS_LANG_PREFIX#}{#SETTINGS_LANG_NAME#}
      + + {if $smarty.request.Id==''} + + {else} + + {/if} +
      +
      +
      +
      \ No newline at end of file diff --git a/admin/templates/settings/settings_main.tpl b/admin/templates/settings/settings_main.tpl new file mode 100644 index 0000000..e0d599e --- /dev/null +++ b/admin/templates/settings/settings_main.tpl @@ -0,0 +1,573 @@ +
      {#SETTINGS_MAIN_TITLE#}
      + +
      +
      + {#SETTINGS_SAVE_INFO#} +
      +
      + + + +{$message} + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      + +
      + +
      + + + + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_NAME#}
      {#SETTINGS_VALUE#}
      {#SETTINGS_SITE_NAME#}
      {#SETTINGS_SITE_COUNTRY#} +
      + +
      +
      {#SETTINGS_DATE_FORMAT#} +
      + +
      +
      {#SETTINGS_TIME_FORMAT#} +
      + +
      +
      {#SETTINGS_USE_DOCTIME#} +
      +   + +
      +
      {#SETTINGS_ERROR_PAGE#} +
      +     {#SETTINGS_PAGE_DEFAULT#} +
      +
      {#SETTINGS_TEXT_PERM#} +
      + +
      +
      {#SETTINGS_HIDDEN_TEXT#} +
      + +
      +
      +
      + +
      +
      {#SETTINGS_MAIN_MAIL#}
      + +++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_NAME#}
      {#SETTINGS_VALUE#}
      {#SETTINGS_EMAIL_NAME#} +
      + +
      +
      {#SETTINGS_EMAIL_SENDER#} +
      + + +
      +
      {#SETTINGS_TEXT_EMAIL#}
      {#SETTINGS_TEXT_INFO#}
      +
      + +
      +
      {#SETTINGS_EMAIL_FOOTER#} +
      + +
      +
      {#SETTINGS_SYMBOL_BREAK#} +
      + + +
      +
      {#SETTINGS_MAIL_TRANSPORT#} +
      + +
      +
      {#SETTINGS_SMTP_SERVER#} +
      + +
      +
      {#SETTINGS_MAIL_PORT#} +
      + +
      +
      {#SETTINGS_SMTP_NAME#} +
      + +
      +
      {#SETTINGS_SMTP_PASS#} +
      + +
      +
      {#SETTINGS_SMTP_ENCRYPT#} +
      + +
      +
      {#SETTINGS_MAIL_PATH#} +
      + +
      +
      +
      + +
      +
      {#SETTINGS_MAIN_PAGENAVI#}
      + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_NAME#}{#SETTINGS_VALUE#}{#SETTINGS_NAME#}{#SETTINGS_VALUE#}
      {#SETTINGS_NAVI_BOX#} +
      + +
      +
      {#SETTINGS_LINK_BOX#} +
      + +
      +
      {#SETTINGS_ACTIVE_LINK_BOX#} +
      + +
      +
      {#SETTINGS_TOTAL_BOX#} +
      + +
      +
      {#SETTINGS_PAGE_BEFORE#} +
      + +
      +
      {#SETTINGS_PAGE_SEPARATOR#} +
      + +
      +
      {#SETTINGS_PAGE_SEPAR#} +
      + +
      +
      {#SETTINGS_PAGE_START#} +
      + +
      +
      {#SETTINGS_PAGE_END#} +
      + +
      +
      {#SETTINGS_PAGE_NEXT#} +
      + +
      +
      {#SETTINGS_PAGE_PREV#} +
      + +
      +
      +
      + +
      +
      {#SETTINGS_MAIN_BREADCRUMBS#}
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SETTINGS_NAME#}
      {#SETTINGS_VALUE#}
      {#SETTINGS_NAME#}
      {#SETTINGS_VALUE#}
      {#SETTINGS_BREAD_MAIN#} +
      +   + +
      +
      {#SETTINGS_BREAD_HOST#} +
      +   + +
      +
      {#SETTINGS_BREAD_BOX#} +
      + +
      +
      {#SETTINGS_BREAD_BOX_LINK#} +
      + +
      +
      {#SETTINGS_BREAD_LINK_TPL#} +
      + +
      +
      {#SETTINGS_BREAD_SELF_BOX#} +
      + +
      +
      {#SETTINGS_BREAD_BOX_LASTLINK#} +
      +   + +
      +
      {#SETTINGS_BREAD_SEPPARATOR#} +
      + +
      +
      {#SETTINGS_BREAD_SEPP_USE#} +
      +   + +
      +
      + +
      +
      +  {#SETTINGS_OR#}  +
      +
      + +
      +
      +
      + + + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" textarea_id='message_forbidden' ctrls='$("#settings").ajaxSubmit(sett_options);' height='150'} +{include file="$codemirror_editor" textarea_id='hidden_text' ctrls='$("#settings").ajaxSubmit(sett_options);' height='150'} \ No newline at end of file diff --git a/admin/templates/settings/settings_pagination.tpl b/admin/templates/settings/settings_pagination.tpl new file mode 100644 index 0000000..a21e926 --- /dev/null +++ b/admin/templates/settings/settings_pagination.tpl @@ -0,0 +1,82 @@ +
      +
      {#SETTINGS_PAGINATION#}
      +
      + +
      +
      + {#SETTINGS_SAVE_INFO#} +
      +
      + + + +
      +
      + {if check_permission('cache_clear')}{#MAIN_STAT_CLEAR_CACHE_FULL#} {/if} + {if check_permission('cache_thumb')}{#MAIN_STAT_CLEAR_THUMB#} {/if} + {if check_permission('document_revisions')}{#MAIN_STAT_CLEAR_REV#} {/if} + {if check_permission('gen_settings')}{#MAIN_STAT_CLEAR_COUNT#} {/if} + {if check_permission('gen_settings_robots')}{#SETTINGS_FILE_ROBOTS#} {/if} + {if check_permission('gen_settings_fcustom')}{#SETTINGS_FILE_CUSTOM#}{/if} +
      +
      + +
      + + + + + + + + + + + + + + + + {if $items} + {foreach from=$items item=item} + + + + + + + {/foreach} + {/if} + +
      ID{#PAGINATION_NAME#}{#PAGINATION_ACTIONS#}
      + {$item->id} + + {$item->pagination_name} + + + + {if $item->id == 1} + + {else} + + {/if} +
      +
      +{include file="$codemirror_connect"} \ No newline at end of file diff --git a/admin/templates/start.tpl b/admin/templates/start.tpl new file mode 100644 index 0000000..c1bb3b8 --- /dev/null +++ b/admin/templates/start.tpl @@ -0,0 +1,258 @@ +
      +
      {#MAIN_WELCOME#}
      +
      + +
      + {if $smarty.const.CHECK_VERSION} +
        + +
      + {/if} + {if $login_menu && $online_users > "1"} + + {/if} + +
      +
      +
      {#MAIN_START_DOC_TITLE#}
      +
      +
      +
      +
      + +
      +
      + + + + + + + + + + + + + + {foreach from=$doc_start item=item} + document_deleted==1}class="red"{/if}{if $item->document_status!=1}class="yellow"{/if}> + + + + + + {/foreach} +
      {#MAIN_START_DOC_ID#}{#MAIN_START_DOC_NAME#}{#MAIN_START_DOC_RUBRIC#}{#MAIN_START_DOC_DATE#}
      {$item->Id} +
      + {if $item->cantEdit==1} + {if $item->rubric_admin_teaser_template != ""} + {$item->rubric_admin_teaser_template} + {else} + + + {if $item->document_breadcrum_title != ""}{$item->document_breadcrum_title|stripslashes|escape}{elseif $item->document_title != ""}{$item->document_title|stripslashes|escape}{else}{#MAIN_DOC_SHOW3_TITLE#}{/if} + + +
      + {$item->document_alias} + {/if} + {else} + {if $item->document_breadcrum_title != ""}{$item->document_breadcrum_title|stripslashes|escape}{elseif $item->document_title != ""}{$item->document_title|stripslashes|escape}{else}{#MAIN_DOC_SHOW3_TITLE#}{/if} +
      + {$item->document_alias} + {/if} +
      +
      + {if check_permission('rubric_edit')} + {$item->rubric_title|escape:html} +
      + {#MAIN_START_DOC_AUTOR#}: {$item->document_author|escape} + {else} + {$item->rubric_title|escape:html} +
      + {#MAIN_START_DOC_AUTOR#}: {$item->document_author|escape} + {/if} +
      {$item->document_published|date_format:$TIME_FORMAT|pretty_date}
      +
      +
      +
      + +
      + +
      + + +
      +
      +
      {#MAIN_STAT_SYSTEM_INFO#}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {$smarty.const.APP_NAME}{$smarty.const.APP_VERSION}
      {#MAIN_STAT_DOMEN#}{$domain}
      {#MAIN_STAT_PHP#}{$php_version}
      {#MAIN_STAT_MYSQL_VERSION#}{$mysql_version}
      {#MAIN_STAT_MYSQL#}{$mysql_size}
      {#MAIN_STAT_CACHE#}{#MAIN_STAT_CACHE_SHOW#}
      +
      + +
      + + +
      + + +
      +
      +
      {#MAIN_STAT#}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + {if $cnts.modules_0} + + + + + {/if} + + + + + {if $cnts.users_0} + + + + + {/if} + +
      {#MAIN_STAT_DOCUMENTS#}{#MAIN_STAT_CACHE_SHOW#}
      {#MAIN_STAT_RUBRICS#}{$cnts.rubrics}
      {#MAIN_STAT_QUERIES#}{$cnts.request}
      {#MAIN_STAT_TEMPLATES#}{$cnts.templates}
      {#MAIN_STAT_MODULES#}{$cnts.modules_0+$cnts.modules_1}
      {#MAIN_STAT_MODULES_OFF#}{$cnts.modules_0|default:0}
      {#MAIN_STAT_USERS#}{$cnts.users_0+$cnts.users_1}
      {#MAIN_STAT_USERS_WAIT#}{$cnts.users_0|default:0}
      +
      + +
      + + +
      + + +
      +
      +
      {#MAIN_LOGS#}
      +
      + + + + + + + + + + + + + + + + + +
      + {if check_permission('logs_view')} + {#MAIN_START_LOGS_LOG#} + {else} + {#MAIN_START_LOGS_LOG#} + {/if} + {$logs.logs}
      + {if check_permission('logs_view')} + {#MAIN_START_LOGS_404#} + {else} + {#MAIN_START_LOGS_404#} + {/if} + 0}class="cmsStatsAlert"{else}class="cmsStats"{/if}>{$logs.404}
      + {if check_permission('logs_view')} + {#MAIN_START_LOGS_SQL#} + {else} + {#MAIN_START_LOGS_SQL#} + {/if} + 0}class="cmsStatsAlert"{else}class="cmsStats"{/if}>{$logs.sql}
      +
      + +
      +
      +
      + {if check_permission('logs_view')} + + {/if} \ No newline at end of file diff --git a/admin/templates/sysblocks/form.tpl b/admin/templates/sysblocks/form.tpl new file mode 100644 index 0000000..34a33b1 --- /dev/null +++ b/admin/templates/sysblocks/form.tpl @@ -0,0 +1,337 @@ + + +
      +
      {#SYSBLOCK_INSERT_H#}
      +
      + +
      +
      {#SYSBLOCK_INSERT#}
      +
      + + + +
      + + + + + + + + + + + + + + +
      + {#SYSBLOCK_LIST_LINK#} + + {#SYSBLOCK_BUTTON_ADD#} + + {#SYS_GROUPS#} +
      +
      + +
      +
      +
      +
      {if $smarty.request.id != ''}{#SYSBLOCK_EDIT_H#}{else}{#SYSBLOCK_INSERT_H#}{/if}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if $sysblock_external} + + + + {/if} +
      + {#SYSBLOCK_NAME#} + +
      + +
      +
      {#SYSBLOCK_DESCRIPTION#} + +
      +
      + [?] {#SYSBLOCK_ALIAS#}: +
      +
      +
      +   + + + + +
      +
      +
      + Группа +
      +
      +
      + +
      +
      + + + + + + + +
      + +
      +
      + +
      +
      +
      {#SYSBLOCK_HTML#}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#SYSBLOCK_TAGS#}{#SYSBLOCK_HTML#}
      + [tag:mediapath]
      {#SYSBLOCK_MEDIAPATH#}
      +
      + +
        +
      • + {#MAIN_CODEMIRROR_HELP#} +
      • +
      +
      + [tag:path]
      {#SYSBLOCK_PATH#}
      +
      + [tag:home]
      {#SYSBLOCK_HOME#}
      +
      + [tag:docid]
      {#SYSBLOCK_DOCID_INFO#}
      +
      + [tag:breadcrumb]
      {#SYSBLOCK_BREADCRUMB#}
      +
      {#SYSBLOCK_TAGS_2#} |  + OL +  |  + UL +  |  + LI +  |  + P +  |  + B +  |  + I +  |  + H1 +  |  + H2 +  |  + H3 +  |  + H4 +  |  + H5 +  |  + DIV +  |  + A +  |  + IMG +  |  + SPAN +  |  + PRE +  |  + BR +  |  + TAB +  |
      + +
      +
      + {if $smarty.request.id != ''} + + + {else} + + {/if} + + {#SYSBLOCK_OR#} + + {if $smarty.request.action=='edit'} + + {else} + + {/if} +
      +
      + +
      +
      + +{literal} + +{/literal} + +{if $smarty.request.action != 'new'} + +{/if} +{include file="$codemirror_connect"} +{include file="$codemirror_editor" textarea_id='sysblock_text' ctrls='$("#sysblock").ajaxSubmit(sett_options);' height='400'} \ No newline at end of file diff --git a/admin/templates/sysblocks/form_visual.tpl b/admin/templates/sysblocks/form_visual.tpl new file mode 100644 index 0000000..235adf8 --- /dev/null +++ b/admin/templates/sysblocks/form_visual.tpl @@ -0,0 +1,263 @@ + + +
      +
      {#SYSBLOCK_INSERT_H#}
      +
      + +
      +
      {#SYSBLOCK_INSERT#}
      +
      + + + +
      + + + + + + + + + + + + + + +
      + {#SYSBLOCK_LIST_LINK#} + + {#SYSBLOCK_BUTTON_ADD#} + + {#SYS_GROUPS#} +
      +
      + +
      +
      +
      +
      {if $smarty.request.id != ''}{#SYSBLOCK_EDIT_H#}{else}{#SYSBLOCK_INSERT_H#}{/if}
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + {if $sysblock_external} + + + + {/if} +
      {#SYSBLOCK_NAME#} +
      + +
      +
      {#SYSBLOCK_DESCRIPTION#} + +
      +
      + [?] {#SYSBLOCK_ALIAS#}: +
      +
      +
      +   + + + + +
      +
      +
      + Группа +
      +
      +
      + +
      +
      + + + + + + + +
      + +
      +
      +
      +
      +
      {#SYSBLOCK_HTML#}
      +
      + + + + + + +
      + {$sysblock_text} +
      + +
      +
      + {if $smarty.request.id != ''} + + + {else} + + {/if} +
      +
      + +
      +
      +{literal} + +{/literal} + +{if $smarty.request.action != 'new'} + +{/if} \ No newline at end of file diff --git a/admin/templates/sysblocks/groups.tpl b/admin/templates/sysblocks/groups.tpl new file mode 100644 index 0000000..0115381 --- /dev/null +++ b/admin/templates/sysblocks/groups.tpl @@ -0,0 +1,194 @@ + + +
      +
      {#SYS_GROUPS#}
      +
      + +
      +
      + {#SYS_GROUPS_TIP#} +
      +
      + + + +
      + + + + + + + + + + + + + + +
      + {#SYSBLOCK_LIST_LINK#} + + {#SYSBLOCK_BUTTON_ADD#} + + {#SYS_GROUPS#} +
      +
      + +{if $groups} +
      + +
      +
      {#SYS_GROUPS#}
      +
      + +
      + + + + + + + + + + + + + + + + + {foreach from=$groups item=group} + = 2} data-id="group_{$group.id}" class="group_tbody"{/if}> + + + + + + {/foreach} + +
      ID[?]{#SYS_GROUPS_GROUP_TITLE#}
      + {$group.id} + + + + {$group.title} + + +
      +
      +
      + +{else} + +
      + +
      +
      {#SYS_GROUPS#}
      +
      + +
      + + + + + + + + + + + + + + + + + + +
      +
        +
      • {#SYS_NO_GROUPS#}
      • +
      +
      + +
      +
      + +{/if} + +
      + +
      +
      {#SYS_GROUPS_NEW#}
      +
      + +
      +
      + + + + + + + + + + + + + + + + + + + +
      + {#SYS_GROUP_TITLE#} + +
      + +
      +
      + {#SYS_GROUP_DESCRIPTION#} + +
      + +
      +
      +
      + +
      +
      +
      +
      + + + diff --git a/admin/templates/sysblocks/multi.tpl b/admin/templates/sysblocks/multi.tpl new file mode 100644 index 0000000..4933b7c --- /dev/null +++ b/admin/templates/sysblocks/multi.tpl @@ -0,0 +1,67 @@ +
      +
      {#SYSBLOCK_COPY_TITLE#}
      +
      + +
      +
      + {#SYSBLOCK_COPY_TIP2#} +
      +
      + + + +
      + + + + + + + + + + + + + + +
      + {#SYSBLOCK_LIST_LINK#} + + {#SYSBLOCK_BUTTON_ADD#} + + {#SYS_GROUPS#} +
      +
      + +{foreach from=$errors item=e} +{assign var=message value=$e} +
        +
      • Ошибка: {$message}
      • +
      +{/foreach} + +
      +
      +
      {#SYSBLOCK_COPY_TITLE#}
      +
      +
      +
      + + +
      +   +
      +
      + +
      +
      +
      diff --git a/admin/templates/sysblocks/nav.tpl b/admin/templates/sysblocks/nav.tpl new file mode 100644 index 0000000..7ba7135 --- /dev/null +++ b/admin/templates/sysblocks/nav.tpl @@ -0,0 +1 @@ +
    9. {#MAIN_SYSBLOCKS#}
    10. \ No newline at end of file diff --git a/admin/templates/sysblocks/start.tpl b/admin/templates/sysblocks/start.tpl new file mode 100644 index 0000000..4c05aca --- /dev/null +++ b/admin/templates/sysblocks/start.tpl @@ -0,0 +1,181 @@ + + +
      +
      {#SYSBLOCK_EDIT#}
      +
      + +
      +
      + {#SYSBLOCK_EDIT_TIP#} +
      +
      + + + +
      + + + + + + + + + + + + + + +
      + {#SYSBLOCK_LIST_LINK#} + + {#SYSBLOCK_BUTTON_ADD#} + + {#SYS_GROUPS#} +
      +
      + + +{foreach from=$groups item=group} + {assign var="group_id" value=$group.id} + + {if $group_id == null} + {assign var="group_id" value='0'} + {/if} + +
      +
      +
      {if $group.title}{$group.title}{else}{#SYS_GROUP_NO_TITLE#}{/if} ({$group.count})
      +
      +
      + +
      + {if $group.description}{$group.description}{else}{#SYS_GROUP_NO_DESCRIPTION#}{/if} +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + {if check_permission('sysblocks_edit')}{/if} + + + + + {foreach from=$sysblocks.$group_id item=sysblock} + + + + + + + + + + + + + + + {if check_permission('sysblocks_edit')} + + + + + + {/if} + + {foreachelse} + + + + {/foreach} + + +
      {#SYSBLOCK_ID#}[?][?][?]{#SYSBLOCK_NAME#}{#SYSBLOCK_AUTHOR#}{#SYSBLOCK_DATE#}{#SYSBLOCK_TAG#}{#SYSBLOCK_ACTIONS#}
      + {$sysblock.id} + + {if $sysblock.sysblock_external}{else}{/if} + + + + + + {if check_permission('sysblocks_edit')} + + {$sysblock.sysblock_name|escape} + + {if $sysblock.sysblock_description} +
      {$sysblock.sysblock_description|escape} + {/if} + {else} + {$sysblock.sysblock_name|escape} + {/if} +
      + {$sysblock.author|escape} + + {$sysblock.sysblock_created|date_format:$TIME_FORMAT|pretty_date} + +
      + + + + +
      +
      + + + + + +
      +
        +
      • {#SYSBLOCK_NO_ITEMS#}
      • +
      +
      +
      +
      +
      +{/foreach} + + +{literal} + +{/literal} \ No newline at end of file diff --git a/admin/templates/templates/edit_css.tpl b/admin/templates/templates/edit_css.tpl new file mode 100644 index 0000000..2e065e2 --- /dev/null +++ b/admin/templates/templates/edit_css.tpl @@ -0,0 +1,89 @@ +
      {#TEMPLATES_CSS_EDITOR#}
      + +
      +
      + {#TEMPLATES_CSS_TITLE#} +
      +
      + + + +
      + +
      +
      {$smarty.request.name_file|escape}
      + +
      + +
      +
      + +
      + + {#TEMPLATES_OR#} + +
      +
      + +
      +
      + + + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" textarea_id='code_text' ctrls='$("#code_templ").ajaxSubmit(sett_options);' mode='text/css'} \ No newline at end of file diff --git a/admin/templates/templates/edit_js.tpl b/admin/templates/templates/edit_js.tpl new file mode 100644 index 0000000..80c73fe --- /dev/null +++ b/admin/templates/templates/edit_js.tpl @@ -0,0 +1,88 @@ +
      {#TEMPLATES_JS_TITLE#}
      + +
      +
      + {#TEMPLATES_JS_TITLE#} +
      +
      + + + +
      + +
      +
      {$smarty.request.name_file|escape}
      + +
      + +
      +
      + +
      + + {#TEMPLATES_OR#} + +
      +
      + +
      +
      + + +{include file="$codemirror_connect"} +{include file="$codemirror_editor" textarea_id='code_text' ctrls='$("#code_templ").ajaxSubmit(sett_options);' mode='text/javascript'} \ No newline at end of file diff --git a/admin/templates/templates/form.tpl b/admin/templates/templates/form.tpl new file mode 100644 index 0000000..80f04c4 --- /dev/null +++ b/admin/templates/templates/form.tpl @@ -0,0 +1,358 @@ +{if $smarty.request.action=='new'} +
      {#TEMPLATES_TITLE_NEW#}
      +
      {#TEMPLATES_WARNING2#}
      +{else} +
      {#TEMPLATES_TITLE_EDIT#}
      +
      {#TEMPLATES_WARNING1#}
      +{/if} + + + +{if $errors} +
      + +
        + +
      • + {foreach from=$errors item=e} + {assign var=message value=$e} + • {$message}
        + {/foreach} +
      • + +
      + +
      +{/if} + +
      + +
      +
      +
      {#TEMPLATES_TITLE_EDIT#}
      +
      + +
      + +
      + +
      +
      +
      +
      + + {if $php_forbidden==1} +
      +
        +
      • {#TEMPLATES_USE_PHP#}
      • +
      +
      + {/if} + +
      +
      +
      {#TEMPLATES_HTML#}
      +
      + {if !check_permission('template_php')} +
      +
        +
      • + {#TEMPLATES_REPORT_PHP_ERR#} +
      • +
      +
      +
      + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#TEMPLATES_TAGS#}{#TEMPLATES_HTML#}
      + [tag:theme:folder] + + +
        +
      • + {#MAIN_CODEMIRROR_HELP#} +
      • +
      +
      + [tag:language] +
      + [tag:sitename] +
      + [tag:rubheader] +
      + [tag:rubfooter] +
      + [tag:title] +
      + [tag:keywords] +
      + [tag:description] +
      + [tag:robots] +
      + [tag:canonical] +
      + [tag:path] +
      + [tag:mediapath] +
      + [tag:css:FFF:P],   + [tag:js:FFF:P] +
      + [tag:doc:XXX] +
      + [tag:langfile:XXX] +
      + [tag:maincontent] +
      + [tag:alias] +
      + [tag:domain] +
      + [tag:home] +
      + [tag:printlink] +
      + [tag:breadcrumb] +
      + [tag:teaser:XXX] +
      + [tag:sysblock:XXX] +
      + [tag:navigation:XXX] +
      + [tag:lang:XX][/tag:lang] +
      + [tag:if_print][/tag:if_print] +
      + [tag:if_notprint][/tag:if_notprint] +
      + [tag:version] +
      HTML Tags + |  + OL |  + UL |  + LI |  + P |  + B |  + I |  + H1 |  + H2 |  + H3 |  + H4 |  + H5 |  + DIV |  + A |  + IMG |  + SPAN |  + PRE |  + BR |  + TAB | +
      +
      +
      + {if $smarty.request.action == 'new'} + + {else} + + {/if} + {#TEMPLATES_OR#} + {if $smarty.request.action=='edit'} + + + {else} + + {/if} +
      +
      +
      +
      +{if $smarty.request.action != 'new'} + +{/if} + +{include file="$codemirror_connect"} + +{if $php_forbidden == 1} + {include file="$codemirror_editor" textarea_id='template_text' ctrls='$("#f_tpl").ajaxSubmit(sett_options);' height='720' readonly='true'} +{else} + {include file="$codemirror_editor" textarea_id='template_text' ctrls='$("#f_tpl").ajaxSubmit(sett_options);' height='720'} +{/if} diff --git a/admin/templates/templates/nav.tpl b/admin/templates/templates/nav.tpl new file mode 100644 index 0000000..a298925 --- /dev/null +++ b/admin/templates/templates/nav.tpl @@ -0,0 +1 @@ +
    11. {#MAIN_TEMPLATES#}
    12. \ No newline at end of file diff --git a/admin/templates/templates/templates.tpl b/admin/templates/templates/templates.tpl new file mode 100644 index 0000000..3280fd8 --- /dev/null +++ b/admin/templates/templates/templates.tpl @@ -0,0 +1,261 @@ + + +
      {#TEMPLATES_SUB_TITLE#}
      + +
      +
      + {#TEMPLATES_TIP1#} +
      +
      + + + +
      + + +
      +
      + + + + + + + + + + + + + {foreach from=$items item=tpl} + + + + + + + + + + {/foreach} + +
      {#TEMPLATES_ID#}{#TEMPLATES_NAME#}{#TEMPLATES_AUTHOR#}{#TEMPLATES_DATE#}{#TEMPLATES_ACTION#}
      {$tpl->Id}{if check_permission('template_edit')}{$tpl->template_title|escape}{else}{$tpl->template_title|escape}{/if}{$tpl->template_author}{$tpl->template_created|date_format:$TIME_FORMAT|pretty_date} + {if check_permission('template_edit')} + + {else} + + {/if} + + {if check_permission('template_edit')} + + {else} + + {/if} + + {if $tpl->Id == 1} + + {else} + {if $tpl->can_deleted==1} + {if check_permission('template_edit')} + + {else} + + {/if} + {else} + + {/if} + {/if} +
      +
      + + {if check_permission('template_edit')} + + {/if} + + {if check_permission('template_edit')} + + + + {/if} + + {if check_permission('mediapool_finder')} + + {/if} + +
      + +
      +
      + + + + {if $page_nav} + + {/if} diff --git a/admin/templates/user/form.tpl b/admin/templates/user/form.tpl new file mode 100644 index 0000000..a0df04b --- /dev/null +++ b/admin/templates/user/form.tpl @@ -0,0 +1,340 @@ +{if !$no_edit} + +{literal} + +{/literal} + +{if $smarty.request.action=='new'} +
      {#USER_NEW_TITLE#}
      +
      {#USER_NEW_TIP#}
      +{else} +
      {#USER_EDIT_TITLE#}
      +
      {#USER_EDIT_TIP#}
      +{/if} + + + + +{if $errors} +
        +
      • {#USER_ERRORS#}
        {foreach from=$errors item=error}• {$error}
        {/foreach}
      • +
      +{/if} + +
      + +{if $smarty.request.action=='edit'} + +{/if} + +
      + +
      +
      {#USER_EDIT_TITLE#}
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{if $is_forum==1 && $smarty.request.action=='edit'} + + + + + + + + + +{/if} + + + + + + +{if $is_shop==1} + + + + +{/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{assign var=u_group value=$row->user_group|lower|escape|stripslashes} + + + + + + + + + + + + + + + +{if $smarty.request.action=='edit'} + + + + + + + + + +{/if} + + +
      {#USER_LOGIN#}
      {#USER_FIRSTNAME#}
      {#USER_LASTNAME#}
      {#USER_EMAIL#}
      {#USER_PASSWORD#} {if $smarty.request.action=='edit'} ({#USER_PASSWORD_CHANGE#}){/if} +
      + + +
      +
      + +
      + {if $smarty.request.action=='edit'} + + {/if} +
      {#USER_NICK#}
      {#USER_SIGNATURE#}
      {#USER_AVATAR#}
      + {if $row->avatar}{/if} +
      + +
      {#USER_TAX#}
      + taxpay=='1'}checked="checked" {/if}/> + taxpay=='0'}checked="checked" {/if}/> +
      {#USER_COMPANY#}
      {#USER_HOUSE_STREET#}
      +   + +
      {#USER_ZIP_CODE#}
      {#USER_CITY#}
      {#USER_COUNTRY#}
      + +
      {#USER_PHONE#}
      {#USER_FAX#}
      {#USER_BIRTHDAY#} {#USER_BIRTHDAY_FORMAT#}
      {#USER_NOTICE#}
      {#USER_MAIN_GROUP#} +
      + {if check_permission('user_perms')} + {if ($smarty.session.user_id == $row->Id) && $row->user_group != 1} + + {else} + + {/if} + {else} + + {/if} +
      +
      {#USER_SECOND_GROUP#}
      {#USER_SECOND_INFO#}
      +
      +{if check_permission('user_perms')} + {foreach from=$ugroups item=groups} + user_group == $row->user_group} disabled="disabled"{/if} + {if $us_groups|@is_array && in_array($groups->user_group, $us_groups)} checked="checked"{/if} + > + +
      + {/foreach} +{/if} +
      +
      {#USER_STATUS#} +
      + +
      + {if $smarty.request.action=='edit'} + + {/if} +
      {#USER_MESSAGE_SUBJECT#}
      {#USER_MESSAGE_TEXT#}
      + +
      +
      + +
      +
      + +
      + +
      +
      + +{else} + +
      {#USER_SUB_TITLE#}
      + +
      +
      + + {#USER_WARNING_TIP#} + +
      +
      + +
        +
      • • {#USER_YOUR_NOT_CHANGE#}
      • +
      +{/if} diff --git a/admin/templates/user/nav.tpl b/admin/templates/user/nav.tpl new file mode 100644 index 0000000..16caf25 --- /dev/null +++ b/admin/templates/user/nav.tpl @@ -0,0 +1 @@ +
    13. {#MAIN_USERS#}
    14. \ No newline at end of file diff --git a/admin/templates/user/users.tpl b/admin/templates/user/users.tpl new file mode 100644 index 0000000..90c63d0 --- /dev/null +++ b/admin/templates/user/users.tpl @@ -0,0 +1,423 @@ + + +
      {#USER_SUB_TITLE#}
      + +
      +
      + {#USER_TIP1#} +
      +
      + + + +
      +
      {#MAIN_SEARCH_USERS#}
      +
      +
      + + + + + + + + + + + + + + + + +
      {#MAIN_USER_PARAMS#}{#MAIN_USER_GROUP#}{#MAIN_ALL_USER_GROUP#}
      + + + +
      + +
      + +
      +
      +
      + +
      + + + +
      +
      + + {if !$users} +
        +
      • Ошибка: {#USER_LIST_EMPTY#}
      • +
      + {else} + + {if check_permission('user_edit')} +
      + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + + {foreach from=$users item=user} + status}class="yellow"{/if}> + + + + + + + + + + + + + + +{* + + + +*} + + {/foreach} + +
      {#USER_ID#}-{#USER_AVATAR#}{#USER_NAME#}{#USER_GROUP#}{#USER_LAST_VISIT#}{#USER_REGISTER_DATE#}
      {#USER_ACTION#}
      {$user->Id} + + + {if check_permission('user_edit')} + + {if ($smarty.session.user_group != 1 && $user->user_group == 1)} + + + {elseif $smarty.session.user_group == 1 && $user->Id != 1} + + + {else} + + {if $smarty.session.user_group == $user->user_group && $smarty.session.user_id == $user->Id} + + + {elseif $smarty.session.user_group == $user->user_group && $smarty.session.user_id != $user->Id} + + + {else} + + {/if} + {/if} + + {else} + + {/if} + + {if $user->avatar}{else}{/if} + + {if check_permission('user_edit')} + + {if ($smarty.session.user_group != 1 && $user->user_group == 1)} + {$user->user_name|escape}{if $user->firstname && $user->lastname} ({$user->firstname|escape} {$user->lastname|escape}){/if} + + {elseif $smarty.session.user_group == 1} + + {$user->user_name|escape}{if $user->firstname && $user->lastname} ({$user->firstname|escape} {$user->lastname|escape}){/if} + + + {else} + + {if $smarty.session.user_group == $user->user_group && $smarty.session.user_id == $user->Id} + + {$user->user_name|escape}{if $user->firstname && $user->lastname} ({$user->firstname|escape} {$user->lastname|escape}){/if} + + + {elseif $smarty.session.user_group == $user->user_group && $smarty.session.user_id != $user->Id} + {$user->user_name|escape}{if $user->firstname && $user->lastname} ({$user->firstname|escape} {$user->lastname|escape}){/if} + + {else} + + {$user->user_name|escape}{if $user->firstname && $user->lastname} ({$user->firstname|escape} {$user->lastname|escape}){/if} + + {/if} + {/if} +
      + {$user->email|escape} (IP:{$user->reg_ip|escape}) + + {else} + {$user->user_name|escape}{if $user->firstname && $user->lastname} ({$user->firstname|escape} {$user->lastname|escape}){/if} +
      + {$user->email|escape} (IP:{$user->reg_ip|escape}) + {/if} +
      + {if !$user->status} +
      {#USER_STATUS_WAIT#}
      + {else} + {if check_permission('user_perms')} +{* + {if ($smarty.session.user_id == $user->Id) && $user->user_group != 1} + + {else} + + {/if} + {else} + +*} + + + {if check_permission('user_edit')} + + {if ($smarty.session.user_group != 1 && $user->user_group == 1)} + + + {elseif $smarty.session.user_group == 1} + + + {else} + + {if $smarty.session.user_group == $user->user_group && $smarty.session.user_id == $user->Id} + + + {elseif $smarty.session.user_group == $user->user_group && $smarty.session.user_id != $user->Id} + + + {else} + + {/if} + {/if} + + {else} + + {/if} + + + {/if} + {/if} +
      + {if $user->status AND $user->last_visit>0} + {$user->last_visit|date_format:$TIME_FORMAT|pretty_date} + {else} + - + {/if} + {$user->reg_time|date_format:$TIME_FORMAT|pretty_date} + + + {if check_permission('user_edit')} + + {if ($smarty.session.user_group != 1 && $user->user_group == 1)} + + + {elseif $smarty.session.user_group == 1} + + + {else} + + {if $smarty.session.user_group == $user->user_group && $smarty.session.user_id == $user->Id} + + + {elseif $smarty.session.user_group == $user->user_group && $smarty.session.user_id != $user->Id} + + + {else} + + {/if} + {/if} + + {else} + + {/if} + + + {if $user->Id != 1 && $smarty.session.user_group != $user->user_group} + {if check_permission('user_perms') && $user->Id!=$smarty.session.user_id} + + {else} + + {/if} + {else} + + {/if} + + {if $user->IsShop && $user->Orders} + + {else} + + {/if} + + {if $user->IsShop} + + {else} + + {/if} +
      + + {if check_permission('user_edit')} +
      + +
      +
      + {/if} + +{/if} + +
      + {if check_permission('user_edit')} + + {/if} + +
      + +
      +
      + +{if $page_nav} + +{/if} \ No newline at end of file diff --git a/admin/user.php b/admin/user.php new file mode 100644 index 0000000..d879548 --- /dev/null +++ b/admin/user.php @@ -0,0 +1,67 @@ +userListFetch(); + +$AVE_Template->config_load(BASE_DIR . '/admin/lang/' . $_SESSION['admin_language'] . '/user.txt', 'user'); + +switch ($_REQUEST['action']) +{ + case '': + if (check_permission_acp('user_view')) + { + $AVE_Template->assign('content', $AVE_Template->fetch('user/users.tpl')); + } + break; + + case 'edit': + if (check_permission_acp('user_edit')) + { + $AVE_User->userEdit($_REQUEST['Id']); + } + break; + + case 'new': + if (check_permission_acp('user_edit')) + { + $AVE_User->userNew(); + } + break; + + case 'delete': + if (check_permission_acp('user_edit')) + { + $AVE_User->userDelete($_REQUEST['Id']); + } + break; + + case 'quicksave': + if (check_permission_acp('user_edit')) + { + $AVE_User->userListEdit(); + } + break; +} + +?> \ No newline at end of file diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 0000000..cef02c9 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,53 @@ +------------------------------------------------------------------------- + +Добавлена позиция документа, можно использовать в сортировках в запросах + +------------------------------------------------------------------------- + +Добавлено полям использование дополнительных шаблонов (tpl) + +Пример +file-doc.tpl +file-doc-ID.tpl +file-doc-ID-XXX.tpl + +Вызов через тег +[tag:fld:ID] +[tag:fld:ID:XXX] + +------------------------------------------------------------------------- + +Системным блокам добавлены параметры в видже JSON строки + +Вызов системного блока +[tag:sysblock:{"PARAM_NAME":"value"}] + +В коде системного блока, получение параметров +[sys:param:PARAM_NAME] + +------------------------------------------------------------------------- + +Добавлено системным блокам галочка, Выполнять PHP перед возвращением результата + +------------------------------------------------------------------------- + +Можно использовать тег одного поля в данных другого поля + +------------------------------------------------------------------------- + +Можно использовать тег системного блока внутри другого блока + +------------------------------------------------------------------------- + +Списку документам в админке можно делать назначать свои шаблоны вывода, +по id рубрики admin/templates/documents/docs-ID.tpl + +------------------------------------------------------------------------- + +Добавлено системным блокам группы + +------------------------------------------------------------------------- + +В поиске документов добавилось по параметру документа + +------------------------------------------------------------------------- \ No newline at end of file diff --git a/class/.htaccess b/class/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/class/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/class/class.blocks.php b/class/class.blocks.php new file mode 100644 index 0000000..8b84248 --- /dev/null +++ b/class/class.blocks.php @@ -0,0 +1,266 @@ +Query(" + SELECT 1 + FROM + " . PREFIX . "_blocks + WHERE + block_alias = '" . $alias . "' + AND + id != '" . $id . "' + ")->GetCell(); + } + + /** + * Вывод списка системных блоков + */ + function blockList() + { + global $AVE_DB, $AVE_Template; + + $vis_blocks = array(); + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_blocks + ORDER BY + id + "); + + // Формируем массив из полученных данных + while ($row = $sql->FetchRow()) + { + $row->block_author_id = get_username_by_id($row->block_author_id); + array_push($vis_blocks, $row); + } + + $AVE_Template->assign('sid', 0); + $AVE_Template->assign('vis_blocks', $vis_blocks); + $AVE_Template->assign('content', $AVE_Template->fetch('blocks/list.tpl')); + } + + /** + * Сохранение системного блока + * + * @param int $block_id идентификатор системного блока + */ + function blockSave ($block_id = null) + { + global $AVE_DB, $AVE_Template; + + if (is_numeric($block_id)) + { + $_REQUEST['block_visual'] = (isset($_REQUEST['block_visual'])) ? $_REQUEST['block_visual'] : 0; + + $block_alias = isset($_REQUEST['block_alias']) + ? $_REQUEST['block_alias'] + : ''; + + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_blocks + SET + block_name = '" . $_REQUEST['block_name'] . "', + block_description = '" . addslashes($_REQUEST['block_description']) . "', + block_alias = '" . $_REQUEST['block_alias'] . "', + block_text = '" . $_REQUEST['block_text'] . "' + WHERE + id = '" . $block_id . "' + "); + + if ($sql->_result === false) + { + $message = $AVE_Template->get_config_vars('BLOCK_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('BLOCK_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('BLOCK_SAVED'); + $header = $AVE_Template->get_config_vars('BLOCK_SUCCESS'); + $theme = 'accept'; + + //-- Стираем кеш блока + $this->clearCache($block_id, $block_alias); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('BLOCK_SQLUPDATE') . " (" . stripslashes($_REQUEST['block_name']) . ") (id: $block_id)"); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=blocks&cp=' . SESSION); + } + + exit; + } + else + { + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_blocks + SET + block_name = '" . $_REQUEST['block_name'] . "', + block_description = '" . addslashes($_REQUEST['block_description']) . "', + block_alias = '" . $_REQUEST['block_alias'] . "', + block_text = '" . $_REQUEST['block_text'] . "', + block_author_id = '" . (int)$_SESSION['user_id'] . "', + block_created = '" . time() . "' + "); + + $block_id = $AVE_DB->InsertId(); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('BLOCK_SQLNEW') . " (" . stripslashes($_REQUEST['block_name']) . ") (id: $block_id)"); + } + + if (! isset($_REQUEST['next_edit'])) + header('Location:index.php?do=blocks&cp=' . SESSION); + else + header('Location:index.php?do=blocks&action=edit&&id=' . $block_id . '&cp=' . SESSION); + } + + /** + * Редактирование системного блока + * + * @param int $block_id идентификатор системного блока + */ + function blockEdit ($block_id) + { + global $AVE_DB, $AVE_Template; + + $row = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_blocks + WHERE + id = '" . $block_id . "' + OR + block_alias = '" . $block_id . "' + ")->FetchAssocArray(); + + $AVE_Template->assign('sid', $row['id']); + + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['customConfig'] = 'block.js'; + $oCKeditor->config['toolbar'] = 'Big'; + $oCKeditor->config['height'] = 400; + $config = array(); + $row['block_text'] = $oCKeditor->editor('block_text', $row['block_text'], $config); + + $AVE_Template->assign($row); + $AVE_Template->assign('content', $AVE_Template->fetch('blocks/form.tpl')); + } + + /** + * Создание блока + */ + function blockNew() + { + global $AVE_DB, $AVE_Template; + + $row['block_name'] = ''; + $row['block_alias'] = ''; + $row['block_text'] = ''; + + $AVE_Template->assign('sid', 0); + + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['customConfig'] = 'block.js'; + $oCKeditor->config['toolbar'] = 'Big'; + $oCKeditor->config['height'] = 400; + $config = array(); + $row['block_text'] = $oCKeditor->editor('block_text', $row['block_text'], $config); + + $AVE_Template->assign($row); + $AVE_Template->assign('content', $AVE_Template->fetch('blocks/form.tpl')); + } + + /** + * Удаление блока + * + * @param int $block_id идентификатор блока + */ + function blockDelete($block_id) + { + global $AVE_DB, $AVE_Template; + + if (is_numeric($block_id)) + { + $row = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_blocks + WHERE + id = '" . $block_id . "' + ")->FetchRow(); + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_blocks + WHERE + id = '" . $block_id . "' + "); + + //-- Стираем кеш блока + $this->clearCache($block_id, $row->block_alias); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('BLOCK_SQLDEL') . " (" . stripslashes($row->block_name) . ") (id: $block_id)"); + } + + header('Location:index.php?do=blocks&cp=' . SESSION); + } + + + function clearCache ($id, $alias = null) + { + $cache_id = md5('block' . $id); + $cache_alias = md5('block' . $alias); + + $cache_id_file = BASE_DIR . '/tmp/cache/sql/block/' . $cache_id . '.cache'; + $cache_alias_file = BASE_DIR . '/tmp/cache/sql/block/' . $cache_alias . '.cache'; + + if (file_exists($cache_id_file)) + unlink($cache_id_file); + + if (file_exists($cache_alias_file)) + unlink($cache_alias_file); + } + } +?> \ No newline at end of file diff --git a/class/class.cache.php b/class/class.cache.php new file mode 100644 index 0000000..662bb1e --- /dev/null +++ b/class/class.cache.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/class/class.core.php b/class/class.core.php new file mode 100644 index 0000000..3a3cf66 --- /dev/null +++ b/class/class.core.php @@ -0,0 +1,2078 @@ +HTTP Error 404: Page not found'; + + /** + * Сообщение об ошибке, если для рубрики не найден шаблон + * + * @public string + */ + public $_rubric_template_empty = '

      Ошибка


      Не задан шаблон рубрики.'; + + /** + * Сообщение об ошибке, если документ запрещен к показу + * + * @public string + */ + public $_doc_not_published = 'Запрашиваемый документ запрещен к публикации.'; + + /** + * Сообщение об ошибке, если модуль не может быть загружен + * + * @public string + */ + public $_module_error = 'Запрашиваемый модуль не может быть загружен.'; + + /** + * Сообщение об ошибке, если модуль, указанный в шаблоне, не установлен в системе + * + * @public string + */ + public $_module_not_found = 'Запрашиваемый модуль не найден.'; + + + function _getRequestModule ($name = null) + { + foreach ($this->install_modules as $k => $v) + if ($v['ModuleSysName'] == $name && $v['ModuleStatus'] == 1) + return true; + + return false; + } + + /** + * Получаем шаблон документа + * + * @param $rubric_id + * @param $template_id + * + * @return bool|null|string + */ + function _getMainTemplate($rubric_id, $template_id) + { + global $AVE_DB; + + $return = null; + + if (is_numeric($template_id)) + { + $cache_file = BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/include/templates/' . $template_id . '/template.inc'; + + // Если включен DEV MODE, то отключаем кеширование + if (defined('DEV_MODE') AND DEV_MODE) + $cache_file = null; + + if (! is_dir(dirname($cache_file))) + @mkdir(dirname($cache_file), 0766, true); + + // Если файл есть и он не пустой используем его + if (file_exists($cache_file) && filesize($cache_file)) + { + $return = file_get_contents($cache_file); + } + // Иначе лезем в БД и достаем шаблон + else + { + $return = $AVE_DB->Query(" + SELECT + template_text + FROM + " . PREFIX . "_templates + WHERE + Id = '" . $template_id . "' + LIMIT 1 + ")->GetCell(); + + $return = stripslashes($return); + + // Сохраняем в файл + if ($cache_file) + file_put_contents($cache_file, $return); + } + } + + return $return; + } + + + /** + * Получение основных настроек сисблока + * + * @param string $param параметр настройки, если не указан - все параметры + * @return mixed + */ + function _requestGet($id, $param = '') + { + global $AVE_DB; + + static $request = null; + + if ($request === null) + { + $request = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_request + WHERE + " . (is_numeric($id) ? 'Id' : 'request_alias') . " = '" . $id . "' + ")->FetchAssocArray(); + } + + if ($param == '') + return $request; + + return isset($request[$param]) + ? $request[$param] + : null; + } + + /** + * Метод, предназначенный для получения шаблонов + * + * @param int $rubric_id идентификатор рубрики + * @param string $template шаблон + * @param string $fetched шаблон модуля + * @return string + */ + function _coreDocumentTemplateGet($rubric_id = null, $template = null, $fetched = null, $template_id = null) + { + global $AVE_DB; + + // Если выводится только содержимое модуля или это новое окно (например страница для печати), + // просто возвращаем содержимое. + if (defined('ONLYCONTENT') || (isset ($_REQUEST['pop']) && $_REQUEST['pop'] == 1)) + { + $out = '[tag:maincontent]'; + } + else + { + // В противном случае, если в качестве аргумента передан шаблон модуля, возвращаем его. + if (! empty($fetched)) + { + $out = $fetched; + } + else + { + // В противном случае, если в качестве аргумента передан общий шаблон, возвращаем его + if (! empty($template)) + { + $out = $template; + } + else // В противном случае, если аргументы не определены, тогда проверяем + { + // Если для текущего документа в свойстве класса $this->curentdoc определен шаблон, тогда возвращаем его + if (! empty ($this->curentdoc->template_text)) + { + $out = stripslashes($this->curentdoc->template_text); + unset($this->curentdoc->template_text); + } + else + { + // В противном случае, если не указан идентификатор рубрики + if (empty ($rubric_id)) + { + // Получаем id документа из запроса + $_REQUEST['id'] = (isset ($_REQUEST['id']) && is_numeric($_REQUEST['id'])) + ? $_REQUEST['id'] + : 1; + + // Выполняем запрос к БД на получение id рубрики на основании id документа + $rubric_id = $AVE_DB->Query(" + SELECT + rubric_id + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $_REQUEST['id'] . "' + LIMIT 1 + ")->GetCell(); + + // Если id рубрики не найден, возвращаем пустую строку + if (! $rubric_id) + return ''; + } + + // Выполняем запрос к БД на получение основного шаблона, а также шаблона рубрики + $tpl = $this->_getMainTemplate($rubric_id, $template_id); + + // Если запрос выполнился с нулевым результатом, возвращаем пустую строку + $out = $tpl + ? stripslashes($tpl) + : ''; + } + } + } + } + + // получаем из шаблона системный тег, определяющий название темы дизайна + $match = array(); + + preg_match('/\[tag:theme:(\w+)]/', $out, $match); + + define('THEME_FOLDER', empty ($match[1]) + ? DEFAULT_THEME_FOLDER + : $match[1]); + + $out = preg_replace('/\[tag:theme:(.*?)]/', '', $out); + + // Если пришел вызов на активацию языковых файлов + $out = preg_replace_callback( + '/\[tag:language]/', + function () + { + global $AVE_Template; + + $lang_file = BASE_DIR . '/templates/' . THEME_FOLDER . '/lang/' . $_SESSION['user_language'] . '.txt'; + + $AVE_Template->config_load($lang_file); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + }, + $out + ); + + return $out; + } + + /** + * Метод, предназначенный для получения шаблона модуля + * + * @return string + */ + function _coreModuleTemplateGet() + { + global $AVE_DB; + + if (isset($_REQUEST['module']) && ! preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $_REQUEST['module'])) + return ''; + + // Если папка, с запрашиваемым модулем не существует, выполняем редирект + // на главную страницу и отображаем сообщение с ошибкой + if (! is_dir(BASE_DIR . '/modules/' . $_REQUEST['module'])) + { + echo ''; + $out = $this->_module_not_found; + } + // В противном случае + else + { + // Выполняем запрос к БД на получение списка общих шаблонов имеющиюся в системе + // и шаблоне, который установлен для данного модуля + // Например, в системе есть шаблоны Template_1 и Template_2, а для модуля установлен Template_3 + $out = $AVE_DB->Query(" + SELECT + tmpl.template_text + FROM + " . PREFIX . "_templates AS tmpl + LEFT JOIN + " . PREFIX . "_module AS mdl + ON tmpl.Id = mdl.ModuleTemplate + WHERE + ModuleSysName = '" . $_REQUEST['module'] . "' + ")->GetCell(); + + // Если шаблон, установленный для модуля не найден в системе, принудительно устанавливаем для него + // первый шаблон (id=1) + if (empty ($out)) + { + $out = $AVE_DB->Query(" + SELECT + template_text + FROM + " . PREFIX . "_templates + WHERE + Id = '1' + LIMIT 1 + ")->GetCell(); + } + } + // Возвращаем информацию о полученном шаблоне + return stripslashes($out); + } + + /** + * Метод, предназначенный для получения прав доступа к документам рубрики + * + * @param int $rubrik_id идентификатор рубрики + */ + function _coreRubricPermissionFetch($rubrik_id = '') + { + global $AVE_DB; + + unset ($_SESSION[$rubrik_id . '_docread']); + + // Если для документа уже получены права доступа, тогда + if (!empty ($this->curentdoc->rubric_permission)) + { + // Формируем массив с правами доступа + $rubric_permissions = explode('|', $this->curentdoc->rubric_permission); + + // Циклически обрабатываем сформированный массив и создаем в сессии соответсвующие переменные + foreach ($rubric_permissions as $rubric_permission) + { + if (!empty ($rubric_permission)) + { + $_SESSION[$rubrik_id . '_' . $rubric_permission] = 1; + } + } + } // В противном случае + else + { + // Выполняем запрос к БД на получение списка прав для данного документа + $sql = $AVE_DB->Query(" + SELECT + rubric_permission + FROM + " . PREFIX . "_rubric_permissions + WHERE + rubric_id = '" . $rubrik_id . "' + AND + user_group_id = '" . UGROUP . "' + "); + + // Обрабатываем полученные данные и создаем в сессии соответсвующие переменные + while ($row = $sql->FetchRow()) + { + $row->rubric_permission = explode('|', $row->rubric_permission); + + foreach ($row->rubric_permission as $rubric_permission) + { + if (! empty($rubric_permission)) + { + $_SESSION[$rubrik_id . '_' . $rubric_permission] = 1; + } + } + } + } + } + + + /** + * Метод, предназначенный для обработки события 404 Not Found, т.е. когда страница не найдена. + * + * @return unknown + */ + function _coreErrorPage404() + { + global $AVE_DB; + + // Выполняем запрос к БД на проверку существования страницы, которая содержит информацию о том, что + // запрашиваемая страница не найдена + $available = $AVE_DB->Query(" + SELECT + COUNT(*) + FROM + " . PREFIX . "_documents + WHERE + Id = '" . PAGE_NOT_FOUND_ID . "' + LIMIT 1 + ")->GetCell(); + + // Если такая страница в БД существует, выполняем переход на страницу с ошибкой + if ($available) + { + header('Location:' . ABS_PATH . 'index.php?id=' . PAGE_NOT_FOUND_ID); + } + // Если не существует, тогда просто выводим текст, определенный в свойстве _doc_not_found + else + { + echo $this->_doc_not_found; + } + + exit; + } + + + /** + * Метод, предназначенный для проверки существования документа в БД + * + * @param int $document_id - id документа + * @param int $user_group - группа пользователя + * @return boolean + */ + function _coreCurrentDocumentFetch($document_id = 1, $user_group = 2) + { + global $AVE_DB; + + // Выполняем составной запрос к БД на получение информации о запрашиваемом документе + $this->curentdoc = $AVE_DB->Query(" + SELECT + doc.*, + rubric_permission, + rubric_template, + rubric_header_template, + rubric_footer_template, + rubric_meta_gen, + template_text, + other.template + FROM + " . PREFIX . "_documents AS doc + JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = doc.rubric_id + JOIN + " . PREFIX . "_templates AS tpl + ON tpl.Id = rubric_template_id + JOIN + " . PREFIX . "_rubric_permissions AS prm + ON doc.rubric_id = prm.rubric_id + LEFT JOIN + " . PREFIX . "_rubric_templates AS other + ON doc.rubric_id = other.rubric_id AND doc.rubric_tmpl_id = other.id + WHERE + user_group_id = '" . $user_group . "' + AND + doc.Id = '" . $document_id . "' + LIMIT 1 + ")->FetchRow(); + + if ($this->curentdoc->rubric_tmpl_id != 0) + { + $this->curentdoc->rubric_template = (($this->curentdoc->template != '') + ? $this->curentdoc->template + : $this->curentdoc->rubric_template); + + unset($this->curentdoc->template); + } + + // Возвращаем 1, если документ найден, либо 0 в противном случае + return (isset($this->curentdoc->Id) && $this->curentdoc->Id == $document_id); + } + + /** + * Метод, предназначенный для получения содержимого страницы с 404 ошибкой + * + * + * @param int $page_not_found_id + * @param int $user_group + * @return int/boolean + */ + function _corePageNotFoundFetch($page_not_found_id = 2, $user_group = 2) + { + global $AVE_DB; + + // Выполняем запрос к БД на получение полной информации о странице с 404 ошибкой, включая + // права доступа, шаблон рубрики и основной шаблон сайта + $this->curentdoc = $AVE_DB->Query(" + SELECT + doc.*, + rubric_permission, + rubric_template, + rubric_header_template, + rubric_footer_template, + rubric_meta_gen, + template_text + FROM + " . PREFIX . "_documents AS doc + JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = doc.rubric_id + JOIN + " . PREFIX . "_templates AS tpl + ON tpl.Id = rubric_template_id + JOIN + " . PREFIX . "_rubric_permissions AS prm + ON doc.rubric_id = prm.rubric_id + WHERE + user_group_id = '" . $user_group . "' + AND + doc.Id = '" . $page_not_found_id . "' + LIMIT 1 + ")->FetchRow(); + + return (isset($this->curentdoc->Id) && $this->curentdoc->Id == $page_not_found_id); + } + + /** + * Метод, предназначенный для получения МЕТА-тегов для различных модулей. + * ToDo + * @return boolean + */ + function _coreModuleMetatagsFetch() + { + global $AVE_DB; + + // Если в запросе не пришел параметр module, заврешаем работу + if (! isset($_REQUEST['module'])) + return false; + + $this->curentdoc = $AVE_DB->Query(" + SELECT + 1 AS Id, + 0 AS document_published, + document_meta_robots, + document_meta_keywords, + document_meta_description, + document_title + FROM + " . PREFIX . "_documents + WHERE + Id = 1 + ")->FetchRow(); + + return (isset($this->curentdoc->Id) && $this->curentdoc->Id == 1); + } + + /** + * Метод, предназначенный для определения статуса документа (доступен ли он к публикации). + * + * @return int/boolean + */ + function _coreDocumentIsPublished() + { + //Контроль даты: Использовать/Не использовать + if (get_settings('use_doctime') != 0) + { + if (!empty ($this->curentdoc) // документ есть + && $this->curentdoc->Id != PAGE_NOT_FOUND_ID // документ не сообщение ошибки 404 + && $this->curentdoc->document_deleted == 1 // пометка удаления + ) + { + // Если пользователь авторизован в Панели управления или имеет полные права на просмотр документа, тогда + if (isset ($_SESSION['adminpanel']) || isset ($_SESSION['alles'])) + { + // Отображаем информационное окно с сообщением, определенным в свойстве _doc_not_published + display_notice($this->_doc_not_published); + } + else // В противном случае фиксируем ошибку + { + $this->curentdoc = false; + } + } + } + else + { + if (! empty($this->curentdoc) // документ есть + && $this->curentdoc->Id != PAGE_NOT_FOUND_ID // документ не сообщение ошибки 404 + && $this->curentdoc->document_deleted == 1 // пометка удаления + ) + { + // Если пользователь авторизован в Панели управления или имеет полные права на просмотр документа, тогда + if (isset ($_SESSION['adminpanel']) || isset ($_SESSION['alles'])) + { + // Отображаем информационное окно с сообщением, определенным в свойстве _doc_not_published + display_notice($this->_doc_not_published); + } + else // В противном случае фиксируем ошибку + { + $this->curentdoc = false; + } + } + } + return (! empty($this->curentdoc)); + } + + /** + * Метод парсинга тега [tag:(css|js):files] + * для вывода css/js-файлов в шаблоне через combine.php + * + * @param array $tag параметры тега + * @return string что выводить в шаблоне + */ + function _parse_combine($tag) + { + // тип тега (css|js) + $type = $tag[1]; + // имена файлов + $files = explode(',',$tag[2]); + + // определяем путь. если указан - то считаем от корня, если нет, то в /[tag:mediapath]/css|js/ + if ($tag[3]) + { + $path = '/' . trim($tag[3],'/') . '/'; + } + else + { + $path = '/templates/' . THEME_FOLDER . '/' . $type . '/'; + } + + // уровень вложенности + $level = substr_count($path,'/') - 1; + + // копируем combine.php, если он поменялся или отсутствует + $dest_stat = stat(BASE_DIR . $path . 'combine.php'); + $source_stat = stat(BASE_DIR . '/lib/combine/combine.php'); + + if (! file_exists(BASE_DIR . $path . 'combine.php') || $source_stat[9] > $dest_stat[9]) + { + @copy(BASE_DIR . '/lib/combine/combine.php', BASE_DIR . $path . 'combine.php'); + } + + // удаляем из списка отсутствующие файлы + foreach($files as $key=>$file) + { + if (! file_exists(BASE_DIR . $path . $file)) + unset($files[$key]); + } + + if ($files) + { + $combine = $path . 'combine.php?level=' . $level . '&' . $type . '=' . implode(',', $files); + $combine = @str_replace('//','/',$combine); + } + + return $combine; + } + + + /** + * @param $main_content + * @param $id + * @param $rubTmpl + * + * @return mixed|null|string|string[] + */ + function _main_content ($rubTmpl) + { + Debug::startTime('MAINCONTENT'); + + // Проверяем теги полей в шаблоне рубрики на условие != '' + if (defined('USE_GET_FIELDS') && USE_GET_FIELDS) + { + $main_content = preg_replace("/\[tag:if_notempty:fld:([a-zA-Z0-9-_]+)\]/u", '<'.'?php if((htmlspecialchars(get_field(\'$1\'), ENT_QUOTES)) != \'\') { '.'?'.'>', $rubTmpl); + $main_content = preg_replace("/\[tag:if_empty:fld:([a-zA-Z0-9-_]+)\]/u", '<'.'?php if((htmlspecialchars(get_field(\'$1\'), ENT_QUOTES)) == \'\') { '.'?'.'>', $main_content); + } + else + { + $main_content = preg_replace("/\[tag:if_notempty:fld:([a-zA-Z0-9-_]+)\]/u", '<'.'?php if((htmlspecialchars(document_get_field(\'$1\'), ENT_QUOTES)) != \'\') { '.'?'.'>', $rubTmpl); + $main_content = preg_replace("/\[tag:if_empty:fld:([a-zA-Z0-9-_]+)\]/u", '<'.'?php if((htmlspecialchars(document_get_field(\'$1\'), ENT_QUOTES)) == \'\') { '.'?'.'>', $main_content); + } + + $main_content = str_replace('[tag:if:else]', '', $main_content); + $main_content = str_replace('[tag:/if]', '', $main_content); + + // Парсим элементы полей + $main_content = preg_replace_callback( + '/\[tag:fld:([a-zA-Z0-9-_]+)\]\[([0-9]+)]\[([0-9]+)]/', + function($m) + { + return get_field_element($m[1], $m[2], $m[3], $this->curentdoc->Id); + }, + $main_content + ); + + // Парсим теги полей документа в шаблоне рубрики + $main_content = preg_replace_callback('/\[tag:fld:([a-zA-Z0-9-_]+)(|[:(\d)])+?\]/', 'document_get_field', $main_content); + + // Повторно парсим элементы полей + $main_content = preg_replace_callback( + '/\[tag:fld:([a-zA-Z0-9-_]+)\]\[([0-9]+)]\[([0-9]+)]/', + function($m) + { + return get_field_element($m[1], $m[2], $m[3], $this->curentdoc->Id); + }, + $main_content + ); + + // Повторно парсим теги полей документа в шаблоне рубрики + $main_content = preg_replace_callback('/\[tag:fld:([a-zA-Z0-9-_]+)(|[:(\d)])+?\]/', 'document_get_field', $main_content); + + // Watermarks + $main_content = preg_replace_callback('/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', 'watermarks', $main_content); + + // Thumbnail + $main_content = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $main_content); + + // Возвращаем поле из БД документа + $main_content = preg_replace_callback('/\[tag:doc:([a-zA-Z0-9-_]+)\]/u', + function ($match) + { + return isset($this->curentdoc->{$match[1]}) + ? $this->curentdoc->{$match[1]} + : null; + }, + $main_content + ); + + // Если пришел вызов на активацию языковых файлов + $main_content = preg_replace_callback( + '/\[tag:langfile:([a-zA-Z0-9-_]+)\]/u', + function ($match) + { + global $AVE_Template; + + return $AVE_Template->get_config_vars($match[1]); + }, + $main_content + ); + + // парсим теги в шаблоне рубрики + $main_content = preg_replace_callback( + '/\[tag:date:([a-zA-Z0-9-. \/]+)\]/', + function ($match) + { + return translate_date(date($match[1], $this->curentdoc->document_published)); + }, + $main_content + ); + + // GetField + $main_content = preg_replace_callback( + '/\[tag:get:([a-zA-Z0-9-_]+)(|:([0-9]+))+?\]/', + function ($match) { + return get_field($match[1], $match[3]); + }, + $main_content + ); + + // GetDocumentsField + $main_content = preg_replace_callback( + '/\[tag:docs:([0-9]+)(|:([a-zA-Z0-9-_]+))+?\]/', + function ($match) { + return get_document($match[1], $match[3]); + }, + $main_content + ); + + $main_content = str_replace('[tag:docdate]', translate_date(strftime(DATE_FORMAT, $this->curentdoc->document_published)), $main_content); + $main_content = str_replace('[tag:doctime]', translate_date(strftime(TIME_FORMAT, $this->curentdoc->document_published)), $main_content); + $main_content = str_replace('[tag:humandate]', human_date($this->curentdoc->document_published), $main_content); + $main_content = str_replace('[tag:docauthorid]', $this->curentdoc->document_author_id, $main_content); + + if (preg_match('[tag:docauthor]', $main_content)) + $main_content = str_replace('[tag:docauthor]', get_username_by_id($this->curentdoc->document_author_id), $main_content); + + // Удаляем ошибочные теги полей документа в шаблоне рубрики + $main_content = preg_replace('/\[tag:watermark:\w*\]/', '', $main_content); + $main_content = preg_replace('/\[tag:fld:\w*\]/', '', $main_content); + $main_content = preg_replace('/\[tag:doc:\w*\]/', '', $main_content); + $main_content = preg_replace('/\[tag:langfile:\w*\]/', '', $main_content); + + //-- Кеширование скомпилированного документа + $this->setCompileDocument($main_content); + + $GLOBALS['block_generate']['DOCUMENT']['MAINCONTENT'] = Debug::endTime('MAINCONTENT'); + + return $main_content; + } + + + /** + * Метод, предназначенный для формирования хэша страницы + * + * @return string + */ + function _get_cache_hash () + { + $hash = 'g-' . UGROUP; // Группа пользователей + $hash .= 'r-' . RUB_ID; // ID Рубрики + $hash .= 't-' . $this->curentdoc->rubric_tmpl_id; // Шаблон рубрики + //$hash .= 'u-' . get_redirect_link(); // ToDo + + return md5($hash); + } + + + /** + * Получаем ID для кеша документа + * + * @return array|bool + */ + function _get_cache_id () + { + $cache = []; + + $cache['id'] = (int)$this->curentdoc->Id; + + if (! $cache['id']) + return false; + + $cache['id'] = (int)$cache['id']; + $cache['dir'] = 'documents/' . (floor($cache['id'] / 1000)) . '/' . $cache['id']; + + $cache['compile_id'] = 'compile/' . (floor($cache['id'] / 1000)) . '/' . $cache['id']; + + $cache['file'] = $this->_get_cache_hash() . '.compiled'; + $cache['compile_file'] = $this->_get_cache_hash() . '.php'; + + if (! $cache['file']) + return false; + + $cache['dir'] = BASE_DIR . '/tmp/cache/sql/' . (trim($cache['dir']) > '' + ? trim($cache['dir']) . '/' + : substr($cache['file'], 0, 2) . '/' . substr($cache['file'], 2, 2) . '/' . substr($cache['file'], 4, 2) . '/'); + + $cache['compile_dir'] = BASE_DIR . '/tmp/cache/sql/' . (trim($cache['compile_id']) > '' + ? trim($cache['compile_id']) . '/' + : substr($cache['file'], 0, 2) . '/' . substr($cache['file'], 2, 2) . '/' . substr($cache['file'], 4, 2) . '/'); + + return $cache; + } + + + /** + * Создаем компилированный документ + * + * @param $main_content + * + * @return bool + */ + function setCompileDocument ($main_content) + { + $cache = $this->_get_cache_id(); + + if (! $cache) + return false; + + //-- Удаляем файл, если существует + if (file_exists($cache['dir'] . $cache['file'])) + unlink($cache['dir'] . $cache['file']); + + // Если включен DEV MODE, то отключаем кеширование запросов + if (defined('DEV_MODE') AND DEV_MODE) + return false; + + //-- Кэширование разрешено + if (defined('CACHE_DOC_TPL') && CACHE_DOC_TPL) + { + //-- Если нет папки, создаем + if (! is_dir($cache['dir'])) + @mkdir($cache['dir'], 0766, true); + + //-- Сохраняем скомпилированный шаблон в кэш + file_put_contents($cache['dir'] . $cache['file'], $main_content); + } + + return true; + } + + + /** + * Получаем скомпилированный документ + * + * @return bool|string + */ + function getCompileDocument () + { + $cache = $this->_get_cache_id(); + + if (! $cache) + return false; + + $content = false; + + //-- Если нет папки, создаем + if (! is_dir($cache['dir'])) + @mkdir($cache['dir'], 0766, true); + + //-- Получаем сразу поля + get_document_fields((int)$this->curentdoc->Id); + + // Наличие файла + if (file_exists($cache['dir'] . $cache['file'])) + { + // Получаем время создания файла + $file_time = filemtime($cache['dir'] . $cache['file']); + + // Получаем время для проверки + $cache_time = $this->curentdoc->rubric_changed; + + if (! $cache_time || $cache_time > $file_time) + { + unlink ($cache['dir'] . $cache['file']); + } + else if (defined('CACHE_DOC_TPL') && CACHE_DOC_TPL) + // Извлекаем скомпилированный шаблон документа из кэша + $content = file_get_contents($cache['dir'] . $cache['file']); + } + else + { + $content = false; + } + + return $content; + } + + + function checkAcceptCache () + { + $isAjax = isAjax(); + $page = get_current_page(); + $array = ['module', 'sysblock', 'request', 'page', 'apage', 'artpage']; + + foreach ($array AS $k => $v) + { + if (in_array($v, $_REQUEST)) + return false; + } + + if ( ($isAjax == true) || ($page != 1) ) + return false; + + return true; + } + + + function setCompileContent ($content) + { + $cache = $this->_get_cache_id(); + + if (! $cache) + return false; + + //-- Удаляем файл, если существует + if (file_exists($cache['compile_dir'] . $cache['file'])) + unlink($cache['compile_dir'] . $cache['file']); + + if ($this->checkAcceptCache() == false) + return false; + + // Если включен DEV MODE, то отключаем кеширование запросов + if (defined('DEV_MODE') AND DEV_MODE) + return false; + + if (UGROUP == 1 && (defined('CACHE_DOC_FULL_ADMIN') && CACHE_DOC_FULL_ADMIN == false)) + return false; + + //-- Кэширование разрешено + if (defined('CACHE_DOC_FULL') && CACHE_DOC_FULL) + { + //-- Если нет папки, создаем + if (! is_dir($cache['compile_dir'])) + @mkdir($cache['compile_dir'], 0766, true); + + //-- Сохраняем скомпилированный шаблон в кэш + file_put_contents($cache['compile_dir'] . $cache['compile_file'], $content); + + $GLOBALS['block_generate']['COMPILE']['SET'] = true; + } + + return true; + } + + + function getCompileContent () + { + if ($this->checkAcceptCache() == false) + return false; + + $cache = $this->_get_cache_id(); + + if (! $cache) + return false; + + $content = false; + + //-- Если нет папки, создаем + if (! is_dir($cache['compile_dir'])) + @mkdir($cache['compile_dir'], 0766, true); + + // Наличие файла + if (file_exists($cache['compile_dir'] . $cache['compile_file'])) + { + // Получаем время создания файла + $file_time = filemtime($cache['compile_dir'] . $cache['compile_file']); + + // Получаем время для проверки + $cache_time = $this->curentdoc->rubric_changed; + + if (! $cache_time || $cache_time > $file_time) + { + unlink ($cache['compile_dir'] . $cache['compile_file']); + } + else if (defined('CACHE_DOC_FULL') && CACHE_DOC_FULL) + { + $content = file_get_contents($cache['compile_dir'] . $cache['compile_file']); + + $GLOBALS['block_generate']['COMPILE']['GET'] = true; + } + } + else + { + $content = false; + } + + return $content; + } + + + /** + * Метод, предназначенный для обработки системных тегов модулей. Здесь подключаются только те файлы модулей, + * системные теги которых обнаружены в шаблоне при парсинге. Также формирует массив всех установленных модулей + * в системе, предварительно проверяя их доступность. + * + * @param string $template текст шаблона с тегами + * @return string текст шаблона с обработанными тегами модулей + */ + function coreModuleTagParse($template) + { + global $AVE_DB, $AVE_Template, $AVE_Module; + + Debug::startTime('MODULES_PARSE'); + + $pattern = []; // Массив системных тегов + $replace = []; // Массив функций, на которые будут заменены системные теги + + if (null !== $AVE_Module->moduleListGet()) + $this->install_modules = $AVE_Module->moduleListGet(); + + // Если уже имеются данные об установленных модулях + if (null !== $this->install_modules) + { + // Циклически обрабатываем каждый модуль + foreach ($this->install_modules as $row) + { + if ($row['ModuleStatus'] != 1) + continue; + + // Если в запросе пришел вызов модуля или у модуля есть функция вызываемая тегом, + // который присутствует в шаблоне + if ( + (isset($_REQUEST['module']) && $_REQUEST['module'] == $row['ModuleSysName']) + || + ( + 1 == $row['ModuleIsFunction'] + && + (isset($row['ModuleAveTag']) && !empty($row['ModuleAveTag'])) + && + 1 == @preg_match($row['ModuleAveTag'], $template) + ) + ) + { + // Проверяем, существует ли для данного модуля функция. Если да, + // получаем php код функции. + if (function_exists($row['ModuleFunction'])) + { + $pattern[] = $row['ModuleAveTag']; + $replace[] = $row['ModulePHPTag']; + } + else // В противном случае + { + // Проверяем, существует ли для данного модуля файл module.php в его персональной директории + $mod_file = BASE_DIR . '/modules/' . $row['ModuleSysName'] . '/module.php'; + + if (is_file($mod_file) && include_once($mod_file)) + { + // Если файл модуля найден, тогда + if ($row['ModuleAveTag']) + { + $pattern[] = $row['ModuleAveTag']; // Получаем его системный тег + + // Проверяем, существует ли для данного модуля функция. Если да, + // получаем php код функции, в противном случае формируем сообщение с ошибкой + $replace[] = function_exists($row['ModuleFunction']) + ? $row['ModulePHPTag'] + : ($this->_module_error . ' "' . $row['ModuleName'] . '"'); + } + } + // Если файла module.php не существует, формируем сообщение с ошибкой + elseif ($row['ModuleAveTag']) + { $pattern[] = $row['ModuleAveTag']; + $replace[] = $this->_module_error . ' "' . $row['ModuleName'] . '"'; + } + } + } + } + + $GLOBALS['block_generate']['DOCUMENT']['MODULES'] = Debug::endTime('MODULES_PARSE'); + + // Выполняем замену систеного тега на php код и возвращаем результат + return preg_replace($pattern, $replace, $template); + } + else // В противном случае, если список модулей пустой + { + $this->install_modules = array(); + + // Выполняем запрос к БД на получение информации о всех модулях, которые установлены в системе + // (именно установлены, а не просто существуют в виде папок) + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX. "_module + WHERE + ModuleStatus = '1' + "); + + // Циклически обрабатываем полученные данные + while ($row = $sql->FetchRow()) + { + // Если в запросе пришел параметр module и для данного названия модуля существует + // директория или данный модуль имеет функцию и его системный тег указан в каком-либо шаблоне, тогда + if ((isset($_REQUEST['module']) && $_REQUEST['module'] == $row->ModuleSysName) || + (1 == $row->ModuleIsFunction && ! empty($row->ModuleAveTag) && 1 == preg_match($row->ModuleAveTag, $template))) + { + // Проверяем, существует ли для данного модуля файл module.php в его персональной директории + $mod_file = BASE_DIR . '/modules/' . $row->ModuleSysName . '/module.php'; + + if (is_file($mod_file) && include_once($mod_file)) + { // Если файл модуля найден, тогда + if (! empty($row->ModuleAveTag)) + { + $pattern[] = $row->ModuleAveTag; // Получаем его системный тег + + // Проверяем, существует ли для данного модуля функция. Если да, + // получаем php код функции, в противном случае формируем сообщение с ошибкой + $replace[] = function_exists($row->ModuleFunction) + ? $row->ModulePHPTag + : ($this->_module_error . ' "' . $row->ModuleSysName . '"'); + } + // Сохряняем информацию о модуле + $this->install_modules[$row->ModuleSysName] = $row; + } + elseif ($row->ModuleAveTag) // Если файла module.php не существует, формируем сообщение с ошибкой + { + $pattern[] = $row->ModuleAveTag; + $replace[] = $this->_module_error . ' "' . $row->ModuleSysName . '"'; + } + } + else + { // Если у модуля нет функции или тег модуля не используется - просто помещаем в массив информацию о модуле + $this->install_modules[$row->ModuleSysName] = $row; + } + } + + $GLOBALS['block_generate']['DOCUMENT']['MODULES'] = Debug::endTime('MODULES_PARSE'); + + // Выполняем замену систеного тега на php код и возвращаем результат + return preg_replace($pattern, $replace, $template); + } + } + + /** + * Метод, предназанченный для сборки всей страницы в единое целое. + * + * @param int $id идентификатор документа + * @param int $rub_id идентификатор рубрики + */ + function coreSiteFetch ($id, $rub_id = '') + { + global $AVE_DB, $AVE_Module; + + Debug::startTime('DOC_' . $id); + + $cacheCompile = false; + + // Определяем рубрику + define('RUB_ID', ! empty ($rub_id) + ? $rub_id + : $this->curentdoc->rubric_id); + + $main_content = ''; + + if ((defined('CACHE_DOC_FULL') && CACHE_DOC_FULL) && isAjax() == false) + { + if ($out = $this->getCompileContent()) + { + foreach ($AVE_Module->moduleListGet() as $row) + { + // Проверяем, существует ли для данного модуля файл module.php в его персональной директории + $mod_file = BASE_DIR . '/modules/' . $row['ModuleSysName'] . '/module.php'; + + if (is_file($mod_file)) + include_once($mod_file); + } + + $this->_coreRubricPermissionFetch(RUB_ID); + + // Выполняем Код рубрики До загрузки документа + ob_start(); + eval(' ?>' . $this->curentdoc->rubric_start_code . '_coreModuleMetatagsFetch(); + $out = $this->_coreDocumentTemplateGet('', '', $this->_coreModuleTemplateGet()); + } + // Если происходит вызов системного блока + elseif (isset($_REQUEST['sysblock']) && ! empty($_REQUEST['sysblock'])) + { + if (! is_numeric($_REQUEST['sysblock']) && preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $_REQUEST['sysblock']) !== 1) + { + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true); + exit; + } + + // проверяем разрешение на внешнее обращение + if (! _getSysBlock($_REQUEST['sysblock'], 'sysblock_external')) + { + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true); + exit; + } + + // проверяем разрешение на обращение только по Ajax + if (_getSysBlock($_REQUEST['sysblock'], 'sysblock_ajax')) + { + if (isAjax()) + $out = parse_sysblock($_REQUEST['sysblock']); + else + $this->_coreErrorPage404(); + } + else + { + $out = parse_sysblock($_REQUEST['sysblock']); + } + } + // Если происходит вызов запроса + elseif (isset($_REQUEST['request']) && ! empty($_REQUEST['request'])) + { + if (! is_numeric($_REQUEST['request']) && preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $_REQUEST['request']) !== 1) + $this->_coreErrorPage404(); + + // Проверяем разрешение на внешнее обращение + if (! $this->_requestGet($_REQUEST['request'], 'request_external')) + $this->_coreErrorPage404(); + + // Проверяем разрешение на обращение только по Ajax + if ($this->_requestGet($_REQUEST['request'], 'request_ajax')) + { + if (isAjax()) + $out = request_parse($_REQUEST['request']); + else + $this->_coreErrorPage404(); + } + else + { + $out = request_parse($_REQUEST['request']); + } + } + // В противном случае начинаем вывод документа + else + { + if (! isset($this->curentdoc->Id) && ! $this->_coreCurrentDocumentFetch($id, UGROUP)) + { + // Определяем документ с 404 ошибкой в случае, если документ не найден + if ($this->_corePageNotFoundFetch(PAGE_NOT_FOUND_ID, UGROUP)) + $_REQUEST['id'] = $_GET['id'] = $id = PAGE_NOT_FOUND_ID; + } + + // проверяем параметры публикации документа + if (! $this->_coreDocumentIsPublished()) + $this->_coreErrorPage404(); + + $this->_coreRubricPermissionFetch(RUB_ID); + + // Выполняем Код рубрики До загрузки документа + ob_start(); + eval(' ?>' . $this->curentdoc->rubric_start_code . '_coreDocumentTemplateGet(RUB_ID, null, null, $this->curentdoc->rubric_template_id); + + if (! ((isset ($_SESSION[RUB_ID . '_docread']) && $_SESSION[RUB_ID . '_docread'] == 1) + || (isset ($_SESSION[RUB_ID . '_alles']) && $_SESSION[RUB_ID . '_alles'] == 1)) ) + { // читать запрещено - извлекаем ругательство и отдаём вместо контента + $main_content = get_settings('message_forbidden'); + } + else + { + if (isset ($_REQUEST['print']) && $_REQUEST['print'] == 1) + { // Увеличиваем счетчик версий для печати + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_count_print = document_count_print + 1 + WHERE + Id = '" . $id . "' + "); + } + else + { + if (! isset ($_SESSION['doc_view'][$id])) + { // Увеличиваем счетчик просмотров (1 раз в пределах сессии) + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_count_view = document_count_view + 1 + WHERE + Id = '" . $id . "' + "); + + $_SESSION['doc_view'][$id] = time(); + } + + $curdate = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + + if (! isset($_SESSION['doc_view_dayly['.$curdate.'][' . $id . ']'])) + { + // и подневный счетчик просмотров тоже увеличиваем + $curdate = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_view_count + SET + count = count + 1 + WHERE + document_id = '" . $id . "' AND + day_id = '".$curdate."' + "); + + if (! $AVE_DB->getAffectedRows()) + { + $AVE_DB->Query(" + INSERT INTO " . PREFIX . "_view_count ( + document_id, + day_id, + count + ) + VALUES ( + '" . $id . "', '".$curdate."', '1' + ) + "); + } + + $_SESSION['doc_view_dayly['.$curdate.'][' . $id . ']'] = time(); + } + } + + // Извлекаем скомпилированный шаблон документа из кэша + if (defined('CACHE_DOC_TPL') && CACHE_DOC_TPL) // && empty ($_POST) + $main_content = $this->getCompileDocument(); + else + // Кэширование запрещено + $main_content = false; + + // Собираем контент + // Если в кеше нет контента, то + if (empty($main_content)) + { + // Кэш пустой или отключен, извлекаем и компилируем шаблон + if (! empty ($this->curentdoc->rubric_template)) + { + $rubTmpl = $this->curentdoc->rubric_template; + } + else + { + // Если документу задан другой шаблон из данной рубрики, то берем его + if ($this->curentdoc->rubric_tmpl_id != 0) + { + $rubTmpl = $AVE_DB->Query(" + SELECT + template + FROM + " . PREFIX . "_rubric_templates + WHERE + id = '" . $this->curentdoc->rubric_tmpl_id . "' + AND + rubric_id = '" . RUB_ID . "' + LIMIT 1 + ")->GetCell(); + } + // Иначе берем стандартный шаблон рубрики + else + { + $rubTmpl = $AVE_DB->Query(" + SELECT + rubric_template + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . RUB_ID . "' + LIMIT 1 + ")->GetCell(); + } + } + + $rubTmpl = trim($rubTmpl); + + // Собираем шаблон рубрики + if (empty($rubTmpl)) + // Если не задан шаблон рубрики, выводим сообщение + $main_content = $this->_rubric_template_empty; + else + // Обрабатываем основные поля рубрики + $main_content = $this->_main_content($rubTmpl); + } + } + + $out = str_replace('[tag:maincontent]', $main_content, $out); + + unset ($this->curentdoc->rubric_template, $this->curentdoc->template); + } + //-- Конец вывода документа + + //Работа с условиями + /* + $out = preg_replace('/\[tag:if_exp:?(.*)\]/u', '', $out); + $out = str_replace('[tag:if_exp_else]', '', $out); + $out = str_replace('[tag:/if_exp]', '', $out); + + */ + + // Тут мы вводим в хеадер и футер иньекцию скриптов. + if (defined('RUB_ID')) + { + $replace = [ + '[tag:rubheader]' => $this->curentdoc->rubric_header_template, + '[tag:rubfooter]' => $this->curentdoc->rubric_footer_template + ]; + + $out = str_replace(array_keys($replace), array_values($replace), $out); + + unset ($replace); + } + + // Парсим поля запроса + $out = preg_replace_callback('/\[tag:rfld:([a-zA-Z0-9-_]+)]\[(more|esc|img|[0-9-]+)]/', + function ($m) use ($id) + { + return request_get_document_field($m[1], $id, $m[2], (defined('RUB_ID') ? RUB_ID : 0)); + }, + $out + ); + + // Удаляем ошибочные теги полей документа в шаблоне рубрики + $out = preg_replace('/\[tag:rfld:\w*\]/', '', $out); + + // Если в GET запросе пришел параметр print, т.е. страница для печати, + // парсим контент, который обрамлен тегами только для печати + if (isset ($_REQUEST['print']) && $_REQUEST['print'] == 1) + { + $out = str_replace(array('[tag:if_print]', '[/tag:if_print]'), '', $out); + $out = preg_replace('/\[tag:if_notprint\](.*?)\[\/tag:if_notprint\]/si', '', $out); + } + else + { + // В противном случае наоборот, парсим только тот контент, который предназначен НЕ для печати + $out = preg_replace('/\[tag:if_print\](.*?)\[\/tag:if_print\]/si', '', $out); + $out = str_replace(array('[tag:if_notprint]', '[/tag:if_notprint]'), '', $out); + } + + // Парсим теги визуальных блоков + $out = preg_replace_callback('/\[tag:block:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_block', $out); + + // Парсим теги системных блоков + $out = preg_replace_callback('/\[tag:sysblock:([A-Za-z0-9-_]{1,20}+)(|:\{(.*?)\})\]/', + function ($m) + { + return parse_sysblock($m[1], $m[2]); + }, + $out); + + // Парсим тизер документа + $out = preg_replace_callback('/\[tag:teaser:(\d+)(|:\[(.*?)\])\]/', + function ($m) + { + return showteaser($m[1], $m[2]); + }, + $out + ); + + // Парсим теги модулей + $out = $this->coreModuleTagParse($out); + + // Если в запросе пришел параметр module, т.е. вызов модуля, + // проверяем установлен и активен ли модуль + if (isset($_REQUEST['module']) && ! $this->_getRequestModule($_REQUEST['module'])) + display_notice($this->_module_error . ' "' . $_REQUEST['module'] . '"'); // Выводим сообщение о том что такого модуля нет + + // Парсим теги системы внутренних запросов + $out = preg_replace_callback('/\[tag:request:([A-Za-z0-9-_]{1,20}+)\]/', 'request_parse', $out); + + // Парсим теги навигации + $out = preg_replace_callback('/\[tag:navigation:([A-Za-z0-9-_]{1,20}+):?([0-9,]*)\]/', 'parse_navigation', $out); + + // Парсим теги скрытого текста + $out = parse_hide($out); + + // Если в запросе пришел параметр sysblock, т.е. вызов сис блока, + // парсим контент + if (isset($_REQUEST['sysblock']) && $_REQUEST['sysblock'] != '') + { + $search = array( + '[tag:mediapath]', + '[tag:path]', + '[tag:sitename]', + '[tag:home]', + '[tag:docid]', + '[tag:docparent]' + ); + + $replace = array( + ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', + ABS_PATH, + htmlspecialchars(get_settings('site_name'), ENT_QUOTES), + get_home_link(), + (isset ($this->curentdoc->Id) ? $this->curentdoc->Id : ''), + (isset ($this->curentdoc->document_parent) ? $this->curentdoc->document_parent : '') + ); + } + // Если в запросе пришел параметр request, т.е. вызов запроса, + // парсим контент + elseif (isset($_REQUEST['request']) && $_REQUEST['request'] != '') + { + $search = array( + '[tag:mediapath]', + '[tag:path]', + '[tag:sitename]', + '[tag:home]', + '[tag:docid]', + '[tag:docparent]' + ); + + $replace = array( + ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', + ABS_PATH, + htmlspecialchars(get_settings('site_name'), ENT_QUOTES), + get_home_link(), + (isset ($this->curentdoc->Id) ? $this->curentdoc->Id : ''), + (isset ($this->curentdoc->document_parent) ? $this->curentdoc->document_parent : '') + ); + } + else + { + // В противном случае + // парсим остальные теги основного шаблона + $search = array( + '[tag:mediapath]', + '[tag:path]', + '[tag:sitename]', + '[tag:alias]', + '[tag:domain]', + '[tag:home]', + '[tag:robots]', + '[tag:canonical]', + '[tag:docid]', + '[tag:docparent]' + ); + + $replace = array( + ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', + ABS_PATH, + htmlspecialchars(get_settings('site_name'), ENT_QUOTES), + (isset($_REQUEST['id'])) ? isset ($this->curentdoc->document_alias) ? $this->curentdoc->document_alias : '' : '', + getSiteUrl(), + get_home_link(), + (isset($this->curentdoc->document_meta_robots) ? $this->curentdoc->document_meta_robots : ''), + canonical(isset ($this->curentdoc->document_alias) ? getSiteUrl() . str_replace('//', '/', ABS_PATH . $this->curentdoc->document_alias) : ''), + (isset($this->curentdoc->Id) ? $this->curentdoc->Id : ''), + (isset($this->curentdoc->document_parent) ? $this->curentdoc->document_parent : '') + ); + } + + // Если пришел контент из модуля + if (defined('MODULE_CONTENT')) + { + // парсинг тегов при выводе из модуля + $search[] = '[tag:maincontent]'; + $replace[] = MODULE_CONTENT; + $search[] = '[tag:title]'; + $replace[] = htmlspecialchars(defined('MODULE_TITLE') ? MODULE_TITLE : '', ENT_QUOTES); + $search[] = '[tag:description]'; + $replace[] = htmlspecialchars(defined('MODULE_DESCRIPTION') ? MODULE_DESCRIPTION : '', ENT_QUOTES); + $search[] = '[tag:keywords]'; + $replace[] = htmlspecialchars(defined('MODULE_KEYWORDS') ? MODULE_KEYWORDS : '', ENT_QUOTES); + } + // Или из системного блока + elseif (isset($_REQUEST['sysblock'])) + { + // Убираем пустые теги в сис блоке + $main_content = preg_replace('/\[tag:(.+?)\]/', '', $main_content); + $main_content = preg_replace('/\[mod_(.+?)\]/', '', $main_content); + } + // Или из запроса + elseif (isset($_REQUEST['request'])) + { + // Убираем пустые теги в запросе + $main_content = preg_replace('/\[tag:(.+?)\]/', '', $main_content); + $main_content = preg_replace('/\[mod_(.+?)\]/', '', $main_content); + } + // Иначе + else + { + // Если стоит вкл на генерацию keywords, description + if ($this->curentdoc->rubric_meta_gen) + { + // Генерируем keywords, description на основе + // данных документа, если позволяет рубрика + require_once(dirname(__FILE__).'/class.meta.php'); + $meta = new Meta(); + $res = $meta->generateMeta($main_content); + } + + // Убираем пустые теги + $main_content = preg_replace('/\[tag:(.+?)\]/', '', $main_content); + $main_content = preg_replace('/\[mod_(.+?)\]/', '', $main_content); + + // Парсим keywords, description, title + $search[] = '[tag:keywords]'; + $replace[] = stripslashes(htmlspecialchars((! empty ($this->curentdoc->rubric_meta_gen) ? $res['keywords'] : $this->curentdoc->document_meta_keywords), ENT_QUOTES)); + $search[] = '[tag:description]'; + $replace[] = stripslashes(htmlspecialchars((! empty ($this->curentdoc->rubric_meta_gen) ? $res['description'] : $this->curentdoc->document_meta_description), ENT_QUOTES)); + $search[] = '[tag:title]'; + $replace[] = stripslashes(htmlspecialchars_decode(pretty_chars($this->curentdoc->document_title))); + } + + // Возвращаем поле из БД документа + $out = preg_replace_callback('/\[tag:doc:([a-zA-Z0-9-_]+)\]/u', + function ($match) + { + return isset($this->curentdoc->{$match[1]}) + ? $this->curentdoc->{$match[1]} + : null; + }, + $out + ); + + // Если пришел вызов на активацию языковых файлов + $out = preg_replace_callback( + '/\[tag:langfile:([a-zA-Z0-9-_]+)\]/u', + function ($match) + { + global $AVE_Template; + + return $AVE_Template->get_config_vars($match[1]); + }, + $out + ); + + // Убираем пустые теги + $out = preg_replace('/\[tag:doc:\d*\]/', '', $out); + $out = preg_replace('/\[tag:langfile:\d*\]/', '', $out); + + // Убираем дубликат + $search[] = '[tag:maincontent]'; + $replace[] = ''; + + // Парсим линк на версию для печати + $search[] = '[tag:printlink]'; + $replace[] = get_print_link(); + + // Парсим тег версии системы + $search[] = '[tag:version]'; + $replace[] = APP_NAME . ' v' . APP_VERSION ; + + // Парсим тег кол-ва просмотра данного документа + $search[] = '[tag:docviews]'; + $replace[] = isset ($this->curentdoc->document_count_view) ? $this->curentdoc->document_count_view : ''; + + // Парсим тизер документа + $out = preg_replace_callback('/\[tag:teaser:(\d+)(|:\[(.*?)\])\]/', + function ($m) + { + return showteaser($m[1], $m[2]); + }, + $out + ); + + // Парсим аватар автора документа + if (defined('RUB_ID')) + $out = preg_replace_callback('/\[tag:docauthoravatar:(\d+)\]/', + function ($m) + { + return getAvatar(intval($this->curentdoc->document_author_id), $m[1]); + }, + $out + ); + + // Парсим теги языковых условий + if (defined('RUB_ID')) + { + $out = preg_replace('/\[tag:lang:([a-zA-Z0-9-_]+)\]/', 'curentdoc->document_lang == "$1") { ?>', $out); + } + else + { + $out = preg_replace('/\[tag:lang:([a-zA-Z0-9-_]+)\]/', '', $out); + } + + $out = str_replace('[tag:/lang]', '', $out); + + // Парсим хлебные крошки + if (preg_match('/\[tag:breadcrumb]/u', $out)) + { + $out = preg_replace_callback('/\[tag:breadcrumb\]/', 'get_breadcrumb', $out); + } + + // Парсим остальные теги основного шаблона + $out = str_replace($search, $replace, $out); + + // Парсим теги для combine.php + $out = preg_replace_callback('/\[tag:(css|js):([^ :\/]+):?(\S+)*\]/', array($this, '_parse_combine'), $out); + + // ЧПУ + $out = str_ireplace('"//"','"/"', str_ireplace('///','/', rewrite_link($out))); + + unset ($search, $replace, $main_content); //Убираем данные + + $GLOBALS['block_generate']['DOCUMENT']['FETCH'] = Debug::endTime('DOC_' . $id); + + if ($cacheCompile == false) + { + $this->setCompileContent($out); + } + } + + // Выводим собранный документ + echo $out; + } + + /** + * Метод, предназначенный для формирования ЧПУ, а также для поиска документа и разбора + * дополнительных параметров в URL + * + * @param string $get_url Строка символов + * + */ + function coreUrlParse($get_url = '') + { + global $AVE_DB; + + Debug::startTime('URL_PARSE'); + + $document_id = null; + + $cache_time = 0; + + //-- Если нужны параметры GET, можно отключить + $get_url = (strpos($get_url, ABS_PATH . '?') === 0 + ? '' + : $get_url); + + if (substr($get_url, 0, strlen(ABS_PATH . 'index.php')) != ABS_PATH . 'index.php' AND strpos($get_url, '?') !== false) + $get_url = substr($get_url, 0, strpos($get_url, '?')); + + $get_url = rawurldecode($get_url); + $get_url = mb_substr($get_url, strlen(ABS_PATH)); + + //-- Сохранение старого урла для првоерки использования суффикса + $check_url = $get_url; + + if (mb_substr($get_url, - strlen(URL_SUFF)) == URL_SUFF) + { + $get_url = mb_substr($get_url, 0, - strlen(URL_SUFF)); + } + + //-- Ложный URL + $fake_url = false; + + //-- Разбиваем строку параметров на отдельные части + $get_url = explode('/', $get_url); + + if (isset ($get_url['index'])) + { + unset ($get_url['index']); + } + + if (isset ($get_url['print'])) + { + $_GET['print'] = $_REQUEST['print'] = 1; + unset ($get_url['print']); + } + + //-- Определяем, используется ли у нас разделение документа по страницам + $pages = preg_grep('/^(a|art)?page-\d+$/i', $get_url); + + if (! empty ($pages)) + { + $get_url = implode('/', array_diff($get_url, $pages)); + $pages = implode('/', $pages); + + preg_replace_callback('/(page|apage|artpage)-(\d+)/i', + function ($matches) + { + $_GET[$matches[1]] = $matches[2]; + $_REQUEST[$matches[1]] = $matches[2]; + }, + $pages); + } + //-- В противном случае формируем окончательную ссылку для документа + else + { + $get_url = implode('/', $get_url); + } + + //-- Страница тегов + preg_match('/^tags(|(\/.*))+$/is', $get_url, $match); + + //-- Если есть совпадение с tag + if ($match) + { + //-- Смотрим условие + if (isset($match[2])) + { + //-- Отрезаем лишнее + $matches = trim($match[2], '/'); + + //-- Разбиваем + $matches = explode('/', $matches); + + //-- Берем первое значение + $matches = urldecode(array_shift($matches)); + + //-- Если значение не равно пусто + if ($matches != '') + { + //-- Передаем в _GET условие tag + $_GET['tag'] = $_REQUEST['tag'] = $matches; + + //-- Парсим query strings + parse_str($_SERVER['QUERY_STRING'], $query_string); + + //-- Назначаем условие + $query_string['tag'] = $matches; + + //-- Пересобираем QUERY_STRING + $_SERVER['QUERY_STRING'] = http_build_query($query_string); + + //-- Назначаем URL + $get_url = 'tags'; + + //-- Инициализируем ложный URL + $fake_url = true; + } + } + } + + //-- Экранируем поступающий URL + $get_url = $AVE_DB->ClearUrl($get_url); + + //-- Заглушка для главной страницы + if ($get_url == '') + $get_url = '/'; + + //-- Проверяем есть ли данный URL в таблице алиасов модулей + $sql = " + SELECT + document_id, + module_name, + module_action, + module_link + FROM + " . PREFIX . "_modules_aliases + WHERE + module_url = '" . str_ireplace("'", "\'", $get_url) . "' + # MODULE LINK + "; + + $module = $AVE_DB->Query($sql)->FetchAssocArray(); + + //-- Если модуль есть, переназначаем URL и переменные + if ($module) + { + //-- Передаем глобальные перемененные + $_GET['module'] = $_REQUEST['module'] = $module['module_name']; + $_GET['action'] = $_REQUEST['action'] = $module['module_action']; + + $get_url = ABS_PATH . $module['module_link']; + + //-- Если есть document_id, назначем его + if ($module['document_id']) + $document_id = $_REQUEST['id'] = (int)$module['document_id']; + else + $document_id = $_REQUEST['id'] = 1; + } + + //-- УБираем лишнее + unset ($sql, $module); + + //-- Если пришел $_REQUEST['id'] документа, получаем URL для проверки + if (! empty($_REQUEST['id']) && is_numeric($_REQUEST['id'])) + { + $sql = " + SELECT + document_alias + FROM + " . PREFIX . "_documents + WHERE + Id = '" . intval($_REQUEST['id']) . "' + # FIND DOCID + "; + + $document_id = intval($_REQUEST['id']); + + $get_url = $AVE_DB->Query($sql)->GetCell(); + } + // Иначе пробуем получить ID по URL + else + { + $sql = " + SELECT + Id + FROM + " . PREFIX . "_documents + WHERE + document_alias = '" . str_ireplace("'", "\'", $get_url) . "' + # FIND DOCURL + "; + + $document_id = intval($AVE_DB->Query($sql)->GetCell()); + } + + //-- УБираем лишнее + unset ($sql); + + //-- Выполняем запрос к БД на получение всей необходимой + //-- информации о документе + $this->curentdoc = getDocument($document_id); + + if (defined('CACHE_DOC_FILE') && CACHE_DOC_FILE) + $cache_time = -1; + + // Если данные документа получены + if ($this->curentdoc) + { + // Получить шаблон рубрики + $sql = " + SELECT STRAIGHT_JOIN + prm.rubric_permission, + rub.rubric_template, + rub.rubric_meta_gen, + rub.rubric_template_id, + rub.rubric_header_template, + rub.rubric_footer_template, + rub.rubric_start_code, + rub.rubric_changed, + rub.rubric_changed_fields, + other.template + FROM + " . PREFIX . "_rubrics AS rub + LEFT JOIN + " . PREFIX . "_rubric_permissions AS prm + ON rub.Id = prm.rubric_id + LEFT JOIN + " . PREFIX . "_rubric_templates AS other + ON (rub.Id = other.rubric_id AND other.id = '" . $this->curentdoc->rubric_tmpl_id . "') + WHERE + prm.user_group_id = '" . UGROUP . "' + AND + rub.Id = '" . $this->curentdoc->rubric_id . "' + # FETCH RUB = " . $this->curentdoc->rubric_id . " + "; + + $query = $AVE_DB->Query($sql, $cache_time, 'rub_' . $this->curentdoc->rubric_id, true, '.rubric')->FetchRow(); + + $this->curentdoc = (object) array_merge((array) $query, (array) $this->curentdoc); + + if ($this->curentdoc->rubric_tmpl_id != 0) + { + $this->curentdoc->rubric_template = (($this->curentdoc->template != '') + ? $this->curentdoc->template + : $this->curentdoc->rubric_template); + + unset ($this->curentdoc->template); + } + + //-- Переназначем глобальные переменные + $_GET['id'] = $_REQUEST['id'] = $this->curentdoc->Id; + $_GET['doc'] = $_REQUEST['doc'] = $this->curentdoc->document_alias; + + //-- Назначаем язык пользователю, в завивисомтси от языка документа + if ($this->curentdoc->Id != PAGE_NOT_FOUND_ID OR $this->curentdoc->document_lang == '--') + $_SESSION['user_language'] = $this->curentdoc->document_lang; + + //-- Если есть ложный URL указываем его + if ($fake_url) + { + $check_url = preg_replace('/\/(a|art)?page-\d+/i', '', $check_url); + + $_GET['doc'] = $_REQUEST['doc'] = $check_url; + $this->curentdoc->document_alias = $check_url; + $get_url = $check_url; + } + + $GLOBALS['block_generate']['DOCUMENT']['URL_PARSE'] = Debug::endTime('URL_PARSE'); + + //-- Перенаправление на адреса с суффиксом + if ( + $check_url !== $get_url . URL_SUFF + && ! $pages && $check_url + && ! $_REQUEST['print'] + && ! $_REQUEST['module'] + && ! $_REQUEST['tag'] + && REWRITE_MODE + ) + { + header('HTTP/1.1 301 Moved Permanently'); + + if ($this->curentdoc->Id == 1) + header('Location:' . ABS_PATH); + else + header('Location:' . ABS_PATH . $get_url . URL_SUFF); + exit; + } + } + // Иначе ищем URL в редиректах + else + { + $sql = " + SELECT + # REDIRECT = $get_url + a.document_alias, + h.document_alias_header + FROM + ".PREFIX."_document_alias_history AS h, + ".PREFIX."_documents AS a + WHERE + h.document_id = a.Id + AND + h.document_alias = '" . $get_url . "' + "; + + $redirect_alias = $AVE_DB->Query($sql)->FetchRow(); + + $GLOBALS['block_generate']['DOCUMENT']['URL_PARSE'] = Debug::endTime('URL_PARSE'); + + if ($redirect_alias->document_alias && ! empty($redirect_alias->document_alias)) + { + $redirect_alias = ABS_PATH . $redirect_alias->document_alias . URL_SUFF; + $redirect_alias = str_replace('//', '/', $redirect_alias); + + header('Location:' . $redirect_alias, true, $redirect_alias->document_alias_header); + exit; + } + + if (! (! empty($_REQUEST['sysblock']) || ! empty($_REQUEST['module']) || ! empty($_REQUEST['request']))) + $_GET['id'] = $_REQUEST['id'] = PAGE_NOT_FOUND_ID; + } + + unset ($sql, $query); + } + } +?> \ No newline at end of file diff --git a/class/class.database.php b/class/class.database.php new file mode 100644 index 0000000..b7ae356 --- /dev/null +++ b/class/class.database.php @@ -0,0 +1,1606 @@ +_result = $_result; + } + + + /** + * Метод, предназначенный для обработки результата запроса. + * Возвращает как ассоциативный, так и численный массив. + * + * @return array + */ + public function FetchArray() + { + if (is_array($this->_result)) + { + $a = current($this->_result); + + next($this->_result); + + $b = array(); + + if (! is_array($a)) + return false; + + foreach($a as $k => $v) + $b[] = $v; + + return array_merge($b, $a); + } + + return mysqli_fetch_array($this->_result); + } + + + /** + * Метод, предназначенный для обработки результата запроса. + * Возвращает только ассоциативный массив. + * + * @return array + */ + public function FetchAssocArray() + { + if (is_array($this->_result)) + { + $a = current($this->_result); + + next($this->_result); + + return $a; + } + + return mysqli_fetch_assoc($this->_result); + } + + + /** + * Метод, предназначенный для обработки результата запроса, возвращая данные в виде объекта. + * + * @return object + */ + public function FetchRow() + { + if (is_array($this->_result)) + { + $a = $this->FetchAssocArray(); + + return array2object($a); + } + + return mysqli_fetch_object($this->_result); + } + + + /** + * Метод, предназначенный для возвращения данных результата запроса + * + * @return mixed + */ + public function GetCell() + { + if (is_array($this->_result)) + { + $a = current($this->_result); + + if (is_array($a)) + return current($a); + else + return false; + } + + if ($this->NumRows()) + { + $a = mysqli_fetch_row($this->_result); + return $a[0]; + } + + return false; + } + + + + /** + * Метод, предназначенный для обработки результата запроса. + * Возвращает полный ассоциативный массив. + * + * @return array + */ + public function GetArray() + { + if (is_array($this->_result)) + { + $data = current($this->_result); + + next($this->_result); + + return $data; + } + + $array = []; + + while ($row = mysqli_fetch_assoc($this->_result)) + array_push($array, $row); + + return $array; + } + + + /** + * Метод, предназначенный для обработки результата запроса. + * Возвращает данные в виде объекта. + * + * @return array + */ + public function GetObject() + { + if (is_array($this->_result)) + { + $data = $this->FetchAssocArray(); + + return array2object($data); + } + + $array = array(); + + while ($row = mysqli_fetch_object($this->_result)) + array_push($array, $row); + + return $array; + } + + + /** + * Метод, предназначенный для перемещения внутреннего указателя в результате запроса + * + * @param int $id - номер ряда результатов запроса + * @return bool + */ + public function DataSeek($id = 0) + { + if (is_array($this->_result)) + { + //не нашел как переместить указатель в массиве на конкретный + reset($this->_result); + + for ($x = 0; $x == $id; $x++) + next ($this->_result); + + return $id; //эээ а что вернуть то надо было? + } + + return mysqli_data_seek($this->_result, $id); + } + + + /** + * Метод, предназначенный для получения количества рядов результата запроса + * + * @return int + */ + public function NumRows() + { + if (is_array($this->_result)) + return (int)count($this->_result); + + return (int)mysqli_num_rows($this->_result); + } + + + /** + * Метод, предназначенный для получения количества полей результата запроса + * + * @return int + */ + public function NumFields() + { + if (is_array($this->_result)) + { + $a = current($this->_result); + + return count($a); + } + + return (int)mysqli_num_fields($this->_result); + } + + + /** + * Метод, предназначенный для получения названия указанной колонки результата запроса + * + * @param int $i - индекс колонки + * @return string + */ + public function FieldName($i) + { + if (is_array($this->_result)) + { + $a = current($this->_result); + + $b = array_keys($a); + + return($b[$i]); + } + + mysqli_field_seek($this->_result, $i); + + $field = mysqli_fetch_field($this->_result); + + return $field->name; + } + + +/** + * Метод, предназначенный для освобождения памяти от результата запроса + * + * @return bool + */ +public function Close() +{ + // Проверяем, является ли $this->_result объектом mysqli_result + if ($this->_result instanceof mysqli_result) { + @mysqli_free_result($this->_result); + $this->_result = null; // Устанавливаем в null, чтобы избежать повторного освобождения + } + + return true; +} + + + + /** + * Возвращает объект результата _result. + * + * @internal param $void + * @return resource + */ + public function getResult() + { + return $this->_result; + } + + + /** + * Удаляем объект + */ + public function __destruct() + { + $this->Close(); + } + } + + + /************************************************************** + * + * Класс, предназначенный для работы непосредственно с MySQL БД + * + **************************************************************/ + class AVE_DB + { + /** + * Хост + * + * @var string + */ + protected $db_host; + + /** + * Имя пользователя + * + * @var string + */ + protected $db_user; + + /** + * Пароль + * + * @var string + */ + protected $db_pass; + + /** + * Номер порта + * + * @var int + */ + protected $db_port; + + /** + * Сокет + * + * @var int + */ + protected $db_socket; + + /** + * Имя текущей БД. + * + * @var string + */ + protected $db_name; + + /** + * Префикс БД. + * + * @var string + */ + protected $db_prefix; + + /** + * Стандартный объект соединения сервером MySQL. + * + * @var mysqli + */ + protected $mysqli; + + /** + * Список выполненных запросов + * + * @var array + */ + public $_query_list; + + /** + * Метки времени до и после выполнения SQL-запроса + * + * @var array + */ + public $_time_exec; + + /** + * Последний запрос SQL-запроса + * + * @var array + */ + public $_last_query; + + private $conn; // Объект соединения + private $is_connected = false; // Свойство для отслеживания статуса соединения + + + //-- Instance + protected static $instance = null; + + /** + * Конструктор + * + * @param $db + * + * @throws AVE_DB_Exception + * @return \AVE_DB AVE_DB - объект + */ + private function __construct($db) + { + $this->db_host = $db['dbhost']; + $this->db_user = $db['dbuser']; + $this->db_password = $db['dbpass']; + $this->db_prefix = $db['dbpref']; + + if (! isset($db['dbport'])) + $this->db_port = ini_get ('mysqli.default_port'); + else + $this->db_port = (isset($db['dbport']) ? $db['dbport'] : null); + + if (! isset($db['dbsock'])) + $this->db_socket = ini_get ('mysqli.default_socket'); + else + $this->db_port = (isset($db['dbsock']) ? $db['dbsock'] : null); + + $this->Connect(); + + // Определяем профилирование + if (defined('SQL_PROFILING') && SQL_PROFILING) + { + // mysqli_query($this->mysqli, "QUERY_CACHE_TYPE = OFF"); + // mysqli_query($this->mysqli, "FLUSH TABLES"); + if (mysqli_query($this->mysqli, "SET PROFILING_HISTORY_SIZE = 100")) + { + mysqli_query($this->mysqli,"SET PROFILING = 1"); + } + } + } + + + /** + * Устанавливает соеденение с базой данных. + * + * @throws AVE_DB_Exception + * @internal param void + * @return void + */ + private function Connect() + { + if (!is_object($this->mysqli) || !$this->mysqli instanceof mysqli) + { + $this->mysqli = @new mysqli($this->db_host, $this->db_user, $this->db_password, null, $this->db_port, $this->db_socket); + if ($this->mysqli->connect_error) + { + throw new AVE_DB_Exception(__METHOD__ . ': ' . $this->mysqli->connect_error); + } + } + } + + + /** + * Задает набор символов по умолчанию. + * + * @param string $charset + * + * @throws AVE_DB_Exception + * @return AVE_DB + */ + public function setCharset($charset) + { + if (!$this->mysqli->set_charset($charset)) + { + throw new AVE_DB_Exception(__METHOD__ . ': ' . $this->mysqli->error); + } + + return $this; + } + + + /** + * Задает Sql Mode + * + * @param string $charset + * + * @throws AVE_DB_Exception + * @return AVE_DB + */ + public function setSqlMode() + { + if (!$this->mysqli->query("SET SQL_MODE = ''")) + { + throw new AVE_DB_Exception(__METHOD__ . ': ' . $this->mysqli->error); + } + + return $this; + } + + + /** + * Устанавливает имя используемой СУБД. + * + * @param string $database_name - имя базы данных + * @throws AVE_DB_Exception + * @return AVE_DB + */ + public function setDatabaseName($database_name) + { + if (!$database_name) + { + throw new AVE_DB_Exception(__METHOD__ . ': Не указано имя базы данных'); + } + + $this->db_name = $database_name; + + if (!$this->mysqli->select_db($this->db_name)) + { + throw new AVE_DB_Exception(__METHOD__ . ': ' . $this->mysqli->error); + } + + return $this; + } + + + /** + * Создает инстанс данного класса. + * + * @uses $AVE_DB = AVE_DB::getInstance($server, $username, $password, $port, $socket); + * @param $db + * @return object возвращает инстанс данного класса. + */ + public static function getInstance ($config = array()) + { + return new self($config); + } + + + /** + * Возвращает префикс БД. + * + * @param void + * @return string + */ + public function getPrefix() + { + return $this->db_prefix; + } + + + /** + * Возвращает кодировку по умолчанию, установленную для соединения с БД. + * + * @param void + * @return string + */ + public function getCharset() + { + return $this->mysqli->character_set_name(); + } + + + /** + * Возвращает имя текущей БД. + * + * @param void + * @return string + */ + public function getDatabaseName() + { + return $this->db_name; + } + + + /** + * Получает количество рядов, задействованных в предыдущей MySQL-операции. + * Возвращает количество рядов, задействованных в последнем запросе INSERT, UPDATE или DELETE. + * Если последним запросом был DELETE без оператора WHERE, + * все записи таблицы будут удалены, но функция возвратит ноль. + * + * @see mysqli_affected_rows + * @param void + * @return int + */ + public function getAffectedRows() + { + return $this->mysqli->affected_rows; + } + + + /** + * Возвращает последний выполненный MySQL-запрос. + * + * @param void + * @return string + */ + public function getQueryString() + { + return $this->_last_query; + } + + + /** + * Возвращает массив со всеми исполненными SQL-запросами в рамках текущего объекта. + * + * @param void + * @return array + */ + public function getQueries() + { + return $this->_query_list; + } + + + public function prepareQuery($string) + { + $search = array( + "/[\t]/", + '/(\s)+/s', + '/(GROUP BY |STRAIGHT_JOIN |UNION |FROM |WHERE |LIMIT |ORDER BY |LEFT JOIN|INNER JOIN|RIGHT JOIN|JOIN|ON |AND |OR |SET |VALUES)/s' + ); + + $replace = array( + " ", + '\\1', + "\r\n$1" + ); + + return trim(preg_replace($search, $replace, $string)); + } + + + public function showAllQueries () + { + if (! is_array($this->_query_list)) + return false; + + $div = ''; + + include_once BASE_DIR . '/lib/debug/sql.php'; + + $SqlFormatter = new SqlFormatter(); + + foreach ($this->_query_list AS $k => $v) + { + $_caller = ''; + + if (is_array($v['caller'])) + { + foreach ($v['caller'] AS $caller) + { + $_caller .= 'File: ' . $caller['call_file'] . PHP_EOL; + $_caller .= 'Func: ' . $caller['call_func'] . PHP_EOL; + $_caller .= 'Line: ' . $caller['call_line'] . PHP_EOL; + $_caller .= PHP_EOL; + } + } + + $_ttl = $v['ttl'] > 0 ? $v['ttl'] : 'None'; + + if (isset($v['cache'])) + $_ttl .= PHP_EOL . $v['cache']; + + $_query = SqlFormatter::format($v['query']); + + $div .= ' +
      ' . + '
      ' . + '' . ($k+1) . '' . + '
      ' . + '
      ' .
      +						'Trace:' . PHP_EOL .
      +						$_caller .
      +						'Cache:' . PHP_EOL .
      +						$_ttl . PHP_EOL .
      +						PHP_EOL .
      +						'Query:' . PHP_EOL .
      +						'
      ' . + $_query . + '
      ' . + '
      ' . + '
      + '; + } + + return $div; + } + + /** + * Возвращает id, сгенерированный предыдущей операцией INSERT. + * + * @see mysqli_insert_id + * @param void + * @return int + */ + public function getLastInsertId() + { + return $this->mysqli->insert_id; + } + + + /** + * Метод, предназначенный для возвращения ID записи, сгенерированной при последнем INSERT-запросе + * + * @return int + */ + public function InsertId() + { + return (int)mysqli_insert_id($this->mysqli); + } + + + /** + * Метод, предназначенный для получения функции из которой пришел запрос с ошибкой + * + * @return array|string + */ + public function getCaller() + { + if (! function_exists('debug_backtrace')) + return ''; + + $stack = debug_backtrace(); + $stack = array_reverse($stack); + + $caller = array(); + + foreach ((array)$stack as $call) + { + if (isset($call['class']) && $call['class'] == __CLASS__) + continue; + + $function = $call['function']; + + if (isset($call['class'])) + { + $function = $call['class'] . "->$function"; + } + + $caller[] = [ + 'call_file' => (isset($call['file']) ? $call['file'] : 'Unknown'), + 'call_func' => $function, + 'call_line' => (isset($call['line']) ? $call['line'] : 'Unknown') + ]; + } + + return $caller; + } + + + /************************* Внешние методы класса *************************/ + + + /** + * Метод, предназначенный для выполнения запроса к MySQL + * + * @param string $query - текст SQL-запроса + * @param bool $log - записать ошибки в лог? по умолчанию включено + * @return object/bool - объект с указателем на результат выполнения запроса + */ + public function Real_Query($query, $log = true, $TTL = null) + { + $result = @mysqli_query($this->mysqli, $query); + + // Запоминаем последний запрос + $this->_last_query = $query; + + // Если стоит в настройках, запоминать все запросы + if (defined('SQL_PROFILING') && SQL_PROFILING) + { + $_caller = $this->getCaller(); + $this->_query_list[] = array('caller' => $_caller, 'query' => $query, 'ttl' => $TTL); + } + + // Если нет результата и стоит выводить логи, выводим лог ошибки + if (! $result && $log) + $this->_error('query', $query); + + if (is_object($result) && $result instanceof mysqli_result) + return new AVE_DB_Result($result); + + return $result; + } + + + /** + * Метод, предназначенный для выполнения запроса к MySQL и возвращение результата в виде асоциативного массива с поддержкой кеша + * + * @param string $query - текст SQL-запроса + * @param integer $TTL - время жизни кеша (-1 безусловный кеш) + * @param string $cache_id - Id файла кеша + * @param bool $log - записать ошибки в лог? по умолчанию включено + * @return array|AVE_DB_Result + */ + public function Query ($query, $TTL = null, $cache_id = '', $log = true, $ext = '') + { + $cache_id = $this->cacheId($cache_id); + + // Принудительная фильтрация запроса + if (defined(SQL_QUERY_SANITIZE) && SQL_QUERY_SANITIZE) + $query = filter_var($query, FILTER_SANITIZE_STRING); + + $result = []; + + // Если это SELECT - то отслеживаем кеширование + $TTL = strtoupper(substr(trim($query), 0, 6)) == 'SELECT' + ? $TTL + : null; + + // Если включен DEV MODE, то отключаем кеширование запросов + if (defined('DEV_MODE') AND DEV_MODE) + $TTL = null; + + if ($TTL && ($TTL != 'nocache' AND $TTL != null)) + { + $cache_file = md5($query) . $ext; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : substr($cache_file, 0, 2) . '/' . substr($cache_file, 2, 2) . '/' . substr($cache_file, 4, 2) . '/'); + + if (! file_exists($cache_dir)) + mkdir($cache_dir, 0766, true); + + $TTL = ($TTL == -1) + ? true + : time() - filemtime($cache_dir . $cache_file) < $TTL; + + if (! (file_exists($cache_dir . $cache_file) && $TTL)) + { + $res = $this->Real_Query($query, $log); + + while ($mfa = $res->FetchAssocArray()) + $result[] = $mfa; + + if (defined('USE_ENCODE_SERIALIZE') && USE_ENCODE_SERIALIZE) + file_put_contents($cache_dir . $cache_file, _base64_encode(serialize($result))); + else + file_put_contents($cache_dir . $cache_file, serialize($result)); + } + else + { + // Если стоит в настройках, запоминать все запросы + if (defined('SQL_PROFILING') && SQL_PROFILING) + { + $_caller = $this->getCaller(); + + $this->_query_list[] = [ + 'caller' => $_caller, + 'query' => $query, + 'ttl' => $TTL, + 'cache' => $cache_dir . $cache_file + ]; + } + + if (defined('USE_ENCODE_SERIALIZE') && USE_ENCODE_SERIALIZE) + $result = unserialize(_base64_decode(file_get_contents($cache_dir . $cache_file))); + else + $result = unserialize(file_get_contents($cache_dir . $cache_file)); + } + + return new AVE_DB_Result($result); + } + + else + return $this->Real_Query($query, $log, $TTL); + } + + + /** + * Метод, предназначенный для выполнения запроса к MySQL и возвращение результата в виде асоциативного массива с поддержкой кеша + * + * @param string $query - текст SQL-запроса + * @param integer $TTL - время жизни кеша (-1 безусловный кеш) + * @param string $cache_id - Id файла кеша + * @param bool $log - записать ошибки в лог? по умолчанию включено + * @return void + */ + public function Queries ($array) + { + if (is_array($array)) + { + foreach ($array AS $sql) + { + // Принудительная фильтрация запроса + if (defined(SQL_QUERY_SANITIZE) && SQL_QUERY_SANITIZE) + $sql = filter_var($sql, FILTER_SANITIZE_STRING); + + $this->Real_Query($sql); + } + } + } + + + /** + * This method is needed for prepared statements. They require + * the data type of the field to be bound with "i" s", etc. + * This function takes the input, determines what type it is, + * and then updates the param_type. + * + * @param mixed $item Input to determine the type. + * + * @return string The joined parameter types. + */ + protected function DetermineType($item) + { + switch (gettype($item)) + { + case 'NULL': + case 'string': + return 's'; + break; + + case 'boolean': + case 'integer': + return 'i'; + break; + + case 'blob': + return 'b'; + break; + + case 'double': + return 'd'; + break; + } + return ''; + } + + + /** + * Метод, предназначенный для экранирования специальных символов в строках для использования в выражениях SQL + * + * @param mixed $value - обрабатываемое значение + * @return mixed + */ + public function Escape($value) + { + if (! is_numeric($value)) + { + $value = mysqli_real_escape_string($this->mysqli, $value); + } + + return $value; + } + + + /** + * Метод, предназначенный для экранирования специальных символов в строках для использования в выражениях SQL + * + * @param mixed $value - обрабатываемое значение + * @return mixed - возвращает строку запроса вычещенной + */ + public function EscStr($value) + { + global $AVE_DB; + + $search = array( + '&' => '&', + '&gt;' => '>', + '<' => '<', + ';' => ':', + '|' => '|', + '>' => '>', + "'" => ''', + '"' => '"', + ')' => ')', + '(' => '(', + '{' => '{', + '}' => '}', + '$' => '$' + ); + + $value = str_replace(array_keys($search), array_values($search), $value); + $value = str_ireplace('%3Cscript', '', $value); + + $value = htmlspecialchars($value, ENT_QUOTES); + + if (! is_array($value)) + { + $value = mysqli_real_escape_string($this->mysqli, $value); + } + else + { + $value = array_map(array($AVE_DB, 'Escape'), $value); + } + + return $value; + } + + + /** + * Метод, предназначенный для экранирования и очищения значения при поиске url в базе + * + * @param string $value - обрабатываемое значение + * @return string - возвращает строку запроса вычещенной + */ + function ClearUrl($url) + { + global $AVE_DB; + + // Убираем пробелы + $url = trim($url); + + // Условия + $search = ['<', ';', '|', '&', '>', "'", '"', ')', '(', '{', '}', '$', '=']; + + // Убираем пробелы + $url = preg_replace('/[\s,]+/i', '', $url); + + // Проходимся условиями + $url = str_replace($search, '', $url); + $url = str_ireplace('%3Cscript', '', $url); + + // Применяем встроенный SANITIZE + $url = filter_var($url, FILTER_SANITIZE_STRING); + + // Переводим html в сущности, если чтото осталось + $url = htmlspecialchars($url); + + // Если это не массив + if (! is_array($url)) + { + // Проходимся функцией от MySQL + $url = $this->mysqli->real_escape_string($url); + } + // Иначе вообще очищаем строку + else + { + $url = array_map([$AVE_DB, 'Escape'], $url); + } + + return $url; + } + + + /** + * Метод, предназначенный для возвращения количества всех найденных записей (после запроса) + * + * @return int + */ + public function GetFoundRows() + { + $result = $this->Query('SELECT FOUND_ROWS();'); + $strRow = $result->FetchArray(); + + return (int)$strRow[0]; + } + + + /** + * Метод, предназначенный для возвращения количества всех найденных записей (после запроса типа "SELECT SQL_CALC_FOUND_ROWS * ...") + * + * @param $query + * @param null $TTL + * @param string $cache_id + * @return int + */ + public function NumAllRows ($query, $TTL = null, $cache_id = '') + { + $cache_id = $this->cacheId($cache_id); + + // Если включен DEV MODE, то отключаем кеширование запросов + if (defined('DEV_MODE') AND DEV_MODE) + $TTL = null; + + if ($TTL AND ($TTL != 'nocache' AND $TTL != null)) + { + // Кол-во + $cache_file = md5($query) . '.count'; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : substr($cache_file, 0, 2) . '/'. substr($cache_file, 2, 2) . '/' . substr($cache_file, 4, 2) . '/'); + + if (! file_exists($cache_dir)) + mkdir($cache_dir, 0777, true); + + if (! (file_exists($cache_dir . $cache_file) && ($TTL == -1 ? true : time() - filemtime($cache_dir . $cache_file) < $TTL))) + { + if ($query <> $this->_last_query) + { + $res = $this->Real_Query($query); + } + else + { + $res = (int)$this->Query('SELECT FOUND_ROWS();')->GetCell(); + + file_put_contents($cache_dir . $cache_file, $res); + } + + return $res; + } + else + { + // Если стоит в настройках, запоминать все запросы + if (defined('SQL_PROFILING') && SQL_PROFILING) + { + $_caller = $this->getCaller(); + + $this->_query_list[] = [ + 'caller' => $_caller, + 'query' => 'SELECT FOUND_ROWS();', + 'ttl' => $TTL, + 'cache' => $cache_dir . $cache_file + ]; + } + + return file_get_contents($cache_dir . $cache_file); + } + } + + return (int)$this->Query('SELECT FOUND_ROWS();')->GetCell(); + } + + + /** + * Метод, предназначенный для формирования статистики выполнения SQL-запросов. + * + * @param string $type - тип запрашиваемой статистики + *
      +		 * Возможные значения:
      +		 *     list  - список выполненых зпаросов
      +		 *     time  - время исполнения зпросов
      +		 *     count - количество выполненных запросов
      +		 * 
      + * @return mixed + */ + public function DBStatisticGet($type = '') + { + switch ($type) + { + case 'list': + list($s_dec, $s_sec) = explode(' ', $GLOBALS['start_time']); + + $query_list = ''; + + $nq = 0; + + //$time_exec = 0; + $arr = $this->_time_exec; + + $co = sizeof($arr); + + for ($it = 0; $it < $co;) + { + list($a_dec, $a_sec) = explode(' ', $arr[$it++]); + list($b_dec, $b_sec) = explode(' ', $arr[$it++]); + + $time_main = ($a_sec - $s_sec + $a_dec - $s_dec)*1000; + $time_exec = ($b_sec - $a_sec + $b_dec - $a_dec)*1000; + + $query = sizeof(array_keys($this->_query_list, $this->_query_list[$nq])) > 1 + ? "" . $this->_query_list[$nq++] . "" + : $this->_query_list[$nq++]; + + $query_list .= (($time_exec > 1) ? "
    15. (" : "
    16. (") + . round($time_main) . " ms) " . $time_exec . " ms " . $query . "
    17. \n"; + } + + return $query_list; + break; + + case 'time': + $arr = $this->_time_exec; + + $time_exec = 0; + + $co = sizeof($arr); + + for ($it = 0; $it < $co;) + { + list($a_dec, $a_sec) = explode(" ", $arr[$it++]); + list($b_dec, $b_sec) = explode(" ", $arr[$it++]); + + $time_exec += $b_sec - $a_sec + $b_dec - $a_dec; + } + + return $time_exec; + break; + + case 'count': + return sizeof($this->_query_list); + break; + + default: + return ''; + break; + } + } + + + /** + * Метод, предназначенный для формирования статистики выполнения SQL-запросов. + * + * @param string $type - тип запрашиваемой статистики + *
      +		 * Возможные значения:
      +		 *     list  - список выполненых зпаросов
      +		 *     time  - время исполнения зпросов
      +		 *     count - количество выполненных запросов
      +		 * 
      + * @return mixed + */ + public function DBProfilesGet($type = '') + { + static $result, $list, $time, $count; + + if (! defined('SQL_PROFILING') OR ! SQL_PROFILING) + return false; + + if (! $result) + { + $list = "" + . "\n\t\n\t"; + + $result = mysqli_query($this->mysqli, "SHOW PROFILES"); + + while (list($qid, $qtime, $qstring) = @mysqli_fetch_row($result)) + { + $time += $qtime; + + $qstring = preg_replace('/\t+/', '', $qstring); + + $list .= "\n\t\n\t\t\n\t\t\n\t\t\n\t"; + + $res = mysqli_query($this->mysqli, " + SELECT + STATE, + FORMAT(DURATION, 6) AS DURATION + FROM + INFORMATION_SCHEMA.PROFILING + WHERE + QUERY_ID = " . $qid + ); + + while (list($state, $duration) = @mysqli_fetch_row($res)) + { + $list .= "\n\t\n\t\t\n\t\t\n\t"; + } + } + + $time = number_format($time * 1, 6, ',', ''); + $list .= "\n
      " + . $qid + . "" + . number_format($qtime * 1, 6, ',', '') + . "" + . $qstring + . "
       " + . number_format($duration * 1, 6, ',', '') + . "" . $state . "
      "; + $count = @mysqli_num_rows($result); + } + + switch ($type) + { + case 'list': return $list; break; + case 'time': return $time; break; + case 'count': return $count; break; + } + + return false; + } + + +/** + * Закрывает MySQL-соединение. + * + * @param void + * @return AVE_DB + */ +public function Close() +{ + if (!$this->is_connected) { + return $this; // Соединение уже закрыто, ничего не делаем + } + + if ($this->conn instanceof mysqli) { + $this->conn->close(); + } + + $this->is_connected = false; + + return $this; +} + + + + + /** + * Метод, предназначенный для обработки ошибок + * + * @param string $type - тип ошибки (при подключении к БД или при выполнении SQL-запроса) + * @param string $query - текст SQL запроса вызвавшего ошибку + * @access private + */ + public function _error($type, $query = '') + { + + + if ($type != 'query') + { + display_notice('Error ' . $type . ' MySQL database.'); + } + else + { + $my_error = mysqli_error($this->mysqli); + + $log = array( + 'sql_error' => $my_error, + 'sql_query' => htmlentities(stripslashes($query), ENT_QUOTES), + 'caller' => $this->getCaller(), + 'url' => HOST . $_SERVER['SCRIPT_NAME']. '?' . $_SERVER['QUERY_STRING'] + ); + + reportSqlLog($log); + + // Если в настройках системы установлен параметр на отправку сообщений на e-mail, тогда + if (SEND_SQL_ERROR) + { + // Формируем текст сообщения с ошибкой + $mail_body = ( + 'SQL ERROR: ' . $my_error . PHP_EOL + . 'TIME: ' . date('d-m-Y, H:i:s') . PHP_EOL + . 'URL: ' . HOST . $_SERVER['SCRIPT_NAME'] + . '?' . $_SERVER['QUERY_STRING'] . PHP_EOL + . $this->getCaller() . PHP_EOL + . 'QUERY: ' . stripslashes($query) . PHP_EOL + ); + + // Отправляем сообщение + send_mail( + get_settings('mail_from'), + $mail_body, + 'MySQL Error!', + get_settings('mail_from'), + get_settings('mail_from_name'), + 'text' + ); + } + } + } + + + /** + * Удаляем объект + * + * @param void + */ + public function __destruct() + { + $this->Close(); + } + + + /** + * Метод, предназначенный для получения информации о сервере MySQL + * + * @param void + * @return string + */ + public function mysql_version() + { + return @mysqli_get_server_info($this->mysqli); + } + + + /** + * Метод, предназначенный для определения кеша + * + * @param $cache_id + * @return bool + */ + public function cacheId ($cache_id) + { + //-- Если это документ, то меняем расположение + if (substr($cache_id, 0, 3) == 'doc') { + $cache_id = (int) str_replace('doc_', '', $cache_id); + return $cache_id = 'documents/' . (floor($cache_id / 1000)) . '/' . $cache_id; + } + + //-- Если это полный документ, то меняем расположение + if (substr($cache_id, 0, 3) == 'dat') { + $cache_id = (int) str_replace('dat_', '', $cache_id); + return $cache_id = 'documents/' . (floor($cache_id / 1000)) . '/' . $cache_id; + } + + //-- Если это скомпилированный шаблон документа, то меняем расположение + if (substr($cache_id, 0, 3) == 'cmd') { + $cache_id = (int) str_replace('cmd_', '', $cache_id); + return $cache_id = 'documents/' . (floor($cache_id / 1000)) . '/' . $cache_id; + } + + //-- Если это поля документа, то меняем расположение + if (substr($cache_id, 0, 3) == 'fld') { + $cache_id = (int) str_replace('fld_', '', $cache_id); + return $cache_id = 'documents/' . (floor($cache_id / 1000)) . '/' . $cache_id; + } + + //-- Если это рубрика, то меняем расположение + if (substr($cache_id, 0, 3) == 'rub') { + $cache_id = (int) str_replace('rub_', '', $cache_id); + return $cache_id = 'rubrics/' . $cache_id; + } + + //-- Если это запрос, то меняем расположение + if (substr($cache_id, 0, 3) == 'req') { + $cache_id = (int) str_replace('req_', '', $cache_id); + return $cache_id = 'requests/' . $cache_id; + } + + //-- Если это элемент запроса, то меняем расположение + if (substr($cache_id, 0, 3) == 'rqe') { + $cache_id = (int) str_replace('rqe_', '', $cache_id); + return $cache_id = 'requests/elements/' . (floor($cache_id / 1000)) . '/' . $cache_id; + } + + //-- Если это настройки запроса, то меняем расположение + if (substr($cache_id, 0, 3) == 'rqs') { + $cache_id = str_replace('rqs_', '', $cache_id); + return $cache_id = 'requests/settings/' . $cache_id; + } + + //-- Если это условия запроса, то меняем расположение + if (substr($cache_id, 0, 3) == 'rqc') { + $cache_id = str_replace('rqc_', '', $cache_id); + return $cache_id = 'requests/settings/' . $cache_id; + } + + // -- Навигация + if (substr($cache_id, 0, 3) == 'nav') { + $cache_id = explode('_', $cache_id); + return $cache_id = 'navigations/' . $cache_id[1]; + } + + //-- Если это скомпилированный документ, то меняем расположение + if (substr($cache_id, 0, 3) == 'cmp') { + $cache_id = (int) str_replace('cmp_', '', $cache_id); + return $cache_id = 'compile/' . (floor($cache_id / 1000)) . '/' . $cache_id; + } + + if (substr_count($cache_id, '__') > 0) { + return str_replace('__', '/', $cache_id); + } + + return $cache_id; + } + + + /** + * Метод, предназначенный для очищения кеша документов + * + * @param $cache_id + * @return bool + */ + public function clearCache($cache_id) + { + $cache_id = $this->cacheId($cache_id); + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : ''); + + return rrmdir($cache_dir); + } + + + /** + * Метод, предназначенный для очищения кеша документов + * + * @param $cache_id + * @return bool + */ + public function clearCurrentCache($cache_id, $sql = '', $ext = '') + { + $cache_id = $this->cacheId($cache_id); + + $cache_file = md5($sql) . $ext; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : substr($cache_file, 0, 2) . '/' . substr($cache_file, 2, 2) . '/' . substr($cache_file, 4, 2) . '/'); + + if (file_exists($cache_dir . $cache_file)) + unlink($cache_dir . $cache_file); + + return true; + } + + + /** + * Метод, предназначенный для очищения кеша документов + * + * @param $cache_id + * @return bool + */ + public function clearCacheUrl($cache_id) + { + $cache_id = str_replace('url_', '', $cache_id); + $cache_id = 'documents/urls/' . substr($cache_id, 0, 3); + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : ''); + + return rrmdir($cache_dir); + } + + + /** + * Метод, предназначенный для очищения кеша запросов + * + * @param $cache_id + * @return bool + */ + public function clearCacheRequest($cache_id) + { + $cache_id = (int)str_replace('req_', '', $cache_id); + $cache_id = 'request/' . (floor($cache_id / 1000)) . '/' . $cache_id; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : ''); + + return rrmdir($cache_dir); + } + + + /** + * Метод, предназначенный для очищения кеша запросов + * + * @param $cache_id + * @return bool + */ + public function clearRequest($cache_id) + { + $request = request_get_settings($cache_id); + + $cache_from_id = BASE_DIR . '/tmp/cache/sql/requests/settings/' . (trim($request->Id) > '' + ? trim($request->Id) . '/' + : ''); + + $cache_from_alias = BASE_DIR . '/tmp/cache/sql/requests/settings/' . (trim($request->request_alias) > '' + ? trim($request->request_alias) . '/' + : ''); + + return (rrmdir($cache_from_id) AND rrmdir($cache_from_alias)); + } + + + /** + * Метод, предназначенный для очищения кеша запросов + * + * @param int $doc_id + */ + public function clearDocument($doc_id) + { + $this->clearCache('doc_' . $doc_id); // Параметры + $this->clearCache('fld_' . $doc_id); // Поля + $this->clearCache('cmd_' . $doc_id); // Компиляция + $this->clearCache('rqe_' . $doc_id); // Элемент запроса + $this->clearCache('cmp_' . $doc_id); // Скомпилированный документ + } + + + /* + |-------------------------------------------------------------------------------------- + | Перефоратирует текст запроса + |-------------------------------------------------------------------------------------- + | + | @param string + | @return string + | + */ + function queryList ($string) + { + $search = array( + "/[\t]/", + '/(\s)+/s', + '/(GROUP BY|STRAIGHT_JOIN|UNION|FROM|WHERE|LIMIT|ORDER BY|LEFT JOIN|INNER JOIN|RIGHT JOIN|JOIN|ON|AND|OR|SET)/s' + + ); + + $replace = array( + " ", + '\\1', + "\r\n$1" + ); + + return trim(preg_replace($search, $replace, $string)); + } + + } // End AVE_DB class +?> \ No newline at end of file diff --git a/class/class.dbdump.php b/class/class.dbdump.php new file mode 100644 index 0000000..4364d47 --- /dev/null +++ b/class/class.dbdump.php @@ -0,0 +1,643 @@ +_database_dump = ''; + + // Циклически обрабатываем каждую таблицу + foreach ($_REQUEST['ta'] as $table) + { + if (! DB_EXPORT_PREFIX) + $table_export = preg_replace('/^' . PREFIX . '/', '%%PRFX%%', $table); + + // Если таблица имеет корректный префикс + if (preg_match('/^' . preg_quote(PREFIX) . '_/', $table)) + { + $row = $AVE_DB->Query("SHOW CREATE TABLE " . $table)->FetchArray(); + // Сохраняем CREATE и DROP запросы + $this->_database_dump .= "DROP TABLE IF EXISTS `" . (! DB_EXPORT_PREFIX ? $table_export : $table) . "`;" . $this->_delimiter . "\n"; + + if (! DB_EXPORT_PREFIX) + $this->_database_dump .= str_replace('CREATE TABLE `' . PREFIX . '_', 'CREATE TABLE `%%PRFX%%_', $row[1]) . ";" . $this->_delimiter . "\n\n"; + else + $this->_database_dump .= $row[1] . ";" . $this->_delimiter . "\n\n"; + + $nums = 0; + + // Получаем данные, которые в дальнейшем будут вставлены в INSERT запросы. + $sql = $AVE_DB->Query('SELECT * FROM `' . $table . '`'); + + while ($row = $sql->FetchArray()) + { + if ($nums == 0) + { + $nums = $sql->NumFields(); + + $temp_array = array(); + + for ($i = 0; $i < $nums; $i++) + { + $temp_array[] = $sql->FieldName($i); + } + + $table_list = '(`' . implode('`, `', $temp_array) . '`)'; + } + + $temp_array = array(); + + for ($i=0; $i<$nums; $i++) + { + if (! isset($row[$i])) + { + $temp_array[] = 'NULL'; + } + elseif ($row[$i] != '') + { + $temp_array[] = "'" . str_replace($search, $replace, addslashes($row[$i])) . "'"; + } + else + { + $temp_array[] = "''"; + } + } + + // Сохряняем INSERT запросы + $this->_database_dump .= 'INSERT INTO `' . (! DB_EXPORT_PREFIX ? $table_export : $table) . '` ' . $table_list . ' VALUES (' . implode(', ', $temp_array) . ");" . $this->_delimiter . "\n"; + } + + $this->_database_dump .= "\n"; + + $sql->Close(); + } + } + + return ! empty($this->_database_dump); + } + + + /** + * Метод, предназначенный для формирования файла дампа базы данных + * + * @return boolean + */ + function _databaseTopDumpCreate() + { + global $AVE_DB; + + $dbtables = array(); + + $sql = $AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_%'"); + + while ($row = $sql->FetchArray()) + { + array_push($dbtables, $row[0]); + } + + $search = array("\x00", "\x0a", "\x0d", "\x1a"); + $replace = array('\0', '\n', '\r', '\Z'); + + $this->_database_dump = ''; + + // Циклически обрабатываем каждую таблицу + foreach ($dbtables as $table) + { + if (! DB_EXPORT_PREFIX) + $table_export = preg_replace('/^' . PREFIX . '/', '%%PRFX%%', $table); + + // Если таблица имеет корректный префикс + if (preg_match('/^' . preg_quote(PREFIX) . '_/', $table)) + { + $row = $AVE_DB->Query("SHOW CREATE TABLE " . $table)->FetchArray(); + + // Сохраняем CREATE и DROP запросы + $this->_database_dump .= "DROP TABLE IF EXISTS `" . (! DB_EXPORT_PREFIX ? $table_export : $table) . "`;" . $this->_delimiter . "\n"; + + if (! DB_EXPORT_PREFIX) + $this->_database_dump .= str_replace('CREATE TABLE `' . PREFIX . '_', 'CREATE TABLE `%%PRFX%%_', $row[1]) . ";" . $this->_delimiter . "\n\n"; + else + $this->_database_dump .= $row[1] . ";" . $this->_delimiter . "\n\n"; + + $nums = 0; + + // Получаем данные, которые в дальнейшем будут вставлены в INSERT запросы. + $sql = $AVE_DB->Query('SELECT * FROM `' . $table . '`'); + + while ($row = $sql->FetchArray()) + { + if ($nums==0) + { + $nums = $sql->NumFields(); + + $temp_array = array(); + for ($i=0; $i<$nums; $i++) + { + $temp_array[] = $sql->FieldName($i); + } + $table_list = '(`' . implode('`, `', $temp_array) . '`)'; + } + + $temp_array = array(); + + for ($i=0; $i<$nums; $i++) + { + if (!isset($row[$i])) + { + $temp_array[] = 'NULL'; + } + elseif ($row[$i] != '') + { + $temp_array[] = "'" . str_replace($search, $replace, addslashes($row[$i])) . "'"; + } + else + { + $temp_array[] = "''"; + } + } + + // Сохряняем INSERT запросы + $this->_database_dump .= 'INSERT INTO `' . (! DB_EXPORT_PREFIX ? $table_export : $table) . '` ' . $table_list . ' VALUES (' . implode(', ', $temp_array) . ");" . $this->_delimiter . "\n"; + } + + $this->_database_dump .= "\n"; + + $sql->Close(); + } + } + + return ! empty($this->_database_dump); + } + + + /** + * Внешние методы класса + */ + + /** + * Метод, предназначенный для сохранения файла дампа базы данных на жеский диск + * + */ + function databaseDumpExport($top = 0, $exit = 0) + { + global $AVE_Template; + + // Если дамп не удалось создать, тогда завершаем работу + if ($top) + { + if (! $this->_databaseTopDumpCreate()) + exit; + } + else + { + if (! $this->_databaseDumpCreate()) + exit; + } + + // Готовим шаблон имени файла + if (isset($_REQUEST['file_name']) AND $_REQUEST['file_name'] != '') + $file_name = prepare_fname($_REQUEST['file_name']); + else + $file_name = preg_replace_ru(array("/%SERVER%/", "/%DATE%/", "/%TIME%/"), array($_SERVER['SERVER_NAME'], date('d.m.y'), date('H.i.s')), DB_EXPORT_TPL); + + $dump = (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ + ? gzencode($this->_database_dump) + : $this->_database_dump); + + if (isset($_REQUEST['server']) && $_REQUEST['server'] == 1) + { + if (! is_dir(BASE_DIR . '/tmp/backup/')) + { + @mkdir(BASE_DIR . '/tmp/backup/', 0777, true); + write_htaccess_deny(BASE_DIR . '/tmp/backup/'); + } + + @file_put_contents(BASE_DIR . '/tmp/backup/'. $file_name . '.sql'. (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ ? '.gz' : ''), $dump); + + @chmod(BASE_DIR . '/tmp/backup/'. $file_name . '.sql', 0777); + + if (! $exit) + header('Location:index.php?do=dbsettings&cp=' . SESSION); + else + return BASE_DIR . '/tmp/backup/'. $file_name . '.sql'. (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ ? '.gz' : ''); + } + else + { + // Формируем заголовок + header('Content-Type: text/plain'); + header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Content-Disposition: attachment; filename=' . $file_name . '.sql'. (defined('DB_EXPORT_GZ') && DB_EXPORT_GZ ? '.gz' : '')); + header('Content-Length: ' . strlen($dump)); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + + // Выводим данные + echo $dump; + + $this->_database_dump = ''; + } + + // Выполняем запись системного сообщения в журнал + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP')); + exit; + } + + + /** + * Метод, предназначенный для сохранения файла дампа базы данных на жеский диск + * + */ + function databaseDumpFileSave($file = '') + { + global $AVE_Template; + + $file = BASE_DIR . '/tmp/backup/'. $file; + + // Если дамп не удалось создать, тогда завершаем работу + if (! is_file($file)) + return false; + + header('Content-Description: File Transfer'); + header('Content-Type: application/octet-stream'); + header('Content-Disposition: attachment; filename=' . basename($file)); + header('Content-Transfer-Encoding: binary'); + header('Expires: 0'); + header('Cache-Control: must-revalidate'); + header('Pragma: public'); + header('Content-Length: ' . filesize($file)); + + ob_clean(); + + flush(); + + readfile($file); + + exit; + } + + + /** + * Метод, предназначенный для восстановления базы данных из дампа + * + * @param string $tempdir путь к папке в которую загружается файл дампа + */ + function databaseDumpImport($tempdir) + { + global $AVE_DB, $AVE_Template; + + $insert = false; + + // Если файл не пустой + if ($_FILES['file']['size'] != 0) + { + // Получаем имя файла и его расширение (должно быть sql) + $fupload_name = $_FILES['file']['name']; + $gz = substr($fupload_name, -3) == '.gz'; + $end = substr($fupload_name, -3); + + // Если расширение sql, тогда + if ($gz || $end == 'sql') + { + // Если файл не удалось загрузить, формируем сообщение с ошибкой + if (! @move_uploaded_file($_FILES['file']['tmp_name'], $tempdir . $fupload_name)) + die('Ошибка при загрузке файла!'); + + // Устанавливаем права чтения, записи, выполнения на файл + @chmod($fupload_name, 0777); + + // Определяем флаг готовности к записи данных в БД + $insert = true; + } + else + { + // В противном случае, если расширение файла НЕ sql, формируем сообщение с ошибкой + $AVE_Template->assign('msg', '
    18. Ошибка: ' . $AVE_Template->get_config_vars('MAIN_SQL_FILE_ERROR') . '
    19. '); + } + } + + // Если флаг готовности записи установлен, тогда + if ($insert) + { + // Еще раз провреяем наличие загруженного файла + if ($fupload_name != '' && file_exists($tempdir . $fupload_name)) + { + // Читаем данные из файла + $handle = @fopen($tempdir . $fupload_name, 'r'); + + $db_q = @fread($handle, filesize($tempdir . $fupload_name)); + + fclose($handle); + + if ($gz) + $db_q = gzdecode($db_q); + + $m_ok = 0; + + $m_fail = 0; + + // Формируем массив запросов ориентируясь по разделителю указанному в свойстве _delimiter + $querys = @explode($this->_delimiter, $db_q); + + // Циклически обрабатываем массив, выполняя каждый запрос + foreach ($querys as $val) + { + if (chop($val) != '') + { + $q = str_replace("\n",'',$val); + + $q = $q . ';'; + + if ($AVE_DB->Query($q)) + { + $m_ok++; + } + else + { + $m_fail++; + } + } + } + + // Удаляем файл дампа + @unlink($tempdir . $fupload_name); + + // Формируем сопроводительные сообщения + $msg = '
    20. ' . $AVE_Template->get_config_vars('MAIN_RESTORE_OK') . '

      ' + . $AVE_Template->get_config_vars('MAIN_TABLE_SUCC') + . '' . $m_ok . '
      ' + . $AVE_Template->get_config_vars('MAIN_TABLE_ERROR') + . '' . $m_fail . '
    21. '; + + $AVE_Template->assign('msg', $msg); + } + else // В противном случае, если файл не найден, формируем сообщение с ошибкой + { + $AVE_Template->assign('msg', '
    22. '.$AVE_Template->get_config_vars('DB_REPORT_DUMP_ER').'
    23. '); + } + } + + // Выполняем запись системного сообщения в журнал + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_RECOVER')); + } + + /** + * Метод, предназначенный для удаления файла дампа на сервере + * + * @param string $file путь к файлу дампа + */ + function databaseDumpFileDelete($file = '') + { + global $AVE_DB, $AVE_Template; + + $file = BASE_DIR . '/tmp/backup/'. $file; + + if (! is_file($file)) + return false; + + if (@unlink($file)) + { + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_DEL_OK') . ' ('.basename($file).')'); + } + else + { + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_DEL_ER') . ' ('.basename($file).')'); + } + + header('Location:index.php?do=dbsettings&cp=' . SESSION); + } + + /** + * Метод, предназначенный для восстановления базы данных из дампа на сервере + * + * @param string $file путь к файлу дампа + */ + function databaseDumpFileImport($file = '') + { + global $AVE_DB, $AVE_Template; + + $insert = false; + + $file = BASE_DIR . '/tmp/backup/'. $file; + + // Если дамп не удалось создать, тогда завершаем работу + if (! is_file($file)) $insert = false; + + // Если файл не пустой + if (filesize($file) != 0) + { + // Получаем имя файла и его расширение (должно быть sql) + $file_name = basename($file); + $gz = substr($file_name, -3)=='.gz'; + $end = substr($file_name, -3); + + // Если расширение sql, тогда + if ($gz || $end == 'sql') + { + // Определяем флаг готовности к записи данных в БД + $insert = true; + } + else + { + // В противном случае, если расширение файла НЕ sql, формируем сообщение с ошибкой + $AVE_Template->assign('msg', '
    24. Ошибка: ' . $AVE_Template->get_config_vars('MAIN_SQL_FILE_ERROR') . '
    25. '); + } + } + + // Если флаг готовности записи установлен, тогда + if ($insert) + { + // Еще раз провреяем наличие загруженного файла + if ($file_name != '' && file_exists($file)) + { + // Читаем данные из файла + $handle = @fopen($file, 'r'); + + $db_q = @fread($handle, filesize($file)); + + fclose($handle); + + if($gz)$db_q=gzdecode($db_q); + + $m_ok = 0; + + $m_fail = 0; + + // Формируем массив запросов ориентируясь по разделителю указанному в свойстве _delimiter + $querys = @explode($this->_delimiter, $db_q); + + // Циклически обрабатываем массив, выполняя каждый запрос + foreach ($querys as $val) + { + if (chop($val) != '') + { + $q = str_replace("\n",'',$val); + + $q = $q . ';'; + + @$q = str_replace('%%PRFX%%', PREFIX, $q); + + if ($AVE_DB->Query($q)) + { + $m_ok++; + } + else + { + $m_fail++; + } + } + } + + // Формируем сопроводительные сообщения + $msg = '
    26. ' . $AVE_Template->get_config_vars('MAIN_RESTORE_OK') . '

      ' + . $AVE_Template->get_config_vars('MAIN_TABLE_SUCC') + . '' . $m_ok . '
      ' + . $AVE_Template->get_config_vars('MAIN_TABLE_ERROR') + . '' . $m_fail . '
    27. '; + + $AVE_Template->assign('msg', $msg); + } + else // В противном случае, если файл не найден, формируем сообщение с ошибкой + { + $AVE_Template->assign('msg', '
    28. '.$AVE_Template->get_config_vars('DB_REPORT_DUMP_ER').'
    29. '); + } + } + + // Выполняем запись системного сообщения в журнал + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_RECOVER') . ' ('.$file_name.')'); + } + + /** + * Метод, предназначенный для оптимизации таблиц базы данных + * + */ + function databaseTableOptimize() + { + global $AVE_DB, $AVE_Template; + + if (! empty($_POST['ta']) && is_array($_POST['ta'])) + { + // Выполняем запрос на оптимизацию + $AVE_DB->Query("OPTIMIZE TABLE `" . implode("`, `", $_POST['ta']) . "`"); + + // Выполняем запись системного сообщения в журнал + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_OPTIM')); + } + } + + /** + * Метод, предназначенный для восстановления повреждённых таблиц базы данных + * + */ + function databaseTableRepair() + { + global $AVE_DB, $AVE_Template; + + if (! empty($_POST['ta']) && is_array($_POST['ta'])) + { + // Выполняем запрос на восстановление + $AVE_DB->Query("REPAIR TABLE `" . implode("`, `", $_POST['ta']) . "`"); + + // Выполняем запись системного сообщения в журнал + reportLog($AVE_Template->get_config_vars('DB_REPORT_DUMP_TABLE')); + } + } + + /** + * Метод, предназначенный для формирования списка всех таблиц в БД + * + * @return string + */ + function databaseTableGet() + { + global $AVE_DB; + + $tables = ''; + + // Получаем список всех таблиц, которые имею префикс, указанный в конфигурации системы + $sql = $AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_%'"); + + while ($row = $sql->FetchArray()) + { + $tables .= ''; + } + + $sql->Close(); + + // Возвращаем полученный список + return $tables; + } + + /** + * Метод, предназначенный для вывода всех sql файлов в папке backup + * + * @return string + */ + function databaseFilesGet() + { + $dir = BASE_DIR . '/tmp/backup/'; + + if($handle = opendir($dir)) + { + $files = array(); + + while (false !== ($file = readdir($handle))) + { + if ($file != "." && $file != ".." && (substr($file, -3) == 'sql' || substr($file, -2) == 'gz')) + { + if(is_file($dir . '/' . $file)) + { + $files[] = array( + 'name' => $file, + 'data' => (filectime($dir . '/' . $file)), + 'size' => (filesize($dir . '/' . $file)) + ); + } + } + } + closedir($handle); + } + + return msort($files, 'data', null, SORT_DESC); + } + } +?> \ No newline at end of file diff --git a/class/class.debug.php b/class/class.debug.php new file mode 100644 index 0000000..b1e80c7 --- /dev/null +++ b/class/class.debug.php @@ -0,0 +1,1239 @@ +(\s+|\s$)/', ' => ', $var_dump); + + $var_dump = htmlspecialchars($var_dump); + + $var_dump = preg_replace('/(=>)/', '$1', $var_dump); + + ob_end_clean(); + + if (! empty($name)) + { + $fn_name = explode(',', $name[1]); + $fn_name = array_shift($fn_name); + } + else + $fn_name = 'EVAL'; + + if ($_bg) + $bg = 'style="background: #' . $_bg . ';"'; + else + $bg = ''; + + $var_dump = ' + +
      +
      + var_dump(' . trim($fn_name) . ') +
      + '.self::_trace().' +
      +
      '
      +						. $var_dump .
      +						'
      +
      +
      + '; + + if (! $echo) + return $var_dump; + + echo $var_dump; + + if ($exit) + exit; + } + + + /** + * Функция для вывода переменной (для отладки) + * + * @param mixed $var любая переменная + * @param bool $exit + * @param null $bg + * @param bool $echo + * + * @return null|string|string[] + */ + public static function _print($var, $exit = false, $_bg = null, $echo = true) + { + $code = ''; + + $backtrace = debug_backtrace(); + + $backtrace = $backtrace[0]; + + if (preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'])) + { + preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'], $match); + $file = $match[1]; + } + + $fh = fopen((isset($file) + ? $file + : $backtrace['file']), 'r'); + + $line = 0; + + while (++$line <= $backtrace['line']) + $code = fgets($fh); + + fclose($fh); + + preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name); + + ob_start(); + + print_r($var); + + $var_dump = htmlspecialchars(ob_get_contents()); + + $var_dump = preg_replace('/(=>)/', '$1', $var_dump); + + ob_end_clean(); + + if (! empty($name)) + { + $fn_name = explode(',', $name[1]); + $fn_name = array_shift($fn_name); + } + else + $fn_name = 'EVAL'; + + if ($_bg) + $bg = 'style="background: #' . $_bg . ';"'; + else + $bg = ''; + + $var_dump = ' + +
      +
      + print_r(' . trim($fn_name) . ') +
      + '.self::_trace().' +
      +
      '
      +						. $var_dump .
      +						'
      +
      +
      + '; + + if (! $echo) + return $var_dump; + + echo $var_dump; + + if ($exit) + exit; + } + + + /** + * Функция для вывода переменной (для экспорта) + * + * @param mixed $var любая переменная + * @param bool $exit + * @param null $bg + * @param bool $echo + * + * @return string + */ + public static function _exp($var, $exit = false, $_bg = null, $echo = true) + { + $code = ''; + + $backtrace = debug_backtrace(); + + $backtrace = $backtrace[0]; + + if (preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'])) + { + preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'], $match); + $file = $match[1]; + } + + $fh = fopen((isset($file) + ? $file + : $backtrace['file']), 'r'); + + $line = 0; + + while (++$line <= $backtrace['line']) + $code = fgets($fh); + + fclose($fh); + + preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name); + + ob_start(); + + var_export($var); + + if (! empty($name)) + { + $fn_name = explode(',', $name[1]); + $fn_name = array_shift($fn_name); + } + else + $fn_name = 'EVAL'; + + if ($_bg) + $bg = 'style="background: #' . $_bg . ';"'; + else + $bg = ''; + + $var_export = htmlspecialchars(ob_get_contents()); + + $var_export = preg_replace('/(=>)/', '$1', $var_export); + + ob_end_clean(); + + $var_dump = ' + +
      +
      + var_export(' . trim($fn_name) . ') +
      + '.self::_trace().' +
      +
      '
      +						. $var_export .
      +						'
      +
      +
      + '; + + if (! $echo) + return $var_dump; + + echo $var_dump; + + if ($exit) + exit; + } + + + /** + * Функция для вывода переменной (для отладки) + * + * @param mixed $var любая переменная + * @param bool $exit true - остановливает дальнейшее выполнение скрипта, false - продолжает выполнять скрипт + * @param null $bg + * @param bool $echo + * + * @return false|string + */ + public static function _html($var, $exit = false, $_bg = null, $echo = true) + { + $code = ''; + + $backtrace = debug_backtrace(); + + $backtrace = $backtrace[0]; + + if (preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'])) + { + preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'], $match); + $file = $match[1]; + } + + $fh = fopen((isset($file) + ? $file + : $backtrace['file']), 'r'); + + $line = 0; + + while (++$line <= $backtrace['line']) + $code = fgets($fh); + + fclose($fh); + + preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name); + + ob_start(); + + var_export($var); + + if (! empty($name)) + { + $fn_name = explode(',', $name[1]); + $fn_name = array_shift($fn_name); + } + else + $fn_name = 'EVAL'; + + if ($_bg) + $bg = 'style="background: #' . $_bg . ';"'; + else + $bg = ''; + + $var_dump = ob_get_contents(); + + ob_end_clean(); + + $var_dump = ' + +
      +
      + var_export(' . trim($fn_name) . ') +
      + '.self::_trace().' +
      +
      '
      +						. htmlentities($var_dump, ENT_QUOTES) .
      +						'
      +
      +
      + '; + + if (! $echo) + return $var_dump; + + echo $var_dump; + + if ($exit) + exit; + } + + + /** + * Функция для записи переменной в файл (для отладки) + * + * @param mixed $var любая переменная + * @param bool $exit true - остановливает дальнейшее выполнение скрипта, false - продолжает выполнять скрипт + * @param null $bg + * @param bool $append + */ + public static function _dump($var, $exit = false, $bg = null, $append = true) + { + $code = ''; + + $backtrace = debug_backtrace(); + + $backtrace = $backtrace[0]; + + if (preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'])) + { + $file = preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'], $match); + $file = $match[1]; + } + + $fh = fopen((isset($file) + ? $file + : $backtrace['file']), 'r'); + + $line = 0; + + while (++$line <= $backtrace['line']) + $code = fgets($fh); + + fclose($fh); + + preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name); + + ob_start(); + + var_dump($var); + + $var_dump = ob_get_contents(); + + $var_dump = preg_replace('/=>(\s+|\s$)/', ' => ', $var_dump); + + $var_dump = htmlspecialchars($var_dump); + + $var_dump = preg_replace('/(=> )+([a-zA-Z]+\(\d+\))/', '$1$2', $var_dump); + + ob_end_clean(); + + if (! empty($name)) + { + $fn_name = explode(',', $name[1]); + $fn_name = array_shift($fn_name); + } + else + $fn_name = 'EVAL'; + + if (! $bg) + { + $br = '2a5885'; + $bg = '43648c'; + } + else + { + $br = $bg; + } + + $var_dump = ' + +
      +
      + var_dump(' . trim($fn_name) . ') +
      + '.self::_trace().' +
      +
      '
      +						. $var_dump .
      +						'
      +
      +
      + '; + + if ($append) + file_put_contents(BASE_DIR . '/debug.html', $var_dump, FILE_APPEND); + else + file_put_contents(BASE_DIR . '/debug.html', $var_dump); + + if ($exit) + exit; + } + + + /** + * Функция для вывода переменной (для отладки) + * + * @param mixed $var любая переменная + * @param bool $exit + * @param null $bg + * @param bool $echo + * + * @return false|null|string|string[] + */ + public static function _($var, $_bg = null, $from = '') + { + $code = ''; + + $backtrace = debug_backtrace(); + + $backtrace = $backtrace[0]; + + if (preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'])) + { + preg_match('/([^\(]*)\((.*)\)/i', $backtrace['file'], $match); + $file = $match[1]; + } + + $fh = fopen((isset($file) + ? $file + : $backtrace['file']), 'r'); + + $line = 0; + + while (++$line <= $backtrace['line']) + $code = fgets($fh); + + fclose($fh); + + preg_match('/' . __FUNCTION__ . '\s*\((.*)\)\s*;/u', $code, $name); + + unset ($code, $backtrace); + + ob_start(); + + var_dump($var); + + $var_dump = ob_get_contents(); + + $var_dump = preg_replace('/=>(\s+|\s$)/', ' => ', $var_dump); + + $var_dump = htmlspecialchars($var_dump); + + $var_dump = preg_replace('/(=>)/', '$1', $var_dump); + + ob_end_clean(); + + if (! empty($name)) + { + $fn_name = explode(',', $name[1]); + $fn_name = array_shift($fn_name); + } + else + $fn_name = 'EVAL'; + + if ($_bg) + $bg = 'style="background: #' . $_bg . ';"'; + else + $bg = ''; + + $var_dump = ' + +
      +
      + var_dump(' . trim($fn_name) . ') ' . $from . ' +
      + '.self::_trace().' +
      +
      '
      +				. $var_dump .
      +				'
      +
      +
      + '; + + self::$_debug[] = $var_dump; + } + + + /** + * Функция для трейсинга дебаггера + * + * @param + * @return string + */ + public static function _trace() + { + $bt = debug_backtrace(); + + $trace = $bt[1]; + + $line = $trace['line']; + + $file = $trace['file']; + + //$function = $trace['function']; + + $class = (isset($bt[2]['class']) + ? $bt[2]['class'] + : 'None'); + + if (isset($bt[2]['class'])) + $type = $bt[2]['type']; + else + $type = 'Unknow'; + + $function = isset($bt[2]['function']) + ? $bt[2]['function'] + : 'None'; + + return sprintf('
      Class: %s | Type: %s | Function: %s
      File: %s line %s
      ', $class, $type, $function, $file, $line); + } + + + /** + * Функция отвечает за начало таймера + * + * @param string $name любая переменная (ключ массива) + */ + public static function startTime($name = '') + { + Debug::$time[$name] = microtime(true); + } + + + /** + * Функция отвечает за окончание таймера + * + * @param string $name любая переменная (ключ массива) + * + * @return string + */ + public static function endTime($name = '') + { + if (isset(Debug::$time[$name])) + return sprintf("%01.4f", microtime(true) - Debug::$time[$name]) . ' sec'; + } + + + /** + * Функция отвечает за начало подсчета используеой памяти + * + * @param string $name любая переменная (ключ массива) + */ + public static function startMemory($name = '') + { + Debug::$memory[$name] = memory_get_usage(); + } + + + /** + * Функция отвечает за окончание подсчета используемой памяти + * + * @param string $name любая переменная (ключ массива) + * @return string + */ + public static function endMemory($name = '') + { + if (isset(Debug::$memory[$name])) + return Debug::formatSize(memory_get_usage() - Debug::$memory[$name]); + } + + + /** + * Форматированный вывод размера + * + * @param int $size размер + * @return string нормированный размер с единицой измерения + */ + public static function formatSize($size) + { + if ($size >= 1073741824) + $size = round($size / 1073741824 * 100) / 100 . ' Gb'; + elseif ($size >= 1048576) + $size = round($size / 1048576 * 100) / 100 . ' Mb'; + elseif ($size >= 1024) + $size = round($size / 1024 * 100) / 100 . ' Kb'; + else + $size = $size . ' b'; + + return $size; + } + + + /** + * Форматированный вывод чисел + * + * @param int $number число + * @param int $decimal + * @param string $after + * @param string $thousand + * @return string + */ + public static function numFormat($number, $decimal = 0, $after = ',', $thousand= '.') + { + if ($number) + return number_format($number, $decimal, $after, $thousand); + + return ''; + } + + + /** + * @param $header + * @param $body + * @param $caller + * @param bool $exit + */ + public static function _errorSql ($header, $body, $caller, $exit = false) + { + // + } + + + /** + * Вывод статистики + * + * @param null $type + * + * @return int|null|string + */ + public static function getStatistic ($type = null) + { + global $AVE_DB; + + define ('START_MEMORY', memory_get_usage()); + + $stat = null; + + switch ($type) + { + case 'time': + $stat = number_format(microtime_diff(START_MICROTIME, microtime()), 3, ',', ' '); + break; + + case 'memory': + $stat = Debug::formatSize(memory_get_usage() - START_MEMORY); + break; + + case 'peak': + $stat = Debug::formatSize(memory_get_peak_usage()); + break; + + case 'sqlcount': + $stat = $AVE_DB->DBProfilesGet('count'); + break; + + case 'sqltrace': + $stat = count($AVE_DB->_query_list); + break; + + case 'sqltime': + $stat = $AVE_DB->DBProfilesGet('time'); + break; + + case 'get': + $stat = self::_stat_get('get'); + break; + + case 'post': + $stat = self::_stat_get('post'); + break; + + case 'request': + $stat = self::_stat_get('request'); + break; + + case 'files': + $stat = self::_stat_get('files'); + break; + + case 'cookie': + $stat = self::_stat_get('cookie'); + break; + + case 'env': + $stat = self::_stat_get('env'); + break; + + case 'session': + $stat = self::_stat_get('session'); + break; + + case 'server': + $stat = self::_stat_get('server'); + break; + + case 'globals': + $stat = self::_stat_get('globals'); + break; + + case 'blocks': + $stat = self::_stat_get('blocks'); + break; + } + + return $stat; + } + + + /** + * @param string $type + * + * @return false|null|string|string[] + */ + public static function _stat_get (string $type = 'get') + { + ob_start(); + + if ($type == 'get') + var_dump($_GET); + else if ($type == 'post') + var_dump($_POST); + else if ($type == 'request') + var_dump($_REQUEST); + else if ($type == 'files') + var_dump($_FILES); + else if ($type == 'cookie') + var_dump($_COOKIE); + else if ($type == 'session') + var_dump($_SESSION); + else if ($type == 'server') + var_dump($_SERVER); + else if ($type == 'env') + var_dump($_ENV); + else if ($type == 'globals') + var_dump($GLOBALS); + else if ($type == 'blocks') + var_dump($GLOBALS['block_generate']); + $stat = ob_get_contents(); + $stat = preg_replace('/=>(\s+|\s$)/', ' => ', $stat); + $stat = htmlspecialchars($stat); + $stat = preg_replace('/(=>)/', '$1', $stat); + $stat = '
      '. $stat .'
      '; + + ob_end_clean(); + + return $stat; + } + + + public static function getDocumentInfo () + { + global $AVE_Template; + + $_arr = [ + 'DOC' => '/admin/index.php?do=docs&action=edit&Id=', + 'RUBRIC' => '/admin/index.php?do=rubs&action=edit&Id=', + 'BLOCKS' => '/admin/index.php?do=blocks&action=edit&id=', + 'SYSBLOCK' => '/admin/index.php?do=sysblocks&action=edit&id=', + 'REQUESTS' => '/admin/index.php?do=request&action=edit&Id=', + 'NAVIAGTIONS' => '/admin/index.php?do=navigation&action=templates&navigation_id=' + ]; + + $doc = get_document($_REQUEST['id']); + + $_edit = []; + + $_edit['DOC'][$doc['Id']] = $_arr['DOC'] . $doc['Id']; + $_edit['RUBRIC'][$doc['rubric_id']] = $_arr['RUBRIC'] . $doc['rubric_id']; + + foreach ($GLOBALS['block_generate'] AS $k => $v) + { + if (! in_array($k, array_keys($_arr))) { + continue; + } + + foreach ($v as $key => $value) { + $_edit[$k][$key] = $_arr[$k] . $key; + } + } + + $AVE_Template->assign('edit', $_edit); + $AVE_Template->assign('session', session_id()); + + $return = $AVE_Template->fetch(BASE_DIR . '/lib/debug/debug.tpl'); + + return $return; + } + + + /** + * @return string + */ + public static function displayInfo (): string + { + global $AVE_DB; + + $out = PHP_EOL; + $out .= ''; + $out .= PHP_EOL; + $out .= ''; + $out .= PHP_EOL; + $out .= ''; + $out .= PHP_EOL; + $out .= '
      '; + $out .= PHP_EOL; + $out .= ' +
      +
        +
      • Timers
      • +
      • Blocks
      • +
      • $_GET
      • +
      • $_POST
      • +
      • $_REQUEST
      • +
      • $_FILES
      • +
      • $_COOKIE
      • +
      • $_SESSION
      • +
      • $_SERVER
      • +
      • $_ENV
      • +
      • $GLOBALS
      • +
      • MySQL
      • +
      • Trace
      • +
      • Debug
      • +
      • Edit
      • +
      + '; + $out .= PHP_EOL; + $out .= '
      ' . PHP_EOL; + $out .= 'Time generation: ' . self::getStatistic('time') . ' sec'; + $out .= '
      '; + $out .= 'Memory usage: ' . self::getStatistic('memory'); + $out .= '
      '; + $out .= 'Memory peak usage: ' . self::getStatistic('peak'); + $out .= '
      '; + $out .= 'Real SQL Queries: ' . $AVE_DB->DBProfilesGet('count') . ' for ' . $AVE_DB->DBProfilesGet('time') . ' sec'; + $out .= '
      '; + $out .= 'All SQL Queries: ' . (is_array($AVE_DB->_query_list) || $AVE_DB->_query_list instanceof Countable ? count($AVE_DB->_query_list) : 0); + $out .= '
      '; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= '
      '; + + return $out; + } + + /** + * @return string + */ + public static function displayInfoLight (): string + { + global $AVE_DB; + + $out = PHP_EOL; + $out .= ''; + $out .= PHP_EOL; + $out .= ''; + $out .= PHP_EOL; + $out .= ''; + $out .= PHP_EOL; + $out .= '
      '; + $out .= PHP_EOL; + $out .= ' +
      +
        +
      • Timers
      • +
      • Blocks
      • +
      • Content
      • +
      • Debug
      • +
      • Document
      • +
      + '; + $out .= PHP_EOL; + $out .= '
      ' . PHP_EOL; + $out .= 'Time generation: ' . self::getStatistic('time') . ' sec'; + $out .= '
      '; + $out .= 'Memory usage: ' . self::getStatistic('memory'); + $out .= '
      '; + $out .= 'Memory peak usage: ' . self::getStatistic('peak'); + $out .= '
      '; + $out .= 'Real SQL Queries: ' . $AVE_DB->DBProfilesGet('count') . ' for ' . $AVE_DB->DBProfilesGet('time') . ' sec'; + $out .= '
      '; + $out .= 'All SQL Queries: ' . (is_array($AVE_DB->_query_list) || $AVE_DB->_query_list instanceof Countable ? count($AVE_DB->_query_list) : 0); + $out .= '
      '; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= ''; + + $out .= PHP_EOL; + $out .= '
      '; + + return $out; + } + } +?> \ No newline at end of file diff --git a/class/class.docs.php b/class/class.docs.php new file mode 100644 index 0000000..a893213 --- /dev/null +++ b/class/class.docs.php @@ -0,0 +1,4546 @@ +Query($sql); + + $ids = array(); + + while ($row = $query->FetchAssocArray()) + { + $ids[$row['Id']]['rubric_field_type'] = $row['rubric_field_type']; + $ids[$row['Id']]['rubric_field_numeric'] = (int)$row['rubric_field_numeric']; + } + + return $ids; + } + + + function _get_document_text_fields ($id) + { + global $AVE_DB; + + $sql = " + SELECT + rubric_field_id + FROM + ".PREFIX."_document_fields_text + WHERE + document_id = '" . $id . "' + "; + + $query = $AVE_DB->Query($sql); + + $ids = array(); + + while ($row = $query->GetCell()) + array_push($ids, $row); + + return $ids; + } + + + function _get_rubric ($id) + { + global $AVE_DB; + + if (! $id) + return false; + + $sql = " + SELECT + rubric_alias, + rubric_alias_history, + rubric_code_start, + rubric_code_end + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $id . "' + "; + + return $AVE_DB->Query($sql)->FetchRow(); + } + + + /** + * Метод, предназначенный для получения списка документов в Панели управления + * + */ + /** + * Метод, предназначенный для получения списка документов в Панели управления + * + */ + function documentListGet() + { + global $AVE_DB, $AVE_Rubric, $AVE_Template; + + $ex_titel = ''; + $nav_titel = ''; + $ex_time = ''; + $nav_time = ''; + $request = ''; + $ex_rub = ''; + $ex_delete = ''; + $nav_rub = ''; + $ex_docstatus = ''; + $navi_docstatus = ''; + + // При смене страницы убираем из сессии параметры выборки документов + unset ($_SESSION['search_query']); + + // Если в запросе пришел параметр на поиск документа по названию + if (! empty($_REQUEST['QueryTitel'])) + { + $request = $_REQUEST['QueryTitel']; + $chain = explode(' ', $request); // Получаем список слов, разделяя по пробелу (если их несколько) + + // Циклически обрабатываем слова, формируя условия, которые будут применены в запросе к БД + foreach ($chain as $search) + { + $and = @explode(' +', $search); + + foreach ($and as $and_word) + { + if (strpos($and_word, '+') !== false) + { + $ex_titel .= " AND ((UPPER(doc.document_title) LIKE '%" . mb_strtoupper(substr($and_word, 1)) . "%')OR(UPPER(doc.document_alias) LIKE '%" . mb_strtoupper(substr($and_word, 1)) . "%'))"; + } + } + + $and_not = @explode(' -', $search); + foreach ($and_not as $and_not_word) + { + if (strpos($and_not_word, '-') !== false) + { + $ex_titel .= " AND (UPPER(doc.document_title) NOT LIKE '%" . mb_strtoupper($and_not_word, 1) . "%')"; + } + } + + $start = explode(' +', $request); + if (strpos($start[0], ' -') !== false) $start = explode(' -', $request); + $start = $start[0]; + } + + $ex_titel = "AND ((UPPER(doc.document_title) LIKE '%" . mb_strtoupper($start) . "%')OR(UPPER(doc.document_alias) LIKE '%" . mb_strtoupper($start) . "%'))" . $ex_titel; + $nav_titel = '&QueryTitel=' . urlencode($request); + } + + $sql_join_field = ''; + $sql_where_field = ''; + $field_link = ''; + + // Если в запросе пришел id определенного поля рубрики + if (isset($_REQUEST['field_id']) && (int)$_REQUEST['field_id'] > 0) + { + $sql_join_field = " + LEFT JOIN + " . PREFIX . "_document_fields AS df1 + ON + doc.Id = df1.document_id + LEFT JOIN + " . PREFIX . "_document_fields_text AS df2 + ON + df1.document_id = df2.document_id + "; + + if ($_REQUEST['field_request'] == 'eq' && $_REQUEST['field_search'] != '') + { + $sql_where_field = " + AND + (df1.rubric_field_id = '" . (int)$_REQUEST['field_id'] . "' + AND + (UPPER(df1.field_value) = '" . mb_strtoupper($_REQUEST['field_search']) . "' + OR + df1.field_number_value = '" . mb_strtoupper($_REQUEST['field_search']) . "')) + "; + } + else if ($_REQUEST['field_request'] == 'like' && $_REQUEST['field_search'] != '') + { + $sql_where_field = " + AND + (df1.rubric_field_id = '" . (int)$_REQUEST['field_id'] . "' + AND + (UPPER(df1.field_value) LIKE '%" . mb_strtoupper($_REQUEST['field_search']) . "%' + OR + df1.field_number_value LIKE '%" . mb_strtoupper($_REQUEST['field_search']) . "%')) + "; + } + + $field_link = '&field_id=' . (int)$_REQUEST['field_id'] . '&field_request=' . $_REQUEST['field_request'] . '&field_search=' . $_REQUEST['field_search']; + } + + $sql_where_param = ''; + $param_link = ''; + + // Если в запросе пришел параметр определенного поля документа + if (isset($_REQUEST['param_id']) && $_REQUEST['param_id'] != '') + { + if ($_REQUEST['param_request'] == 'eq' && $_REQUEST['param_search'] != '') + { + $sql_where_param = " + AND doc." . $_REQUEST['param_id'] . " = '" . $_REQUEST['param_search'] . "' + "; + } + else if ($_REQUEST['param_request'] == 'like' && $_REQUEST['param_search'] != '') + { + $sql_where_param = "AND doc." . $_REQUEST['param_id'] . " LIKE '%" . $_REQUEST['param_search'] . "%'"; + } + + $param_link = '¶m_id=' . $_REQUEST['param_id'] . '¶m_request=' . $_REQUEST['param_request'] . '¶m_search=' . $_REQUEST['param_search']; + } + + // Если в запросе пришел id определенной рубрики + if (isset($_REQUEST['rubric_id']) && $_REQUEST['rubric_id'] != 'all') + { + // Формируем условия, которые будут применены в запросе к БД + $ex_rub = " AND doc.rubric_id = '" . $_REQUEST['rubric_id'] . "'"; + + // формируем условия, которые будут применены в ссылках + $nav_rub = '&rubric_id=' . (int)$_REQUEST['rubric_id']; + + $sql = $AVE_DB->Query(" + SELECT + Id, + rubric_field_type, + rubric_field_title + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $_REQUEST['rubric_id'] ."' + ORDER BY + rubric_field_title ASC + "); + + $fields = array(); + + while($row = $sql->FetchRow()) + array_push($fields, $row); + + $AVE_Template->assign('fields', $fields); + } + + $ex_db = ''; + + // Поиск с учётом условий настроек рубрик + if (! isset($_REQUEST['rubric_id']) && empty($_REQUEST['QueryTitel'])) + { + // Формируем условия, которые будут применены в запросе к БД + $ex_rub = " AND rub.rubric_docs_active = '1'"; + + // формируем условия для бд + $ex_db = "LEFT JOIN " . PREFIX . "_rubrics as rub on rub.Id = rubric_id"; + } + + $ex_lang = ''; + + // Поиск с учётом языка документа + if (isset($_REQUEST['lang_id']) && $_REQUEST['lang_id'] != '') + { + // Формируем условия, которые будут применены в запросе к БД + $ex_lang = " AND doc.document_lang = '{$_REQUEST["lang_id"]}'"; + + $nav_lang = '&lang_id=' . $_REQUEST['lang_id']; + } + else + $nav_lang = ''; + + // Поиск с выводом всех результатов из всех рубрик + if (@$_REQUEST['rubric_id'] == 'all') + { + $nav_rub = '&rubric_id=all'; + } + + // Если в запросе пришел параметр на фильтрацию документов по определенному временному интервалу + if (@$_REQUEST['document_published'] && @$_REQUEST['document_expire']) + { + // Формируем условия, которые будут применены в запросе к БД + $ex_time = 'AND ((doc.document_published BETWEEN ' . $this->_documentListStart() . ' AND ' . $this->_documentListEnd() . ') OR doc.document_published = 0)'; + + // формируем условия, которые будут применены в ссылках + $nav_time = '&TimeSelect=1' + . '&document_published=' . $_REQUEST['document_published'] + . '&document_expire=' . $_REQUEST['document_expire']; + } + + // Если в запросе пришел параметр на фильтрацию документов по статусу + if (! empty($_REQUEST['status'])) + { + // Определяем, какой статус запрашивается и формируем условия, которые будут применены в запросе к БД, + // а также в ссылках, для дальнейшей навигации + switch ($_REQUEST['status']) + { + // С любым статусом + case '': + case 'All': + break; + + // Только опубликованные + case 'Opened': + $ex_docstatus = "AND doc.document_status = '1'"; + $navi_docstatus = '&status=Opened'; + break; + + // Только неопубликованные + case 'Closed': + $ex_docstatus = "AND doc.document_status = '0'"; + $navi_docstatus = '&status=Closed'; + break; + + // Помеченные на удаление + case 'Deleted': + $ex_docstatus = "AND doc.document_deleted = '1'"; + $navi_docstatus = '&status=Deleted'; + break; + } + } + + // Определяем группу пользоваеля и id документа, если он присутствует в запросе + // $ex_delete = (UGROUP != 1) ? "AND doc.document_deleted != '1'" : '' ; + // Определяем группу пользоваеля и id документа, если он присутствует в запросе + // $ex_delete = (UGROUP != 1) ? "AND doc.document_deleted != '1'" : '' ; + $w_id = !empty($_REQUEST['doc_id']) + ? " AND doc.Id = '" . $_REQUEST['doc_id'] . "'" + : ''; + + // Выполняем запрос к БД на получение количества документов соответствующих вышеопределенным условиям + $sql = " + SELECT + COUNT(doc.Id) + FROM + " . PREFIX . "_documents as doc + " . $ex_db . " + " . $sql_join_field . " + WHERE 1 + " . $ex_delete . " + " . $ex_time . " + " . $ex_titel . " + " . $ex_rub . " + " . $ex_docstatus . " + " . $ex_lang . " + " . $w_id . " + " . $sql_where_param . " + " . $sql_where_field . " + "; + + $num = $AVE_DB->Query($sql)->GetCell(); + + // Определяем лимит документов, который будет показан на 1 странице + $limit = (isset($_REQUEST['limit']) && is_numeric($_REQUEST['limit']) && $_REQUEST['limit'] > 0) + ? $_REQUEST['limit'] + : $limit = $this->_limit; + + $nav_limit = '&limit=' . $limit; + + // Определяем количество страниц, которые будут сформированы на основании количества полученных документов + $pages = ceil($num / $limit); + $start = get_current_page() * $limit - $limit; + + $db_sort = 'ORDER BY doc.Id DESC'; + $navi_sort = '&sort=id_desc'; + + // Параметры вывборки документов + $search_query = base64_encode($_SERVER['QUERY_STRING']); + + // При смене страницы убираем из сессии параметры выборки документов + unset ($_SESSION['query_strings']); + + // Если в запросе используется параметр сортировки + if (!empty($_REQUEST['sort'])) + { + // Определяем, по какому параметру происходит сортировка + switch ($_REQUEST['sort']) + { + // По позиции документа, по возрастанию + case 'position' : + $db_sort = 'ORDER BY doc.document_position ASC'; + $navi_sort = '&sort=position'; + break; + + // По позиции документа, по убыванию + case 'position_desc' : + $db_sort = 'ORDER BY doc.document_position DESC'; + $navi_sort = '&sort=position_desc'; + break; + + // По id документа, по возрастанию + case 'id' : + $db_sort = 'ORDER BY doc.Id ASC'; + $navi_sort = '&sort=id'; + break; + + // По id документа, по убыванию + case 'id_desc' : + $db_sort = 'ORDER BY doc.Id DESC'; + $navi_sort = '&sort=id_desc'; + break; + + // По названию документа, в алфавитном порядке + case 'title' : + $db_sort = 'ORDER BY doc.document_title ASC'; + $navi_sort = '&sort=title'; + break; + + // По названию документа, в обратном алфавитном порядке + case 'title_desc' : + $db_sort = 'ORDER BY doc.document_title DESC'; + $navi_sort = '&sort=title_desc'; + break; + + // По url-адресу, в алфавитном порядке + case 'alias' : + $db_sort = 'ORDER BY doc.document_alias ASC'; + $navi_sort = '&sort=alias'; + break; + + // По url-адресу, в обратном алфавитном порядке + case 'alias_desc' : + $db_sort = 'ORDER BY doc.document_alias DESC'; + $navi_sort = '&sort=alias_desc'; + break; + + // По id рубрики, по возрастанию + case 'rubric' : + $db_sort = 'ORDER BY doc.rubric_id ASC'; + $navi_sort = '&sort=rubric'; + break; + + // По id рубрики, по убыванию + case 'rubric_desc' : + $db_sort = 'ORDER BY doc.rubric_id DESC'; + $navi_sort = '&sort=rubric_desc'; + break; + + // По дате публикации, по возрастанию + case 'published' : + $db_sort = 'ORDER BY doc.document_published ASC'; + $navi_sort = '&sort=published'; + break; + + // По дате публикации, по убыванию + case 'published_desc' : + $db_sort = 'ORDER BY doc.document_published DESC'; + $navi_sort = '&sort=published_desc'; + break; + + // По количеству просмотров, по возрастанию + case 'view' : + $db_sort = 'ORDER BY doc.document_count_view ASC'; + $navi_sort = '&sort=view'; + break; + + // По количеству просмотров, по убыванию + case 'view_desc' : + $db_sort = 'ORDER BY doc.document_count_view DESC'; + $navi_sort = '&sort=view_desc'; + break; + + // По количеству печати документа, по возрастанию + case 'print' : + $db_sort = 'ORDER BY doc.document_count_print ASC'; + $navi_sort = '&sort=print'; + break; + + // По количеству печати документа, по убыванию + case 'print_desc' : + $db_sort = 'ORDER BY doc.document_count_print DESC'; + $navi_sort = '&sort=print_desc'; + break; + + // По автору, по алфавитному возрастанию + case 'author' : + $db_sort = 'ORDER BY doc.document_author_id ASC'; + $navi_sort = '&sort=author'; + break; + + // По автору, по алфавитному убыванию + case 'author_desc' : + $db_sort = 'ORDER BY doc.document_author_id DESC'; + $navi_sort = '&sort=author_desc'; + break; + + // По дате последнего редактирования, по возрастанию + case 'changed': + $db_sort = 'ORDER BY doc.document_changed ASC'; + $navi_sort = '&sort=changed'; + break; + + // По дате последнего редактирования, по убыванию + case 'changed_desc': + $db_sort = 'ORDER BY doc.document_changed DESC'; + $navi_sort = '&sort=changed_desc'; + break; + + // По языку документа, по возрастанию + case 'lang': + $db_sort = 'ORDER BY doc.document_lang ASC'; + $navi_sort = '&sort=lang'; + break; + + // По языку документа, по убыванию + case 'lang_desc': + $db_sort = 'ORDER BY doc.document_lang DESC'; + $navi_sort = '&sort=lang_desc'; + break; + + // По умолчанию, по дате последнего редактирования по убыванию. + // Последний отредактированный документ, будет первым в списке. + default : + $db_sort = 'ORDER BY doc.document_changed DESC'; + $navi_sort = '&sort=changed_desc'; + break; + } + } + + $docs = array(); + + // Выполняем запрос к БД на получение уже не количества документов, отвечающих условиям, а уже на + // получение всех данных, с учетом всех условий, а также типа сортировки и лимита для вывода на + // одну страницу. + // Выполняем запрос к БД на получение уже не количества документов, отвечающих условиям, а уже на + // получение всех данных, с учетом всех условий, а также типа сортировки и лимита для вывода на + // одну страницу. + $sql = " + SELECT STRAIGHT_JOIN SQL_CALC_FOUND_ROWS + doc.*, + rub.rubric_admin_teaser_template + FROM + " . PREFIX . "_documents as doc + LEFT JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = doc.rubric_id + " . $sql_join_field . " + WHERE 1 + " . $ex_rub . " + " . $ex_delete . " + " . $ex_time . " + " . $ex_titel . " + " . $ex_docstatus . " + " . $ex_lang . " + " . $w_id . " + " . $sql_where_param . " + " . $sql_where_field . " + GROUP BY doc.Id + " . $db_sort . " + LIMIT + " . $start . "," . $limit . " + "; + + //Debug::_echo($sql, true, '270'); + $sql = $AVE_DB->Query($sql); + + // Циклически обрабатываем полученные данные с целью приведения некоторых из них к удобочитаемому виду + while ($row = $sql->FetchRow()) + { + // Запомниаем в сесии, параметры выборки для документа + $_SESSION['search_query'][$row->Id] = $search_query; + + // Определяем количество комментариев, оставленных для данного документа + $row->ist_remark = $AVE_DB->Query(" + SELECT + COUNT(*) + FROM + " . PREFIX . "_document_remarks + WHERE + document_id = '" . $row->Id . "' + ")->GetCell(); + + $this->documentPermissionFetch($row->rubric_id); + + // Получаем название рубрики по ее Id + $row->RubName = $AVE_Rubric->rubricNameByIdGet($row->rubric_id)->rubric_title; + $row->document_author = get_username_by_id($row->document_author_id); // Получаем имя пользователя (Автора) + $row->cantEdit = 0; + $row->canDelete = 0; + $row->canEndDel = 0; + $row->canOpenClose = 0; + $row->rubric_admin_teaser_template = @eval2var(' ?>'.($row->rubric_admin_teaser_template>'' + ? @showrequestelement($row, $row->rubric_admin_teaser_template) + : '').'document_title = stripslashes(htmlspecialchars_decode($row->document_title)); + $row->document_breadcrum_title = stripslashes(htmlspecialchars_decode($row->document_breadcrum_title)); + + $lang_pack = array(); + + if ($row->document_lang_group > 0) + { + $sql1 = $AVE_DB->Query(" + SELECT SQL_CALC_FOUND_ROWS + Id, + rubric_id, + document_alias, + document_lang, + document_status + FROM + ".PREFIX."_documents + WHERE + document_lang_group=" . $row->document_lang_group . " + OR + Id = " . $row->document_lang_group + ); + + while ($row1 = $sql1->FetchAssocArray()) + $lang_pack[$row1['document_lang']] = $row1; + } + + $row->lang_pack = $lang_pack; + + // разрешаем редактирование и удаление + // если автор имеет право изменять свои документы в рубрике + // или пользователю разрешено изменять все документы в рубрике + if ( + ($row->document_author_id == @$_SESSION['user_id'] && isset($_SESSION[$row->rubric_id . '_editown']) && @$_SESSION[$row->rubric_id . '_editown'] == 1) + || + (isset($_SESSION[$row->rubric_id . '_editall']) && $_SESSION[$row->rubric_id . '_editall'] == 1) + ) + { + $row->cantEdit = 1; + $row->canDelete = 1; + $row->canOpenClose = 1; + } + + // запрещаем редактирование главной страницы и страницу ошибки 404 если требуется одобрение Администратора + if ( ($row->Id == 1 || $row->Id == PAGE_NOT_FOUND_ID) + && isset($_SESSION[$row->rubric_id . '_newnow']) && @$_SESSION[$row->rubric_id . '_newnow'] != 1) + { + $row->cantEdit = 0; + } + + // разрешаем автору блокировать и разблокировать свои документы если не требуется одобрение Администратора + if ($row->document_author_id == @$_SESSION['user_id'] + && isset($_SESSION[$row->rubric_id . '_newnow']) && @$_SESSION[$row->rubric_id . '_newnow'] == 1) + { + $row->canOpenClose = 1; + } + + // разрешаем всё, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if (UGROUP == 1 || @$_SESSION[$row->rubric_id . '_alles'] == 1) + { + $row->cantEdit = 1; + $row->canDelete = 1; + $row->canEndDel = 1; + $row->canOpenClose = 1; + } + // Запрещаем удаление Главной страницы и страницы с 404 ошибкой + if ($row->Id == 1 || $row->Id == PAGE_NOT_FOUND_ID) + { + $row->canDelete = 0; + $row->canEndDel = 0; + } + + array_push($docs, $row); + } + + // Передаем полученные данные в шаблон для вывода + $AVE_Template->assign('docs', $docs); + + $link = "index.php?do=docs"; + $link .= (isset($_REQUEST['action']) && $_REQUEST['action'] == 'showsimple') ? '&action=showsimple' : ''; + $link .= !empty($_REQUEST['target']) ? '&target=' . urlencode($_REQUEST['target']) : ''; + $link .= !empty($_REQUEST['doc']) ? '&doc=' . urlencode($_REQUEST['doc']) : ''; + $link .= !empty($_REQUEST['document_alias']) ? '&document_alias=' . urlencode($_REQUEST['document_alias']) : ''; + $link .= !empty($_REQUEST['navi_item_target']) ? '&navi_item_target=' . urlencode($_REQUEST['navi_item_target']) : ''; + $link .= $navi_docstatus; + $link .= $nav_titel; + $link .= $nav_rub; + $link .= $nav_lang; + $link .= $nav_time; + $link .= $nav_limit; + $link .= $field_link; + $link .= $param_link; + $link .= (isset($_REQUEST['selurl']) && $_REQUEST['selurl'] == 1) ? '&selurl=1' : ''; + $link .= (isset($_REQUEST['selecturl']) && $_REQUEST['selecturl'] == 1) ? '&selecturl=1' : ''; + $link .= (isset($_REQUEST['function']) && $_REQUEST['function'] == 1) ? '&function=1' : ''; + $link .= (isset($_REQUEST['idonly']) && $_REQUEST['idonly'] == 1) ? '&idonly=1' : ''; + $link .= (isset($_REQUEST['idtitle']) && $_REQUEST['idtitle'] == 1) ? '&idtitle=1' : ''; + $link .= (isset($_REQUEST['pop']) && $_REQUEST['pop'] == 1) ? '&pop=1' : ''; + $link .= (isset($_REQUEST['onlycontent']) && $_REQUEST['onlycontent'] == 1) ? '&onlycontent=1' : ''; + $link .= (isset($_REQUEST['langCode']) && !empty($_REQUEST['langCode'])) ? '&langCode='.$_REQUEST['langCode'] : ''; + $link .= (isset($_REQUEST['CKEditor']) && !empty($_REQUEST['CKEditor'])) ? '&CKEditor='.$_REQUEST['CKEditor'] : ''; + $link .= (isset($_REQUEST['CKEditorFuncNum']) && $_REQUEST['CKEditorFuncNum'] == 1) ? '&CKEditorFuncNum=1' : ''; + + $AVE_Template->assign('link', $link); + + // Если количество отобранных документов превышает лимит на одной странице - формируем постраничную навигацию + if ($num > $limit) + { + $page_nav = get_pagination($pages, 'page', ' {t}'); + + $AVE_Template->assign('page_nav', $page_nav); + } + + $params = [ + 'rubric_id', + 'rubric_tmpl_id', + 'document_parent', + 'document_property', + 'document_rating', + 'document_position' + ]; + + $AVE_Template->assign('params', $params); + $AVE_Template->assign('DEF_DOC_START_YEAR', mktime(0, 0, 0, date("m"), date("d"), date("Y") - 10)); + $AVE_Template->assign('DEF_DOC_END_YEAR', mktime(0, 0, 0, date("m"), date("d"), date("Y") + 10)); + } + + /** + * Метод, предназначенный для сохранения статусов документа в БД + * + */ + function documentEditStatus() + { + global $AVE_DB; + + switch(@$_REQUEST['moderation']) + { + // статусы + case "1" : + foreach (@$_REQUEST['document'] as $id => $status) + { + if (is_numeric($id) && is_numeric($status)) + { + $AVE_DB->Query("UPDATE " . PREFIX . "_documents SET document_status = '1' WHERE Id = '".$id."' "); + } + } + break; + + // статусы + case "0" : + foreach (@$_REQUEST['document'] as $id => $status) + { + if (is_numeric($id) && is_numeric($status)) + { + $AVE_DB->Query("UPDATE " . PREFIX . "_documents SET document_status = '0' WHERE Id = '".$id."' "); + } + } + break; + + // в корзину + case "intrash" : + foreach (@$_REQUEST['document'] as $id => $status) + { + if (is_numeric($id) && is_numeric($status)) + { + $AVE_DB->Query("UPDATE " . PREFIX . "_documents SET document_deleted = '1' WHERE Id = '".$id."' "); + } + } + break; + + // из корзины + case "outtrash" : + foreach (@$_REQUEST['document'] as $id => $status) + { + if (is_numeric($id) && is_numeric($status)) + { + $AVE_DB->Query("UPDATE " . PREFIX . "_documents SET document_deleted = '0' WHERE Id = '".$id."' "); + } + } + break; + + // совсем удалить + case "trash" : + foreach (@$_REQUEST['document'] as $id => $status) + { + if (is_numeric($id) && is_numeric($status)) + { + $AVE_DB->Query("DELETE FROM " . PREFIX . "_documents WHERE Id = '".$id."'"); + $AVE_DB->Query("DELETE FROM " . PREFIX . "_document_fields WHERE document_id = '".$id."'"); + $AVE_DB->Query("DELETE FROM " . PREFIX . "_document_fields_text WHERE document_id = '".$id."'"); + } + } + break; + } + + header('Location:index.php?do=docs'.(empty($_REQUEST['rubric_id']) ? '' : '&rubric_id='.$_REQUEST['rubric_id']).'&cp=' . SESSION); + exit; + } + + /** + * Функция предназначенна для анализа ключевых слов и разненсения их по табличке _document_keyword + * + */ + function generateKeywords($document_id, $keywords = null) + { + global $AVE_DB; + + if (! $keywords) + $keywords = $AVE_DB->Query("SELECT document_meta_keywords FROM " . PREFIX . "_documents WHERE Id = " . intval($document_id) . " LIMIT 1")->GetCell(); + + $keywords = explode(',', $keywords); + + $res = $AVE_DB->Query("DELETE FROM " . PREFIX . "_document_keywords where document_id = " . intval($document_id)); + + foreach ($keywords as $k => $v) + { + if (trim($v) > '') + { + $key = trim(mb_substr($v, 0, 254)); + + $res = $AVE_DB->Query("INSERT INTO ".PREFIX."_document_keywords + ( + document_id, + keyword + ) + VALUES + ( + '".intval($document_id)."', + '".clean_no_print_char($key)."' + ) + "); + } + } + } + + /** + * Функция предназначенна для анализа ключевых слов и разненсения их по табличке _document_tags + * + */ + function saveTags($document_id, $rubric_id, $tags = null) + { + global $AVE_DB; + + if (! $tags) + return false; + + $tags = explode(',', $tags); + + $res = $AVE_DB->Query("DELETE FROM " . PREFIX . "_document_tags WHERE document_id = " . intval($document_id)); + + foreach ($tags as $k => $v) + { + if (trim($v) > '') + { + $key = trim(mb_substr($v, 0, 254)); + + $res = $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_document_tags + SET + rubric_id = '".intval($rubric_id)."', + document_id = '" . intval($document_id) . "', + tag = '" . clean_no_print_char($key) . "' + "); + } + } + } + + /** + * Метод, предназначенный для сохранения ревизии документа в БД + * + */ + static function SaveRevission($document_id) + { + global $AVE_DB; + + $sql = $AVE_DB->Query(" + SELECT + doc.rubric_field_id, + doc.field_value, + more.field_value as more + FROM + " . PREFIX . "_document_fields AS doc + LEFT JOIN + " . PREFIX . "_document_fields_text AS more + ON + (more.rubric_field_id = doc.rubric_field_id and more.document_id=doc.document_id) + WHERE + doc.document_id = '" . $document_id . "' + "); + + $rows = array(); + + while ($row = $sql->FetchAssocArray()) + { + $row['field_value'] = (string)$row['field_value'] . (string)$row['more']; + $rows[$row['rubric_field_id']] = pretty_chars(clean_no_print_char($row['field_value'])); + } + + $dtime = $AVE_DB->Query('SELECT document_changed FROM ' . PREFIX . '_documents WHERE Id = ' . $document_id)->GetCell(); + + $last_rev = @unserialize($AVE_DB->Query("SELECT doc_data FROM " . PREFIX . "_document_rev WHERE doc_id=" . $document_id . " ORDER BY doc_revision DESC LIMIT 1")->GetCell()); + // это я долго пытался понять почему всегда старая ревизия не равна новой даже если просто нажали лишний раз сохранить + // оказывается редактор подсовывет alt="" если альта в имге нету и сносит его если он есть там пустой )))))))))) + // но пусть проверка будет - может редакторы сменятся/апдейтятся а может кто просто хардкором будет код править))) + $dorev = false; + + foreach ($rows as $k => $v) + { + if ($rows[$k] <> $last_rev[$k]) + { + $dorev = true; + } + } + + if ($dorev) + { + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_document_rev + SET + doc_id = '" . $document_id . "', + doc_revision = '" . $dtime . "', + doc_data = '" . addslashes(serialize($rows)) . "', + user_id = '" . $_SESSION['user_id'] ."' + "); + } + + return $rows; + } + + /** + * Метод, предназначенный для востановления ревизии документа + * + */ + function documentRevissionRestore($document_id, $revision, $rubric_id) + { + + global $AVE_DB, $AVE_Template; + + $this->documentPermissionFetch($rubric_id); + + if ( (isset($_SESSION[$rubric_id . '_delrev']) && $_SESSION[$rubric_id . '_delrev'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1) ) + { + $run = true; + } + + if ($run === true) + { + $res = $AVE_DB->Query(" + SELECT + doc_data + FROM + " . PREFIX . "_document_rev + WHERE + doc_id = '" . $document_id . "' + AND + doc_revision = '" . $revision . "' + LIMIT 1 + ")->GetCell(); + + if (! $res) + return false; + + $data = @unserialize($res); + + foreach($data as $k => $v) + { + if ($k) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_fields + SET + field_value = '" . mb_substr($v,0,499) . "', + field_number_value = '" . preg_replace('/[^\d.]/', '', $v) . "' + WHERE + document_id = '" . $document_id . "' + AND + rubric_field_id = '" . $k . "' + "); + + if (mb_strlen($v) > 500) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_fields_text + SET + field_value = '" . mb_substr($v,500) . "' + WHERE + document_id = '" . $document_id . "' + AND + rubric_field_id = '" . $k . "' + "); + } + else + { + $AVE_DB->Query(" + DELETE + FROM + ". PREFIX . "_document_fields_text + WHERE + document_id= '" . $document_id . "' + AND + rubric_field_id='" . $k . "' + "); + } + } + } + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('DOC_REVISION_RECOVER')." (Doc: $document_id Rev: $revision)"); + header('Location:index.php?do=docs&action=edit&Id=' . (int)$_REQUEST['doc_id'] . '&rubric_id=' . (int)$_REQUEST['rubric_id'] . '&cp=' . SESSION); + } + else + { + $AVE_Template->assign('content', $AVE_Template->get_config_vars('DOC_NO_RES_REVISION')); + } + } + + /** + * Метод, предназначенный для удаления ревизии документа + * + */ + function documentRevissionDelete($document_id, $revision, $rubric_id){ + + global $AVE_DB, $AVE_Template; + + $this->documentPermissionFetch($rubric_id); + + if ( (isset($_SESSION[$rubric_id . '_delrev']) && $_SESSION[$rubric_id . '_delrev'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1) ){ $run = true; } + + if ($run === true) + { + + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_rev + WHERE + doc_id = '" . $document_id . "' + AND + doc_revision='".$revision."' + "); + + reportLog($AVE_Template->get_config_vars('DOC_REVISION_DELETE')." (Doc: $document_id Rev: $revision)"); + + if (! isset($_REQUEST['ajax'])) + { + header('Location:index.php?do=docs&action=edit&rubric_id=' . $rubric_id . '&Id=' . $document_id . '&cp=' . SESSION); + } + + } + else + { + $AVE_Template->assign('content', $AVE_Template->get_config_vars('DOC_NO_DEL_REVISION')); + } + } + + + /** + * Метод, предназначенный для сохранения документа в БД + * + * @param int $rubric_id Идентификатор Рубрики + * @param int $document_id Идентификатор Документа или null, если документ новый + * @param array $data Документ в массиве структура - хитрая + * @param bool $update_non_exists_fields Изменять поля на пустые значения у не переданных полей или не надо + * @param bool $rubric_code Использовать код рубрики или не надо + * @param bool $revisions Использовать ревизии документов + * @param bool $logs Писать системные сообщения в журнал + * @param bool $generate Генерировать Meta + * + * @return int|bool Возвращает номер документа если все удачно или false если все плохо + */ + + function documentSave ($rubric_id, $document_id, $data, $update_non_exists_fields = false, $rubric_code = true, $revisions = true, $logs = true, $generate = true) + { + global $AVE_DB, $AVE_Template; + + //-- Проверяем входящие данные -- // + + // Если отсутсвует рубрика, ничего не делаем + if (! $rubric_id) + return false; + + // Если отсутсвуют данные, ничего не делаем + if (! isset($data)) + return false; + + // Если отсутсвуют данные полей, ничего не делаем + if (! isset($data['feld'])) + return false; + + $rubric_id = (int)$rubric_id; + $document_id = (int)$document_id; + + // Определяем тип операции + $oper = 'INSERT'; + + // Забираем параметры рубрики + $_rubric = $this->_get_rubric($rubric_id); + + // Регистрируем триггер перед сохранением + Hooks::register('DocumentBeforeSave', 'DocumentBeforeSave', 100); + + // Запускаем триггер перед сохранением, возвращаем $data для дальнейшего сохранения + $data = Hooks::trigger('DocumentBeforeSave', $data); + + $data['rubric_id'] = $rubric_id; + + // Выполняем стартовый код рубрики + if ($rubric_code) + eval (' ?'.'>' . $_rubric->rubric_code_start . ' 0) + $oper = 'UPDATE'; + + // Если пользователь имеет права на добавление документов в указанную рубрику, тогда + if ($oper == 'INSERT' && !( (isset($_SESSION[$rubric_id . '_newnow']) && $_SESSION[$rubric_id . '_newnow'] == 1) + || (isset($_SESSION[$rubric_id . '_new']) && $_SESSION[$rubric_id . '_new'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1) )) + return false; + + // Title документа + $data['document_title'] = $_url = empty($data['document_title']) + ? $AVE_Template->get_config_vars('DOC_WITHOUT_TITLE') + : $data['document_title']; + + // Если оператор равен UPDATE + if ($oper == 'UPDATE') + { + // Выполняем запрос к БД на получение автора документа и id Рубрики + $row = $AVE_DB->Query(" + SELECT + rubric_id, + document_author_id + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + // Присваиваем значение переменной $rubric_id + $rubric_id = $row->rubric_id; + + // Запрещаем редактирвание + $row->cantEdit = 0; + + // Определяем права доступа к документам в данной рубрики + $this->documentPermissionFetch($row->rubric_id); + + // Разрешаем редактирование + // если автор имеет право изменять свои документы в рубрике + // или пользователю разрешено изменять все документы в рубрике + if ( (isset($_SESSION['user_id']) && $row->document_author_id == $_SESSION['user_id'] && + isset($_SESSION[$row->rubric_id . '_editown']) && $_SESSION[$row->rubric_id . '_editown'] == 1) + || (isset($_SESSION[$row->rubric_id . '_editall']) && @$_SESSION[$row->rubric_id . '_editall'] == 1) ) + { + // Разрешаем редактирование + $row->cantEdit = 1; + } + + // Запрещаем редактирование главной страницы и страницы ошибки 404 если требуется одобрение Администратора + if ( ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) && @$_SESSION[$row->rubric_id . '_editall'] != 1 ) + { + // Запрещаем редактирвание + $row->cantEdit = 0; + } + + // Разрешаем редактирование, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$row->rubric_id . '_alles']) && $_SESSION[$row->rubric_id . '_alles'] == 1) ) + { + // Разрешаем редактирование + $row->cantEdit = 1; + } + + // выходим если нельзя редактировать + if(! $row->cantEdit==1 ) + return false; + + //-- Обрабатываем все данные, пришедшие в запросе --// + + + // Поиск по документу 1 - Да / 0 - Нет + $search = (isset($data['document_in_search']) && $data['document_in_search'] == 1) + ? '1' + : '0'; + + // Если пользователь имеет права на добавление/редактирование документов в указанную рубрику, тогда + if ( + (isset($_SESSION[$row->rubric_id . '_newnow']) && $_SESSION[$row->rubric_id . '_newnow'] == 1) + || + (isset($_SESSION[$row->rubric_id . '_editall']) && $_SESSION[$row->rubric_id . '_editall'] == 1) + || + (isset($_SESSION[$row->rubric_id . '_alles']) && $_SESSION[$row->rubric_id . '_alles'] == 1) + || + (defined('UGROUP') && UGROUP == 1) + ) + { + // Статус документа 1 - Опубликован / 0 - Нет + $data['document_status'] = (isset($data['document_status']) + ? $data['document_status'] + : '0'); + } + else + { + // Не опубликован + $data['document_status'] = '0'; + } + + // Если ID документа равно 1 или ID равно Документа 404 + // то стату всегда будет 1 + $data['document_status'] = ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) + ? '1' + : $data['document_status']; + + // Формируем/проверяем адрес на уникальность + if ($document_id != 1) + { + $data['document_alias'] = $_url = prepare_url(empty($data['document_alias']) + ? trim($_POST['prefix'] . '/' . $data['document_title'], '/') + : $data['document_alias']); + } + // Если ID документа = 1, то алиас не меняем + else + { + $data['document_alias'] = "/"; + } + + $cnt = 1; + + // Проверяем адрес на уникальность, если не уникален + // добавляем число к адресу + while ($AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_documents + WHERE + Id != '" . $document_id . "' + AND + document_alias = '" . $data['document_alias'] . "' + LIMIT 1 + ")->NumRows() == 1) + { + $data['document_alias'] = $_url . '-' . $cnt; + $cnt++; + } + } + // Если оператор INSERT + else + { + // Поиск по документу 1 - Да / 0 - Нет + $search = (isset($data['document_in_search']) && $data['document_in_search'] == 1) + ? '1' + : '0'; + + // Статус документа 1 - Опубликован / 0 - Нет + $data['document_status'] = ! empty($data['document_status']) + ? (int)$data['document_status'] + : '0'; + + // Формируем/проверяем адрес на уникальность + $data['document_alias'] = $_url = prepare_url(empty($data['document_alias']) + ? trim($data['prefix'] . '/' . $data['document_title'], '/') + : $data['document_alias']); + + $cnt = 1; + + // Проверяем адрес на уникальность, если не уникален + // добавляем число к адресу + while ( + $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_documents + WHERE + document_alias = '" . $data['document_alias'] . "' + LIMIT 1 + ")->NumRows() + ) + { + $data['document_alias'] = $_url . '-' . $cnt; + $cnt++; + } + } + + // Если оператор UPDATE, забираем перед сохранением старый алиас документа + if ($oper == 'UPDATE') + { + $data['document_alias_old'] = $AVE_DB->Query(" + SELECT + document_alias + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->GetCell(); + } + else + { + // Если оператор INSERT + // Если новый алиас документа, совпадает с алиасом в истории, просто стираем историю + $AVE_DB->Query(" + DELETE FROM + ". PREFIX . "_document_alias_history + WHERE + document_alias = '" . $data['document_alias'] . "' + "); + } + + // Дата публикации документа + // Для документов с ID = 1 и Ошибки 404, дата не пишется + $data['document_published'] = ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) + ? '0' + : $this->_documentStart($data['document_published']); + + // Дата окончания публикации документа + // Для документов с ID = 1 и Ошибки 404, дата не пишется + $data['document_expire'] = ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) + ? '0' + : $this->_documentEnd($data['document_expire']); + + // Дата изменения документа + $data['document_changed'] = time(); + + // Использовать ли историю алиасов + $data['document_alias_history'] = (empty($data['document_alias_history'])) + ? '0' + : $data['document_alias_history']; + + // Sitemap + $data['document_sitemap_freq'] = ($data['document_sitemap_freq'] != '' + ? (int)$data['document_sitemap_freq'] + : 3); + + // Sitemap + $data['document_sitemap_pr'] = ($data['document_sitemap_pr'] != '' + ? $data['document_sitemap_pr'] + : '0.5'); + + $data['document_linked_navi_id'] = ($data['document_linked_navi_id'] != '' + ? $data['document_linked_navi_id'] + : 0); + + $fields = array(); + + // Получаем структуру документа + if ($oper == 'INSERT') + { + $sql = " + SELECT + * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY + rubric_field_position ASC + "; + } + else + { + $sql = " + SELECT + rub.*, + rubric_field_default, + df.field_value + FROM + " . PREFIX . "_rubric_fields AS rub + LEFT JOIN + " . PREFIX . "_document_fields AS df + ON rubric_field_id = rub.Id + WHERE + document_id = '" . $document_id . "' + ORDER BY + rubric_field_position ASC + "; + } + + $query = $AVE_DB->Query($sql); + + // Если пришел вызов поля, который связан с модулем + if (isset($data['field_module'])) + { + foreach ($data['field_module'] AS $mod_key => $mod_val) + { + require_once(BASE_DIR . '/modules/' . $mod_val . '/document.php'); + + $mod_function = (string)$mod_val . '_document_save'; + + $fields = $mod_function($mod_key, $mod_val, $query, $data['feld'][$mod_key], $mod_key, $rubric_id); + } + } + else + { + while ($row = $query->FetchRow()) + { + $fields[$row->Id] = $row; + } + } + + unset ($sql, $query); + + $where = ($oper == 'UPDATE' ? 'WHERE Id = ' . $document_id : ''); + $author = ($oper != 'UPDATE' ? 'document_author_id = ' . $_SESSION['user_id'] . ',' : ''); + $operator = ($oper == 'UPDATE' ? "UPDATE " . PREFIX . "_documents" : "INSERT INTO " . PREFIX . "_documents"); + + $breadcrumb_title = (isset($data['document_breadcrum_title']) && $data['document_breadcrum_title'] != '') + ? $data['document_breadcrum_title'] + : ''; + + $document_tags = isset($data['document_tags']) + ? $data['document_tags'] + : ''; + + // Сохраняем все параметры документа + $sql = " + $operator + SET + rubric_id = '" . $rubric_id . "', + rubric_tmpl_id = '" . (int)$data['rubric_tmpl_id'] . "', + document_parent = '" . (int)$data['document_parent'] . "', + document_title = '" . htmlspecialchars(clean_no_print_char($data['document_title']), ENT_QUOTES) . "', + document_breadcrum_title = '" . htmlspecialchars(clean_no_print_char($breadcrumb_title), ENT_QUOTES) . "', + document_alias = '" . $data['document_alias'] . "', + document_alias_history = '" . $data['document_alias_history'] . "', + document_published = '" . $data["document_published"] . "', + document_expire = '" . $data["document_expire"] . "', + document_changed = '" . $data["document_changed"] . "', + $author + document_in_search = '" . $search . "', + document_meta_keywords = '" . htmlspecialchars(clean_no_print_char($data['document_meta_keywords']), ENT_QUOTES) . "', + document_meta_description = '" . htmlspecialchars(clean_no_print_char($data['document_meta_description']), ENT_QUOTES) . "', + document_meta_robots = '" . $data['document_meta_robots'] . "', + document_sitemap_freq = '" . $data['document_sitemap_freq'] . "', + document_sitemap_pr = '" . $data['document_sitemap_pr'] . "', + document_status = '" . $data['document_status'] . "', + document_linked_navi_id = '" . (int)$data['document_linked_navi_id'] . "', + document_tags = '" . addslashes(htmlspecialchars(clean_no_print_char($document_tags))). "', + document_lang = '" . (empty($data['document_lang']) ? DEFAULT_LANGUAGE : $data['document_lang']). "', + document_lang_group = '" . (empty($data['document_lang_group']) ? '0' : (int)$data['document_lang_group']). "', + document_position = '" . (empty($data['document_position']) ? '0' : (int)$data['document_position']). "', + document_property = '" . (empty($data['document_property']) ? '' : $data['document_property']). "' + $where + "; + + $AVE_DB->Query($sql); + + // Получаем id добавленной записи + $iid = $AVE_DB->InsertId(); + + // Сохраняем ревизию документа + if ($oper == 'UPDATE' && $revisions) + $this->SaveRevission($document_id); + + // Переназначаем $document_id + $document_id = $_REQUEST['Id'] = ($oper == "INSERT" ? $iid : $document_id); + + //Проверяем алиас на изменения (Старый/Новый) + if ( + $oper == 'UPDATE' + AND $data['document_alias'] != $data['document_alias_old'] + AND ( + ($data['document_alias_history'] == '0' AND $_rubric->rubric_alias_history == '1') + OR + ($data['document_alias_history'] == '1') + ) + AND + ($AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_document_alias_history + WHERE + document_alias = '" . $data['document_alias_old'] . "' + LIMIT 1 + ")->NumRows() == 0) + ) + { + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_document_alias_history + SET + document_id = '" . $document_id . "', + document_alias = '" . $data['document_alias_old'] . "', + document_alias_author = '" . $_SESSION['user_id'] . "', + document_alias_changed = '" . time() . "' + "); + } + + // Сохраняем системное сообщение в журнал + if ($logs) + reportLog(($oper=='INSERT' + ? $AVE_Template->get_config_vars('DOC_SAVE_ADD') + : $AVE_Template->get_config_vars('DOC_SAVE_EDIT')) . $AVE_Template->get_config_vars('DOC_SAVE_LOG_DOC') .' (' . $data['document_title'] . ' Id: ' . $document_id . ')'); + + // Получаем ID полей в данной рубрике + $rubric_fields = $this->_get_rubric_fields($rubric_id); + + // Получаем ID текстовых полей в данном документе + $document_text_fields = $this->_get_document_text_fields($document_id); + + // Собираем запросы в массив + $sql_fields = []; + + // Циклически обрабатываем поля документа + foreach ($fields as $k => $v) + { + $fld_id = $v->Id; + $slash = false; + + // Если в данных нет поля и мы редактируем документ - изменять ли это поле на пустое значение + if ($oper == 'UPDATE' && (! (isset($data['feld'][$fld_id]))) && ! $update_non_exists_fields) + continue; + + $fld_val = (isset($data['feld'][$fld_id]) + ? $data['feld'][$fld_id] + : $v->rubric_field_default); + + /* ------------------------------------------------------------------- */ + + // Если значение поля не является массивом + if (! is_array ($fld_val)) + { + // Если запрещено использование php кода, тогда обнуляем данные поля + if (! check_permission('document_php')) + { + if (is_php_code($fld_val)) + $fld_val = ''; + } + + // Убираем из текста непечатабельные символы + $fld_val = clean_no_print_char($fld_val); + $fld_val = pretty_chars($fld_val); + } + + // Отправляем полученные данные в функцию поля, в раздел "Save" + // для преобразования перед сохранением + $func = 'get_field_' . $rubric_fields[$fld_id]['rubric_field_type']; + + // Если вызывается функция + if (is_callable ($func)) + $fld_val = $func($fld_val, 'save', $fld_id, '', 0, $x, 0, 0, 0); + + //-- Собираем запрос к БД на добавление нового поля с его содержимым --// + + $where = ($oper == 'UPDATE' + ? "WHERE document_id = '" . $document_id . "' AND rubric_field_id = '" . $fld_id . "'" + : ''); + + $operator = ($oper == 'UPDATE' + ? "UPDATE " . PREFIX . "_document_fields" + : "INSERT INTO " . PREFIX . "_document_fields"); + + $insert = ($oper == 'UPDATE' + ? '' + : "rubric_field_id = '" . $fld_id . "', document_id = '" . $document_id . "',"); + + $fval = is_array ($fld_val) + ? serialize ($fld_val) + : $fld_val; + + $substr = 500; + + if (mb_substr($fval, 501, 1)) + $substr = 499; + + // Сохраняем первые 500 символов + $f_val_500 = mb_substr ($fval, 0, $substr); + + // Проверяем чтобы не было в конце слеша - \ + if (mb_substr($f_val_500, 498, 1) == '\\') + $slash = true; + + if ($slash) + $f_val_500 = rtrim ($f_val_500, '\\'); + + $sql_fields[] = " + $operator + SET + $insert + field_value = '" . $f_val_500 . "', + field_number_value = '" . (($rubric_fields[$fld_id]['rubric_field_numeric']) + ? preg_replace ('/[^\d.]/', '', $fld_val) + : 0) . "', + document_in_search = '" . $search . "' + $where + ;"; + + unset ($f_val_500, $fld_val); + + // Если символов больше 500, то сохраняем их в другой таблице + if (mb_strlen($fval) > $substr) + { + // Проверяем есть ли запись о поле в БД + $check_field = false; + + if (in_array ($fld_id, $document_text_fields)) + $check_field = true; + + $operator = ($check_field + ? "UPDATE " . PREFIX . "_document_fields_text" + : "INSERT INTO " . PREFIX . "_document_fields_text" + ); + + $where = ($check_field + ? "WHERE document_id = '" . $document_id . "' AND rubric_field_id = '" . $fld_id . "'" + : ''); + + $insert = ($check_field + ? '' + : "rubric_field_id = '" . $fld_id . "', document_id = '" . $document_id . "',"); + + $f_val_unlim = mb_substr($fval, $substr); + + if ($slash) + $f_val_unlim = '\\' . $f_val_unlim; + + $sql_fields[] = " + $operator + SET + $insert + field_value = '" . $f_val_unlim . "' + $where + ;"; + + unset ($f_val_unlim); + } + // Если символов меньше 500, то чистим поле в другой таблице + else + { + $sql_fields[] = " + DELETE + FROM + ". PREFIX . "_document_fields_text + WHERE + document_id = '" . $document_id . "' + AND + rubric_field_id='" . $fld_id . "' + ;"; + } + } + + // Выполняем + $AVE_DB->Queries($sql_fields); + + unset ($sql_fields); + + $field_module = isset($data['field_module']) + ? $data['field_module'] + : ''; + + // Регистрируем триггер после сохранением + Hooks::register('DocumentAfterSave', 'DocumentAfterSave', 100); + + // Запускаем триггер после сохранения + Hooks::trigger('DocumentAfterSave', $data); + + // Выполняем код рубрики, после сохранения + if ($rubric_code) + eval (' ?'.'>' . $_rubric->rubric_code_end . 'clearDocument($document_id); + + unset ($_rubric, $fields); + + // Дополнительные обработки + if ($generate) + $this->generateKeywords($document_id); + + return $document_id; + } + + /** + * Метод, предназначенный для добавления нового документа в БД + * + * @param int $rubric_id идентификатор Рубрики + */ + function documentNew($rubric_id) + { + global $AVE_DB, $AVE_Rubric, $AVE_Template; + + $this->documentPermissionFetch($rubric_id); + + // Если пользователь имеет права на добавление документов в указанную рубрику, тогда + if ( (isset($_SESSION[$rubric_id . '_newnow']) && $_SESSION[$rubric_id . '_newnow'] == 1) + || (isset($_SESSION[$rubric_id . '_new']) && $_SESSION[$rubric_id . '_new'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1) ) + { + // Поля + $sql = $AVE_DB->Query(" + SELECT + a.*, + b.Id AS group_id, + b.group_title, + b.group_description, + b.group_position + FROM + " . PREFIX . "_rubric_fields AS a + LEFT JOIN + " . PREFIX . "_rubric_fields_group AS b + ON a.rubric_field_group = b.Id + WHERE + a.rubric_id = '" . $rubric_id . "' + ORDER BY + b.group_position ASC, + a.rubric_field_position ASC + "); + + $fields_list = array(); + + while ($row = $sql->FetchRow()) + { + $group_id = ($row->rubric_field_group) ? $row->rubric_field_group : 0; + + $fields_list[$group_id]['group_id'] = $row->group_id; + $fields_list[$group_id]['group_position'] = ($row->group_position) ? $row->group_position : 100; + $fields_list[$group_id]['group_title'] = $row->group_title; + $fields_list[$group_id]['group_description'] = $row->group_description; + $fields_list[$group_id]['fields'][$row->Id]['Id'] = $row->Id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_id'] = $row->rubric_id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_title'] = $row->rubric_field_title; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_description'] = $row->rubric_field_description; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_default'] = $row->rubric_field_default; + $fields_list[$group_id]['fields'][$row->Id]['result'] = $this->_documentFieldGet($row->rubric_field_type, $row->rubric_field_default, $row->Id, $row->rubric_field_default); + } + + $fields_list = msort($fields_list, 'group_position'); + + $AVE_Template->assign('groups_count', count($fields_list)); + $AVE_Template->assign('fields_list', $fields_list); + + // Группы полей + $fields_groups = array(); + + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_rubric_fields_group + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY + group_position ASC + "); + + while ($row = $sql->FetchRow()) + { + array_push($fields_groups, $row); + } + + $AVE_Template->assign('fields_groups', $fields_groups); + + // Определяем вид действия, переданный в параметре sub + switch ($_REQUEST['sub']) + { + case 'save': // Сохранение документа в БД + + $public_start = $this->_documentStart(); // Дата/время начала публикации документа + $public_end = $this->_documentEnd(); // Дата/время окончания публикации документа + + $innavi = check_permission_acp('navigation_new') ? '&innavi=1' : ''; + + // Определяем статус документа + $document_status = ! empty($_REQUEST['document_status']) + ? (int)$_REQUEST['document_status'] + : '0'; + + // Если статус документа не определен + if (empty($document_status) && $_SESSION['user_group'] != 1) + { + $innavi = ''; + @reset($_POST); + $newtext = "\n\n"; + + // Формируем текст сообщения, состоящий из данных, + // которые пользователь ввел в поля документа + foreach ($_POST['feld'] as $val) + { + if (! empty($val)) + { + $newtext .= $val; + $newtext .= "\n---------------------\n"; + } + } + + $text = strip_tags($newtext); + + // Получаем e-mail адрес из общих настроек системы + $system_mail = get_settings('mail_from'); + $system_mail_name = get_settings('mail_from_name'); + + // Отправляем администартору уведомление, о том что необходимо проверить документ + $body_to_admin = $AVE_Template->get_config_vars('DOC_MAIL_BODY_CHECK'); + $body_to_admin = str_replace('%N%', "\n", $body_to_admin); + $body_to_admin = str_replace('%TITLE%', stripslashes($_POST['document_title']), $body_to_admin); + $body_to_admin = str_replace('%USER%', "'" . $_SESSION['user_name'] . "'", $body_to_admin); + + send_mail( + $system_mail, + $body_to_admin . $text, + $AVE_Template->get_config_vars('DOC_MAIL_SUBJECT_CHECK'), + $system_mail, + $system_mail_name, + 'text' + ); + + // Отправляем уведомление автору, о том что документ находится на проверке + $body_to_author = str_replace('%N%', "\n", $AVE_Template->get_config_vars('DOC_MAIL_BODY_USER')); + $body_to_author = str_replace('%TITLE%', stripslashes($_POST['document_title']), $body_to_author); + $body_to_author = str_replace('%USER%', "'" . $_SESSION['user_name'] . "'", $body_to_author); + send_mail( + $_SESSION['user_email'], + $body_to_author, + $AVE_Template->get_config_vars('DOC_MAIL_SUBJECT_USER'), + $system_mail, + $system_mail_name, + 'text' + ); + } + + if (! ((isset($_SESSION[$rubric_id . '_newnow']) && $_SESSION[$rubric_id . '_newnow'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1)) ) + { + $document_status = 0; + } + + $_POST['document_status'] = $document_status; + + $iid = $this->documentSave($rubric_id, null, $_POST, true); + + if ($_REQUEST['doc_after']) + header('Location:index.php?do=docs&action=after&document_id=' . $iid . '&rubric_id=' . $rubric_id . '&cp=' . SESSION . $innavi); + else + header('Location:index.php?do=docs&action=edit&Id=' . $iid . '&rubric_id=' . $rubric_id . '&cp=' . SESSION); + exit; + + case '': // Действия по умолчанию, если не задано + $document = new stdClass(); + + // Получаем список прав доступа на добавление документов в определенную рубрику + $this->documentPermissionFetch($rubric_id); + + // Определяем флаг, который будет активировать или запрещать смену статуса у документа + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (isset($_SESSION[$rubric_id . '_newnow']) && $_SESSION[$rubric_id . '_newnow'] == 1) ) + { + $document->dontChangeStatus = 0; + } + else + { + $document->dontChangeStatus = 1; + } + + $maxId = $AVE_DB->Query(" + SELECT + MAX(Id) + FROM + " . PREFIX . "_documents + ")->GetCell(); + + // получения списка документов из связанной рубрики + $linked_id = $AVE_DB->Query(" + SELECT + rubric_linked_rubric + FROM + " . PREFIX . "_rubrics + WHERE + Id = '".$rubric_id."' + ")->GetCell(); + + $linked_id = @unserialize($linked_id); + + $document_alias = array(); + + if ($linked_id) + { + foreach ($linked_id as $linked_id) + { + $sql = $AVE_DB->Query(" + SELECT + doc.document_alias, + doc.document_title, + doc.document_breadcrum_title, + doc.Id, + rub.rubric_title + FROM + " . PREFIX . "_documents as doc + JOIN + " . PREFIX . "_rubrics as rub + ON rub.Id = doc.rubric_id + WHERE + doc.rubric_id = '".$linked_id."' + "); + + while ($row = $sql->FetchRow()) + { + $document_alias[$row->rubric_title][] = array( + 'document_alias' => $row->document_alias, + 'document_title' => $row->document_title, + 'document_breadcrum_title' => $row->document_breadcrum_title, + 'Id' => $row->Id + ); + } + } + } + + // получения списка документов из связанной рубрики + $AVE_Template->assign('document_alias', $document_alias); + + $lang_pack = array(); + + if (! empty($_REQUEST['lang_pack'])) + { + $sql1 = $AVE_DB->Query(" + SELECT + Id, + rubric_id, + document_alias, + document_lang, + document_status + FROM + ".PREFIX."_documents + WHERE + document_lang_group=".intval($_REQUEST['lang_pack'])." OR Id=".intval($_REQUEST['lang_pack'])); + + while ($row1 = $sql1->FetchAssocArray()) + { + $lang_pack[$row1['document_lang']] = $row1; + + if ($row1['Id'] == intval($_REQUEST['lang_pack'])) + $document->document_alias=$_REQUEST['lang'].'/'.trim(ltrim($row1['document_alias'], $row1['document_lang']), '/'); + } + } + + // Формируем данные и передаем в шаблон + $document->lang_pack=$lang_pack; + $document->fields = $fields_list; + $document->rubric_title = $AVE_Rubric->rubricNameByIdGet($rubric_id)->rubric_title; + $document->rubric_url_prefix = strftime(str_ireplace("%id", $maxId+1, $AVE_Rubric->rubricNameByIdGet($rubric_id)->rubric_alias)); + $document->formaction = 'index.php?do=docs&action=new&sub=save&rubric_id=' . $rubric_id . ((isset($_REQUEST['pop']) && $_REQUEST['pop']==1) ? 'pop=1' : '') . '&cp=' . SESSION; + $document->count_groups = count($fields_list); + $document->document_published = time(); + $document->document_expire = mktime(date("H"), date("i"), 0, date("m"), date("d"), date("Y") + 10); + + $rubric_tmpls = array(); + + $sql = $AVE_DB->Query(" + SELECT + id, + title + FROM + " . PREFIX . "_rubric_templates + WHERE + rubric_id = '" . $rubric_id . "' + "); + + while ($row = $sql->FetchRow()) + { + array_push($rubric_tmpls, $row); + } + + // Доступные шаблоны рубрики + $AVE_Template->assign('rubric_tmpls', $rubric_tmpls); + + $AVE_Template->assign('document', $document); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/form.tpl')); + break; + } + } + else + { // Пользователь не имеет прав на создание документа, формируем сообщение с ошибкой + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('DOC_NO_PERMISSION_RUB')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + } + + /** + * Метод, предназначенный для редактирования документа + * + * @param int $document_id идентификатор Документа + */ + function documentEdit($document_id) + { + global $AVE_DB, $AVE_Rubric, $AVE_Template; + + // Определяем действие, выбранное пользователем + switch ($_REQUEST['sub']) + { + // Если была нажата кнопка Сохранить изменения + case 'save': + + $row = $AVE_DB->Query(" + SELECT + rubric_id, + document_author_id + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + $this->documentSave($row->rubric_id, $document_id, $_POST, true); + + if (isset($_REQUEST['closeafter']) && $_REQUEST['closeafter'] == 1) + { + if (! isAjax()) + { + echo ""; + } + else + { + $message = $AVE_Template->get_config_vars('DOCUMENT_SAVED'); + $header = $AVE_Template->get_config_vars('DOC_REV_SUCCESS'); + $theme = 'accept'; + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + } + else + { + + if (! isAjax()) + { + header('Location:index.php?do=docs&action=after&document_id=' . $document_id . '&rubric_id=' . $row->rubric_id . '&cp=' . SESSION); + } + else + { + $message = $AVE_Template->get_config_vars('DOCUMENT_SAVED'); + $header = $AVE_Template->get_config_vars('DOC_REV_SUCCESS'); + $theme = 'accept'; + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + } + exit; + + // Если пользователь не выполнял никаких действий, а просто открыл документ для редактирования + case '': + // Выполняем запрос к БД на получение данных о документе + $document = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + // Проверяем, был ли найден документ + if ($document === null) { + header('Location:index.php?do=docs&rubric_id=' . $rubric_id . '&cp=' . SESSION); + exit; + } + + $lang_pack = array(); + + $sql = $AVE_DB->Query(" + SELECT + Id, + document_alias, + document_lang, + document_lang_group, + document_status + FROM + ".PREFIX."_documents + WHERE + ". ($document->document_lang_group > 0 + ? "document_lang_group = ".$document->document_lang_group." OR Id = ".$document->document_lang_group." OR " + : "")."document_lang_group = ".$document_id." OR Id = ".$document_id + ); + + while ($row = $sql->FetchAssocArray()) + { + $lang_pack[$row['document_lang']] = $row; + } + + $document->lang_pack = $lang_pack; + + $show = true; + + // Проверяем права доступа к документу + $this->documentPermissionFetch($document->rubric_id); + + // запрещаем доступ, + // если автору документа не разрешено изменять свои документы в рубрике + // или пользователю не разрешено изменять все документы в рубрике + if (!( (isset($_SESSION['user_id']) && $document->document_author_id == $_SESSION['user_id'] + && isset($_SESSION[$document->rubric_id . '_editown']) && $_SESSION[$document->rubric_id . '_editown'] == 1) + || (isset($_SESSION[$document->rubric_id . '_editall']) && $_SESSION[$document->rubric_id . '_editall'] == 1))) + { + $show = false; + } + + // запрещаем доступ к главной странице и странице ошибки 404, если требуется одобрение Администратора + if ( ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) && + !(isset($_SESSION[$document->rubric_id . '_editall']) && $_SESSION[$document->rubric_id . '_editall'] == 1) ) + { + $show = false; + } + + // разрешаем доступ, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) ) + { + $show = true; + } + + if ($show) + { + $fields = array(); + + if ( + (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$document->rubric_id . '_newnow']) && $_SESSION[$document->rubric_id . '_newnow'] == 1) + || (isset($_SESSION[$document->rubric_id . '_editall']) && $_SESSION[$document->rubric_id . '_editall'] == 1) + || (isset($_SESSION[$document->rubric_id . '_editown']) && $_SESSION[$document->rubric_id . '_editown'] == 1) + || (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) + ) + { + $document->dontChangeStatus = 0; + } + else + { + $document->dontChangeStatus = 1; + } + + // Выполняем запрос к БД на получение списка полей, которые относятся к данному документу + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $document->rubric_id . "' + ORDER BY + rubric_field_position ASC + "); + + // не парсим поля, просто создаём контрольный массив полей + while ($row = $sql->FetchRow()) + { + $fields[$row->Id] = $row; + } + + $doc_fields = array(); + + // Выполняем запрос к БД и получаем все данные для полей документа + $sql = $AVE_DB->Query(" + SELECT + doc.Id AS df_id, + `groups`.*, + groups.Id AS group_id, + rub.*, + rubric_field_default, + rubric_field_alias, + doc.field_value, + field_more.field_value as field_value_more + FROM + " . PREFIX . "_rubric_fields AS rub + LEFT JOIN + " . PREFIX . "_rubric_fields_group AS `groups` + ON rub.rubric_field_group = groups.Id + LEFT JOIN + " . PREFIX . "_document_fields AS doc + ON (rubric_field_id = rub.Id) + LEFT JOIN + " . PREFIX . "_document_fields_text AS field_more + ON (field_more.rubric_field_id = doc.rubric_field_id AND doc.document_id=field_more.document_id) + WHERE + doc.document_id = '" . $document_id . "' + ORDER BY + groups.group_position ASC, rub.rubric_field_position ASC + "); + + // записываем массив с полями документа + while ($row = $sql->FetchRow()) + { + $row->field_value = (string)$row->field_value . (string)$row->field_value_more; + $row->field = $this->_documentFieldGet($row->rubric_field_type, $row->field_value, $row->Id, $row->rubric_field_default); + + $doc_fields[$row->Id] = $row; + } + + // для каждого поля из контрольного массива... + foreach ($fields as $field_id => $row) + { + // если в документе поле есть, то записываем его + if ($doc_fields[$field_id]) + { + $fields[$field_id] = $doc_fields[$field_id]; + } + + // если нет, парсим чистое поле и добавляем в бд + else + { + $row->field = $this->_documentFieldGet($row->rubric_field_type, $row->rubric_field_default, $row->Id, $row->rubric_field_default); + + $fields[$field_id] = $row; + + $AVE_DB->Query(" + INSERT INTO " . PREFIX . "_document_fields + SET + rubric_field_id = '" . $field_id . "', + document_id = '" . $document->Id . "' + "); + } + } + + foreach ($fields as $field) + { + $group_id = ($field->rubric_field_group) ? $field->rubric_field_group : 0; + $fields_list[$group_id]['group_id'] = $field->group_id; + $fields_list[$group_id]['group_position'] = ($field->group_position) ? $field->group_position : 100; + $fields_list[$group_id]['group_title'] = $field->group_title; + $fields_list[$group_id]['fields'][$field->Id]['Id'] = $field->Id; + $fields_list[$group_id]['fields'][$field->Id]['rubric_id'] = $row->rubric_id; + $fields_list[$group_id]['fields'][$field->Id]['rubric_field_title'] = $field->rubric_field_title; + $fields_list[$group_id]['fields'][$field->Id]['rubric_field_alias'] = $field->rubric_field_alias; + $fields_list[$group_id]['fields'][$field->Id]['rubric_field_description'] = $field->rubric_field_description; + $fields_list[$group_id]['fields'][$field->Id]['result'] = $field->field; + } + + $fields_list = msort($fields_list, 'group_position'); + + unset($doc_fields); + unset($fields); + + // Заглушка на время публикации + $document->document_published = ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) ? '0' : $document->document_published = $document->document_published == 0 ? time() : $document->document_published; + $document->document_expire = ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) ? '0' : $document->document_expire = $document->document_expire == 0 ? mktime(date("H"), date("i"), 0, date("m"), date("d"), date("Y") + 10) : $document->document_expire; + + // Формируем ряд переменных и передаем их в шаблон для вывода + $document->fields = $fields_list; + $document->count_groups = count($fields_list); + $document->document_title = htmlspecialchars_decode(stripslashes(html_entity_decode($document->document_title))); + $document->document_meta_keywords = htmlspecialchars_decode(stripslashes(html_entity_decode($document->document_meta_keywords))); + $document->document_meta_description = htmlspecialchars_decode(stripslashes(html_entity_decode($document->document_meta_description))); + $document->document_breadcrum_title = htmlspecialchars_decode(stripslashes(html_entity_decode($document->document_breadcrum_title))); + $document->document_alias_breadcrumb = rewrite_link('index.php?id=' . $document->Id . '&doc=' . (empty($document->document_alias) ? prepare_url($document->document_title) : $document->document_alias)); + $document->rubric_title = $AVE_Rubric->rubricNameByIdGet($document->rubric_id)->rubric_title; + $document->rubric_url_prefix = $AVE_Rubric->rubricNameByIdGet($document->rubric_id)->rubric_alias; + $document->formaction = 'index.php?do=docs&action=edit&sub=save&Id=' . $document_id . '&cp=' . SESSION; + + if ($document->document_parent != 0) $document->parent = $AVE_DB->Query("SELECT document_alias, document_title, Id FROM " . PREFIX . "_documents WHERE Id = '".$document->document_parent."' ")->FetchRow(); + + $document_rev = array(); + + if ( (isset($_SESSION[$document->rubric_id . '_delrev']) && $_SESSION[$document->rubric_id . '_delrev'] == 1) + || (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1) ) + { + $document->canDelRev = 1; + } + + $sql_rev = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_document_rev + WHERE + doc_id = '" . $document_id . "' + ORDER BY + doc_revision DESC + LIMIT 7 + "); + + // Формируем массив из полученных данных + while ($result = $sql_rev->FetchRow()) + { + $result->user_id = get_username_by_id($result->user_id); + array_push($document_rev, $result); + } + + $AVE_Template->assign('document_rev', $document_rev); + + // получения списка документов из связанной рубрики + $linked_id = $AVE_DB->Query(" + SELECT + rubric_linked_rubric + FROM + " . PREFIX . "_rubrics + WHERE + Id = '".$document->rubric_id."' + ")->GetCell(); + + @$linked_id = unserialize($linked_id); + + $document_alias = array(); + + if ($linked_id) + { + foreach ($linked_id as $linked_id) + { + $sql = $AVE_DB->Query(" + SELECT + doc.document_alias, + doc.document_title, + doc.document_breadcrum_title, + doc.Id, + rub.rubric_title + FROM + " . PREFIX . "_documents as doc + JOIN + " . PREFIX . "_rubrics as rub + ON rub.Id = doc.rubric_id + WHERE + doc.rubric_id = '" . $linked_id . "' + "); + + while ($row = $sql->FetchRow()) + { + $document_alias[$row->rubric_title][] = array( + 'document_alias'=>$row->document_alias, + 'document_title'=>htmlspecialchars_decode(stripslashes(html_entity_decode($row->document_title))), + 'document_breadcrum_title'=>htmlspecialchars_decode(stripslashes(html_entity_decode($row->document_breadcrum_title))), + 'Id'=>$row->Id + ); + } + } + } + + $rubric_tmpls = array(); + + $sql = $AVE_DB->Query(" + SELECT + id, + title + FROM + " . PREFIX . "_rubric_templates + WHERE + rubric_id = '" . $document->rubric_id . "' + "); + + while ($row = $sql->FetchRow()) + { + array_push($rubric_tmpls, $row); + } + + // Доступные шаблоны рубрики + $AVE_Template->assign('rubric_tmpls', $rubric_tmpls); + + // получения списка документов из связанной рубрики + $AVE_Template->assign('document_alias', $document_alias); + + $AVE_Template->assign('document', $document); + + // Отображаем страницу для редактирования + $AVE_Template->assign('content', $AVE_Template->fetch('documents/form.tpl')); + } + else // Если пользователь не имеет прав на редактирование, формируем сообщение об ошибке + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('DOC_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + } + } + + + /** + * Метод, предназначенный для копирования документа + * + * @param int $document_id идентификатор Документа + */ + function documentCopy ($document_id) + { + global $AVE_DB, $AVE_Rubric, $AVE_Template; + + // Определяем действие, выбранное пользователем + switch ($_REQUEST['sub']) + { + // Если была нажата кнопка Сохранить изменения + case 'save': // Сохранение документа в БД + $public_start = $this->_documentStart(); // Дата/время начала публикации документа + $public_end = $this->_documentEnd(); // Дата/время окончания публикации документа + + $rubric_id = $_REQUEST['rubric_id']; + + $innavi = check_permission_acp('navigation_new') + ? '&innavi=1' + : ''; + + // Определяем статус документа + $document_status = ! empty($_REQUEST['document_status']) + ? (int)$_REQUEST['document_status'] + : '0'; + + // Если статус документа не определен + if (empty($document_status) && $_SESSION['user_group'] != 1) + { + $innavi = ''; + + @reset($_POST); + + $newtext = "\n\n"; + + // Формируем текст сообщения, состоящий из данных, + // которые пользователь ввел в поля документа + foreach ($_POST['feld'] as $val) + { + if (!empty($val)) + { + $newtext .= $val; + $newtext .= "\n---------------------\n"; + } + } + + $text = strip_tags($newtext); + + // Получаем e-mail адрес из общих настроек системы + $system_mail = get_settings('mail_from'); + $system_mail_name = get_settings('mail_from_name'); + + // Отправляем администартору уведомление, о том что необходимо проверить документ + $body_to_admin = $AVE_Template->get_config_vars('DOC_MAIL_BODY_CHECK'); + $body_to_admin = str_replace('%N%', "\n", $body_to_admin); + $body_to_admin = str_replace('%TITLE%', stripslashes($_POST['document_title']), $body_to_admin); + $body_to_admin = str_replace('%USER%', "'" . $_SESSION['user_name'] . "'", $body_to_admin); + + send_mail( + $system_mail, + $body_to_admin . $text, + $AVE_Template->get_config_vars('DOC_MAIL_SUBJECT_CHECK'), + $system_mail, + $system_mail_name, + 'text' + ); + + // Отправляем уведомление автору, о том что документ находится на проверке + $body_to_author = str_replace('%N%', "\n", $AVE_Template->get_config_vars('DOC_MAIL_BODY_USER')); + $body_to_author = str_replace('%TITLE%', stripslashes($_POST['document_title']), $body_to_author); + $body_to_author = str_replace('%USER%', "'" . $_SESSION['user_name'] . "'", $body_to_author); + + send_mail( + $_SESSION['user_email'], + $body_to_author, + $AVE_Template->get_config_vars('DOC_MAIL_SUBJECT_USER'), + $system_mail, + $system_mail_name, + 'text' + ); + } + + if (! ((isset($_SESSION[$rubric_id . '_newnow']) && $_SESSION[$rubric_id . '_newnow'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1)) ) + { + $document_status = 0; + } + + $_POST['document_status'] = $document_status; + + $iid = $this->documentSave($_REQUEST['rubric_id'],null, $_POST,true); + + if (! $_REQUEST['next_edit']) + { + header('Location:index.php?do=docs&action=after&document_id=' . $iid . '&rubric_id=' . $rubric_id . '&cp=' . SESSION . $innavi); + } + else + { + header('Location:index.php?do=docs&action=edit&Id=' . $iid . '&rubric_id=' . $rubric_id . '&cp=' . SESSION); + } + + exit; + + // Если пользователь не выполнял никаких действий, а просто открыл документ для копирования + // Если пользователь не выполнял никаких действий, а просто открыл документ для редактирования + case '': + // Выполняем запрос к БД на получение данных о документе + $document = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + $show = true; + + // Проверяем права доступа к документу + $this->documentPermissionFetch($document->rubric_id); + + // запрещаем доступ, + // если автору документа не разрешено изменять свои документы в рубрике + // или пользователю не разрешено изменять все документы в рубрике + if (!( (isset($_SESSION['user_id']) && $document->document_author_id == $_SESSION['user_id'] + && isset($_SESSION[$document->rubric_id . '_editown']) && $_SESSION[$document->rubric_id . '_editown'] == 1) + || (isset($_SESSION[$document->rubric_id . '_editall']) && $_SESSION[$document->rubric_id . '_editall'] == 1))) + { + $show = false; + } + + // запрещаем доступ к главной странице и странице ошибки 404, если требуется одобрение Администратора + if ( ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) && + !(isset($_SESSION[$document->rubric_id . '_newnow']) && $_SESSION[$document->rubric_id . '_newnow'] == 1) ) + { + $show = false; + } + + // разрешаем доступ, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) ) + { + $show = true; + } + + if ($show) + { + $fields = array(); + + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$document->rubric_id . '_newnow']) && $_SESSION[$document->rubric_id . '_newnow'] == 1) ) + { + $document->dontChangeStatus = 0; + } + else + { + $document->dontChangeStatus = 1; + } + + // Выполняем запрос к БД и получаем все данные для полей документа + $sql = $AVE_DB->Query(" + SELECT + doc.Id AS df_id, + `groups`.*, + rub.*, + rubric_field_default, + doc.field_value, + field_more.field_value as field_value_more + FROM + " . PREFIX . "_rubric_fields AS rub + LEFT JOIN + " . PREFIX . "_rubric_fields_group AS `groups` + ON rub.rubric_field_group = groups.Id + LEFT JOIN + " . PREFIX . "_document_fields AS doc + ON (rubric_field_id = rub.Id) + LEFT JOIN + " . PREFIX . "_document_fields_text AS field_more + ON (field_more.rubric_field_id = doc.rubric_field_id AND doc.document_id=field_more.document_id) + WHERE + doc.document_id = '" . $document_id . "' + ORDER BY + groups.group_position ASC, rub.rubric_field_position ASC + "); + + while ($row = $sql->FetchRow()) + { + $row->field_value = (string)$row->field_value . (string)$row->field_value_more; + $row->field = $this->_documentFieldGet($row->rubric_field_type, $row->field_value, $row->Id, $row->rubric_field_default); + array_push($fields, $row); + } + + $maxId = $AVE_DB->Query(" + SELECT + MAX(Id) + FROM + " . PREFIX . "_documents + ")->GetCell(); + + foreach ($fields as $field) + { + $group_id = ($field->rubric_field_group) ? $field->rubric_field_group : 0; + + $fields_list[$group_id]['group_position'] = ($field->group_position) ? $field->group_position : 100; + $fields_list[$group_id]['group_title'] = $field->group_title; + $fields_list[$group_id]['fields'][$field->Id]['Id'] = $field->Id; + $fields_list[$group_id]['fields'][$field->Id]['rubric_id'] = $row->rubric_id; + $fields_list[$group_id]['fields'][$field->Id]['rubric_field_title'] = $field->rubric_field_title; + $fields_list[$group_id]['fields'][$field->Id]['rubric_field_description'] = $field->rubric_field_description; + $fields_list[$group_id]['fields'][$field->Id]['result'] = $field->field; + } + + $fields_list = msort($fields_list, 'group_position'); + + unset($doc_fields); + unset($fields); + + // Формируем ряд переменных и передаем их в шаблон для вывода + $document->fields = $fields_list; + $document->count_groups = count($fields_list); + $document->document_alias = ''; + $document->rubric_title = $AVE_Rubric->rubricNameByIdGet($_REQUEST['rubric_id'])->rubric_title; + $document->rubric_url_prefix = strftime(str_ireplace("%id", $maxId+1, $AVE_Rubric->rubricNameByIdGet($_REQUEST['rubric_id'])->rubric_alias)); + $document->formaction = 'index.php?do=docs&action=copy&sub=save&rubric_id=' . $_REQUEST['rubric_id'] . ((isset($_REQUEST['pop']) && $_REQUEST['pop']==1) ? 'pop=1' : '') . '&cp=' . SESSION; + $document->document_published = time(); + $document->document_expire = mktime(date("H"), date("i"), 0, date("m"), date("d"), date("Y") + 10); + + if ($document->document_parent != 0) + $document->parent = $AVE_DB->Query("SELECT document_title, Id FROM " . PREFIX . "_documents WHERE Id = '" . $document->document_parent . "' ")->FetchRow(); + + $AVE_Template->assign('document', $document); + + // Отображаем страницу для редактирования + $AVE_Template->assign('content', $AVE_Template->fetch('documents/form.tpl')); + } + else // Если пользователь не имеет прав на редактирование, формируем сообщение об ошибке + { + $AVE_Template->assign('erorr', $AVE_Template->get_config_vars('DOC_NO_PERMISSION')); + $AVE_Template->assign('content', $AVE_Template->fetch('error.tpl')); + } + break; + } + } + + /** + * Метод, предназначенный для пометки документа к удалению + * + * @param int $document_id идентификатор Документа + */ + function documentMarkDelete($document_id) + { + global $AVE_DB; + + // Выполняем запрос к БД на получение информации о документе (id, id рубрики, автор) + $row = $AVE_DB->Query(" + SELECT + Id, + rubric_id, + document_alias, + document_author_id + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + // Если у пользователя достаточно прав на выполнение данной операции + if ( + (isset($_SESSION[$row->rubric_id . '_editall']) && $_SESSION[$row->rubric_id . '_editall'] == 1) + || + (isset($_SESSION[$row->rubric_id . '_editown']) && $_SESSION[$row->rubric_id . '_editown'] == 1) + || + (isset($_SESSION[$row->rubric_id . '_alles']) && $_SESSION[$row->rubric_id . '_alles'] == 1) + || + (defined('UGROUP') && UGROUP == 1) + ) + { + // и это не главная страница и не страница с ошибкой 404 + if ($document_id != 1 && $document_id != PAGE_NOT_FOUND_ID) + { + // Выполняем запрос к БД на обновление данных (пометка на удаление) + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_deleted = '1' + WHERE + Id = '" . $document_id . "' + "); + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + // Сохраняем системное сообщение в журнал + reportLog('Положил документ в корзину (' . $document_id . ')'); + } + } + + // Выполняем обновление страницы + header('Location:index.php?do=docs'.(empty($_REQUEST['rubric_id']) ? '' : '&rubric_id='.$_REQUEST['rubric_id']).'&cp=' . SESSION); + } + + /** + * Метод, предназначенный для снятия отметки об удаления + * + * @param int $document_id идентификатор Документа + */ + function documentUnmarkDelete($document_id) + { + global $AVE_DB; + + // Выполняем запрос к БД на обновление информации (снятие отметки об удалении) + $row = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_deleted = '0' + WHERE + Id = '" . $document_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog('Восстановил удаленный документ (' . $document_id . ')'); + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + // Выполняем обновление страницы + header('Location:index.php?do=docs'.(empty($_REQUEST['rubric_id']) ? '' : '&rubric_id='.$_REQUEST['rubric_id']).'&cp=' . SESSION); + } + + /** + * Метод, предназначенный для полного удаления документа без возможности восстановления + * + * @param int $document_id идентификатор Документа + */ + function documentDelete($document_id) + { + global $AVE_DB; + + // Проверяем, чтобы удаляемый документ не являлся главной страницей и не страницей с 404 ощибкой + if ($document_id != 1 && $document_id != PAGE_NOT_FOUND_ID) + { + $row = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + // Выполняем запрос к БД на удаление информации о документе + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ;"); + + // Выполняем запрос к БД на удаление полей, которые относились к документу + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_document_fields + WHERE + document_id = '" . $document_id . "' + ;"); + + // Выполняем запрос к БД на удаление полей, которые относились к документу + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_document_fields_text + WHERE + document_id = '" . $document_id . "' + ;"); + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + // Сохраняем системное сообщение в журнал + reportLog('Удалил документ '. $row->document_title . ' (ID: ' . $document_id . ')'); + } + + // Выполняем обновление страницы + header('Location:index.php?do=docs'.(empty($_REQUEST['rubric_id']) + ? '' + : '&rubric_id='.$_REQUEST['rubric_id']).'&cp=' . SESSION); + } + + /** + * Метод, предназначенный для публикации или отмены публикации документа + * + * @param int $document_id идентификатор Документа + * @param string $openclose статус Документа {open|close} + */ + function documentStatusSet($document_id, $openclose = 0) + { + global $AVE_DB, $AVE_Template; + + $errors = array(); + + $show = true; + + // Выполняем запрос к БД на получение информации о документе (id, id рубрики, автор) + $document = $AVE_DB->Query(" + SELECT + Id, + rubric_id, + document_alias, + document_author_id + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + ")->FetchRow(); + + // Проверяем права доступа к документу + $this->documentPermissionFetch($document->rubric_id); + + // запрещаем доступ, + // если автору документа не разрешено изменять свои документы в рубрике + // или пользователю не разрешено изменять все документы в рубрике + if (! + ( + (isset($_SESSION[$document->rubric_id . '_editall']) && $_SESSION[$document->rubric_id . '_editall'] == 1) + || + (isset($_SESSION[$document->rubric_id . '_editown']) && $_SESSION[$document->rubric_id . '_editown'] == 1) + || + (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) + || + (defined('UGROUP') && UGROUP == 1) + ) + ) + { + $show = false; + } + + // запрещаем доступ к главной странице и странице ошибки 404, если требуется одобрение Администратора + if ( ($document_id == 1 || $document_id == PAGE_NOT_FOUND_ID) && + !(isset($_SESSION[$document->rubric_id . '_newnow']) && $_SESSION[$document->rubric_id . '_newnow'] == 1) ) + { + $show = false; + } + + // разрешаем доступ, если пользователь принадлежит группе Администраторов или имеет все права на рубрику + if ( (defined('UGROUP') && UGROUP == 1) + || (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) ) + { + $show = true; + } + + if ($show) + { + // Выполняем запрос к БД на получение id автора документа, чтобы проверить уровень прав доступа + + // Проверем, чтобы у пользователя было достаточно прав на выполнение данной операции + if ( + ( + ($document->document_author_id == @$_SESSION['user_id']) + && + (isset($_SESSION[$document->rubric_id . '_newnow']) && @$_SESSION[$document->rubric_id . '_newnow'] == 1) + || + @$_SESSION[$document->rubric_id . '_alles'] == 1 + || + (defined('UGROUP') && UGROUP == 1) + ) + || + (isset($_SESSION[$document->rubric_id . '_editall']) && $_SESSION[$document->rubric_id . '_editall'] == 1) + || + (isset($_SESSION[$document->rubric_id . '_editown']) && $_SESSION[$document->rubric_id . '_editown'] == 1) + || + (isset($_SESSION[$document->rubric_id . '_alles']) && $_SESSION[$document->rubric_id . '_alles'] == 1) + || + (defined('UGROUP') && UGROUP == 1) + ) + { + // Если это не главная страница и не страница с 404 ошибкой + if ($document_id != 1 && $document_id != PAGE_NOT_FOUND_ID) + { + // Выполянем запрос к БД на смену статуса у документа + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_status = '" . $openclose . "' + WHERE + Id = '" . $document_id . "' + "); + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + // Сохраняем системное сообщение в журнал + reportLog($_SESSION['user_name'] . ' - ' . (($openclose==1) ? $AVE_Template->get_config_vars('DOC_DOCUMENT_ACT') : $AVE_Template->get_config_vars('DOC_DOCUMENT_DISACT')) . ' ' . $AVE_Template->get_config_vars('DOC_DOCUMENT_DOC') . ' (' . $document_id . ')', 2, 2); + + } + else + { + $errors[] = $AVE_Template->get_config_vars('DOC_DOCUMENT_OPEN_ERR'); + } + + } + else + { + $errors[] = $AVE_Template->get_config_vars('DOC_DOCUMENT_OPEN_PRIVE'); + } + + if (isset($_REQUEST['ajax'])) + { + if (empty($errors)) + { + // Если ошибок не найдено, формируем сообщение об успешной операции + echo json_encode(array((($openclose==1) ? $AVE_Template->get_config_vars('DOC_DOCUMENT_OPEN') : $AVE_Template->get_config_vars('DOC_DOCUMENT_CLOSE')) . implode(',
      ', $errors), 'accept')); + } + else + { + // В противном случае формируем сообщение с ошибкой + echo json_encode(array($AVE_Template->get_config_vars('DOC_URL_CHECK_ER') . implode(',
      ', $errors), 'error')); + + } + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + exit; + + } + else + { + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + // Выполняем обновление страницы + header('Location:index.php?do=docs'.(empty($_REQUEST['rubric_id']) ? '' : '&rubric_id='.$_REQUEST['rubric_id']).'&cp=' . SESSION); + exit; + } + } + else + { + header('Location:index.php?do=docs&cp=' . SESSION); + exit; + } + } + + /** + * Метод, предназначенный для передачи в Smarty шаблонизатор меток периода времени отображаемых + * в списке документов + * + */ + function documentTemplateTimeAssign() + { + global $AVE_Template; + + if (!empty($_REQUEST['TimeSelect'])) + { + $AVE_Template->assign('sel_start', $this->_documentListStart()); + $AVE_Template->assign('sel_end', $this->_documentListEnd()); + } + } + + /** + * Метод, предназначенный для переноса документа в другую рубрику + * + */ + function documentRubricChange() + { + global $AVE_DB, $AVE_Template; + + $document_id = (int)$_REQUEST['Id']; // идентификатор документа + $rubric_id = (int)$_REQUEST['rubric_id']; // идентификатор текущей рубрики + + // Если в запросе пришел идентификатор новой рубрики и id документа, тогда + // выполняем автоматический перенос документа из одной рубрики в другую + if ((! empty($_POST['NewRubr'])) and (! empty($_GET['Id']))) + { + $new_rubric_id = (int)$_POST['NewRubr']; // идентификатор целевой рубрики + + // Циклически обрабатываем данные, пришедшие в запросе методо POST + foreach ($_POST as $key => $value) + { + if (is_integer($key)) + { + // Определяем флаг поля + switch ($value) + { + // Если 0, тогда + case 0: + // Выполняем запрос к БД на удаление старого поля (лишнее или не требует переноса) + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_fields + WHERE + document_id = '" . $document_id . "' + AND + rubric_field_id = '" . $key . "' + "); + + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_fields_text + WHERE + document_id = '" . $document_id . "' + AND + rubric_field_id = '" . $key . "' + "); + break; + + // Если -1, тогда + case -1: + // Выполняем запрос на получение данных для этого (старого) поля + $row_fd = $AVE_DB->Query(" + SELECT + rubric_field_title, + rubric_field_type + FROM + " . PREFIX . "_rubric_fields + WHERE + Id = '" . $key . "' + ")->FetchRow(); + + // Выполняем запрос к БД и получаем последнюю позицию полей в рубрики КУДА переносим + $new_pos = $AVE_DB->Query(" + SELECT + rubric_field_position + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $new_rubric_id . "' + ORDER BY + rubric_field_position DESC + LIMIT 1 + ")->GetCell(); + + ++$new_pos; + + // Выполняем запрос к БД и добавляем новое поле в новую рубрику + $AVE_DB->Query(" + INSERT + INTO + " . PREFIX . "_rubric_fields + SET + rubric_id = '" . $new_rubric_id . "', + rubric_field_title = '" . addslashes($row_fd->rubric_field_title) . "', + rubric_field_type = '" . addslashes($row_fd->rubric_field_type) . "', + rubric_field_position = '" . $new_pos . "' + "); + + $lastid = $AVE_DB->InsertId(); + + // Выполняем запрос к БД и добавляем запись о поле в таблицу с полями документов + $sql_docs = $AVE_DB->Query(" + SELECT Id + FROM + " . PREFIX . "_documents + WHERE + rubric_id = '" . $new_rubric_id . "' + "); + + while ($row_docs = $sql_docs->FetchRow()) + { + $AVE_DB->Query(" + INSERT + INTO + " . PREFIX . "_document_fields + SET + rubric_field_id = '" . $lastid . "', + document_id = '" . $row_docs->Id . "', + field_value = '', + document_in_search = '1' + "); + } + + // Выполняем запрос к БД и создаем новое поле для изменяемого документа + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_fields + SET + rubric_field_id = '" . $lastid . "' + WHERE + rubric_field_id = '" . $key . "' + AND + document_id = '" . $document_id . "' + "); + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_fields_text + SET + rubric_field_id = '" . $lastid . "' + WHERE + rubric_field_id = '" . $key . "' + AND + document_id = '" . $document_id . "' + "); + break; + + // По умолчанию + default: + // Выполняем запрос к БД и просто обновляем имеющиеся данные + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_fields + SET + rubric_field_id = '" . $value . "' + WHERE + rubric_field_id = '" . $key . "' + AND + document_id = '" . $document_id . "' + "); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_fields_text + SET + rubric_field_id = '" . $value . "' + WHERE + rubric_field_id = '" . $key . "' + AND + document_id = '" . $document_id . "' + "); + break; + } + } + } + + // Выполняем запрос к БД и получаем список всех полей у новой рубрики + $sql_rub = $AVE_DB->Query(" + SELECT Id + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $new_rubric_id . "' + ORDER BY + Id ASC + "); + + // Выполняем запросы к БД на проверку наличия нужных полей. + while ($row_rub = $sql_rub->FetchRow()) + { + $num = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_document_fields + WHERE + rubric_field_id = '" . $row_rub->Id . "' + AND + document_id = '" . $document_id . "' + LIMIT 1 + ")->NumRows(); + + // Если в новой рубрики требуемого поля нет, выполняем запрос к БД на добавление нового типа поля + if ($num != 1) + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_document_fields + SET + rubric_field_id = '" . $row_rub->Id . "', + document_id = '" . $document_id . "', + field_value = '', + document_in_search = '1' + "); + } + } + + // Выполянем запрос к БД на обновление информации, в котором устанавливаем для перенесенного документа + // новое значение id рубрики + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + rubric_id = '" . $new_rubric_id . "' + WHERE + Id = '" . $document_id . "' + "); + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + echo ''; + } + else // Если в запросе не был указан id рубрики и id документа + { + // Формируем и отображаем форму, где пользователь самостоятельно определяет перенос + $fields = array(); + + if ((! empty($_GET['NewRubr'])) and ($rubric_id != (int)$_GET['NewRubr'])) + { + // Выполняем запрос к БД и выбираем все поля новой рубрики + $sql_rub = $AVE_DB->Query(" + SELECT + Id, + rubric_field_title, + rubric_field_type + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . (int)$_GET['NewRubr'] . "' + ORDER BY + Id ASC + "); + $mass_new_rubr = array(); + + while ($row_rub = $sql_rub->FetchRow()) + { + $mass_new_rubr[] = array('Id' => $row_rub->Id, + 'title' => $row_rub->rubric_field_title, + 'rubric_field_type' => $row_rub->rubric_field_type + ); + } + + // Выполняем запрос к БД и выбираем все поля старой рубрики + $sql_old_rub = $AVE_DB->Query(" + SELECT + Id, + rubric_field_title, + rubric_field_type + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY + Id ASC + "); + + // Циклически обрабатываем полученные данные + while ($row_nr = $sql_old_rub->FetchRow()) { + $type = $row_nr->rubric_field_type; + $option_arr = array('0' => $AVE_Template->get_config_vars('DOC_CHANGE_DROP_FIELD'), + '-1' => $AVE_Template->get_config_vars('DOC_CHANGE_CREATE_FIELD') + ); + $selected = -1; + foreach ($mass_new_rubr as $row) + { + if ($row['rubric_field_type'] == $type) + { + $option_arr[$row['Id']] = $row['title']; + + if ($row_nr->rubric_field_title == $row['title']) + $selected = $row['Id']; + } + } + $fields[$row_nr->Id] = array('title' => $row_nr->rubric_field_title, + 'Options' => $option_arr, + 'Selected' => $selected + ); + } + } + + // Чистим кеш + $AVE_DB->clearDocument($document_id); + + // Формируем ряд переменых и отображаем страницу с выбором рубрики + $AVE_Template->assign('fields', $fields); + $AVE_Template->assign('formaction', 'index.php?do=docs&action=change&Id=' . $document_id . '&rubric_id=' . $rubric_id . '&pop=1&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/change.tpl')); + } + } + + /** + * Метод, предназначенный для формирования прав доступа Группы пользователей на Документы определённой Рубрики + * + * @param int $rubric_id идентификатор Рубрики + */ + function documentPermissionFetch($rubric_id) + { + global $AVE_DB; + + // Массив прав пользователей + static $rubric_permissions = array(); + + // Если у нас уже имеются полученные права для данной рубрики, просто прерываем проверку + if (isset($rubric_permissions[$rubric_id])) return; + + // Выполняем запрос к БД на получение прав для данной рубрики + $sql = $AVE_DB->Query(" + SELECT + rubric_id, + rubric_permission + FROM + " . PREFIX . "_rubric_permissions + WHERE + user_group_id = '" . UGROUP . "' + "); + + // Циклически обрабатываем полученные данные и формируем массив прав + while ($row = $sql->FetchRow()) + { + $rubric_permissions[$row->rubric_id] = 1; + + $permissions = explode('|', $row->rubric_permission); + + foreach ($permissions as $rubric_permission) + { + if (! empty($rubric_permission)) + { + $_SESSION[$row->rubric_id . '_' . $rubric_permission] = 1; + } + } + } + } + + /** + * Метод, предназначенный для просмотра и добавления Заметок к Документу + * + * @param int $reply признак ответа на Заметку + */ + function documentRemarkNew($document_id = 0, $reply = 0) + { + global $AVE_DB, $AVE_Template, $AVE_Core; + + // Если id документа не число или 0, прерываем выполнение + if (! (is_numeric($document_id) && $document_id > 0)) + exit; + + $document_title = get_document($document_id, 'document_title'); + $AVE_Template->assign('document_title', $document_title); + + // Если в запросе пришел параметр на Сохранение + if (isset($_REQUEST['sub']) && $_REQUEST['sub'] == 'save') + { + // Если пользователь оставил комментарий и у него имеются права и это не ответ, а новая заметка, тогда + if (!empty($_REQUEST['remark_text']) && check_permission('remarks') && empty($_REQUEST['reply'])) + { + // Выполняем запрос к БД на добавление новой заметки для документа + $AVE_DB->Query(" + INSERT + " . PREFIX . "_document_remarks + SET + document_id = '" . $document_id . "', + remark_title = '" . clean_no_print_char($_REQUEST['remark_title']) . "', + remark_text = '" . substr(clean_no_print_char($_REQUEST['remark_text']), 0, $this->_max_remark_length) . "', + remark_author_id = '" . $_SESSION['user_id'] . "', + remark_published = '" . time() . "', + remark_first = '1', + remark_author_email = '" . $_SESSION['user_email'] . "' + "); + } + + // Выполняем обновление страницы + header('Location:index.php?do=docs&action=remark_reply&Id=' . $document_id . '&pop=1&cp=' . SESSION); + } + + // Если это ответ на уже существующую заметку + if ($reply == 1) + { + if (isset($_REQUEST['sub']) && $_REQUEST['sub'] == 'save') + { + // Если пользователь оставил ответ и имеет на это права + if (! empty($_REQUEST['remark_text']) && check_permission('remarks')) + { + // Выполняем запрос на получение e-mail адреса автора заметки + $remark_author_email = $AVE_DB->Query(" + SELECT + remark_author_email + FROM + " . PREFIX . "_document_remarks + WHERE + remark_first = '1' + AND + document_id = '" . $document_id . "' + ")->GetCell(); + + // Выполняем запрос к БД на добавление заметки в БД + $AVE_DB->Query(" + INSERT + " . PREFIX . "_document_remarks + SET + document_id = '" . $document_id . "', + remark_title = '" . clean_no_print_char($_REQUEST['remark_title']) . "', + remark_text = '" . substr(clean_no_print_char($_REQUEST['remark_text']), 0, $this->_max_remark_length) . "', + remark_author_id = '" . $_SESSION['user_id'] . "', + remark_published = '" . time() . "', + remark_first = '0', + remark_author_email = '" . $_SESSION['user_email'] . "' + "); + } + + // Формируем сообщение и отправляем письмо автору, с информацией о том, что на его заметку есть ответ + $system_mail = get_settings('mail_from'); + $system_mail_name = get_settings('mail_from_name'); + $link = get_home_link() . 'index.php?do=docs&doc_id=' . $document_id; + + $body_to_admin = $AVE_Template->get_config_vars('DOC_MAIL_BODY_NOTICE'); + $body_to_admin = str_replace('%N%', "\n", $body_to_admin); + $body_to_admin = str_replace('%TITLE%', stripslashes($_POST['remark_title']), $body_to_admin); + $body_to_admin = str_replace('%USER%', get_username_by_id($_SESSION['user_id']), $body_to_admin); + $body_to_admin = str_replace('%LINK%', $link, $body_to_admin); + send_mail( + $remark_author_email, + $body_to_admin, + $AVE_Template->get_config_vars('DOC_MAIL_SUBJECT_NOTICE'), + $system_mail, + $system_mail_name, + 'text' + ); + + // Выполняем обновление страницы + header('Location:index.php?do=docs&action=remark_reply&Id=' . $document_id . '&pop=1&cp=' . SESSION); + } + + // Получаем общее количество заметок для документа + $num = $AVE_DB->Query(" + SELECT COUNT(*) + FROM " . PREFIX . "_document_remarks + WHERE document_id = '" . $document_id . "' + ")->GetCell(); + + // Определяыем лимит заметок на 1 странице и подсчитываем количество страниц + $limit = 10; + $pages = ceil($num / $limit); + $start = get_current_page() * $limit - $limit; + + $answers = array(); + + // Выполняем запрос к БД на получение заметок с учетом количества на 1 странцу + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_document_remarks + WHERE + document_id = '" . $document_id . "' + ORDER BY + Id DESC + LIMIT " . $start . "," . $limit + ); + + while ($row = $sql->FetchAssocArray()) + { + $row['remark_author'] = get_username_by_id($row['remark_author_id']); + $row['remark_text'] = nl2br($row['remark_text']); + $row['remark_avatar'] = getAvatar($row['remark_author_id'],40); + array_push($answers, $row); + } + + $remark_status = $AVE_DB->Query(" + SELECT + remark_status + FROM + " . PREFIX . "_document_remarks + WHERE + document_id = '" . $document_id . "' + AND + remark_first = '1' + ")->GetCell(); + + // Если количество заметок превышает допустимое значение, определенное в переменной $limit, тогда + // формируем постраничную навигацию + if ($num > $limit) + { + $page_nav = "
    30. {t}
    31. "; + $page_nav = get_pagination($pages, 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + // Передаем данные в шаблон и отображаем страницу со списком заметок + $AVE_Template->assign('document_title', $document_title); + $AVE_Template->assign('remark_status', $remark_status); + $AVE_Template->assign('answers', $answers); + $AVE_Template->assign('reply', 1); + $AVE_Template->assign('formaction', 'index.php?do=docs&action=remark_reply&sub=save&Id=' . $document_id . '&reply=1&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/newremark.tpl')); + } + else + { // В противном случае, если заметок еще нет, открываем форму для добавление заметки + $AVE_Template->assign('reply', 1); + $AVE_Template->assign('new', 1); + $AVE_Template->assign('formaction', 'index.php?do=docs&action=remark&sub=save&Id=' . $document_id . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/newremark.tpl')); + } + } + + /** + * Метод, предназначенный для управления статусами дискусии (разрешить или запретить оставлять + * ответы на заметки для других пользователей) + * + * @param int $document_id идентификатор документа + * @param int $status статус дискусии + */ + function documentRemarkStatus($document_id = 0, $status = 0) + { + global $AVE_DB; + + // Если id документа число и оно больше 0, тогда + if (is_numeric($document_id) && $document_id > 0) + { + // Выполняем запрос к БД на обновление статуса у заметок + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_remarks + SET + remark_status = '" . ($status != 1 ? 0 : 1) . "' + WHERE + remark_first = '1' + AND + document_id = '" . $document_id . "' + "); + } + + // Выполняем обновление данных + header('Location:index.php?do=docs&action=remark_reply&Id=' . $document_id . '&pop=1&cp=' . SESSION); + exit; + } + + /** + * Метод, предназначенный для удаление заметок + * + * @param int $all признак удаления всех Заметок (1 - удалить все) + */ + function documentRemarkDelete($document_id = 0, $all = 0) + { + global $AVE_DB; + + // Если id документа не число или 0, прерываем выполнение + if (! (is_numeric($document_id) && $document_id > 0)) + exit; + + // Если в запросе пришел параметр на удаление всех заметок + if ($all == 1) + { + // Выполянем запрос к БД и удалаем заметки + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_remarks + WHERE + document_id = '" . $document_id . "' + "); + + // Выполняем обновление страницы + header('Location:index.php?do=docs&action=remark&Id=' . $document_id . '&pop=1&cp=' . SESSION); + exit; + } + else + { + if (! (isset($_REQUEST['CId']) && is_numeric($_REQUEST['CId']) && $_REQUEST['CId'] > 0)) + exit; + + // В противном случае, выполняем запрос к БД и удаляем только ту заметку, которая была выбрана + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_remarks + WHERE + document_id = '" . $document_id . "' + AND + Id = '" . $_REQUEST['CId'] . "' + "); + + // Выполняем обновление страницы + header('Location:index.php?do=docs&action=remark_reply&Id=' . $document_id . '&pop=1&cp=' . SESSION); + exit; + } + } + + /** + * Добавить в навигацию пункт ссылающийся на документ + * + */ + function documentInNavi() + { + global $AVE_DB; + + $document_id = isset($_REQUEST['document_id']) ? (int)$_REQUEST['document_id'] : 0; + $rubric_id = isset($_REQUEST['rubric_id']) ? (int)$_REQUEST['rubric_id'] : 0; + $title = isset($_REQUEST['navi_title']) ? clean_no_print_char($_REQUEST['navi_title']) : ''; + + if ($document_id > 0 && $rubric_id > 0 && $title != '' && check_permission_acp('navigation_new')) + { + $document_alias = $AVE_DB->Query(" + SELECT + document_alias + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + AND + rubric_id = '" . $rubric_id . "' + LIMIT 1 + ")->GetCell(); + } + + + if (isset($document_alias) && $document_alias !== false) + { + // Получаем id пункта меню из запроса + $parent_id = isset($_REQUEST['parent_id']) ? (int)$_REQUEST['parent_id'] : 0; + + // Если пункт не родительский, а какой-либо дочерний + if ($parent_id > 0) + { + // Выполняем запрос к БД на получение id меню навигации и уровня + list($navigation_id, $status, $level) = $AVE_DB->Query(" + SELECT + navigation_id, + status, + level+1 + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $parent_id . "' + LIMIT 1 + ")->FetchArray(); + } + else + { + $navigation_id = (isset($_REQUEST['navi_id']) && (int)$_REQUEST['navi_id'] > 0) ? (int)$_REQUEST['navi_id'] : 1; + $status = 1; + $level = 1; + } + + $target = (isset($_REQUEST['navi_item_target']) && $_REQUEST['navi_item_target'] == '_blank') ? '_blank' : '_self'; + + $position = empty($_REQUEST['navi_item_position']) ? 1 : (int)$_REQUEST['navi_item_position']; + + if ($level > 3) + $level = '3'; + + // Добавляем информации о новой связке Документ<->Пункт меню + $AVE_DB->Query(" + INSERT + INTO + " . PREFIX . "_navigation_items + SET + title = '" . $title . "', + document_id = '" . $document_id . "', + alias = '" . $document_alias . "', + parent_id = '" . $parent_id . "', + navigation_id = '" . $navigation_id . "', + level = '" . $level . "', + target = '" . $target . "', + position = '" . $position . "', + status = '" . $status . "' + "); + } + + header('Location:index.php?do=docs&action=after&document_id=' . $document_id . '&rubric_id=' . $rubric_id . '&cp=' . SESSION); + exit; + } + + /** + * Вывод формы дополнительных действий с новым или отредактированным документом + * + */ + function documentFormAfter() + { + global $AVE_DB, $AVE_Template; + + $document_id = isset($_REQUEST['document_id']) ? (int)$_REQUEST['document_id'] : 0; + $rubric_id = isset($_REQUEST['rubric_id']) ? (int)$_REQUEST['rubric_id'] : 0; + $innavi = (isset($_REQUEST['innavi']) && check_permission_acp('navigation_new')) ? 1 : 0; + + if ($document_id > 0 && $rubric_id > 0) + { + $document = $AVE_DB->Query(" + SELECT + Id AS document_id, + rubric_id, + document_title AS document_title, + '" . $innavi . "' AS innavi + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $document_id . "' + AND + rubric_id = '" . $rubric_id . "' + LIMIT 1 + ")->FetchAssocArray(); + } + + if (empty($document)) + { + header('Location:index.php?do=docs&cp=' . SESSION); + exit; + } + + $search_query = isset($_SESSION['search_query'][$document_id]) ? true : false; + + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('search_query', $search_query); + $AVE_Template->assign($document); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/form_after.tpl')); + } + + + /** + * Редирект сохраненного документа на раздел, учитывая фильтр + * + */ + function documentSaveRedirect() + { + $document_id = isset($_REQUEST['document_id']) + ? (int)$_REQUEST['document_id'] + : 0; + + // Если не пришел $documet_id + if (! $document_id) + { + header('Location:index.php?do=docs&cp=' . SESSION); + exit; + } + + // Параметры поиска + $search_query = base64_decode($_SESSION['search_query'][$document_id]); + + $search_query = $search_query + ? $search_query + : 'do=docs&cp=' . SESSION; + + // Убираем из сессии данный документ + unset ($_SESSION['search_query'][$document_id]); + + // Переходим на страницу + header('Location: index.php?' . $search_query); + exit; + } + + + /** + * Метод, предназначенный для смены автора документа + * + * @param int $doc_id идентификатор документа + * @param int $user_id идентификатор пользователя + */ + function changeAutorSave() + { + global $AVE_DB; + + // Если id документа число и оно больше 0, тогда + if (is_numeric($_REQUEST['doc_id']) && $_REQUEST['doc_id'] > 0) + { + // Выполняем запрос к БД на обновление статуса у заметок + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_author_id = '" . $_REQUEST['user_id'] . "' + WHERE + Id = '" . $_REQUEST['doc_id'] . "' + "); + + $username = get_username_by_id($_REQUEST['user_id']); + + echo " + + "; + } + exit; + } + + /** + * Метод, предназначенный для удаления ревизий документов + * + */ + function documentsRevisionsClear() + { + global $AVE_DB, $AVE_Template; + + if (check_permission('document_php')) + { + $sql = $AVE_DB->Query(" + TRUNCATE TABLE " . PREFIX . "_document_rev + "); + + if ($sql->_result === false) + { + $message = $AVE_Template->get_config_vars('SETTINGS_REV_DELETED_ERR'); + $header = $AVE_Template->get_config_vars('SETTINGS_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('SETTINGS_REV_DELETED'); + $header = $AVE_Template->get_config_vars('SETTINGS_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('SETTINGS_REV_UPDATE')); + } + + if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] = 'run') + { + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme + ) + ); + } + else + { + header('Location:index.php?do=settings&cp=' . SESSION); + } + } + exit; + } + + /** + * Метод, предназначенный для удаления ревизий документов + * + */ + function documentCounterClear() + { + global $AVE_DB, $AVE_Template; + + if (check_permission('gen_settings')) + { + $sql = $AVE_DB->Query(" + TRUNCATE TABLE + " . PREFIX . "_view_count + "); + + if ($sql->_result === false) + { + $message = $AVE_Template->get_config_vars('SETTINGS_COUNT_DELETED_ERR'); + $header = $AVE_Template->get_config_vars('SETTINGS_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('SETTINGS_COUNT_DELETED'); + $header = $AVE_Template->get_config_vars('SETTINGS_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('SETTINGS_COUNT_UPDATE')); + } + + if (isAjax()) + { + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme + ) + ); + } + else + { + header('Location:index.php?do=settings&cp=' . SESSION); + } + } + exit; + } + + + /** + * Метод, предназначенный для формирования URL + * + */ + function documentAliasCreate() + { + $alias = empty($_REQUEST['alias']) ? '' : prepare_url($_REQUEST['alias']); + $prefix = empty($_REQUEST['prefix']) ? '' : prepare_url($_REQUEST['prefix']); + $title = empty($_REQUEST['title']) ? '' : prepare_url($_REQUEST['title']); + + if ($alias != $title && $alias != trim($prefix . '/' . $title, '/')) + $alias = trim($alias . '/' . $title, '/'); + + return $alias; + } + + + /** + * Метод, предназначенный для контроля уникальности URL + * + */ + function documentAliasCheck() + { + global $AVE_DB, $AVE_Template; + + $document_id = (isset($_REQUEST['id']) && is_numeric($_REQUEST['id'])) ? (int)$_REQUEST['id'] : 0; + $document_alias = (isset($_REQUEST['alias'])) ? $_REQUEST['alias'] : ''; + $alias_id = (isset($_REQUEST['alias_id'])) ? (int)$_REQUEST['alias_id'] : 0; + + $errors = []; + + // Если указанный URL пользователем не пустой + if (! empty($document_alias)) + { + // Проверяем, чтобы данный URL соответствовал требованиям + if (preg_match(TRANSLIT_URL ? '/[^\.a-z0-9\/_-]+/' : '/^[^0-9A-Za-zА-Яа-яЁё]+$/u', $document_alias)) + { + $errors[] = $AVE_Template->get_config_vars('DOC_URL_ERROR_SYMBOL'); + } + + // Если URL начинается с "/" - фиксируем ошибку + if ($document_alias[0] == '/') + $errors[] = $AVE_Template->get_config_vars('DOC_URL_ERROR_START'); + + // Если суффикс URL заканчивается на "/" и URL заканчивается на "/" - фиксируем ошибку + if (substr(URL_SUFF, 0, 1) == '/' && substr($document_alias, -1) == '/') + $errors[] = $AVE_Template->get_config_vars('DOC_URL_ERROR_END'); + + // Если в URL используются слова apage-XX, artpage-XX,page-XX,print, фиксируем ошибку, где ХХ - число + $matches = preg_grep('/^(apage-\d+|artpage-\d+|page-\d+|print)$/i', explode('/', $document_alias)); + + if (! empty($matches)) + $errors[] = $AVE_Template->get_config_vars('DOC_URL_ERROR_SEGMENT') . implode(', ', $matches); + + $and_docs = (($document_id > 0) ? "AND Id != '" . $document_id . "'" : ''); + $and_alias_id = (isset($alias_id) ? "AND id != '" . $alias_id . "'" : ''); + + // Выполняем запрос к БД на получение всех URL и проверку на уникальность + if (empty($errors)) + { + $sql = " + SELECT 1 + FROM + " . PREFIX . "_documents + WHERE + document_alias = '" . $document_alias . "' + $and_docs + LIMIT 1 + "; + + $alias_exist = $AVE_DB->Query($sql)->NumRows(); + + if ($alias_exist) + $errors[] = $AVE_Template->get_config_vars('DOC_URL_ERROR_DUPLICATES'); + + $alias_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_document_alias_history + WHERE + document_alias = '" . $document_alias . "' + $and_alias_id + LIMIT 1 + ")->NumRows(); + + if ($alias_exist) + $errors[] = $AVE_Template->get_config_vars('DOC_URL_H_ERROR_DUPLICATES'); + } + } + else + { + // В противном случае, если URL пустой, формируем сообщение об ошибке + $errors[] = $AVE_Template->get_config_vars('DOC_URL_ERROR_EMTY'); + } + + // Если ошибок не найдено, формируем сообщение об успешной операции + if (empty($errors)) + { + return _json(array($AVE_Template->get_config_vars('DOC_URL_CHECK_OK') . implode(',
      ', $errors), 'accept'), true); + } + else + { // В противном случае формируем сообщение с ошибкой + return _json(array($AVE_Template->get_config_vars('DOC_URL_CHECK_ER') . implode(',
      ', $errors), 'error'), true); + } + } + + /** + * Метод, предназначенный для + * + */ + function documentAliasHistoryList() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + h.id, + h.document_id, + h.document_alias_changed, + COUNT(h.document_id) as count, + d.rubric_id, + d.document_title, + d.document_alias, + r.rubric_title + FROM + " . PREFIX . "_document_alias_history AS h + LEFT JOIN + " . PREFIX . "_documents AS d + ON h.document_id = d.Id + LEFT JOIN + " . PREFIX . "_rubrics AS r + ON d.rubric_id = r.Id + WHERE + h.document_id = d.Id + GROUP BY + h.document_id + ORDER BY + h.document_alias_changed DESC + "); + + $documents = array(); + + while ($row = $sql->FetchAssocArray()) + { + array_push($documents, $row); + } + + $AVE_Template->assign('documents', $documents); + $AVE_Template->assign('content', $AVE_Template->fetch('documents/alias_list.tpl')); + } + + /** + * Метод, предназначенный для + * + */ + function documentAliasListDoc($id) + { + global $AVE_DB, $AVE_Template, $AVE_Rubric; + + $document = $AVE_DB->Query(" + SELECT + d.rubric_id, + d.document_title, + d.document_alias, + r.rubric_title + FROM + " . PREFIX . "_documents AS d + LEFT JOIN + " . PREFIX . "_rubrics AS r + ON d.rubric_id = r.Id + WHERE + d.Id = " . $id . " + ")->FetchRow(); + + $sql = $AVE_DB->Query(" + SELECT * + FROM + ".PREFIX."_document_alias_history + WHERE + document_id = '". $id ."' + "); + + $aliases = array(); + + while ($row = $sql->FetchRow()) + { + $row->document_alias_author_name = get_username_by_id($row->document_alias_author); + array_push($aliases, $row); + } + + $AVE_Template->assign('document', $document); + $AVE_Template->assign('aliases', $aliases); + + switch($_REQUEST['sub']) + { + case 'list': + $AVE_Template->assign('content', $AVE_Template->fetch('documents/alias_doc_list.tpl')); + break; + + default: + $AVE_Template->assign('content', $AVE_Template->fetch('documents/alias_doc.tpl')); + break; + } + } + + /** + * Метод, предназначенный для + * + */ + function documentAliasNew() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + INSERT + INTO + " . PREFIX . "_document_alias_history + SET + document_id = '" . (int)$_REQUEST['doc_id'] . "', + document_alias = '" . trim($_REQUEST['alias']) . "', + document_alias_author = '" . (int)UID . "', + document_alias_changed = '" . time() . "' + "); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('DOC_ALIASES_REP_ER_T'); + $header = $AVE_Template->get_config_vars('DOC_ALIASES_REP_ER'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('DOC_ALIASES_REP_OK_T'); + $header = $AVE_Template->get_config_vars('DOC_ALIASES_REP_OK'); + $theme = 'accept'; + } + + if (isAjax()) + { + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme + ) + ); + } + else + { + header('Location:index.php?do=docs&action=aliases_doc&cp=' . SESSION); + } + exit; + } + + /** + * Метод, предназначенный для + * + */ + function documentAliasEdit() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_document_alias_history + SET + document_alias = '" . $_REQUEST['alias'] . "' + WHERE + id = '" . $_REQUEST['id'] . "' + "); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('DOC_ALIASES_REP_ER_T_E'); + $header = $AVE_Template->get_config_vars('DOC_ALIASES_REP_ER'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('DOC_ALIASES_REP_OK_T_E'); + $header = $AVE_Template->get_config_vars('DOC_ALIASES_REP_OK'); + $theme = 'accept'; + } + + if (isAjax()) + { + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme + ) + ); + } + else + { + header('Location:index.php?do=docs&action=aliases_doc&cp=' . SESSION); + } + + exit; + } + + /** + * Метод, предназначенный для + * + */ + function documentAliasSave() + { + global $AVE_DB, $AVE_Template; + + if (isset($_REQUEST['alias_del'])) + { + foreach ($_REQUEST['alias_del'] as $id => $val) + { + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_alias_history + WHERE + id = '" . $id . "' + "); + } + } + + exit; + } + + + /** + * Метод, предназначенный для + * + */ + function documentAliasDel() + { + global $AVE_DB, $AVE_Template; + + if (isset($_REQUEST['alias_id'])) + { + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_document_alias_history + WHERE + id = '" . $_REQUEST['alias_id'] . "' + "); + } + + exit; + } + + + /** + * Метод, предназначенный для + * + */ + function documentPosition() + { + global $AVE_DB, $AVE_Template; + + $query = false; + + if (isset($_REQUEST['id'])) + { + $docid = (int)$_REQUEST['id']; + $value = (int)$_REQUEST['value']; + + $sql = " + UPDATE + ".PREFIX."_documents + SET + document_position = " . $value . " + WHERE + Id = " . $docid . " + "; + + $query = $AVE_DB->Query($sql); + } + + if ($query === false) + $return = [ + 'message' => $AVE_Template->get_config_vars('DOCUMENT_POSITION_ERR'), + 'header' => $AVE_Template->get_config_vars('DOCUMENT_POSITION_ERROR'), + 'theme' => 'error' + ]; + else + $return = [ + 'message' => $AVE_Template->get_config_vars('DOCUMENT_POSITION_OK'), + 'header' => $AVE_Template->get_config_vars('DOCUMENT_POSITION_SUCCESS'), + 'theme' => 'accept' + ]; + + if (isAjax()) + echo _json($return, true); + else + header('Location:index.php?do=sysblocks&cp=' . SESSION); + + exit; + } + + function documentPublish () + { + global $AVE_DB, $AVE_Template; + + $doc_id = (int)$_REQUEST['doc_id']; + + if (! $doc_id) + { + $return = [ + 'success' => false, + 'header' => $AVE_Template->get_config_vars('DOC_STATUS_ERROR'), + 'message' => '', + 'theme' => 'error' + ]; + + _json($return, true); + } + + $sql = " + SELECT + document_status + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $doc_id . "' + "; + + $status = $AVE_DB->Query($sql)->GetCell(); + + $sql = " + UPDATE + " . PREFIX . "_documents + SET + document_status = '" . ($status == 1 ? 0 : 1) . "' + WHERE + Id = '" . $doc_id . "' + "; + + $AVE_DB->Query($sql); + + $return = [ + 'success' => true, + 'status' => ($status == 1 ? '0' : '1'), + 'text' => ($status == 1 ? $AVE_Template->get_config_vars('DOC_ENABLE_TITLE') : $AVE_Template->get_config_vars('DOC_DISABLE_TITLE')), + 'header' => $AVE_Template->get_config_vars('DOC_STATUS_SUCCESS'), + 'message' => ($status == 1 ? $AVE_Template->get_config_vars('DOC_STATUS_OFF') : $AVE_Template->get_config_vars('DOC_STATUS_ON')), + 'theme' => 'accept' + ]; + + $AVE_DB->clearDocument($doc_id); + + reportLog($_SESSION['user_name'] . ' - ' . (($status == 1) ? $AVE_Template->get_config_vars('DOC_DOCUMENT_CLOSE') : $AVE_Template->get_config_vars('DOC_DOCUMENT_OPEN')) . ' (' . $doc_id . ')', 2, 2); + + _json($return, true); + } + + function documentRecycle () + { + global $AVE_DB, $AVE_Template; + + $doc_id = (int) $_REQUEST['doc_id']; + + if (!$doc_id) { + $return = [ + 'success' => false, + 'header' => $AVE_Template->get_config_vars('DOC_STATUS_ERROR'), + 'message' => '', + 'theme' => 'error' + ]; + + _json($return, true); + } + + $sql = " + SELECT + document_deleted + FROM + " . PREFIX . "_documents + WHERE + Id = '" . $doc_id . "' + "; + + $status = $AVE_DB->Query($sql)->GetCell(); + + $sql = " + UPDATE + " . PREFIX . "_documents + SET + document_deleted = '" . ($status == 0 ? 1 : 0) . "' + WHERE + Id = '" . $doc_id . "' + "; + + $AVE_DB->Query($sql); + + $return = [ + 'success' => true, + 'status' => ($status == 1 ? '0' : '1'), + 'text' => ($status == 1 ? $AVE_Template->get_config_vars('DOC_TEMPORARY_DELETE') : $AVE_Template->get_config_vars('DOC_RESTORE_DELETE')), + 'header' => $AVE_Template->get_config_vars('DOC_STATUS_SUCCESS'), + 'message' => ($status == 1 ? $AVE_Template->get_config_vars('DOC_RECYCLE_ON') : $AVE_Template->get_config_vars('DOC_RECYCLE_OFF')), + 'theme' => 'accept' + ]; + + $AVE_DB->clearDocument($doc_id); + + reportLog($_SESSION['user_name'] . ' - ' . (($status == 1) ? $AVE_Template->get_config_vars('DOC_RECYCLE_ON') : $AVE_Template->get_config_vars('DOC_RECYCLE_OFF')) . ' (' . $doc_id . ')', 2, 2); + + _json($return, true); + } + + + function documentRevissionsDelete() + { + global $AVE_DB, $AVE_Template; + + $document_id = (int)$_REQUEST['id']; + $rubric_id = (int)$_REQUEST['rubric_id']; + + $this->documentPermissionFetch($rubric_id); + + if ((isset($_SESSION[$rubric_id . '_delrev']) && $_SESSION[$rubric_id . '_delrev'] == 1) + || (isset($_SESSION[$rubric_id . '_alles']) && $_SESSION[$rubric_id . '_alles'] == 1) + || (defined('UGROUP') && UGROUP == 1)) + { + $run = true; + } + + if ($run === true) + { + $sql = " + DELETE + FROM + " . PREFIX . "_document_rev + WHERE + doc_id = '" . $document_id . "' + "; + + $AVE_DB->Query($sql); + + reportLog($AVE_Template->get_config_vars('DOC_REVISIONS_DELETE') . " (Doc: $document_id)"); + + if (! isAjax()) { + header('Location:index.php?do=docs&action=edit&rubric_id=' . $rubric_id . '&Id=' . $document_id . '&cp=' . SESSION); + } else { + $return = [ + 'success' => true, + 'message' => $AVE_Template->get_config_vars('DOC_REVISIONS_DELETE') + ]; + + _json($return, true); + } + + } else { + $AVE_Template->assign('content', $AVE_Template->get_config_vars('DOC_NO_DEL_REVISION')); + } + } + } +?> \ No newline at end of file diff --git a/class/class.errors.php b/class/class.errors.php new file mode 100644 index 0000000..f31e1ea --- /dev/null +++ b/class/class.errors.php @@ -0,0 +1,163 @@ +'; + $out .= '
      '; + $out .= '' . $errseverity . ' Line ' . $errline . ': ' . $errfile; + $out .= '
      '; + $out .= '
      '; + $out .= '['.$errno.'] '. $errstr; + $out .= '
      '; + $out .= ''; + + echo $out; + } + + + /** + * + */ + public function shutDown () + { + if ($error = error_get_last()) + { + if (! headers_sent()) + header('HTTP/1.1 500 Internal Server Error'); + + switch($error['type']) + { + case E_ERROR: + case E_PARSE: + case E_STRICT: + case E_CORE_ERROR: + case E_CORE_WARNING: + case E_COMPILE_ERROR: + case E_COMPILE_WARNING: + case E_USER_ERROR: + case E_RECOVERABLE_ERROR: + $this->scriptError($error['type'], $error['message'], $error['file'], $error['line']); + break; + } + } + } + } \ No newline at end of file diff --git a/class/class.hooks.php b/class/class.hooks.php new file mode 100644 index 0000000..c962ee7 --- /dev/null +++ b/class/class.hooks.php @@ -0,0 +1,175 @@ + $function + ); + } + } + else + { + // Store the action hook in the $hooks array + self::$hooks[$name][$priority][$function] = array( + "function" => $function + ); + } + + return true; + } + + /** + * Do Hook + */ + public static function trigger ($name, $arguments = "") + { + // Oh, no you didn't. Are you trying to run an action hook that doesn't exist? + if (! isset(self::$hooks[$name])) + { + return $arguments; + } + + // Set the current running hook to this + self::$current_hook = $name; + + // Key sort our action hooks + ksort(self::$hooks[$name]); + foreach (self::$hooks[$name] AS $priority => $names) + { + if (is_array($names)) + { + foreach ($names AS $name) + { + $return = call_user_func_array($name['function'], array( + &$arguments + )); + + if ($return) + { + $arguments = $return; + } + + self::$run_hooks[$name][$priority]; + } + } + } + + self::$current_hook = ''; + + return $arguments; + } + + /** + * Remove Hook + */ + public static function unregister ($name, $function, $priority = 10) + { + // If the action hook doesn't, just return true + if (!isset(self::$hooks[$name][$priority][$function])) + { + return true; + } + // Remove the action hook from our hooks array + unset(self::$hooks[$name][$priority][$function]); + + return ''; + } + + + /** + * Current Hook + * + * Get the currently running action hook + * + */ + public static function current () + { + return self::$current_hook; + } + + + /** + * Has Run + */ + public static function has ($hook, $priority = 10) + { + if (isset(self::$hooks[$hook][$priority])) + { + return true; + } + else + { + return false; + } + } + + + /** + * Hook Exists + */ + public static function exists ($name) + { + if (isset(self::$hooks[$name])) + { + return true; + } + else + { + return false; + } + } + } +?> \ No newline at end of file diff --git a/class/class.logs.php b/class/class.logs.php new file mode 100644 index 0000000..6e5a080 --- /dev/null +++ b/class/class.logs.php @@ -0,0 +1,329 @@ +_logdir; + $_lines = []; + + if (file_exists($file_name) && $fp = @fopen($file_name, 'rb')) + { + $_count = 10000; + + $_size = @filesize($file_name); + + $_slice = 10240; + + $_size > $_slice && fseek($fp, $_size - $_slice); + + while (!feof($fp)) + { + $event = fgetcsv($fp, $_slice); + + if (empty($event[0]) || count($event) < 3) { + continue; + } + + $_lines[] = [ + 'log_time' => $event['0'], + 'log_ip' => $event['1'], + 'log_url' => $event['2'], + 'log_user_id' => $event['3'], + 'log_user_name' => $event['4'], + 'log_text' => $event['5'], + 'log_type' => $event['6'], + 'log_rubric' => $event['7'] + ]; + } + + count($_lines) > $_count && $_lines = array_slice($_lines, -$_count); + } + + // Передаем данные в шаблон для вывода и отображаем страницу + $AVE_Template->assign('logs', $_lines); + $AVE_Template->assign('content', $AVE_Template->fetch('logs/logs.tpl')); + } + + /** + * Метод, предназначенный для отображения всех записей Журнала событий 404 + * + */ + function List404() + { + global $AVE_Template; + + $file_name = BASE_DIR . $this->_404dir; + $_lines = []; + + if (file_exists($file_name) && $fp = @fopen($file_name, 'rb')) + { + $_count = 10000; + + $_size = @filesize($file_name); + + $_slice = 10240; + + $_size > $_slice && fseek($fp, $_size - $_slice); + + while (!feof($fp)) + { + $event = fgetcsv($fp, $_slice); + + if (empty($event[0]) || count($event) < 3) { + continue; + } + + $_lines[] = [ + 'log_time' => $event['0'], + 'log_ip' => $event['1'], + 'log_query' => $event['2'], + 'log_user_agent' => $event['3'], + 'log_user_referer' => $event['4'], + 'log_request_uri' => $event['5'] + ]; + } + + count($_lines) > $_count && $_lines = array_slice($_lines, -$_count); + } + + // Передаем данные в шаблон для вывода и отображаем страницу + $AVE_Template->assign('logs', $_lines); + $AVE_Template->assign('content', $AVE_Template->fetch('logs/404.tpl')); + } + + /** + * Метод, предназначенный для отображения всех записей Журнала событий 404 + * + */ + function ListSql() + { + global $AVE_Template; + + $file_name = BASE_DIR . $this->_sqldir; + $_lines = []; + + if (file_exists($file_name) && $fp = @fopen($file_name, 'rb')) + { + $_count = 10000; + + $_size = @filesize($file_name); + + $_slice = 10240; + + $_size > $_slice && fseek($fp, $_size - $_slice); + + while (!feof($fp)) + { + $event = fgetcsv($fp, $_slice); + + if (empty($event[0]) || count($event) < 3) { + continue; + } + + $_lines[] = [ + 'log_time' => $event['0'], + 'log_ip' => $event['1'], + 'log_url' => $event['2'], + 'log_user_id' => $event['3'], + 'log_user_name' => $event['4'], + 'log_text' => unserialize(base64_decode($event['5'])) + ]; + } + + count($_lines) > $_count && $_lines = array_slice($_lines, -$_count); + } + + // Передаем данные в шаблон для вывода и отображаем страницу + $AVE_Template->assign('logs', $_lines); + $AVE_Template->assign('content', $AVE_Template->fetch('logs/sql.tpl')); + } + + /** + * Метод, предназначенный для удаление записей Журнала событий + * + */ + function logDelete() + { + global $AVE_Template; + + $logfile = BASE_DIR . $this->_logdir; + + if(file_exists($logfile)) + unlink($logfile); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('LOGS_CLEAN')); + + header('Location:index.php?do=logs&cp=' . SESSION); + exit; + } + + /** + * Метод, предназначенный для удаление записей Журнала событий 404 + * + */ + function DeleteSql() + { + global $AVE_Template; + + $logfile = BASE_DIR . $this->_sqldir; + + if(file_exists($logfile)) + unlink($logfile); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('LOGS_SQL_CLEAN')); + + header('Location:index.php?do=logs&action=logsql&cp=' . SESSION); + exit; + } + + /** + * Метод, предназначенный для удаление записей Журнала событий 404 + * + */ + function Delete404() + { + global $AVE_Template; + + $logfile = BASE_DIR . $this->_404dir; + + if(file_exists($logfile)) + unlink($logfile); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('LOGS_404_CLEAN')); + + header('Location:index.php?do=logs&action=log404&cp=' . SESSION); + exit; + } + + /** + * Метод, предназначенный для экспорта системных сообщений + * + */ + function logExport() + { + global $AVE_Template; + + $file_name = BASE_DIR . $this->_logdir; + $dateName = 'system_log_' . date('dmyhis', time()) . '.csv'; + + // Определяем заголовки документа + header('Content-Encoding: windows-1251'); + header('Content-type: text/csv; charset=windows-1251'); + header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Content-Disposition: attachment; filename="' . $dateName . '"'); + header('Content-Length: ' . filesize($file_name)); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + + // Выводим данные + readfile($file_name); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('LOGS_EXPORT')); + + exit; + } + + /** + * Метод, предназначенный для экспорта сообщений 404 + * + */ + function Export404() + { + global $AVE_Template; + + $file_name = BASE_DIR . $this->_404dir; + $dateName = 'system_log_' . date('dmyhis', time()) . '.csv'; + + // Определяем заголовки документа + header('Content-Encoding: windows-1251'); + header('Content-type: text/csv; charset=windows-1251'); + header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Content-Disposition: attachment; filename="' . $dateName . '"'); + header('Content-Length: ' . filesize($file_name)); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + + // Выводим данные + readfile($file_name); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('LOGS_EXPORT')); + + exit; + } + + /** + * Метод, предназначенный для экспорта сообщений 404 + * + */ + function ExportSql() + { + global $AVE_Template; + + $file_name = BASE_DIR . $this->_sqldir; + $dateName = 'system_log_' . date('dmyhis', time()) . '.csv'; + + // Определяем заголовки документа + header('Content-Encoding: windows-1251'); + header('Content-type: text/csv; charset=windows-1251'); + header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT'); + header('Content-Disposition: attachment; filename="' . $dateName . '"'); + header('Content-Length: ' . filesize($file_name)); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + + // Выводим данные + readfile($file_name); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('LOGS_EXPORT')); + + exit; + } + } \ No newline at end of file diff --git a/class/class.meta.php b/class/class.meta.php new file mode 100644 index 0000000..bbdbf49 --- /dev/null +++ b/class/class.meta.php @@ -0,0 +1,72 @@ +_keyword_count = $keyword_count; + } + + public function setKeywordCount( $keyword_count ) + { + if( (int) $keyword_count ) $this->_keyword_count = $keyword_count; + } + + public function generateMeta( $text ) + { + $newarr = array (); + + $quotes = array ("\x22", "\x60", "\t", "\n", "\r", ",", "/", "¬", "#", ";", ":", "@", "~", "[", "]", "{", "}", "=", "+", ")", "(", "*", "^", "%", "$", "<", ">", "?", "!", '"'); + $fastquotes = array ("\x22", "\x60", "\t", "\n", "\r", '"', "\\", '\r', '\n', "/", "{", "}", "[", "]" ); + + $text = str_replace( chr(9), ' ', $text ); + $text = str_replace( chr(10), ' ', $text ); + $text = str_replace( chr(13), ' ', $text ); + $text = str_replace( " ", " ", $text ); + $text = str_replace( '
      ', ' ', $text ); + $text = strip_tags( $text ); + $text = preg_replace('/ {2,}/',' ',$text); + $text = preg_replace( "#&(.+?);#", "", $text ); + //$text = trim(str_replace( " ,", "", stripslashes( $text ))); + $text = preg_replace('/\[tag:(.+?)\]/', '', $text); + $text = preg_replace('/\[mod_(.+?)\]/', '', $text); + + $text = str_replace( $fastquotes, '', $text ); + + $text = str_replace( $quotes, ' ', $text ); + + $arr = explode( " ", $text ); + + foreach ( $arr as $word ) { + if( mb_strlen( ($word) ) > 4 OR (mb_strtoupper($word)==$word) and mb_strlen( ($word) ) > 1) $newarr[] = $word; + } + + $arr = array_count_values( $newarr ); + arsort( $arr ); + + $arr = array_keys( $arr ); + + $total = count( $arr ); + + $offset = 0; + + $arr = array_slice( $arr, $offset, $this->_keyword_count ); + + $return['keywords'] = implode( ", ", $arr ); + $return['description'] = trim(mb_substr( trim($text), 0, 220 ),'.').'.'; + + return $return; + } +} diff --git a/class/class.modules.php b/class/class.modules.php new file mode 100644 index 0000000..9b84ba9 --- /dev/null +++ b/class/class.modules.php @@ -0,0 +1,604 @@ +_modules = $this->getModules(); + } + + + public static function init () + { + if (is_null(self::$instance)) + { + self::$instance = new AVE_Module; + } + + return self::$instance; + } + + + /** + * Метод, который обрабатывает все module.php и записывает как свойство класса списки модулей + */ + public function getModules () + { + $modules = []; + + // Получаем из БД информацию о всех установленных модулях + $modules_db = $this->moduleListGet(); + + // Определяем директорию, где хранятся модули + $d = dir(BASE_DIR . '/modules'); + + // Циклически обрабатываем директории + while (false !== ($entry = $d->read())) + { + if (substr($entry, 0, 1) == '.') + { + continue; + } + + if (! is_dir(BASE_DIR . '/modules/' . $entry)) + { + continue; + } + + $AVE_Template = new AVE_Template(BASE_DIR . '/admin/templates'); + + $_no_lang_file = false; + + // Языковой файл + $lang_file = BASE_DIR . '/modules/'.$entry.'/lang/' . $_SESSION['user_language'] . '.txt'; + + // Отдаем SMARTY переменные + if (file_exists($lang_file)) + { + $AVE_Template->config_load($lang_file, 'name'); + } + else + { + $_no_lang_file = true; + } + + $module_dir = $d->path . '/' . $entry; + + if (! is_dir($module_dir)) + { + continue; + } + + $module = []; + + // Если не удалось подключить основной файл модуля module.php - Фиксируем ошибку + if (! (is_file($module_dir . '/info.php') && @include_once($module_dir . '/info.php'))) + { + $modules['errors'][] = $entry; + continue; + } + + $module['ModuleName'] = !$_no_lang_file + ? $AVE_Template->get_config_vars('MODULE_NAME') + : 'No name'; + + $module['ModuleDescription'] = !$_no_lang_file + ? $AVE_Template->get_config_vars('MODULE_DESCRIPTION') + : 'No description'; + + // Дополняем массив с данными модуля + $module['permission'] = check_permission('mod_'. $module['ModuleSysName']); + + // Установлен/Не установлен по системному имени + $row = isset($modules_db[$module['ModuleSysName']]) + ? $modules_db[$module['ModuleSysName']] + : false; + + // установленные модули + if ($row) + { + $module['id'] = $row->Id; + $module['need_update'] = ($row->ModuleVersion != $module['ModuleVersion']); + $module['template'] = ($row->ModuleTemplate ? $row->ModuleTemplate : 0); + $module['ModuleAveTag'] = $row->ModuleAveTag; + $module['ModulePHPTag'] = $row->ModulePHPTag; + $module['ModuleStatus'] = $row->ModuleStatus; + $module['ModuleVersion'] = $row->ModuleVersion; + } + // неустановленные модули + else + { + $module['id'] = $module['ModuleSysName']; + $module['template'] = (! empty($module['ModuleTemplate']) ? $module['ModuleTemplate'] : ''); + $module['ModuleStatus'] = false; + } + + // записываем в массив + $modules[$module['ModuleSysName']] = $module; + + unset ($module); + } + + // Закрываем папку + $d->Close(); + + return $modules; + } + + + /** + * Метод, предназначенный для вывода модулей + * + */ + public function moduleList () + { + global $AVE_DB, $AVE_Template; + + $assign = []; // Массив для передачи в Smarty + $errors = []; // Массив с ошибками + + // Получаем список всех шаблонов + $sql = " + SELECT + Id, + template_title + FROM + " . PREFIX . "_templates + "; + + $query = $AVE_DB->Query($sql); + + while ($row = $query->FetchRow()) + { + $assign['all_templates'][$row->Id] = htmlspecialchars($row->template_title, ENT_QUOTES); + } + + // Заголовок: Автор модуля + $author_title = $AVE_Template->get_config_vars('MODULES_AUTHOR'); + + // Получаем список всех модулей + $modules = $this->_modules; + + foreach ($modules AS $module) + { + $module['info'] = $module['ModuleDescription'] . (! $module['ModuleAutor'] + ? '

      ' + : "

      $author_title
      " . $module['ModuleAutor'] . "
      ") . '
      ' . $module['ModuleCopyright'] . ''; + // установленные модули + if ($module['ModuleStatus'] !== false) + { + $installed_modules[$module['ModuleSysName']] = $module; + } + // неустановленные модули + else + { + $not_installed_modules[$module['ModuleSysName']] = $module; + } + } + + ! empty($installed_modules) + ? ksort($installed_modules) + : $installed_modules = []; + + ! empty($not_installed_modules) + ? ksort($not_installed_modules) + : $not_installed_modules = []; + + $assign['installed_modules'] = msort((array)$installed_modules,'ModuleName'); + $assign['not_installed_modules'] = msort((array)$not_installed_modules,'ModuleName'); + + // Массив с ошибками + if (! empty($modules['errors'])) + { + foreach ($modules['errors'] as $error) + { + $assign['errors'][] = $AVE_Template->get_config_vars('MODULES_ERROR') . $error; + } + } + + // Передаем данные в шаблон и отображаем страницу со списком модулей + $AVE_Template->assign($assign); + $AVE_Template->assign('content', $AVE_Template->fetch('modules/modules.tpl')); + } + + + /** + * Метод получения списка модулей + * + * @param int $status статус возвращаемых модулей + * 1 - активные модули + * 0 - неактивные модули + * если не указано возвращает модули без учета статуса + * @return array + */ + public function moduleListGet($status = null) + { + global $AVE_DB; + + $modules = array(); + + if (! empty($this->_modules)) + { + foreach ($this->_modules AS $k => $v) + { + if ($status && $v['ModuleStatus'] != $status) + { + continue; + } + + $modules[$k] = $v; + } + } + else + { + // Условие, определяющее статус документа для запроса к БД + $where_status = ($status !== null) + ? "WHERE ModuleStatus = '" . (int)$status . "'" + : ''; + + // Выполняем запрос к БД и получаем список документов, + // согласно статусу, либо все модули, если статус не указан + $sql = " + SELECT + # MODULES + * + FROM + " . PREFIX . "_module + " . $where_status . " + ORDER BY + ModuleName ASC + "; + + $query = $AVE_DB->Query($sql, -1, 'modules', true, '.modules'); + + while ($row = $query->FetchRow()) + { + $modules[$row->ModuleSysName] = $row; + } + } + + // Возвращаем список модулей + return $modules; + } + + + /** + * Метод, предназначенный для обновления в БД информации о шаблонах модулей + * + */ + public function moduleOptionsSave () + { + global $AVE_DB; + + // Циклически обрабатываем массив с информацией о шаблонах модулей + foreach ($_POST['Template'] as $id => $template_id) + { + // Обновление информации о шаблоне модуля + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_module + SET + ModuleTemplate = '" . (int)$template_id . "' + WHERE + Id = '" . (int)$id . "' + "); + } + + $this->clearModulesCache (); + + // Выполняем обновление страницы со списком модулей + header('Location:index.php?do=modules&cp=' . SESSION); + exit; + } + + + /** + * Метод, предназначенный для установки или переустановки модуля + * + */ + public function moduleInstall () + { + global $AVE_DB, $AVE_Template; + + // Получаем данные модуля + $modules = $this->_modules; + + // Выбираем нужный нам модуль + $module = $modules[MODULE_PATH]; + + // Удаляем информацию о модуле в таблице module + $sql = " + DELETE + FROM + " . PREFIX . "_module + WHERE + ModuleSysName = '" . MODULE_PATH . "' + "; + + $AVE_DB->Query($sql); + + // Определяем, имеет ли модуль возможность настройки в Панели управления + $module['ModuleAdminEdit'] = (! empty($module['ModuleAdminEdit'])) + ? $module['ModuleAdminEdit'] + : 0; + + // Определяем, имеет ли модуль возможность смены шаблона + $module['ModuleTemplate'] = ($module['ModuleTemplate']) + ? $module['ModuleTemplate'] + : 0; + + // Добавляем информацию о модуле в таблицу module + $sql = " + INSERT INTO + " . PREFIX . "_module + SET + ModuleName = '" . $module['ModuleName'] . "', + ModuleStatus = '1', + ModuleAveTag = '" . $module['ModuleAveTag'] . "', + ModulePHPTag = '" . $module['ModulePHPTag'] . "', + ModuleFunction = '" . $module['ModuleFunction'] . "', + ModuleIsFunction = '" . $module['ModuleIsFunction'] . "', + ModuleSysName = '" . MODULE_PATH . "', + ModuleVersion = '" . $module['ModuleVersion'] . "', + ModuleTemplate = '" . $module['ModuleTemplate'] . "', + ModuleAdminEdit = '" . $module['ModuleAdminEdit'] . "' + "; + + $AVE_DB->Query($sql); + + // Подключаем файл с запросами к БД для данного модуля + $module_sql_deinstall = []; + $module_sql_install = []; + $sql_file = BASE_DIR . '/modules/' . MODULE_PATH . '/sql.php'; + + if (is_file($sql_file) && @include($sql_file)) + { + // Выполняем запросы удаления таблиц модуля + // из массива $module_sql_deinstall файла sql.php + foreach ($module_sql_deinstall AS $sql) + { + $AVE_DB->Query(str_replace('%%PRFX%%', PREFIX, $sql)); + } + + // Выполняем запросы создания таблиц и данных модуля + // из массива $module_sql_install файла sql.php + foreach ($module_sql_install AS $sql) + { + $AVE_DB->Query(str_replace('%%PRFX%%', PREFIX, $sql)); + } + } + // Сохраняем системное сообщение в журнал + ($_REQUEST['action'] == 'reinstall') + ? reportLog($AVE_Template->get_config_vars('MODULES_ACTION_REINSTALL') . ' (' . $module['ModuleName'] . ')') + : reportLog($AVE_Template->get_config_vars('MODULES_ACTION_INSTALL') . ' (' . $module['ModuleName'] . ')'); + + $this->clearModulesCache(); + + // Выполняем обновление страницы со списком модулей + header('Location:index.php?do=modules&cp=' . SESSION); + exit; + } + + + /** + * Метод, предназначенный для обновления модуля при увеличении номера версии модуля + * + */ + public function moduleUpdate () + { + global $AVE_DB, $AVE_Template; + + // Подключаем файл с запросами к БД для данного модуля + $module_sql_update = []; + + $module = []; + + $sql_file = BASE_DIR . '/modules/' . MODULE_PATH . '/sql.php'; + + $mod_file = BASE_DIR . '/modules/' . MODULE_PATH . '/info.php'; + + if (file_exists($mod_file) && file_exists($sql_file)) + { + include ($mod_file); + include ($sql_file); + + // Выполняем запросы обновления модуля + // из массива $module_sql_update файла sql.php + foreach ($module_sql_update AS $sql) + { + $AVE_DB->Query(str_replace('%%PRFX%%', PREFIX, $sql)); + } + } + // Обновляем модуль, если в нем не применяется (отсутствует) файл sql.php + elseif (file_exists($mod_file) && file_exists($sql_file) === false) + { + include ($mod_file); + + if (isset ($module) && ! empty($module)) + { + $sql = " + UPDATE + " . PREFIX . "_module + SET + ModuleAveTag = '" . $module['ModuleAveTag'] . "', + ModulePHPTag = '" . $module['ModulePHPTag'] . "', + ModuleFunction = '" . $module['ModuleFunction'] . "', + ModuleIsFunction = '" . $module['ModuleIsFunction'] . "', + ModuleSysName = '" . MODULE_PATH . "', + ModuleVersion = '" . $module['ModuleVersion'] . "', + ModuleTemplate = '" . $module['ModuleTemplate'] . "', + ModuleAdminEdit = '" . $module['ModuleAdminEdit'] . "', + ModuleStatus = '1' + WHERE + ModuleSysName = '" . MODULE_PATH . "' + "; + + $AVE_DB->Query($sql); + } + + } + // Сохраняем системное сообщение в журнал + reportLog ($AVE_Template->get_config_vars('MODULES_ACTION_UPDATE') . ' (' . MODULE_PATH . ')'); + + $this->clearModulesCache(); + + // Выполняем обновление страницы со списком модулей + header('Location:index.php?do=modules&cp=' . SESSION); + exit; + } + + + /** + * Метод, предназначенный для удаление модуля + * + */ + public function moduleDelete () + { + global $AVE_DB, $AVE_Template; + + // Подключаем файл с запросами к БД для данного модуля + $module_sql_deinstall = []; + + $sql_file = BASE_DIR . '/modules/' . MODULE_PATH . '/sql.php'; + + if (is_file($sql_file) && @include($sql_file)) + { + // Выполняем запросы удаления таблиц модуля + // из массива $module_sql_deinstall файла sql.php + foreach ($module_sql_deinstall as $sql) + { + $AVE_DB->Query(str_replace('%%PRFX%%', PREFIX, $sql)); + } + } + + // Удаляем информацию о модуле в таблице module + $sql = " + DELETE + FROM + " . PREFIX . "_module + WHERE + ModuleSysName = '" . MODULE_PATH . "' + "; + + $AVE_DB->Query($sql); + + $this->clearModulesCache(); + + // Сохраняем системное сообщение в журнал + reportLog ($AVE_Template->get_config_vars('MODULES_ACTION_DELETE') .' (' . MODULE_PATH . ')'); + + // Выполняем обновление страницы со списком модулей + header('Location:index.php?do=modules&cp=' . SESSION); + exit; + } + + + /** + * Метод, предназначенный для отключения/включение модуля в Панели управления + * + */ + public function moduleStatusChange () + { + global $AVE_DB, $AVE_Template; + + $sql = " + SELECT + ModuleName, + ModuleStatus + FROM + " . PREFIX . "_module + WHERE + ModuleSysName = '" . MODULE_PATH . "' + "; + + $status = $AVE_DB->Query($sql)->FetchRow(); + + $ModuleStatus = ($status->ModuleStatus == '0' || $status->ModuleStatus == NULL) + ? '1' + : '0'; + + // Выполняем запрос к БД на смену статуса модуля + $sql = " + UPDATE + " . PREFIX . "_module + SET + ModuleStatus = '" . $ModuleStatus . "' + WHERE + ModuleSysName = '" . MODULE_PATH . "' + "; + + $AVE_DB->Query($sql); + + $this->clearModulesCache (); + + // Сохраняем системное сообщение в журнал + reportLog ((($ModuleStatus == '0') + ? $AVE_Template->get_config_vars('MODULES_ACTION_OFFLINE') + : $AVE_Template->get_config_vars('MODULES_ACTION_ONLINE')) . ' (' . $status->ModuleName . ')'); + + // Выполняем обновление страницы со списком модулей + header('Location:index.php?do=modules&cp=' . SESSION); + exit; + } + + + public function moduleRemove ($dir) + { + global $AVE_Template; + + $directory = BASE_DIR . '/modules/' . $dir; + + $files = glob($directory . '*', GLOB_MARK); + + foreach ($files as $file) + { + if (substr($file, -1) == '/') + { + $this->moduleRemove($file); + } + else + { + unlink($file); + } + } + + rrmdir ($directory); + + $this->clearModulesCache(); + + // Сохраняем системное сообщение в журнал + reportLog ($AVE_Template->get_config_vars('MODULES_ACTION_REMOVE') . ' (' . $dir . ')'); + + // Выполняем обновление страницы со списком модулей + header('Location:index.php?do=modules&cp=' . SESSION); + exit; + } + + + /** + * Функция очищает кеш системных настроек + * + */ + public function clearModulesCache() + { + $cache_dir = BASE_DIR . '/tmp/cache/sql/modules/'; + + return rrmdir($cache_dir); + } + } +?> \ No newline at end of file diff --git a/class/class.navigation.php b/class/class.navigation.php new file mode 100644 index 0000000..73d2b04 --- /dev/null +++ b/class/class.navigation.php @@ -0,0 +1,1306 @@ +<\''); + return $text; + } + + /** + * Внутренние методы + */ + + /** + * Проверка алиаса тега на валидность и уникальность + */ + function navigationValidate ($alias = '', $id = 0) + { + global $AVE_DB; + + //-- Соответствие требованиям + if (empty ($alias) || preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $alias) !== 1 || is_numeric($alias)) + return 'syn'; + + //-- Уникальность + return !(bool)$AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_navigation + WHERE + alias = '" . $alias . "' + AND + navigation_id != '" . $id . "' + ")->GetCell(); + } + + + /** + * Метод, предназначенный для вывода списка всех существующих меню навигаций в Паели управления + * + */ + function navigationList() + { + global $AVE_DB, $AVE_Template; + + $navigations = array(); + + // Выполняем запрос к БД на получение списка всех меню навигаций + $sql = $AVE_DB->Query(" + SELECT + navigation_id, + alias, + title + FROM + " . PREFIX . "_navigation + ORDER BY + navigation_id ASC + "); + + // Формируем данные в массив + while ($row = $sql->FetchRow()) + { + array_push($navigations, $row); + } + + // Передаем данные в шаблон для вывода и отображаем страницу со списком меню + $AVE_Template->assign('nid', 0); + $AVE_Template->assign('navigations', $navigations); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/list.tpl')); + } + + + + /** + * Метод, предназначенный для добавления нового меню + * + */ + function navigationNew() + { + global $AVE_DB, $AVE_Template, $AVE_User; + + // Определяем действие пользователя + switch($_REQUEST['sub']) + { + // Если действие не определено, отображаем чистую форму для создания шаблона навигации + case '': + + // Передаем данные в шаблон и отображаем страницу для добавления нового шаблона меню + $AVE_Template->assign('groups', $AVE_User->userGroupListGet()); + $AVE_Template->assign('form_action', 'index.php?do=navigation&action=new&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/template.tpl')); + break; + + + // Если пользователь нажал на кнопку Добавить (Сохранить) + case 'save': + + // Определяем название меню навигации + $navigation_title = (empty($_REQUEST['title'])) ? 'title' : $_REQUEST['title']; + + // Определяем шаблон оформления 1-го уровня ссылок + // в меню. Если шаблон не указан пользователем,тогда + // используем вариант "по умолчанию" + $navigation_level1 = (empty($_REQUEST['level1'])) ? "[tag:linkname]" : $_REQUEST['level1']; + $navigation_level1_active = (empty($_REQUEST['level1_active'])) ? "[tag:linkname]" : $_REQUEST['level1_active']; + + // Выполняем запрос к БД на добавление нового меню + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_navigation + SET + navigation_id = '', + alias = '" . $_REQUEST['alias'] . "', + title = '" . $navigation_title . "', + level1 = '" . $navigation_level1 . "', + level1_active = '" . $navigation_level1_active . "', + level2 = '" . $_REQUEST['level2'] . "', + level2_active = '" . $_REQUEST['level2_active'] . "', + level3 = '" . $_REQUEST['level3'] . "', + level3_active = '" . $_REQUEST['level3_active'] . "', + level1_begin = '" . $_REQUEST['level1_begin'] . "', + level2_begin = '" . $_REQUEST['level2_begin'] . "', + level3_begin = '" . $_REQUEST['level3_begin'] . "', + level1_end = '" . $_REQUEST['level1_end'] . "', + level2_end = '" . $_REQUEST['level2_end'] . "', + level3_end = '" . $_REQUEST['level3_end'] . "', + begin = '" . $_REQUEST['begin'] . "', + end = '" . $_REQUEST['end'] . "', + user_group = '" . (empty($_REQUEST['user_group']) ? '' : implode(',', $_REQUEST['user_group'])) . "', + expand_ext = '" . $_REQUEST['expand_ext'] . "' + "); + + $navigation_id = $AVE_DB->getLastInsertId(); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_NEW') . " (" . stripslashes($navigation_title) . ") (ID: $navigation_id)"); + + // Выполянем переход к списку меню навигаций + header('Location:index.php?do=navigation&cp=' . SESSION); + break; + } + } + + + + /** + * Метод, предназначенный для редактирования шаблона навигации + * + * @param int $navigation_id идентификатор меню навигации + */ + function navigationEdit($navigation_id) + { + global $AVE_DB, $AVE_Template, $AVE_User; + + // Определяем действие пользователя + switch ($_REQUEST['sub']) + { + // Если действие не определено, отображаем форму с данными для редактирования + case '': + + // Выполняем запрос к БД и получаем всю информацию о данном меню + $row = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = '" . $navigation_id . "' + OR + alias = '" . $navigation_id . "' + ")->FetchRow(); + + // Формируем список групп пользователей + $row->user_group = explode(',', $row->user_group); + + // Формируем ряд переменных для использования в шаблоне и отображаем форм с данными для редактирования + $AVE_Template->assign('nid', $row->navigation_id); + $AVE_Template->assign('navigation', $row); + $AVE_Template->assign('groups', $AVE_User->userGroupListGet()); + $AVE_Template->assign('form_action', 'index.php?do=navigation&action=templates&sub=save&navigation_id=' . $navigation_id . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/template.tpl')); + break; + + // Если пользователь нажал на кнопку Сохранить изменения + case 'save': + + // Выполняем запрос к БД и обновляем информацию в таблице для данного меню + $sql = $AVE_DB->Query(" + UPDATE " . PREFIX . "_navigation + SET + title = '" . $_REQUEST['title'] . "', + alias = '" . $_REQUEST['alias'] . "', + level1 = '" . $_REQUEST['level1'] . "', + level1_active = '" . $_REQUEST['level1_active'] . "', + level2 = '" . $_REQUEST['level2'] . "', + level2_active = '" . $_REQUEST['level2_active'] . "', + level3 = '" . $_REQUEST['level3'] . "', + level3_active = '" . $_REQUEST['level3_active'] . "', + level1_begin = '" . $_REQUEST['level1_begin'] . "', + level2_begin = '" . $_REQUEST['level2_begin'] . "', + level3_begin = '" . $_REQUEST['level3_begin'] . "', + level1_end = '" . $_REQUEST['level1_end'] . "', + level2_end = '" . $_REQUEST['level2_end'] . "', + level3_end = '" . $_REQUEST['level3_end'] . "', + begin = '" . $_REQUEST['begin'] . "', + end = '" . $_REQUEST['end'] . "', + user_group = '" . (empty($_REQUEST['user_group']) ? '' : implode(',', $_REQUEST['user_group'])) . "', + expand_ext = '" . $_REQUEST['expand_ext'] . "' + WHERE + navigation_id = '" . $navigation_id . "' + "); + + //-- Стираем кеш навигации + $this->clearCache($navigation_id, $_REQUEST['alias']); + $this->clearCacheNav($navigation_id, $_REQUEST['alias']); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('NAVI_REPORT_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('NAVI_REPORT_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('NAVI_REPORT_SAVED'); + $header = $AVE_Template->get_config_vars('NAVI_REPORT_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_EDIT') . " (" . stripslashes($_REQUEST['title']) . ") (ID: $navigation_id)"); + } + + if (isAjax()) + { + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme + ) + ); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=navigation&cp=' . SESSION); + } + exit; + } + } + + + + /** + * Метод, предназначенный для копирования шаблона меню + * + * @param int $navigation_id идентификатор меню навигации источника + */ + function navigationCopy($navigation_id) + { + global $AVE_DB, $AVE_Template; + + // Если в запросе указано числовое значение id меню + if (is_numeric($navigation_id)) + { + // Выполняем запрос к БД на получение информации о копируемом меню + $row = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = '" . $navigation_id . "' + ")->FetchRow(); + + // Если данные получены, тогда + if ($row) + { + // Выполняем запрос к БД на добавление нового меню и сохраняем информацию с учетом данных, + // полученных в предыдущем запросе к БД + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_navigation + SET + navigation_id = '', + title = '" . addslashes((empty($_REQUEST['title']) ? $row->title : $_REQUEST['title'])) . "', + alias = '', + level1 = '" . addslashes($row->level1) . "', + level1_active = '" . addslashes($row->level1_active) . "', + level2 = '" . addslashes($row->level2) . "', + level2_active = '" . addslashes($row->level2_active) . "', + level3 = '" . addslashes($row->level3) . "', + level3_active = '" . addslashes($row->level3_active) . "', + level1_begin = '" . addslashes($row->level1_begin) . "', + level2_begin = '" . addslashes($row->level2_begin) . "', + level3_begin = '" . addslashes($row->level3_begin) . "', + level1_end = '" . addslashes($row->level1_end) . "', + level2_end = '" . addslashes($row->level2_end) . "', + level3_end = '" . addslashes($row->level3_end) . "', + begin = '" . addslashes($row->begin) . "', + end = '" . addslashes($row->end) . "', + user_group = '" . addslashes($row->user_group) . "', + expand_ext = '" . $row->expand_ext . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_COPY') . " (" . (empty($_REQUEST['title']) ? $row->title : $_REQUEST['title']) . ") (ID: $navigation_id)"); + } + } + + // Выполянем переход к списку меню навигаций + header('Location:index.php?do=navigation&cp=' . SESSION); + } + + + + /** + * Метод, предназначенный для удаления меню навигации и всех пунктов относящихся к нему + * + * @param int $navigation_id идентификатор меню навигации + */ + function navigationDelete($navigation_id) + { + global $AVE_DB, $AVE_Template; + + // Если id меню числовой и это не первое меню (id не 1) + if (is_numeric($navigation_id) && $navigation_id != 1) + { + + $sql= $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = '" . $navigation_id . "' + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($navigation_id, $sql->alias); + + //-- Выполняем запрос к БД на удаление общей информации и шаблона оформления меню + $AVE_DB->Query("DELETE FROM " . PREFIX . "_navigation WHERE navigation_id = '" . $navigation_id . "'"); + //-- Выполняем запрос к БД на удаление всех пунктов для данного меню + $AVE_DB->Query("DELETE FROM " . PREFIX . "_navigation_items WHERE navigation_id = '" . $navigation_id . "'"); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_DEL') . " (" . stripslashes($sql->title) . ") (ID: $navigation_id)"); + } + + //-- Выполянем переход к списку меню навигаций + header('Location:index.php?do=navigation&cp=' . SESSION); + } + + + + /** + * Метод, предназначенный для получения списка всех пунктов у всех меню навигации + * + */ + function navigationAllItemList() + { + global $AVE_DB, $AVE_Template; + + $navigations = array(); + + //-- Выполняем запрос к БД на получение id и названия меню навигации + $sql = $AVE_DB->Query(" + SELECT + navigation_id, + title + FROM + " . PREFIX . "_navigation + "); + + $items = null; + + //-- Циклически обрабатываем полученные данные + while ($navigation = $sql->FetchRow()) + { + //-- Выполняем запрос к БД на получение всех пунктов для каждого меню. + $sql_items = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_id = " . (int)$navigation->navigation_id . " + AND + parent_id = 0 + ORDER BY + position ASC + "); + + while ($row = $sql_items->FetchAssocArray()) + { + //-- имя связанного документа + if ($row['document_id'] > 0) + { + $doc_info = get_document((int)$row['document_id']); + $row['document_title'] = (($doc_info['document_breadcrum_title']) ? $doc_info['document_breadcrum_title'] : $doc_info['document_title']); + } + else + { + $row['document_title'] = ''; + } + + $row['children'] = $this->getChildrenById($row['navigation_item_id'], 0, true); + + if (! empty($item_id)) + $items = $row; + else + $items[] = $row; + } + + $navigation->navigation_items = $items; + + unset($items); + + array_push($navigations, $navigation); + } + + //-- Передаем полученные данные в шаблон для вывода + $AVE_Template->assign('navigations', $navigations); + $AVE_Template->assign('select_tpl', 'navigation/select.tpl'); + } + + + /** + * Метод, предназначенный для вывода пунктов меню навигации в Панели управления + * + * @param int $id идентификатор меню навигации + */ + function navigationItemList($navigation_id) + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_id = " . (int)$navigation_id . " + AND + parent_id = 0 + ORDER BY + position ASC + "); + + $items = array(); + + while ($row = $sql->FetchAssocArray()) + { + // имя связанного документа + if ($row['document_id'] > 0) + { + $doc_info = get_document((int)$row['document_id']); + $row['document_title'] = (($doc_info['document_breadcrum_title']) + ? $doc_info['document_breadcrum_title'] + : $doc_info['document_title']); + } + else + { + $row['document_title'] = ''; + } + + $row['children'] = $this->getChildrenById($row['navigation_item_id'], 0, true); + + if (! empty($item_id)) + $items = $row; + else + $items[] = $row; + } + + $navigation = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = '" . $navigation_id . "' + ")->FetchRow(); + + $AVE_Template->assign('navigation', $navigation); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('level', 1); + + $AVE_Template->assign('nestable_tpl', 'navigation/nestable.tpl'); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/items.tpl')); + } + + + /** + * Метод для рекурсивного получения + * пунктов меню навигации в Панели управления + */ + public function getChildrenById($navigation_item_id, $rec_status = 1, $recurse = false) + { + global $AVE_DB; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + parent_id = " . $navigation_item_id . " + ORDER BY + position ASC + "); + + $children = array(); + + while($row = $sql->FetchAssocArray()) + { + if($recurse) + { + // имя связанного документа + if ($row['document_id'] > 0) + { + $doc_info = get_document((int)$row['document_id']); + $row['document_title'] = (($doc_info['document_breadcrum_title']) + ? $doc_info['document_breadcrum_title'] + : $doc_info['document_title']); + } + else + { + $row['document_title'] = ''; + } + + $row['children'] = $this->getChildrenById($row['navigation_item_id'], $rec_status,$recurse); + } + + $children[] = $row; + } + + return ((count($children) > 0) + ? $children + : false + ); + } + + + /** + * Метод, предназначенный для управления пунктами меню навигации в Панели управления + * + * @param int $id идентификатор меню навигации + */ + function navigationItemEdit($navigation_item_id = null) + { + global $AVE_DB, $AVE_Template; + + // Определяем действие пользователя + switch ($_REQUEST['sub']) + { + // Если действие не определено, отображаем форму с данными для редактирования + case 'new': + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_id = " . (int)$_REQUEST['navigation_id'] . " + AND + parent_id = 0 + ORDER BY + position ASC + "); + + $items = array(); + + while ($row = $sql->FetchAssocArray()) + { + $row['css_style'] = stripslashes($row['css_style']); + + // имя связанного документа + if ($row['document_id'] > 0) + { + $doc_info = get_document((int)$row['document_id']); + + $row['document_title'] = (($doc_info['document_breadcrum_title']) + ? $doc_info['document_breadcrum_title'] + : $doc_info['document_title']); + } + else + { + $row['document_title'] = ''; + } + + $row['children'] = $this->getChildrenById($row['navigation_item_id'], 0, true); + + if (! empty($item_id)) + $items = $row; + else + $items[] = $row; + } + + $alias = $AVE_DB->Query(" + SELECT + alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $_REQUEST['navigation_id'] . " + ")->GetCell(); + + //-- Стираем кеш навигации + $this->clearCache($_REQUEST['navigation_id'], $alias); + + $AVE_Template->assign('select_tpl', 'navigation/select.tpl'); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/item_new.tpl')); + break; + + case 'edit': + + $item = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = " . $navigation_item_id . " + ")->FetchRow(); + + $item->css_style = stripslashes($item->css_style); + + if ($item->document_id) + $doc_info = get_document((int)$item->document_id); + + $item->document_title = (($doc_info['document_breadcrum_title']) + ? $doc_info['document_breadcrum_title'] + : $doc_info['document_title']); + + $item->document_alias = $doc_info['document_alias']; + + $AVE_Template->assign('item', $item); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/item_edit.tpl')); + break; + + case 'save': + + $_REQUEST['alias'] = (strpos($_REQUEST['alias'], 'javascript') !== false) + ? str_replace(array(' ', '%'), '-', $_REQUEST['alias']) + : $_REQUEST['alias']; + + // Определяем флаг статуса пункта меню (активен/неактивен) + $status = (empty($_REQUEST['alias'])) + ? 0 + : 1; + + if ($navigation_item_id) + { + // Выполняем запрос к БД и обновляем информацию в таблице для данного меню + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + document_id = '" . (($_REQUEST['document_id']) ? (int)$_REQUEST['document_id'] : '') . "', + title = '" . $this->_replace_wildcode($_REQUEST['title']) . "', + alias = '" . $_REQUEST['alias'] . "', + description = '" . $this->_replace_wildcode($_REQUEST['description']) . "', + image = '" . $_REQUEST['image'] . "', + css_style = '" . addslashes($_REQUEST['css_style']) . "', + css_class = '" . $_REQUEST['css_class'] . "', + css_id = '" . $_REQUEST['css_id'] . "', + target = '" . $_REQUEST['target'] . "', + status = '" . $status . "' + WHERE + navigation_item_id = '" . $navigation_item_id . "' + "); + + $navigation_id = $AVE_DB->Query(" + SELECT + navigation_id + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $navigation_item_id . "' + ")->GetCell(); + + $alias = $AVE_DB->Query(" + SELECT + alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $navigation_id . " + ")->GetCell(); + + //-- Стираем кеш навигации + $this->clearCache($_REQUEST['navigation_id'], $alias); + } + else + { + if ($_REQUEST['after']) + $after = $AVE_DB->Query("SELECT * FROM ".PREFIX."_navigation_items WHERE navigation_item_id = '" . $_REQUEST['after'] . "' ")->FetchArray(); + else + $after = array('parent_id' => 0, 'level' => 1, 'position' => 0); + + // Выполняем запрос к БД и обновляем информацию в таблице для данного меню + $sql = $AVE_DB->Query(" + INSERT + " . PREFIX . "_navigation_items + SET + navigation_id = '" . $_REQUEST['navigation_id'] . "', + document_id = '" . (($_REQUEST['document_id']) ? (int)$_REQUEST['document_id'] : '') . "', + title = '" . $this->_replace_wildcode($_REQUEST['title']) . "', + alias = '" . $_REQUEST['alias'] . "', + description = '" . $this->_replace_wildcode($_REQUEST['description']) . "', + image = '" . $_REQUEST['image'] . "', + css_style = '" . addslashes($_REQUEST['css_style']) . "', + css_class = '" . $_REQUEST['css_class'] . "', + css_id = '" . $_REQUEST['css_id'] . "', + target = '" . $_REQUEST['target'] . "', + parent_id = '" . $after['parent_id'] . "', + level = '" . $after['level'] . "', + position = '" . $after['position'] . "', + status = '" . $status . "' + "); + + $navigation_item_id = $AVE_DB->getLastInsertId(); + + $alias = $AVE_DB->Query(" + SELECT + alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $_REQUEST['navigation_id'] . " + ")->GetCell(); + + //-- Стираем кеш навигации + $this->clearCache($_REQUEST['navigation_id'], $alias); + } + + $message = 'Пункт меню успешно сохранен'; + $header = 'Выполнено'; + $theme = 'accept'; + + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme, + 'after' => $_REQUEST['after'], + 'item_id' => $navigation_item_id) + ); + exit; + } + /* + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_ADDIT') . " (" . $this->_replace_wildcode($title) . ") - ". $AVE_Template->get_config_vars('NAVI_REPORT_TLEV')); + + // Выполняем обновление страницы + header('Location:index.php?do=navigation&action=entries&id=' . $nav_id . '&cp=' . SESSION); + exit; + */ + } + + + + /** + * Метод, предназначенный для удаления пунктов меню навигации связанных с удаляемым документом. + * Данный метод вызывается при удалении документа с идентификатором $document_id. + * Если у пункта меню нет потомков - пункт удаляется, в противном случае пункт деактивируется + * + * @param int $document_id идентификатор удаляемого документа + */ + function navigationItemDeleteFromDoc($document_id) + { + global $AVE_DB, $AVE_Template; + + if (! is_numeric($document_id)) + return; + + // Выполняем запрос к БД и получаем ID пункта меню, с которым связан документ + $sql = $AVE_DB->Query(" + SELECT + navigation_item_id + FROM + " . PREFIX . "_navigation_items + WHERE + document_id = '" . $document_id . "' + "); + + while ($row = $sql->FetchRow()) + { + // Выполняем запрос к БД для определения у удаляемого пункта подпунктов + $num = $AVE_DB->Query(" + SELECT + COUNT(1) + FROM + " . PREFIX . "_navigation_items + WHERE + parent_id = '" . $row->navigation_item_id . "' + ")->GetCell(); + + // Если данный пункт имеет подпункты, тогда + if ($num > 0) + { + // Выполняем запрос к БД и деактивируем пункт меню + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + status = '0' + WHERE + navigation_item_id = '" . $row->navigation_item_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_DEACT') . " (id: $row->navigation_item_id)"); + } + else + { // В противном случае, если данный пункт не имеет подпунктов, тогда + + // Выполняем запрос к БД и удаляем помеченный пункт + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $row->navigation_item_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_DELIT') . " (id: $row->navigation_item_id)"); + } + } + } + + + /** + * Метод, предназначенный для удаления пункта меню навигации в Панели управления + * + * @param int $navigation_item_id идентификатор меню навигации + */ + function navigationItemDelete($navigation_item_id) + { + global $AVE_DB, $AVE_Template; + + if (!is_numeric($navigation_item_id)) + return; + + // Выполняем запрос к БД для определения у удаляемого пункта подпунктов + $num = $AVE_DB->Query(" + SELECT + COUNT(1) + FROM + " . PREFIX . "_navigation_items + WHERE + parent_id = '" . $navigation_item_id . "' + ")->GetCell(); + + // Если данный пункт имеет подпункты, тогда + if ($num > 0) + { + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $navigation_item_id . "' + LIMIT 1 + ")->FetchRow(); + + // Выполняем запрос к БД и деактивируем пункт меню + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + status = '0' + WHERE + navigation_item_id = '" . $navigation_item_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_DEACT') . " (" . stripslashes($sql->title) . ") (id: $navigation_item_id)"); + } + else + { + // В противном случае, если данный пункт не имеет подпунктов, тогда + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $navigation_item_id . "' + LIMIT 1 + ")->FetchRow(); + + // Выполняем запрос к БД и удаляем помеченный пункт + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $navigation_item_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_DELIT') . " (" . stripslashes($sql->title) . ") (id: $navigation_item_id)"); + } + + $nav = $AVE_DB->Query(" + SELECT + navigation_id, alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $sql->navigation_id . " + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($nav->navigation_id, $nav->alias); + + // Выполняем обновление страницы + header('Location:' . get_referer_admin_link()); + exit; + } + + + /** + * Метод, предназначенный для активации пункта меню навигации. + * Данный метод используется при изменении статуса документа с идентификатором $document_id + * + * @param int $document_id идентификатор документа на который ссылается пункт меню + */ + function navigationItemStatusOn($document_id) + { + global $AVE_DB, $AVE_Template; + + if (!is_numeric($document_id)) + return; + + // Выполняем запрос к БД и получаем id пункта меню, который соответствует идентификатору документа в ссылке + $sql = $AVE_DB->Query(" + SELECT + navigation_id, + navigation_item_id + FROM + " . PREFIX . "_navigation_items + WHERE + document_id = '" . $document_id . "' + AND + status = '0' + "); + + while ($row = $sql->FetchRow()) + { + // Выполняем запрос к БД изменяем статус пункта меню на активный (1) + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + status = '1' + WHERE + navigation_item_id = '" . $row->navigation_item_id . "' + "); + + $nav = $AVE_DB->Query(" + SELECT + navigation_id, alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $row->navigation_id . " + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($nav->navigation_id, $nav->alias); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_ACT') . " (id: $row->navigation_item_id)"); + } + + + } + + /** + * Метод, предназначенный для деактивации пункта меню навигации. + * Данный метод используется при изменении статуса документа с идентификатором $document_id + * + * @param int $document_id идентификатор документа на который ссылается пункт меню + */ + function navigationItemStatusOff($document_id) + { + global $AVE_DB, $AVE_Template; + + if (! is_numeric($document_id)) + return; + + // Выполняем запрос к БД и получаем id пункта меню, + // который соответствует идентификатору документа в ссылке + $sql = $AVE_DB->Query(" + SELECT + navigation_id, + navigation_item_id + FROM + " . PREFIX . "_navigation_items + WHERE + document_id = '" . $document_id . "' + AND + status = '1' + "); + + while ($row = $sql->fetchrow()) + { + // Выполняем запрос к БД изменяем статус пункта меню на неактивный (0) + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + status = '0' + WHERE + navigation_item_id = '" . $row->navigation_item_id . "' + "); + + + $nav = $AVE_DB->Query(" + SELECT + navigation_id, alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $row->navigation_id . " + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($nav->navigation_id, $nav->alias); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('NAVI_REPORT_DEACT') . " (id: $row->navigation_item_id)"); + } + } + + /** + * Метод, предназначенный для активации пункта меню навигации. + * Данный метод используется при изменении статуса документа с идентификатором $document_id + * + * @param int $document_id идентификатор документа на который ссылается пункт меню + */ + function navigationItemGet($navigation_item_id) + { + global $AVE_DB, $AVE_Template; + + if (! is_numeric($navigation_item_id)) + return; + + // Выполняем запрос к БД и получаем id пункта меню, который соответствует идентификатору документа в ссылке + $item = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $navigation_item_id . "' + ")->FetchAssocArray(); + + if ($item['document_id']) + $doc_info = get_document((int)$item['document_id']); + + $item['document_title'] = (($doc_info['document_breadcrum_title']) + ? $doc_info['document_breadcrum_title'] + : $doc_info['document_title']); + + $item['document_alias'] = $doc_info['document_alias']; + + $nav = $AVE_DB->Query(" + SELECT + navigation_id, alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $item['navigation_id'] . " + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($nav->navigation_id, $nav->alias); + + $AVE_Template->assign('item', $item); + $AVE_Template->assign('content', $AVE_Template->fetch('navigation/item.tpl')); + } + + /** + * Метод, предназначенный для рекурсивоной + * сортировки пунктов меню навигации. + */ + function navigationSort() + { + global $AVE_DB, $AVE_Template; + + $level = 1; + + $navigation_id = (int)$_REQUEST['navigation_id']; + + foreach ($_REQUEST['data'] as $item_id => $item) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + level = '" . $level . "', + parent_id = '0', + position = '" . (int)$item_id . "' + WHERE + navigation_item_id = " . $item['id'] ." + AND + navigation_id = " . $navigation_id . " + "); + + if (is_array($item['children'])) + { + $this->navigationSortNested($item['children'], $item['id'], $level, $navigation_id); + } + } + + $nav = $AVE_DB->Query(" + SELECT + navigation_id, alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $navigation_id . " + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($nav->navigation_id, $nav->alias); + + if (isAjax()) + { + echo json_encode( + array( + 'message' => $AVE_Template->get_config_vars('NAVI_SORTED'), + 'header' => $AVE_Template->get_config_vars('NAVI_REPORT_SUCCESS'), + 'theme' => 'accept' + ) + ); + } + + exit; + } + + /** + * Метод, предназначенный для рекурсивоной + * сортировки пунктов меню навигации. + */ + function navigationSortNested($array = array(), $parent_id = null, $level = null, $navigation_id = null) + { + global $AVE_DB; + + $level++; + + foreach($array as $key => $value) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + level = '" . $level . "', + parent_id = '" . (int)$parent_id . "', + position = '" . $key . "' + WHERE + navigation_item_id = " . $value['id'] . " + AND + navigation_id = " . $navigation_id . " + "); + + if (is_array($value['children'])) + { + $this->navigationSortNested($value['children'], $value['id'], $level, $navigation_id); + } + } + } + + + function getDocumentById($doc_id = null) + { + $document = get_document($doc_id); + + echo json_encode( + array( + 'doc_id' => $doc_id, + 'document_title' => $document['document_title'], + 'document_alias' => $document['document_alias'] + ) + ); + exit; + } + + + function navigationItemStatus($navigation_item_id, $status = 1) + { + global $AVE_DB; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_navigation_items + SET + status = '" . $status . "' + WHERE + navigation_item_id = '" . $navigation_item_id . "' + "); + + $navigation_id = $AVE_DB->Query(" + SELECT + navigation_id + FROM + " . PREFIX . "_navigation_items + WHERE + navigation_item_id = '" . $navigation_item_id . "' + ")->GetCell(); + + $nav = $AVE_DB->Query(" + SELECT + navigation_id, alias + FROM + " . PREFIX . "_navigation + WHERE + navigation_id = " . $navigation_id . " + ")->FetchRow(); + + //-- Стираем кеш навигации + $this->clearCache($nav->navigation_id, $nav->alias); + + echo json_encode( + array( + 'status' => ($status == 0 ? 1 : 0) + ) + ); + + exit; + } + + + function clearCache($id, $alias = '') + { + if (file_exists(BASE_DIR . '/tmp/cache/sql/navigations/' . $id . '/template.cache')) + unlink(BASE_DIR . '/tmp/cache/sql/navigations/' . $id . '/template.cache'); + + if (file_exists(BASE_DIR . '/tmp/cache/sql/navigations/' . $alias . '/template.cache')) + unlink(BASE_DIR . '/tmp/cache/sql/navigations/' . $alias . '/template.cache'); + + if (file_exists(BASE_DIR . '/tmp/cache/sql/navigations/' . $id . '/items.cache')) + unlink(BASE_DIR . '/tmp/cache/sql/navigations/' . $id . '/items.cache'); + + if (file_exists(BASE_DIR . '/tmp/cache/sql/navigations/' . $alias . '/items.cache')) + unlink(BASE_DIR . '/tmp/cache/sql/navigations/' . $alias . '/items.cache'); + } + + + function clearCacheNav($id, $alias) + { + $cache_id = explode('_', $id); + $cache_id = 'navigations/' . $cache_id[1]; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : ''); + + rrmdir($cache_dir); + + $cache_id = explode('_', $alias); + $cache_id = 'navigations/' . $cache_id[1]; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : ''); + + rrmdir($cache_dir); + } + } +?> diff --git a/class/class.paginations.php b/class/class.paginations.php new file mode 100644 index 0000000..5957cd5 --- /dev/null +++ b/class/class.paginations.php @@ -0,0 +1,256 @@ + 5 && $curent_page > 3) + { + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, 1, $pagination_start_label); + + $first = str_replace($search, $replace, $pagination_link_template); + + $pagination .= sprintf($pagination_link_box, str_replace(array('{s}', '{t}'), $pagination_start_label, str_replace(array('&'. $type .'={s}', '&' . $type .'={s}', '/' . $type . '-{s}'), '', $first))); + + // Если есть шаблон метки о наличии страниц, добавляем + if ($pagination_separator_label != '') + $pagination .= sprintf($pagination_separator_box, $pagination_separator_label); + } + + // Предыдущая + if ($curent_page > 1) + { + // Если равна 2 + if ($curent_page - 1 == 1) + { + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $curent_page-1, $pagination_prev_label); + + $link = str_replace($search, $replace, $pagination_link_template); + + $pagination .= sprintf($pagination_link_box, str_replace('{t}', $pagination_prev_label, str_replace(array('&' . $type . '={s}', '&' . $type . '={s}', '/' . $type . '-{s}'), '', $link))); + } + // Если больше 2х + else + { + + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $curent_page - 1, $pagination_prev_label); + + $link = str_replace($search, $replace, $pagination_link_template); + + $pagination .= sprintf($pagination_link_box, str_replace('{t}', $pagination_prev_label, str_replace('{s}', ($curent_page - 1), $link))); + } + } + + foreach ($pages as $page) + { + if ($page >= 1 && $page <= $total_pages) + { + // Текущий номер страницы (активная страница) + if ($curent_page == $page && $curent_page != 1) + { + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $curent_page, $curent_page); + + $link = str_replace($search, $replace, $pagination_link_active_template); + + $pagination .= sprintf($pagination_active_link_box, str_replace('{s}', ($curent_page), $link)); + } + else + { + // Страница номер 1 + if ($page == 1) + { + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $page, $page); + + if ($curent_page != 1) { + $link = str_replace($search, $replace, $pagination_link_template); + $pagination .= sprintf($pagination_link_box, str_replace(array('{s}', '{t}'), $page, str_replace(array('&' . $type . '={s}', '&' . $type . '={s}', '/' . $type . '-{s}'), '', $link))); + } + else + { + $link = str_replace($search, $replace, $pagination_link_active_template); + $pagination .= sprintf($pagination_active_link_box, str_replace(array('{s}', '{t}'), $page, str_replace(array('&' . $type . '={s}', '&' . $type . '={s}', '/' . $type . '-{s}'), '', $link))); + } + } + // Остальные неактивные номера страниц + else + { + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $page, $page); + + $link = str_replace($search, $replace, $pagination_link_template); + + $pagination .= sprintf($pagination_link_box, str_replace(array('{s}', '{t}'), $page, $link)); + } + } + } + } + + + // Следующая + if ($curent_page < $total_pages) + { + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $curent_page + 1, $pagination_next_label); + + $link = str_replace($search, $replace, $pagination_link_template); + + $pagination .= sprintf($pagination_link_box, str_replace('{t}', $pagination_next_label, str_replace('{s}', ($curent_page + 1), $link))); + } + + // Последняя + if ($total_pages > 5 && ($curent_page < $total_pages - 2)) + { + // Если есть шаблон метки о наличии страниц, добавляем + if ($pagination_separator_label != '') + $pagination .= sprintf($pagination_separator_box, $pagination_separator_label); + + $search = array('[link]', '[page]', '[name]'); + $replace = array($template_label, $total_pages, $pagination_end_label); + + $last = str_replace($search, $replace, $pagination_link_template); + + $pagination .= sprintf($pagination_link_box, str_replace('{t}', $pagination_end_label, str_replace('{s}', $total_pages, $last))); + } + + // Общий контейнер + if ($pagination != '') + { + // Если пришел внешний контейнер для + if ($pagination_box_ext != '') + $pagination = sprintf($pagination_box_ext, $pagination); + else if ($pagination_box != '') + $pagination = sprintf($pagination_box, $pagination); + } + + return $pagination; + } + + + /** + * Текущая страница + * + * @param string $type тип постраничной навигации, + * допустимые значения: page, apage, artpage + * @return int номер текущей страницы + */ + public static function getCurrentPage($type = 'page') + { + if (! in_array($type, array('page', 'apage', 'artpage'))) + return 1; + + $page = (isset($_REQUEST[$type]) && is_numeric($_REQUEST[$type])) + ? $_REQUEST[$type] + : 1; + + return (int)$page; + } + + + /** + * Достаем всю информацию о данной пагинации + * + * @param int $id id постраничной навигации + * @return array информация + */ + public static function getContainers($id) + { + global $AVE_DB; + + $containers = $AVE_DB->Query(" + SELECT + # PAGINATION = $id + * + FROM + " . PREFIX . "_paginations + WHERE + id = '" . $id . "' + ", -1, 'paginations', true, '.paginations')->FetchAssocArray(); + + return $containers; + } + + + /** + * Очистка кеша постраничной навигации + * + * @param void + * @return + */ + public static function clearCache() + { + global $AVE_DB; + + $AVE_DB->clearCache('paginations'); + } + } \ No newline at end of file diff --git a/class/class.porter.php b/class/class.porter.php new file mode 100644 index 0000000..76e88b1 --- /dev/null +++ b/class/class.porter.php @@ -0,0 +1,109 @@ +Stem_Caching && isset($this->Stem_Cache[$word])) + { + return $this->Stem_Cache[$word]; + } + + $stem = $word; + + do + { + if (! preg_match($this->RVRE, $word, $p)) + break; + + $start = $p[1]; + $RV = $p[2]; + + if (!$RV) + break; + + # Step 1 + if (! $this->s($RV, $this->PERFECTIVEGROUND, '')) + { + $this->s($RV, $this->REFLEXIVE, ''); + + if ($this->s($RV, $this->ADJECTIVE, '')) + { + $this->s($RV, $this->PARTICIPLE, ''); + } + else + { + if (! $this->s($RV, $this->VERB, '')) + $this->s($RV, $this->NOUN, ''); + } + } + + # Step 2 + $this->s($RV, '/и$/', ''); + + # Step 3 + if ($this->m($RV, $this->DERIVATIONAL)) + $this->s($RV, '/ость?$/', ''); + + # Step 4 + if (!$this->s($RV, '/ь$/', '')) + { + $this->s($RV, '/ейше?/', ''); + $this->s($RV, '/нн$/', 'н'); + } + + $stem = $start.$RV; + } + while(false); + + if ($this->Stem_Caching) + $this->Stem_Cache[$word] = $stem; + + return $stem; + } + + function stem_caching($parm_ref) + { + $caching_level = @$parm_ref['-level']; + if ($caching_level) { + if (!$this->m($caching_level, '/^[012]$/')) { + die(__CLASS__ . "::stem_caching() - Legal values are '0','1' or '2'. '$caching_level' is not a legal value"); + } + $this->Stem_Caching = $caching_level; + } + return $this->Stem_Caching; + } + + function clear_stem_cache() + { + $this->Stem_Cache = array(); + } + } +?> \ No newline at end of file diff --git a/class/class.registry.php b/class/class.registry.php new file mode 100644 index 0000000..cd50893 --- /dev/null +++ b/class/class.registry.php @@ -0,0 +1,147 @@ + \ No newline at end of file diff --git a/class/class.request.php b/class/class.request.php new file mode 100644 index 0000000..77f49af --- /dev/null +++ b/class/class.request.php @@ -0,0 +1,962 @@ +_limit; + $start = get_current_page() * $limit - $limit; + + // Получаем общее количество запросов + $num = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_request")->GetCell(); + + // Если количество больше, чем установленный лимит, тогда формируем постраничную навигацию + if ($num > $limit) + { + $page_nav = " {t} "; + $page_nav = get_pagination(ceil($num / $limit), 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + $limit = $pagination ? "LIMIT " . $start . "," . $limit : ''; + } + + // Выполняем запрос к БД на получение списка запросов с учетом лимита вывода на страницу (если необходимо) + $items = array(); + $sql = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_request + ORDER BY request_title ASC + " . $limit . " + "); + + // Формируем массив из полученных данных + while ($row = $sql->FetchRow()) + { + $row->request_author = get_username_by_id($row->request_author_id); + array_push($items, $row); + } + + // Возвращаем массив + return $items; + } + + /** + * Получить наименование и описание Запроса по идентификатору + * + * @param int $request_id идентификатор Запроса + * @return object наименование Запроса + */ + function get_request_by_id($request_id = 0) + { + global $AVE_DB; + + static $requests = array(); + + if (! isset($requests[$request_id])) + { + $requests[$request_id] = $AVE_DB->Query(" + SELECT + rubric_id, + request_title, + request_description + FROM + " . PREFIX . "_request + WHERE + Id = '" . $request_id . "' + LIMIT 1 + ")->FetchRow(); + } + + return $requests[$request_id]; + } + + /** + * Проверка алиаса тега на валидность и уникальность + * + * @param string $alias + * @param int $id + * + * @return bool|string + */ + function requestValidate ($alias = '', $id = 0) + { + global $AVE_DB; + + //-- Соответствие требованиям + if (empty ($alias) || preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $alias) !== 1 || is_numeric($alias)) + return 'syn'; + + //-- Уникальность + return !(bool)$AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_request + WHERE + request_alias = '" . $alias . "' + AND + Id != '" . $id . "' + ")->GetCell(); + } + + +/** + * Внешние методы класса + */ + + /** + * Метод, предназначенный для формирования списка Запросов + * + */ + function requestListFetch() + { + global $AVE_Template; + + $AVE_Template->assign('conditions', $this->_requestListGet(false)); + } + + /** + * Метод, предназначенный для отображения списка Запросов + * + */ + function requestListShow() + { + global $AVE_Template; + + // Получаем список запросов + $AVE_Template->assign('items', $this->_requestListGet()); + + // Передаем в шаблон и отображаем страницу со списком + $AVE_Template->assign('content', $AVE_Template->fetch('request/request.tpl')); + } + + /** + * Метод, предназначенный для создания нового Запроса + * + */ + function requestNew() + { + global $AVE_DB, $AVE_Template; + + // Определяем действие пользователя + switch ($_REQUEST['sub']) + { + // Действие не определено + case '': + $AVE_Template->assign('rid', 0); + // Отображаем пустую форму для создания нового запроса + $AVE_Template->assign('formaction', 'index.php?do=request&action=new&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('request/form.tpl')); + break; + + // Нажата кнопка Сохранить запрос + case 'save': + $save = true; + $errors = array(); + + $row = new stdClass(); + + $row->request_template_item = stripslashes(pretty_chars($_REQUEST['request_template_item'])); + $row->request_template_main = stripslashes(pretty_chars($_REQUEST['request_template_main'])); + $row->request_title = stripslashes($_REQUEST['request_title']); + $row->rubric_id = stripslashes($_REQUEST['rubric_id']); + $row->request_items_per_page = stripslashes($_REQUEST['request_items_per_page']); + $row->request_order_by = stripslashes($_REQUEST['request_order_by']); + $row->request_order_by_nat = stripslashes($_REQUEST['request_order_by_nat']); + $row->request_asc_desc = stripslashes($_REQUEST['request_asc_desc']); + $row->request_description = stripslashes($_REQUEST['request_description']); + $row->request_show_pagination = (isset($_REQUEST['request_show_pagination']) ? (int)($_REQUEST['request_show_pagination']) : 0); + $row->request_pagination = (isset($_REQUEST['request_pagination']) ? (int)($_REQUEST['request_pagination']) : 1); + $row->request_external = (isset($_REQUEST['request_external']) ? (int)$_REQUEST['request_external'] : 0); + $row->request_ajax = (isset($_REQUEST['request_ajax']) ? (int)$_REQUEST['request_ajax'] : 0); + $row->request_only_owner = (isset($_REQUEST['request_only_owner']) ? (int)($_REQUEST['request_only_owner']) : 0); + $row->request_hide_current = (isset($_REQUEST['request_hide_current']) ? (int)($_REQUEST['request_hide_current']) : 0); + $row->request_use_query = (isset($_REQUEST['request_use_query']) ? $_REQUEST['request_use_query'] : 0); + $row->request_count_items = (isset($_REQUEST['request_count_items']) ? $_REQUEST['request_count_items'] : 0); + $row->request_lang = (isset($_REQUEST['request_lang']) ? (int)$_REQUEST['request_lang'] : 0); + $row->request_show_statistic = (isset($_REQUEST['request_show_statistic']) ? (int)$_REQUEST['request_show_statistic'] : 0); + $row->request_show_sql = (isset($_REQUEST['request_show_sql']) ? (int)$_REQUEST['request_show_sql'] : 0); + $row->request_cache_elements = (isset($_REQUEST['request_cache_elements']) ? (int)$_REQUEST['request_cache_elements'] : 0); + $row->request_cache_lifetime = (int)($_REQUEST['request_cache_lifetime']); + + + + if (empty($_REQUEST['rubric_id'])) + { + $save = false; + $message = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_RUBRIC'); + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_RUBRIC'); + } + + if (empty($_REQUEST['request_title'])) + { + $save = false; + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_TITLE'); + } + + if (empty($_REQUEST['request_template_main'])) + { + $save = false; + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_TEXT'); + } + + $check_code_template_item = strtolower($_REQUEST['request_template_item']); + $check_code_template_main = strtolower($_REQUEST['request_template_main']); + + if ((is_php_code($check_code_template_item) || is_php_code($check_code_template_main)) && !check_permission('request_php')) + { + $save = false; + $message = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_PHP'); + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_PHP'); + reportLog($AVE_Template->get_config_vars('REQUEST_REPORT_ERR_PHP_N') . ' (' . stripslashes(htmlspecialchars($_REQUEST['request_title'], ENT_QUOTES)) . ')'); + } + + if ($save === false) + { + $AVE_Template->assign('row', $row); + $AVE_Template->assign('errors', $errors); + $AVE_Template->assign('formaction', 'index.php?do=request&action=new&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('request/form.tpl')); + } + else + { + $sql = " + INSERT " . PREFIX . "_request + SET + rubric_id = '" . (int)$_REQUEST['rubric_id'] . "', + request_alias = '" . (isset($_REQUEST['request_alias']) ? stripslashes($_REQUEST['request_alias']) : '') . "', + request_title = '" . (isset($_REQUEST['request_title']) ? stripslashes($_REQUEST['request_title']) : '') . "', + request_items_per_page = '" . (isset($_REQUEST['request_items_per_page']) ? stripslashes($_REQUEST['request_items_per_page']) : 0) . "', + request_template_item = '" . (isset($_REQUEST['request_template_item']) ? stripslashes(pretty_chars($_REQUEST['request_template_item'])) : '') . "', + request_template_main = '" . (isset($_REQUEST['request_template_main']) ? stripslashes(pretty_chars($_REQUEST['request_template_main'])) : '') . "', + request_order_by = '" . (isset($_REQUEST['request_order_by']) ? stripslashes($_REQUEST['request_order_by']) : '') . "', + request_order_by_nat = '" . (isset($_REQUEST['request_order_by_nat']) ? (int)trim($_REQUEST['request_order_by_nat']) : 0) . "', + request_description = '" . (isset($_REQUEST['request_description']) ? stripslashes($_REQUEST['request_description']) : '') . "', + request_author_id = '" . (int)$_SESSION['user_id'] . "', + request_created = '" . time() . "', + request_asc_desc = '" . (isset($_REQUEST['request_asc_desc']) ? stripslashes($_REQUEST['request_asc_desc']) : 'DESC') . "', + request_show_pagination = '" . (isset($_REQUEST['request_show_pagination']) ? (int)$_REQUEST['request_show_pagination'] : 0) . "', + request_pagination = '" . (isset($_REQUEST['request_pagination']) ? (int)$_REQUEST['request_pagination'] : 1) . "', + request_external = '" . (isset($_REQUEST['request_external']) ? (int)$_REQUEST['request_external'] : 0). "', + request_ajax = '" . (isset($_REQUEST['request_ajax']) ? (int)$_REQUEST['request_ajax'] : 0). "', + request_hide_current = '" . (isset($_REQUEST['request_hide_current']) ? (int)($_REQUEST['request_hide_current']) : 0) . "', + request_only_owner = '" . (isset($_REQUEST['request_only_owner']) ? (int)($_REQUEST['request_only_owner']) : 0) . "', + request_use_query = '" . (isset($_REQUEST['request_use_query']) ? (int)$_REQUEST['request_use_query'] : 0) . "', + request_count_items = '" . (isset($_REQUEST['request_count_items']) ? (int)$_REQUEST['request_count_items'] : 0) . "', + request_lang = '" . (isset($_REQUEST['request_lang']) ? (int)$_REQUEST['request_lang'] : 0). "', + request_show_statistic = '" . (isset($_REQUEST['request_show_statistic']) ? (int)$_REQUEST['request_show_statistic'] : 0). "', + request_show_sql = '" . (isset($_REQUEST['request_show_sql']) ? (int)$_REQUEST['request_show_sql'] : 0). "', + request_cache_elements = '" . (isset($_REQUEST['request_cache_elements']) ? (int)$_REQUEST['request_cache_elements'] : 0). "', + request_cache_lifetime = '" . (isset($_REQUEST['request_cache_lifetime']) ? (int)($_REQUEST['request_cache_lifetime']) : 0) . "', + request_changed = '" . time() . "', + request_changed_elements = '" . time() . "' + "; + + // Выполняем запрос к БД и сохраняем введенную пользователем информацию + $AVE_DB->Query($sql); + + // Получаем id последней записи + $iid = $AVE_DB->InsertId(); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('REQUEST_ADD_NEW_SUC') . ' (' . stripslashes(htmlspecialchars($_REQUEST['request_title'], ENT_QUOTES)) . ') (' . $iid . ')'); + + // Если в запросе пришел параметр на продолжение редактирования запроса + if ($_REQUEST['reedit'] == 1) + { + // Выполняем переход на страницу с редактированием запроса + header('Location:index.php?do=request&action=edit&Id=' . $iid . '&rubric_id=' . $_REQUEST['rubric_id'] . '&cp=' . SESSION); + } + else + { + // В противном случае выполняем переход к списку запросов + if (!$_REQUEST['next_edit']) + header('Location:index.php?do=request&cp=' . SESSION); + else + header('Location:index.php?do=request&action=edit&Id=' . $iid . '&rubric_id='.$_REQUEST['rubric_id'].'&cp=' . SESSION); + } + + exit; + } + } + } + + /** + * Метод, предназначенный для редактирования Запроса + * + * @param int $request_id идентификатор запроса + */ + function requestEdit($request_id) + { + global $AVE_DB, $AVE_Template; + + // Определяем действие пользователя + switch ($_REQUEST['sub']) + { + // Если действие не определено + case '': + // Выполняем запрос к БД и получаем всю информацию о запросе + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_request + WHERE + Id = '" . $request_id . "' + OR + request_alias = '" . $request_id . "' + "); + + if ($sql->_result->num_rows == 0) + { + header('Location:index.php?do=request&cp=' . SESSION); + exit; + } + + $row = $sql->FetchRow(); + + // Получаем постраничную навигацию + $sql = $AVE_DB->Query(" + SELECT + id, + pagination_name + FROM + " . PREFIX . "_paginations + "); + + $paginations = array(); + + while ($pages = $sql->FetchRow()) + array_push($paginations, $pages); + + // Передаем данные в шаблон и отображаем страницу с редактированием запроса + if (! isset($_REQUEST['rubric_id'])) + $_REQUEST['rubric_id'] = $row->rubric_id; + + $AVE_Template->assign('row', $row); + $AVE_Template->assign('rid', $row->Id); + $AVE_Template->assign('paginations', $paginations); + $AVE_Template->assign('formaction', 'index.php?do=request&action=edit&sub=save&Id=' . $row->Id . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('request/form.tpl')); + + break; + + // Пользователь нажал кнопку Сохранить изменения + case 'save': + + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_request + WHERE + Id = '" . $request_id . "' + "); + + if ($sql->_result->num_rows == 0) + { + header('Location:index.php?do=request&cp=' . SESSION); + exit; + } + + $save = true; + $errors = array(); + $row = new stdClass(); + $row->request_template_item = (isset($_REQUEST['request_template_item']) ? stripslashes(pretty_chars($_REQUEST['request_template_item'])) : ''); + $row->request_template_main = (isset($_REQUEST['request_template_main']) ? stripslashes(pretty_chars($_REQUEST['request_template_main'])) : ''); + $row->request_title = (isset($_REQUEST['request_title']) ? stripslashes($_REQUEST['request_title']) : ''); + $row->rubric_id = (isset($_REQUEST['rubric_id']) ? stripslashes($_REQUEST['rubric_id']) : 0); + $row->request_items_per_page = (isset($_REQUEST['request_items_per_page']) ? stripslashes($_REQUEST['request_items_per_page']) : 0); + $row->request_order_by = (isset($_REQUEST['request_order_by']) ? stripslashes($_REQUEST['request_order_by']) : ''); + $row->request_order_by_nat = (isset($_REQUEST['request_order_by_nat']) ? (int)trim($_REQUEST['request_order_by_nat']) : 0); + $row->request_asc_desc = (isset($_REQUEST['request_asc_desc']) ? stripslashes($_REQUEST['request_asc_desc']) : 'DESC'); + $row->request_description = (isset($_REQUEST['request_description']) ? stripslashes($_REQUEST['request_description']) : ''); + $row->request_show_pagination = (isset($_REQUEST['request_show_pagination']) ? $_REQUEST['request_show_pagination'] : 0); + $row->request_pagination = (isset($_REQUEST['request_pagination']) ? (int)($_REQUEST['request_pagination']) : 1); + $row->request_external = (isset($_REQUEST['request_external']) ? (int)$_REQUEST['request_external'] : 0); + $row->request_ajax = (isset($_REQUEST['request_ajax']) ? (int)$_REQUEST['request_ajax'] : 0); + $row->request_only_owner = (isset($_REQUEST['request_only_owner']) ? (int)($_REQUEST['request_only_owner']) : 0); + $row->request_hide_current = (isset($_REQUEST['request_hide_current']) ? (int)($_REQUEST['request_hide_current']) : 0); + $row->request_use_query = (isset($_REQUEST['request_use_query']) ? $_REQUEST['request_use_query'] : 0); + $row->request_count_items = (isset($_REQUEST['request_count_items']) ? $_REQUEST['request_count_items'] : 0); + $row->request_lang = (isset($_REQUEST['request_lang']) ? (int)$_REQUEST['request_lang'] : 0); + $row->request_show_statistic = (isset($_REQUEST['request_show_statistic']) ? (int)$_REQUEST['request_show_statistic'] : 0); + $row->request_show_sql = (isset($_REQUEST['request_show_sql']) ? (int)$_REQUEST['request_show_sql'] : 0); + $row->request_cache_elements = (isset($_REQUEST['request_cache_elements']) ? (int)$_REQUEST['request_cache_elements'] : 0); + $row->request_cache_lifetime = (int)($_REQUEST['request_cache_lifetime']); + + $message = ''; + + if (empty($_REQUEST['rubric_id'])) + { + $save = false; + $message = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_RUBRIC'); + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_RUBRIC'); + } + + if (empty($_REQUEST['request_title'])) + { + $save = false; + $message = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_TITLE'); + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_TITLE'); + } + + if (empty($_REQUEST['request_template_main'])) + { + $save = false; + $message = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_TEXT'); + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_TEXT'); + } + + $check_code_template_item = strtolower($_REQUEST['request_template_item']); + $check_code_template_main = strtolower($_REQUEST['request_template_main']); + + if ((is_php_code($check_code_template_item) || is_php_code($check_code_template_main)) && !check_permission('request_php')) + { + $save = false; + $message = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_PHP'); + $errors[] = $AVE_Template->get_config_vars('REQUEST_REPORT_ERR_PHP'); + reportLog($AVE_Template->get_config_vars('REQUEST_REPORT_ERR_PHP_E') . ' (' . stripslashes(htmlspecialchars($_REQUEST['request_title'], ENT_QUOTES)) . ') (Id:' . $request_id . ')'); + } + + if ($save === false) + { + if (isAjax()) + { + $header = $AVE_Template->get_config_vars('REQUEST_ERROR'); + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => 'error')); + exit; + } + + $AVE_Template->assign('row', $row); + $AVE_Template->assign('errors', $errors); + $AVE_Template->assign('formaction', 'index.php?do=request&action=edit&sub=save&Id=' . $request_id . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('request/form.tpl')); + } + else + { + // Выполняем запрос к БД и обновляем имеющиеся данные + $sql = " + UPDATE " . PREFIX . "_request + SET + rubric_id = '" . (int)$_REQUEST['rubric_id'] . "', + request_alias = '" . (isset($_REQUEST['request_alias']) ? $_REQUEST['request_alias'] : '') . "', + request_title = '" . (isset($_REQUEST['request_title']) ? $_REQUEST['request_title'] : '') . "', + request_items_per_page = '" . (isset($_REQUEST['request_items_per_page']) ? $_REQUEST['request_items_per_page'] : 0) . "', + request_template_item = '" . (isset($_REQUEST['request_template_item']) ? $_REQUEST['request_template_item'] : '') . "', + request_template_main = '" . (isset($_REQUEST['request_template_main']) ? $_REQUEST['request_template_main'] : '') . "', + request_order_by = '" . (isset($_REQUEST['request_order_by']) ? $_REQUEST['request_order_by'] : '') . "', + request_order_by_nat = '" . (isset($_REQUEST['request_order_by_nat']) ? (int)trim($_REQUEST['request_order_by_nat']) : 0) . "', + request_description = '" . (isset($_REQUEST['request_description']) ? $_REQUEST['request_description'] : '') . "', + request_asc_desc = '" . (isset($_REQUEST['request_asc_desc']) ? $_REQUEST['request_asc_desc'] : 'DESC') . "', + request_show_pagination = '" . (isset($_REQUEST['request_show_pagination']) ? (int)$_REQUEST['request_show_pagination'] : 0) . "', + request_pagination = '" . (isset($_REQUEST['request_pagination']) ? (int)$_REQUEST['request_pagination'] : 1) . "', + request_external = '" . (isset($_REQUEST['request_external']) ? (int)$_REQUEST['request_external'] : 0). "', + request_ajax = '" . (isset($_REQUEST['request_ajax']) ? (int)$_REQUEST['request_ajax'] : 0). "', + request_hide_current = '" . (isset($_REQUEST['request_hide_current']) ? (int)($_REQUEST['request_hide_current']) : 0) . "', + request_only_owner = '" . (isset($_REQUEST['request_only_owner']) ? (int)($_REQUEST['request_only_owner']) : 0) . "', + request_use_query = '" . (isset($_REQUEST['request_use_query']) ? (int)$_REQUEST['request_use_query'] : 0) . "', + request_count_items = '" . (isset($_REQUEST['request_count_items']) ? (int)$_REQUEST['request_count_items'] : 0) . "', + request_lang = '" . (isset($_REQUEST['request_lang']) ? (int)$_REQUEST['request_lang'] : 0). "', + request_show_statistic = '" . (isset($_REQUEST['request_show_statistic']) ? (int)$_REQUEST['request_show_statistic'] : 0). "', + request_show_sql = '" . (isset($_REQUEST['request_show_sql']) ? (int)$_REQUEST['request_show_sql'] : 0). "', + request_cache_elements = '" . (isset($_REQUEST['request_cache_elements']) ? (int)$_REQUEST['request_cache_elements'] : 0). "', + request_cache_lifetime = '" . (isset($_REQUEST['request_cache_lifetime']) ? (int)($_REQUEST['request_cache_lifetime']) : 0) . "', + request_changed = '" . time() . "', + request_changed_elements = '" . time() . "' + + WHERE + Id = '" . $request_id . "' + "; + + $AVE_DB->Query($sql); + + $AVE_DB->clearRequest($request_id); + + // ToDO Сделать проверку на сохранение + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('REQUEST_SAVE_CHA_SUC') . ' (' . stripslashes(htmlspecialchars($_REQUEST['request_title'], ENT_QUOTES)) . ') (Id:' . $request_id . ')'); + + // В противном случае выполняем переход к списку запросов + if (! isAjax()) + { + header('Location:index.php?do=request&cp=' . SESSION); + exit; + } + else + { + $message = $AVE_Template->get_config_vars('REQUEST_TEMPLATE_SAVED'); + $header = $AVE_Template->get_config_vars('REQUEST_SUCCESS'); + $theme = 'accept'; + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + } + break; + } + } + + /** + * Метод, предназначенный для создания копии Запроса + * + * @param int $request_id идентификатор запроса + */ + function requestCopy($request_id) + { + global $AVE_DB; + + // Выполняем запрос к БД на получение информации о копиреумом запросе + $row = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_request + WHERE Id = '" . $request_id . "' + ")->FetchRow(); + + // Выполняем запрос к БД на добавление нового запроса на основании полученных ранее данных + $AVE_DB->Query(" + INSERT " . PREFIX . "_request + SET + rubric_id = '" . $row->rubric_id . "', + request_items_per_page = '" . $row->request_items_per_page . "', + request_title = '" . substr($_REQUEST['cname'], 0, 25) . "', + request_template_item = '" . addslashes($row->request_template_item) . "', + request_template_main = '" . addslashes($row->request_template_main) . "', + request_order_by = '" . addslashes($row->request_order_by) . "', + request_order_by_nat = '" . addslashes($row->request_order_by_nat) . "', + request_author_id = '" . (int)$_SESSION['user_id'] . "', + request_created = '" . time() . "', + request_description = '" . addslashes($row->request_description) . "', + request_asc_desc = '" . $row->request_asc_desc . "', + request_show_pagination = '" . $row->request_show_pagination . "', + request_pagination = '" . $row->request_pagination . "', + request_hide_current = '" . $row->request_hide_current . "', + request_only_owner = '" . $row->request_only_owner . "', + request_use_query = '" . $row->request_use_query . "', + request_count_items = '" . $row->request_count_items . "', + request_lang = '" . $row->request_lang . "', + request_show_statistic = '" . $row->request_show_statistic . "', + request_show_sql = '" . $row->request_show_sql . "', + request_cache_elements = '" . (isset($row->request_cache_elements) ? $row->request_cache_elements : 0) . "' + "); + + // Получаем id добавленной записи + $iid = $AVE_DB->InsertId(); + + // Сохраняем системное сообщение в журнал + reportLog($_SESSION['user_name'] . ' - создал копию запроса (' . $request_id . ')', 2, 2); + + // Выполняем запрос к БД и получаем все условия запроса для копируемого запроса + $sql = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_request_conditions + WHERE request_id = '" . $request_id . "' + "); + + // Обрабатываем полученные данные и + while ($row_ak = $sql->FetchRow()) + { + // Выполняем запрос к БД на добавление условий для нового, скопированного запроса + $AVE_DB->Query(" + INSERT " . PREFIX . "_request_conditions + SET + request_id = '" . $iid . "', + condition_compare = '" . $row_ak->condition_compare . "', + condition_field_id = '" . $row_ak->condition_field_id . "', + condition_value = '" . $row_ak->condition_value . "', + condition_join = '" . $row_ak->condition_join . "' + "); + } + + // Выполянем переход к списку запросов + header('Location:index.php?do=request&cp=' . SESSION); + exit; + } + + /** + * Метод, предназначенный для удаления запроса + * + * @param int $request_id идентификатор запроса + */ + function requestDelete($request_id) + { + global $AVE_DB; + + // Выполняем запрос к БД на удаление общей информации о запросе + $AVE_DB->Query(" + DELETE + FROM " . PREFIX . "_request + WHERE Id = '" . $request_id . "' + "); + + // Выполняем запрос к БД на удаление условий запроса + $AVE_DB->Query(" + DELETE + FROM " . PREFIX . "_request_conditions + WHERE request_id = '" . $request_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($_SESSION['user_name'] . ' - удалил запрос (' . $request_id . ')', 2, 2); + + // Выполянем переход к списку запросов + header('Location:index.php?do=request&cp=' . SESSION); + exit; + } + + /** + * Метод, предназначенный для редактирования условий Запроса + * + * @param int $request_id идентификатор запроса + */ + function requestConditionEdit($request_id) + { + global $AVE_DB, $AVE_Template; + + // Определяем действие пользователя + switch ($_REQUEST['sub']) + { + // Если действие не определено + case '': + $fields = array(); + + // Выполняем запрос к БД и получаем список полей у той рубрики, к которой относится данный запрос + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $_REQUEST['rubric_id'] . "' + ORDER BY rubric_field_position ASC + "); + + // Обрабатываем полученные данные и формируем массив + while ($row = $sql->FetchRow()) + array_push($fields, $row); + + $conditions = array(); + + // Выполняем запрос к БД и получаем условия запроса + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_request_conditions + WHERE + request_id = '" . $request_id . "' + ORDER BY condition_position ASC + "); + + // Обрабатываем полученные данные и формируем массив + while ($row = $sql->FetchRow()) + array_push($conditions, $row); + + // Передаем данные в шаблон и отображаем страницу с редактированием условий + $AVE_Template->assign('request_title', $this->get_request_by_id($request_id)->request_title); + $AVE_Template->assign('fields', $fields); + $AVE_Template->assign('conditions', $conditions); + + if (isAjax() && (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] == 1)) + $AVE_Template->assign('content', $AVE_Template->fetch('request/cond_list.tpl')); + else + $AVE_Template->assign('content', $AVE_Template->fetch('request/conditions.tpl')); + + break; + + case 'sort': + + foreach ($_REQUEST['sort'] as $position => $cond_id) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_request_conditions + SET + condition_position = '" . (int)$position . "' + WHERE + Id = '" . (int)$cond_id . "' + "); + } + + if (isAjax()) + { + $message = $AVE_Template->get_config_vars('REQUEST_SORTED'); + $header = $AVE_Template->get_config_vars('REQUEST_SUCCESS'); + $theme = 'accept'; + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + + exit; + + // Если пользователь нажал кнопку Сохранить изменения + case 'save': + // Если существует хотя бы одно условие, тогда + + if (isset($_REQUEST['conditions']) && is_array($_POST['conditions'])) + { + $condition_edited = false; + + // Обрабатываем данные полей + foreach ($_REQUEST['conditions'] as $condition_id => $val) + { + // Выполняем запрос к БД на обновление информации об условиях + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_request_conditions + SET + request_id = '" . $request_id . "', + condition_compare = '" . $val['condition_compare'] . "', + condition_field_id = '" . $val['condition_field_id'] . "', + condition_value = '" . (! empty($val['condition_value']) ? $val['condition_value'] : '') . "', + condition_join = '" . $val['condition_join'] . "', + condition_status = '" . ((! empty($val['condition_value'])) ? (($val['condition_status'] == '1') ? '1' : '0') : ''). "' + WHERE + Id = '" . $condition_id . "' + "); + + $condition_edited = true; + } + + // Если изменения были, сохраняем системное сообщение в журнал + if ($condition_edited) + { + reportLog('' . $AVE_Template->get_config_vars('REQUEST_COND_CHA_SUC') . ' (' . stripslashes(htmlspecialchars($this->get_request_by_id($request_id)->request_title, ENT_QUOTES)) . ') - ( Id: '.$request_id.' )'); + + $message = $AVE_Template->get_config_vars('REQUEST_COND_POST_OK'); + $header = $AVE_Template->get_config_vars('REQUEST_SUCCESS'); + $theme = 'accept'; + } + else + { + + $message = $AVE_Template->get_config_vars('REQUEST_COND_POST_ERR'); + $header = $AVE_Template->get_config_vars('REQUEST_ERROR'); + $theme = 'error'; + } + } + else + { + $message = $AVE_Template->get_config_vars('REQUEST_COND_NO_POST'); + $header = $AVE_Template->get_config_vars('REQUEST_ERROR'); + $theme = 'error'; + } + + // Если некоторые из условий были помечены на удаление + if (isset($_POST['del']) && is_array($_POST['del'])) + { + // Обрабатываем все поля помеченные на удаление + foreach ($_POST['del'] as $condition_id => $val) + { + // Выполняем запрос к БД на удаление условий + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_request_conditions + WHERE + Id = '" . $condition_id . "' + "); + } + + // Сохраняем системное сообщение в журнал + reportLog('' . $AVE_Template->get_config_vars('REQUEST_COND_DEL_SUC') . ' (' . stripslashes(htmlspecialchars($this->get_request_by_id($request_id)->request_title, ENT_QUOTES)) . ') - ( Id: '.$request_id.' )'); + } + + // Нет смысла каждый раз формировать SQL-запрос с условиями Запроса + // поэтому формируем SQL-запрос только при изменении условий + // require(BASE_DIR . '/functions/func.parserequest.php'); + request_get_condition_sql_string($request_id, true); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_request + SET + request_changed = '" . time() . "' + WHERE + Id = '" . $request_id . "' + "); + + $AVE_DB->clearRequest($request_id); + + if (! isAjax()) + { + // Выполняем обновление страницы + header('Location:index.php?do=request&action=conditions&rubric_id=' . $_REQUEST['rubric_id'] . '&Id=' . $request_id . '&cp=' . SESSION . ($_REQUEST['pop'] ? '&pop=1' : '')); + exit; + } + else + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + + break; + + // Если пользователь добавил новое условие + case 'new': + if ($_POST['new_value'] !== '') + { + // Выполняем запрос к БД на добавление нового условия + $sql = $AVE_DB->Query(" + INSERT + " . PREFIX . "_request_conditions + SET + request_id = '" . $request_id . "', + condition_compare = '" . $_POST['new_operator'] . "', + condition_field_id = '" . $_POST['field_new'] . "', + condition_value = '" . $_POST['new_value'] . "', + condition_join = '" . $_POST['oper_new'] . "' + "); + + if ($sql->_result === false) + { + $message = $AVE_Template->get_config_vars('REQUEST_COND_NEW_ERR'); + $header = $AVE_Template->get_config_vars('REQUEST_ERROR'); + $theme = 'error'; + } + else + { + // Сохраняем системное сообщение в журнал + reportLog('' . $AVE_Template->get_config_vars('REQUEST_COND_ADD_SUC') . ' (' . stripslashes(htmlspecialchars($this->get_request_by_id($request_id)->request_title, ENT_QUOTES)) . ') - ( Id: '.$request_id.' )'); + } + + } + else + { + $message = $AVE_Template->get_config_vars('REQUEST_COND_VALUE_ERR'); + $header = $AVE_Template->get_config_vars('REQUEST_ERROR'); + $theme = 'error'; + } + + // Нет смысла каждый раз формировать SQL-запрос с условиями Запроса + // поэтому формируем SQL-запрос только при изменении условий + // require(BASE_DIR . '/functions/func.parserequest.php'); + request_get_condition_sql_string($request_id, true); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_request + SET + request_changed = '" . time() . "' + WHERE + Id = '" . $request_id . "' + "); + + $AVE_DB->clearRequest($request_id); + + if (! isAjax()) + { + header('Location:index.php?do=request&action=conditions&rubric_id=' . $_REQUEST['rubric_id'] . '&Id=' . $request_id . '&cp=' . SESSION); + exit; + } + else + { + if (! $message) + { + $message = $AVE_Template->get_config_vars('REQUEST_COND_NEW_SUC'); + $header = $AVE_Template->get_config_vars('REQUEST_SUCCESS'); + $theme = 'accept'; + } + + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + break; + } + } + + /** + * @param $field_id + * @param $cond_id + */ + function conditionFieldChange($field_id, $cond_id) + { + global $AVE_DB, $AVE_Template; + + // Передаем данные в шаблон и отображаем страницу с редактированием условий + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('cond_id', $cond_id); + $AVE_Template->assign('content', $AVE_Template->fetch('request/change.tpl')); + } + + + /** + * @param $field_id + * @param $cond_id + */ + function conditionFieldChangeSave($field_id, $cond_id) + { + global $AVE_DB, $AVE_Template; + + // ToDo + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_request_conditions + SET + condition_field_id = '" . $field_id . "' + WHERE + Id = '" . $cond_id . "' + "); + + request_get_condition_sql_string((int)$_REQUEST['req_id'], true); + + $request_id = $AVE_DB->Query(" + SELECT + request_id + FROM + " . PREFIX . "_request_conditions + WHERE + Id = '" . $cond_id . "' + ")->GetCell(); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_request + SET + request_changed = '" . time() . "' + WHERE + Id = '" . $request_id . "' + "); + + $AVE_DB->clearRequest($request_id); + + // Передаем данные в шаблон и отображаем страницу с редактированием условий + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('cond_id', $cond_id); + $AVE_Template->assign('content', $AVE_Template->fetch('request/change.tpl')); + } + +} + +?> \ No newline at end of file diff --git a/class/class.rubs.php b/class/class.rubs.php new file mode 100644 index 0000000..f9adb11 --- /dev/null +++ b/class/class.rubs.php @@ -0,0 +1,2582 @@ +Query(" + SELECT + * + FROM + " . PREFIX . "_rubric_fields_group + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY + group_position ASC + "); + + $groups = array(); + + while($row = $sql->FetchRow()) + { + array_push($groups, $row); + } + + return $groups; + } + + + /** + * Вывод списка рубрик + * + */ + function rubricList() + { + global $AVE_DB, $AVE_Template; + + $rubrics = array(); + $num = $AVE_DB->Query("SELECT COUNT(*) FROM " . PREFIX . "_rubrics")->GetCell(); + + $page_limit = $this->_limit; + $pages = ceil($num / $page_limit); + $set_start = get_current_page() * $page_limit - $page_limit; + + if ($num > $page_limit) + { + $page_nav = " {t} "; + $page_nav = get_pagination($pages, 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + $sql = $AVE_DB->Query(" + SELECT + rub.*, + (SELECT 1 FROM " . PREFIX . "_documents WHERE rubric_id = rub.Id LIMIT 1) AS doc_count, + (SELECT count(*) FROM " . PREFIX . "_rubric_fields AS fld WHERE fld.rubric_id = rub.Id) AS fld_count, + (SELECT count(*) FROM " . PREFIX . "_rubric_templates AS tmpls WHERE tmpls.rubric_id = rub.Id) AS tmpls_count + FROM + " . PREFIX . "_rubrics AS rub + GROUP BY rub.Id + ORDER BY rub.rubric_position + LIMIT " . $set_start . "," . $page_limit + ); + + while ($row = $sql->FetchRow()) + array_push($rubrics, $row); + + $AVE_Template->assign('rubrics', $rubrics); + } + + /** + * создание рубрики + * + */ + function rubricNew() + { + global $AVE_DB, $AVE_Template; + + switch ($_REQUEST['sub']) + { + case '': + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/rubnew.tpl')); + break; + + case 'save': + $errors = array(); + + if (empty($_POST['rubric_title'])) + { + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_NO_NAME')); + } + else + { + $name_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics + WHERE + rubric_title = '" . $_POST['rubric_title'] . "' + LIMIT 1 + ")->NumRows(); + + if ($name_exist) array_push($errors, $AVE_Template->get_config_vars('RUBRIK_NAME_EXIST')); + + if (! empty($_POST['rubric_alias'])) + { + if (preg_match(TRANSLIT_URL ? '/[^\%HYa-z0-9\/_-]+/' : '/[^\%HYa-zа-яА-Яёїєі0-9\/_-]+/u', $_POST['rubric_alias'])) + { + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_PREFIX_BAD_CHAR')); + } + else + { + $prefix_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics + WHERE + rubric_alias = '" . $_POST['rubric_alias'] . "' + LIMIT 1 + ")->NumRows(); + + if ($prefix_exist) array_push($errors, $AVE_Template->get_config_vars('RUBRIK_PREFIX_EXIST')); + } + } + + if (!empty($errors)) + { + $AVE_Template->assign('errors', $errors); + $AVE_Template->assign('templates', get_all_templates()); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/rubnew.tpl')); + } + else + { + $position = (int)$AVE_DB->Query(" + SELECT + MAX(rubric_position) + FROM + " . PREFIX . "_rubrics + ")->GetCell() + 1; + + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubrics + SET + rubric_title = '" . $_POST['rubric_title'] . "', + rubric_alias = '" . $_POST['rubric_alias'] . "', + rubric_template_id = '" . intval($_POST['rubric_template_id']) . "', + rubric_author_id = '" . $_SESSION['user_id'] . "', + rubric_created = '" . time() . "', + rubric_position = '" . $position . "', + rubric_changed = '" . time() . "', + rubric_changed_fields = '" . time() . "' + "); + + $iid = $AVE_DB->InsertId(); + + // Выставляем всем право на просмотр рубрики, админу - все права + $sql_user = $AVE_DB->Query(" + SELECT + grp.*, + COUNT(usr.Id) AS UserCount + FROM + " . PREFIX . "_user_groups AS grp + LEFT JOIN + " . PREFIX . "_users AS usr + ON usr.user_group = grp.user_group + GROUP BY grp.user_group + "); + while ($row = $sql_user->FetchRow()) + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubric_permissions + SET + rubric_id = '" . $iid . "', + user_group_id = '" . $row->user_group . "', + rubric_permission = '". (($row->user_group == 1) ? "alles|docread|new|newnow|editown|editall|delrev" : "docread")."' + "); + } + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('RUBRIK_LOG_NEW_RUBRIC') . ' - ' . stripslashes(htmlspecialchars($_POST['rubric_title'], ENT_QUOTES)) . ' (id: '.$iid.')'); + + header('Location:index.php?do=rubs&action=edit&Id=' . $iid . '&cp=' . SESSION); + exit; + } + } + break; + } + } + + + /** + * Запись настроек рубрики + * + */ + function quickSave() + { + global $AVE_DB, $AVE_Template; + + if (check_permission_acp('rubric_edit')) + { + foreach ($_POST['rubric_title'] as $rubric_id => $rubric_title) + { + if (! empty($rubric_title)) + { + $set_rubric_title = ''; + $set_rubric_alias = ''; + + $name_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics + WHERE + rubric_title = '" . $rubric_title . "' + AND + Id != '" . $rubric_id . "' + LIMIT 1 + ")->NumRows(); + + if (!$name_exist) + { + $set_rubric_title = "rubric_title = '" . $rubric_title . "',"; + } + + if (isset($_POST['rubric_alias'][$rubric_id]) && $_POST['rubric_alias'][$rubric_id] != '') + { + $pattern = TRANSLIT_URL ? '/[^\%HYa-z0-9\/_-]+/' : '/[^\%HYa-zа-яА-Яёїєі0-9\/_-]+/u'; + + if (! (preg_match($pattern, $_POST['rubric_alias'][$rubric_id]))) + { + $prefix_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics + WHERE + rubric_alias = '" . $_POST['rubric_alias'][$rubric_id] . "' + AND + Id != '" . $rubric_id . "' + LIMIT 1 + ")->NumRows(); + + if (! $prefix_exist) + { + $set_rubric_alias = "rubric_alias = '" . trim(preg_replace($pattern, '', $_POST['rubric_alias'][$rubric_id]), '/') . "',"; + } + } + } + else + { + $set_rubric_alias = "rubric_alias = '',"; + } + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + " . $set_rubric_title . " + " . $set_rubric_alias . " + rubric_meta_gen = '" . (isset($_POST['rubric_meta_gen'][$rubric_id]) ? $_POST['rubric_meta_gen'][$rubric_id] : '0') . "', + rubric_alias_history = '" . (isset($_POST['rubric_alias_history'][$rubric_id]) ? $_POST['rubric_alias_history'][$rubric_id] : '0') . "', + rubric_template_id = '" . (int)$_POST['rubric_template_id'][$rubric_id] . "', + rubric_docs_active = '" . (isset($_POST['rubric_docs_active'][$rubric_id]) ? $_POST['rubric_docs_active'][$rubric_id] : '0') . "', + rubric_changed = '".time()."', + rubric_changed_fields = '".time()."' + WHERE + Id = '" . $rubric_id . "' + "); + } + } + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + $message = $AVE_Template->get_config_vars('RUBRIK_REP_QUICKSAVE_T'); + $header = $AVE_Template->get_config_vars('RUBRIK_REP_QUICKSAVE_H'); + $theme = 'accept'; + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_QUICKSAVE')); + + if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] = 'run') + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $page = !empty($_REQUEST['page']) ? '&page=' . $_REQUEST['page'] : '' ; + header('Location:index.php?do=rubs' . $page . '&cp=' . SESSION); + } + + exit; + } + } + + + /** + * Копирование рубрики + * + */ + function rubricCopy() + { + global $AVE_DB, $AVE_Template; + + $rubric_id = (int)$_REQUEST['Id']; + + $errors = array(); + + if (empty($_REQUEST['rubric_title'])) + { + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_NO_NAME')); + } + else + { + $name_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics + WHERE + rubric_title = '" . $_POST['rubric_title'] . "' + LIMIT 1 + ")->NumRows(); + + if ($name_exist) + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_NAME_EXIST')); + } + + if (! empty($_POST['rubric_alias'])) + { + if (preg_match(TRANSLIT_URL ? '/[^\%HYa-z0-9\/-]+/' : '/[^\%HYa-zа-яёїєі0-9\/_-]+/', $_POST['rubric_alias'])) + { + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_PREFIX_BAD_CHAR')); + } + else + { + $prefix_exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics + WHERE + rubric_alias = '" . $_POST['rubric_alias'] . "' + LIMIT 1 + ")->NumRows(); + + if ($prefix_exist) + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_PREFIX_EXIST')); + } + } + + $row = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $rubric_id . "' + ")->FetchRow(); + + if (! $row) + array_push($errors, $AVE_Template->get_config_vars('RUBRIK_NO_RUBRIK')); + + if (! empty($errors)) + { + $AVE_Template->assign('errors', $errors); + } + else + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubrics + SET + rubric_title = '" . $_POST['rubric_title'] . "', + rubric_alias = '" . $_POST['rubric_alias'] . "', + rubric_template = '" . addslashes($row->rubric_template) . "', + rubric_template_id = '" . addslashes($row->rubric_template_id) . "', + rubric_author_id = '" . (int)$_SESSION['user_id'] . "', + rubric_created = '" . time() . "', + rubric_teaser_template = '" . addslashes($row->rubric_teaser_template) . "', + rubric_header_template = '" . addslashes($row->rubric_header_template) . "', + rubric_footer_template = '" . addslashes($row->rubric_footer_template) . "', + rubric_admin_teaser_template = '" . addslashes($row->rubric_admin_teaser_template) . "', + rubric_changed = '" . time() . "', + rubric_changed_fields = '" . time() . "' + "); + + $iid = $AVE_DB->InsertId(); + + $sql = $AVE_DB->Query(" + SELECT + user_group_id, + rubric_permission + FROM + " . PREFIX . "_rubric_permissions + WHERE + rubric_id = '" . $rubric_id . "' + "); + + while ($row = $sql->FetchRow()) + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubric_permissions + SET + rubric_id = '" . $iid . "', + user_group_id = '" . (int)$row->user_group_id . "', + rubric_permission = '" . addslashes($row->rubric_permission) . "' + "); + } + + $sql = $AVE_DB->Query(" + SELECT + rubric_field_title, + rubric_field_alias, + rubric_field_type, + rubric_field_position, + rubric_field_default, + rubric_field_template, + rubric_field_template_request, + rubric_field_description + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY rubric_field_position ASC + "); + + while ($row = $sql->FetchRow()) + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubric_fields + SET + rubric_id = '" . $iid . "', + rubric_field_title = '" . addslashes($row->rubric_field_title) . "', + rubric_field_alias = '" . addslashes($row->rubric_field_alias) . "', + rubric_field_type = '" . addslashes($row->rubric_field_type) . "', + rubric_field_position = '" . (int)$row->rubric_field_position . "', + rubric_field_default = '" . addslashes($row->rubric_field_default) . "', + rubric_field_template = '" . addslashes($row->rubric_field_template) . "', + rubric_field_template_request = '" . addslashes($row->rubric_field_template_request) . "', + rubric_field_description = '" . addslashes($row->rubric_field_description) . "' + "); + } + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_COPY') . ' - ' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title, ENT_QUOTES)) . ' (id: '.$rubric_id.')'); + + echo ''; + } + } + + + /** + * Удаление рубрики + * + */ + function rubricDelete() + { + global $AVE_DB, $AVE_Template; + + $rubric_id = (int)$_REQUEST['Id']; + + if ($rubric_id <= 1) + { + header('Location:index.php?do=rubs&cp=' . SESSION); + exit; + } + + $rubric_not_empty = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_documents + WHERE + rubric_id = '" . $rubric_id . "' + LIMIT 1 + ")->GetCell(); + + if (!$rubric_not_empty) + { + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $rubric_id . "' + "); + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + "); + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_rubric_permissions + WHERE + rubric_id = '" . $rubric_id . "' + "); + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_rubric_templates + WHERE + rubric_id = '" . $rubric_id . "' + "); + + // Удалить КЕШ + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + // Удалить файлы шаблонов + $this->clearTemplates($rubric_id); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('RUBRIK_LOG_DEL_RUBRIC') . ' - ' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title, ENT_QUOTES)) . ' (id: '.$rubric_id.')'); + } + + header('Location:index.php?do=rubs&cp=' . SESSION); + exit; + } + + + /** + * Вывод списка полей рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricFieldShow($rubric_id = 0, $ajax) + { + global $AVE_DB, $AVE_Template; + + if (check_permission_acp('rubric_edit')) + { + // Поля + $sql = $AVE_DB->Query(" + SELECT + a.*, + b.group_title, + b.group_description, + b.group_position + FROM + " . PREFIX . "_rubric_fields AS a + LEFT JOIN + " . PREFIX . "_rubric_fields_group AS b + ON a.rubric_field_group = b.Id + WHERE + a.rubric_id = '" . $rubric_id . "' + ORDER BY + b.group_position ASC, a.rubric_field_position ASC + "); + + $fields_list = array(); + + while ($row = $sql->FetchRow()) + { + $group_id = ($row->rubric_field_group) ? $row->rubric_field_group : 0; + + $fields_list[$group_id]['group_position'] = ($row->group_position) ? $row->group_position : 100; + $fields_list[$group_id]['group_title'] = $row->group_title; + $fields_list[$group_id]['group_description'] = $row->group_description; + $fields_list[$group_id]['fields'][$row->Id]['Id'] = $row->Id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_id'] = $row->rubric_id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_group'] = $row->rubric_field_group; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_alias'] = $row->rubric_field_alias; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_title'] = $row->rubric_field_title; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_type'] = $row->rubric_field_type; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_numeric'] = $row->rubric_field_numeric; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_default'] = $row->rubric_field_default; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_search'] = $row->rubric_field_search; + } + + $fields_list = msort($fields_list, 'group_position'); + + $AVE_Template->assign('groups_count', count($fields_list)); + $AVE_Template->assign('fields_list', $fields_list); + + // Группы полей + $fields_groups = array(); + + $sql = $AVE_DB->Query(" + SELECT * + FROM + " . PREFIX . "_rubric_fields_group + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY + group_position ASC + "); + + while ($row = $sql->FetchRow()) + array_push($fields_groups, $row); + + $AVE_Template->assign('fields_groups', $fields_groups); + + // Права + $groups = array(); + + $sql = $AVE_DB->Query("SELECT * FROM " . PREFIX . "_user_groups"); + + while ($row = $sql->FetchRow()) + { + $row->doall = ($row->user_group == 1) ? ' disabled="disabled" checked="checked"' : ''; + $row->doall_h = ($row->user_group == 1) ? 1 : ''; + + $rubric_permission = $AVE_DB->Query(" + SELECT + rubric_permission + FROM + " . PREFIX . "_rubric_permissions + WHERE + user_group_id = '" . $row->user_group . "' + AND + rubric_id = '" . $rubric_id . "' + ")->GetCell(); + + $row->permissions = @explode('|', $rubric_permission); + + array_push($groups,$row); + } + + $sql = $AVE_DB->Query(" + SELECT + rubric_title, + rubric_linked_rubric, + rubric_description + FROM + " . PREFIX . "_rubrics + WHERE + id = '" . $rubric_id . "' + LIMIT 1 + "); + + $rubrik = $sql->FetchRow(); + + $rubrik->rubric_linked_rubric = ($rubrik->rubric_linked_rubric != '0') + ? unserialize($rubrik->rubric_linked_rubric) + : array(); + + $AVE_Template->assign('rubric', $rubrik); + $AVE_Template->assign('groups', $groups); + $AVE_Template->assign('fields', get_field_type()); + $AVE_Template->assign('rubs', $this->rubricShow()); + + if (isAjax()) + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/fields.tpl')); + else + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/fields_list.tpl')); + } + else + { + header('Location:index.php?do=rubs&cp=' . SESSION); + exit; + } + } + + + /** + * Вывод списка полей рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricRulesShow($rubric_id = 0) + { + global $AVE_DB, $AVE_Template; + + if (check_permission_acp('rubric_edit')) + { + // Права + $groups = array(); + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_user_groups + "); + + while ($row = $sql->FetchRow()) + { + $row->doall = ($row->user_group == 1) ? ' disabled="disabled" checked="checked"' : ''; + $row->doall_h = ($row->user_group == 1) ? 1 : ''; + + $rubric_permission = $AVE_DB->Query(" + SELECT + rubric_permission + FROM + " . PREFIX . "_rubric_permissions + WHERE + user_group_id = '" . $row->user_group . "' + AND + rubric_id = '" . $rubric_id . "' + ")->GetCell(); + + $row->permissions = @explode('|', $rubric_permission); + + array_push($groups,$row); + } + + $sql = $AVE_DB->Query(" + SELECT + rubric_title, + rubric_linked_rubric, + rubric_description + FROM + " . PREFIX . "_rubrics + WHERE + id = '" . $rubric_id . "' + LIMIT 1 + "); + + $rubric = $sql->FetchRow(); + + $AVE_Template->assign('rubric', $rubric); + $AVE_Template->assign('groups', $groups); + + if (isAjax()) + { + + } + else + { + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/rules.tpl')); + } + } + else + { + header('Location:index.php?do=rubs&cp=' . SESSION); + exit; + } + } + + + + /** + * Вывод списка рубрик + * + * @param int $rubric_id идентификатор текущей рубрики + */ + function rubricShow($RubLink=null) + { + global $AVE_DB; + + if ($RubLink !== null) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_linked_rubric = '" . serialize($_REQUEST['rubric_linked']) . "' + WHERE + Id = '" . (int)$_REQUEST['Id'] . "' + "); + + header('Location:index.php?do=rubs&action=edit&Id=' . (int)$_REQUEST['Id'] . '&cp=' . SESSION); + exit; + } + else + { + $rubs = array(); + + $sql = $AVE_DB->Query(" + SELECT + rubric_title, + Id + FROM + " . PREFIX . "_rubrics + ORDER BY + rubric_position ASC + "); + + while ($row = $sql->FetchRow()) + array_push($rubs, $row); + + return $rubs; + } + } + + /** + * Создание нового поля рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricFieldNew($rubric_id = 0, $ajax) + { + global $AVE_DB, $AVE_Template; + + if (! empty($_POST['title_new'])) + { + $position = (int)$AVE_DB->Query(" + SELECT + MAX(rubric_field_position) + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + ")->GetCell() + 1; + + if ($_POST['rub_type_new'] == 'dropdown') + { + $rubric_field_default = trim($_POST['default_value']); + $rubric_field_default = preg_split('/\s*,\s*/', $rubric_field_default); + $rubric_field_default = implode(',', $rubric_field_default); + } + else + { + $rubric_field_default = $_POST['default_value']; + } + + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubric_fields + SET + rubric_id = '" . $rubric_id . "', + rubric_field_group = '" . (($_POST['group_new'] != '') ? (int)$_POST['group_new'] : '0') . "', + rubric_field_title = '" . $_POST['title_new'] . "', + rubric_field_type = '" . $_POST['rub_type_new'] . "', + rubric_field_position = '" . $position . "', + rubric_field_default = '" . $rubric_field_default . "', + rubric_field_numeric = '" . (($_POST['rubric_field_numeric'] == 1) ? $_POST['rubric_field_numeric'] : '0') . "', + rubric_field_search = '" . (($_POST['rubric_field_search'] == 1) ? $_POST['rubric_field_search'] : '0') . "' + "); + + $UpdateRubricField = $AVE_DB->InsertId(); + + $sql = $AVE_DB->Query(" + SELECT + Id + FROM + " . PREFIX . "_documents + WHERE + rubric_id = '" . $rubric_id . "' + "); + + while ($row = $sql->FetchRow()) + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_document_fields + SET + rubric_field_id = '" . $UpdateRubricField . "', + document_id = '" . $row->Id . "' + "); + } + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . $rubric_id . "' + "); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('RUBRIK_LOG_NEW_FIELD').' (' . stripslashes(htmlspecialchars($_POST['title_new'], ENT_QUOTES)) . ') '. stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title, ENT_QUOTES)). ' (id: '.$rubric_id.')'); + } + else + { + if (! isAjax()) + { + header('Location:index.php?do=rubs&action=edit&Id=' . $rubric_id . '&cp=' . SESSION); + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIK_EMPTY_MESSAGE'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'error'; + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + + exit; + } + + if (! isAjax()) + { + header('Location:index.php?do=rubs&action=edit&Id=' . $rubric_id . '&cp=' . SESSION); + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIK_FILD_SAVED'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'accept'; + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + + exit; + } + + + /** + * Редактирование кода для рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricCodeEdit($rubric_id = 0) + { + global $AVE_DB, $AVE_Template; + + switch ($_REQUEST['sub']) { + + case '': + $code = $AVE_DB->Query(" + SELECT + rubric_code_start, + rubric_code_end, + rubric_start_code + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $rubric_id . "' + ")->FetchRow(); + + $AVE_Template->assign('code', $code); + $AVE_Template->assign('rubric_title', $this->rubricNameByIdGet($rubric_id)->rubric_title); + $AVE_Template->assign('formaction', 'index.php?do=rubs&action=code&sub=save&Id=' . $rubric_id . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/code.tpl')); + break; + + case 'save': + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_start_code = '" . $_POST['rubric_start_code'] . "', + rubric_code_start = '" . $_POST['rubric_code_start'] . "', + rubric_code_end = '" . $_POST['rubric_code_end'] . "', + rubric_changed = '" . time() . "' + WHERE + Id = '" . $rubric_id . "' + "); + + // Очищаем кэш рубрики + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + if ($sql !== true) + { + $message = $AVE_Template->get_config_vars('RUBRIK_CODE_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIK_CODE_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIK_CODE_SAVED'); + $header = $AVE_Template->get_config_vars('RUBRIK_CODE_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('RUBRIK_CODE_UPDATE') . " (" . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title, ENT_QUOTES)) . ") (id: $rubric_id)"); + } + + if (isAjax()) + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + else + header('Location:index.php?do=rubs&action=code&Id=' . $rubric_id . '&cp=' . SESSION); + + exit; + } + } + + /** + * Редактирование кода для рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricCode($rubric_id = 0) + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_start_code = '" . $_POST['rubric_start_code'] . "', + rubric_code_start = '" . $_POST['rubric_code_start'] . "', + rubric_code_end = '" . $_POST['rubric_code_end'] . "', + rubric_changed = '" . time() . "' + WHERE + Id = '" . $rubric_id . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + if ($sql->_result === false) + { + $message = $AVE_Template->get_config_vars('RUBRIK_CODE_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIK_CODE_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIK_CODE_SAVED'); + $header = $AVE_Template->get_config_vars('RUBRIK_CODE_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('RUBRIK_CODE_UPDATE') . " (" . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title, ENT_QUOTES)) . ") (id: $rubric_id)"); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + header('Location:index.php?do=rubs&action=edit&Id=' . $rubric_id . '&cp=' . SESSION); + } + exit; + } + + /** + * Редактирование описания рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricDesc($rubric_id = 0) + { + global $AVE_DB; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_description = '" . $_POST['rubric_description'] . "' + WHERE + Id = '" . $rubric_id . "' + "); + + header('Location:index.php?do=rubs&action=edit&Id=' . $rubric_id . '&cp=' . SESSION); + exit; + } + + /** + * Управление полями рубрики + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricFieldSave($rubric_id = 0) + { + global $AVE_DB, $AVE_Template; + + foreach ($_POST['title'] as $id => $title) + { + if (! empty($title)) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_title = '" . $title . "', + rubric_field_numeric = '" . $_POST['rubric_field_numeric'][$id] . "', + rubric_field_search = '" . $_POST['rubric_field_search'][$id] . "' + WHERE + Id = '" . $id . "' + "); + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_FIELD_EDIT') . ' (' . stripslashes($title) . ') '.$AVE_Template->get_config_vars('RUBRIK_REPORT_RUB').' (' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title)) . ') (Id:' . $rubric_id . ')'); + } + } + + foreach ($_POST['del'] as $id => $Del) + { + if (! empty($Del)) + { + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_rubric_fields + WHERE + Id = '" . $id . "' + AND + rubric_id = '" . $rubric_id . "' + "); + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_document_fields + WHERE + rubric_field_id = '" . $id . "' + "); + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_FIELD_DEL') . ' (' . stripslashes($_POST['title'][$id]) . ') '.$AVE_Template->get_config_vars('RUBRIK_REPORT_RUB').' (' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title)) . ') (Id:' . $rubric_id . ')'); + } + } + + // Очищаем кэш шаблона документов рубрики + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed = '" . time() . "', + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . $rubric_id . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + $message = $AVE_Template->get_config_vars('RUBRIK_FILDS_SAVED'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'accept'; + + reportLog($AVE_Template->get_config_vars('RUBRIK_FILDS_REPORT') . ' (' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title)) . ') (Id:' . $rubric_id . ')'); + + if (isAjax()) + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=rubs&action=edit&Id=' . $rubric_id . '&cp=' . SESSION); + } + + exit; + } + + /** + * Сортировка полей рубрики + * + * @param array $sorted последовательность id полей + */ + function rubricFieldsSort() + { + global $AVE_DB, $AVE_Template; + + foreach ($_REQUEST['sort'] as $position => $field_id) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_position = '" . (int)$position . "' + WHERE + Id = '" . (int)$field_id . "' + "); + } + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_SORTE_FIELDS')); + + if (isAjax()) + { + $message = $AVE_Template->get_config_vars('RUBRIK_SORTED'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'accept'; + + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + + } + + /** + * Сортировка рубрик + * + * @param array $sorted последовательность id полей + */ + function rubricsSort() + { + global $AVE_DB, $AVE_Template; + + foreach ($_REQUEST['sort'] as $position => $rub_id) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_position = '" . (int)$position . "' + WHERE + Id = '" . (int)$rub_id . "' + "); + } + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_SORTE')); + + if (isAjax()) + { + $message = $AVE_Template->get_config_vars('RUBRIK_SORTED'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'accept'; + + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + } + + /** + * Вывод шаблона рубрики + * + * @param int $show + * @param int $extern + */ + function rubricTemplateShow($show = '', $extern = '0') + { + global $AVE_DB, $AVE_Template; + + if ($extern == 1) + $fetchId = (isset($_REQUEST['rubric_id']) && is_numeric($_REQUEST['rubric_id'])) ? $_REQUEST['rubric_id'] : 0; + else + $fetchId = (isset($_REQUEST['Id']) && is_numeric($_REQUEST['Id'])) ? $_REQUEST['Id'] : 0; + + $rubric = $AVE_DB->Query(" + SELECT + rubric_title, + rubric_template, + rubric_header_template, + rubric_footer_template, + rubric_teaser_template, + rubric_admin_teaser_template, + rubric_description + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $fetchId . "' + ")->FetchRow(); + + // Поля + $sql = $AVE_DB->Query(" + SELECT + a.*, + b.group_title, + b.group_description, + b.group_position + FROM + " . PREFIX . "_rubric_fields AS a + LEFT JOIN + " . PREFIX . "_rubric_fields_group AS b + ON a.rubric_field_group = b.Id + WHERE + a.rubric_id = '" . $fetchId . "' + ORDER BY + b.group_position ASC, a.rubric_field_position ASC + "); + + $fields_list = array(); + $drop_down_fields = array(); + + while ($row = $sql->FetchRow()) + { + $group_id = ($row->rubric_field_group) ? $row->rubric_field_group : 0; + + if ($row->rubric_field_type == 'drop_down' || $row->rubric_field_type == 'drop_down_key') + array_push($drop_down_fields, $row->Id); + + $fields_list[$group_id]['group_position'] = ($row->group_position) ? $row->group_position : 100; + $fields_list[$group_id]['group_title'] = $row->group_title; + $fields_list[$group_id]['group_description'] = $row->group_description; + $fields_list[$group_id]['fields'][$row->Id]['Id'] = $row->Id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_id'] = $row->rubric_id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_group'] = $row->rubric_field_group; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_alias'] = $row->rubric_field_alias; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_title'] = $row->rubric_field_title; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_type'] = $row->rubric_field_type; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_numeric'] = $row->rubric_field_numeric; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_default'] = $row->rubric_field_default; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_search'] = $row->rubric_field_search; + } + + $fields_list = msort($fields_list, 'group_position'); + + $AVE_Template->assign('groups_count', count($fields_list)); + $AVE_Template->assign('fields_list', $fields_list); + + $AVE_Template->assign('field_array', get_field_type()); + + if ($show == 1 ) + $rubric->rubric_template = stripslashes($_POST['rubric_template']); + + if ($extern == 1) + { + $AVE_Template->assign('ddid', implode(',', $drop_down_fields)); + } + else + { + $AVE_Template->assign('rubric', $rubric); + $AVE_Template->assign('formaction', 'index.php?do=rubs&action=template&sub=save&Id=' . $fetchId . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/form.tpl')); + } + } + + /** + * Редактирование шаблона рубрики + * + * @param string $data + */ + function rubricTemplateSave($Rtemplate, $Htemplate = '', $Ttemplate = '', $Atemplate = '', $Ftemplate = '') + { + global $AVE_DB, $AVE_Template; + + $rubric_id = (int)$_REQUEST['Id']; + + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_template = '" . ($Rtemplate) . "', + rubric_header_template = '" . $Htemplate . "', + rubric_footer_template = '" . $Ftemplate . "', + rubric_teaser_template = '" . $Ttemplate . "', + rubric_admin_teaser_template = '" . $Atemplate . "', + rubric_changed = '" . time() . "' + WHERE + Id = '" . $rubric_id . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_TPL_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIK_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_TPL'); + $header = $AVE_Template->get_config_vars('RUBRIC_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_TEMPL_RUB') . ' (' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title)) . ') (Id:' . $rubric_id . ')'); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=rubs&cp=' . SESSION); + } + + exit; + } + + /** + * Управление правами доступа к документам рубрик + * + * @param int $rubric_id идентификатор рубрики + */ + function rubricPermissionSave($rubric_id = 0) + { + global $AVE_DB, $AVE_Template; + + if (check_permission_acp('rubric_perms') && is_numeric($rubric_id) && $rubric_id > 0) + { + foreach ($_POST['user_group'] as $key => $user_group_id) + { + $exist = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubric_permissions + WHERE + user_group_id = '" . $user_group_id . "' + AND + rubric_id = '" . $rubric_id . "' + LIMIT 1 + ")->NumRows(); + + $rubric_permission = @implode('|', $_POST['perm'][$key]); + + if ($exist) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_permissions + SET + rubric_permission = '" . $rubric_permission . "' + WHERE + user_group_id = '" . $user_group_id . "' + AND + rubric_id = '" . $rubric_id . "' + "); + } + else + { + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubric_permissions + SET + rubric_id = '" . $rubric_id . "', + user_group_id = '" . $user_group_id . "', + rubric_permission = '" . $rubric_permission . "' + "); + } + } + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed = '" . time() . "' + WHERE + Id = '" . $rubric_id . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_PERMS'); + $header = $AVE_Template->get_config_vars('RUBRIC_SUCCESS'); + $theme = 'accept'; + + reportLog($AVE_Template->get_config_vars('RUBRIK_REPORT_PERMISION') . ' (' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title)) . ') (Id:' . $rubric_id . ')'); + + if (isAjax()) + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + else + header('Location:index.php?do=rubs&action=edit&Id=' . $rubric_id . '&cp=' . SESSION); + + exit; + } + } + + /** + * Получить наименование и URL-префикс Рубрики по идентификатору + * + * @param int $rubric_id идентификатор Рубрики + * @return object наименование Рубрики + */ + function rubricNameByIdGet($rubric_id = 0) + { + global $AVE_DB; + + static $rubrics = array(); + + if (! isset($rubrics[$rubric_id])) + { + $rubrics[$rubric_id] = $AVE_DB->Query(" + SELECT + rubric_title, + rubric_alias, + rubric_description + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $rubric_id . "' + LIMIT 1 + ")->FetchRow(); + } + + return $rubrics[$rubric_id]; + } + + /** + * Формирование прав доступа Групп пользователей на все Рубрики + * + */ + function rubricPermissionFetch() + { + global $AVE_DB, $AVE_Document, $AVE_Template; + + $items = array(); + + $sql = $AVE_DB->Query(" + SELECT + Id, + rubric_title, + rubric_docs_active + FROM + " . PREFIX . "_rubrics + ORDER + BY rubric_position + "); + + while ($row = $sql->FetchRow()) + { + $AVE_Document->documentPermissionFetch($row->Id); + + if (defined('UGROUP') && UGROUP == 1) $row->Show = 1; + elseif (isset($_SESSION[$row->Id . '_editown']) && $_SESSION[$row->Id . '_editown'] == 1) $row->Show = 1; + elseif (isset($_SESSION[$row->Id . '_editall']) && $_SESSION[$row->Id . '_editall'] == 1) $row->Show = 1; + elseif (isset($_SESSION[$row->Id . '_new']) && $_SESSION[$row->Id . '_new'] == 1) $row->Show = 1; + elseif (isset($_SESSION[$row->Id . '_newnow']) && $_SESSION[$row->Id . '_newnow'] == 1) $row->Show = 1; + elseif (isset($_SESSION[$row->Id . '_alles']) && $_SESSION[$row->Id . '_alles'] == 1) $row->Show = 1; + + array_push($items, $row); + } + + $AVE_Template->assign('rubrics', $items); + } + + /** + * Получить + */ + function rubricAliasAdd() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + a.rubric_title, + b.rubric_field_title, + b.rubric_field_alias + FROM + " . PREFIX . "_rubrics AS a + JOIN + " . PREFIX . "_rubric_fields AS b + WHERE + a.Id = '" . $_REQUEST['rubric_id'] . "' + AND + b.Id = '" . $_REQUEST['field_id'] . "' + ")->FetchAssocArray(); + + $AVE_Template->assign($sql); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/alias.tpl')); + } + + + function rubricAliasCheck($rubric_id, $field_id, $value) + { + global $AVE_DB, $AVE_Template; + + $errors = array(); + + if (! intval($rubric_id)>0) + $errors[] = $AVE_Template->get_config_vars('RUBRIK_ALIAS_RUBID'); + + if (! intval($field_id)>0) + $errors[] = $AVE_Template->get_config_vars('RUBRIK_ALIAS_FIELDID'); + + if (! preg_match('/^[A-Za-z][[:word:]]{0,19}$/', $value)) + $errors[] = $AVE_Template->get_config_vars('RUBRIK_ALIAS_MATCH'); + + //Проверяем есть такой алиас уже + $res = $AVE_DB->Query(" + SELECT + COUNT(*) + FROM + " . PREFIX . "_rubric_fields + WHERE + Id <> " . intval($field_id) . " + AND rubric_id = " . intval($rubric_id) . " + AND rubric_field_alias = '" . addslashes($value) . "' + ")->GetCell(); + + if ($res > 0) + $errors[] = $AVE_Template->get_config_vars('RUBRIK_ALIAS_MATCH'); + + if (empty($errors)) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_alias = '" . addslashes($value) . "' + WHERE + Id = '" . intval($field_id) . "' + AND + rubric_id = '" . intval($rubric_id) . "' + "); + + $AVE_Template->assign('success', true); + } + else + { + $AVE_Template->assign('errors', $errors); + } + + $sql = $AVE_DB->Query(" + SELECT + a.rubric_title, + b.rubric_field_title, + b.rubric_field_alias + FROM + " . PREFIX . "_rubrics AS a + JOIN + " . PREFIX . "_rubric_fields AS b + WHERE + a.Id = '" . $_REQUEST['rubric_id'] . "' + AND + b.Id = '" . $_REQUEST['field_id'] . "' + ")->FetchAssocArray(); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_Template->assign($sql); + + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/alias.tpl')); + } + + function rubricFieldTemplate() + { + global $AVE_DB, $AVE_Template; + + $field = $AVE_DB->Query(" + SELECT + a.rubric_title, + b.rubric_field_default, + b.rubric_field_title, + b.rubric_field_template, + b.rubric_field_template_request, + b.rubric_field_description + FROM + " . PREFIX . "_rubrics AS a + JOIN + " . PREFIX . "_rubric_fields AS b + WHERE + a.Id = '" . $_REQUEST['rubric_id'] . "' + AND + b.Id = '" . $_REQUEST['field_id'] . "' + ")->FetchAssocArray(); + + $AVE_Template->assign($field); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/field_template.tpl')); + } + + + function rubricFieldTemplateSave($id, $rubric_id) + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_default = '" . $_POST['rubric_field_default'] . "', + rubric_field_template = '" . $_POST['rubric_field_template'] . "', + rubric_field_template_request = '" . $_POST['rubric_field_template_request'] . "', + rubric_field_description = '" . $_POST['rubric_field_description'] . "' + WHERE + Id = '" . $id . "' + "); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_FLDTPL_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIK_ERROR'); + $theme = 'error'; + + if (isAjax() && ! $_REQUEST['save']) + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + else + $this->rubricFieldTemplate(); + + exit; + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_FLDTPL'); + $header = $AVE_Template->get_config_vars('RUBRIC_SUCCESS'); + $theme = 'accept'; + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + } + } + + + function rubricFieldChange($field_id, $rubric_id) + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + AND + Id = " . $field_id . " + ")->FetchAssocArray(); + + $AVE_Template->assign('rf', $sql); + $AVE_Template->assign('fields', get_field_type()); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/change.tpl')); + } + + + function rubricFieldChangeSave($field_id, $rubric_id) + { + global $AVE_DB, $AVE_Template; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_type = '" . trim($_POST['rubric_field_type']) . "' + WHERE + Id = '" . $field_id . "' + AND + rubric_id = '" . $rubric_id . "' + "); + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + AND + Id = " . $field_id . " + ")->FetchAssocArray(); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_Template->assign('rf', $sql); + $AVE_Template->assign('fields', get_field_type()); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/change.tpl')); + } + + + function rubricFieldsGroups($rubric_id) + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_rubric_fields_group + WHERE + rubric_id = '" . $rubric_id . "' + ORDER BY + group_position + "); + + $groups = array(); + + while ($row = $sql->FetchRow()) + array_push($groups, $row); + + $AVE_Template->assign('rubric', $this->rubricNameByIdGet($rubric_id)); + $AVE_Template->assign('groups', $groups); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/fields_groups.tpl')); + } + + /** + * Сортировка групп полей рубрики + * + * @param array $sorted последовательность id полей + */ + function rubricFieldsGroupsSort() + { + global $AVE_DB, $AVE_Template; + + foreach ($_REQUEST['sort'] as $position => $group_id) + { + $position++; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields_group + SET + group_position = '" . (int)$position . "' + WHERE + Id = '" . (int)$group_id . "' + "); + } + + if (isAjax()) + { + $message = $AVE_Template->get_config_vars('RUBRIK_SORTED'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'accept'; + + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + } + + + function rubricNewGroupFields($rubric_id) + { + global $AVE_DB; + + $position = $AVE_DB->Query(" + SELECT + MAX(group_position) + FROM + " . PREFIX . "_rubric_fields_group + WHERE + rubric_id = '" . $rubric_id . "' + ")->GetCell(); + + $position++; + + $AVE_DB->Query(" + INSERT + " . PREFIX . "_rubric_fields_group + SET + rubric_id = '" . $rubric_id . "', + group_position = '" . $position . "', + group_title= '" . $_REQUEST['group_title'] . "' + "); + + header('Location:index.php?do=rubs&action=fieldsgroups&Id=' . $rubric_id . '&cp=' . SESSION); + exit; + } + + + function rubricEditGroupFields($rubric_id) + { + global $AVE_DB; + + foreach($_REQUEST['group_title'] as $k => $v) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields_group + SET + group_title= '" . $v . "' + WHERE + Id = '" . $k . "' + "); + } + + header('Location:index.php?do=rubs&action=fieldsgroups&Id=' . $rubric_id . '&cp=' . SESSION); + exit; + } + + + function rubricDelGroupFields($Id, $rubric_id) + { + global $AVE_DB; + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_rubric_fields_group + WHERE + Id = '" . $Id . "' + "); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_group = '0' + WHERE + rubric_field_group = '" . $Id . "' + AND + rubric_id = '" . $rubric_id . "' + "); + + header('Location:index.php?do=rubs&action=fieldsgroups&Id=' . $rubric_id . '&cp=' . SESSION); + exit; + } + + + function rubricFieldGroupChange($field_id, $rubric_id) + { + + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + AND + Id = " . $field_id . " + ")->FetchAssocArray(); + + $AVE_Template->assign('rf', $sql); + $AVE_Template->assign('groups', $this->get_rubric_fields_group($rubric_id)); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/groups.tpl')); + } + + + function rubricFieldGroupChangeSave($field_id, $rubric_id) + { + global $AVE_DB, $AVE_Template; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_fields + SET + rubric_field_group = '" . trim($_POST['rubric_field_group']) . "' + WHERE + Id = '" . $field_id . "' + AND + rubric_id = '" . $rubric_id . "' + "); + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '" . $rubric_id . "' + AND + Id = " . $field_id . " + ")->FetchAssocArray(); + + $AVE_Template->assign('rf', $sql); + $AVE_Template->assign('groups', $this->get_rubric_fields_group($rubric_id)); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/groups.tpl')); + } + + + // Список дополнительных шаблон для данной рубрики + function tmplsList() + { + global $AVE_DB, $AVE_Template; + + $templates = array(); + + $num = $AVE_DB->Query(" + SELECT + COUNT(*) + FROM + " . PREFIX . "_rubric_templates + WHERE + rubric_id = '" . $_REQUEST['Id'] . "' + ")->GetCell(); + + $page_limit = $this->_limit; + + $pages = ceil($num / $page_limit); + + $set_start = get_current_page() * $page_limit - $page_limit; + + if ($num > $page_limit) + { + $page_nav = " {t} "; + $page_nav = get_pagination($pages, 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + $sql = $AVE_DB->Query(" + SELECT + rub.*, + rubrics.rubric_title, + (SELECT 1 FROM " . PREFIX . "_documents WHERE rubric_id = rub.rubric_id AND rubric_tmpl_id = rub.id LIMIT 1) AS doc_count + FROM + " . PREFIX . "_rubric_templates AS rub + LEFT JOIN + " . PREFIX . "_rubrics AS rubrics + ON rubrics.Id = rub.rubric_id + WHERE + rub.rubric_id = '" . (int)$_REQUEST['Id'] . "' + GROUP + BY rub.id + ORDER + BY rub.id + LIMIT + " . $set_start . "," . $page_limit + ); + + while ($row = $sql->FetchRow()) + { + $row->author_id = get_username_by_id($row->author_id); + array_push($templates, $row); + } + + $rubric = $this->rubricNameByIdGet((int)$_REQUEST['Id']); + + $AVE_Template->assign('rubric', $rubric); + $AVE_Template->assign('templates', $templates); + } + + /** + * Вывод шаблона рубрики + * + * @param int $show + * @param int $extern + */ + function tmplsEdit() + { + global $AVE_DB, $AVE_Template; + + $tmpls_id = (isset($_REQUEST['id']) && is_numeric($_REQUEST['id'])) ? $_REQUEST['id'] : 0; + $rubric_id = (int)$_REQUEST['rubric_id']; + + if ($tmpls_id) + { + $template = $AVE_DB->Query(" + SELECT + title, + template + FROM + " . PREFIX . "_rubric_templates + WHERE + id = '" . $tmpls_id . "' + ") + ->FetchRow(); + } + + if ($_REQUEST['action'] == 'tmpls_from') + { + $template = $AVE_DB->Query(" + SELECT + rubric_title as title, + rubric_template as template + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . $rubric_id . "' + ") + ->FetchRow(); + } + + if ($_REQUEST['action'] == 'tmpls_copy') + { + $template = $AVE_DB->Query(" + SELECT + title, + template + FROM + " . PREFIX . "_rubric_templates + WHERE + id = '" . $_REQUEST['tmpls_id'] . "' + ") + ->FetchRow(); + } + + // Поля + $sql = $AVE_DB->Query(" + SELECT + a.*, + b.group_title, + b.group_description, + b.group_position + FROM + " . PREFIX . "_rubric_fields AS a + LEFT JOIN + " . PREFIX . "_rubric_fields_group AS b + ON a.rubric_field_group = b.Id + WHERE + a.rubric_id = '" . $rubric_id . "' + ORDER BY + b.group_position ASC, a.rubric_field_position ASC + "); + + $fields_list = array(); + $drop_down_fields = array(); + + while ($row = $sql->FetchRow()) + { + $group_id = ($row->rubric_field_group) ? $row->rubric_field_group : 0; + + if ($row->rubric_field_type == 'drop_down' || $row->rubric_field_type == 'drop_down_key') + array_push($drop_down_fields, $row->Id); + + $fields_list[$group_id]['group_position'] = ($row->group_position) ? $row->group_position : 100; + $fields_list[$group_id]['group_title'] = $row->group_title; + $fields_list[$group_id]['group_description'] = $row->group_description; + $fields_list[$group_id]['fields'][$row->Id]['Id'] = $row->Id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_id'] = $row->rubric_id; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_group'] = $row->rubric_field_group; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_alias'] = $row->rubric_field_alias; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_title'] = $row->rubric_field_title; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_type'] = $row->rubric_field_type; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_numeric'] = $row->rubric_field_numeric; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_default'] = $row->rubric_field_default; + $fields_list[$group_id]['fields'][$row->Id]['rubric_field_search'] = $row->rubric_field_search; + } + + $fields_list = msort($fields_list, 'group_position'); + + $AVE_Template->assign('groups_count', count($fields_list)); + $AVE_Template->assign('fields_list', $fields_list); + + $AVE_Template->assign('field_array', get_field_type()); + + $rubric = $this->rubricNameByIdGet($rubric_id); + + $AVE_Template->assign('rubric', $rubric); + + $AVE_Template->assign('template', $template); + + $AVE_Template->assign('formaction', 'index.php?do=rubs&action=tmpls_edit&sub=save&id=' . $tmpls_id . '&rubric_id=' . $_REQUEST['rubric_id'] . '&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('rubs/tmpls_form.tpl')); + } + + + /** + * Редактирование шаблона рубрики + * + * @param string $data + */ + function tmplsSave($template = '', $title = '') + { + global $AVE_DB, $AVE_Template; + + $tmpls_id = (int)$_REQUEST['id']; + $rubric_id = (int)$_REQUEST['rubric_id']; + + if ($tmpls_id) + { + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubric_templates + SET + title = '" . $title . "', + template = '" . $template . "' + WHERE + id = '" . $tmpls_id . "' + "); + } + else + { + $sql = $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_rubric_templates + SET + title = '" . $title . "', + template = '" . $template . "', + rubric_id = '" . $rubric_id . "', + author_id = '" . UID . "', + created = '" . time() . "' + "); + + $tmpls_id = $AVE_DB->InsertId(); + } + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_TPL_ERR'); + $header = $AVE_Template->get_config_vars('RUBRIK_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('RUBRIC_SAVED_TPL'); + $header = $AVE_Template->get_config_vars('RUBRIC_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('RUBRIC_TEMPL_REPORT') . ' ' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title)) . ' (Id шаблона:' . $tmpls_id . ')'); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=rubs&action=tmpls&Id='.$rubric_id.'&cp=' . SESSION); + } + + exit; + } + + + function tmplsDelete() + { + global $AVE_DB, $AVE_Template; + + $rubric_id = (int)$_REQUEST['rubric_id']; + $tmpls_id = (int)$_REQUEST['tmpls_id']; + + $rubric_not_empty = $AVE_DB->Query(" + SELECT 1 + FROM " . PREFIX . "_documents + WHERE + rubric_id = '" . $rubric_id . "' + AND + rubric_tmpl_id = '" . $tmpls_id . "' + LIMIT 1 + ")->GetCell(); + + if (! $rubric_not_empty) + { + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_rubric_templates + WHERE + id = '" . $tmpls_id . "' + AND + rubric_id = '" . $rubric_id . "' + "); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + // Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('RUBRIC_TMPLS_LOG_DEL') . ' - ' . stripslashes(htmlspecialchars($this->rubricNameByIdGet($rubric_id)->rubric_title, ENT_QUOTES)) . ' (Id шаблона: '.$rubric_id.')'); + } + + header('Location:index.php?do=rubs&action=tmpls&Id='.$rubric_id.'&cp=' . SESSION); + exit; + } + + + + function _get_fields_type($type = null) + { + static $fields; + + if (is_array($fields)) + return $fields; + + $arr = get_defined_functions(); + + $fields = array(); + $field = array(); + + foreach ($arr['user'] as $v) + { + if (trim(substr($v, 0, strlen('get_field_'))) == 'get_field_') + { + $d = ''; + + $name = @$v('', 'name', '', '', 0, $d); + + $id = substr($v, strlen('get_field_')); + + if ($name != false && is_string($name)) + $fields[] = array('id' => $id,'name' => (isset($fields_vars[$name]) + ? $fields_vars[$name] + : $name)); + + if (! empty($type) && $id == $type) + $field = array('id' => $id,'name' => (isset($fields_vars[$name]) + ? $fields_vars[$name] + : $name)); + } + } + + $fields = msort($fields, array('name')); + + return (! empty($type)) ? $field : $fields; + } + + + function ShowFields() + { + global $AVE_DB, $AVE_Template; + + $rubric_id = (int)$_REQUEST['Id']; + + $sql = $AVE_DB->Query(" + SELECT + rubric_field_type + FROM + " . PREFIX . "_rubric_fields + WHERE + rubric_id = '".$rubric_id."' + GROUP BY + rubric_field_type + "); + + $enable = array(); + + while ($row = $sql->FetchArray()) + $enable[] = $row['rubric_field_type']; + + $fields = $this->_get_fields_type(); + + foreach ($fields as $field) + { + $exists[$field['id']]['adm'] = file_exists(BASE_DIR . '/fields/' . $field['id'] . '/tpl/field.tpl'); + $exists[$field['id']]['doc'] = file_exists(BASE_DIR . '/fields/' . $field['id'] . '/tpl/field-doc.tpl'); + $exists[$field['id']]['req'] = file_exists(BASE_DIR . '/fields/' . $field['id'] . '/tpl/field-req.tpl'); + } + + $sql = $AVE_DB->Query(" + SELECT + rubric_title, + rubric_linked_rubric, + rubric_description + FROM + " . PREFIX . "_rubrics + WHERE + id = '" . $rubric_id . "' + LIMIT 1 + "); + + $rubric = $sql->FetchRow(); + + $AVE_Template->assign('rubric', $rubric); + $AVE_Template->assign("enable", $enable); + $AVE_Template->assign("exists", $exists); + $AVE_Template->assign("fields", $fields); + $AVE_Template->assign("content", $AVE_Template->fetch('rubs/_fields_list.tpl')); + } + + + function ShowFieldsByType($fld) + { + global $AVE_DB, $AVE_Template; + + $rubric_id = (int)$_REQUEST['rubric_id']; + + $sql = $AVE_DB->Query(" + SELECT + a.Id, + a.rubric_id, + a.rubric_field_type, + a.rubric_field_title, + b.rubric_title + FROM + " . PREFIX . "_rubric_fields AS a + LEFT JOIN + " . PREFIX . "_rubrics AS b + ON a.rubric_id = b.Id + WHERE + a.rubric_field_type = '" . $fld ."' + AND + a.rubric_id = '".$rubric_id."' + ORDER BY + a.rubric_id + "); + + $rubrics = []; + + while ($row = $sql->FetchRow()) + { + $rubrics[$row->rubric_id]['rubric_id'] = $row->rubric_id; + $rubrics[$row->rubric_id]['rubric_title'] = $row->rubric_title; + $rubrics[$row->rubric_id]['rubric_field_type'] = $row->rubric_field_type; + $rubrics[$row->rubric_id]['fields'][$row->Id]['id'] = $row->Id; + $rubrics[$row->rubric_id]['fields'][$row->Id]['title'] = $row->rubric_field_title; + $rubrics[$row->rubric_id]['fields'][$row->Id]['adm_tpl'] = file_exists(BASE_DIR . '/fields/' . $fld . '/tpl/field-' . $row->Id . '.tpl'); + $rubrics[$row->rubric_id]['fields'][$row->Id]['doc_tpl'] = file_exists(BASE_DIR . '/fields/' . $fld . '/tpl/field-doc-' . $row->Id . '.tpl'); + $rubrics[$row->rubric_id]['fields'][$row->Id]['req_tpl'] = file_exists(BASE_DIR . '/fields/' . $fld . '/tpl/field-req-' . $row->Id . '.tpl'); + $rubrics[$row->rubric_id]['fields'][$row->Id]['adm_main'] = file_exists(BASE_DIR . '/fields/' . $fld . '/tpl/field.tpl'); + $rubrics[$row->rubric_id]['fields'][$row->Id]['doc_main'] = file_exists(BASE_DIR . '/fields/' . $fld . '/tpl/field-doc.tpl'); + $rubrics[$row->rubric_id]['fields'][$row->Id]['req_main'] = file_exists(BASE_DIR . '/fields/' . $fld . '/tpl/field-req.tpl'); + } + + $sql = $AVE_DB->Query(" + SELECT + rubric_title, + rubric_linked_rubric, + rubric_description + FROM + " . PREFIX . "_rubrics + WHERE + id = '" . $rubric_id . "' + LIMIT 1 + "); + + $rubric = $sql->FetchRow(); + + $AVE_Template->assign('rubric', $rubric); + $AVE_Template->assign('main', $this->_get_fields_type($fld)); + $AVE_Template->assign("rubrics", $rubrics); + $AVE_Template->assign("content", $AVE_Template->fetch('rubs/_field_list.tpl')); + } + + + function EditFieldTpl($id = '', $fld, $type) + { + global $AVE_DB, $AVE_Template, $_fm_dir; + + switch ($type) + { + case 'adm': + $file = BASE_DIR . '/fields/' . $fld . '/tpl/field-' . $id . '.tpl'; + $source = BASE_DIR . '/fields/' . $fld . '/tpl/field.tpl'; + break; + + case 'doc': + $file = BASE_DIR . '/fields/' . $fld . '/tpl/field-doc-' . $id . '.tpl'; + $source = BASE_DIR . '/fields/' . $fld . '/tpl/field-doc.tpl'; + break; + + case 'req': + $file = BASE_DIR . '/fields/' . $fld . '/tpl/field-req-' . $id . '.tpl'; + $source = BASE_DIR . '/fields/' . $fld . '/tpl/field-req.tpl'; + break; + } + + if (empty($id)) + $file = $source; + + if (file_exists($file)) + $code_text = file_get_contents($file); + else + $code_text = file_get_contents($source); + + $sql = $AVE_DB->Query(" + SELECT + a.rubric_field_title, + b.rubric_title + FROM + " . PREFIX . "_rubric_fields AS a + LEFT JOIN + " . PREFIX . "_rubrics AS b + ON a.rubric_id = b.Id + WHERE + a.rubric_field_type = '" . $fld ."' + AND + a.Id = '" . $id ."' + ")->FetchAssocArray(); + + $params = + array( + 'id' => $id, + 'fld' => $fld, + 'type' => $type, + 'func' => (file_exists($file) ? 'edit' : 'new'), + 'field' => $sql, + ); + + $AVE_Template->assign('main', $this->_get_fields_type($fld)); + $AVE_Template->assign('params', $params); + $AVE_Template->assign('code_text', $code_text); + $AVE_Template->assign("content", $AVE_Template->fetch('rubs/_field_code.tpl')); + } + + + /** + * Сохранение шаблона + * + */ + function SaveFieldTpl($id = '', $fld, $type, $func) + { + global $AVE_DB; + + switch ($type) + { + case 'adm': + $file = (! empty($id)) + ? BASE_DIR . '/fields/' . $fld . '/tpl/field-' . $id . '.tpl' + : BASE_DIR . '/fields/' . $fld . '/tpl/field.tpl'; + break; + + case 'doc': + $file = (! empty($id)) + ? BASE_DIR . '/fields/' . $fld . '/tpl/field-doc-' . $id . '.tpl' + : BASE_DIR . '/fields/' . $fld . '/tpl/field-doc.tpl'; + break; + + case 'req': + $file = (! empty($id)) + ? BASE_DIR . '/fields/' . $fld . '/tpl/field-req-' . $id . '.tpl' + : BASE_DIR . '/fields/' . $fld . '/tpl/field-req.tpl'; + break; + } + + $data = stripcslashes($_REQUEST['code_text']); + + @file_put_contents($file, $data); + chmod($file, 0644); + + $rubric_id = (int)$_REQUEST['rubric_id']; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + $message = 'Шаблон успешнно сохранен'; + $header = 'Выполнено'; + $theme = 'accept'; + + echo json_encode( + array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme) + ); + + exit; + } + + /** + * Удаление шаблона поля + * + */ + function DeleteFieldTpl($id, $fld, $type, $func) + { + global $AVE_DB; + + switch ($type) + { + case 'adm': + $file = BASE_DIR . '/fields/' . $fld . '/tpl/field-' . $id . '.tpl'; + break; + + case 'doc': + $file = BASE_DIR . '/fields/' . $fld . '/tpl/field-doc-' . $id . '.tpl'; + break; + + case 'req': + $file = BASE_DIR . '/fields/' . $fld . '/tpl/field-req-' . $id . '.tpl'; + break; + } + + @unlink($file); + + $rubric_id = $AVE_DB->Query("SELECT rubric_id FROM " . PREFIX . "_rubric_fields WHERE Id = '".$id."'")->GetCell(); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_rubrics + SET + rubric_changed_fields = '" . time() . "' + WHERE + Id = '" . intval($rubric_id) . "' + "); + + $AVE_DB->clearCache('rub_' . $rubric_id); + $this->clearChanges(); + + header('Location:' . get_referer_link()); + exit; + } + + + function clearTemplates($rubric_id) + { + + } + + + function clearChanges() + { + $cache_file = BASE_DIR . '/tmp/cache/sql/rubrics/all/rubrics.cahnges'; + unlink($cache_file); + } + } +?> \ No newline at end of file diff --git a/class/class.session.files.php b/class/class.session.files.php new file mode 100644 index 0000000..b68083a --- /dev/null +++ b/class/class.session.files.php @@ -0,0 +1,142 @@ +sess_lifetime = (defined('SESSION_LIFETIME') && is_numeric(SESSION_LIFETIME)) + ? SESSION_LIFETIME + : (get_cfg_var("session.gc_maxlifetime") < 1440 ? 1440 : get_cfg_var("session.gc_maxlifetime")); + + return true; + } + + /* Open session */ + function _open($sess_save_path, $session_name) + { + global $sess_save_path, $sess_session_name; + + $sess_save_path = BASE_DIR . '/tmp/session'; + $sess_session_name = $session_name; + + return true; + } + + /* Close session */ + function _close() + { + $this->_gc($this->sess_lifetime); + return true; + } + + /* Read session */ + function _read($id) + { + global $sess_save_path, $sess_session_name, $sess_session_id; + + $sess_session_id = $id; + $sess_file = $this->_folder() . '/' . $id . '.sess'; + + if (!file_exists($sess_file)) return ""; + + if ($fp = @fopen($sess_file, "r")) + { + $sess_data = fread($fp, filesize($sess_file)); + return($sess_data); + } + else + { + return ''; + } + } + + /* Write new data */ + function _write ($id, $sess_data) + { + global $sess_save_path, $sess_session_name, $sess_session_id; + + $sess_session_id = $id; + $sess_file = $this->_folder() . '/' . $id . '.sess'; + + if(!file_exists($this->_folder())) + mkdir($this->_folder(), 0777, true); + + if ($fp = @fopen($sess_file, "w")) + { + return fwrite($fp, $sess_data); + } + else + { + return false; + } + } + + /* Destroy session */ + function _destroy ($id) + { + global $sess_save_path, $sess_session_name, $sess_session_id; + + $sess_session_id = $id; + $sess_dir = $this->_folder(); + $sess_file = $sess_dir . '/' . $id . '.sess'; + + return @unlink($sess_file); + } + + /* Garbage collection, deletes old sessions */ + function _gc ($maxlifetime) + { + global $sess_save_path, $sess_session_id; + + $this->_clear($sess_save_path, 'sess', $maxlifetime); + + return true; + } + + function _clear($dir, $mask, $maxlifetime) + { + foreach(glob($dir . '/*') as $filename) + { + if (strtolower(substr($filename, strlen($filename) - strlen($mask), strlen($mask))) == strtolower($mask)) + { + if ((filemtime($filename) + $maxlifetime) < time()) + @unlink($filename); + } + + if (is_dir($filename)) + if (! count(glob($filename.'/*'))) + @rmdir($filename); + + self::_clear($filename, $mask, $maxlifetime); + } + } + + function _folder() + { + global $sess_session_id, $sess_save_path; + + return $sess_save_path . '/' . mb_substr($sess_session_id, 0, 3); + } + + function __destruct () + { + register_shutdown_function('session_write_close'); + } + } +?> \ No newline at end of file diff --git a/class/class.session.memcached.php b/class/class.session.memcached.php new file mode 100644 index 0000000..806812b --- /dev/null +++ b/class/class.session.memcached.php @@ -0,0 +1,72 @@ +memcached = new Memcached; + $this->memcached->addServer(MEMCACHED_SERVER, MEMCACHED_PORT); + + $this->ttl = (defined('SESSION_LIFETIME') && is_numeric(SESSION_LIFETIME)) + ? SESSION_LIFETIME + : (get_cfg_var("session.gc_maxlifetime") < 1440 ? 1440 : get_cfg_var("session.gc_maxlifetime")); + + $this->prefix = 'sess_'; + } + + /* Open session */ + function _open($sess_save_path, $session_name) + { + return true; + } + + /* Close session */ + function _close() + { + return true; + } + + /* Read session */ + function _read($id) + { + return $this->memcached->get($this->prefix . $id) ? : ''; + } + + /* Write new data */ + function _write ($id, $sess_data) + { + $this->memcached->set($this->prefix . $id, $sess_data, time() + $this->ttl); + + return true; + } + + /* Destroy session */ + function _destroy ($id) + { + $this->memcached->delete($this->prefix . $id); + + return true; + } + + /* Garbage collection, deletes old sessions */ + function _gc ($maxlifetime) + { + return true; + } + } +?> \ No newline at end of file diff --git a/class/class.session.php b/class/class.session.php new file mode 100644 index 0000000..9b092eb --- /dev/null +++ b/class/class.session.php @@ -0,0 +1,216 @@ +db_host = $config['dbhost']; + $this->db_user = $config['dbuser']; + $this->db_pass = $config['dbpass']; + $this->db_dbase = $config['dbname']; + $this->db_prefix = $config['dbpref']; + + $this->sess_lifetime = (defined('SESSION_LIFETIME') && is_numeric(SESSION_LIFETIME)) + ? (int)SESSION_LIFETIME + : (get_cfg_var("session.gc_maxlifetime") < 1440 ? 1440 : (int)get_cfg_var("session.gc_maxlifetime")); + + $this->connect(); + } + + private function connect(): void + { + $this->mysql_connect = new mysqli($this->db_host, $this->db_user, $this->db_pass, $this->db_dbase); + + if ($this->mysql_connect->connect_error) { + $this->error(); + } + + $this->mysql_connect->set_charset('utf8'); + } + + private function ensureConnection(): bool + { + if (!($this->mysql_connect instanceof mysqli) || !$this->mysql_connect->ping()) { + $this->connect(); + if (!$this->mysql_connect || $this->mysql_connect->connect_error) { + return false; + } + } + return true; + } + + public function __destruct() + { + if ($this->mysql_connect instanceof mysqli) { + $this->mysql_connect->close(); + $this->mysql_connect = null; + } + } + + public function _open(string $path, string $name): bool + { + return true; + } + + public function _close(): bool + { + if (!$this->ensureConnection()) { + return false; + } + + $sql = "DELETE FROM " . $this->db_prefix . "_sessions WHERE expiry < ?"; + $stmt = $this->mysql_connect->prepare($sql); + if (!$stmt) { + error_log("Prepare failed in _close: " . $this->mysql_connect->error); + return false; + } + $now = time(); + $stmt->bind_param('i', $now); + $stmt->execute(); + $stmt->close(); + + // Соединение не закрываем! + + return true; + } + + public function _read(string $ses_id): string + { + if (!$this->ensureConnection()) { + return ''; + } + + $sql = "SELECT value, Ip FROM " . $this->db_prefix . "_sessions WHERE sesskey = ? AND expiry > ?"; + $stmt = $this->mysql_connect->prepare($sql); + if (!$stmt) { + error_log("Prepare failed in _read: " . $this->mysql_connect->error); + return ''; + } + + $now = time(); + $stmt->bind_param('si', $ses_id, $now); + $stmt->execute(); + $stmt->bind_result($value, $ip); + $result = ''; + if ($stmt->fetch() && $ip === ($_SERVER['REMOTE_ADDR'] ?? '')) { + $result = $value; + } + $stmt->close(); + + return $result; + } + + public function _write(string $ses_id, string $data): bool + { + if (!$this->ensureConnection()) { + return false; + } + + $expiry = time() + $this->sess_lifetime; + $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? ''; + + $sql = "INSERT INTO " . $this->db_prefix . "_sessions (sesskey, expiry, value, Ip, expire_datum) + VALUES (?, ?, ?, ?, FROM_UNIXTIME(?,'%d.%m.%Y, %H:%i:%s')) + ON DUPLICATE KEY UPDATE + expiry = VALUES(expiry), + value = VALUES(value), + Ip = VALUES(Ip), + expire_datum = VALUES(expire_datum)"; + + $stmt = $this->mysql_connect->prepare($sql); + if (!$stmt) { + error_log("Prepare failed in _write: " . $this->mysql_connect->error); + return false; + } + + $stmt->bind_param('sisss', $ses_id, $expiry, $data, $remoteAddr, $expiry); + $result = $stmt->execute(); + if (!$result) { + error_log("Execute failed in _write: " . $stmt->error); + } + $stmt->close(); + + return $result; + } + + public function _destroy(string $ses_id): bool + { + if (!$this->ensureConnection()) { + return false; + } + + $sql = "DELETE FROM " . $this->db_prefix . "_sessions WHERE sesskey = ?"; + $stmt = $this->mysql_connect->prepare($sql); + if (!$stmt) { + error_log("Prepare failed in _destroy: " . $this->mysql_connect->error); + return false; + } + + $stmt->bind_param('s', $ses_id); + $result = $stmt->execute(); + if (!$result) { + error_log("Execute failed in _destroy: " . $stmt->error); + } + $stmt->close(); + + return $result; + } + + public function _gc(int $maxlifetime): bool + { + if (!$this->ensureConnection()) { + return false; + } + + $threshold = time() - $maxlifetime; + $sql = "DELETE FROM " . $this->db_prefix . "_sessions WHERE expiry < ?"; + $stmt = $this->mysql_connect->prepare($sql); + if (!$stmt) { + error_log("Prepare failed in _gc: " . $this->mysql_connect->error); + return false; + } + + $stmt->bind_param('i', $threshold); + $result = $stmt->execute(); + if (!$result) { + error_log("Execute failed in _gc: " . $stmt->error); + } + $stmt->close(); + + return $result; + } + + private function error(): void + { + ob_start(); + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + header('Retry-After: 3600'); + header('X-Powered-By:'); + echo "Error connect to MySQL."; + die; + } +} diff --git a/class/class.settings.php b/class/class.settings.php new file mode 100644 index 0000000..2e88e73 --- /dev/null +++ b/class/class.settings.php @@ -0,0 +1,902 @@ +assign('date_formats', $date_formats); + $AVE_Template->assign('time_formats', $time_formats); + $AVE_Template->assign('row', get_settings()); + $AVE_Template->assign('available_countries', get_country_list(1)); + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_main.tpl')); + } + + /** + * Метод отображения дополнительных настроек + * + */ + function settingsCase() + { + global $AVE_Template; + + // Сохраняем настройки + if (isset($_REQUEST['more'])) + { + $set = ' $type) + { + foreach($type as $k => $v) + { + switch ($GLOBALS['CMS_CONFIG'][$key][$k]['TYPE']) + { + case 'bool' : + $v = $v ? 'true' : 'false'; + break; + + case 'integer' : + $v = intval($v); + break; + + case 'string' : + $v = "'" . add_slashes($v) . "'"; + break; + + case 'dropdown' : + $v = "'" . add_slashes($v) . "'"; + break; + + default : + $v = "'" . add_slashes($v) . "'"; + break; + } + + $set .= "\t" . "// " . $GLOBALS['CMS_CONFIG'][$key][$k]['DESCR'] . "\r\n"; + $set .= "\t" . "define('" . $k . "', " . $v . ");\r\n\r\n"; + } + } + + $set .= '?>'; + + $result = file_put_contents(BASE_DIR . '/config/config.inc.php', $set); + + if ($result > 0) + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED'); + $header = $AVE_Template->get_config_vars('SETTINGS_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('SETTINGS_SAVE_DOP')); + } + else + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('SETTINGS_ERROR'); + $theme = 'error'; + } + + if (isAjax()) + { + echo json_encode(array( + 'message' => $message, + 'header' => $header, + 'theme' => $theme) + ); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=settings&sub=case&cp=' . SESSION); + } + + exit; + // Выводим настройки + } + else + { + $AVE_Template->assign('CMS_CONFIG', $GLOBALS['CMS_CONFIG']); + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_case.tpl')); + } + } + + /** + * Метод записи настроек + * + */ + function settingsSave() + { + global $AVE_DB, $AVE_Template; + + $muname = ($_REQUEST['mail_smtp_login']) ? "mail_smtp_login = '" . $_REQUEST['mail_smtp_login'] . "'," : ''; + $mpass = ($_REQUEST['mail_smtp_pass']) ? "mail_smtp_pass = '" . $_REQUEST['mail_smtp_pass'] . "'," : ''; + $msmp = ($_REQUEST['mail_sendmail_path']) ? "mail_sendmail_path = '" . $_REQUEST['mail_sendmail_path'] . "'," : ''; + $mn = ($_REQUEST['mail_from_name']) ? "mail_from_name = '" . $_REQUEST['mail_from_name'] . "'," : ''; + $ma = ($_REQUEST['mail_from']) ? "mail_from = '" . $_REQUEST['mail_from'] . "'," : ''; + $ep = ($_REQUEST['page_not_found_id']) ? "page_not_found_id = '" . $_REQUEST['page_not_found_id'] . "'," : ''; + $sn = ($_REQUEST['site_name']) ? "site_name = '" . $_REQUEST['site_name'] . "'," : ''; + $mp = ($_REQUEST['mail_port']) ? "mail_port = '" . $_REQUEST['mail_port'] . "'," : ''; + $mh = ($_REQUEST['mail_host']) ? "mail_host = '" . $_REQUEST['mail_host'] . "'," : ''; + + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_settings + SET + " . $muname . " + " . $mpass . " + mail_smtp_encrypt = '" . $_REQUEST['mail_smtp_encrypt'] . "', + " . $msmp . " + " . $ma . " + " . $mn . " + " . $ep . " + " . $sn . " + " . $mp . " + " . $mh . " + default_country = '" . $_REQUEST['default_country'] . "', + mail_type = '" . $_REQUEST['mail_type'] . "', + mail_content_type = '" . $_REQUEST['mail_content_type'] . "', + mail_word_wrap = '" . (int)$_REQUEST['mail_word_wrap'] . "', + mail_new_user = '" . $_REQUEST['mail_new_user'] . "', + mail_signature = '" . $_REQUEST['mail_signature'] . "', + message_forbidden = '" . $_REQUEST['message_forbidden'] . "', + hidden_text = '" . $_REQUEST['hidden_text'] . "', + navi_box = '" . $_REQUEST['navi_box'] . "', + start_label = '" . $_REQUEST['start_label'] . "', + end_label = '" . $_REQUEST['end_label'] . "', + separator_label = '" . $_REQUEST['separator_label'] . "', + next_label = '" . $_REQUEST['next_label'] . "', + prev_label = '" . $_REQUEST['prev_label'] . "', + total_label = '" . $_REQUEST['total_label'] . "', + link_box = '" . $_REQUEST['link_box'] . "', + total_box = '" . $_REQUEST['total_box'] . "', + active_box = '" . $_REQUEST['active_box'] . "', + separator_box = '" . $_REQUEST['separator_box'] . "', + bread_box = '" . $_REQUEST['bread_box'] . "', + bread_show_main = '" . ($_REQUEST['bread_show_main'] != 0 ? 1 : 0) . "', + bread_show_host = '" . ($_REQUEST['bread_show_host'] != 0 ? 1 : 0) . "', + bread_sepparator = '" . $_REQUEST['bread_sepparator'] . "', + bread_sepparator_use = '" . ($_REQUEST['bread_sepparator_use'] != 0 ? 1 : 0) . "', + bread_link_box = '" . $_REQUEST['bread_link_box'] . "', + bread_link_template = '" . $_REQUEST['bread_link_template'] . "', + bread_self_box = '" . $_REQUEST['bread_self_box'] . "', + bread_link_box_last = '" . ($_REQUEST['bread_link_box_last'] != 0 ? 1 : 0) . "', + date_format = '" . $_REQUEST['date_format'] . "', + time_format = '" . $_REQUEST['time_format'] . "', + use_doctime = '" . intval($_REQUEST['use_doctime']) . "' + WHERE + Id = 1 + "); + + if ($sql->_result === false) + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('SETTINGS_ERROR'); + $theme = 'error'; + } + else + { + $this->clearSettingsCache(); + + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED'); + $header = $AVE_Template->get_config_vars('SETTINGS_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('SETTINGS_SAVE_MAIN')); + } + + if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] = '1') + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=settings&cp=' . SESSION); + } + + exit; + } + + /** + * Метод отображения списка стран + * + */ + function settingsCountriesList() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT SQL_CALC_FOUND_ROWS * + FROM + " . PREFIX . "_countries + ORDER BY country_status ASC, country_name ASC + LIMIT " . (get_current_page() * $this->_limit - $this->_limit) . "," . $this->_limit + ); + + $countries = array(); + + while ($row = $sql->FetchAssocArray()) + array_push($countries, $row); + + $num = $AVE_DB->Query("SELECT FOUND_ROWS()")->GetCell(); + + if ($num > $this->_limit) + { + $page_nav = "{t}"; + $page_nav = get_pagination(ceil($num / $this->_limit), 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + $AVE_Template->assign('countries', $countries); + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_countries.tpl')); + } + + /** + * Метод записи параметров стран + * + */ + function settingsCountriesSave() + { + global $AVE_DB, $AVE_Template; + + foreach ($_POST['country_name'] as $id => $country_name) + { + $AVE_DB->Query(" + UPDATE " . PREFIX . "_countries + SET + country_name = '" . $country_name . "', + country_status = '" . $_POST['country_status'][$id] . "', + country_eu = '" . $_POST['country_eu'][$id] . "' + WHERE + Id = '" . $id . "' + "); + } + + reportLog($AVE_Template->get_config_vars('SETTINGS_SAVE_COUNTRY')); + } + + + /** + * Метод отображения списка языков + * + */ + function settingsLanguageList() + { + global $AVE_DB, $AVE_Template; + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_settings_lang + ORDER BY lang_default DESC, lang_status ASC, lang_key ASC + "); + + $language = array(); + + while ($row = $sql->FetchAssocArray()) + array_push($language, $row); + + $AVE_Template->assign('language', $language); + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_lang.tpl')); + } + + + /** + * Метод Редактирования параметров языков + * + */ + function settingsLanguageEdit() + { + global $AVE_DB, $AVE_Template; + + if (isset($_REQUEST["Id"])) + { + $items = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_settings_lang + WHERE + Id = '" . $_REQUEST["Id"] . "' + ")->FetchRow(); + + $AVE_Template->assign('items', $items); + } + + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_lang_edit.tpl')); + } + + + function settingsLanguageEditSave() + { + global $AVE_DB, $AVE_Template; + + if (! empty($_REQUEST["Id"])) + { + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_settings_lang + SET + lang_key = '" .$_REQUEST['lang_key']. "', + lang_alias_pref = '" .$_REQUEST['lang_alias_pref']. "', + lang_name = '" .$_REQUEST['lang_name']. "' + WHERE + Id = '" . $_REQUEST["Id"] . "' + "); + } + else + { + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_settings_lang + SET + lang_key = '" .$_REQUEST['lang_key']. "', + lang_name = '" .$_REQUEST['lang_name']. "', + lang_alias_pref = '" .$_REQUEST['lang_alias_pref']. "', + lang_default = '0', + lang_status = '0' + "); + + } + + $AVE_DB->clearCache('langs'); + + echo ""; + } + + + function settingsPaginationsList() + { + global $AVE_DB, $AVE_Template; + + $sql = " + SELECT + id, + pagination_name + FROM + " . PREFIX . "_paginations + "; + + $query = $AVE_DB->Query($sql); + + $items = array(); + + while ($row = $query->FetchRow()) + array_push($items, $row); + + $AVE_Template->assign('items', $items); + + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_pagination.tpl')); + } + + + function settingsPaginationsNew() + { + global $AVE_DB, $AVE_Template; + + $pagination = new stdClass(); + + $AVE_Template->assign('pagination', $pagination); + $AVE_Template->assign('content', $AVE_Template->fetch('settings/pagination_edit.tpl')); + } + + + function settingsPaginationsEdit() + { + global $AVE_DB, $AVE_Template; + + $sql = " + SELECT + * + FROM + " . PREFIX . "_paginations + WHERE + id = '" . $_REQUEST['id'] . "' + "; + + $pagination = $AVE_DB->Query($sql)->FetchRow(); + + $AVE_Template->assign('pagination', $pagination); + $AVE_Template->assign('content', $AVE_Template->fetch('settings/pagination_edit.tpl')); + } + + + function settingsPaginationsSave() + { + global $AVE_DB, $AVE_Template; + + // Если пришел ID + if (isset($_REQUEST['id']) && $_REQUEST['id'] > 0) + { + $sql = " + UPDATE + " . PREFIX . "_paginations + SET + pagination_name = '" . $_REQUEST['pagination_name'] . "', + pagination_box = '" . $_REQUEST['pagination_box'] . "', + pagination_start_label = '" . $_REQUEST['pagination_start_label'] . "', + pagination_end_label = '" . $_REQUEST['pagination_end_label'] . "', + pagination_separator_box = '" . $_REQUEST['pagination_separator_box'] . "', + pagination_separator_label = '" . $_REQUEST['pagination_separator_label'] . "', + pagination_next_label = '" . $_REQUEST['pagination_next_label'] . "', + pagination_prev_label = '" . $_REQUEST['pagination_prev_label'] . "', + pagination_link_box = '" . $_REQUEST['pagination_link_box'] . "', + pagination_active_link_box = '" . $_REQUEST['pagination_active_link_box'] . "', + pagination_link_template = '" . $_REQUEST['pagination_link_template'] . "', + pagination_link_active_template = '" . $_REQUEST['pagination_link_active_template'] . "' + WHERE + id = '" . $_REQUEST['id'] . "' + "; + + $query = $AVE_DB->Query($sql); + + if ($query === false) + { + $message = $AVE_Template->get_config_vars('PAGINATION_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('PAGINATION_ERROR'); + $theme = 'error'; + } + else + { + AVE_Paginations::clearCache(); + + $message = $AVE_Template->get_config_vars('PAGINATION_SAVED'); + $header = $AVE_Template->get_config_vars('PAGINATION_SUCCESS'); + $theme = 'accept'; + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + header('Location:index.php?do=settings&action=paginations&cp=' . SESSION); + } + + exit; + } + // Если не пришел ID + else + { + $sql = " + INSERT INTO + " . PREFIX . "_paginations + SET + pagination_name = '" . $_REQUEST['pagination_name'] . "', + pagination_box = '" . $_REQUEST['pagination_box'] . "', + pagination_start_label = '" . $_REQUEST['pagination_start_label'] . "', + pagination_end_label = '" . $_REQUEST['pagination_end_label'] . "', + pagination_separator_box = '" . $_REQUEST['pagination_separator_box'] . "', + pagination_separator_label = '" . $_REQUEST['pagination_separator_label'] . "', + pagination_next_label = '" . $_REQUEST['pagination_next_label'] . "', + pagination_prev_label = '" . $_REQUEST['pagination_prev_label'] . "', + pagination_link_box = '" . $_REQUEST['pagination_link_box'] . "', + pagination_active_link_box = '" . $_REQUEST['pagination_active_link_box'] . "', + pagination_link_template = '" . $_REQUEST['pagination_link_template'] . "', + pagination_link_active_template = '" . $_REQUEST['pagination_link_active_template'] . "' + "; + } + + $query = $AVE_DB->Query($sql); + + header('Location:index.php?do=settings&action=paginations&cp=' . SESSION); + exit; + } + + + function settingsPaginationsDel() + { + global $AVE_DB, $AVE_Template; + + if (isset($_REQUEST['id']) && $_REQUEST['id'] > 1) + { + $sql = " + DELETE + FROM + " . PREFIX . "_paginations + WHERE + id = '" . $_REQUEST['id'] . "' + "; + + $AVE_DB->Query($sql); + + AVE_Paginations::clearCache(); + } + + header('Location:index.php?do=settings&action=paginations&cp=' . SESSION); + exit; + } + + + /** + * Функция делает рекурсивный обход вложенных папок, и добавляет их в архив + * + * @param string $src_dir папка которую хотим заархивировать + * @param string $zip Куда кладем и как называем файл архива + * @return ZIP + */ + function ZipDirectory($src_dir, $zip, $dir_in_archive = '') + { + $dirHandle = opendir($src_dir); + + while (false !== ($file = readdir($dirHandle))) + { + if (($file != '.') && ($file != '..')) + { + if (! is_dir($src_dir . $file)) + { + $zip->addFile($src_dir . $file, $dir_in_archive.$file); + } + else + { + $zip->addEmptyDir($dir_in_archive.$file); + $zip = ZipDirectory($src_dir . $file . DIRECTORY_SEPARATOR, $zip, $dir_in_archive . $file . DIRECTORY_SEPARATOR); + } + } + } + + return $zip; + } + + /** + * Функция проверяет, возможно ли создать zip-архив, запускает + * ZipDirectory и закрывает файл при завершении обхода папок. + * + * @param string $src_dir папка которую хотим заархивировать + * @param string $archive_path Куда кладем и как называем файл архива + * @return bool true|false + */ + function ZipFull($src_dir, $archive_path) + { + $zip = new ZipArchive(); + + if ($zip->open($archive_path, ZIPARCHIVE::CREATE) !== true) + { + return false; + } + + $zip = ZipDirectory($src_dir,$zip); + + $zip->close(); + + return true; + } + + /** + * Функция очищает кеш системных настроек + * + */ + function clearSettingsCache() + { + $cache_dir = BASE_DIR . '/tmp/cache/sql/settings/'; + + return rrmdir($cache_dir); + } + + + /** + * Функция редактирования robots.txt + * + */ + function editRobots() + { + global $AVE_DB, $AVE_Template; + + $file_name = 'robots.txt'; + + $_REQUEST['sub'] = (! isset($_REQUEST['sub'])) + ? '' + : $_REQUEST['sub']; + + switch ($_REQUEST['sub']) + { + case 'save': + $file = BASE_DIR . '/' . $file_name; + + $template = stripcslashes($_REQUEST['code_text']); + + $result = file_put_contents($file, trim($template)); + + if ($result === false) + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED_ERR_FILE'); + $header = $AVE_Template->get_config_vars('SETTINGS_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED_FILE'); + $header = $AVE_Template->get_config_vars('SETTINGS_SUCCESS'); + $theme = 'accept'; + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=settings&cp=' . SESSION); + } + exit; + + default: + $file = BASE_DIR . '/' . $file_name; + + $template = file_get_contents($file); + + $formaction = "index.php?do=settings&action=robots&sub=save&cp=" . SESSION; + + $AVE_Template->assign('file_name', $file_name); + $AVE_Template->assign('formaction', $formaction); + $AVE_Template->assign('template', $template); + break; + } + + $AVE_Template->assign('content', $AVE_Template->fetch('settings/edit_file.tpl')); + } + + + /** + * Функция редактирования func.custom.php + * + */ + function editCustom() + { + global $AVE_Template; + + $file_name = 'func.custom.php'; + + $_REQUEST['sub'] = (! isset($_REQUEST['sub'])) + ? '' + : $_REQUEST['sub']; + + switch ($_REQUEST['sub']) + { + case 'save': + $file = BASE_DIR . '/functions/' . $file_name; + + $template = stripcslashes($_REQUEST['code_text']); + + $result = file_put_contents($file, trim($template)); + + if ($result === false) + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED_ERR_FILE'); + $header = $AVE_Template->get_config_vars('SETTINGS_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('SETTINGS_SAVED_FILE'); + $header = $AVE_Template->get_config_vars('SETTINGS_SUCCESS'); + $theme = 'accept'; + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=settings&cp=' . SESSION); + } + exit; + + default: + $file = BASE_DIR . '/functions/' . $file_name; + + $template = file_get_contents($file); + + $formaction = "index.php?do=settings&action=custom&sub=save&cp=" . SESSION; + + $AVE_Template->assign('file_name', $file_name); + $AVE_Template->assign('formaction', $formaction); + $AVE_Template->assign('template', $template); + break; + } + + $AVE_Template->assign('content', $AVE_Template->fetch('settings/edit_file.tpl')); + } + + + function showCache () + { + global $AVE_Template; + + + + $AVE_Template->assign('content', $AVE_Template->fetch('settings/settings_cache.tpl')); + } + + + function showCacheSize () + { + global $AVE_Template; + + switch ($_REQUEST['source']) + { + case 'smarty': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/smarty')); + break; + + case 'block': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/block')); + break; + + case 'documents': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/documents')); + break; + + case 'compiled': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/compile')); + break; + + case 'langs': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/langs')); + break; + + case 'modules': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/modules')); + break; + + case 'navigations': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/navigations')); + break; + + case 'paginations': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/paginations')); + break; + + case 'requests': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/requests')); + break; + + case 'rubrics': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/rubrics')); + break; + + case 'sessions': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/session')); + break; + + case 'sysblocks': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/sysblocks')); + break; + + case 'settings': + $size = format_size(get_dir_size(BASE_DIR . '/tmp/cache/sql/settings')); + break; + } + + $return = [ + 'size' => $size, + 'message' => $AVE_Template->get_config_vars('SETTINGS_SUCCESS'), + 'theme' => 'accept' + ]; + + _json($return, true); + } + + + function clearCache () + { + global $AVE_Template; + + switch ($_REQUEST['source']) + { + case 'smarty': + $cache_dir = BASE_DIR . '/tmp/cache/smarty'; + break; + + case 'block': + $cache_dir = BASE_DIR . '/tmp/cache/sql/block'; + break; + + case 'documents': + $cache_dir = BASE_DIR . '/tmp/cache/sql/documents'; + break; + + case 'compiled': + $cache_dir = BASE_DIR . '/tmp/cache/sql/compile'; + break; + + case 'langs': + $cache_dir = BASE_DIR . '/tmp/cache/sql/langs'; + break; + + case 'modules': + $cache_dir = BASE_DIR . '/tmp/cache/sql/modules'; + break; + + case 'navigations': + $cache_dir = BASE_DIR . '/tmp/cache/sql/navigations'; + break; + + case 'paginations': + $cache_dir = BASE_DIR . '/tmp/cache/sql/paginations'; + break; + + case 'requests': + $cache_dir = BASE_DIR . '/tmp/cache/sql/requests'; + break; + + case 'rubrics': + $cache_dir = BASE_DIR . '/tmp/cache/sql/rubrics'; + break; + + case 'sysblocks': + $cache_dir = BASE_DIR . '/tmp/cache/sql/sysblocks'; + break; + + case 'sessions': + $cache_dir = BASE_DIR . '/tmp/session'; + break; + + case 'settings': + $cache_dir = BASE_DIR . '/tmp/cache/sql/settings'; + break; + } + + $remove = rrmdir($cache_dir); + + $return = [ + 'size' => format_size(get_dir_size($cache_dir)), + 'header' => $remove ? $AVE_Template->get_config_vars('SETTINGS_CACHE_SUCCESS') : $AVE_Template->get_config_vars('SETTINGS_CACHE_ERROR'), + 'message' => $remove ? $AVE_Template->get_config_vars('SETTINGS_CACHE_SUCCESS_T') : $AVE_Template->get_config_vars('SETTINGS_CACHE_ERROR_T'), + 'theme' => $remove ? 'accept' : 'error' + ]; + + _json($return, true); + } + } +?> \ No newline at end of file diff --git a/class/class.sysblocks.php b/class/class.sysblocks.php new file mode 100644 index 0000000..dad5e76 --- /dev/null +++ b/class/class.sysblocks.php @@ -0,0 +1,677 @@ +Query($sql)->GetCell(); + } + + + /* + |-------------------------------------------------------------------------------------- + | getGroups + |-------------------------------------------------------------------------------------- + | + | Получаем список групп + | + */ + public static function getGroups () + { + global $AVE_DB; + + $sql = " + SELECT + * + FROM + " . PREFIX . "_sysblocks_groups + "; + + $query = $AVE_DB->Query($sql); + + $groups = []; + + while ($row = $query->FetchRow()) + array_push($groups, $row); + + return $groups; + } + + + /* + |-------------------------------------------------------------------------------------- + | startPage + |-------------------------------------------------------------------------------------- + | + | Гланая страница + | + */ + public static function startPage () + { + global $AVE_DB, $AVE_Template; + + //-- Группы + $groups = []; + + $sql = " + SELECT + * + FROM + " . PREFIX . "_sysblocks_groups + ORDER BY + position ASC + "; + + $query = $AVE_DB->Query($sql); + + while ($row = $query->FetchAssocArray()) + { + $row['count'] = 0; + $groups[$row['id']] = $row; + } + + //-- Блоки + $sysblocks = []; + + $sql = " + SELECT + a.*, + a.sysblock_group_id + FROM + " . PREFIX . "_sysblocks AS a + LEFT JOIN + " . PREFIX . "_sysblocks_groups AS b + ON a.sysblock_group_id = b.id + ORDER BY + b.position ASC, a.id ASC + "; + + $query = $AVE_DB->Query($sql); + + while ($row = $query->FetchAssocArray()) + { + $row['author'] = get_username_by_id($row['sysblock_author_id']); + $sysblocks[$row['sysblock_group_id']][] = $row; + } + + foreach ($sysblocks AS $_k => $_v) + { + if ($_k == 0) + $groups[$_k]['position'] = 0; + + $groups[$_k]['count'] = count($sysblocks[$_k]); + } + + $AVE_Template->assign('groups', $groups); + $AVE_Template->assign('sysblocks', $sysblocks); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/start.tpl')); + } + + + /* + |-------------------------------------------------------------------------------------- + | listBlocks + |-------------------------------------------------------------------------------------- + | + | Список системных блоков + | + */ + public static function listBlocks () + { + global $AVE_DB, $AVE_Template; + + $sysblocks = []; + + $sql = " + SELECT + * + FROM + " . PREFIX . "_sysblocks + ORDER BY + id + "; + + $query = $AVE_DB->Query($sql); + + // Формируем массив из полученных данных + while ($row = $query->FetchRow()) + { + $row->sysblock_author_id = get_username_by_id($row->sysblock_author_id); + array_push($sys_blocks, $row); + } + + $AVE_Template->assign('sid', 0); + $AVE_Template->assign('sysblocks', $sysblocks); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/list.tpl')); + } + + + /* + |-------------------------------------------------------------------------------------- + | listGroups + |-------------------------------------------------------------------------------------- + | + | Список групп системных блоков + | + */ + public static function listGroups () + { + global $AVE_DB, $AVE_Template; + + $groups = []; + + $sql = " + SELECT + * + FROM + " . PREFIX . "_sysblocks_groups + ORDER BY + position + "; + + $query = $AVE_DB->Query($sql); + + // Формируем массив из полученных данных + while ($row = $query->FetchAssocArray()) + array_push($groups, $row); + + $AVE_Template->assign('sid', 0); + $AVE_Template->assign('groups', $groups); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/groups.tpl')); + } + + + /* + |-------------------------------------------------------------------------------------- + | groupsSort + |-------------------------------------------------------------------------------------- + | + | Сортировка групп + | + */ + public static function groupsSort () + { + global $AVE_DB, $AVE_Template; + + foreach ($_REQUEST['sort'] AS $position => $group_id) + { + $position++; + + $sql = " + UPDATE + " . PREFIX . "_sysblocks_groups + SET + position = '" . (int)$position . "' + WHERE + id = '" . (int)$group_id . "' + "; + + $AVE_DB->Query($sql); + } + + if (isAjax()) + { + $message = $AVE_Template->get_config_vars('RUBRIK_SORTED'); + $header = $AVE_Template->get_config_vars('RUBRIK_FILDS_SUCCESS'); + $theme = 'accept'; + + echo json_encode(['message' => $message, 'header' => $header, 'theme' => $theme]); + exit; + } + } + + + /* + |-------------------------------------------------------------------------------------- + | newGroup + |-------------------------------------------------------------------------------------- + | + | Новая группа + | + */ + public static function newGroup () + { + global $AVE_DB; + + $sql = " + SELECT + MAX(position) + FROM + " . PREFIX . "_sysblocks_groups + "; + + $position = $AVE_DB->Query($sql)->GetCell(); + + $position++; + + $sql = " + INSERT + " . PREFIX . "_sysblocks_groups + SET + position = '" . $position . "', + title = '" . $_REQUEST['title'] . "', + description = '" . $_REQUEST['description'] . "' + "; + + $AVE_DB->Query($sql); + + header('Location:index.php?do=sysblocks&action=groups&cp=' . SESSION); + exit; + } + + + /* + |-------------------------------------------------------------------------------------- + | delGroup + |-------------------------------------------------------------------------------------- + | + | Удалить группу + | + */ + public static function delGroup () + { + global $AVE_DB; + + $id = (int)$_REQUEST['id']; + + $sql = " + DELETE FROM + " . PREFIX . "_sysblocks_groups + WHERE + id = '" . $id . "' + "; + + $AVE_DB->Query($sql); + + header('Location:index.php?do=sysblocks&action=groups&cp=' . SESSION); + exit; + } + + + /* + |-------------------------------------------------------------------------------------- + | newBlock + |-------------------------------------------------------------------------------------- + | + | Создание системного блока + | + */ + public static function newBlock () + { + global $AVE_Template; + + $row['sysblock_name'] = ''; + $row['sysblock_alias'] = ''; + $row['sysblock_text'] = ''; + $row['sysblock_eval'] = '1'; + $row['sysblock_visual'] = (isset($_REQUEST['sysblock_visual']) && $_REQUEST['sysblock_visual'] != 0) ? $_REQUEST['sysblock_visual'] : ''; + + $AVE_Template->assign('sid', 0); + $AVE_Template->assign('groups', self::getGroups()); + + if ((isset($_REQUEST['sysblock_visual']) && $_REQUEST['sysblock_visual'] == 1) || $row['sysblock_visual'] == 1) + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['customConfig'] = 'sysblock.js'; + $oCKeditor->config['toolbar'] = 'Big'; + $oCKeditor->config['height'] = 400; + $config = []; + $row['sysblock_text'] = $oCKeditor->editor('sysblock_text', $row['sysblock_text'], $config); + + $AVE_Template->assign($row); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/form_visual.tpl')); + } + else + { + $AVE_Template->assign($row); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/form.tpl')); + } + } + + + /* + |-------------------------------------------------------------------------------------- + | editBlock + |-------------------------------------------------------------------------------------- + | + | Редактирование системного блока + | + */ + public static function editBlock () + { + global $AVE_DB, $AVE_Template; + + $sysblock_id = $_REQUEST['id']; + + $sql = " + SELECT + * + FROM + " . PREFIX . "_sysblocks + WHERE + id = '" . $sysblock_id . "' + OR + sysblock_alias = '" . $sysblock_id . "' + "; + + $row = $AVE_DB->Query($sql)->FetchAssocArray(); + + $AVE_Template->assign('sid', $row['id']); + $AVE_Template->assign('groups', self::getGroups()); + + if ((isset($_REQUEST['sysblock_visual']) && $_REQUEST['sysblock_visual'] == 1) || $row['sysblock_visual'] == 1) + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['customConfig'] = 'sysblock.js'; + $oCKeditor->config['toolbar'] = 'Big'; + $oCKeditor->config['height'] = 400; + $config = []; + $row['sysblock_text'] = $oCKeditor->editor('sysblock_text', $row['sysblock_text'], $config); + + $AVE_Template->assign($row); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/form_visual.tpl')); + } + else + { + $AVE_Template->assign($row); + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/form.tpl')); + } + } + + + /* + |-------------------------------------------------------------------------------------- + | editBlock + |-------------------------------------------------------------------------------------- + | + | Сохранение системного блока + | + */ + public static function saveBlock () + { + global $AVE_DB, $AVE_Template; + + $sysblock_id = $_REQUEST['id'] + ? (int)$_REQUEST['id'] + : null; + + if (is_numeric($sysblock_id)) + { + + $_REQUEST['sysblock_external'] = (isset($_REQUEST['sysblock_external'])) ? $_REQUEST['sysblock_external'] : 0; + $_REQUEST['sysblock_ajax'] = (isset($_REQUEST['sysblock_ajax'])) ? $_REQUEST['sysblock_ajax'] : 0; + $_REQUEST['sysblock_eval'] = (isset($_REQUEST['sysblock_eval'])) ? $_REQUEST['sysblock_eval'] : 0; + $_REQUEST['sysblock_visual'] = (isset($_REQUEST['sysblock_visual'])) ? $_REQUEST['sysblock_visual'] : 0; + $_REQUEST['sysblock_alias'] = isset($_REQUEST['sysblock_alias']) ? $_REQUEST['sysblock_alias'] : ''; + + $sql = " + UPDATE + " . PREFIX . "_sysblocks + SET + sysblock_group_id = '" . (int)$_REQUEST['sysblock_group_id'] . "', + sysblock_name = '" . $_REQUEST['sysblock_name'] . "', + sysblock_description = '" . addslashes($_REQUEST['sysblock_description']) . "', + sysblock_alias = '" . $_REQUEST['sysblock_alias'] . "', + sysblock_text = '" . $_REQUEST['sysblock_text'] . "', + sysblock_eval = '" . (int)$_REQUEST['sysblock_eval'] . "', + sysblock_external = '" . (int)$_REQUEST['sysblock_external'] . "', + sysblock_ajax = '" . (int)$_REQUEST['sysblock_ajax'] . "', + sysblock_visual = '" . (int)$_REQUEST['sysblock_visual'] . "' + WHERE + id = '" . $sysblock_id . "' + "; + + $query = $AVE_DB->Query($sql); + + if ($query->_result === false) + { + $message = $AVE_Template->get_config_vars('SYSBLOCK_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('SYSBLOCK_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('SYSBLOCK_SAVED'); + $header = $AVE_Template->get_config_vars('SYSBLOCK_SUCCESS'); + $theme = 'accept'; + + //-- Стираем кеш сисблока + self::clearCache($sysblock_id, $_REQUEST['sysblock_alias']); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('SYSBLOCK_SQLUPDATE') . " (" . stripslashes($_REQUEST['sysblock_name']) . ") (id: $sysblock_id)"); + } + + if (isAjax()) + { + echo json_encode(['message' => $message, 'header' => $header, 'theme' => $theme]); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=sysblocks&cp=' . SESSION); + } + + exit; + } + else + { + $sql = " + INSERT INTO + " . PREFIX . "_sysblocks + SET + sysblock_group_id = '" . (int)$_REQUEST['sysblock_group_id'] . "', + sysblock_name = '" . $_REQUEST['sysblock_name'] . "', + sysblock_description = '" . addslashes($_REQUEST['sysblock_description']) . "', + sysblock_alias = '" . $_REQUEST['sysblock_alias'] . "', + sysblock_text = '" . $_REQUEST['sysblock_text'] . "', + sysblock_author_id = '" . (int)$_SESSION['user_id'] . "', + sysblock_eval = '" . (int)$_REQUEST['sysblock_eval'] . "', + sysblock_external = '" . (int)$_REQUEST['sysblock_external'] . "', + sysblock_ajax = '" . (int)$_REQUEST['sysblock_ajax'] . "', + sysblock_visual = '" . (int)$_REQUEST['sysblock_visual'] . "', + sysblock_created = '" . time() . "' + "; + + $AVE_DB->Query($sql); + + $sysblock_id = $AVE_DB->InsertId(); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('SYSBLOCK_SQLNEW') . " (" . stripslashes($_REQUEST['sysblock_name']) . ") (id: $sysblock_id)"); + } + + if (! isset($_REQUEST['next_edit'])) + header('Location:index.php?do=sysblocks&cp=' . SESSION); + else + header('Location:index.php?do=sysblocks&action=edit&&id=' . $sysblock_id . '&cp=' . SESSION); + } + + + /* + |-------------------------------------------------------------------------------------- + | delBlock + |-------------------------------------------------------------------------------------- + | + | Удаление системного блока + | + */ + public static function delBlock () + { + global $AVE_DB, $AVE_Template; + + $sysblock_id = $_REQUEST['id']; + + if (is_numeric($sysblock_id)) + { + $sysblock = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_sysblocks + WHERE + id = '" . $sysblock_id . "' + ")->FetchRow(); + + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_sysblocks + WHERE + id = '" . $sysblock_id . "' + "); + + //-- Стираем кеш сисблока + self::clearCache($sysblock_id, $sysblock->sysblock_alias); + + //-- Сохраняем системное сообщение в журнал + reportLog($AVE_Template->get_config_vars('SYSBLOCK_SQLDEL') . " (" . stripslashes($sysblock->sysblock_name) . ") (id: $sysblock_id)"); + } + + header('Location:index.php?do=sysblocks&cp=' . SESSION); + } + + + /* + |-------------------------------------------------------------------------------------- + | editBlock + |-------------------------------------------------------------------------------------- + | + | Очистка кеша системного блока + | + */ + public static function clearCache ($id, $alias = null) + { + $from_id = BASE_DIR . '/tmp/cache/sql/sysblocks/' . $id; + rrmdir($from_id); + + if ($alias) + { + $from_alias = BASE_DIR . '/tmp/cache/sql/sysblocks/' . $alias; + rrmdir($from_alias); + } + } + + + /* + |-------------------------------------------------------------------------------------- + | multiBlock + |-------------------------------------------------------------------------------------- + | + | Копирование системного блока + | + */ + public static function multiBlock () + { + global $AVE_DB, $AVE_Template; + + $_REQUEST['sub'] = (!isset($_REQUEST['sub'])) + ? '' + : $_REQUEST['sub']; + + $errors = []; + + switch ($_REQUEST['sub']) + { + case 'save': + $ok = true; + + $sql = " + SELECT + sysblock_name + FROM + " . PREFIX . "_sysblocks + WHERE + sysblock_name = '" . $_REQUEST['sysblock_name'] . "' + "; + + $row = $AVE_DB->Query($sql)->FetchRow(); + + if (@$row->sysblock_name != '') + { + array_push($errors, $AVE_Template->get_config_vars('SYSBLOCK_EXIST')); + $AVE_Template->assign('errors', $errors); + $ok = false; + } + + if ($_REQUEST['sysblock_name'] == '') + { + array_push($errors, $AVE_Template->get_config_vars('SYSBLOCK_COPY_TIP')); + $AVE_Template->assign('errors', $errors); + $ok = false; + } + + if ($ok) + { + $sql = " + SELECT + sysblock_text + FROM + " . PREFIX . "_sysblocks + WHERE + id = '" . (int)$_REQUEST['id'] . "' + "; + + $row = $AVE_DB->Query($sql)->FetchRow(); + + $sql = " + INSERT INTO + " . PREFIX . "_sysblocks + SET + Id = '', + sysblock_name = '" . $_REQUEST['sysblock_name'] . "', + sysblock_text = '" . addslashes($row->sysblock_text) . "', + sysblock_author_id = '" . $_SESSION['user_id'] . "', + sysblock_created = '" . time() . "' + "; + + $AVE_DB->Query($sql); + + reportLog($_SESSION['user_name'] . ' - ' . $AVE_Template->get_config_vars('SYSBLOCK_COPY_LOG') .' (' . (int)$_REQUEST['id'] . ')', 2, 2); + + header('Location:index.php?do=sysblocks'.'&cp=' . SESSION); + } + + $AVE_Template->assign('content', $AVE_Template->fetch('sysblocks/multi.tpl')); + break; + } + } + } +?> \ No newline at end of file diff --git a/class/class.template.php b/class/class.template.php new file mode 100644 index 0000000..be46651 --- /dev/null +++ b/class/class.template.php @@ -0,0 +1,374 @@ +template_dir = $template_dir; + + /** + * Имя каталога, в котором хранятся компилированные шаблоны. + */ + $this->compile_dir = BASE_DIR . '/tmp/cache/smarty'; + + /** + * Имя каталога, в котором хранится кэш. + */ + $this->cache_dir_root = BASE_DIR . '/tmp/cache'; + + /** + * Имя каталога, в котором хранится кэш шаблонов. + */ + $this->cache_dir = BASE_DIR . '/tmp/cache/tpl'; + + /** + * Имя каталога, в котором хранится кэш модулей. + */ + $this->module_cache_dir = BASE_DIR . '/tmp/cache/module'; + + /** + * Имя каталога, в котором хранится сессии пользователей. + */ + $this->session_dir = BASE_DIR . '/tmp/session'; + + /** + * Имя каталога, в котором хранится сессии пользователей. + */ + $this->sql_cache_dir = BASE_DIR . '/tmp/cache/sql'; + + /** + * Использование поддиректорий для хранения кэша и скомпилированных шаблонов. + */ + $this->use_sub_dirs = SMARTY_USE_SUB_DIRS; + + /** + * При каждом вызове РНР-приложения Smarty проверяет, изменился или нет текущий шаблон + * с момента последней компиляции. Если шаблон изменился, он перекомпилируется. + * В случае, если шаблон еще не был скомпилирован, его компиляция производится + * с игнорированием значения этого параметра. + */ + $this->compile_check = SMARTY_COMPILE_CHECK; + + /** + * Активирует debugging console - порожденное при помощи javascript окно браузера, + * содержащее информацию о подключенных шаблонах и загруженных переменных для текущей страницы. + */ + $this->debugging = SMARTY_DEBUGGING; + + /** + * Регистрация плагинов-функций Smarty. + * Передается наименование функции шаблона и имя функции, реализующей ее. + */ + $this->register_function('check_permission', 'check_permission'); + $this->register_function('get_home_link', 'get_home_link'); + $this->register_function('num_format', 'num_format'); + $this->register_function('thumb', 'make_thumbnail'); + + /** + * Регистрация плагинов-модификаторов Smarty. + * Передается имя модификатора и имя функции, реализующей его. + */ + $this->register_modifier('pretty_date', 'pretty_date'); + $this->register_modifier('translate_date', 'translate_date'); + $this->register_modifier('utf8', 'utf8'); + + // плагин позволяющий поставить метки шаблонов + // для быстрого поиска шаблона отвечающего за вывод + // перед использованием очистить cache/smarty + // $this->register_postfilter('add_template_comment'); + + /** + * Присваиваем общие значения для шаблонов. + * Можно явно передавать пары имя/значение, + * или ассоциативные массивы, содержащие пары имя/значение. + */ + $assign['BASE_DIR'] = BASE_DIR; + $assign['ABS_PATH'] = ABS_PATH; + $assign['DATE_FORMAT'] = DATE_FORMAT; + $assign['TIME_FORMAT'] = TIME_FORMAT; + $assign['PAGE_NOT_FOUND_ID'] = PAGE_NOT_FOUND_ID; + + $this->assign($assign); + } + + /** + * ВНУТРЕННИЕ МЕТОДЫ + */ + + /** + * Проверка наличия одноименного шаблона в директории темы дизайна. + * При наличии шаблона в директории темы дизайна используется этот шаблон. + * + * @param string $tpl путь к шаблону + * @return string + */ + function _redefine_template($tpl) + { + if (!defined('THEME_FOLDER')) return $tpl; + + $r_tpl = str_replace(BASE_DIR, BASE_DIR . '/templates/' . THEME_FOLDER, $tpl); + + return (file_exists($r_tpl) && is_file($r_tpl)) ? $r_tpl : $tpl; + } + + /** + * ВНЕШНИЕ МЕТОДЫ + */ + + /** + * Переопределение одноименного метода Smarty + * для конфигурационных файлов созданных в теме дизайна. + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + Smarty::config_load($this->_redefine_template($file), $section, $scope); + } + + /** + * Переопределение одноименного метода Smarty + * для пользовательских шаблонов созданных в теме дизайна. + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + return Smarty::is_cached($this->_redefine_template($tpl_file), $cache_id, $compile_id); + } + + /** + * Переопределение одноименного метода Smarty + * для пользовательских шаблонов созданных в теме дизайна. + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + return Smarty::fetch($this->_redefine_template($resource_name), $cache_id, $compile_id, $display); + } + + /** + * Переопределение одноименного метода Smarty + * для пользовательских шаблонов созданных в теме дизайна. + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + + function recursivDelete($dir) + { + $it = new RecursiveDirectoryIterator($dir . '/'); + $files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST); + + foreach($files as $file) + { + if ($file->getFilename() === '.' || $file->getFilename() === '..') + continue; + + if ($file->isDir()) + rmdir($file->getRealPath()); + else + unlink($file->getRealPath()); + } + + rmdir($dir); + } + + + /** + * Метод очистки кэша + * + */ + function CacheClear() + { + global $AVE_DB, $AVE_Template; + + $message = array(); + + // Метод очистки кэша + if (isset($_REQUEST['templateCache']) && $_REQUEST['templateCache'] == '1') + { + // Smarty clear cache + $this->clear_all_cache(); + + foreach (glob($this->cache_dir_root . "/cache_*") as $filename) + @unlink($filename); + + write_htaccess_deny($this->cache_dir . '/'); + + // Memcached + if (MEMCACHED_SERVER && MEMCACHED_PORT) + { + $m = new Memcached(); + $m->addServer(MEMCACHED_SERVER, MEMCACHED_PORT); + $m->flush(); + } + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_CACHE_SUCCESS'); + reportLog($AVE_Template->get_config_vars('TEMPLATES_CACHE_SUCCESS_LOG')); + + // Очищаем кэш сессий в БД в таблице _sessions + $AVE_DB->Query(" + DELETE FROM + " . PREFIX . "_sessions + "); + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_CACHE_DB_SUCCESS'); + reportLog($AVE_Template->get_config_vars('TEMPLATES_CACHE_DB_SUCCESS_LOG')); + } + + + //Метод удаления скомпилированных шаблонов + if (isset($_REQUEST['templateCompiledTemplate']) && $_REQUEST['templateCompiledTemplate'] == '1') + { + // Smarty compiled cache + $this->clear_compiled_tpl(); + + write_htaccess_deny($this->compile_dir . '/'); + + $filename = $this->compile_dir . '/.htaccess'; + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_CACHE_CT_SUCCESS'); + reportLog($AVE_Template->get_config_vars('TEMPLATES_CACHE_CT_SUCCESS_LOG')); + } + + + //Метод удаления скомпилированных шаблонов модулей + if (isset($_REQUEST['moduleCache']) && $_REQUEST['moduleCache'] == '1') + { + $this->recursivDelete($this->module_cache_dir); + + mkdir($this->module_cache_dir, 0777, true); + + write_htaccess_deny($this->module_cache_dir . '/'); + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_CACHE_MC_SUCCESS'); + reportLog($AVE_Template->get_config_vars('TEMPLATES_CACHE_MC_SUCCESS_LOG')); + } + + + //Метод удаления всех сессий + if (isset($_REQUEST['sessionUsers']) && $_REQUEST['sessionUsers'] == '1') + { + $this->recursivDelete($this->session_dir); + + mkdir($this->session_dir, 0777, true); + + write_htaccess_deny($this->session_dir . '/'); + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_CACHE_SU_SUCCESS'); + reportLog($AVE_Template->get_config_vars('TEMPLATES_CACHE_SU_SUCCESS_LOG')); + } + + + //Метод удаления кэша запросов + if (isset($_REQUEST['sqlCache']) && $_REQUEST['sqlCache'] == '1') + { + $this->recursivDelete($this->sql_cache_dir); + + mkdir($this->sql_cache_dir, 0777, true); + + write_htaccess_deny($this->sql_cache_dir . '/'); + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_CACHE_SC_SUCCESS'); + reportLog($AVE_Template->get_config_vars('TEMPLATES_CACHE_SC_SUCCESS_LOG')); + } + + echo json_encode(array($AVE_Template->get_config_vars('TEMPLATES_MESSAGE') . "
      " . implode('
      ', $message), 'accept')); + } + + + /** + * Метод очистки миниатюр + * + */ + function ThumbnailsClear() + { + global $AVE_DB, $AVE_Template; + + $message = []; + + function rdel_thumb($dirname) + { + $dirs = glob("$dirname/*", GLOB_ONLYDIR|GLOB_NOSORT); + + $dir_thumb = THUMBNAIL_DIR; + + foreach ($dirs AS $dir) + { + $tmb = glob("$dir/$dir_thumb", GLOB_ONLYDIR|GLOB_NOSORT); + + foreach ($tmb AS $tmbs) + rrmdir($tmbs); + + rdel_thumb($dir); + } + + $hid_cat = (glob("$dirname/{.tmb}*", GLOB_ONLYDIR|GLOB_BRACE)); + + $hid_tmb = $hid_cat[0]; + + foreach (glob("$hid_cat[0]/*.png", GLOB_NOSORT) AS $filename) + unlink("$filename"); + + rrmdir(BASE_DIR . '/' . UPLOAD_DIR . '/' . THUMBNAIL_DIR); + } + + rdel_thumb(BASE_DIR . '/' . UPLOAD_DIR); + + $message[] = $AVE_Template->get_config_vars('TEMPLATES_THUMBNAILS_SUCCESS'); + + reportLog($AVE_Template->get_config_vars('TEMPLATES_THUMBNAILS_SUCCESS_LOG')); + + echo json_encode(array($AVE_Template->get_config_vars('TEMPLATES_MESSAGE') . "
      " . implode('
      ', $message), 'accept')); + } + } +?> \ No newline at end of file diff --git a/class/class.templates.php b/class/class.templates.php new file mode 100644 index 0000000..440bcff --- /dev/null +++ b/class/class.templates.php @@ -0,0 +1,694 @@ +assign('css_files', $css_files); + + unset($dir, $css_files); + + //-- Js файлы + $dir = BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/js/'; + + if ($handle = opendir($dir)) + { + $js_files = array(); + + while (false !== ($file = readdir($handle))) + { + if ($file != "." && $file != ".." && substr($file,-2) == 'js') + { + if(! is_dir($dir."/".$file)) + $files[$ii]['filename'] = $file; + + $files[$ii]['filesize'] = filesize($dir ."/" . $file); + $js_files[] = $files; + } + } + + closedir($handle); + } + + $AVE_Template->assign('js_files', $js_files); + + unset($dir, $js_files); + + $items = array(); + + $num_tpl = $AVE_DB->Query(" + SELECT + COUNT(*) + FROM + " . PREFIX . "_templates + ")->GetCell(); + + $page_limit = (isset($_REQUEST['set']) && is_numeric($_REQUEST['set'])) ? (int)$_REQUEST['set'] : 30; + $pages = ceil($num_tpl / $page_limit); + $set_start = get_current_page() * $page_limit - $page_limit; + + if ($num_tpl > $page_limit) + { + $page_nav = " {t} "; + $page_nav = get_pagination($pages, 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + $sql = $AVE_DB->Query(" + SELECT + * + FROM + " . PREFIX . "_templates + LIMIT + " . $set_start . "," . $page_limit . " + "); + + while ($row = $sql->FetchRow()) + { + $inuse = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_rubrics AS rubric, + " . PREFIX . "_module AS module + WHERE + rubric.rubric_template_id = '" . $row->Id . "' + OR + module.ModuleTemplate = '" . $row->Id . "' + LIMIT 1 + ")->NumRows(); + + if (! $inuse) + $row->can_deleted = 1; + + $row->template_author = get_username_by_id($row->template_author_id); + + array_push($items, $row); + + unset($row); + } + + $AVE_Template->assign('items', $items); + $AVE_Template->assign('content', $AVE_Template->fetch('templates/templates.tpl')); + } + + + public static function templatesNew() + { + global $AVE_Template; + + $AVE_Template->assign('content', $AVE_Template->fetch('templates/form.tpl')); + } + + + public static function templatesEdit() +{ + global $AVE_DB, $AVE_Template; + + $template_id = (int)($_REQUEST['Id'] ?? 0); + + // Попытка получить запись из базы по ID + $row = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_templates + WHERE Id = '" . $template_id . "' + ")->FetchRow(); + + if (!$row) { + // Если запись не найдена, получаем последний созданный шаблон из базы + $row = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_templates + ORDER BY Id DESC + LIMIT 1 + ")->FetchRow(); + + if (!$row) { + // Если таблица пуста, инициализируем пустой объект + $row = new stdClass(); + $row->template_text = ''; + } + + // При выводе последнего шаблона берем текст из базы напрямую + $row->template_text = pretty_chars($row->template_text); + $row->template_text = stripslashes($row->template_text); + + } else { + // Если шаблон найден, берем содержимое из кеша (файла) + $template = self::getTemplate($template_id); + + if ($template !== false && $template !== null) { + $row->template_text = $template; + } else { + // Если кеш отсутствует, fallback на базу + $row->template_text = pretty_chars($row->template_text); + $row->template_text = stripslashes($row->template_text); + } + } + + // Проверка PHP-кода и прав + $check_code = strtolower($row->template_text ?? ''); + + if (is_php_code($check_code) && !check_permission('template_php')) { + $AVE_Template->assign('php_forbidden', 1); + $AVE_Template->assign('read_only', 'readonly'); + } + + $AVE_Template->assign('row', $row); + $AVE_Template->assign('content', $AVE_Template->fetch('templates/form.tpl')); +} + + + + + public static function templatesSave() + { + global $AVE_DB, $AVE_Template; + + if (isset($_REQUEST['Id']) AND is_numeric($_REQUEST['Id'])) + { + $template_id = $_REQUEST['Id']; + + $ok = true; + + $check_code = strtolower($_REQUEST['template_text']); + + if (is_php_code($check_code) && ! check_permission('template_php')) + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_PHP') . ' (' . stripslashes($_REQUEST['template_title']) . ')'); + + $AVE_Template->assign('php_forbidden', 1); + + $ok = false; + + $message = $AVE_Template->get_config_vars('TEMPLATES_REPORT_PHP_ERR'); + $header = $AVE_Template->get_config_vars('TEMPLATES_ERROR'); + $theme = 'error'; + } + + if ($ok === false) + { + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + else + { + $row->template_text = stripslashes($_REQUEST['template_text']); + $AVE_Template->assign('row', $row); + } + } + else + { + $sql = $AVE_DB->Query(" + UPDATE + " . PREFIX . "_templates + SET + template_title = '" . $_REQUEST['template_title'] . "', + template_text = '" . addslashes(pretty_chars($_REQUEST['template_text'])) . "' + WHERE + Id = '" . $template_id . "' + "); + + if ($sql === false) + { + $message = $AVE_Template->get_config_vars('TEMPLATES_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('TEMPLATES_ERROR'); + $theme = 'error'; + } + else + { + // Сохраняем шаблон в файле + self::setTemplate($template_id); + + $message = $AVE_Template->get_config_vars('TEMPLATES_SAVED'); + $header = $AVE_Template->get_config_vars('TEMPLATES_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_CHANGE') . ' - (' . stripslashes($_REQUEST['template_title']) . ')'); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=templates&cp=' . SESSION); + } + exit; + } + } + else + { + $save = true; + + $errors = array(); + + $row = new stdClass(); + + $row->template_text = pretty_chars($_REQUEST['template_text']); + $row->template_text = stripslashes($row->template_text); + $row->template_title = stripslashes($_REQUEST['template_title']); + + if (empty($_REQUEST['template_title'])) + { + $save = false; + $errors[] = $AVE_Template->get_config_vars('TEMPLATES_REPORT_ERROR_TITLE'); + } + + if (empty($_REQUEST['template_text'])) + { + $save = false; + $errors[] = $AVE_Template->get_config_vars('TEMPLATES_REPORT_ERROR_TEXT'); + } + + $check_code = strtolower($_REQUEST['template_text']); + + if (is_php_code($check_code) && !check_permission('template_php')) + { + $AVE_Template->assign('php_forbidden', 1); + $save = false; + } + + if ($save === false) + { + $AVE_Template->assign('row', $row); + $AVE_Template->assign('errors', $errors); + $AVE_Template->assign('content', $AVE_Template->fetch('templates/form.tpl')); + } + else + { + $sql = $AVE_DB->Query(" + INSERT + INTO + " . PREFIX . "_templates + SET + Id = '', + template_title = '" . $_REQUEST['template_title'] . "', + template_text = '" . addslashes(pretty_chars($_REQUEST['template_text'])) . "', + template_author_id = '" . $_SESSION['user_id'] . "', + template_created = '" . time() . "' + "); + + $template_id = $AVE_DB->InsertId(); + + // Сохраняем шаблон в файле + self::setTemplate($template_id); + + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_NEW') . '(' . stripslashes(htmlspecialchars($_REQUEST['template_text'], ENT_QUOTES)) . ') (Id:' . (int)$iid . ')'); + + if (! $_REQUEST['next_edit']) + header('Location:index.php?do=templates&cp=' . SESSION); + else + header('Location:index.php?do=templates&action=edit&Id=' . (int)$template_new . '&cp=' . SESSION); + + exit; + } + } + + } + + +public static function templatesDelete() +{ + global $AVE_DB, $AVE_Template; + + $template_id = (int)($_REQUEST['Id'] ?? 0); + + // Проверка использования шаблона + $Used = $AVE_DB->Query(" + SELECT rubric_template_id + FROM " . PREFIX . "_rubrics + WHERE rubric_template_id = '" . $template_id . "' + ")->GetCell(); + + if ($Used >= 1 || $template_id == 1) { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_ID_ERR') . ' - (' . templateName($template_id) . ')'); + header('Location:index.php?do=templates'); + exit; + } else { + $template_name = templateName($template_id); + + // Удаляем запись из базы + $AVE_DB->Query(" + DELETE FROM " . PREFIX . "_templates + WHERE Id = '" . $template_id . "' + "); + + // Удаляем кеш-файл шаблона + $cache_file = BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/include/templates/' . $template_id . '/template.inc'; + + if (file_exists($cache_file)) { + @unlink($cache_file); + // Если хотите, можно логировать успешное удаление + reportLog("Cache file deleted: " . $cache_file); + } + + // Можно также удалить пустую папку, если нужно + $cache_dir = dirname($cache_file); + if (is_dir($cache_dir) && count(scandir($cache_dir)) == 2) { // только . и .. + @rmdir($cache_dir); + } + + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_DELETE') . ' - (' . $template_name . ')'); + + header('Location:index.php?do=templates'); + exit; + } +} + + + + public static function templatesMulti() + { + global $AVE_DB, $AVE_Template; + + $ok = true; + + $errors = array(); + + $template_text = $AVE_DB->Query(" + SELECT + template_text + FROM + " . PREFIX . "_templates + WHERE + Id = '" . (int)$_REQUEST['Id'] . "' + ")->GetCell(); + + $template_title = $AVE_DB->Query(" + SELECT + template_title + FROM + " . PREFIX . "_templates + WHERE + template_title = '" . $_REQUEST['template_title'] . "' + ")->GetCell(); + + if ($template_title != '') + { + array_push($errors, $AVE_Template->get_config_vars('TEMPLATES_EXIST')); + + $AVE_Template->assign('errors', $errors); + + $ok = false; + } + + if ($_REQUEST['template_title'] == '') + { + array_push($errors, $AVE_Template->get_config_vars('TEMPLATES_NO_NAME')); + + $AVE_Template->assign('errors', $errors); + + $ok = false; + } + + if ($ok) + { + $AVE_DB->Query(" + INSERT + INTO + " . PREFIX . "_templates + SET + Id = '', + template_title = '" . $_REQUEST['template_title'] . "', + template_text = '" . addslashes($template_text) . "', + template_author_id = '" . $_SESSION['user_id'] . "', + template_created = '" . time() . "' + "); + + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_COPY') . ' - (' . $_REQUEST['template_title'].' - '.templateName((int)$_REQUEST['Id']) . ')'); + + header('Location:index.php?do=templates'.'&cp=' . SESSION); + exit; + } + + $row = new stdClass(); + + $row->template_text = pretty_chars($template_text); + $row->template_text = stripslashes($template_text); + $row->template_title = stripslashes($_REQUEST['template_title']); + + $AVE_Template->assign('row', $row); + $AVE_Template->assign('content', $AVE_Template->fetch('templates/form.tpl')); + } + + + public static function templatesEditCss() + { + global $AVE_Template; + + $_REQUEST['sub'] = (! isset($_REQUEST['sub'])) + ? '' + : $_REQUEST['sub']; + + switch ($_REQUEST['sub']) + { + + case 'save': + $dir = BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/css/' . $_REQUEST['name_file']; + + $check_code = stripcslashes($_REQUEST['code_text']); + + if (is_php_code($check_code)) + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_PHP_CSS') . ' - (' . stripslashes($_REQUEST['name_file']) . ')'); + + $message = $AVE_Template->get_config_vars('TEMPLATES_REPORT_PHP_ERR'); + $header = $AVE_Template->get_config_vars('TEMPLATES_ERROR'); + $theme = 'error'; + + if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] = '1') { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + + header('Location:index.php?do=templates'); + exit; + } + + $result = file_put_contents($dir, trim($check_code)); + + if ($result === false) + { + $message = $AVE_Template->get_config_vars('TEMPLATES_SAVED_ERR_FILE'); + $header = $AVE_Template->get_config_vars('TEMPLATES_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('TEMPLATES_SAVED_FILE'); + $header = $AVE_Template->get_config_vars('TEMPLATES_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_FILE') . ' - (' . stripslashes($dir) . ')'); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=templates&cp=' . SESSION); + } + + exit; + + case 'delete': + + $file = BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/css/'. $_REQUEST['name_file']; + + if (! is_file($file)) + return false; + + if (@unlink($file)) + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_DEL_OK') . ' ('.basename($_REQUEST['name_file']).')'); + } + else + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_DEL_ER') . ' ('.basename($_REQUEST['name_file']).')'); + } + + header('Location:index.php?do=templates&cp=' . SESSION); + exit; + + default: + $dir = BASE_DIR.'/templates/'.DEFAULT_THEME_FOLDER.'/css/'.stripslashes($_REQUEST['name_file']); + $code_text = file_get_contents($dir); + $formaction = "index.php?do=templates&action=edit_css&sub=save&name_file=".stripslashes($_REQUEST['name_file']); + $AVE_Template->assign('formaction', $formaction); + $AVE_Template->assign('code_text', $code_text); + break; + } + + $AVE_Template->assign('content', $AVE_Template->fetch('templates/edit_css.tpl')); + } + + + public static function templatesEditJs() + { + global $AVE_Template; + + $_REQUEST['sub'] = (! isset($_REQUEST['sub'])) + ? '' + : $_REQUEST['sub']; + + switch ($_REQUEST['sub']) + { + case 'save': + $dir = BASE_DIR.'/templates/'.DEFAULT_THEME_FOLDER.'/js/'.$_REQUEST['name_file']; + + $check_code = stripcslashes($_REQUEST['code_text']); + + if (is_php_code($check_code)) + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_PHP_JS') . ' - (' . stripslashes($_REQUEST['name_file']) . ')'); + + $message = $AVE_Template->get_config_vars('TEMPLATES_REPORT_PHP_ERR'); + $header = $AVE_Template->get_config_vars('TEMPLATES_ERROR'); + $theme = 'error'; + + if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] = '1') { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + exit; + } + + header('Location:index.php?do=templates'); + exit; + } + + $result = file_put_contents($dir, trim($check_code)); + + if ($result === false) + { + $message = $AVE_Template->get_config_vars('TEMPLATES_SAVED_ERR_FILE'); + $header = $AVE_Template->get_config_vars('TEMPLATES_ERROR'); + $theme = 'error'; + } + else + { + $message = $AVE_Template->get_config_vars('TEMPLATES_SAVED_FILE'); + $header = $AVE_Template->get_config_vars('TEMPLATES_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_FILE') . ' - (' . stripslashes($dir) . ')'); + } + + if (isAjax()) + { + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } + else + { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=templates&cp=' . SESSION); + } + exit; + + case 'delete': + + $file = BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/js/'. $_REQUEST['name_file']; + + if (! is_file($file)) + return false; + + if (@unlink($file)) + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_DEL_OK') . ' ('.basename($_REQUEST['name_file']).')'); + } + else + { + reportLog($AVE_Template->get_config_vars('TEMPLATES_REPORT_DEL_ER') . ' ('.basename($_REQUEST['name_file']).')'); + } + + header('Location:index.php?do=templates&cp=' . SESSION); + exit; + + + default: + $dir = BASE_DIR.'/templates/'.DEFAULT_THEME_FOLDER.'/js/'.stripslashes($_REQUEST['name_file']); + $code_text = file_get_contents($dir); + $formaction = "index.php?do=templates&action=edit_js&sub=save&name_file=".stripslashes($_REQUEST['name_file']); + $AVE_Template->assign('formaction', $formaction); + $AVE_Template->assign('code_text', $code_text); + break; + } + + $AVE_Template->assign('content', $AVE_Template->fetch('templates/edit_js.tpl')); + } + } +?> \ No newline at end of file diff --git a/class/class.thumbnail.php b/class/class.thumbnail.php new file mode 100644 index 0000000..cbefe01 --- /dev/null +++ b/class/class.thumbnail.php @@ -0,0 +1,1901 @@ + + * + */ + + + if (! defined('IMAGE_TOOLBOX_DEFAULT_PNG_QUALITY')) + define('IMAGE_TOOLBOX_DEFAULT_PNG_QUALITY', 3); + + if (! defined('IMAGE_TOOLBOX_DEFAULT_WEBP_QUALITY')) + define('IMAGE_TOOLBOX_DEFAULT_WEBP_QUALITY', 100); + + if (! defined('IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY')) + define('IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY', 90); + + if (! defined('IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS')) + define('IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS', 256); + + if (! defined('IMAGE_TOOLBOX_BIAS_HORIZONTAL')) + define('IMAGE_TOOLBOX_BIAS_HORIZONTAL', 1); + + if (! defined('IMAGE_TOOLBOX_BIAS_VERTICAL')) + define('IMAGE_TOOLBOX_BIAS_VERTICAL', 0); + + if (! defined('IMAGE_TOOLBOX_BLEND_COPY')) + define('IMAGE_TOOLBOX_BLEND_COPY', 1); + + if (! defined('IMAGE_TOOLBOX_BLEND_MULTIPLY')) + define('IMAGE_TOOLBOX_BLEND_MULTIPLY', 2); + + if (! defined('IMAGE_TOOLBOX_BLEND_SCREEN')) + define('IMAGE_TOOLBOX_BLEND_SCREEN', 3); + + if (! defined('IMAGE_TOOLBOX_BLEND_DIFFERENCE')) + define('IMAGE_TOOLBOX_BLEND_DIFFERENCE', 4); + + if (! defined('IMAGE_TOOLBOX_BLEND_NEGATION')) + define('IMAGE_TOOLBOX_BLEND_NEGATION', 5); + + if (! defined('IMAGE_TOOLBOX_BLEND_EXCLUSION')) + define('IMAGE_TOOLBOX_BLEND_EXCLUSION', 6); + + if (! defined('IMAGE_TOOLBOX_BLEND_OVERLAY')) + define('IMAGE_TOOLBOX_BLEND_OVERLAY', 7); + + /** + * PHP image manipulation class + * + * This class provides an easy to use library to the PHP GD-based imagefunctions + */ + class Image_Toolbox + { + /** + * The prefix for every error message + * + * @access private + * @var string + */ + public $_error_prefix = 'Image: '; + + + /** + * Defines imagetypes and how they are supported by the server + * + * @access private + * @var array + */ + public $_types = array ( + 1 => array ( + 'ext' => 'gif', + 'mime' => 'image/gif', + 'supported' => 0 + ), + 2 => array ( + 'ext' => 'jpg', + 'mime' => 'image/jpeg', + 'supported' => 0 + ), + 3 => array ( + 'ext' => 'png', + 'mime' => 'image/png', + 'supported' => 0 + ), + 18 => array ( + 'ext' => 'webp', + 'mime' => 'image/webp', + 'supported' => 0 + ) + ); + + + /** + * Which PHP image resize function to be used + * imagecopyresampled only supported with GD >= 2.0 + * + * @access private + * @var string + */ + public $_resize_function = 'imagecopyresampled'; + + + /** + * Stores all image resource data + * + * @access private + * @var array + */ + public $_img = array ( + 'main' => array ( + 'resource' => 0, + 'width' => 0, + 'height' => 0, + 'bias' => 0, + 'aspectratio' => 0, + 'type' => 0, + 'output_type' => 0, + 'indexedcolors' => 0, + 'color' => -1 + ) + ); + + + /** + * Which PHP image create function to be used + * imagecreatetruecolor only supported with GD >= 2.0 + * + * @access private + * @var string + */ + public $_imagecreatefunction = ''; + + + /** + * The class constructor. + * + * Determines the image features of the server and sets the according values.
      + * Additionally you can specify a image to be created/loaded. like {@link addImage() addImage}. + * + * If no parameter is given, no image resource will be generated
      + * Or:
      + * string $file imagefile to load
      + * Or:
      + * integer $width imagewidth of new image to be created
      + * integer $height imageheight of new image to be created
      + * string $fillcolor optional fill the new image with this color (hexformat, e.g. '#FF0000')
      + */ + function __construct() + { + $args = func_get_args(); + $argc = func_num_args(); + + //get GD information. see what types we can handle + $gd_info = function_exists('gd_info') + ? gd_info() + : $this->_gd_info(); + + preg_match('/\A[\D]*([\d+\.]*)[\D]*\Z/', $gd_info['GD Version'], $matches); + + list($this->_gd_version_string, $this->_gd_version_number) = $matches; + + $this->_gd_version = substr($this->_gd_version_number, 0, strpos($this->_gd_version_number, '.')); + + if ($this->_gd_version >= 2) + { + $this->_imagecreatefunction = 'imagecreatetruecolor'; + $this->_resize_function = 'imagecopyresampled'; + } + else + { + $this->_imagecreatefunction = 'imagecreate'; + $this->_resize_function = 'imagecopyresized'; + } + + $this->_gd_ttf = $gd_info['FreeType Support']; + $this->_gd_ps = isset($gd_info['T1Lib Support']) ? $gd_info['T1Lib Support'] : false; + + if ($gd_info['GIF Read Support']) + { + $this->_types[1]['supported'] = 1; + + if ($gd_info['GIF Create Support']) + $this->_types[1]['supported'] = 2; + } + + if ((isset($gd_info['JPG Support']) && $gd_info['JPG Support']) || (isset($gd_info['JPEG Support']) && $gd_info['JPEG Support'])) + $this->_types[2]['supported'] = 2; + + if ($gd_info['PNG Support']) + $this->_types[3]['supported'] = 2; + + if ($gd_info['WebP Support']) + $this->_types[18]['supported'] = 2; + + //load or create main image + if ($argc == 0) + { + return true; + } + else + { + if ($this->_addImage($argc, $args)) + { + foreach ($this->_img['operator'] as $key => $value) + $this->_img['main'][$key] = $value; + + $this->_img['main']['output_type'] = $this->_img['main']['type']; + + unset($this->_img['operator']); + + return true; + } + else + { + trigger_error($this->_error_prefix . 'No appropriate constructor found.', E_USER_ERROR); + return null; + } + } + } + + + /** + * Returns an assocative array with information about the image features of this server + * + * Array values: + *
        + *
      • 'gd_version' -> what GD version is installed on this server (e.g. 2.0)
      • + *
      • 'gif' -> 0 = not supported, 1 = reading is supported, 2 = creating is supported
      • + *
      • 'jpg' -> 0 = not supported, 1 = reading is supported, 2 = creating is supported
      • + *
      • 'png' -> 0 = not supported, 1 = reading is supported, 2 = creating is supported
      • + *
      • 'ttf' -> TTF text creation. true = supported, false = not supported + *
      + * + * @return array + */ + function getServerFeatures() + { + $features = array(); + $features['gd_version'] = $this->_gd_version_number; + $features['gif'] = $this->_types[1]['supported']; + $features['jpg'] = $this->_types[2]['supported']; + $features['png'] = $this->_types[3]['supported']; + $features['webp'] = $this->_types[18]['supported']; + $features['ttf'] = $this->_gd_ttf; + + return $features; + } + + + /** + * Flush all image resources and init a new one + * + * Parameter:
      + * string $file imagefile to load
      + * Or:
      + * integer $width imagewidth of new image to be created
      + * integer $height imageheight of new image to be created
      + * string $fillcolor optional fill the new image with this color (hexformat, e.g. '#FF0000')
      + */ + function newImage() + { + $args = func_get_args(); + $argc = func_num_args(); + + if ($this->_addImage($argc, $args)) + { + foreach ($this->_img['operator'] as $key => $value) + $this->_img['main'][$key] = $value; + + $this->_img['main']['output_type'] = $this->_img['main']['type']; + + unset($this->_img['operator']); + + return true; + } + else + { + trigger_error($this->_error_prefix . 'No appropriate constructor found.', E_USER_ERROR); + + return null; + } + } + + + /** + * Reimplements the original PHP {@link gd_info()} function for older PHP versions + * + * @access private + * @return array associative array with info about the GD library of the server + */ + function _gd_info() + { + $array = array( + 'GD Version' => '', + 'FreeType Support' => false, + 'FreeType Linkage' => '', + 'T1Lib Support' => false, + 'GIF Read Support' => false, + 'GIF Create Support' => false, + 'JPG Support' => false, + 'PNG Support' => false, + 'WebP Support' => false, + 'WBMP Support' => false, + 'XBM Support' => false + ); + + $gif_support = 0; + + ob_start(); + + eval('phpinfo();'); + + $info = ob_get_contents(); + + ob_end_clean(); + + foreach(explode('\n', $info) as $line) + { + if (strpos($line, 'GD Version') !== false) + $array['GD Version'] = trim(str_replace('GD Version', '', strip_tags($line))); + + if (strpos($line, 'FreeType Support') !== false) + $array['FreeType Support'] = trim(str_replace('FreeType Support', '', strip_tags($line))); + + if (strpos($line, 'FreeType Linkage') !== false) + $array['FreeType Linkage'] = trim(str_replace('FreeType Linkage', '', strip_tags($line))); + + if (strpos($line, 'T1Lib Support') !== false) + $array['T1Lib Support'] = trim(str_replace('T1Lib Support', '', strip_tags($line))); + + if (strpos($line, 'GIF Read Support') !== false) + $array['GIF Read Support'] = trim(str_replace('GIF Read Support', '', strip_tags($line))); + + if (strpos($line, 'GIF Create Support') !== false) + $array['GIF Create Support'] = trim(str_replace('GIF Create Support', '', strip_tags($line))); + + if (strpos($line, 'GIF Support') !== false) + $gif_support = trim(str_replace('GIF Support', '', strip_tags($line))); + + if (strpos($line, 'JPG Support') !== false) + $array['JPG Support'] = trim(str_replace('JPG Support', '', strip_tags($line))); + + if (strpos($line, 'PNG Support') !== false) + $array['PNG Support'] = trim(str_replace('PNG Support', '', strip_tags($line))); + + if (strpos($line, 'WebP Support') !== false) + $array['WebP Support'] = trim(str_replace('WebP Support', '', strip_tags($line))); + + if (strpos($line, 'WBMP Support') !== false) + $array['WBMP Support'] = trim(str_replace('WBMP Support', '', strip_tags($line))); + + if (strpos($line, 'XBM Support') !== false) + $array['XBM Support'] = trim(str_replace('XBM Support', '', strip_tags($line))); + } + + if ($gif_support === 'enabled') + { + $array['GIF Read Support'] = true; + $array['GIF Create Support'] = true; + } + + if ($array['FreeType Support'] === 'enabled') + { + $array['FreeType Support'] = true; + } + + if ($array['T1Lib Support'] === 'enabled') + { + $array['T1Lib Support'] = true; + } + + if ($array['GIF Read Support'] === 'enabled') + { + $array['GIF Read Support'] = true; + } + + if ($array['GIF Create Support'] === 'enabled') + { + $array['GIF Create Support'] = true; + } + + if ($array['JPG Support'] === 'enabled') + { + $array['JPG Support'] = true; + } + + if ($array['PNG Support'] === 'enabled') + { + $array['PNG Support'] = true; + } + + if ($array['WebP Support'] === 'enabled') + { + $array['WebP Support'] = true; + } + + if ($array['WBMP Support'] === 'enabled') + { + $array['WBMP Support'] = true; + } + + if ($array['XBM Support'] === 'enabled') + { + $array['XBM Support'] = true; + } + + return $array; + } + + + /** + * Convert a color defined in hexvalues to the PHP color format + * + * @access private + * @param string $hex color value in hexformat (e.g. '#FF0000') + * @return integer color value in PHP format + */ + function _hexToPHPColor($hex) + { + $length = strlen($hex); + $dr = hexdec(substr($hex, $length - 6, 2)); + $dg = hexdec(substr($hex, $length - 4, 2)); + $db = hexdec(substr($hex, $length - 2, 2)); + $color = ($dr << 16) + ($dg << 8) + $db; + + return $color; + } + + + /** + * Convert a color defined in hexvalues to corresponding dezimal values + * + * @access private + * @param string $hex color value in hexformat (e.g. '#FF0000') + * @return array associative array with color values in dezimal format (fields: 'red', 'green', 'blue') + */ + function _hexToDecColor($hex) + { + $length = strlen($hex); + $color['red'] = hexdec(substr($hex, $length - 6, 2)); + $color['green'] = hexdec(substr($hex, $length - 4, 2)); + $color['blue'] = hexdec(substr($hex, $length - 2, 2)); + + return $color; + } + + + /** + * Generate a new image resource based on the given parameters + * + * Parameter: + * string $file imagefile to load
      + * Or:
      + * integer $width imagewidth of new image to be created
      + * integer $height imageheight of new image to be created
      + * string $fillcolor optional fill the new image with this color (hexformat, e.g. '#FF0000')
      + * + * @access private + */ + function _addImage($argc, $args) + { + if (($argc == 2 || $argc == 3) && is_int($args[0]) && is_int($args[1]) && (is_string($args[2]) || ! isset($args[2]))) + { + //neues leeres bild mit width und height (fillcolor optional) + $this->_img['operator']['width'] = $args[0]; + $this->_img['operator']['height'] = $args[1]; + + ($this->_img['operator']['width'] >= $this->_img['operator']['height']) + ? ($this->_img['operator']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) + : ($this->_img['operator']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL); + + $this->_img['operator']['aspectratio'] = $this->_img['operator']['width'] / $this->_img['operator']['height']; + + $this->_img['operator']['indexedcolors'] = 0; + + $functionname = $this->_imagecreatefunction; + + $this->_img['operator']['resource'] = $functionname($this->_img['operator']['width'], $this->_img['operator']['height']); + + // set default type jpg. + $this->_img['operator']['type'] = 2; + + if (isset($args[2]) && is_string($args[2])) + { + //neues bild mit farbe fЃllen + $fillcolor = $this->_hexToPHPColor($args[2]); + + imagefill($this->_img['operator']['resource'], 0, 0, $fillcolor); + + $this->_img['operator']['color'] = $fillcolor; + } + else + { + $this->_img['operator']['color'] = 0; + } + } + elseif ($argc == 1 && is_string($args[0])) + { + //bild aus datei laden. width und height original gr”sse + $this->_img['operator'] = $this->_loadFile($args[0]); + + $this->_img['operator']['indexedcolors'] = imagecolorstotal($this->_img['operator']['resource']); + + $this->_img['operator']['color'] = -1; + } + else + { + return false; + } + + return true; + } + + /** + * Loads a image file + * + * @access private + * @param string $filename imagefile to load + * @return array associative array with the loaded filedata + */ + function _loadFile($filename) + { + if (file_exists($filename)) + { + $info = getimagesize($filename); + + $filedata['width'] = $info[0]; + + $filedata['height'] = $info[1]; + + ($filedata['width'] >= $filedata['height']) + ? ($filedata['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) + : ($filedata['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL); + + $filedata['aspectratio'] = $filedata['width'] / $filedata['height']; + $filedata['type'] = $info[2]; + + if ($this->_types[$filedata['type']]['supported'] < 1) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$filedata['type']]['ext'].') not supported for reading.', E_USER_ERROR); + return null; + } + + switch ($filedata['type']) + { + case 1: + $dummy = imagecreatefromgif($filename); + $functionname = $this->_imagecreatefunction; + $filedata['resource'] = $functionname($filedata['width'], $filedata['height']); + imagecopy($filedata['resource'], $dummy, 0, 0, 0, 0, $filedata['width'], $filedata['height']); + imagedestroy($dummy); + break; + + case 2: + $filedata['resource'] = imagecreatefromjpeg($filename); + break; + + case 3: + $dummy = imagecreatefrompng($filename); + + if (imagecolorstotal($dummy) != 0) + { + $functionname = $this->_imagecreatefunction; + $filedata['resource'] = $functionname($filedata['width'], $filedata['height']); + imagecopy($filedata['resource'], $dummy, 0, 0, 0, 0, $filedata['width'], $filedata['height']); + } + else + { + $filedata['resource'] = $dummy; + } + unset($dummy); + break; + + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 15: + case 16: + case 17: + case 18: + $dummy = imagecreatefromwebp($filename); + + if (imagecolorstotal($dummy) != 0) + { + $functionname = $this->_imagecreatefunction; + $filedata['resource'] = $functionname($filedata['width'], $filedata['height']); + imagecopy($filedata['resource'], $dummy, 0, 0, 0, 0, $filedata['width'], $filedata['height']); + } + else + { + $filedata['resource'] = $dummy; + } + unset($dummy); + break; + + default: + trigger_error($this->_error_prefix . 'Imagetype not supported.', E_USER_ERROR); + return null; + } + return $filedata; + } + else + { + trigger_error($this->_error_prefix . 'Imagefile (' . $filename . ') does not exist.', E_USER_ERROR); + return null; + } + } + + + /** + * Output a image to the browser + * + * $output_type can be one of the following:
      + *
        + *
      • 'gif' -> gif image (if supported) (8-bit indexed colors)
      • + *
      • 'png' -> png image (if supported) (truecolor)
      • + *
      • 'png8' -> png image (if supported) (8-bit indexed colors)
      • + *
      • 'jpg' -> jpeg image (if supported) (truecolor)
      • + *
      + * (default: same as original) + * + * $dither:
      + * If this is true than dither is used on the conversion from truecolor to 8-bit indexed imageformats (png8, gif)
      + * (default = false) + * + * @param string|integer $output_type type of outputted image + * @param integer $output_quality jpeg quality of outputted image (default: IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY) + * @param bool $dither use dither + * @return bool true on success, otherwise false + */ + function output($output_type = false, $output_quality = false, $dither = false) + { + if ($output_type === false) + $output_type = $this->_img['main']['output_type']; + + switch ($output_type) + { + case 1: + case 'gif': + case 'GIF': + if ($this->_types[1]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + header ('Content-type: ' . $this->_types[$output_type]['mime']); + + if ($this->_gd_version >= 2) + { + if ($this->_img['main']['indexedcolors'] == 0) + { + $dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']); + imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']); + + if ($output_quality === false) + { + $output_quality = IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS; + } + + imagetruecolortopalette($dummy, $dither, $output_quality); + } + imagegif($dummy); + imagedestroy($dummy); + } + else + { + imagegif($this->_img['main']['resource']); + } + break; + + case 2: + case '2': + case 'jpg': + case 'jpeg': + case 'JPG': + case 'JPEG': + if ($this->_types[2]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + header ('Content-type: ' . $this->_types[$output_type]['mime']); + + if ($output_quality === false) + { + $output_quality = IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY; + } + + imagejpeg($this->_img['main']['resource'], null, $output_quality); + break; + + case 3: + case '3': + case 'png': + case 'PNG': + case 'png24': + case 'PNG24': + if ($this->_types[3]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + header ('Content-type: ' . $this->_types[$output_type]['mime']); + + if (version_compare(PHP_VERSION, '5.1.2', '>=')) + { + if ($output_quality === false) + { + $output_quality = IMAGE_TOOLBOX_DEFAULT_PNG_QUALITY; + } + + imagepng($this->_img['main']['resource'], null, $output_quality); + } + else + { + imagepng($this->_img['main']['resource']); + } + break; + + case 4: + case '4': + case 'png8': + case 'PNG8': + if ($this->_types[3]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + header ('Content-type: ' . $this->_types[$output_type]['mime']); + + if ($this->_gd_version >= 2) + { + if ($this->_img['main']['indexedcolors'] == 0) + { + $dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']); + + imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']); + + imagetruecolortopalette($dummy, $dither, 255); + } + + if (version_compare(PHP_VERSION, '5.1.2', '>=')) + { + if ($output_quality === false) + { + $output_quality = IMAGE_TOOLBOX_DEFAULT_PNG_QUALITY; + } + + imagepng($dummy, null, $output_quality); + } + else + { + imagepng($dummy); + } + + imagedestroy($dummy); + } + else + { + imagepng($this->_img['main']['resource']); + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 15: + case 16: + case 17: + case 18: + case '18': + case 'webp': + case 'WebP': + case 'WEBP': + if ($this->_types[18]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + header ('Content-type: ' . $this->_types[$output_type]['mime']); + + if (version_compare(PHP_VERSION, '5.1.2', '>=')) + { + if ($output_quality === false) + { + $output_quality = IMAGE_TOOLBOX_DEFAULT_WEBP_QUALITY; + } + + imagewebp($this->_img['main']['resource'], null, $output_quality); + } + else + { + imagewebp($this->_img['main']['resource']); + } + break; + + default: + trigger_error($this->_error_prefix . 'Output-Imagetype not supported.', E_USER_ERROR); + return null; + } + return true; + } + + + /** + * Save a image to disk + * + * $output_type can be one of the following:
      + *
        + *
      • 'gif' -> gif image (if supported) (8-bit indexed colors)
      • + *
      • 'png' -> png image (if supported) (truecolor)
      • + *
      • 'png8' -> png image (if supported) (8-bit indexed colors)
      • + *
      • 'jpg' -> jpeg image (if supported) (truecolor)
      • + *
      + * (default: same as original) + * + * $dither:
      + * If this is true than dither is used on the conversion from truecolor to 8-bit indexed imageformats (png8, gif)
      + * (default = false) + * + * @param string $filename filename of saved image + * @param string|integer $output_type type of saved image + * @param integer $output_quality jpeg quality of saved image (default: IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY) + * @param bool $dither use dither + * @return bool true on success, otherwise false + */ + function save ($filename, $output_type = false, $output_quality = false, $dither = false) + { + if ($output_type === false) + $output_type = $this->_img['main']['output_type']; + switch ($output_type) + { + case 1: + case '1': + case 'gif': + case 'GIF': + if ($this->_types[1]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + if ($this->_gd_version >= 2) + { + if ($this->_img['main']['indexedcolors'] == 0) + { + $dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']); + imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']); + + if ($output_quality === false) + $output_quality = IMAGE_TOOLBOX_DEFAULT_8BIT_COLORS; + + imagetruecolortopalette($dummy, $dither, $output_quality); + } + + imagegif($dummy, $filename); + imagedestroy($dummy); + } + else + { + imagegif($this->_img['main']['resource']); + } + break; + + case 2: + case '2': + case 'jpg': + case 'jpeg': + case 'JPG': + case 'JPEG': + if ($this->_types[2]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + if ($output_quality === false) + $output_quality = IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY; + + if (defined('JPG_PROGRESSIVE') && JPG_PROGRESSIVE == true) + imageinterlace($this->_img['main']['resource'], 1); + + imagejpeg($this->_img['main']['resource'], $filename, $output_quality); + + break; + + case 3: + case '3': + case 'png': + case 'PNG': + case 'png24': + case 'PNG24': + if ($this->_types[3]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + if (version_compare(PHP_VERSION, '5.1.2', '>=')) + { + if ($output_quality === false) + $output_quality = IMAGE_TOOLBOX_DEFAULT_PNG_QUALITY; + + imagepng($this->_img['main']['resource'], $filename, $output_quality); + } + else + { + imagepng($this->_img['main']['resource'], $filename); + } + break; + + case 4: + case '4': + case 'png8': + case 'PNG8': + if ($this->_types[3]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + if ($this->_gd_version >= 2) + { + if ($this->_img['main']['indexedcolors'] == 0) + { + $dummy = imagecreatetruecolor($this->_img['main']['width'], $this->_img['main']['height']); + imagecopy($dummy, $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']); + imagetruecolortopalette($dummy, $dither, 255); + } + + if (version_compare(PHP_VERSION, '5.1.2', '>=')) + { + if ($output_quality === false) + $output_quality = IMAGE_TOOLBOX_DEFAULT_PNG_QUALITY; + + imagepng($dummy, $filename, $output_quality); + } + else + { + imagepng($dummy, $filename); + } + imagedestroy($dummy); + } + else + { + imagepng($this->_img['main']['resource'], $filename); + } + break; + + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 15: + case 16: + case 17: + case 18: + case '18': + case 'webp': + case 'WebP': + case 'WEBP': + if ($this->_types[18]['supported'] < 2) + { + trigger_error($this->_error_prefix . 'Imagetype ('.$this->_types[$output_type]['ext'].') not supported for creating/writing.', E_USER_ERROR); + return null; + } + + if (version_compare(PHP_VERSION, '5.1.2', '>=')) + { + if ($output_quality === false) + $output_quality = IMAGE_TOOLBOX_DEFAULT_WEBP_QUALITY; + + imagewebp($this->_img['main']['resource'], $filename, $output_quality); + } + else + { + imagewebp($this->_img['main']['resource'], $filename); + } + break; + + default: + trigger_error($this->_error_prefix . 'Output-Imagetype not supported.', E_USER_ERROR); + return null; + } + + return true; + } + + + /** + * Sets the resize method of choice + * + * $method can be one of the following:
      + *
        + *
      • 'resize' -> supported by every version of GD (fast but ugly resize of image)
      • + *
      • 'resample' -> only supported by GD version >= 2.0 (slower but antialiased resize of image)
      • + *
      + * + * @param string|integer $method resize method + * @return bool true on success, otherwise false + */ + function setResizeMethod($method) + { + switch ($method) + { + case 1: + case '1': + case 'resize': + $this->_resize_function = 'imagecopyresized'; + break; + + case 2: + case '2': + case 'resample': + if (! function_exists('imagecopyresampled')) + // no error message. just return false. + return null; + + $this->_resize_function = 'imagecopyresampled'; + break; + + default: + trigger_error($this->_error_prefix . 'Resizemethod not supported.', E_USER_ERROR); + return null; + } + + return true; + } + + + /** + * Resize the current image + * + * if $width = 0 the new width will be calculated from the $height value preserving the correct aspectratio.
      + * + * if $height = 0 the new height will be calculated from the $width value preserving the correct aspectratio.
      + * + * $mode can be one of the following:
      + *
        + *
      • 0 -> image will be resized to the new output size, regardless of the original aspectratio. (default)
      • + *
      • 1 -> image will be cropped if necessary to preserve the aspectratio and avoid image distortions.
      • + *
      • 2 -> image will be resized preserving its original aspectratio. differences to the new outputsize will be filled with $bgcolor
      • + *
      + * + * if $autorotate is set to true the given $width and $height values may "change place" if the given image bias is different from the original one.
      + * if either $width or $height is 0, the new size will be applied to either the new width or the new height based on the bias value of the original image.
      + * (default = false) + * + * @param integer $width new width of image + * @param integer $height new height of image + * @param integer $mode resize mode + * @param bool $autorotate use autorotating + * @param string $bgcolor background fillcolor (hexformat, e.g. '#FF0000') + * @return bool true on success, otherwise false + */ + function newOutputSize($width, $height, $mode = 0, $autorotate = false, $bgcolor = '#000000') + { + if ($width > 0 && $height > 0 && is_int($width) && is_int($height)) + { + // ignore aspectratio + if (! $mode) + { + // do not crop to get correct aspectratio + ($width >= $height) + ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) + : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL); + + if ($this->_img['main']['bias'] == $this->_img['target']['bias'] || !$autorotate) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = $height; + } + else + { + $this->_img['target']['width'] = $height; + $this->_img['target']['height'] = $width; + } + + $this->_img['target']['aspectratio'] = $this->_img['target']['width'] / $this->_img['target']['height']; + + $cpy_w = $this->_img['main']['width']; + $cpy_h = $this->_img['main']['height']; + $cpy_w_offset = 0; + $cpy_h_offset = 0; + } + // crop to get correct aspectratio + elseif ($mode == 1) + { + //crop to get correct aspectratio + ($width >= $height) + ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) + : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL); + + if ($this->_img['main']['bias'] == $this->_img['target']['bias'] || !$autorotate) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = $height; + } + else + { + $this->_img['target']['width'] = $height; + $this->_img['target']['height'] = $width; + } + + $this->_img['target']['aspectratio'] = $this->_img['target']['width'] / $this->_img['target']['height']; + + if ($this->_img['main']['width'] / $this->_img['target']['width'] >= $this->_img['main']['height'] / $this->_img['target']['height']) + { + $cpy_h = $this->_img['main']['height']; + $cpy_w = (integer) $this->_img['main']['height'] * $this->_img['target']['aspectratio']; + $cpy_w_offset = (integer) ($this->_img['main']['width'] - $cpy_w) / 2; + $cpy_h_offset = 0; + } + else + { + $cpy_w = $this->_img['main']['width']; + $cpy_h = (integer) $this->_img['main']['width'] / $this->_img['target']['aspectratio']; + $cpy_h_offset = (integer) ($this->_img['main']['height'] - $cpy_h) / 2; + $cpy_w_offset = 0; + } + } + // fill remaining background with a color to keep aspectratio + elseif ($mode == 2) + { + $final_aspectratio = $width / $height; + + if ($final_aspectratio < $this->_img['main']['aspectratio']) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = (integer) $width / $this->_img['main']['aspectratio']; + $cpy_w_offset2 = 0; + $cpy_h_offset2 = (integer) (($height - $this->_img['target']['height']) / 2); + } + else + { + $this->_img['target']['height'] = $height; + $this->_img['target']['width'] = (integer) $height * $this->_img['main']['aspectratio']; + $cpy_h_offset2 = 0; + $cpy_w_offset2 = (integer) (($width - $this->_img['target']['width']) / 2); + } + + $this->_img['target']['aspectratio'] = $this->_img['main']['aspectratio']; + $cpy_w = $this->_img['main']['width']; + $cpy_h = $this->_img['main']['height']; + $cpy_w_offset = 0; + $cpy_h_offset = 0; + } + // fill remaining background with a color to keep aspectratio + elseif ($mode == 3) + { + $final_aspectratio = $width / $height; + + if ($final_aspectratio < $this->_img['main']['aspectratio']) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = (integer) $width / $this->_img['main']['aspectratio']; + $cpy_w_offset2 = 0; + $cpy_h_offset2 = (integer) (($height - $this->_img['target']['height']) / 2); + } + else + { + $this->_img['target']['height'] = $height; + $this->_img['target']['width'] = (integer) $height * $this->_img['main']['aspectratio']; + $cpy_h_offset2 = 0; + $cpy_w_offset2 = 0; + } + + $this->_img['target']['aspectratio'] = $this->_img['main']['aspectratio']; + + $cpy_w = $this->_img['main']['width']; + $cpy_h = $this->_img['main']['height']; + $cpy_w_offset = 0; + $cpy_h_offset = 0; + } + // smart crop + elseif ($mode == 4) + { + ($width >= $height) + ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) + : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL); + + if ($this->_img['main']['bias'] == $this->_img['target']['bias'] || !$autorotate) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = $height; + } + else + { + $this->_img['target']['width'] = $height; + $this->_img['target']['height'] = $width; + } + + $this->_img['target']['aspectratio'] = $this->_img['target']['width'] / $this->_img['target']['height']; + + if ($this->_img['main']['width'] / $this->_img['target']['width'] >= $this->_img['main']['height'] / $this->_img['target']['height']) + { + $cpy_h = $this->_img['main']['height']; + $cpy_w = (integer) $this->_img['main']['height'] * $this->_img['target']['aspectratio']; + $cpy_w_offset = (integer) ($this->_img['main']['width'] - $cpy_w) / 2; + $cpy_h_offset = 0; + } + else + { + $cpy_w = $this->_img['main']['width']; + $cpy_h = (integer) $this->_img['main']['width'] / $this->_img['target']['aspectratio']; + $cpy_h_offset = (integer) ($this->_img['main']['height'] - $cpy_h) / 2; + $cpy_w_offset = 0; + } + + if ($this->_img['main']['width'] >= $this->_img['target']['height']) + { + $cpy_w_offset = (integer) ($this->_img['main']['width'] - $cpy_w) / 2; + $cpy_h_offset = 0; + } + else + { + $cpy_w_offset = 0; + $cpy_h_offset = (integer) ($this->_img['main']['height'] - $cpy_h) / 2; + } + } + } + elseif (($width == 0 && $height > 0) || ($width > 0 && $height == 0) && is_int($width) && is_int($height)) + { + //keep aspectratio + if ($autorotate == true) + { + if ($this->_img['main']['bias'] == IMAGE_TOOLBOX_BIAS_HORIZONTAL && $width > 0) + { + $height = $width; + $width = 0; + } + elseif ($this->_img['main']['bias'] == IMAGE_TOOLBOX_BIAS_VERTICAL && $height > 0) + { + $width = $height; + $height = 0; + } + } + + ($width >= $height) + ? ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_HORIZONTAL) + : ($this->_img['target']['bias'] = IMAGE_TOOLBOX_BIAS_VERTICAL); + + if ($width != 0) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = (integer) $width / $this->_img['main']['aspectratio']; + } + else + { + $this->_img['target']['height'] = $height; + $this->_img['target']['width'] = (integer) $height * $this->_img['main']['aspectratio']; + } + + $this->_img['target']['aspectratio'] = $this->_img['main']['aspectratio']; + + $cpy_w = $this->_img['main']['width']; + $cpy_h = $this->_img['main']['height']; + $cpy_w_offset = 0; + $cpy_h_offset = 0; + } + else + { + trigger_error($this->_error_prefix . ' Output width and height must be integers greater zero.', E_USER_ERROR); + return null; + } + + //create resized picture + $functionname = $this->_imagecreatefunction; + + $dummy = $functionname($this->_img['target']['width'] + 1, $this->_img['target']['height'] + 1); + + if ($this->_img['main']['type'] == 3) + { + // turning off alpha blending (to ensure alpha channel information + // is preserved, rather than removed (blending with the rest of the + // image in the form of black)) + imagealphablending($dummy, false); + + // turning on alpha channel information saving (to ensure the full range + // of transparency is preserved) + imagesavealpha($dummy, true); + } + + $resize_function = $this->_resize_function; + + $resize_function($dummy, $this->_img['main']['resource'], 0, 0, $cpy_w_offset, $cpy_h_offset, $this->_img['target']['width'], $this->_img['target']['height'], $cpy_w, $cpy_h); + + if ($mode == 2) + { + $this->_img['target']['resource'] = $functionname($width, $height); + $fillcolor = $this->_hexToPHPColor($bgcolor); + imagefill($this->_img['target']['resource'], 0, 0, $fillcolor); + } + else + { + $this->_img['target']['resource'] = $functionname($this->_img['target']['width'], $this->_img['target']['height']); + $cpy_w_offset2 = 0; + $cpy_h_offset2 = 0; + } + + if ($this->_img['main']['type'] == 3) + { + // turning off alpha blending (to ensure alpha channel information + // is preserved, rather than removed (blending with the rest of the + // image in the form of black)) + imagealphablending($this->_img['target']['resource'], false); + + // turning on alpha channel information saving (to ensure the full range + // of transparency is preserved) + imagesavealpha($this->_img['target']['resource'], true); + } + + imagecopy($this->_img['target']['resource'], $dummy, $cpy_w_offset2, $cpy_h_offset2, 0, 0, $this->_img['target']['width'], $this->_img['target']['height']); + imagedestroy($dummy); + + if ($mode == 2) + { + $this->_img['target']['width'] = $width; + $this->_img['target']['height'] = $height; + } + + //update _img['main'] with new data + foreach ($this->_img['target'] as $key => $value) + $this->_img['main'][$key] = $value; + + unset ($this->_img['target']); + + return true; + } + + + /** + * Adds a new image resource based on the given parameters. + * + * It does not overwrite the existing image resource.
      + * Instead it is used to load a second image to merge with the existing image. + * + * Parameter:
      + * string $file imagefile to load
      + * Or:
      + * integer $width imagewidth of new image to be created
      + * integer $height imageheight of new image to be created
      + * string $fillcolor optional fill the new image with this color (hexformat, e.g. '#FF0000')
      + */ + function addImage() + { + $args = func_get_args(); + $argc = func_num_args(); + + if ($this->_addImage($argc, $args)) + { + return true; + } + else + { + trigger_error($this->_error_prefix . 'failed to add image.', E_USER_ERROR); + return false; + } + } + + + /** + * Blend two images. + * + * Original image and the image loaded with {@link addImage() addImage}
      + * NOTE: This operation can take very long and is not intended for realtime use. + * (but of course depends on the power of your server :) ) + * + * IMPORTANT: {@link imagecopymerge() imagecopymerged} doesn't work with PHP 4.3.2. Bug ID: {@link http://bugs.php.net/bug.php?id=24816 24816}
      + * + * $x:
      + * negative values are possible.
      + * You can also use the following keywords ('left', 'center' or 'middle', 'right').
      + * Additionally you can specify an offset in pixel with the keywords like this 'left +10'.
      + * (default = 0) + * + * $y:
      + * negative values are possible.
      + * You can also use the following keywords ('top', 'center' or 'middle', 'bottom').
      + * Additionally you can specify an offset in pixel with the keywords like this 'bottom -10'.
      + * (default = 0) + * + * Possible values for $mode: + *
        + *
      • IMAGE_TOOLBOX_BLEND_COPY
      • + *
      • IMAGE_TOOLBOX_BLEND_MULTIPLY
      • + *
      • IMAGE_TOOLBOX_BLEND_SCREEN
      • + *
      • IMAGE_TOOLBOX_BLEND_DIFFERENCE
      • + *
      • IMAGE_TOOLBOX_BLEND_EXCLUSION
      • + *
      • IMAGE_TOOLBOX_BLEND_OVERLAY
      • + *
      + * + * $percent:
      + * alpha value in percent of blend effect (0 - 100)
      + * (default = 100) + * + * @param string|integer $x Horizontal position of second image. + * @param integer $y Vertical position of second image. negative values are possible. + * @param integer $mode blend mode. + * @param integer $percent alpha value + */ + function blend($x = 0, $y = 0, $mode = IMAGE_TOOLBOX_BLEND_COPY, $percent = 100) + { + if (is_string($x) || is_string($y)) + { + list($xalign, $xalign_offset) = explode(" ", $x); + list($yalign, $yalign_offset) = explode(" ", $y); + } + + if (is_string($x)) + { + switch ($xalign) + { + case 'left': + $dst_x = 0 + $xalign_offset; + $src_x = 0; + $src_w = $this->_img['operator']['width']; + break; + + case 'right': + $dst_x = ($this->_img['main']['width'] - $this->_img['operator']['width']) + $xalign_offset; + $src_x = 0; + $src_w = $this->_img['operator']['width']; + break; + + case 'middle': + case 'center': + $dst_x = (($this->_img['main']['width'] / 2) - ($this->_img['operator']['width'] / 2)) + $yalign_offset; + $src_x = 0; + $src_w = $this->_img['operator']['width']; + break; + } + } + else + { + if ($x >= 0) + { + $dst_x = $x; + $src_x = 0; + $src_w = $this->_img['operator']['width']; + } + else + { + $dst_x = 0; + $src_x = abs($x); + $src_w = $this->_img['operator']['width'] - $src_x; + } + } + + if (is_string($y)) + { + switch ($yalign) + { + case 'top': + $dst_y = 0 + $yalign_offset; + $src_y = 0; + $src_h = $this->_img['operator']['height']; + break; + + case 'bottom': + $dst_y = ($this->_img['main']['height'] - $this->_img['operator']['height']) + $yalign_offset; + $src_y = 0; + $src_h = $this->_img['operator']['height']; + break; + + case 'middle': + case 'center': + $dst_y = (($this->_img['main']['height'] / 2) - ($this->_img['operator']['height'] / 2)) + $yalign_offset; + $src_y = 0; + $src_h = $this->_img['operator']['height']; + break; + } + } + else + { + if ($y >= 0) + { + $dst_y = $y; + $src_y = 0; + $src_h = $this->_img['operator']['height']; + } + else + { + $dst_y = 0; + $src_y = abs($y); + $src_h = $this->_img['operator']['height'] - $src_y; + } + } + + if (($xalign == 'repeat') && ($yalign == 'repeat')) + { + $xLogoPosition = 0; + $yLogoPosition = 0; + + $widthWatermark = $this->_img['operator']['width']; + $heightWatermark = $this->_img['operator']['height']; + $widthPhoto = $this->_img['main']['width']; + $heightPhoto = $this->_img['main']['height']; + + // x line + $__xRepeat = ceil($widthPhoto / $widthWatermark); + + for ($i = 0; $i <= $__xRepeat; $i++) + { + $this->_imagecopymerge_alpha($this->_img['main']['resource'], $this->_img['operator']['resource'], ($xLogoPosition + $widthWatermark * $i), $yLogoPosition, 0, 0, ImageSX($this->_img['operator']['resource']), ImageSY($this->_img['operator']['resource']), $percent); + + // y line + $__yRepeat = ceil($heightPhoto / $heightWatermark); + + for ($ii = 1; $ii <= $__yRepeat; $ii++) + { + $this->_imagecopymerge_alpha($this->_img['main']['resource'], $this->_img['operator']['resource'], ($xLogoPosition + $widthWatermark * $i), ($yLogoPosition + $widthWatermark * $ii), 0, 0, ImageSX($this->_img['operator']['resource']), ImageSY($this->_img['operator']['resource']), $percent); + } + } + + } + else + { + $this->_imageBlend($mode, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent); + } + + return true; + } + + + /* + * PNG ALPHA CHANNEL SUPPORT for imagecopymerge(); + * This is a function like imagecopymerge but it handle alpha channel well!!! + */ + private function _imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct) + { + $opacity = $pct; + + // creating a cut resource + $cut = imagecreatetruecolor($src_w, $src_h); + + // copying that section of the background to the cut + imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h); + + // placing the watermark now + imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h); + + imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $opacity); + } + + + /** + * Blend two images. + * + * @access private + */ + function _imageBlend($mode, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent) + { + if ($mode == IMAGE_TOOLBOX_BLEND_COPY) + { + if ($percent == 100) + imagecopy($this->_img['main']['resource'], $this->_img['operator']['resource'], $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h); + else + $this->_imagecopymerge_alpha($this->_img['main']['resource'], $this->_img['operator']['resource'], $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent); + + } + else + { + $functionname = $this->_imagecreatefunction; + $dummy = $functionname($src_w, $src_h); + + for ($y=0; $y < $src_h; $y++) + { + for ($x=0; $x < $src_w; $x++) + { + $colorindex = imagecolorat($this->_img['main']['resource'], $dst_x + $x, $dst_y + $y); + $colorrgb1 = imagecolorsforindex($this->_img['main']['resource'], $colorindex); + $colorindex = imagecolorat($this->_img['operator']['resource'], $src_x + $x, $src_y + $y); + $colorrgb2 = imagecolorsforindex($this->_img['operator']['resource'], $colorindex); + $colorblend = $this->_calculateBlendvalue($mode, $colorrgb1, $colorrgb2); + $newcolor = imagecolorallocate($dummy, $colorblend['red'], $colorblend['green'], $colorblend['blue']); + imagesetpixel($dummy, $x, $y, $newcolor); + } + } + + $this->_img['target']['resource'] = $functionname($this->_img['main']['width'], $this->_img['main']['height']); + imagecopy($this->_img['target']['resource'], $this->_img['main']['resource'], 0, 0, 0, 0, $this->_img['main']['width'], $this->_img['main']['height']); + imagecopymerge($this->_img['target']['resource'], $dummy, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $percent); + + $this->_img['main']['resource'] = $this->_img['target']['resource']; + unset($this->_img['target']); + } + } + + + /** + * Calculate blend values for given blend mode + * + * @access private + */ + function _calculateBlendvalue($mode, $colorrgb1, $colorrgb2) + { + switch ($mode) + { + case IMAGE_TOOLBOX_BLEND_MULTIPLY: + $c['red'] = ($colorrgb1['red'] * $colorrgb2['red']) >> 8; + $c['green'] = ($colorrgb1['green'] * $colorrgb2['green']) >> 8; + $c['blue'] = ($colorrgb1['blue'] * $colorrgb2['blue']) >> 8; + break; + + case IMAGE_TOOLBOX_BLEND_SCREEN: + $c['red'] = 255 - ((255 - $colorrgb1['red']) * (255 - $colorrgb2['red']) >> 8); + $c['green'] = 255 - ((255 - $colorrgb1['green']) * (255 - $colorrgb2['green']) >> 8); + $c['blue'] = 255 - ((255 - $colorrgb1['blue']) * (255 - $colorrgb2['blue']) >> 8); + break; + + case IMAGE_TOOLBOX_BLEND_DIFFERENCE: + $c['red'] = abs($colorrgb1['red'] - $colorrgb2['red']); + $c['green'] = abs($colorrgb1['green'] - $colorrgb2['green']); + $c['blue'] = abs($colorrgb1['blue'] - $colorrgb2['blue']); + break; + + case IMAGE_TOOLBOX_BLEND_NEGATION: + $c['red'] = 255 - abs(255 - $colorrgb1['red'] - $colorrgb2['red']); + $c['green'] = 255 - abs(255 - $colorrgb1['green'] - $colorrgb2['green']); + $c['blue'] = 255 - abs(255 - $colorrgb1['blue'] - $colorrgb2['blue']); + break; + + case IMAGE_TOOLBOX_BLEND_EXCLUSION: + $c['red'] = $colorrgb1['red'] + $colorrgb2['red'] - (($colorrgb1['red'] * $colorrgb2['red']) >> 7); + $c['green'] = $colorrgb1['green'] + $colorrgb2['green'] - (($colorrgb1['green'] * $colorrgb2['green']) >> 7); + $c['blue'] = $colorrgb1['blue'] + $colorrgb2['blue'] - (($colorrgb1['blue'] * $colorrgb2['blue']) >> 7); + break; + + case IMAGE_TOOLBOX_BLEND_OVERLAY: + if ($colorrgb1['red'] < 128) + { + $c['red']= ($colorrgb1['red'] * $colorrgb2['red']) >> 7; + } + else + { + $c['red'] = 255 - ((255 - $colorrgb1['red']) * (255 - $colorrgb2['red']) >> 7); + } + + if ($colorrgb1['green'] < 128) + { + $c['green'] = ($colorrgb1['green'] * $colorrgb2['green']) >> 7; + } + else + { + $c['green'] = 255 - ((255 - $colorrgb1['green']) * (255 - $colorrgb2['green']) >> 7); + } + + if ($colorrgb1['blue'] < 128) + { + $c['blue'] = ($colorrgb1['blue'] * $colorrgb2['blue']) >> 7; + } + else + { + $c['blue'] = 255 - ((255 - $colorrgb1['blue']) * (255 - $colorrgb2['blue']) >> 7); + } + break; + + default: + break; + } + + return $c; + } + + + /** + * convert iso character coding to unicode (PHP conform) + * needed for TTF text generation of special characters (Latin-2) + * + * @access private + */ + function _iso2uni($isoline) + { + $iso2uni = array( + 173 => "¡", + 155 => "¢", + 156 => "£", + 15 => "¤", + 157 => "¥", + 124 => "¦", + 21 => "§", + 249 => "¨", + 184 => "©", + 166 => "ª", + 174 => "«", + 170 => "¬", + 169 => "®", + 238 => "¯", + 248 => "°", + 241 => "±", + 253 => "²", + 252 => "³", + 239 => "´", + 230 => "µ", + 20 => "¶", + 250 => "·", + 247 => "¸", + 251 => "¹", + 167 => "º", + 175 => "»", + 172 => "¼", + 171 => "½", + 243 => "¾", + 168 => "¿", + 183 => "À", + 181 => "Á", + 182 => "Â", + 199 => "Ã", + 142 => "Ä", + 143 => "Å", + 146 => "Æ", + 128 => "Ç", + 212 => "È", + 144 => "É", + 210 => "Ê", + 211 => "Ë", + 141 => "Ì", + 161 => "Í", + 140 => "Î", + 139 => "Ï", + 209 => "Ð", + 165 => "Ñ", + 227 => "Ò", + 224 => "Ó", + 226 => "Ô", + 229 => "Õ", + 153 => "Ö", + 158 => "×", + 157 => "Ø", + 235 => "Ù", + 233 => "Ú", + 234 => "Û", + 154 => "Ü", + 237 => "Ý", + 232 => "Þ", + 225 => "ß", + 133 => "à", + 160 => "á", + 131 => "â", + 198 => "ã", + 132 => "ä", + 134 => "å", + 145 => "æ", + 135 => "ç", + 138 => "è", + 130 => "é", + 136 => "ê", + 137 => "ë", + 141 => "ì", + 161 => "í", + 140 => "î", + 139 => "ï", + 208 => "ð", + 164 => "ñ", + 149 => "ò", + 162 => "ó", + 147 => "ô", + 228 => "õ", + 148 => "ö", + 246 => "÷", + 155 => "ø", + 151 => "ù", + 163 => "ú", + 150 => "û", + 129 => "ü", + 236 => "ý", + 231 => "þ", + 152 => "ÿ" + ); + $uniline = ''; + $len = strlen($isoline); + + for ($i=0; $i < $len; $i++) + { + $thischar = substr($isoline, $i, 1); + $key = ord($thischar); + $uniline .= isset($iso2uni[$key]) ? $iso2uni[$key] : $thischar; + } + + return $uniline; + } + + + /** + * Writes text over the image + * + * only TTF fonts are supported at the moment + * + * $x:
      + * You can also use the following keywords ('left', 'center' or 'middle', 'right').
      + * Additionally you can specify an offset in pixel with the keywords like this 'left +10'.
      + * (default = 0) + * + * $y:
      + * You can also use the following keywords ('top', 'center' or 'middle', 'bottom').
      + * Additionally you can specify an offset in pixel with the keywords like this 'bottom -10'.
      + * (default = 0) + * + * @param string $text text to be generated. + * @param string $font TTF fontfile to be used. (relative paths are ok). + * @param integer $size textsize. + * @param string $color textcolor in hexformat (e.g. '#FF0000'). + * @param string|integer $x horizontal postion in pixel. + * @param string|integer $y vertical postion in pixel. + * @param integer $angle rotation of the text. + */ + function addText($text, $font, $size, $color, $x, $y, $angle = 0) + { + global $HTTP_SERVER_VARS; + + if (substr($font, 0, 1) == DIRECTORY_SEPARATOR || (substr($font, 1, 1) == ":" && (substr($font, 2, 1) == "\\" || substr($font, 2, 1) == "/"))) + $prepath = ''; + else + $prepath = substr($HTTP_SERVER_VARS['SCRIPT_FILENAME'], 0, strrpos($HTTP_SERVER_VARS['SCRIPT_FILENAME'], DIRECTORY_SEPARATOR)) . DIRECTORY_SEPARATOR; + + $text = $this->_iso2uni($text); + + if (is_string($x) || is_string($y)) + { + $textsize = imagettfbbox($size, $angle, $prepath.$font, $text); + $textwidth = abs($textsize[2]); + $textheight = abs($textsize[7]); + list($xalign, $xalign_offset) = explode(" ", $x); + list($yalign, $yalign_offset) = explode(" ", $y); + } + + if (is_string($x)) + { + switch ($xalign) + { + case 'left': + $x = 0 + $xalign_offset; + break; + + case 'right': + $x = ($this->_img['main']['width'] - $textwidth) + $xalign_offset; + break; + + case 'middle': + case 'center': + $x = (($this->_img['main']['width'] - $textwidth) / 2) + $xalign_offset; + break; + } + } + + if (is_string($y)) + { + switch ($yalign) + { + case 'top': + $y = (0 + $textheight) + $yalign_offset; + break; + + case 'bottom': + $y = ($this->_img['main']['height']) + $yalign_offset; + break; + + case 'middle': + case 'center': + $y = ((($this->_img['main']['height'] - $textheight) / 2) + $textheight) + $yalign_offset; + break; + } + } + + imagettftext($this->_img['main']['resource'], $size, $angle, $x, $y, $this->_hexToPHPColor($color), $prepath . $font, $text); + + return true; + } + } +?> \ No newline at end of file diff --git a/class/class.user.php b/class/class.user.php new file mode 100644 index 0000000..1cc3d7f --- /dev/null +++ b/class/class.user.php @@ -0,0 +1,898 @@ +get_config_vars('USER_NO_USERNAME'); + } + elseif (preg_match($regex_username, $_POST['user_name'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_ERROR_USERNAME'); + } + + // Проверка имени + if (empty($_POST['firstname'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_NO_FIRSTNAME'); + } + elseif (preg_match($regex, stripslashes($_POST['firstname']))) + { + $errors[] = @$AVE_Template->get_config_vars('USER_ERROR_FIRSTNAME'); + } + + // Проверка фамилии + if (empty($_POST['lastname'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_NO_LASTNAME'); + } + elseif (preg_match($regex, stripslashes($_POST['lastname']))) + { + $errors[] = @$AVE_Template->get_config_vars('USER_ERROR_LASTNAME'); + } + + // Проверка e-Mail + if (empty($_POST['email'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_NO_EMAIL'); + } + elseif (!preg_match($regex_email, $_POST['email'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_EMAIL_ERROR'); + } + else + { + $email_exist = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_users + WHERE email != '" . $_POST['Email_Old'] . "' + AND email = '" . $_POST['email'] . "' + " . ($new ? "AND email != '" . $_SESSION['user_email'] . "'" : '') . " + LIMIT 1 + ")->NumRows(); + if ($email_exist==1) + { + $errors[] = @$AVE_Template->get_config_vars('USER_EMAIL_EXIST'); + } + } + + // Проверка пароля + if (isset($_REQUEST['action']) && $_REQUEST['action'] != 'edit') + { + if (empty($_POST['password'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_NO_PASSWORD'); + } + elseif (strlen($_POST['password']) < 4) + { + $errors[] = @$AVE_Template->get_config_vars('USER_PASSWORD_SHORT'); + } + elseif (preg_match($regex_password, $_POST['password'])) + { + $errors[] = @$AVE_Template->get_config_vars('USER_PASSWORD_ERROR'); + } + } + + // Проверка даты рождения + $match = ''; + + if (! empty($_POST['birthday']) && ! preg_match($regex_birthday, $_POST['birthday'], $match)) + { + $errors[] = @$AVE_Template->get_config_vars('USER_ERROR_DATEFORMAT'); + } + elseif (!empty($match)) + { + + $_POST['birthday'] = $match[1] + . $this->_birthday_delimetr . $match[3] + . $this->_birthday_delimetr . $match[4]; + } + + return $errors; + } + +/** + * ВНЕШНИЕ МЕТОДЫ + */ + + /** + * Группы пользователей + */ + + /** + * Получение списка Групп пользователей + * + * @param string $exclude идентификатор исключаемой Группы пользователей (гостей) + * @return array + */ + function userGroupListGet($exclude = '') + { + global $AVE_DB; + + $user_groups = array(); + $sql = $AVE_DB->Query(" + SELECT + grp.*, + COUNT(usr.Id) AS UserCount + FROM + " . PREFIX . "_user_groups AS grp + LEFT JOIN + " . PREFIX . "_users AS usr + ON usr.user_group = grp.user_group + " . (($exclude != '' && is_numeric($exclude)) ? "WHERE grp.user_group != '" . $exclude . "'" : '') . " + GROUP BY grp.user_group + "); + + while ($row = $sql->FetchRow()) + { + array_push($user_groups, $row); + } + + return $user_groups; + } + + /** + * Отобразить список Групп пользователей + * + */ + function userGroupListShow() + { + global $AVE_Template; + + $AVE_Template->assign('ugroups', $this->userGroupListGet()); + $AVE_Template->assign('content', $AVE_Template->fetch('groups/groups.tpl')); + } + + /** + * Создание новой Группы пользователей + * + */ + function userGroupNew() + { + global $AVE_DB, $AVE_Template; + + if (!empty($_POST['user_group_name'])) + { + $AVE_DB->Query(" + INSERT + INTO " . PREFIX . "_user_groups + SET + user_group = '', + user_group_name = '" . $_POST['user_group_name'] . "', + status = '1', + user_group_permission = '' + "); + $iid = $AVE_DB->InsertId(); + + reportLog($AVE_Template->get_config_vars('UGROUP_REPORT_ADD') . ' - (' . groupName($iid) . ')'); + + header('Location:index.php?do=groups&action=grouprights&Id=' . $iid . '&cp=' . SESSION); + } + else + { + header('Location:index.php?do=groups&cp=' . SESSION); + } + } + + /** + * Удаление Группы пользователей + * + * @param int $user_group_id идентификатор Группы пользователей + */ + function userGroupDelete($user_group_id = '0') + { + global $AVE_DB, $AVE_Template; + + if (is_numeric($user_group_id) && $user_group_id > 2) + { + $exist_user_in_group = $AVE_DB->Query(" + SELECT user_group + FROM " . PREFIX . "_users + WHERE user_group = '" . $user_group_id . "' + LIMIT 1 + ")->NumRows(); + + if (!$exist_user_in_group) + { + $AVE_DB->Query(" + DELETE + FROM " . PREFIX . "_user_groups + WHERE user_group = '" . $user_group_id . "' + "); + + reportLog($AVE_Template->get_config_vars('UGROUP_REPORT_DEL') . ' - (' . groupName($user_group_id) . ')'); + } + } + + header('Location:index.php?do=groups&cp=' . SESSION); + } + + /** + * Редактирование прав Группы пользователей + * + * @param int $user_group_id идентификатор Группы пользователей + */ + function userGroupPermissionEdit($user_group_id) + { + global $AVE_DB, $AVE_Template, $AVE_Module; + + if ((UGROUP != 1 && UGROUP == $user_group_id) || (UGROUP != 1 && $user_group_id == 1) || (UGROUP != 1 && $user_group_id == 2)) + { + + $AVE_Template->assign('own_group', true); + } + else + { + if (is_numeric($user_group_id) && $user_group_id) + { + $row = $AVE_DB->Query(" + SELECT + user_group_name, + user_group_permission + FROM + " . PREFIX . "_user_groups + WHERE + user_group = '" . $user_group_id . "' + ")->FetchRow(); + } + + if (empty($row)) + { + $AVE_Template->assign('no_group', true); + } + else + { + $AVE_Template->assign('g_all_permissions', $this->_allowed_admin_permission); + $AVE_Template->assign('g_group_permissions', array_diff(explode('|', $row->user_group_permission), array(''))); + $AVE_Template->assign('g_name', $row->user_group_name); + $AVE_Template->assign('modules', $AVE_Module->_modules); + } + } + + $AVE_Template->assign('content', $AVE_Template->fetch('groups/perms.tpl')); + } + + /** + * Запись прав Групп пользователей + * + * @param int $user_group_id идентификатор Группы пользователей + */ + function userGroupPermissionSave($user_group_id) + { + global $AVE_DB, $AVE_Template; + +if (is_numeric($user_group_id)) { + $permsArray = (isset($_REQUEST['perms']) && is_array($_REQUEST['perms'])) ? $_REQUEST['perms'] : []; + $perms = !empty($permsArray) ? implode('|', $permsArray) : ''; + + if ($user_group_id == '1' || in_array('alles', $permsArray)) { + $perms = 'alles'; + } + + if ($user_group_id == '2') { + $perms = ''; + } + + $sql = $AVE_DB->Query(" + UPDATE " . PREFIX . "_user_groups + SET user_group_permission = '" . $perms . "' + " . (!empty($_POST['user_group_name']) ? ", user_group_name = '" . $_POST['user_group_name'] . "'" : '') . " + WHERE user_group = '" . $user_group_id . "' + "); +} + + if ($sql->_result === false) { + $message = $AVE_Template->get_config_vars('UGROUP_SAVED_ERR'); + $header = $AVE_Template->get_config_vars('UGROUP_ERROR'); + $theme = 'error'; + + }else{ + $message = $AVE_Template->get_config_vars('UGROUP_SAVED'); + $header = $AVE_Template->get_config_vars('UGROUP_SUCCESS'); + $theme = 'accept'; + reportLog($AVE_Template->get_config_vars('UGROUP_SAVE_MAIN') . ' - (' . groupName($user_group_id) . ')'); + } + + if (isset($_REQUEST['ajax']) && $_REQUEST['ajax'] = '1') { + + echo json_encode(array('message' => $message, 'header' => $header, 'theme' => $theme)); + } else { + $AVE_Template->assign('message', $message); + header('Location:index.php?do=groups&cp=' . SESSION); + } + + exit; + } + + /** + * Учетные записи пользователей + */ + + /** + * Формирование спискка учетных записей пользователей + * + * @param int $user_group_id идентификатор Группы пользователей + */ + function userListFetch($user_group_id = '') + { + global $AVE_DB, $AVE_Template; + + $search_by_group = ''; + $search_by_id_or_name = ''; + $user_group_navi = ''; + $query_navi = ''; + $status_search = ''; + $status_navi = ''; + + if (isset($_REQUEST['user_group']) && $_REQUEST['user_group'] != '0') + { + $user_group_id = ($user_group_id != '') ? $user_group_id : $_REQUEST['user_group']; + $user_group_navi = '&user_group=' . $user_group_id; + $search_by_group = " AND user_group = '" . $user_group_id . "' "; + } + + if (!empty($_REQUEST['query'])) + { + $q = urldecode($_REQUEST['query']); + $search_by_id_or_name = " + AND (email LIKE '%" . $q . "%' + OR email = '" . $q . "' + OR Id = '" . $q . "' + OR firstname LIKE '" . $q . "%' + OR lastname LIKE '" . $q . "%') + "; + $query_navi = '&query=' . urlencode($_REQUEST['query']); + } + + if (isset($_REQUEST['status']) && $_REQUEST['status'] != 'all') + { + $status_search = " AND status = '" . $_REQUEST['status'] . "' "; + $status_navi = '&status=' . $_REQUEST['status']; + } + + $num = $AVE_DB->Query(" + SELECT COUNT(*) + FROM " . PREFIX . "_users + WHERE 1" + . $search_by_group + . $search_by_id_or_name + . $status_search + )->GetCell(); + + $sql = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_users + WHERE 1" + . $search_by_group + . $search_by_id_or_name + . $status_search + . " LIMIT " . (get_current_page()*$this->_limit-$this->_limit) . "," . $this->_limit + ); + + $isShop = $AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_modul_shop_bestellungen'")->GetCell(); + $users = array(); + + while ($row = $sql->FetchRow()) + { + // для комментариев + //$sqla = $AVE_DB->Query("SELECT * FROM " . PREFIX . "_modul_comment_info WHERE comment_author_id = '".(int)$row->Id."'"); + //$row->comments = $sqla->numrows(); + $row->avatar=getAvatar($row->Id,40); + array_push($users, $row); + } + + if ($num > $this->_limit) + { + $page_nav = '
    32. {t}
    33. '; + $page_nav = get_pagination(ceil($num/$this->_limit), 'page', $page_nav); + $AVE_Template->assign('page_nav', $page_nav); + } + + $AVE_Template->assign('ugroups', $this->userGroupListGet(2)); + $AVE_Template->assign('users', $users); + } + + /** + * Создание новой учетной записи + * + */ + function userNew() + { + global $AVE_DB, $AVE_Template; + + switch($_REQUEST['sub']) + { + case '': + $AVE_Template->assign('available_countries', get_country_list(1)); + $AVE_Template->assign('ugroups', $this->userGroupListGet(2)); + $AVE_Template->assign('formaction', 'index.php?do=user&action=new&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('user/form.tpl')); + break; + + case 'save': + $errors = $this->_userFieldValidate(1); + if (!empty($errors)) + { + $AVE_Template->assign('errors', $errors); + $AVE_Template->assign('available_countries', get_country_list(1)); + $AVE_Template->assign('ugroups', $this->userGroupListGet(2)); + $AVE_Template->assign('formaction', 'index.php?do=user&action=new&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('user/form.tpl')); + } + else + { + $salt = make_random_string(); + $password = md5(md5(trim($_POST['password']) . $salt)); +$user_group_extra = ''; +if (isset($_POST['user_group_extra']) && is_array($_POST['user_group_extra'])) { + $user_group_extra = implode(';', $_POST['user_group_extra']); +} + +$AVE_DB->Query(" + INSERT INTO " . PREFIX . "_users + SET + Id = '', + password = '" . $password . "', + salt = '" . $salt . "', + email = '" . $_POST['email'] . "', + street = '" . $_POST['street'] . "', + street_nr = '" . $_POST['street_nr'] . "', + zipcode = '" . $_POST['zipcode'] . "', + city = '" . $_POST['city'] . "', + phone = '" . $_POST['phone'] . "', + telefax = '" . $_POST['telefax'] . "', + description = '" . $_POST['description'] . "', + firstname = '" . $_POST['firstname'] . "', + lastname = '" . $_POST['lastname'] . "', + user_name = '" . $_POST['user_name'] . "', + user_group = '" . $_POST['user_group'] . "', + reg_time = '" . time() . "', + status = '" . $_POST['status'] . "', + last_visit = '" . time() . "', + country = '" . $_POST['country'] . "', + birthday = '" . $_POST['birthday'] . "', + company = '" . $_POST['company'] . "', + taxpay = '" . $_POST['taxpay'] . "', + user_group_extra = '" . $user_group_extra . "' +"); + $user_id=$AVE_DB->InsertId(); + if(is_uploaded_file($_FILES["avatar"]["tmp_name"])) + { + // Если файл загружен успешно, перемещаем его + // из временной директории в конечную + $newf_n= BASE_DIR.'/'. UPLOAD_DIR.'/avatars/new/'.$_FILES["avatar"]["name"]; + move_uploaded_file($_FILES["avatar"]["tmp_name"],$newf_n); + SetAvatar($user_id,$newf_n); + } + + $message = get_settings('mail_new_user'); + $message = str_replace('%NAME%', $_POST['user_name'], $message); + $message = str_replace('%HOST%', HOST . ABS_PATH, $message); + $message = str_replace('%PASSWORD%', $_POST['password'], $message); + $message = str_replace('%EMAIL%', $_POST['email'], $message); + $message = str_replace('%EMAILSIGNATURE%', get_settings('mail_signature'), $message); +/* + send_mail( + $_POST['email'], + $message, + $AVE_Template->get_config_vars('USER_MAIL_SUBJECT') + ); +*/ + reportLog($AVE_Template->get_config_vars('USER_REPORT_ADD') . ' - (' . stripslashes($_POST['user_name']) . ')'); + + header('Location:index.php?do=user&cp=' . SESSION); + } + break; + } + } + + /** + * Редактирование учетной записи пользователя + * + * @param int $user_id идентификатор учетной записи пользователя + */ + function userEdit($user_id) + { + global $AVE_DB, $AVE_Template; + + $user_id = (int)$user_id; + + switch($_REQUEST['sub']) + { + case '': + $row = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_users + WHERE Id = '" . $user_id . "' + ")->FetchRow(); + + if (!$row) + { + header('Location:index.php?do=user&cp=' . SESSION); + exit; + } +/* + if ($AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_modul_shop'")->GetCell()) + { + $AVE_Template->assign('is_shop', 1); + } + + if ($AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_modul_forum_userprofile'")->GetCell()) + { + $row = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_modul_forum_userprofile + WHERE BenutzerId = '" . $user_id . "' + ")->FetchRow(); + + if (is_object($row)) + { + $AVE_Template->assign('row_fp', $row); + $AVE_Template->assign('is_forum', 1); + } + } +*/ + if (($_SESSION['user_group'] != 1)){ + + if (($_SESSION['user_group'] == $row->user_group) && ($_SESSION['user_id'] != $row->Id)){ + $AVE_Template->assign('no_edit', true); + } + + if ($row->user_group == 1 && $row->Id == 1) { + $AVE_Template->assign('no_edit', true); + } + + } + + $row->avatar = getAvatar($user_id, 70); + + $AVE_Template->assign('row', $row); + + $AVE_Template->assign('user_group_extra', explode(';', $row->user_group_extra)); + $AVE_Template->assign('available_countries', get_country_list(1)); + $AVE_Template->assign('ugroups', $this->userGroupListGet(2)); + $AVE_Template->assign('us_groups', explode(';', $row->user_group_extra)); + $AVE_Template->assign('formaction', 'index.php?do=user&action=edit&Id='. $user_id .'&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('user/form.tpl')); + break; + + case 'save': + $errors = $this->_userFieldValidate(); + if (!empty($errors)) + { + + $row = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_users + WHERE Id = '" . $user_id . "' + ")->FetchRow(); + + if (!$row) + { + header('Location:index.php?do=user&cp=' . SESSION); + exit; + } + + if (($_SESSION['user_group'] != 1)){ + + if (($_SESSION['user_group'] == $row->user_group) && ($_SESSION['user_id'] != $row->Id)){ + $AVE_Template->assign('no_edit', true); + } + + if ($row->user_group == 1 && $row->Id == 1) { + $AVE_Template->assign('no_edit', true); + } + + } + + $row->avatar = getAvatar($user_id, 70); + + $AVE_Template->assign('row', $row); + $AVE_Template->assign('errors', $errors); + $AVE_Template->assign('user_group_extra', explode(';', $row->user_group_extra)); + $AVE_Template->assign('available_countries', get_country_list(1)); + $AVE_Template->assign('ugroups', $this->userGroupListGet(2)); + $AVE_Template->assign('us_groups', explode(';', $row->user_group_extra)); + $AVE_Template->assign('formaction', 'index.php?do=user&action=edit&Id='. $user_id .'&sub=save&cp=' . SESSION); + $AVE_Template->assign('content', $AVE_Template->fetch('user/form.tpl')); + } + else + { + if (!empty($_REQUEST['password'])) + { + $salt = make_random_string(); + $password = md5(md5(trim($_POST['password']) . $salt)); + $password_set = "password = '" . $password . "', salt = '" . $salt . "',"; + } + else + { + $password_set = ''; + } + + $user_group_set = ($_SESSION['user_id'] != $user_id) ? "user_group = '" . $_REQUEST['user_group'] . "'," : ''; + + $times = ($_REQUEST['deleted'] == "1") ? time() : ''; + + if(is_uploaded_file($_FILES["avatar"]["tmp_name"])) + { + // Если файл загружен успешно, перемещаем его + // из временной директории в конечную + $newf_n = BASE_DIR.'/'. UPLOAD_DIR.'/avatars/new/'.$_FILES["avatar"]["name"]; + move_uploaded_file($_FILES["avatar"]["tmp_name"],$newf_n); + SetAvatar($user_id,$newf_n); + } + +$user_group_extra = ''; +if (isset($_REQUEST['user_group_extra']) && is_array($_REQUEST['user_group_extra'])) { + $user_group_extra = implode(';', $_REQUEST['user_group_extra']); +} + +$AVE_DB->Query(" + UPDATE " . PREFIX . "_users + SET + " . $password_set . " + " . $user_group_set . " + email = '" . $_REQUEST['email'] . "', + street = '" . $_REQUEST['street'] . "', + street_nr = '" . $_REQUEST['street_nr'] . "', + zipcode = '" . $_REQUEST['zipcode'] . "', + city = '" . $_REQUEST['city'] . "', + phone = '" . $_REQUEST['phone'] . "', + telefax = '" . $_REQUEST['telefax'] . "', + description = '" . $_REQUEST['description'] . "', + firstname = '" . $_REQUEST['firstname'] . "', + lastname = '" . $_REQUEST['lastname'] . "', + user_name = '" . $_REQUEST['user_name'] . "', + status = '" . $_REQUEST['status'] . "', + country = '" . $_REQUEST['country'] . "', + birthday = '" . $_REQUEST['birthday'] . "', + deleted = '" . $_REQUEST['deleted'] . "', + del_time = '" . $times . "', + taxpay = '" . $_REQUEST['taxpay'] . "', + company = '" . $_REQUEST['company'] . "', + user_group_extra = '" . $user_group_extra . "' + WHERE + Id = '" . $user_id . "' +"); + + +/* + if ($AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_module_forum_userprofile'")->GetCell()) + { + $AVE_DB->Query(" + UPDATE " . PREFIX . "_modul_forum_userprofile + SET + GroupIdMisc = '" . @implode(';', $_REQUEST['user_group_extra']) . "', + BenutzerName = '" . @$_REQUEST['BenutzerName_fp']. "', + Signatur = '" . @$_REQUEST['Signatur_fp'] . "' , + Avatar = '" . @$_REQUEST['Avatar_fp'] . "' + WHERE + BenutzerId = '" . $user_id . "' + "); + } +*/ + + if ($_REQUEST['status'] == 1 && @$_REQUEST['SendFreeMail'] == 1) + { + $host = HOST . ABS_PATH; + $body_start = $AVE_Template->get_config_vars('USER_MAIL_BODY1'); + $body_start = str_replace('%USER%', $_REQUEST['user_name'], $body_start); + $body_start .= str_replace('%HOST%', $host, $AVE_Template->get_config_vars('USER_MAIL_BODY2')); + $body_start .= str_replace('%HOMEPAGENAME%', get_settings('site_name'), $AVE_Template->get_config_vars('USER_MAIL_FOOTER')); + $body_start = str_replace('%N%', "\n", $body_start); + $body_start = str_replace('%HOST%', $host, $body_start); + + send_mail( + $_POST['email'], + $body_start, + $AVE_Template->get_config_vars('USER_MAIL_SUBJECT'), + get_settings('mail_from'), + get_settings('mail_from_name') . ' (' . get_settings('site_name') . ')', + 'text' + ); + } + + if (!empty($_REQUEST['password']) && $_REQUEST['PassChange'] == 1) + { + $host = HOST . ABS_PATH; + $body_start = $AVE_Template->get_config_vars('USER_MAIL_BODY1'); + $body_start = str_replace('%USER%', $_REQUEST['user_name'], $body_start); + $body_start .= str_replace('%HOST%', $host, $AVE_Template->get_config_vars('USER_MAIL_PASSWORD2')); + $body_start = str_replace('%NEWPASS%', $_REQUEST['password'], $body_start); + $body_start .= str_replace('%HOMEPAGENAME%', get_settings('site_name'), $AVE_Template->get_config_vars('USER_MAIL_FOOTER')); + $body_start = str_replace('%N%', "\n", $body_start); + $body_start = str_replace('%HOST%', $host, $body_start); + + send_mail( + $_POST['email'], + $body_start, + $AVE_Template->get_config_vars('USER_MAIL_PASSWORD'), + get_settings('mail_from'), + get_settings('mail_from_name') . ' (' . get_settings('site_name') . ')', + 'text' + ); + } + + if ($_REQUEST['SimpleMessage'] != '') + { + send_mail( + $_POST['email'], + stripslashes($_POST['SimpleMessage']), + stripslashes($_POST['SubjectMessage']), + $_SESSION['user_email'], + $_SESSION['user_name'], + 'text' + ); + } + + if (!empty($_REQUEST['password']) && $_SESSION['user_id'] == $user_id) + { + $_SESSION['user_pass'] = $password; + $_SESSION['user_email'] = $_POST['email']; + } + + reportLog($AVE_Template->get_config_vars('USER_REPORT_EDIT') . ' - (' . stripslashes($_POST['user_name']) . ')'); + + header('Location:index.php?do=user&cp=' . SESSION); + exit; + } + break; + } + } + + /** + * Удаление учетной записи пользователя + * + * @param int $user_id идентификатор учетной записи пользователя + */ + function userDelete($user_id) + { + global $AVE_DB, $AVE_Template; + + if (is_numeric($user_id) && $user_id != 1) + { + $AVE_DB->Query(" + DELETE + FROM " . PREFIX . "_users + WHERE Id = '" . $user_id . "' + "); + + if ($AVE_DB->Query("SHOW TABLES LIKE '" . PREFIX . "_modul_forum_userprofile'")->GetCell()) + { + $AVE_DB->Query(" + DELETE + FROM " . PREFIX . "_modul_forum_userprofile + WHERE BenutzerId = '" . $user_id . "' + "); + } + + reportLog($AVE_Template->get_config_vars('USER_REPORT_DEL') . ' - (' . get_username_by_id($user_id) . ')'); + } + + header('Location:index.php?do=user&cp=' . SESSION); + } + + /** + * Запись изменений учетных записей пользователей в списке + * + */ + function userListEdit() + { + global $AVE_DB, $AVE_Template; + + foreach ($_POST['del'] as $user_id => $del) + { + if (is_numeric($user_id) && $user_id > 1) + { + $AVE_DB->Query(" + DELETE + FROM " . PREFIX . "_users + WHERE Id = '" . $user_id . "' + "); + + reportLog($AVE_Template->get_config_vars('USER_REPORT_DEL') . ' - (' . get_username_by_id($user_id) . ')'); + } + } + + foreach ($_POST['user_group'] as $user_id => $user_group_id) + { + if (is_numeric($user_id) && $user_id > 0 && + is_numeric($user_group_id) && $user_group_id > 0) + { + $AVE_DB->Query(" + UPDATE " . PREFIX . "_users + SET user_group = '" . $user_group_id . "' + WHERE Id = '" . $user_id . "' + "); + reportLog($AVE_Template->get_config_vars('USER_REPORT_GROUP') . ' - (' . get_username_by_id($user_id) . ')'); + } + } + + header('Location:index.php?do=user&cp=' . SESSION); + exit; + } +} + +?> diff --git a/class/class.utm.php b/class/class.utm.php new file mode 100644 index 0000000..0cd9081 --- /dev/null +++ b/class/class.utm.php @@ -0,0 +1,121 @@ +parameters as $param) + if (isset($_GET[$param]) && $_GET[$param] != '') + $return = true; + + return $return; + } + + //Создаёт строку с параметрами вот такого вида: utm_source=test; utm_medium=none; utm_campaign=kompaniya1; + private function create_parameters() + { + $content = ''; + foreach($this->parameters as $param){ + + if (isset($_GET[$param]) && $_GET[$param] != '') + { + $content .= $param.'='.$_GET[$param].'; '; + + } + else + { + $content .= $param.'=none; '; + } + } + + return $content; + } + + //Сохраняет переданные параметры, если требуется + //Если utm_history присутствует, то сохраняет utm_last + public function save_parameters() + { + if (isset($_GET['utm_source']) && trim($_GET['utm_source']) != '') + { + setcookie('utm_source', $_GET['utm_source']); + + $this->utm_source = $_GET['utm_source']; + } + + //$utm_history = ''; + + if (! isset($_COOKIE['utm_history']) || $_COOKIE['utm_history'] == '') + { + //Отсутствует utm_history + if($this->check_parameters() == true) + { + + $utm_history = $this->create_parameters(); + setcookie('utm_history', $utm_history, time()+15552000); //На 6 месяцев + setcookie('utm_last', ''); + + $this->utm_history = $utm_history; + } + + } + else + { + //utm_history присутствует + + $this->utm_history = $_COOKIE['utm_history']; + + //Перезапишем utm_last, если есть данные для этого + if($this->check_parameters() == true){ + + $utm_last = $this->create_parameters(); + + if($utm_last != $_COOKIE['utm_history']) + setcookie('utm_last', $utm_last, time()+15552000); //На 6 месяцев + + $this->utm_last = $utm_last; + + } + + } + + return true; + } + + //Возвращает значение cookies + public function get_value($name = '') + { + $name = trim($name); + + if ($name == '' || ! in_array($name, array('utm_history', 'utm_last', 'utm_source'))) + $name = 'utm_history'; + + if (isset($this->$name) && $this->$name != '') + return $this->$name; + + return isset($_COOKIE[$name]) ? $_COOKIE[$name] : ''; + } +} +?> \ No newline at end of file diff --git a/config/.htaccess b/config/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/config/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/config/config.inc.php b/config/config.inc.php new file mode 100644 index 0000000..e69de29 diff --git a/config/db.config.php b/config/db.config.php new file mode 100644 index 0000000..e69de29 diff --git a/fields/.htaccess b/fields/.htaccess new file mode 100644 index 0000000..1b10bcc --- /dev/null +++ b/fields/.htaccess @@ -0,0 +1,4 @@ +Deny from all + + Allow from all + \ No newline at end of file diff --git a/fields/checkbox/field.php b/fields/checkbox/field.php new file mode 100644 index 0000000..9b76c3f --- /dev/null +++ b/fields/checkbox/field.php @@ -0,0 +1,105 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = ''; + + switch ($action) + { + case 'edit': + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', (int)$field_value); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $field_value = clean_php($field_value); + + $res = ((int)$field_value === 1) + ? (int)$field_value + : null; + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $res; + break; + + case 'req': + $field_value = clean_php($field_value); + + $res = ((int)$field_value === 1) + ? (int)$field_value + : null; + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $res; + break; + + case 'save': + $field_value = clean_php($field_value); + $res = ((int)$field_value === 1) + ? $field_value + : null; + break; + + case 'api': + $field_value = clean_php($field_value); + $res = ((int)$field_value === 1) ? '1' : '0'; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/checkbox/lang/bg.txt b/fields/checkbox/lang/bg.txt new file mode 100644 index 0000000..dce9eff --- /dev/null +++ b/fields/checkbox/lang/bg.txt @@ -0,0 +1,2 @@ +[admin] +name = "Чекбокс (Checkbox)" \ No newline at end of file diff --git a/fields/checkbox/lang/cz.txt b/fields/checkbox/lang/cz.txt new file mode 100644 index 0000000..dce9eff --- /dev/null +++ b/fields/checkbox/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Чекбокс (Checkbox)" \ No newline at end of file diff --git a/fields/checkbox/lang/en.txt b/fields/checkbox/lang/en.txt new file mode 100644 index 0000000..6f0d65c --- /dev/null +++ b/fields/checkbox/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Checkbox" \ No newline at end of file diff --git a/fields/checkbox/lang/pl.txt b/fields/checkbox/lang/pl.txt new file mode 100644 index 0000000..9e2393f --- /dev/null +++ b/fields/checkbox/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Checkbox (pole wyboru)" \ No newline at end of file diff --git a/fields/checkbox/lang/ru.txt b/fields/checkbox/lang/ru.txt new file mode 100644 index 0000000..dce9eff --- /dev/null +++ b/fields/checkbox/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Чекбокс (Checkbox)" \ No newline at end of file diff --git a/fields/checkbox/lang/ua.txt b/fields/checkbox/lang/ua.txt new file mode 100644 index 0000000..dce9eff --- /dev/null +++ b/fields/checkbox/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Чекбокс (Checkbox)" \ No newline at end of file diff --git a/fields/checkbox/tpl/field-doc.tpl b/fields/checkbox/tpl/field-doc.tpl new file mode 100644 index 0000000..40b1e17 --- /dev/null +++ b/fields/checkbox/tpl/field-doc.tpl @@ -0,0 +1,6 @@ +{* + $field_id + $field_default + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/checkbox/tpl/field-req.tpl b/fields/checkbox/tpl/field-req.tpl new file mode 100644 index 0000000..40b1e17 --- /dev/null +++ b/fields/checkbox/tpl/field-req.tpl @@ -0,0 +1,6 @@ +{* + $field_id + $field_default + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/checkbox/tpl/field.tpl b/fields/checkbox/tpl/field.tpl new file mode 100644 index 0000000..ababcf7 --- /dev/null +++ b/fields/checkbox/tpl/field.tpl @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/fields/code/field.php b/fields/code/field.php new file mode 100644 index 0000000..7b8cc13 --- /dev/null +++ b/fields/code/field.php @@ -0,0 +1,118 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('doc_id', (int)$_REQUEST['Id']); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('f_id', $field_id . '_' . $doc_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $AVE_Template->config_load($lang_file, 'public'); + + if (! $tpl_empty) + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function ($data) use ($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('rubric_id', $rubric_id); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + + $AVE_Template->config_load($lang_file, 'public'); + + if (! $tpl_empty) + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('rubric_id', $rubric_id); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + default: return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/code/lang/bg.txt b/fields/code/lang/bg.txt new file mode 100644 index 0000000..8cc468d --- /dev/null +++ b/fields/code/lang/bg.txt @@ -0,0 +1,2 @@ +[admin] +name = "Код (Codemirror)" \ No newline at end of file diff --git a/fields/code/lang/cz.txt b/fields/code/lang/cz.txt new file mode 100644 index 0000000..11f8ae6 --- /dev/null +++ b/fields/code/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Kód (Codemirror)" \ No newline at end of file diff --git a/fields/code/lang/pl.txt b/fields/code/lang/pl.txt new file mode 100644 index 0000000..9c6d74c --- /dev/null +++ b/fields/code/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Kod (CodeMirror)" \ No newline at end of file diff --git a/fields/code/lang/ru.txt b/fields/code/lang/ru.txt new file mode 100644 index 0000000..8cc468d --- /dev/null +++ b/fields/code/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Код (Codemirror)" \ No newline at end of file diff --git a/fields/code/lang/ua.txt b/fields/code/lang/ua.txt new file mode 100644 index 0000000..8cc468d --- /dev/null +++ b/fields/code/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Код (Codemirror)" \ No newline at end of file diff --git a/fields/code/tpl/field-doc.tpl b/fields/code/tpl/field-doc.tpl new file mode 100644 index 0000000..40b1e17 --- /dev/null +++ b/fields/code/tpl/field-doc.tpl @@ -0,0 +1,6 @@ +{* + $field_id + $field_default + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/code/tpl/field-req.tpl b/fields/code/tpl/field-req.tpl new file mode 100644 index 0000000..40b1e17 --- /dev/null +++ b/fields/code/tpl/field-req.tpl @@ -0,0 +1,6 @@ +{* + $field_id + $field_default + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/code/tpl/field.tpl b/fields/code/tpl/field.tpl new file mode 100644 index 0000000..2d6fe27 --- /dev/null +++ b/fields/code/tpl/field.tpl @@ -0,0 +1,8 @@ +{if $codemirror != 'load'} + {assign var = codemirror value='' scope="global"} + {include file = "$codemirror_connect"} + {assign var = codemirror value="load" scope="global"} +{/if} + + +{include file="$codemirror_editor" conn_id=$f_id textarea_id="field_code_$f_id" ctrls='AveDocs.documentSaveFunction();' height=300} \ No newline at end of file diff --git a/fields/code_small/field.php b/fields/code_small/field.php new file mode 100644 index 0000000..2ee8e19 --- /dev/null +++ b/fields/code_small/field.php @@ -0,0 +1,118 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('doc_id', (int)$_REQUEST['Id']); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('f_id', $field_id . '_' . $doc_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $AVE_Template->config_load($lang_file, 'public'); + + if (! $tpl_empty) + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function ($data) use ($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('rubric_id', $rubric_id); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + + $AVE_Template->config_load($lang_file, 'public'); + + if (! $tpl_empty) + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('rubric_id', $rubric_id); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + default: return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/code_small/lang/bg.txt b/fields/code_small/lang/bg.txt new file mode 100644 index 0000000..8cc468d --- /dev/null +++ b/fields/code_small/lang/bg.txt @@ -0,0 +1,2 @@ +[admin] +name = "Код (Codemirror)" \ No newline at end of file diff --git a/fields/code_small/lang/cz.txt b/fields/code_small/lang/cz.txt new file mode 100644 index 0000000..11f8ae6 --- /dev/null +++ b/fields/code_small/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Kód (Codemirror)" \ No newline at end of file diff --git a/fields/code_small/lang/pl.txt b/fields/code_small/lang/pl.txt new file mode 100644 index 0000000..9c6d74c --- /dev/null +++ b/fields/code_small/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Kod (CodeMirror)" \ No newline at end of file diff --git a/fields/code_small/lang/ru.txt b/fields/code_small/lang/ru.txt new file mode 100644 index 0000000..a0a5285 --- /dev/null +++ b/fields/code_small/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Код (Codemirror) маленькое" \ No newline at end of file diff --git a/fields/code_small/lang/ua.txt b/fields/code_small/lang/ua.txt new file mode 100644 index 0000000..8cc468d --- /dev/null +++ b/fields/code_small/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Код (Codemirror)" \ No newline at end of file diff --git a/fields/code_small/tpl/field-doc.tpl b/fields/code_small/tpl/field-doc.tpl new file mode 100644 index 0000000..40b1e17 --- /dev/null +++ b/fields/code_small/tpl/field-doc.tpl @@ -0,0 +1,6 @@ +{* + $field_id + $field_default + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/code_small/tpl/field-req.tpl b/fields/code_small/tpl/field-req.tpl new file mode 100644 index 0000000..40b1e17 --- /dev/null +++ b/fields/code_small/tpl/field-req.tpl @@ -0,0 +1,6 @@ +{* + $field_id + $field_default + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/code_small/tpl/field.tpl b/fields/code_small/tpl/field.tpl new file mode 100644 index 0000000..9df2cd8 --- /dev/null +++ b/fields/code_small/tpl/field.tpl @@ -0,0 +1,8 @@ +{if $codemirror != 'load'} + {assign var = codemirror value='' scope="global"} + {include file = "$codemirror_connect"} + {assign var = codemirror value="load" scope="global"} +{/if} + + +{include file="$codemirror_editor" conn_id=$f_id textarea_id="field_code_$f_id" ctrls='AveDocs.documentSaveFunction();' height=200} \ No newline at end of file diff --git a/fields/date/field.php b/fields/date/field.php new file mode 100644 index 0000000..d08a08e --- /dev/null +++ b/fields/date/field.php @@ -0,0 +1,129 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res=0; + + switch ($action) + { + case 'edit': + $field_value = ($field_value != 0) ? $field_value : ''; + + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('doc_id', (int)$_REQUEST['Id']); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $field_value = clean_php($field_value); + + if ($tpl_empty) + { + $value = pretty_date(strftime(TIME_FORMAT, $field_value)); + } + else + { + $value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_value) + { + return $field_value; + }, + $tpl + ); + + return $res = $value; + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('field_default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'req': + $field_value = clean_php($field_value); + + if ($tpl_empty) + { + $value = pretty_date(strftime(TIME_FORMAT, $field_value)); + } + else + { + $value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_value) + { + return $field_value; + }, + $tpl + ); + + return $res = $value; + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('field_default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'save': + $res = $field_value; + break; + + case 'api': + return clean_php($field_value); + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/date/lang/bg.txt b/fields/date/lang/bg.txt new file mode 100644 index 0000000..13cc934 --- /dev/null +++ b/fields/date/lang/bg.txt @@ -0,0 +1,2 @@ +[admin] +name = "Дата (TimeStamp)" \ No newline at end of file diff --git a/fields/date/lang/cz.txt b/fields/date/lang/cz.txt new file mode 100644 index 0000000..2e5d160 --- /dev/null +++ b/fields/date/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Datum (TimeStamp)" \ No newline at end of file diff --git a/fields/date/lang/pl.txt b/fields/date/lang/pl.txt new file mode 100644 index 0000000..6ac6bc6 --- /dev/null +++ b/fields/date/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Data (TimeStamp)" \ No newline at end of file diff --git a/fields/date/lang/ru.txt b/fields/date/lang/ru.txt new file mode 100644 index 0000000..13cc934 --- /dev/null +++ b/fields/date/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Дата (TimeStamp)" \ No newline at end of file diff --git a/fields/date/lang/ua.txt b/fields/date/lang/ua.txt new file mode 100644 index 0000000..13cc934 --- /dev/null +++ b/fields/date/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Дата (TimeStamp)" \ No newline at end of file diff --git a/fields/date/tpl/field-doc.tpl b/fields/date/tpl/field-doc.tpl new file mode 100644 index 0000000..693f86b --- /dev/null +++ b/fields/date/tpl/field-doc.tpl @@ -0,0 +1,7 @@ +{* +{$field_value|date_format:$TIME_FORMAT|pretty_date|translate_date} +{$field_value|date_format:$DATE_FORMAT|pretty_date|translate_date} +{$field_value|date_format:$TIME_FORMAT|utf8|translate_date} +{$field_value|date_format:$DATE_FORMAT|utf8|translate_date} +*} +{$field_value|date_format:'%d-%m-%Y'} \ No newline at end of file diff --git a/fields/date/tpl/field-req.tpl b/fields/date/tpl/field-req.tpl new file mode 100644 index 0000000..693f86b --- /dev/null +++ b/fields/date/tpl/field-req.tpl @@ -0,0 +1,7 @@ +{* +{$field_value|date_format:$TIME_FORMAT|pretty_date|translate_date} +{$field_value|date_format:$DATE_FORMAT|pretty_date|translate_date} +{$field_value|date_format:$TIME_FORMAT|utf8|translate_date} +{$field_value|date_format:$DATE_FORMAT|utf8|translate_date} +*} +{$field_value|date_format:'%d-%m-%Y'} \ No newline at end of file diff --git a/fields/date/tpl/field.tpl b/fields/date/tpl/field.tpl new file mode 100644 index 0000000..3f7cc01 --- /dev/null +++ b/fields/date/tpl/field.tpl @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/fields/doc_files/css/field.css b/fields/doc_files/css/field.css new file mode 100644 index 0000000..856996c --- /dev/null +++ b/fields/doc_files/css/field.css @@ -0,0 +1,56 @@ +.doc_files { + position: relative; +} + +.doc_files > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} + +.doc_files .doc_file { + border: 1px solid #d9dee9; + display: block; + overflow: hidden; + padding: 10px; + width: auto; + border-radius: 5px; +} + +.doc_files .doc_file .file_block { + display: block; + float: left; +} + +.doc_files .doc_file .handle { + float: left; + display: inline-block; + margin: 4px 7px; + cursor: move; +} + +.doc_files .doc_file .file_block .docs_name { + display: block; + width: 400px; + margin-bottom: 5px; +} + +.doc_files .doc_file .file_block .docs_desc { + display: block; + width: 400px; + height: 40px; + margin-bottom: 5px; +} + +.doc_files .doc_file .file_block .docs_url { + width: 400px; +} \ No newline at end of file diff --git a/fields/doc_files/field.php b/fields/doc_files/field.php new file mode 100644 index 0000000..5933cf2 --- /dev/null +++ b/fields/doc_files/field.php @@ -0,0 +1,229 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = []; + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['name'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['descr'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + $list[$k]['url'] = (isset($list_item[2])) ? htmlspecialchars($list_item[2], ENT_QUOTES) : ''; + } + + $items = $list; + } + else + { + $items = explode(',', $default); + + foreach($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['name'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['descr'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + $list[$k]['url'] = (isset($list_item[2])) ? htmlspecialchars($list_item[2], ENT_QUOTES) : ''; + } + + $items = $list; + } + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'save': + foreach ($field_value AS $v) + { + if (! empty($v['url'])) + { + $field_value_new[] = [ + 'name' => (isset($v['name']) ? $v['name'] : ''), + 'descr' => (isset($v['descr']) ? $v['descr'] : ''), + 'url' => $v['url'] + ]; + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['name'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['descr'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + $list[$k]['url'] = (isset($list_item[2])) ? htmlspecialchars($list_item[2], ENT_QUOTES) : ''; + } + + $items = $list; + } + + return $items; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/doc_files/js/field.js b/fields/doc_files/js/field.js new file mode 100644 index 0000000..06d3503 --- /dev/null +++ b/fields/doc_files/js/field.js @@ -0,0 +1,83 @@ +var DocFiles = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.lists(); + }, + + lists: function() { + this.lists_sortable(); + this.lists_del_item(); + this.lists_add(); + }, + + lists_update: function() { + this.lists_maxid(); + this.lists_del_item(); + AveAdmin.tooltip(); + }, + + lists_maxid: function(id) { + var maxid = 1; + $('#doc_files_' + id).children('.doc_file').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + lists_del_item: function() { + $('.doc_file .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + links_del_conf, + links_del_head, + function(b) { + if (b) { + $('#link_' + id).remove(); + } + } + ); + }); + }, + + lists_add: function() { + $('.doc_files .AddButton').on('click', function(event) { + event.preventDefault(); + + c_id = $(this).parent().parent().parent('.doc_files').attr("data-id"); + iid = DocFiles.lists_maxid(c_id); + + $('#doc_files_' + c_id + ':last').append( + '' + ); + + DocFiles.lists_update(); + }); + }, + + lists_sortable: function() { + $('.doc_files').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + } +} + +$(document).ready(function() { + DocFiles.init(); +}); \ No newline at end of file diff --git a/fields/doc_files/lang/ru.txt b/fields/doc_files/lang/ru.txt new file mode 100644 index 0000000..a3f7243 --- /dev/null +++ b/fields/doc_files/lang/ru.txt @@ -0,0 +1,9 @@ +[admin] +name = "Файлы документов" +delete = "Удалить элемент" +param_name = "Наименование" +param_desc = "Описание" +param_url = "Ссылка" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/doc_files/tpl/field-doc.tpl b/fields/doc_files/tpl/field-doc.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/doc_files/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/doc_files/tpl/field-req.tpl b/fields/doc_files/tpl/field-req.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/doc_files/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/doc_files/tpl/field.tpl b/fields/doc_files/tpl/field.tpl new file mode 100644 index 0000000..3c1a0f3 --- /dev/null +++ b/fields/doc_files/tpl/field.tpl @@ -0,0 +1,33 @@ +{if $doc_files != 'load'} + {assign var=doc_files value='' scope="global"} + + + + {assign var=doc_files value="load" scope="global"} +{/if} + +
      +{foreach from=$items key=key item=item} + + + +{/foreach} +
      \ No newline at end of file diff --git a/fields/doc_from_rub/field.php b/fields/doc_from_rub/field.php new file mode 100644 index 0000000..0f17a42 --- /dev/null +++ b/fields/doc_from_rub/field.php @@ -0,0 +1,184 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + switch ($action) + { + case 'edit': + if (isset($default)) + { + $parent = $AVE_DB->Query(" + SELECT + MIN(document_parent) AS min + FROM + ". PREFIX ."_documents + WHERE + rubric_id IN (" . $default . ") + ")->GetCell(); + + $sql = $AVE_DB->Query(" + SELECT + Id, document_parent, document_title + FROM + ". PREFIX ."_documents + WHERE + rubric_id IN (" . $default . ") + "); + + $cats = array(); + + while ($cat = $sql->FetchAssocArray()) + { + $cats_ID[$cat['Id']][] = $cat; + $cats[$cat['document_parent']][$cat['Id']] = $cat; + } + + $AVE_Template->assign('subtpl', $tpl_dir . "list.tpl"); + $AVE_Template->assign('fields', doc_from_rub_tree($cats, $parent)); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + $AVE_Template->assign('field_value', $field_value); + } + else + { + $AVE_Template->assign('error', $AVE_Template->get_config_vars('error')); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $document = get_document($field_value); + + if ($tpl_empty) + { + $field_value = $document['document_title']; + $field_value = clean_php($field_value); + $field_value = stripcslashes($field_value); + $field_value = htmlspecialchars_decode($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('document', $document); + + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'req': + $document = get_document($field_value); + + if ($tpl_empty) + { + $field_value = $document['document_title']; + $field_value = clean_php($field_value); + $field_value = stripcslashes($field_value); + $field_value = htmlspecialchars_decode($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('document', $document); + + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + } + return ($res ? $res : $field_value); + } + + + if (! function_exists('doc_from_rub_tree')) + { + function doc_from_rub_tree($cats, $parent) + { + if (is_array($cats) and isset($cats[$parent])) + { + foreach($cats[$parent] as $cat) + { + $array[$cat['Id']]['Id'] = $cat['Id']; + $array[$cat['Id']]['document_title'] = $cat['document_title']; + $array[$cat['Id']]['child'] = doc_from_rub_tree($cats, $cat['Id']); + } + } + else + { + return null; + } + + return $array; + } + } +?> \ No newline at end of file diff --git a/fields/doc_from_rub/lang/bg.txt b/fields/doc_from_rub/lang/bg.txt new file mode 100644 index 0000000..42d4ab5 --- /dev/null +++ b/fields/doc_from_rub/lang/bg.txt @@ -0,0 +1,5 @@ +[admin] + +name = "Документ от рубрика" + +error = "Не е зададена рубрика" \ No newline at end of file diff --git a/fields/doc_from_rub/lang/cz.txt b/fields/doc_from_rub/lang/cz.txt new file mode 100644 index 0000000..472feb7 --- /dev/null +++ b/fields/doc_from_rub/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dokument z rubriky" +error = "Rubrika nazadaná" \ No newline at end of file diff --git a/fields/doc_from_rub/lang/en.txt b/fields/doc_from_rub/lang/en.txt new file mode 100644 index 0000000..4070c5f --- /dev/null +++ b/fields/doc_from_rub/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Document from rubric" +error = "Not specified category" \ No newline at end of file diff --git a/fields/doc_from_rub/lang/pl.txt b/fields/doc_from_rub/lang/pl.txt new file mode 100644 index 0000000..e8839ea --- /dev/null +++ b/fields/doc_from_rub/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dokument z rubryki" +error = "Nie wybrano rubryki" \ No newline at end of file diff --git a/fields/doc_from_rub/lang/ru.txt b/fields/doc_from_rub/lang/ru.txt new file mode 100644 index 0000000..12a8e75 --- /dev/null +++ b/fields/doc_from_rub/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Документ из рубрики" +error = "Не задана рубрика" \ No newline at end of file diff --git a/fields/doc_from_rub/lang/ua.txt b/fields/doc_from_rub/lang/ua.txt new file mode 100644 index 0000000..380e51b --- /dev/null +++ b/fields/doc_from_rub/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Документ з рубрики" +error = "Не задано рубрику" \ No newline at end of file diff --git a/fields/doc_from_rub/tpl/field-doc.tpl b/fields/doc_from_rub/tpl/field-doc.tpl new file mode 100644 index 0000000..e7fb4dc --- /dev/null +++ b/fields/doc_from_rub/tpl/field-doc.tpl @@ -0,0 +1,31 @@ +{* + +Доступные параметры: +----------------------------------------------------------- +Id ID Документа +rubric_id ID Рубрики +document_parent ID Документа «родителя» +document_alias Алиас документа +document_title Заголовок документа +document_breadcrum_title Заголовок документа для «хлебных крошек» +document_published Начало публикации +document_expire Окончание публикации +document_changed Дата последнего изменения +document_author_id ID автора документа +document_in_search Учавствует в поиске (0|1) +document_meta_keywords Ключевые слова +document_meta_description Описание документа +document_meta_robots Индексация +document_status Документ опубликован (Статус) (0|1) +document_deleted Документ удален (0|1) +document_count_view Кол-во просмотров +document_linked_navi_id ID пункта меню,с которым связан документ +document_lang Язык документа +document_lang_group Языковая группа документа + +Пример вывода: +----------------------------------------------------------- +{$document.document_title} Просмотров: {$document.document_count_view} + +*} +{$document.document_title|stripcslashes} \ No newline at end of file diff --git a/fields/doc_from_rub/tpl/field-req.tpl b/fields/doc_from_rub/tpl/field-req.tpl new file mode 100644 index 0000000..e7fb4dc --- /dev/null +++ b/fields/doc_from_rub/tpl/field-req.tpl @@ -0,0 +1,31 @@ +{* + +Доступные параметры: +----------------------------------------------------------- +Id ID Документа +rubric_id ID Рубрики +document_parent ID Документа «родителя» +document_alias Алиас документа +document_title Заголовок документа +document_breadcrum_title Заголовок документа для «хлебных крошек» +document_published Начало публикации +document_expire Окончание публикации +document_changed Дата последнего изменения +document_author_id ID автора документа +document_in_search Учавствует в поиске (0|1) +document_meta_keywords Ключевые слова +document_meta_description Описание документа +document_meta_robots Индексация +document_status Документ опубликован (Статус) (0|1) +document_deleted Документ удален (0|1) +document_count_view Кол-во просмотров +document_linked_navi_id ID пункта меню,с которым связан документ +document_lang Язык документа +document_lang_group Языковая группа документа + +Пример вывода: +----------------------------------------------------------- +{$document.document_title} Просмотров: {$document.document_count_view} + +*} +{$document.document_title|stripcslashes} \ No newline at end of file diff --git a/fields/doc_from_rub/tpl/field.tpl b/fields/doc_from_rub/tpl/field.tpl new file mode 100644 index 0000000..453d8f5 --- /dev/null +++ b/fields/doc_from_rub/tpl/field.tpl @@ -0,0 +1,17 @@ +{if $fields && !isset($error)} + + + +{else} + +
        +
      • {#error#}
      • +
      + +{/if} diff --git a/fields/doc_from_rub/tpl/list.tpl b/fields/doc_from_rub/tpl/list.tpl new file mode 100644 index 0000000..95e9912 --- /dev/null +++ b/fields/doc_from_rub/tpl/list.tpl @@ -0,0 +1,12 @@ +{if $items} + {assign var=field_level value=$field_level+1 scope="global"} + {foreach from=$items key=key item=field} + + {include file="$subtpl" items=$field.child} + {/foreach} +{/if} diff --git a/fields/doc_from_rub_all/field.php b/fields/doc_from_rub_all/field.php new file mode 100644 index 0000000..aa7b1f8 --- /dev/null +++ b/fields/doc_from_rub_all/field.php @@ -0,0 +1,150 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + switch ($action) + { + case 'edit': + if (isset($default)) + { + $sql = $AVE_DB->Query(" + SELECT + Id, document_parent, document_title + FROM + ". PREFIX ."_documents + WHERE + rubric_id IN (" . $default . ") + ORDER BY + document_title DESC + "); + + $cats = []; + + while ($cat = $sql->FetchAssocArray()) + array_push($cats, $cat); + + $AVE_Template->assign('fields', $cats); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + $AVE_Template->assign('field_value', $field_value); + } + else + { + $AVE_Template->assign('error', $AVE_Template->get_config_vars('error')); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $document = get_document($field_value); + + if ($tpl_empty) + { + $field_value = $document['document_title']; + $field_value = clean_php($field_value); + $field_value = stripcslashes($field_value); + $field_value = htmlspecialchars_decode($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('document', $document); + + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'req': + $document = get_document($field_value); + + if ($tpl_empty) + { + $field_value = $document['document_title']; + $field_value = clean_php($field_value); + $field_value = stripcslashes($field_value); + $field_value = htmlspecialchars_decode($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('document', $document); + + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/doc_from_rub_all/lang/bg.txt b/fields/doc_from_rub_all/lang/bg.txt new file mode 100644 index 0000000..42d4ab5 --- /dev/null +++ b/fields/doc_from_rub_all/lang/bg.txt @@ -0,0 +1,5 @@ +[admin] + +name = "Документ от рубрика" + +error = "Не е зададена рубрика" \ No newline at end of file diff --git a/fields/doc_from_rub_all/lang/cz.txt b/fields/doc_from_rub_all/lang/cz.txt new file mode 100644 index 0000000..472feb7 --- /dev/null +++ b/fields/doc_from_rub_all/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dokument z rubriky" +error = "Rubrika nazadaná" \ No newline at end of file diff --git a/fields/doc_from_rub_all/lang/en.txt b/fields/doc_from_rub_all/lang/en.txt new file mode 100644 index 0000000..4070c5f --- /dev/null +++ b/fields/doc_from_rub_all/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Document from rubric" +error = "Not specified category" \ No newline at end of file diff --git a/fields/doc_from_rub_all/lang/pl.txt b/fields/doc_from_rub_all/lang/pl.txt new file mode 100644 index 0000000..e8839ea --- /dev/null +++ b/fields/doc_from_rub_all/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dokument z rubryki" +error = "Nie wybrano rubryki" \ No newline at end of file diff --git a/fields/doc_from_rub_all/lang/ru.txt b/fields/doc_from_rub_all/lang/ru.txt new file mode 100644 index 0000000..9176202 --- /dev/null +++ b/fields/doc_from_rub_all/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Документ из рубрики (Все)" +error = "Не задана рубрика" \ No newline at end of file diff --git a/fields/doc_from_rub_all/lang/ua.txt b/fields/doc_from_rub_all/lang/ua.txt new file mode 100644 index 0000000..380e51b --- /dev/null +++ b/fields/doc_from_rub_all/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Документ з рубрики" +error = "Не задано рубрику" \ No newline at end of file diff --git a/fields/doc_from_rub_all/tpl/field-doc.tpl b/fields/doc_from_rub_all/tpl/field-doc.tpl new file mode 100644 index 0000000..e7fb4dc --- /dev/null +++ b/fields/doc_from_rub_all/tpl/field-doc.tpl @@ -0,0 +1,31 @@ +{* + +Доступные параметры: +----------------------------------------------------------- +Id ID Документа +rubric_id ID Рубрики +document_parent ID Документа «родителя» +document_alias Алиас документа +document_title Заголовок документа +document_breadcrum_title Заголовок документа для «хлебных крошек» +document_published Начало публикации +document_expire Окончание публикации +document_changed Дата последнего изменения +document_author_id ID автора документа +document_in_search Учавствует в поиске (0|1) +document_meta_keywords Ключевые слова +document_meta_description Описание документа +document_meta_robots Индексация +document_status Документ опубликован (Статус) (0|1) +document_deleted Документ удален (0|1) +document_count_view Кол-во просмотров +document_linked_navi_id ID пункта меню,с которым связан документ +document_lang Язык документа +document_lang_group Языковая группа документа + +Пример вывода: +----------------------------------------------------------- +{$document.document_title} Просмотров: {$document.document_count_view} + +*} +{$document.document_title|stripcslashes} \ No newline at end of file diff --git a/fields/doc_from_rub_all/tpl/field-req.tpl b/fields/doc_from_rub_all/tpl/field-req.tpl new file mode 100644 index 0000000..e7fb4dc --- /dev/null +++ b/fields/doc_from_rub_all/tpl/field-req.tpl @@ -0,0 +1,31 @@ +{* + +Доступные параметры: +----------------------------------------------------------- +Id ID Документа +rubric_id ID Рубрики +document_parent ID Документа «родителя» +document_alias Алиас документа +document_title Заголовок документа +document_breadcrum_title Заголовок документа для «хлебных крошек» +document_published Начало публикации +document_expire Окончание публикации +document_changed Дата последнего изменения +document_author_id ID автора документа +document_in_search Учавствует в поиске (0|1) +document_meta_keywords Ключевые слова +document_meta_description Описание документа +document_meta_robots Индексация +document_status Документ опубликован (Статус) (0|1) +document_deleted Документ удален (0|1) +document_count_view Кол-во просмотров +document_linked_navi_id ID пункта меню,с которым связан документ +document_lang Язык документа +document_lang_group Языковая группа документа + +Пример вывода: +----------------------------------------------------------- +{$document.document_title} Просмотров: {$document.document_count_view} + +*} +{$document.document_title|stripcslashes} \ No newline at end of file diff --git a/fields/doc_from_rub_all/tpl/field.tpl b/fields/doc_from_rub_all/tpl/field.tpl new file mode 100644 index 0000000..c127347 --- /dev/null +++ b/fields/doc_from_rub_all/tpl/field.tpl @@ -0,0 +1,15 @@ +{if $fields && !isset($error)} + + + +{else} + +
        +
      • {#error#}
      • +
      + +{/if} diff --git a/fields/doc_from_rub_check/field.php b/fields/doc_from_rub_check/field.php new file mode 100644 index 0000000..fa6dab4 --- /dev/null +++ b/fields/doc_from_rub_check/field.php @@ -0,0 +1,208 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + if (isset($default)) + { + $parent = $AVE_DB->Query(" + SELECT + MIN(document_parent) AS min + FROM + ". PREFIX ."_documents + WHERE + rubric_id IN (" . $default . ") + ")->GetCell(); + + $sql = $AVE_DB->Query(" + SELECT + Id, document_parent, document_title + FROM + ". PREFIX ."_documents + WHERE + rubric_id IN (" . $default . ") + "); + + $field_value_array = explode('|', $field_value); + $field_value_array = array_values(array_diff($field_value_array, array(''))); + + $cats = array(); + + while($cat = $sql->FetchAssocArray()) + { + $cat['checked'] = ((in_array($cat['Id'], $field_value_array) == false) ? "0" : "1"); + $cats_ID[$cat['Id']][] = $cat; + $cats[$cat['document_parent']][$cat['Id']] = $cat; + } + + $AVE_Template->assign('subtpl', $tpl_dir."list.tpl"); + $AVE_Template->assign('fields', doc_from_rub_check_tree($cats, $parent)); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + $AVE_Template->assign('field_value', $field_value); + } + else + { + $AVE_Template->assign('error', $AVE_Template->get_config_vars('error')); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + $AVE_Template->assign('subtpl', $tpl_dir."list.tpl"); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $field_value_array = explode('|', $field_value); + $field_value_array = array_values(array_diff($field_value_array, array(''))); + + if ($field_value_array != false) + { + foreach ($field_value_array as $list_item) + { + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $AVE_DB->Query(" + SELECT + Id, + document_title, + document_alias, + document_breadcrum_title + FROM + ".PREFIX."_documents + WHERE + Id = '" . $list_item . "' + ")->FetchAssocArray(); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $field_value_array = explode('|', $field_value); + $field_value_array = array_values(array_diff($field_value_array, array(''))); + + if ($field_value_array != false) + { + foreach ($field_value_array as $list_item) + { + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $AVE_DB->Query(" + SELECT + Id, + document_title, + document_alias, + document_breadcrum_title + FROM + ".PREFIX."_documents + WHERE + Id = '" . $list_item . "' + ")->FetchAssocArray(); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'api': + return $field_value; + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + + } + + return ($res ? $res : $field_value); + } + + if (! function_exists('doc_from_rub_check_tree')) + { + function doc_from_rub_check_tree($cats, $parent) + { + if (is_array($cats) and isset($cats[$parent])) + { + foreach ($cats[$parent] as $cat) + { + $array[$cat['Id']]['Id'] = $cat['Id']; + $array[$cat['Id']]['checked'] = $cat['checked']; + $array[$cat['Id']]['document_title'] = $cat['document_title']; + $array[$cat['Id']]['child'] = doc_from_rub_check_tree($cats, $cat['Id']); + } + } + else + { + return null; + } + + return $array; + } + } +?> \ No newline at end of file diff --git a/fields/doc_from_rub_check/lang/bg.txt b/fields/doc_from_rub_check/lang/bg.txt new file mode 100644 index 0000000..09d64b5 --- /dev/null +++ b/fields/doc_from_rub_check/lang/bg.txt @@ -0,0 +1,4 @@ +[admin] + +name = "Документ от рубрика (Checkbox)" +error = "Не е зададена рубрика" \ No newline at end of file diff --git a/fields/doc_from_rub_check/lang/cz.txt b/fields/doc_from_rub_check/lang/cz.txt new file mode 100644 index 0000000..a8d48b7 --- /dev/null +++ b/fields/doc_from_rub_check/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dokument z rubriky (Checkbox)" +error = "Rubrika nezadaná" \ No newline at end of file diff --git a/fields/doc_from_rub_check/lang/en.txt b/fields/doc_from_rub_check/lang/en.txt new file mode 100644 index 0000000..1c6c38c --- /dev/null +++ b/fields/doc_from_rub_check/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Document from rubric (Checkbox)" +error = "Not specified category" \ No newline at end of file diff --git a/fields/doc_from_rub_check/lang/pl.txt b/fields/doc_from_rub_check/lang/pl.txt new file mode 100644 index 0000000..d606e6a --- /dev/null +++ b/fields/doc_from_rub_check/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dokument z rubryki (Checkbox)" +error = "Nie wybrano rubryki" \ No newline at end of file diff --git a/fields/doc_from_rub_check/lang/ru.txt b/fields/doc_from_rub_check/lang/ru.txt new file mode 100644 index 0000000..ea62541 --- /dev/null +++ b/fields/doc_from_rub_check/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Документ из рубрики (Checkbox)" +error = "Не задана рубрика" \ No newline at end of file diff --git a/fields/doc_from_rub_check/lang/ua.txt b/fields/doc_from_rub_check/lang/ua.txt new file mode 100644 index 0000000..959c810 --- /dev/null +++ b/fields/doc_from_rub_check/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Документ з рубрики (Checkbox)" +error = "Не задано рубрику" \ No newline at end of file diff --git a/fields/doc_from_rub_check/tpl/field-doc.tpl b/fields/doc_from_rub_check/tpl/field-doc.tpl new file mode 100644 index 0000000..78dbf11 --- /dev/null +++ b/fields/doc_from_rub_check/tpl/field-doc.tpl @@ -0,0 +1,23 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$field_id} ID поля +{$field_value} Данные поля (массив) + +$item.Id +$item.document_title +$item.document_alias +$item.document_breadcrum_title + +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +Пример вывода: +----------------------------------------------------------- +*} + \ No newline at end of file diff --git a/fields/doc_from_rub_check/tpl/field-req.tpl b/fields/doc_from_rub_check/tpl/field-req.tpl new file mode 100644 index 0000000..78dbf11 --- /dev/null +++ b/fields/doc_from_rub_check/tpl/field-req.tpl @@ -0,0 +1,23 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$field_id} ID поля +{$field_value} Данные поля (массив) + +$item.Id +$item.document_title +$item.document_alias +$item.document_breadcrum_title + +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +Пример вывода: +----------------------------------------------------------- +*} + \ No newline at end of file diff --git a/fields/doc_from_rub_check/tpl/field.tpl b/fields/doc_from_rub_check/tpl/field.tpl new file mode 100644 index 0000000..a10b489 --- /dev/null +++ b/fields/doc_from_rub_check/tpl/field.tpl @@ -0,0 +1,38 @@ +{if $docfromrubcheck != 'load'} + {assign var=docfromrubcheck value='' scope="global"} + {literal} + + {/literal} + {assign var=docfromrubcheck value="load" scope="global"} +{/if} + +{if $fields && !isset($error)} + +
        + {foreach from=$fields key=key item=field} + +
      • + + +
      • + +
        + {include file="$subtpl" items=$field.child} + {/foreach} +
      +{else} +
        +
      • {#error#}
      • +
      +{/if} diff --git a/fields/doc_from_rub_check/tpl/list.tpl b/fields/doc_from_rub_check/tpl/list.tpl new file mode 100644 index 0000000..d78e0a7 --- /dev/null +++ b/fields/doc_from_rub_check/tpl/list.tpl @@ -0,0 +1,20 @@ +{if $items} +
        + {foreach from=$items key=key item=field} +
      • + + +
      • +
        + {include file="$subtpl" items=$field.child} + {/foreach} +
      +{/if} diff --git a/fields/doc_from_rub_search/css/field.css b/fields/doc_from_rub_search/css/field.css new file mode 100644 index 0000000..0a676da --- /dev/null +++ b/fields/doc_from_rub_search/css/field.css @@ -0,0 +1,18 @@ +.multi_lists { + position: relative; +} + +.multi_lists > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/doc_from_rub_search/field.php b/fields/doc_from_rub_search/field.php new file mode 100644 index 0000000..de4a13d --- /dev/null +++ b/fields/doc_from_rub_search/field.php @@ -0,0 +1,252 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = array(); + + if ($field_value != '' && $field_value != $default) + { + $items = explode('|', $field_value); + $items = array_values(array_diff($items, array(''))); + } + + if (! empty($items)) + { + foreach($items as $k => $v) + { + $list[$k]['param'] = htmlspecialchars(get_document($v, 'document_title'), ENT_QUOTES); + $list[$k]['value'] = $v; + } + + $items = $list; + } + else + { + $items[0]['param'] = ''; + $items[0]['value'] = ''; + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + + return $AVE_Template->fetch($tpl_file); + + case 'save': + foreach ($field_value as $v) + { + if (! empty($v['value'])) + { + $field_value_new[] = $v['value']; + } + } + + if (isset($field_value_new)) + { + return '|' . implode('|', $field_value_new) . '|'; + } + else + { + return $field_value_new = ''; + } + break; + + case 'doc': + $field_value_array = explode('|', $field_value); + $field_value_array = array_values(array_diff($field_value_array, array(''))); + + if ($field_value_array != false) + { + foreach ($field_value_array as $list_item) + { + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $AVE_DB->Query(" + SELECT + Id, + document_title, + document_alias, + document_breadcrum_title + FROM + ".PREFIX."_documents + WHERE + Id = '" . $list_item . "' + ")->FetchAssocArray(); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $field_value_array = explode('|', $field_value); + $field_value_array = array_values(array_diff($field_value_array, array(''))); + + if ($field_value_array != false) + { + foreach ($field_value_array as $list_item) + { + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $AVE_DB->Query(" + SELECT + Id, + document_title, + document_alias, + document_breadcrum_title + FROM + ".PREFIX."_documents + WHERE + Id = '" . $list_item . "' + ")->FetchAssocArray(); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'api' : + $items = []; + + if ($field_value != '' && $field_value != $default) + { + $items = explode('|', $field_value); + $items = array_values(array_diff($items, array(''))); + } + + if (! empty($items)) + { + foreach($items as $k => $v) + { + $list[$k]['param'] = htmlspecialchars_decode(get_document($v, 'document_title'), ENT_QUOTES); + $list[$k]['value'] = $v; + } + + $items = $list; + } + else + { + $items[0]['param'] = ''; + $items[0]['value'] = ''; + } + + return $items; + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + + case 'search': + $default = get_field_default_value($_REQUEST['field_id']); + + $sql = $AVE_DB->Query(" + SELECT + doc.Id, + doc.document_title, + rub.rubric_title + FROM + " . PREFIX . "_documents AS doc + JOIN + " . PREFIX . "_rubrics AS rub + ON doc.rubric_id = rub.Id + WHERE + doc.rubric_id IN (" . $default . ") + AND + doc.document_status = 1 + AND + UPPER (doc.document_title) LIKE UPPER('%" . $_REQUEST['q'] . "%') + GROUP BY + doc.Id + LIMIT + 0,5 + "); + + $doc_finded = array(); + + while ($row = $sql->FetchRow()) + { + $doc_finded[] = array( + 'doc_id' => $row->Id, + 'doc_title' => $row->document_title, + 'doc_rubric' => $row->rubric_title + ); + } + + echo json_encode($doc_finded); + exit; + + default: + return $field_value; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/doc_from_rub_search/js/field.js b/fields/doc_from_rub_search/js/field.js new file mode 100644 index 0000000..3534a2e --- /dev/null +++ b/fields/doc_from_rub_search/js/field.js @@ -0,0 +1,127 @@ +var DocSearch = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.DocSearch_items(); + }, + + DocSearch_items: function() { + this.DocSearch_sortable(); + this.DocSearch_del_item(); + this.DocSearch_add(); + this.DocSearch_search(); + }, + + DocSearch_update: function() { + this.DocSearch_maxid(); + this.DocSearch_del_item(); + this.DocSearch_search(); + AveAdmin.tooltip(); + }, + + DocSearch_maxid: function(id) { + var maxid = 1; + $('#docsearch_lists_' + id).children('.docsearch_list').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + DocSearch_del_item: function() { + $('.docsearch_list .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + docsearch_del_conf, + docsearch_del_head, + function(b) { + if (b) { + $('#docsearch_list_' + id).remove(); + } + } + ); + }); + }, + + DocSearch_add: function() { + $('.AddButton').on('click', function() { + c_id = $(this).parent().parent('.docsearch_lists').attr("data-id"); + d_id = $(this).parent().parent('.docsearch_lists').attr("data-docid"); + i_id = DocSearch.DocSearch_maxid(d_id + '_' + c_id); + $('#docsearch_lists_' + d_id + '_' + c_id + ':last').append( + '
      ' + + '  Id:   ×' + + '
      ' + + '
      ' + ); + + DocSearch.DocSearch_update(); + }); + }, + + DocSearch_sortable: function() { + $('.docsearch_lists').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + }, + + /** + * @return {boolean} + */ + DocSearch_search: function() { + + $(document).on('input', '.search_docsearch', function(event) + { + event.preventDefault(); + + var query = $(this); + + var did = query.attr('data-docid'); + var fid = query.attr('data-fieldid'); + var kid = query.attr('data-id'); + var field_id_input = $('.field_' + did + '_' + fid + '_' + kid); + + query.autocomplete("index.php?do=fields&field=doc_from_rub_search&type=search&doc_id=" + did + "&field_id=" + fid, { + width: query.outerWidth(), + max: 5, + dataType: "json", + matchContains: "word", + scroll: true, + scrollHeight: 200, + parse: function(data) { + return $.map(data, function(row) { + return { + data: row, + value: row.doc_title, + result: query.val() + } + }); + }, + formatItem: function(item) { + return '
      (' + item.doc_rubric + ') ' + item.doc_title + '
      '; + } + }).result(function(event, item) { + + query.val(item.doc_title); + + field_id_input.val(item.doc_id); + + query.unautocomplete(); + }); + + return false; + }); + + return false; + } +} + +$(document).ready(function() +{ + DocSearch.init(); +}); diff --git a/fields/doc_from_rub_search/lang/bg.txt b/fields/doc_from_rub_search/lang/bg.txt new file mode 100644 index 0000000..3b194c7 --- /dev/null +++ b/fields/doc_from_rub_search/lang/bg.txt @@ -0,0 +1,8 @@ +[admin] +name = "Документи от рубрика" +delete = "Изтриване на документ" +param = "Документ" +value = "Id" +del_conf = "Сигурни ли сте, че желаете да изтриете този елемент (Документ)?" +del_head = "Изтриване на елемент(Документ)..." +add = "Добави" \ No newline at end of file diff --git a/fields/doc_from_rub_search/lang/cz.txt b/fields/doc_from_rub_search/lang/cz.txt new file mode 100644 index 0000000..76f3ea0 --- /dev/null +++ b/fields/doc_from_rub_search/lang/cz.txt @@ -0,0 +1,8 @@ +[admin] +name = "Dokument z rubrik" +delete = "Odstranit prvek" +param = "Dokument" +value = "Id" +del_conf = "Opravdu chcete odstranit tento prvek (dokument)?" +del_head = "Odstranění prvku (dokumentu)..." +add = "Přidat" \ No newline at end of file diff --git a/fields/doc_from_rub_search/lang/pl.txt b/fields/doc_from_rub_search/lang/pl.txt new file mode 100644 index 0000000..5c14d3e --- /dev/null +++ b/fields/doc_from_rub_search/lang/pl.txt @@ -0,0 +1,8 @@ +[admin] +name = "Dokumenty z rubryki" +delete = "Usuń element" +param = "Dokument" +value = "ID" +del_conf = "Czy na pewno chcesz usunąć ten element (document)?" +del_head = "Usuń element (document) ..." +add = "Dodaj" \ No newline at end of file diff --git a/fields/doc_from_rub_search/lang/ru.txt b/fields/doc_from_rub_search/lang/ru.txt new file mode 100644 index 0000000..0353712 --- /dev/null +++ b/fields/doc_from_rub_search/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Документы из рубрик" +delete = "Удалить элемент" +param = "Документ" +value = "Id" +del_conf = "Вы уверены, что хотите удалить данный элемент (Документ)?" +del_head = "Удаление элемента (Документа)..." +add = "Добавить" \ No newline at end of file diff --git a/fields/doc_from_rub_search/lang/ua.txt b/fields/doc_from_rub_search/lang/ua.txt new file mode 100644 index 0000000..6acc90e --- /dev/null +++ b/fields/doc_from_rub_search/lang/ua.txt @@ -0,0 +1,8 @@ +[admin] +name = "Документи з рубрик" +delete = "Видалити елемент" +param = "Документ" +value = "Id" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент (Документ)?" +del_head = "Видалення елемента (Документа)..." +add = "Додати" \ No newline at end of file diff --git a/fields/doc_from_rub_search/tpl/field-doc.tpl b/fields/doc_from_rub_search/tpl/field-doc.tpl new file mode 100644 index 0000000..78dbf11 --- /dev/null +++ b/fields/doc_from_rub_search/tpl/field-doc.tpl @@ -0,0 +1,23 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$field_id} ID поля +{$field_value} Данные поля (массив) + +$item.Id +$item.document_title +$item.document_alias +$item.document_breadcrum_title + +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +Пример вывода: +----------------------------------------------------------- +*} + \ No newline at end of file diff --git a/fields/doc_from_rub_search/tpl/field-req.tpl b/fields/doc_from_rub_search/tpl/field-req.tpl new file mode 100644 index 0000000..78dbf11 --- /dev/null +++ b/fields/doc_from_rub_search/tpl/field-req.tpl @@ -0,0 +1,23 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$field_id} ID поля +{$field_value} Данные поля (массив) + +$item.Id +$item.document_title +$item.document_alias +$item.document_breadcrum_title + +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +Пример вывода: +----------------------------------------------------------- +*} + \ No newline at end of file diff --git a/fields/doc_from_rub_search/tpl/field.tpl b/fields/doc_from_rub_search/tpl/field.tpl new file mode 100644 index 0000000..76214b2 --- /dev/null +++ b/fields/doc_from_rub_search/tpl/field.tpl @@ -0,0 +1,29 @@ +{if $docsearch != 'load'} + {assign var=docsearch value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=docsearch value="load" scope="global"} +{/if} + +
      +{foreach from=$items key=key item=item} + +
      +   Id:   {if $key == 0}+{else}×{/if} +
      +
      + +{/foreach} +
      \ No newline at end of file diff --git a/fields/download/field.php b/fields/download/field.php new file mode 100644 index 0000000..2077aff --- /dev/null +++ b/fields/download/field.php @@ -0,0 +1,81 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res=0; + + switch ($action) + { + case 'edit': + $field_value = !empty($field_value) ? htmlspecialchars($field_value, ENT_QUOTES) : ''; + + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $field_value = clean_php($field_value); + $field_param = explode('|', $field_value); + if ($tpl_empty) + { + $field_value = (!empty($field_param[1]) ? $field_param[1] . '
      ' : '') + . '
      '; + } + else + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + $res = $field_value; + break; + + case 'req': + $res=get_field_default($field_value,$action,$field_id,$tpl,$tpl_empty,$maxlength,$document_fields,$rubric_id); + break; + + case 'api' : + return htmlspecialchars_decode($field_value, ENT_QUOTES); + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/download/lang/bg.txt b/fields/download/lang/bg.txt new file mode 100644 index 0000000..568adeb --- /dev/null +++ b/fields/download/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Линк към файл" diff --git a/fields/download/lang/cz.txt b/fields/download/lang/cz.txt new file mode 100644 index 0000000..b7dcd65 --- /dev/null +++ b/fields/download/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Soubor ke stažení" diff --git a/fields/download/lang/en.txt b/fields/download/lang/en.txt new file mode 100644 index 0000000..4936e36 --- /dev/null +++ b/fields/download/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Download file" diff --git a/fields/download/lang/pl.txt b/fields/download/lang/pl.txt new file mode 100644 index 0000000..7d0ef7d --- /dev/null +++ b/fields/download/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Pobierz plik" diff --git a/fields/download/lang/ru.txt b/fields/download/lang/ru.txt new file mode 100644 index 0000000..91e422e --- /dev/null +++ b/fields/download/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Загрузить файл" diff --git a/fields/download/lang/ua.txt b/fields/download/lang/ua.txt new file mode 100644 index 0000000..eef181e --- /dev/null +++ b/fields/download/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Завантажити файл" diff --git a/fields/download/tpl/field.tpl b/fields/download/tpl/field.tpl new file mode 100644 index 0000000..c9d6beb --- /dev/null +++ b/fields/download/tpl/field.tpl @@ -0,0 +1,8 @@ +
      + + +  +  +? +
      \ No newline at end of file diff --git a/fields/drop_down/field.php b/fields/drop_down/field.php new file mode 100644 index 0000000..0917498 --- /dev/null +++ b/fields/drop_down/field.php @@ -0,0 +1,91 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + switch ($action) + { + case 'edit': + $items = array(); + $items = explode(',', $default); + $items = array_diff($items, array('')); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', trim($field_value)); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + @$field_value = clean_php($field_value); + if (!$tpl_empty) + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + $res = $field_value; + break; + + case 'req': + @$field_value = clean_php($field_value); + if (!$tpl_empty) + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + $res = $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> diff --git a/fields/drop_down/lang/bg.txt b/fields/drop_down/lang/bg.txt new file mode 100644 index 0000000..8084852 --- /dev/null +++ b/fields/drop_down/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] +name = "Падащ списък" +no_items = "Не са зададени стойности по подразбиране" \ No newline at end of file diff --git a/fields/drop_down/lang/cz.txt b/fields/drop_down/lang/cz.txt new file mode 100644 index 0000000..2843330 --- /dev/null +++ b/fields/drop_down/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Rozevírací seznam" +no_items = "Neexistuje žádná výchozí hodnota" \ No newline at end of file diff --git a/fields/drop_down/lang/en.txt b/fields/drop_down/lang/en.txt new file mode 100644 index 0000000..1c68529 --- /dev/null +++ b/fields/drop_down/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dropdown list" +no_items = "No default value" \ No newline at end of file diff --git a/fields/drop_down/lang/pl.txt b/fields/drop_down/lang/pl.txt new file mode 100644 index 0000000..96bb798 --- /dev/null +++ b/fields/drop_down/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Lista rozwijana" +no_items = "Nie ma znaczenia domyślnego" \ No newline at end of file diff --git a/fields/drop_down/lang/ru.txt b/fields/drop_down/lang/ru.txt new file mode 100644 index 0000000..41ee8d0 --- /dev/null +++ b/fields/drop_down/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Выпадающий список" +no_items = "Нет значения по умолчанию" \ No newline at end of file diff --git a/fields/drop_down/lang/ua.txt b/fields/drop_down/lang/ua.txt new file mode 100644 index 0000000..4dc25b9 --- /dev/null +++ b/fields/drop_down/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Випадаючий список" +no_items = "Немає значення за замовчуванням" \ No newline at end of file diff --git a/fields/drop_down/tpl/field.tpl b/fields/drop_down/tpl/field.tpl new file mode 100644 index 0000000..05e0b5c --- /dev/null +++ b/fields/drop_down/tpl/field.tpl @@ -0,0 +1,11 @@ +{if $items} + +{else} +
        +
      • {#no_items#}
      • +
      +{/if} \ No newline at end of file diff --git a/fields/drop_down_key/field.php b/fields/drop_down_key/field.php new file mode 100644 index 0000000..9d442d5 --- /dev/null +++ b/fields/drop_down_key/field.php @@ -0,0 +1,130 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + switch ($action) + { + case 'edit': + $items = explode(',', $default); + $items = array_diff($items, array('')); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', trim($field_value)); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + if ($tpl_empty) + { + $key = (int)$field_value; + $items = explode(',', $default); + $items = array_diff($items, array('')); + $field_value = isset($items[$key]) + ? trim($items[$key]) + : ''; + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('key', $key); + $AVE_Template->assign('default', $default); + $AVE_Template->assign('field_value', $field_value); + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'req': + if ($tpl_empty) + { + $key = (int)$field_value; + $items = explode(',', $default); + $items = array_diff($items, array('')); + $field_value = isset($items[$key]) + ? trim($items[$key]) + : ''; + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('key', $key); + $AVE_Template->assign('default', $default); + $AVE_Template->assign('field_value', $field_value); + return $AVE_Template->fetch($tpl_file); + } + + $res = $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> diff --git a/fields/drop_down_key/lang/bg.txt b/fields/drop_down_key/lang/bg.txt new file mode 100644 index 0000000..968df74 --- /dev/null +++ b/fields/drop_down_key/lang/bg.txt @@ -0,0 +1,4 @@ +[admin] + +name = "Падащ списък (Ключ)" +no_items = "Не са зададени стойности по подразбиране" \ No newline at end of file diff --git a/fields/drop_down_key/lang/cz.txt b/fields/drop_down_key/lang/cz.txt new file mode 100644 index 0000000..0bf884b --- /dev/null +++ b/fields/drop_down_key/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Rozevírací seznam (klíč)" +no_items = "Neexistuje žádná výchozí hodnota" \ No newline at end of file diff --git a/fields/drop_down_key/lang/en.txt b/fields/drop_down_key/lang/en.txt new file mode 100644 index 0000000..80554ed --- /dev/null +++ b/fields/drop_down_key/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Dropdown list (Key)" +no_items = "No default value" \ No newline at end of file diff --git a/fields/drop_down_key/lang/pl.txt b/fields/drop_down_key/lang/pl.txt new file mode 100644 index 0000000..92a5a2e --- /dev/null +++ b/fields/drop_down_key/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Lista rozwijana (klucz)" +no_items = "Nie ma znaczenia domyślnego" \ No newline at end of file diff --git a/fields/drop_down_key/lang/ru.txt b/fields/drop_down_key/lang/ru.txt new file mode 100644 index 0000000..f68fdb5 --- /dev/null +++ b/fields/drop_down_key/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Выпадающий список (Ключ)" +no_items = "Нет значения по умолчанию" \ No newline at end of file diff --git a/fields/drop_down_key/lang/ua.txt b/fields/drop_down_key/lang/ua.txt new file mode 100644 index 0000000..4ea234a --- /dev/null +++ b/fields/drop_down_key/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Випадаючий список (Ключ)" +no_items = "Немає значення за замовчуванням" \ No newline at end of file diff --git a/fields/drop_down_key/tpl/field.tpl b/fields/drop_down_key/tpl/field.tpl new file mode 100644 index 0000000..5a0b6a9 --- /dev/null +++ b/fields/drop_down_key/tpl/field.tpl @@ -0,0 +1,12 @@ +{if $items} + +{else} +
        +
      • {#no_items#}
      • +
      +{/if} \ No newline at end of file diff --git a/fields/image_mega/css/field.css b/fields/image_mega/css/field.css new file mode 100644 index 0000000..4b3b6ca --- /dev/null +++ b/fields/image_mega/css/field.css @@ -0,0 +1,139 @@ +.mega { + position: relative; +} + + +.mega_left_block +{ + width: 128px; + display: inline-block; + position: relative; + padding-left: 10px; +} + +.mega_right_block +{ + width: 258px; + display: inline-block; + position: relative; + padding-left: 10px; +} + +.mega_link { + margin-top: 5px; + padding-left: 10px; +} + +.mega_link_input { + display: inline-block; + width: 230px; + height: 24px; + line-height: 24px; + border-radius: 3px; + border: 1px solid #eaeaea !important; + resize: none !important; + padding: 3px !important; + + -webkit-box-shadow: none !important; + -moz-box-shadow: none !important; + box-shadow: none !important; + + -webkit-box-sizing: border-box !important; + -moz-box-sizing: border-box !important; + box-sizing: border-box !important; +} + +.mega_item { + display: inline-block; + margin: 3px; + width: 400px; + height: 210px; + background-color: rgba(255, 255, 255, 0.5); + border: solid 1px #eaeaea; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; + position: relative; + text-align: left; +} + +.mega_item:hover { + background-color: rgba(255, 255, 255, 1.0); + border: solid 1px rgba(234, 234, 234, 0.5); + -webkit-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); +} + +.mega_item:hover > .header { + background-color: rgba(210, 210, 210, 0.3); +} + +.mega_item .header { + background-color: rgba(210, 210, 210, 0.5); + height: 26px; + cursor: move; + border-radius: 5px 5px 0 0; +} + +.mega_item .image { + background-color: #fcfcfc; + border: solid 1px #eaeaea; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.mega_item textarea { + display: inline-block; + width: 238px; + height: 60px; + margin-top: 10px; + border-radius: 3px; + border: 1px solid #eaeaea !important; + resize: none !important; + padding: 3px !important; + + -webkit-box-shadow: none !important; + -moz-box-shadow: none !important; + box-shadow: none !important; + + -webkit-box-sizing: border-box !important; + -moz-box-sizing: border-box !important; + box-sizing: border-box !important; +} + +.mega_item .view { + position: absolute; + top: 3px; + left: 3px; + cursor: pointer !important; +} + +.mega_item .delete { + position: absolute; + top: 3px; + right: 3px; + cursor: pointer !important; +} + +.mega_item .info { + position: absolute; + top: -5px; + right: -5px; + cursor: pointer !important; +} + +.mega_sortable > .ui-state-highlight { + display: inline-block; + margin: 5px; + width: 400px; + height: 210px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; +} \ No newline at end of file diff --git a/fields/image_mega/field.php b/fields/image_mega/field.php new file mode 100644 index 0000000..c26cd30 --- /dev/null +++ b/fields/image_mega/field.php @@ -0,0 +1,476 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + $iniset_count = ini_get('max_file_uploads'); + + switch ($action) + { + case 'edit': + + $items = array(); + $image_items = array(); + + if ($_REQUEST['action'] != 'new') + { + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $k => $v) + { + $image_item = explode('|', $v); + + $image[$k]['url'] = $image_item[0]; + $image[$k]['thumb'] = ($image_item[0] != '') + ? make_thumbnail(['size' => 't128x128', 'link' => $image_item[0]]) + : $img_pixel; + + $image[$k]['title'] = $image_item[1] ?? ''; + + $image[$k]['description'] = $image_item[2] ?? ''; + + $image[$k]['link'] = (isset($image_item[3])) + ? htmlspecialchars($image_item[3], ENT_QUOTES) + : ''; + } + + if (! empty($image)) + { + $image_items = $image; + } + } + } + + $show_upload = true; + + $default = explode('|', $default); + + if (count($default) > 1) + list ($path, $watermark, $position, $transparency) = $default; + else + { + list ($path) = $default; + $watermark = false; + $position = null; + $transparency = null; + } + + if (preg_match("/%id/i", $path)) + { + if ($_REQUEST['action'] != 'new') + { + $path_upload = trim(@str_replace('%id', $_REQUEST['Id'], $path), '/'); + $show_upload = true; + } + else + { + $path_upload = (! empty($path)) + ? trim($default, '/') + : ''; + + $show_upload = false; + } + } + else + { + $path_upload = (! empty($path)) + ? trim($path, '/') + : ''; + + $show_upload = true; + } + + $dir_upload = '/' . UPLOAD_DIR . '/' . ((! empty($path_upload)) + ? $path_upload . '/' + : ''); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + $AVE_Template->assign('max_files', $AVE_Template->get_config_vars('max_f_f') . $iniset_count); + $AVE_Template->assign('dir_upload', $AVE_Template->get_config_vars('upl_dir') . $dir_upload); + $AVE_Template->assign('dir_uploaded', $dir_upload); + $AVE_Template->assign('show_upload', $show_upload); + + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('images', $image_items); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + + $items = (isset($field_value)) + ? unserialize($field_value) + : []; + + $res = []; + + if ($items != false) + { + foreach ($items as $image_item) + { + $field_data = explode('|', clean_php($image_item)); + + if (! empty($field_data)) + { + if ($tpl_empty) + { + $image_item = array(); + + $image_item['url'] = $field_data[0]; + $image_item['title'] = isset($field_data[1]) ? $field_data[1] : ''; + $image_item['description'] = isset($field_data[2]) ? $field_data[2] : ''; + $image_item['link'] = isset($field_data[3]) ? $field_data[3] : ''; + + if (! empty($image_item['link'])) + $image_item['http'] = (preg_match('/^(http|https)/', $image_item['link']) ? true : false); + else + $image_item['http'] = false; + } + else + { + $image_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_data) + { + return $field_data[(int)$data[1]]; + }, + $tpl + ); + + $image_item = preg_replace_callback( + '/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function($m) { + return watermarks($m[1], $m[2], $m[3]); + }, + $image_item + ); + + $image_item = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $image_item); + } + } + + $res[] = $image_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'req': + $items = unserialize($field_value); + + $res = array(); + + if ($items != false) + { + foreach ($items as $image_item) + { + $field_data = explode('|', clean_php($image_item)); + + if (! empty($field_data)) + { + if ($tpl_empty) + { + $image_item = array(); + + $image_item['url'] = $field_data[0]; + $image_item['title'] = $field_data[1] ? $field_data[1] : ''; + $image_item['description'] = $field_data[2] ? $field_data[2] : ''; + $image_item['link'] = $field_data[3] ? $field_data[3] : ''; + + if (! empty($image_item['link'])) + $image_item['http'] = (preg_match('/^(http|https)/', $image_item['link']) ? true : false); + else + $image_item['http'] = false; + } + else + { + $image_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + static function($data) use($field_data) + { + return $field_data[(int)$data[1]]; + }, + $tpl + ); + $image_item = preg_replace_callback( + '/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function($m) { + return watermarks($m[1], $m[2], $m[3]); + }, + $image_item + ); + + $image_item = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $image_item); + } + } + + $res[] = $image_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'save': + if (is_array($field_value)) + { + foreach ($field_value as $v) + { + if (! empty($v['url'])) + { + + $field_value_new[] = $v['url'] + . ($v['title'] ? '|' . stripslashes(htmlspecialchars($v['title'], ENT_QUOTES)) : '|') + . ($v['description'] ? '|' . stripslashes(htmlspecialchars($v['description'], ENT_QUOTES)) : '|') + . ($v['link'] ? '|' . ltrim($v['link'], '/') : '|'); + } + } + } + + if (isset($field_value_new)) + return serialize($field_value_new); + else + return $field_value_new = ''; + + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = []; + + if (! empty($field_value)) + { + $images = unserialize($field_value); + + if (! $images) + return false; + + foreach ($images AS $k => $v) + { + $_item = explode('|', $v); + + $items[$k] = [ + 'url' => $_item[0], + 'title' => (isset($_item[1]) ? $_item[1] : ''), + 'description' => (isset($_item[2]) ? $_item[2] : ''), + 'link' => (isset($_item[3]) ? $_item[3] : '') + ]; + } + } + + return $items; + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + + case 'upload': + $error = false; + + $search = []; + $replace = []; + + $files_input = 'mega_files' . '_' . $_REQUEST['field_id'] . '_' . $_REQUEST['doc_id']; + + $search[] = '%d'; + $replace[] = date('d'); + $search[] = '%m'; + $replace[] = date('m'); + $search[] = '%Y'; + $replace[] = date('Y'); + + $default = explode('|', $default); + + list($path_upload, $watermark, $position, $transparency) = $default; + + if (! empty($path_upload)) + $path_upload = str_replace($search, $replace, $path_upload); + + if(preg_match("/%id/i", $path_upload)) + { + $path = trim(@str_replace('%id', $_REQUEST['doc_id'], $path_upload), '/'); + } + else + { + $path = (! empty($path_upload)) + ? $path_upload + : ''; + } + + if (! function_exists('getExtension')) + { + function getExtension($file) + { + $file = pathinfo($file); + return $file['extension']; + } + } + + $valid_formats = array("jpg", "png", "gif", "bmp", "jpeg", "webp"); + + $dir = '/' . UPLOAD_DIR . '/' . ((! empty($path)) + ? trim($path, '/') . '/' + : ''); + + $dir_abs = BASE_DIR . $dir; + + if (!is_dir($dir_abs) && !mkdir($dir_abs, 0777, true) && !is_dir($dir_abs)) { + throw new \RuntimeException(sprintf('Directory "%s" was not created', $dir_abs)); + } + + $new_files = []; + $thumbs = []; + + foreach ($_FILES[$files_input]['name'] as $name => $value) + { + $filename = strtolower(stripslashes(prepare_url($_FILES[$files_input]['name'][$name]))); + + $ext = getExtension($filename); + $ext = strtolower($ext); + + if (in_array($ext, $valid_formats)) + { + if (file_exists($dir_abs . $filename)) + { + $filename = rand(1000, 9999) . '_' . $filename; + } + + if (@move_uploaded_file($_FILES[$files_input]['tmp_name'][$name], $dir_abs . $filename)) + { + $new_files[] = $filename; + + $thumbs[] = make_thumbnail(array('link' => $dir . $filename, 'size' => 't128x128')); + + if ((bool)$watermark) + { + $position = ($position != '') ? $position : 'center'; + $transparency = ($transparency != '') ? $transparency : '50'; + + watermarks($dir . $filename, $position, $transparency); + } + + $error = false; + } + else + { + $error = true; + } + } + else + { + $error = true; + @unlink($_FILES[$files_input]['tmp_name'][$name]); + } + } + + if ($error !== true) + { + echo json_encode(array( + 'files' => $new_files, + 'thumbs' => $thumbs, + 'dir' => $dir, + 'respons' => 'success', + 'message' => $AVE_Template->get_config_vars('resp_s_m'), + 'header' => $AVE_Template->get_config_vars('resp_s_h'), + 'theme' => 'accept' + ) + ); + } + else + { + echo json_encode(array( + 'respons' => 'error', + 'message' => $AVE_Template->get_config_vars('resp_e_m'), + 'header' => $AVE_Template->get_config_vars('resp_e_h'), + 'theme' => 'error' + ) + ); + } + + exit; + } + + return $res ?: $field_value; + } +?> \ No newline at end of file diff --git a/fields/image_mega/js/field.js b/fields/image_mega/js/field.js new file mode 100644 index 0000000..de1fdd4 --- /dev/null +++ b/fields/image_mega/js/field.js @@ -0,0 +1,303 @@ +let Mega = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.mega(); + }, + + mega: function() { + this.mega_sortable(); + this.mega_del_item(); + this.mega_del_all_item(); + this.mega_add_single(); + this.mega_add_folder(); + this.mega_upload_files(); + this.mega_click_upload(); + }, + + mega_update: function() { + this.mega_maxid(); + this.mega_del_item(); + AveAdmin.fancy_box(); + AveAdmin.tooltip(); + }, + + mega_maxid: function(id, doc) { + let maxid = 1; + + $('#mega_' + doc + '_' + id).children('.mega_sortable').children('.mega_item').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + + return maxid; + }, + + mega_del_item: function() { + $('.mega_item .delete').on('click', function(event) { + event.preventDefault(); + let id = $(this).attr('data-id'); + jConfirm( + mega_del_conf, + mega_del_head, + function(b) { + if (b) { + $('#mega_image_' + id).remove(); + } + } + ); + }); + }, + + mega_del_all_item: function() { + $('.mega_del_all').on('click', function(event) { + event.preventDefault(); + let c_id = $(this).parent().parent().parent('.mega').attr("data-id"); + let d_id = $(this).parent().parent().parent('.mega').attr("data-doc"); + + let empty_input = ''; + + jConfirm( + mega_del_all_c, + mega_del_all_h, + function(b) { + if (b) { + $('#mega_' + d_id + '_' + c_id).children('.mega_sortable').children('.mega_item').each(function() { + $(this).remove(); + }); + $('#mega_' + d_id + '_' + c_id).append(empty_input); + } + } + ); + }); + }, + + mega_upload_files: function() { + $('.mega_upload').on('change', function(event) { + + let mega_input = $(this); + + let iid; + + event.preventDefault(); + + if (mega_input.val() == '') { + return false; + } + + let files_input = this.files.length; + let max_files = mega_input.attr("data-max-files"); + + if (files_input > max_files) { + $.jGrowl(mega_max_f_t, { + header: mega_max_f_h, + theme: 'error' + }); + + mega_input.replaceWith(mega_input.val('').clone(true)); + + return false; + } + + let c_id = $(this).parent('.mega').attr("data-id"); + let d_id = $(this).parent('.mega').attr("data-doc"); + let r_id = $(this).parent('.mega').attr("data-rubric"); + + $('#formDoc').ajaxSubmit({ + url: 'index.php?do=fields', + data: { + "field_id": c_id, + "rubric_id": r_id, + "doc_id": d_id, + "field": 'image_mega', + "type": 'upload' + }, + beforeSend: function() { + $.alerts._overlay('show'); + }, + dataType: "JSON", + success: function(data) { + if (data['respons'] == 'success') { + for (let p = 0, max = data.files.length; p < max; p++) { + + iid = Mega.mega_maxid(c_id, d_id); + let field_value = data['dir'] + data.files[p]; + let img_path = data.thumbs[p]; + + $('#mega_' + d_id + '_' + c_id + ' > .mega_sortable:last').append( + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '
      ' + ); + + $('#empty' + d_id + '_' + c_id ).remove(); + + $('#mega_upload_field_' + c_id + '_' + d_id).val(''); + + $.alerts._overlay('hide'); + + Mega.mega_update(); + } + } + + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + + mega_input.replaceWith(mega_input = mega_input.clone(true)); + mega_input.val(); + } + }); + return false; + }); + }, + + mega_click_upload: function() { + $('.mega_upload_local').on('click', function(event) { + event.preventDefault(); + + let c_id = $(this).parent().parent().parent('.mega').attr("data-id"); + let d_id = $(this).parent().parent().parent('.mega').attr("data-doc"); + + $('.mega_upload_field_' + c_id + '_' + d_id).trigger('click'); + }); + }, + + mega_add_single: function() { + $('.mega_add_single').on('click', function(event) { + event.preventDefault(); + + let c_id = $(this).parent().parent().parent('.mega').attr("data-id"); + let d_id = $(this).parent().parent().parent('.mega').attr("data-doc"); + let iid = Mega.mega_maxid(c_id, d_id); + + $('#mega_' + d_id + '_' + c_id + ' > .mega_sortable:last').prepend( + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '
      ' + ); + + browse_uploads('image__' + c_id + '_' + d_id + '_' + iid + ''); + + $('#empty' + d_id + '_' + c_id ).remove(); + + $('#mega_upload_field_' + c_id + '_' + d_id).val(''); + + Mega.mega_update(); + }); + }, + + mega_sortable: function() { + $('.mega_sortable').sortable({ + handle: ".header", + placeholder: "ui-state-highlight grey_bg" + }); + //$(".mega").disableSelection(); + }, + + mega_add_folder: function() { + $('.mega_add_folder').on('click', function(event) { + event.preventDefault(); + + var c_id = $(this).parent().parent().parent('.mega').attr("data-id"); + var d_id = $(this).parent().parent().parent('.mega').attr("data-doc"); + + browse_dirs("cascad__" + c_id + '_' + d_id); + }); + } +}; + +$(document).ready(function() { + Mega.init(); + + $.fn.myPlugin = function mega_add_items(dir, c_id, d_id) { + + $.ajax({ + url: ave_path + 'admin/index.php?do=docs&action=image_import&ajax=run', + data: { + "path": dir + }, + dataType: "JSON", + success: function(data) { + $.alerts._overlay('hide'); + for (let p = 0, max = data.respons.length; p < max; p++) { + let iid = Mega.mega_maxid(c_id, d_id); + let field_value = dir + data.respons[p]; + let img_path = '../index.php?thumb=' + field_value + '&mode=f&width=128&height=128'; + + $('#mega_' + d_id + '_' + c_id + ' > .mega_sortable:last').prepend( + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '' + + '
      ' + + '
      ' + + '' + + '
      ' + ); + + Mega.mega_update(); + } + } + }); + } + +}); \ No newline at end of file diff --git a/fields/image_mega/lang/bg.txt b/fields/image_mega/lang/bg.txt new file mode 100644 index 0000000..57b02f9 --- /dev/null +++ b/fields/image_mega/lang/bg.txt @@ -0,0 +1,30 @@ +[admin] +name = "Изображение (Mega)" +look = "Преглед" +select = "Избор на изображение" +delete = "Изтриване на елемент от каскадата" +del_conf = "Сигурни ли сте, че желаете да изтриете този елемент?
      (Изображението няма да бъде изтрито от сървъра) +del_head = "Удаление элемента каскада..." +add_n_e = "Добави нов елемент:" +add_f = "Избор на изображение" +add_d = "Избор на папка" +add_l = "Качи от компютъра" +add_upl_e = "Вие може за заредите изображения от локален компютър след създаването на документа. За това натиснете бутона по долу «Добави и продължи редактирането»" +upl_dir = "Папка: " +del_all = "Изтриване на всички елементи" +del_all_c = "Сигурни ли сте, че желаете да изтриете всички елементи?
      (Изображенията няма да бъдат изтрити от сървъра) +del_all_h = "Изтриване на всички елементи на каскадата..." +resp_s_h = "Изпълнено" +resp_s_m = "Файловете са успешно заредени" +resp_e_m = "Възникна грешка при зареждането на файловете. Моля, опитайте отново." +resp_e_h = "Грешка" +resp_m_m = "Броя на файловете за зареждане са повече от максималния, зададен в настройките на PHP." +resp_m_h = "Грешка" +max_f_f = "Максимален брой файлове за зареждане: " +max_f_h = "Грешка" +max_f_t = "Превишен е максималния брой файлове,
      разрешен за едновременно зареждане" +img_title = "Заглавие" +img_description = "Описание" +img_link = "Линк" +from_file = "Файл" +from_docs = "Документ" \ No newline at end of file diff --git a/fields/image_mega/lang/pl.txt b/fields/image_mega/lang/pl.txt new file mode 100644 index 0000000..a8f1cb3 --- /dev/null +++ b/fields/image_mega/lang/pl.txt @@ -0,0 +1,30 @@ +[admin] +name = "Obrazek (Mega)" +look = "Подивитися" +select = "Вибрати зображення" +delete = "Видалити елемент каскада" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент?
      (зі сервера зображення видалене не буде)" +del_head = "Видалення елемента каскада..." +add_n_e = "Додати новий елемент:" +add_f = "Вибрати зображення" +add_d = "Вибрати папку" +add_l = "Завантажити з комп’ютера" +add_upl_e = "Ви зможете завантажити фотографії з локального комп’ютера після створення документа. Для цього натисніть внизу кнопку “Додати та продовжити редагування”" +upl_dir = "Папка: " +del_all = "Видалити усі елементи" +del_all_c = "Ви впевнені, що бажаєте видалити всі елементи?
      (зі сервера зображення видалене не буде)" +del_all_h = "Видалення всіх елементів каскада..." +resp_s_h = "Виконано" +resp_s_m = "Файли успішно завантажилися" +resp_e_m = "Сталася помилка при завантаженні файлів. Спробуйте ще раз." +resp_e_h = "Помилка" +resp_m_m = "Кіл-ть файлів для завантаження перевищує значення, яке вказане у налаштуваннях PHP." +resp_m_h = "Помилка" +max_f_f = "Максимальна кіль-ть файлів, що завантажуються: " +max_f_h = "Помилка" +max_f_t = "Перевищено максимальне число файлів,
      для одночасного завантаженння" +img_title = "Заголовок" +img_description = "Опис" +img_link = "Посилання" +from_file = "Файл" +from_docs = "Документ" \ No newline at end of file diff --git a/fields/image_mega/lang/ru.txt b/fields/image_mega/lang/ru.txt new file mode 100644 index 0000000..1f496fa --- /dev/null +++ b/fields/image_mega/lang/ru.txt @@ -0,0 +1,30 @@ +[admin] +name = "Изображение (Mega)" +look = "Посмотреть" +select = "Выбрать изображение" +delete = "Удалить элемент каскада" +del_conf = "Вы уверены, что хотите удалить данный элемент?
      (Изображение не будет удалено с сервера)" +del_head = "Удаление элемента каскада..." +add_n_e = "Добавить новый элемент:" +add_f = "Выбрать изображение" +add_d = "Выбрать папку" +add_l = "Загрузить с компьютера" +add_upl_e = "Вы сможете загрузить фотографии с локального компьютера после создания документа. Для этого нажмите внизу кнопку «Добавить и продолжить редактирование»" +upl_dir = "Папка: " +del_all = "Удалить все элементы" +del_all_c = "Вы уверены, что хотите удалить все элементы?
      (Изображения не будет удалены с сервера)" +del_all_h = "Удаление всех элемента каскада..." +resp_s_h = "Выполнено" +resp_s_m = "Файлы успешно загрузились" +resp_e_m = "Возникла ошибка при загрузке файлов. Попробуйте еще раз." +resp_e_h = "Ошибка" +resp_m_m = "Кол-во загружаемых файлов превышает значение, заданное в настройках PHP." +resp_m_h = "Ошибка" +max_f_f = "Макимальное кол-во загружаемых файлов: " +max_f_h = "Ошибка" +max_f_t = "Превышено максимальное число файлов,
      для одновременной загрузки" +img_title = "Заголовок" +img_description = "Описание" +img_link = "Ссылка" +from_file = "Файл" +from_docs = "Документ" \ No newline at end of file diff --git a/fields/image_mega/lang/ua.txt b/fields/image_mega/lang/ua.txt new file mode 100644 index 0000000..6b5ffef --- /dev/null +++ b/fields/image_mega/lang/ua.txt @@ -0,0 +1,30 @@ +[admin] +name = "Зображення (Mega)" +look = "Подивитися" +select = "Вибрати зображення" +delete = "Видалити елемент каскада" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент?
      (зі сервера зображення видалене не буде)" +del_head = "Видалення елемента каскада..." +add_n_e = "Додати новий елемент:" +add_f = "Вибрати зображення" +add_d = "Вибрати папку" +add_l = "Завантажити з комп’ютера" +add_upl_e = "Ви зможете завантажити фотографії з локального комп’ютера після створення документа. Для цього натисніть внизу кнопку “Додати та продовжити редагування”" +upl_dir = "Папка: " +del_all = "Видалити усі елементи" +del_all_c = "Ви впевнені, що бажаєте видалити всі елементи?
      (зі сервера зображення видалене не буде)" +del_all_h = "Видалення всіх елементів каскада..." +resp_s_h = "Виконано" +resp_s_m = "Файли успішно завантажилися" +resp_e_m = "Сталася помилка при завантаженні файлів. Спробуйте ще раз." +resp_e_h = "Помилка" +resp_m_m = "Кіл-ть файлів для завантаження перевищує значення, яке вказане у налаштуваннях PHP." +resp_m_h = "Помилка" +max_f_f = "Максимальна кіль-ть файлів, що завантажуються: " +max_f_h = "Помилка" +max_f_t = "Перевищено максимальне число файлів,
      для одночасного завантаженння" +img_title = "Заголовок" +img_description = "Опис" +img_link = "Посилання" +from_file = "Файл" +from_docs = "Документ" \ No newline at end of file diff --git a/fields/image_mega/tpl/field-doc.tpl b/fields/image_mega/tpl/field-doc.tpl new file mode 100644 index 0000000..da7baa7 --- /dev/null +++ b/fields/image_mega/tpl/field-doc.tpl @@ -0,0 +1,46 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$ABS_PATH} Абсолютный путь + +{$field_id} ID поля +{$field_value} Данные поля (массив) +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +FOREACH +$image.url Адрес изображения +$image.title Заголовок +$image.description Описание +$image.link Ссылка +$image.http Есть ли в ссылке http или https (true/false) + +Пример вывода: +{if isset($image.title) && $image.title != ''}{$image.title}{/if} + +Можно использовать тег, для формирования миниатюры +[tag:X000x000:{$image.url}] +----------------------------------------------------------- +*} + +{foreach from=$field_value key=key item=image} +
      + {if isset($image.link) && $image.link != ''} + {if $image.http} + + {else} + + {/if} + {/if} + {if isset($image.title) && $image.title != ''}{$image.title}{/if} + {if isset($image.link)} + + {/if} + {if isset($image.description) && $image.description != ''} +

      + {$image.description|html_entity_decode} +

      + {/if} +
      +{/foreach} \ No newline at end of file diff --git a/fields/image_mega/tpl/field-req.tpl b/fields/image_mega/tpl/field-req.tpl new file mode 100644 index 0000000..cc5c33f --- /dev/null +++ b/fields/image_mega/tpl/field-req.tpl @@ -0,0 +1,46 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$ABS_PATH} Абсолютный путь + +{$field_id} ID поля +{$field_value} Данные поля (массив) +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +FOREACH +$image.url Адрес изображения +$image.title Заголовок +$image.description Описание +$image.link Ссылка +$image.http Есть ли в ссылке http или https (true/false) + +Пример вывода: +{if isset($image.title) && $image.title != ''}{$image.title}{/if} + +Можно использовать тег, для формирования миниатюры +[tag:X000x000:{$image.url}] +----------------------------------------------------------- +*} + +{foreach from=$field_value key=key item=image} +
      + {if isset($image.link) && $image.link != ''} + {if $image.http} + + {else} + + {/if} + {/if} + {if isset($image.title) && $image.title != ''}{$image.title}{/if} + {if isset($image.link)} + + {/if} + {if isset($image.description) && $image.description != ''} +

      + {$image.description} +

      + {/if} +
      +{/foreach} \ No newline at end of file diff --git a/fields/image_mega/tpl/field.tpl b/fields/image_mega/tpl/field.tpl new file mode 100644 index 0000000..04717b3 --- /dev/null +++ b/fields/image_mega/tpl/field.tpl @@ -0,0 +1,83 @@ +{if $mega_new != 'load'} + {assign var=mega_new value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=mega_new value="load" scope="global"} +{/if} + +
      + + {if $show_upload} + + {/if} + + +
      + {foreach from=$images key=key item=image} + +
      +
      + + +
      +
      + + + +
      +
      + + +
      +
      + +
      + + {/foreach} +
      + +
      \ No newline at end of file diff --git a/fields/image_multi/css/field.css b/fields/image_multi/css/field.css new file mode 100644 index 0000000..432acf1 --- /dev/null +++ b/fields/image_multi/css/field.css @@ -0,0 +1,97 @@ +.cascad { + position: relative; +} + +.cascad_item { + display: inline-block; + margin: 3px; + width: 120px; + height: 216px; + background-color: rgba(255, 255, 255, 0.5); + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; +} + +.cascad_item:hover { + background-color: rgba(255, 255, 255, 1.0); + border: solid 1px rgba(234, 234, 234, 0.5); + -webkit-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); +} + +.cascad_item:hover > .header { + background-color: rgba(210, 210, 210, 0.3); +} + +.cascad_item .header { + background-color: rgba(210, 210, 210, 0.5); + height: 26px; + margin-bottom: 10px; + cursor: move; + border-radius: 5px 5px 0 0; +} + +.cascad_item .image { + background-color: #fcfcfc; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.cascad_item textarea { + display: inline-block; + width: 100px; + height: 60px; + margin-top: 10px; + border-radius: 0 0 2px 2px; + border: 1px solid #eaeaea !important; + resize: none !important; + box-shadow: none !important; + -webkit-box-shadow: none !important; + -moz-box-shadow: none !important; + padding: 3px !important; + box-sizing: border-box !important; + -webkit-box-sizing: border-box !important; + -moz-box-sizing: border-box !important; +} + +.cascad_item .view { + position: absolute; + top: 3px; + left: 3px; + cursor: pointer !important; +} + +.cascad_item .delete { + position: absolute; + top: 3px; + right: 3px; + cursor: pointer !important; +} + +.cascad_item .info { + position: absolute; + top: 30px; + right: 3px; + cursor: pointer !important; +} + +.cascad_sortable > .ui-state-highlight { + display: inline-block; + margin: 5px; + width: 120px; + height: 200px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; +} \ No newline at end of file diff --git a/fields/image_multi/field.php b/fields/image_multi/field.php new file mode 100644 index 0000000..888da31 --- /dev/null +++ b/fields/image_multi/field.php @@ -0,0 +1,423 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + $iniset_count = ini_get('max_file_uploads'); + + switch ($action) + { + case 'edit': + + $items = array(); + $image_items = array(); + + if ($_REQUEST['action'] != 'new') + { + $items = unserialize($field_value); + + if($items != false) + { + foreach($items as $k => $v) + { + $image_item = explode('|', $v); + + $img = $image_item[0]; + unset($image_item[0]); + $image_item = array($img, implode('|', $image_item)); + + $image[$k]['url'] = $image_item[0]; + $image[$k]['thumb'] = ($image_item[0] != '') + ? make_thumbnail(array('size' => 'f100x100', 'link' => $image_item[0])) + : $img_pixel; + + $image[$k]['desc'] = (isset($image_item[1])) + ? htmlspecialchars($image_item[1], ENT_QUOTES) + : ''; + } + + if (! empty($image)) + { + $image_items = $image; + } + } + } + + $show_upload = true; + + $default = explode('|', $default); + + list($path, $watermark, $position, $transparency) = $default; + + if(preg_match("/%id/i", $path)) + { + if ($_REQUEST['action'] != 'new') + { + $path_upload = trim(@str_replace('%id', $_REQUEST['Id'], $path), '/'); + $show_upload = true; + } + else + { + $path_upload = (! empty($path)) + ? trim($path, '/') + : ''; + + $show_upload = false; + } + } + else + { + $path_upload = (! empty($path)) + ? $path + : ''; + + $show_upload = true; + } + + $dir_upload = '/' . UPLOAD_DIR . '/' . ((!empty($path_upload)) + ? $path_upload . '/' + : ''); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + $AVE_Template->assign('max_files', $AVE_Template->get_config_vars('max_f_f') . $iniset_count); + $AVE_Template->assign('dir_upload', $AVE_Template->get_config_vars('upl_dir') . $dir_upload); + $AVE_Template->assign('show_upload', $show_upload); + + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('images', $image_items); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + + $items = (isset($field_value)) + ? unserialize($field_value) + : array(); + + $res = array(); + + if ($items != false) + { + foreach ($items as $image_item) + { + $image_item = clean_php($image_item); + $field_param = explode('|', $image_item); + + if ($image_item) + { + if ($tpl_empty) + { + $image_item = $field_param; + } + else + { + $image_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + + $image_item = preg_replace_callback( + '/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function($m) { + return watermarks($m[1], $m[2], $m[3]); + }, + $image_item + ); + + $image_item = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $image_item); + } + } + + $res[] = $image_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'req': + $items = unserialize($field_value); + + $res = array(); + + if ($items != false) + { + foreach ($items as $image_item) + { + $image_item = clean_php($image_item); + $field_param = explode('|', $image_item); + + if ($image_item) + { + if ($tpl_empty) + { + $image_item = $field_param; + } + else + { + $image_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + + $image_item = preg_replace_callback( + '/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function($m) { + return watermarks($m[1], $m[2], $m[3]); + }, + $image_item + ); + + $image_item = preg_replace_callback('/\[tag:([r|c|f]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $image_item); + } + } + + $res[] = $image_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'save': + foreach ($field_value as $v) + { + if (! empty($v['url'])) + { + $field_value_new[] = $v['url'] . ($v['descr'] ? '|' . $v['descr'] : ''); + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = []; + + if (! empty($field_value)) + { + $images = unserialize($field_value); + + if (! $images) + return false; + + foreach ($images AS $k => $v) + { + $_item = explode('|', $v); + + $items[$k] = [ + 'url' => $_item[0], + 'descr' => (isset($_item[1]) ? $_item[2] : ''), + ]; + } + } + + return $items; + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + + case 'upload': + $error = false; + + $search = array(); + $replace = array(); + + $files_unput = 'cascade_files'.'_'.$_REQUEST['field_id'].'_'.$_REQUEST['doc_id']; + + $search[] = '%d'; + $replace[] = date('d'); + $search[] = '%m'; + $replace[] = date('m'); + $search[] = '%Y'; + $replace[] = date('Y'); + + $default = explode('|', $default); + + list($path_upload, $watermark, $position, $transparency) = $default; + + if (! empty($path_upload)) + $path_upload = str_replace($search, $replace, $path_upload); + + if(preg_match("/%id/i", $path_upload)) + { + $path = trim(@str_replace('%id', $_REQUEST['doc_id'], $path_upload), '/'); + } + else + { + $path = (! empty($path_upload)) + ? $path_upload + : ''; + } + + if (! function_exists('getExtension')) { + function getExtension($file) + { + $file = pathinfo($file); + return $file['extension']; + } + } + + $valid_formats = array("jpg", "png", "gif", "bmp","jpeg", "webp"); + + $dir = '/' . UPLOAD_DIR . '/' . ((! empty($path)) + ? trim($path, '/') . '/' + : ''); + + $dir_abs = BASE_DIR . $dir; + + if (! is_dir($dir_abs)) + @mkdir($dir_abs, 0777, true); + + foreach ($_FILES[$files_unput]['name'] as $name => $value) + { + $filename = strtolower(stripslashes(prepare_url($_FILES[$files_unput]['name'][$name]))); + + $ext = getExtension($filename); + $ext = strtolower($ext); + + if(in_array($ext, $valid_formats)) + { + if (file_exists($dir_abs . $filename)) + { + $filename = rand(1000, 9999) . '_' . $filename; + } + + if (@move_uploaded_file($_FILES[$files_unput]['tmp_name'][$name], $dir_abs . $filename)) + { + $new_files[] = $filename; + $error = false; + + if ((bool)$watermark) + { + $position = ($position != '') ? $position : 'center'; + $transparency = ($transparency != '') ? $transparency : '100'; + + watermarks($dir . $filename, $position, $transparency); + } + } + else + { + $error = true; + } + } + else + { + $error = true; + @unlink($_FILES[$files_unput]['tmp_name'][$name]); + } + } + + if ($error !== true) + { + echo json_encode(array( + 'files' => $new_files, + 'dir' => $dir, + 'respons' => 'succes', + 'message' => $AVE_Template->get_config_vars('resp_s_m'), + 'header' => $AVE_Template->get_config_vars('resp_s_h'), + 'theme' => 'accept' + ) + ); + } + else + { + echo json_encode(array( + 'respons' => 'error', + 'message' => $AVE_Template->get_config_vars('resp_e_m'), + 'header' => $AVE_Template->get_config_vars('resp_e_h'), + 'theme' => 'error' + ) + ); + } + + exit; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/image_multi/js/field.js b/fields/image_multi/js/field.js new file mode 100644 index 0000000..1d60ed6 --- /dev/null +++ b/fields/image_multi/js/field.js @@ -0,0 +1,229 @@ +var Cascad = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.cascad(); + }, + + cascad: function() { + this.cascad_sortable(); + this.cascad_del_item(); + this.cascad_del_all_item(); + this.cascad_add_single(); + this.cascad_add_folder(); + this.cascade_upload_files(); + this.cascad_click_upload(); + }, + + cascad_update: function() { + this.cascad_maxid(); + this.cascad_del_item(); + AveAdmin.fancy_box(); + AveAdmin.tooltip(); + }, + + cascad_maxid: function(id, doc) { + var maxid = 1; + $('#cascad_' + doc + '_' + id).children('.cascad_sortable').children('.cascad_item').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + cascad_del_item: function() { + $('.cascad_item .delete').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + del_conf, + del_head, + function(b) { + if (b) { + $('#cascad_image_' + id).remove(); + } + } + ); + }); + }, + + cascad_del_all_item: function() { + $('.del_all').on('click', function(event) { + event.preventDefault(); + var c_id = $(this).parent().parent().parent('.cascad').attr("data-id"); + var d_id = $(this).parent().parent().parent('.cascad').attr("data-doc"); + jConfirm( + del_all_c, + del_all_h, + function(b) { + if (b) { + $('#cascad_' + d_id + '_' + c_id).children('.cascad_sortable').children('.cascad_item').each(function() { + $(this).remove(); + }); + } + } + ); + }); + }, + + cascade_upload_files: function() { + $('.cascade_upload').on('change', function(event) { + + var cascade_input = $(this); + + event.preventDefault(); + + if (cascade_input.val() == '') { + return false; + } + + var files_input = this.files.length; + var max_files = cascade_input.attr("data-max-files"); + + if (files_input > max_files) { + $.jGrowl(max_f_t, { + header: max_f_h, + theme: 'error' + }); + + cascade_input.replaceWith(cascade_input.val('').clone(true)); + + return false; + } + + var cid = $(this).parent('.cascad').attr("data-id"); + var did = $(this).parent('.cascad').attr("data-doc"); + var rid = $(this).parent('.cascad').attr("data-rubric"); + + $('#formDoc').ajaxSubmit({ + url: 'index.php?do=fields', + data: { + "field_id": cid, + "rubric_id": rid, + "doc_id": did, + "field": 'image_multi', + "type": 'upload' + }, + beforeSend: function() { + $.alerts._overlay('show'); + }, + dataType: "json", + success: function(data) { + if (data['respons'] == 'succes') { + for (var p = 0, max = data.files.length; p < max; p++) { + iid = Cascad.cascad_maxid(cid, did); + var field_value = data['dir'] + data.files[p]; + var img_path = '../index.php?thumb=' + field_value + '&mode=f&width=128&height=128'; + $('#cascad_' + did + '_' + cid + ' > .cascad_sortable:last').prepend( + '
      ' + + '
      ' + + '' + + '' + + '' + + '' + + '' + + '' + + '
      ' + ); + $.alerts._overlay('hide'); + Cascad.cascad_update(); + } + } + $.jGrowl(data['message'], { + header: data['header'], + theme: data['theme'] + }); + cascade_input.replaceWith(cascade_input = cascade_input.clone(true)); + cascade_input.val(); + } + }); + return false; + }); + }, + + cascad_click_upload: function() { + $('.upload_local').on('click', function(event) { + event.preventDefault(); + var c_id = $(this).parent().parent().parent('.cascad').attr("data-id"); + var d_id = $(this).parent().parent().parent('.cascad').attr("data-doc"); + $('.cascade_upload_field_' + c_id + '_' + d_id).trigger('click'); + }); + }, + + cascad_add_single: function() { + $('.add_single').on('click', function(event) { + event.preventDefault(); + var c_id = $(this).parent().parent().parent('.cascad').attr("data-id"); + var d_id = $(this).parent().parent().parent('.cascad').attr("data-doc"); + var iid = Cascad.cascad_maxid(c_id, d_id); + $('#cascad_' + d_id + '_' + c_id + ' > .cascad_sortable:last').prepend( + '
      ' + + '
      ' + + '' + + '' + + '' + + '' + + '' + + '
      ' + ); + browse_uploads('image__' + c_id + '_' + d_id + '_' + iid + ''); + Cascad.cascad_update(); + }); + }, + + cascad_sortable: function() { + $('.cascad_sortable').sortable({ + handle: ".header", + placeholder: "ui-state-highlight grey_bg" + }); + //$(".cascad").disableSelection(); + }, + + cascad_add_folder: function() { + $('.add_folder').on('click', function(event) { + event.preventDefault(); + var c_id = $(this).parent().parent().parent('.cascad').attr("data-id"); + var d_id = $(this).parent().parent().parent('.cascad').attr("data-doc"); + browse_dirs("cascad__" + c_id + '_' + d_id); + }); + } +}; + +$(document).ready(function() { + Cascad.init(); + + $.fn.myPlugin = function cascad_add_items(dir, cid, did) { + + $.ajax({ + url: ave_path + 'admin/index.php?do=docs&action=image_import&ajax=run', + data: { + "path": dir + }, + dataType: "json", + success: function(data) { + $.alerts._overlay('hide'); + for (var p = 0, max = data.respons.length; p < max; p++) { + var iid = Cascad.cascad_maxid(cid, did); + var field_value = dir + data.respons[p]; + var img_path = '../index.php?thumb=' + field_value + '&mode=f&width=128&height=128'; + $('#cascad_' + did + '_' + cid + ' > .cascad_sortable:last').prepend( + '
      ' + + '
      ' + + '' + + '' + + '' + + '' + + '' + + '' + + '
      ' + ); + Cascad.cascad_update(); + } + } + }); + } + +}); \ No newline at end of file diff --git a/fields/image_multi/lang/bg.txt b/fields/image_multi/lang/bg.txt new file mode 100644 index 0000000..0bc6828 --- /dev/null +++ b/fields/image_multi/lang/bg.txt @@ -0,0 +1,27 @@ +[admin] +name = "Изображение (Каскада)" +look = "Преглед" +link = "Промени пътя" +select = "Избери изображение" +delete = "Изтриване на елелемт от элемент каскадата" +place = "Описание" +del_conf = "Сигурни ли сте, че желаете да изтриете този елемент?
      (Изображението няма да бъде изтрито от сървъра)" +del_head = "Изтриване на елемент от каскадата..." +add_n_e = "Добави нов елемент:" +add_f = "Избор на изображение" +add_d = "Избор на папка" +add_l = "Качи от компютъра" +add_upl_e = "Вие може за заредите изображения от локален компютър след създаването на документа. За това натиснете бутона по долу «Добави и продължи редактирането»" +upl_dir = "Папка: " +del_all = "Изтриване на всички елементи" +del_all_c = "Сигурни ли сте, че желаете да изтриете всички елементи?
      (Изображенията няма да бъдат изтрити от сървъра)" +del_all_h = "Изтриване на всички елементи на каскадата..." +resp_s_h = "Изпълнено" +resp_s_m = "Файловете са успешно заредени" +resp_e_m = "Възникна грешка при зареждането на файловете. Моля, опитайте отново." +resp_e_h = "Грешка" +resp_m_m = "Броя на файловете за зареждане са повече от максималния, зададен в настройките на PHP." +resp_m_h = "Грешка" +max_f_f = "Максимален брой файлове за зареждане: " +max_f_h = "Грешка" +max_f_t = "Превишен е максималния брой файлове,
      разрешен за едновременно зареждане" \ No newline at end of file diff --git a/fields/image_multi/lang/cz.txt b/fields/image_multi/lang/cz.txt new file mode 100644 index 0000000..b401190 --- /dev/null +++ b/fields/image_multi/lang/cz.txt @@ -0,0 +1,27 @@ +[admin] +name = "Zobrazení (Kaskádové)" +look = "Zobrazit" +link = "Změnit cestu" +select = "Vybrat zobrazení" +delete = "Smazat prvek kaskády" +place = "Popis" +del_conf = "Opravdu chcete odstranit tento prvek?
      (Zobrazení nebude smazáno ze serveru)" +del_head = "Smazání prvku kaskády..." +add_n_e = "Přidat nový element:" +add_f = "Vybrat zobrazení" +add_d = "Vybrat složku" +add_l = "Nahrát z počítače" +add_upl_e = "Můžete nahrávat obrázky z místního počítače po vytvoření dokumentu. Kliknutím níže na "Přidat a pokračovat v úpravách" +upl_dir = "Složka: " +del_all = "Odstranit všechny prvky" +del_all_c = "Opravdu chcete odstranit všechny prvky?
      (Zobrazení nebude smazáno ze serveru)" +del_all_h = "Odstranit všechny prvky kaskádu..." +resp_s_h = "Hotovo" +resp_s_m = "Soubory úspěšně nahrány" +resp_e_m = "Při stahování souborů došlo k chybě. Zkuste znovu." +resp_e_h = "Chyba" +resp_m_m = "Počet souborů, které se mají nahrát překračují hodnotu zadanou v konfiguračním PHP." +resp_m_h = "Chyba" +max_f_f = "Maximální počet souborů ke stažení: " +max_f_h = "Chba" +max_f_t = Překročen maximální počet souborů,
      během jednoho nahrávání" \ No newline at end of file diff --git a/fields/image_multi/lang/en.txt b/fields/image_multi/lang/en.txt new file mode 100644 index 0000000..bffa620 --- /dev/null +++ b/fields/image_multi/lang/en.txt @@ -0,0 +1,26 @@ +[admin] +name = "Cascade of images NEW" +look = "Lool" +link = "Change path" +select = "Select image" +delete = "Delete item cascade" +place = "Description" +del_conf = "are you sure You want to delete this item?
      (the Image will not be deleted from the server)" +del_head = "Delete item cascade..." +add_n_e = "Add new item:" +add_f = "Select image" +add_d = "Select folder" +add_l = "Download to computer" +add_upl_e = "You can upload pictures from your computer after you create the document. To do this, press the bottom button "Add and continue editing"" +del_all = "Delete any items" +del_all_c = "are you sure You want to delete all items?
      (Image will not be deleted from the server)" +del_all_h = "Delete all items of the cascade..." +resp_s_h = "Done" +resp_s_m = "File successfully loaded" +resp_e_m = "an error Occurred when uploading files. Try again." +resp_e_h = "Error" +resp_m_m = "number of uploaded file exceeds the value set in your PHP settings." +resp_m_h = "Error" +max_f_f = "Maximum number zagrozenia files:" +max_f_h = "Error" +max_f_t = "you have Exceeded the maximum number of files
      to download" \ No newline at end of file diff --git a/fields/image_multi/lang/pl.txt b/fields/image_multi/lang/pl.txt new file mode 100644 index 0000000..acdde72 --- /dev/null +++ b/fields/image_multi/lang/pl.txt @@ -0,0 +1,27 @@ +[admin] +name = "Obrazek (Kaskada)" +look = "Popatrz" +link = "Zmień sposób" +select = "Wybierz obrazek" +delete = "Usuń element kaskady" +place = "Opis" +del_conf = "Czy na pewno chcesz usunąć ten element?
      (Obrazek nie będzie usunięty z serwera)" +del_head = "Usuń element kaskady ..." +add_n_e = "Dodaj nowy element" +add_f = "Wybierz obrazek" +add_d = "Wybierz folder" +add_l = "Pobierz z komputera" +add_upl_e = "Możesz pobrać obrazki z komputera lokalnego po utworzeniu dokumentu. Aby to zrobić, kliknij poniżej na “Dodaj i kontynuować edycję”" +upl_dir = "Folder: " +del_all = "Usuń wszystkie elementy" +del_all_c = "Czy na pewno chcesz usunąć wszystkie elementy?
      (Obrazek nie będzie usunięty z serwera)" +del_all_h = "Usuń wszystkie elementy kaskady..." +resp_s_h = "Gotowe" +resp_s_m = "Pliki pomyślnie pobrane" +resp_e_m = "Wystąpił błąd podczas pobierania plików. Spróbuj ponownie." +resp_e_h = "Błąd" +resp_m_m = "Liczba plików do przesłania przekracza wartości określonej w PHP konfiguracji." +resp_m_h = "Błąd" +max_f_f = "Maksymalna liczba plików do pobrania:" +max_f_h = "Błąd" +max_f_t = "Przekroczono maksymalną liczbę plików,
      na jednoczesne ładowanie" \ No newline at end of file diff --git a/fields/image_multi/lang/ru.txt b/fields/image_multi/lang/ru.txt new file mode 100644 index 0000000..f74e7c3 --- /dev/null +++ b/fields/image_multi/lang/ru.txt @@ -0,0 +1,27 @@ +[admin] +name = "Изображение (Каскад)" +look = "Посмотреть" +link = "Изменить путь" +select = "Выбрать изображение" +delete = "Удалить элемент каскада" +place = "Описание" +del_conf = "Вы уверены, что хотите удалить данный элемент?
      (Изображение не будет удалено с сервера)" +del_head = "Удаление элемента каскада..." +add_n_e = "Добавить новый элемент:" +add_f = "Выбрать изображение" +add_d = "Выбрать папку" +add_l = "Загрузить с компьютера" +add_upl_e = "Вы сможете загрузить фотографии с локального компьютера после создания документа. Для этого нажмите внизу кнопку «Добавить и продолжить редактирование»" +upl_dir = "Папка: " +del_all = "Удалить все элементы" +del_all_c = "Вы уверены, что хотите удалить все элементы?
      (Изображения не будет удалены с сервера)" +del_all_h = "Удаление всех элемента каскада..." +resp_s_h = "Выполнено" +resp_s_m = "Файлы успешно загрузились" +resp_e_m = "Возникла ошибка при загрузке файлов. Попробуйте еще раз." +resp_e_h = "Ошибка" +resp_m_m = "Кол-во загружаемых файлов превышает значение, заданное в настройках PHP." +resp_m_h = "Ошибка" +max_f_f = "Макимальное кол-во загружаемых файлов: " +max_f_h = "Ошибка" +max_f_t = "Превышено максимальное число файлов,
      для одновременной загрузки" \ No newline at end of file diff --git a/fields/image_multi/lang/ua.txt b/fields/image_multi/lang/ua.txt new file mode 100644 index 0000000..e45a368 --- /dev/null +++ b/fields/image_multi/lang/ua.txt @@ -0,0 +1,27 @@ +[admin] +name = "Зображення (Каскад)" +look = "Подивитися" +link = "Змінити шлях" +select = "Обрати зображення" +delete = "Видалити елемент каскаду" +place = "Опис" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент?
      (Зображення не буде видалено зі сервера)" +del_head = "Видалення елемента каскаду..." +add_n_e = "Додати новий елемент:" +add_f = "Обрати зображення" +add_d = "Обрати папку" +add_l = "Завантажити з компьютера" +add_upl_e = "Ви зможете завантажити зображення з локального компьютера післе створення документа. Для цього натисніть внизу кнопку “Додати та продовжити редагування”" +upl_dir = "Папка: " +del_all = "Видалити всі елементи" +del_all_c = "Ви впевнені, що бажаєте видалити всі елементи?
      (Зображення не буде видалено зі сервера)" +del_all_h = "Видалення всіх елементів каскаду..." +resp_s_h = "Виконано" +resp_s_m = "Файли успішно завантажилися" +resp_e_m = "Сталася помилка при завантаженні файлів. Спробуйте ще раз." +resp_e_h = "Помилка" +resp_m_m = "Кількість файлів для завантаження перевищує значення, яке вказане у налаштуваннях PHP." +resp_m_h = "Помилка" +max_f_f = "Максимальна кількість файлів для завантаження: " +max_f_h = "Помилка" +max_f_t = "Перевищено максимальне число файлів,
      для одночасного завантаження" \ No newline at end of file diff --git a/fields/image_multi/tpl/field-doc.tpl b/fields/image_multi/tpl/field-doc.tpl new file mode 100644 index 0000000..3e07b09 --- /dev/null +++ b/fields/image_multi/tpl/field-doc.tpl @@ -0,0 +1,16 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$field_id} ID поля +{$field_value} Данные поля (массив) +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +Пример вывода: +----------------------------------------------------------- +*} + +{foreach from=$field_value item=image} + {if isset($image[1])}{$image[1]}{/if} +{/foreach} \ No newline at end of file diff --git a/fields/image_multi/tpl/field-req.tpl b/fields/image_multi/tpl/field-req.tpl new file mode 100644 index 0000000..274765c --- /dev/null +++ b/fields/image_multi/tpl/field-req.tpl @@ -0,0 +1,15 @@ +{* +Доступные параметры: +----------------------------------------------------------- +{$field_id} ID поля +{$field_value} Данные поля (массив) +{$field_count} Кол-во элементов в массиве +{$rubric_id} ID рубрики +{$default} Значение по умолчанию + +Пример вывода: +----------------------------------------------------------- +*} +{foreach from=$field_value item=image} + {if isset($image[1])}{$image[1]}{/if} +{/foreach} \ No newline at end of file diff --git a/fields/image_multi/tpl/field.tpl b/fields/image_multi/tpl/field.tpl new file mode 100644 index 0000000..1fb91d6 --- /dev/null +++ b/fields/image_multi/tpl/field.tpl @@ -0,0 +1,63 @@ +{if $cascad_new != 'load'} + {assign var=cascad_new value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=cascad_new value="load" scope="global"} +{/if} + +
      + + {if $show_upload} + + {/if} + + +
      + {foreach from=$images key=key item=image} + +
      +
      + + + + + + +
      + + {/foreach} +
      + +
      \ No newline at end of file diff --git a/fields/image_single/css/field.css b/fields/image_single/css/field.css new file mode 100644 index 0000000..59a7bbc --- /dev/null +++ b/fields/image_single/css/field.css @@ -0,0 +1,133 @@ +.single_image_images .img { + position: relative; + border-radius: 4px; + display: block; + float: left; + margin: 5px 10px 5px 0; + overflow: hidden; + padding: 0px 0px 4px 0px; + background-color: rgba(255, 255, 255, 0.5); + border: solid 1px #eaeaea; + text-align: center; + width: 138px; +} + +.single_image_images .img:hover { + background-color: rgba(255, 255, 255, 1.0); + border: solid 1px rgba(234, 234, 234, 0.5); + -webkit-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); + box-shadow: 0 0 5px 2px rgba(0, 0, 0, 0.1); +} + +.single_image_images .header { + background-color: rgba(210, 210, 210, 0.5); + height: 26px; + margin-bottom: 8px; + border-radius: 5px 5px 0 0; +} + +.single_image_images .header:hover { + background-color: rgba(210, 210, 210, 0.3); +} + +.single_image_images .img img { + display: inline-block; + float: none; + clear: both; + cursor: pointer; + overflow: hidden; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.single_image_images textarea { + display: inline-block; + width: 128px; + height: 60px; + margin-top: 8px; + border-radius: 0 0 2px 2px; + border: 1px solid #eaeaea !important; + resize: none !important; + box-shadow: none !important; + -webkit-box-shadow: none !important; + -moz-box-shadow: none !important; + padding: 3px !important; + box-sizing: border-box !important; + -webkit-box-sizing: border-box !important; + -moz-box-sizing: border-box !important; +} + +.single_image_images input { + display: inline-block; + width: 128px !important; + height: 20px !important; + margin: 0 0 4px 0 !important; + border-radius: 0 0 2px 2px !important; + border: 1px solid #ccc !important; + resize: none !important; + box-shadow: none !important; + -webkit-box-shadow: none !important; + -moz-box-shadow: none !important; + padding: 3px !important; + box-sizing: border-box !important; + -webkit-box-sizing: border-box !important; + -moz-box-sizing: border-box !important; +} + +.single_image_add { + position: relative; + float: left; + margin: 5px 10px 5px 0; + height: 158px; + width: 100px; +} + +.single_image_add > div { + position: relative; + border: 1px #ccc solid; + border-radius: 4px; + cursor: pointer; + color: #ccc; + font-size: 60px; + text-align: center; + height: 74.5px; + line-height: 60px; + background: #fff; +} + +.single_image_add > div > span { + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 20px; + font-size: 12px; + line-height: normal; + color: #ccc; +} + +.single_image_add input { + filter:alpha(opacity:0); + font-size: 199px; + cursor: pointer; + padding: 0px; + margin: -30px 0 0 -450px; + cursor: pointer !important; +} + +.single_image_images .view { + position: absolute; + top: 3px; + left: 3px; + cursor: pointer !important; +} + +.single_image_images .lnk { + position: absolute; + top: 3px; + right: 3px; + cursor: pointer !important; +} \ No newline at end of file diff --git a/fields/image_single/field.php b/fields/image_single/field.php new file mode 100644 index 0000000..a748a82 --- /dev/null +++ b/fields/image_single/field.php @@ -0,0 +1,174 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + switch ($action) + { + case 'edit': + $blanc = '/uploads/images/noimage.png'; + $image = explode('|', $field_value); + $img = $image[0]; + unset($image[0]); + $image = array($img, implode('|', $image)); + $field = (! empty($image[0]) + ? make_thumbnail(array('link' => $image[0], 'size' => 't128x128')) + : make_thumbnail(array('link' => $blanc, 'size' => 't128x128')) + ); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + $AVE_Template->assign('default', $default); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('image', $image); + $AVE_Template->assign('doc_id', (int)$_REQUEST['Id']); + $AVE_Template->assign('field', $field); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $field_value = clean_php($field_value); + + $field_param = explode('|', $field_value); + + if ($tpl_empty) + { + $field_value = '' . (isset($field_param[1]) ? $field_param[1] : '')
+						. ''; + } + else + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + + $field_value = preg_replace_callback( + '/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function($m) { + return watermarks($m[1], $m[2], $m[3]); + }, + $field_value + ); + + $field_value = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $field_value); + } + + $tpl_file = get_field_tpl ($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('image', $field_param); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + $field_value = clean_php($field_value); + + $field_param = explode('|', $field_value); + $field_param['name'] = preg_replace('/\\.[^.\\s]{3,4}$/', '', $field_param[0]); + $field_param['ext'] = getExtension($field_param[0]); + + if ($tpl_empty) + { + $field_param[1] = isset($field_param[1]) ? $field_param[1] : ''; + $field_value = '' . $field_param[1] . ''; + } + else + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + + $field_value = preg_replace_callback( + '/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function($m) { + return watermarks($m[1], $m[2], $m[3]); + }, + $field_value + ); + + $field_value = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $field_value); + } + + $maxlength = null; + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('image', $field_param); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'save': + if (isset($field_value) && $field_value['img'] != '' ) + { + $field_value = htmlspecialchars(implode("|", $field_value), ENT_QUOTES); + } + else + { + $field_value = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $image = explode('|', $field_value); + + return ['img' => $image[0], 'descr' => isset($image[1]) ? $image[1] : '']; + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/image_single/js/field.js b/fields/image_single/js/field.js new file mode 100644 index 0000000..eda3538 --- /dev/null +++ b/fields/image_single/js/field.js @@ -0,0 +1,55 @@ +var SingleImage = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + this.single_image(); + }, + + single_image: function() { + $('.single_image').each(function(index, element) { + + let image_id = $(element).attr('data-id'); + let doc_id = $(element).attr('data-doc'); + let link = $(element).find('a.lnk'); + let look = $(element).find('a.look'); + let input = $(element).find('input'); + + link.on('click', function(event) { + event.preventDefault(); + $('#image__' + image_id + '_' + doc_id).toggle('show'); + }); + + input.on('input', function(event) { + event.preventDefault(); + + src = $(this).val(); + dir = src.substring(0, src.lastIndexOf("/")); + file_full = src.match(/(\w*)\.\w{3,4}$/)[0]; + + $('.preview__' + image_id + '_' + doc_id).attr({ + 'href': '/' + $(this).val() + }); + + $('#preview__' + image_id + '_' + doc_id).attr({ + //'src': '../index.php?mode=t&width=128&height=128&thumb=/' + dir + '/' + file_full + }); + }); + + if (input.val() == '') { + $('#preview__' + image_id + '_' + doc_id).attr({ + 'src': '/uploads/images/' + thumbdir + '/noimage-t128x128.png' + }); + $('.preview__' + image_id + '_' + doc_id).attr({ + 'href': '/uploads/images/noimage.png' + }); + } + }); + }, +} + +$(document).ready(function() { + SingleImage.init(); +}); \ No newline at end of file diff --git a/fields/image_single/lang/bg.txt b/fields/image_single/lang/bg.txt new file mode 100644 index 0000000..928ec94 --- /dev/null +++ b/fields/image_single/lang/bg.txt @@ -0,0 +1,6 @@ +[admin] +name = "Изображение (Единично)" +look = "Преглед" +link = "Промени пътя" +select = "Избери изображение" +place = "Описание" \ No newline at end of file diff --git a/fields/image_single/lang/cz.txt b/fields/image_single/lang/cz.txt new file mode 100644 index 0000000..f8b0154 --- /dev/null +++ b/fields/image_single/lang/cz.txt @@ -0,0 +1,6 @@ +[admin] +name = "Zobrazení (Jediné)" +look = "Zobrazit" +link = "Změnit cestu" +select = "Vybrat zobrazení" +place = "Popis" \ No newline at end of file diff --git a/fields/image_single/lang/en.txt b/fields/image_single/lang/en.txt new file mode 100644 index 0000000..36ad83d --- /dev/null +++ b/fields/image_single/lang/en.txt @@ -0,0 +1,6 @@ +[admin] +name = "Image (Single)" +look = "Look" +link = "Change path" +select = "Select image" +place = "Description" \ No newline at end of file diff --git a/fields/image_single/lang/pl.txt b/fields/image_single/lang/pl.txt new file mode 100644 index 0000000..b5981c3 --- /dev/null +++ b/fields/image_single/lang/pl.txt @@ -0,0 +1,6 @@ +[admin] +name = "Obrazek (Pojedyńczy)" +look = "Popztrz" +link = "Zmień sposób" +select = "Wybierz obrazek" +place = "Opis" \ No newline at end of file diff --git a/fields/image_single/lang/ru.txt b/fields/image_single/lang/ru.txt new file mode 100644 index 0000000..d38d242 --- /dev/null +++ b/fields/image_single/lang/ru.txt @@ -0,0 +1,6 @@ +[admin] +name = "Изображение (Одиночное)" +look = "Посмотреть" +link = "Изменить путь" +select = "Выбрать изображение" +place = "Описание" \ No newline at end of file diff --git a/fields/image_single/lang/ua.txt b/fields/image_single/lang/ua.txt new file mode 100644 index 0000000..ed8ddf6 --- /dev/null +++ b/fields/image_single/lang/ua.txt @@ -0,0 +1,6 @@ +[admin] +name = "Зображення (Одиночне)" +look = "Подивитися" +link = "Змінити шлях" +select = "Обрати зображення" +place = "Опис" \ No newline at end of file diff --git a/fields/image_single/tpl/field-doc.tpl b/fields/image_single/tpl/field-doc.tpl new file mode 100644 index 0000000..3a46794 --- /dev/null +++ b/fields/image_single/tpl/field-doc.tpl @@ -0,0 +1 @@ +{if isset($image[1])}{$image[1]}{/if} \ No newline at end of file diff --git a/fields/image_single/tpl/field-req.tpl b/fields/image_single/tpl/field-req.tpl new file mode 100644 index 0000000..3a46794 --- /dev/null +++ b/fields/image_single/tpl/field-req.tpl @@ -0,0 +1 @@ +{if isset($image[1])}{$image[1]}{/if} \ No newline at end of file diff --git a/fields/image_single/tpl/field.tpl b/fields/image_single/tpl/field.tpl new file mode 100644 index 0000000..089c786 --- /dev/null +++ b/fields/image_single/tpl/field.tpl @@ -0,0 +1,20 @@ +{if $single_image != 'load'} + {assign var=single_image value='' scope="global"} + + + + {assign var=single_image value="load" scope="global"} +{/if} + +
      +
      +
      + + + + + +
      +
      \ No newline at end of file diff --git a/fields/link/field.php b/fields/link/field.php new file mode 100644 index 0000000..0ab8bfa --- /dev/null +++ b/fields/link/field.php @@ -0,0 +1,104 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = ''; + + switch ($action) + { + case 'edit': + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $field_value = clean_php($field_value); + $field_param = explode('|', $field_value); + $field_param[1] = empty($field_param[1]) ? $field_param[0] : $field_param[1]; + + if ($tpl_empty) + { + $field_value = ' ' . $field_param[1] . ''; + } + else + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $res = $field_value; + break; + + case 'req': + $field_value = clean_php($field_value); + $field_param = explode('|', $field_value); + + if (empty($field_param[1])) + $field_param[1] = $field_param[0]; + + if (isset($document_fields[$rubric_id]['tpl_req_empty'])) + { + $field_value = " " . $field_param[1] . ""; + } + else + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $maxlength = null; + + $res = $field_value; + break; + + case 'api' : + return clean_php($field_value); + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/link/lang/bg.txt b/fields/link/lang/bg.txt new file mode 100644 index 0000000..bf54edb --- /dev/null +++ b/fields/link/lang/bg.txt @@ -0,0 +1,2 @@ +[admin] +name = "Връзка(Link)" \ No newline at end of file diff --git a/fields/link/lang/cz.txt b/fields/link/lang/cz.txt new file mode 100644 index 0000000..3adf02a --- /dev/null +++ b/fields/link/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Odkaz" \ No newline at end of file diff --git a/fields/link/lang/pl.txt b/fields/link/lang/pl.txt new file mode 100644 index 0000000..6a575ee --- /dev/null +++ b/fields/link/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Link" \ No newline at end of file diff --git a/fields/link/lang/ru.txt b/fields/link/lang/ru.txt new file mode 100644 index 0000000..6797df8 --- /dev/null +++ b/fields/link/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Ссылка" \ No newline at end of file diff --git a/fields/link/lang/ua.txt b/fields/link/lang/ua.txt new file mode 100644 index 0000000..605b880 --- /dev/null +++ b/fields/link/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Посилання" \ No newline at end of file diff --git a/fields/link/tpl/field.tpl b/fields/link/tpl/field.tpl new file mode 100644 index 0000000..e007f13 --- /dev/null +++ b/fields/link/tpl/field.tpl @@ -0,0 +1,2 @@ +  + \ No newline at end of file diff --git a/fields/link_multi/css/field.css b/fields/link_multi/css/field.css new file mode 100644 index 0000000..0a676da --- /dev/null +++ b/fields/link_multi/css/field.css @@ -0,0 +1,18 @@ +.multi_lists { + position: relative; +} + +.multi_lists > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/link_multi/field.php b/fields/link_multi/field.php new file mode 100644 index 0000000..19a57d9 --- /dev/null +++ b/fields/link_multi/field.php @@ -0,0 +1,216 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = array(); + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + else + { + $items = explode(',', $default); + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + $items = $list; + } + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'save': + foreach ($field_value as $v) + { + if (! empty($v['param'])) + { + $field_value_new[] = $v['param'] . ($v['value'] ? '|' . $v['value'] : ''); + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + + return $items; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/link_multi/js/field.js b/fields/link_multi/js/field.js new file mode 100644 index 0000000..050438c --- /dev/null +++ b/fields/link_multi/js/field.js @@ -0,0 +1,74 @@ +var MultiLinks = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.lists(); + }, + + lists: function() { + this.lists_sortable(); + this.lists_del_item(); + this.lists_add(); + }, + + lists_update: function() { + this.lists_maxid(); + this.lists_del_item(); + AveAdmin.tooltip(); + }, + + lists_maxid: function(id) { + var maxid = 1; + $('#multi_links_' + id).children('.multi_link').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + lists_del_item: function() { + $('.multi_link .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + links_del_conf, + links_del_head, + function(b) { + if (b) { + $('#link_' + id).remove(); + } + } + ); + }); + }, + + lists_add: function() { + $('.multi_links .AddButton').on('click', function(event) { + event.preventDefault(); + c_id = $(this).parent().parent('.multi_links').attr("data-id"); + iid = MultiLinks.lists_maxid(c_id); + $('#multi_links_' + c_id + ':last').append( + '' + ); + + MultiLinks.lists_update(); + }); + }, + + lists_sortable: function() { + $('.multi_links').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + } +} + +$(document).ready(function() { + MultiLinks.init(); +}); \ No newline at end of file diff --git a/fields/link_multi/lang/ru.txt b/fields/link_multi/lang/ru.txt new file mode 100644 index 0000000..261b752 --- /dev/null +++ b/fields/link_multi/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мульти ссылки" +delete = "Удалить элемент" +param = "Наименование" +value = "Ссылка" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/link_multi/tpl/field-doc-181.tpl b/fields/link_multi/tpl/field-doc-181.tpl new file mode 100644 index 0000000..b72bc47 --- /dev/null +++ b/fields/link_multi/tpl/field-doc-181.tpl @@ -0,0 +1,33 @@ +{if ! empty($field_value)} + + + + + +{foreach from=$field_value item=list} + + + +{/foreach} + +
      + Документация +
      +  {$list[0]} +
      +{else} + + + + + + + +
      + Документация +
      +
      + Нет файлов для скачивания +
      +
      +{/if} \ No newline at end of file diff --git a/fields/link_multi/tpl/field-doc.tpl b/fields/link_multi/tpl/field-doc.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/link_multi/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/link_multi/tpl/field-req.tpl b/fields/link_multi/tpl/field-req.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/link_multi/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/link_multi/tpl/field.tpl b/fields/link_multi/tpl/field.tpl new file mode 100644 index 0000000..5f69d21 --- /dev/null +++ b/fields/link_multi/tpl/field.tpl @@ -0,0 +1,29 @@ +{if $multi_list != 'load'} + {assign var=multi_list value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=multi_list value="load" scope="global"} +{/if} + + \ No newline at end of file diff --git a/fields/multi_checkbox/field.php b/fields/multi_checkbox/field.php new file mode 100644 index 0000000..ff1e79b --- /dev/null +++ b/fields/multi_checkbox/field.php @@ -0,0 +1,168 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + $default_items = explode(',', $default); + $default_items = array_diff($default_items, array('')); + + $field_value_array = explode('|', $field_value); + $field_value_array = array_values(array_diff($field_value_array, array(''))); + + $AVE_Template->assign('items', $default_items); + $AVE_Template->assign('used', $field_value_array); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $default_items = explode(',', $default); + + $items = explode('|', $field_value); + $items = array_diff($items, array('')); + + if (! empty($items)) + { + foreach($items as $item) + { + if ($item) + { + if ($tpl_empty) + { + $item = $default_items[(int)$item-1]; + } + else + { + $field_param = explode('|', $item); + + $item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param, $default_items) + { + return $default_items[$field_param[(int)$data[1]]-1]; + }, + $tpl + ); + } + } + + $res[] = $item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default_items); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'req': + $default_items = explode(',', $default); + + $items = explode('|', $field_value); + $items = array_diff($items, array('')); + + if (! empty($items)) + { + foreach($items as $item) + { + if ($item) + { + if ($tpl_empty) + { + $item = $default_items[(int)$item-1]; + } + else + { + $field_param = explode('|', $item); + + $item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param, $default_items) + { + return $default_items[$field_param[(int)$data[1]]-1]; + }, + $tpl + ); + } + } + + $res[] = $item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default_items); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + + return ($res ? $res : $field_value); +} +?> \ No newline at end of file diff --git a/fields/multi_checkbox/lang/bg.txt b/fields/multi_checkbox/lang/bg.txt new file mode 100644 index 0000000..0b48621 --- /dev/null +++ b/fields/multi_checkbox/lang/bg.txt @@ -0,0 +1,4 @@ +[admin] +name = "Мулти чекбокс" +no_items = "Не са зададени стойности по подразбиране" + diff --git a/fields/multi_checkbox/lang/cz.txt b/fields/multi_checkbox/lang/cz.txt new file mode 100644 index 0000000..4a03569 --- /dev/null +++ b/fields/multi_checkbox/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Multicheckbox" +no_items = "Neexistuje žádná výchozí hodnota" diff --git a/fields/multi_checkbox/lang/en.txt b/fields/multi_checkbox/lang/en.txt new file mode 100644 index 0000000..307549f --- /dev/null +++ b/fields/multi_checkbox/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Multi Checkbox" +no_items = "No default value" diff --git a/fields/multi_checkbox/lang/pl.txt b/fields/multi_checkbox/lang/pl.txt new file mode 100644 index 0000000..9a05810 --- /dev/null +++ b/fields/multi_checkbox/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Multi checkbox" +no_items = "Brak wartości domyślnej" diff --git a/fields/multi_checkbox/lang/ru.txt b/fields/multi_checkbox/lang/ru.txt new file mode 100644 index 0000000..ec4833f --- /dev/null +++ b/fields/multi_checkbox/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Мульти чекбокс" +no_items = "Нет значения по умолчанию" diff --git a/fields/multi_checkbox/lang/ua.txt b/fields/multi_checkbox/lang/ua.txt new file mode 100644 index 0000000..905ddc0 --- /dev/null +++ b/fields/multi_checkbox/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Мульти чекбокс" +no_items = "Немає значення по замовчуванню" diff --git a/fields/multi_checkbox/tpl/field-doc.tpl b/fields/multi_checkbox/tpl/field-doc.tpl new file mode 100644 index 0000000..75fc3ea --- /dev/null +++ b/fields/multi_checkbox/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=item} +
      • {$item}
      • +{/foreach} +
      diff --git a/fields/multi_checkbox/tpl/field-req.tpl b/fields/multi_checkbox/tpl/field-req.tpl new file mode 100644 index 0000000..75fc3ea --- /dev/null +++ b/fields/multi_checkbox/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=item} +
      • {$item}
      • +{/foreach} +
      diff --git a/fields/multi_checkbox/tpl/field.tpl b/fields/multi_checkbox/tpl/field.tpl new file mode 100644 index 0000000..89f5544 --- /dev/null +++ b/fields/multi_checkbox/tpl/field.tpl @@ -0,0 +1,20 @@ +{if $items} + + +{foreach from=$items key=key item=item} + +
      +{/foreach} +{else} +
        +
      • {#no_items#}
      • +
      +{/if} diff --git a/fields/multi_line/field.php b/fields/multi_line/field.php new file mode 100644 index 0000000..23e99db --- /dev/null +++ b/fields/multi_line/field.php @@ -0,0 +1,76 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = null; + + switch ($action) + { + case 'edit': + if (isset($_REQUEST['multiedit']) && ($_REQUEST['multiedit'] === true)) + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['toolbar'] = 'Verysmall'; + $oCKeditor->config['height'] = 250; + $config = array(); + $field = $oCKeditor->editor('data['.$_REQUEST['Id'].'][feld][' . $field_id . ']', $field_value, $config); + } + else + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['toolbar'] = 'Big'; + $oCKeditor->config['height'] = 400; + $config = array(); + $field = $oCKeditor->editor('feld[' . $field_id . ']', $field_value, $config); + } + + $res = $field; + break; + + case 'doc': + $res = get_field_default($field_value, $action, $field_id, $tpl, $tpl_empty, $maxlength, $document_fields, $rubric_id); + $res = document_pagination($res); + break; + + case 'req': + $res = get_field_default($field_value, $action, $field_id, $tpl, $tpl_empty, $maxlength, $document_fields, $rubric_id); + break; + + case 'api': + $res = get_field_default($field_value, $action, $field_id, $tpl, $tpl_empty, $maxlength, $document_fields, $rubric_id); + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_line/lang/bg.txt b/fields/multi_line/lang/bg.txt new file mode 100644 index 0000000..da304fd --- /dev/null +++ b/fields/multi_line/lang/bg.txt @@ -0,0 +1,2 @@ +[admin] +name = "Многоредово (Голямо)" \ No newline at end of file diff --git a/fields/multi_line/lang/cz.txt b/fields/multi_line/lang/cz.txt new file mode 100644 index 0000000..cbcc8a2 --- /dev/null +++ b/fields/multi_line/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Víceřádkové (Velké)" \ No newline at end of file diff --git a/fields/multi_line/lang/en.txt b/fields/multi_line/lang/en.txt new file mode 100644 index 0000000..e277221 --- /dev/null +++ b/fields/multi_line/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Multi Lines (Big)" \ No newline at end of file diff --git a/fields/multi_line/lang/pl.txt b/fields/multi_line/lang/pl.txt new file mode 100644 index 0000000..06975d3 --- /dev/null +++ b/fields/multi_line/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Multi (Wielkie)" \ No newline at end of file diff --git a/fields/multi_line/lang/ru.txt b/fields/multi_line/lang/ru.txt new file mode 100644 index 0000000..db2a8b3 --- /dev/null +++ b/fields/multi_line/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Многострочное (Большое)" \ No newline at end of file diff --git a/fields/multi_line/lang/ua.txt b/fields/multi_line/lang/ua.txt new file mode 100644 index 0000000..3a1553d --- /dev/null +++ b/fields/multi_line/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Багаторядкове (Велике)" \ No newline at end of file diff --git a/fields/multi_line_simple/field.php b/fields/multi_line_simple/field.php new file mode 100644 index 0000000..b150b81 --- /dev/null +++ b/fields/multi_line_simple/field.php @@ -0,0 +1,76 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = null; + + switch ($action) + { + case 'edit': + if (isset($_REQUEST['multiedit']) && ($_REQUEST['multiedit'] === true)) + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['toolbar'] = 'Verysmall'; + $oCKeditor->config['height'] = 250; + $config = array(); + $field = $oCKeditor->editor('data['.$_REQUEST['Id'].'][feld][' . $field_id . ']', $field_value, $config); + } + else + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['toolbar'] = 'Small'; + $oCKeditor->config['height'] = 300; + $config = array(); + $field = $oCKeditor->editor('feld[' . $field_id . ']', $field_value, $config); + } + + $res = $field; + break; + + case 'doc': + $res = get_field_default($field_value,$action,$field_id,$tpl,$tpl_empty,$maxlength,$document_fields,$rubric_id); + $res = document_pagination($res); + break; + + case 'req': + $res = get_field_default($field_value,$action,$field_id,$tpl,$tpl_empty,$maxlength,$document_fields,$rubric_id); + break; + + case 'api': + $res = get_field_default($field_value, $action, $field_id, $tpl, $tpl_empty, $maxlength, $document_fields, $rubric_id); + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_line_simple/lang/bg.txt b/fields/multi_line_simple/lang/bg.txt new file mode 100644 index 0000000..fde0527 --- /dev/null +++ b/fields/multi_line_simple/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Многоредово (Средно)" \ No newline at end of file diff --git a/fields/multi_line_simple/lang/cz.txt b/fields/multi_line_simple/lang/cz.txt new file mode 100644 index 0000000..be5e618 --- /dev/null +++ b/fields/multi_line_simple/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Víceřádkové (Střední)" \ No newline at end of file diff --git a/fields/multi_line_simple/lang/en.txt b/fields/multi_line_simple/lang/en.txt new file mode 100644 index 0000000..bd02d25 --- /dev/null +++ b/fields/multi_line_simple/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Multi Lines (Middle)" \ No newline at end of file diff --git a/fields/multi_line_simple/lang/pl.txt b/fields/multi_line_simple/lang/pl.txt new file mode 100644 index 0000000..d77cd37 --- /dev/null +++ b/fields/multi_line_simple/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Multi (Średnie)" \ No newline at end of file diff --git a/fields/multi_line_simple/lang/ru.txt b/fields/multi_line_simple/lang/ru.txt new file mode 100644 index 0000000..51d2a6e --- /dev/null +++ b/fields/multi_line_simple/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Многострочное (Среднее)" \ No newline at end of file diff --git a/fields/multi_line_simple/lang/ua.txt b/fields/multi_line_simple/lang/ua.txt new file mode 100644 index 0000000..5e6f917 --- /dev/null +++ b/fields/multi_line_simple/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Багаторядкове (Середнє)" \ No newline at end of file diff --git a/fields/multi_line_slim/field.php b/fields/multi_line_slim/field.php new file mode 100644 index 0000000..fd0b81e --- /dev/null +++ b/fields/multi_line_slim/field.php @@ -0,0 +1,76 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = null; + + switch ($action) + { + case 'edit': + if (isset($_REQUEST['multiedit']) && ($_REQUEST['multiedit'] === true)) + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['toolbar'] = 'Verysmall'; + $oCKeditor->config['height'] = 250; + $config = array(); + $field = $oCKeditor->editor('data['.$_REQUEST['Id'].'][feld][' . $field_id . ']', $field_value, $config); + } + else + { + $oCKeditor = new CKeditor(); + $oCKeditor->returnOutput = true; + $oCKeditor->config['toolbar'] = 'Verysmall'; + $oCKeditor->config['height'] = 200; + $config = array(); + $field = $oCKeditor->editor('feld[' . $field_id . ']', $field_value, $config); + } + + $res = $field; + break; + + case 'doc': + $res = get_field_default($field_value,$action,$field_id,$tpl,$tpl_empty,$maxlength,$document_fields,$rubric_id); + $res = document_pagination($res); + break; + + case 'req': + $res = get_field_default($field_value,$action,$field_id,$tpl,$tpl_empty,$maxlength,$document_fields,$rubric_id); + break; + + case 'api': + $res = get_field_default($field_value, $action, $field_id, $tpl, $tpl_empty, $maxlength, $document_fields, $rubric_id); + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_line_slim/lang/bg.txt b/fields/multi_line_slim/lang/bg.txt new file mode 100644 index 0000000..37575ed --- /dev/null +++ b/fields/multi_line_slim/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Многоредово (Малко)" diff --git a/fields/multi_line_slim/lang/cz.txt b/fields/multi_line_slim/lang/cz.txt new file mode 100644 index 0000000..46109f2 --- /dev/null +++ b/fields/multi_line_slim/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Víceřádkové (Malé)" diff --git a/fields/multi_line_slim/lang/en.txt b/fields/multi_line_slim/lang/en.txt new file mode 100644 index 0000000..89829a2 --- /dev/null +++ b/fields/multi_line_slim/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Multi Lines (Small)" diff --git a/fields/multi_line_slim/lang/pl.txt b/fields/multi_line_slim/lang/pl.txt new file mode 100644 index 0000000..d4436af --- /dev/null +++ b/fields/multi_line_slim/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Multi (Małe)" diff --git a/fields/multi_line_slim/lang/ru.txt b/fields/multi_line_slim/lang/ru.txt new file mode 100644 index 0000000..676420d --- /dev/null +++ b/fields/multi_line_slim/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Многострочное (Маленькое)" diff --git a/fields/multi_line_slim/lang/ua.txt b/fields/multi_line_slim/lang/ua.txt new file mode 100644 index 0000000..9871f6b --- /dev/null +++ b/fields/multi_line_slim/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Багаторядкове (Маленьке)" diff --git a/fields/multi_links/css/field.css b/fields/multi_links/css/field.css new file mode 100644 index 0000000..0a676da --- /dev/null +++ b/fields/multi_links/css/field.css @@ -0,0 +1,18 @@ +.multi_lists { + position: relative; +} + +.multi_lists > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/multi_links/field.php b/fields/multi_links/field.php new file mode 100644 index 0000000..1a74662 --- /dev/null +++ b/fields/multi_links/field.php @@ -0,0 +1,216 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = array(); + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + else + { + $items = explode(',', $default); + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + $items = $list; + } + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req'); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'save': + foreach ($field_value as $v) + { + if (! empty($v['param'])) + { + $field_value_new[] = $v['param'] . ($v['value'] ? '|' . $v['value'] : ''); + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars_decode($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars_decode($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + + return $items; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); +} +?> \ No newline at end of file diff --git a/fields/multi_links/js/field.js b/fields/multi_links/js/field.js new file mode 100644 index 0000000..050438c --- /dev/null +++ b/fields/multi_links/js/field.js @@ -0,0 +1,74 @@ +var MultiLinks = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.lists(); + }, + + lists: function() { + this.lists_sortable(); + this.lists_del_item(); + this.lists_add(); + }, + + lists_update: function() { + this.lists_maxid(); + this.lists_del_item(); + AveAdmin.tooltip(); + }, + + lists_maxid: function(id) { + var maxid = 1; + $('#multi_links_' + id).children('.multi_link').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + lists_del_item: function() { + $('.multi_link .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + links_del_conf, + links_del_head, + function(b) { + if (b) { + $('#link_' + id).remove(); + } + } + ); + }); + }, + + lists_add: function() { + $('.multi_links .AddButton').on('click', function(event) { + event.preventDefault(); + c_id = $(this).parent().parent('.multi_links').attr("data-id"); + iid = MultiLinks.lists_maxid(c_id); + $('#multi_links_' + c_id + ':last').append( + '' + ); + + MultiLinks.lists_update(); + }); + }, + + lists_sortable: function() { + $('.multi_links').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + } +} + +$(document).ready(function() { + MultiLinks.init(); +}); \ No newline at end of file diff --git a/fields/multi_links/js/outside.js b/fields/multi_links/js/outside.js new file mode 100644 index 0000000..e67fa2f --- /dev/null +++ b/fields/multi_links/js/outside.js @@ -0,0 +1,75 @@ +var MultiList = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.lists(); + }, + + lists: function() { + this.lists_sortable(); + this.lists_del_item(); + this.lists_add(); + }, + + lists_update: function() { + this.lists_maxid(); + this.lists_del_item(); + AveAdmin.tooltip(); + }, + + lists_maxid: function(id) { + var maxid = 1; + $('#multi_lists_' + id).children('.multi_list').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + lists_del_item: function() { + $('.multi_list .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + list_del_conf, + list_del_head, + function(b) { + if (b) { + $('#list_' + id).remove(); + } + } + ); + }); + }, + + lists_add: function() { + $('.AddButton').on('click', function(event) { + event.preventDefault(); + c_id = $(this).parent().parent('.multi_lists').attr("data-id"); + iid = MultiList.lists_maxid(c_id); + $('#multi_lists_' + c_id + ':last').append( + '
      ' + + '    ×' + + '
      ' + + '
      ' + ); + + MultiList.lists_update(); + }); + }, + + lists_sortable: function() { + $('.multi_lists').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + //$(".multi_lists").disableSelection(); + } +} + +$(document).ready(function() { + MultiList.init(); +}); \ No newline at end of file diff --git a/fields/multi_links/lang/ru.txt b/fields/multi_links/lang/ru.txt new file mode 100644 index 0000000..261b752 --- /dev/null +++ b/fields/multi_links/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мульти ссылки" +delete = "Удалить элемент" +param = "Наименование" +value = "Ссылка" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/multi_links/tpl/field-doc.tpl b/fields/multi_links/tpl/field-doc.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/multi_links/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_links/tpl/field-req.tpl b/fields/multi_links/tpl/field-req.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/multi_links/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_links/tpl/field.tpl b/fields/multi_links/tpl/field.tpl new file mode 100644 index 0000000..dde535a --- /dev/null +++ b/fields/multi_links/tpl/field.tpl @@ -0,0 +1,29 @@ +{if $multi_list != 'load'} + {assign var=multi_link value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=multi_link value="load" scope="global"} +{/if} + + \ No newline at end of file diff --git a/fields/multi_list/css/field.css b/fields/multi_list/css/field.css new file mode 100644 index 0000000..0a676da --- /dev/null +++ b/fields/multi_list/css/field.css @@ -0,0 +1,18 @@ +.multi_lists { + position: relative; +} + +.multi_lists > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/multi_list/field.php b/fields/multi_list/field.php new file mode 100644 index 0000000..72156c0 --- /dev/null +++ b/fields/multi_list/field.php @@ -0,0 +1,216 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = array(); + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + else + { + $items = explode(',', $default); + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + $items = $list; + } + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'save': + foreach ($field_value as $v) + { + if(! empty($v['param'])) + { + $field_value_new[] = $v['param'] . ($v['value'] ? '|' . $v['value'] : ''); + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars_decode($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars_decode($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + + return $items; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_list/js/field.js b/fields/multi_list/js/field.js new file mode 100644 index 0000000..e67fa2f --- /dev/null +++ b/fields/multi_list/js/field.js @@ -0,0 +1,75 @@ +var MultiList = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.lists(); + }, + + lists: function() { + this.lists_sortable(); + this.lists_del_item(); + this.lists_add(); + }, + + lists_update: function() { + this.lists_maxid(); + this.lists_del_item(); + AveAdmin.tooltip(); + }, + + lists_maxid: function(id) { + var maxid = 1; + $('#multi_lists_' + id).children('.multi_list').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + lists_del_item: function() { + $('.multi_list .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + list_del_conf, + list_del_head, + function(b) { + if (b) { + $('#list_' + id).remove(); + } + } + ); + }); + }, + + lists_add: function() { + $('.AddButton').on('click', function(event) { + event.preventDefault(); + c_id = $(this).parent().parent('.multi_lists').attr("data-id"); + iid = MultiList.lists_maxid(c_id); + $('#multi_lists_' + c_id + ':last').append( + '
      ' + + '    ×' + + '
      ' + + '
      ' + ); + + MultiList.lists_update(); + }); + }, + + lists_sortable: function() { + $('.multi_lists').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + //$(".multi_lists").disableSelection(); + } +} + +$(document).ready(function() { + MultiList.init(); +}); \ No newline at end of file diff --git a/fields/multi_list/lang/bg.txt b/fields/multi_list/lang/bg.txt new file mode 100644 index 0000000..d5aa25e --- /dev/null +++ b/fields/multi_list/lang/bg.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мулти лист (Двоен)" +delete = "Изтриване на елемент" +param = "Параметър" +value = "Значение" +del_conf = "Сигурни ли сте, че желаете да изтриете този елемент?" +del_head = "Изтриване на елемент..." +add = "Добави" \ No newline at end of file diff --git a/fields/multi_list/lang/cz.txt b/fields/multi_list/lang/cz.txt new file mode 100644 index 0000000..9b31684 --- /dev/null +++ b/fields/multi_list/lang/cz.txt @@ -0,0 +1,8 @@ +[admin] +name = "Multiseznam (Dvojitý)" +delete = "Odstranit prvek" +param = "Dokument" +value = "Id" +del_conf = "Opravdu chcete odstranit tento prvek?" +del_head = "Odstranění prvku..." +add = "Přidat" \ No newline at end of file diff --git a/fields/multi_list/lang/en.txt b/fields/multi_list/lang/en.txt new file mode 100644 index 0000000..bc5c2d1 --- /dev/null +++ b/fields/multi_list/lang/en.txt @@ -0,0 +1,8 @@ +[admin] +name = "Multi List (Double)" +delete = "Delete element" +param = "Parametr" +value = "Value" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/multi_list/lang/pl.txt b/fields/multi_list/lang/pl.txt new file mode 100644 index 0000000..4ad08df --- /dev/null +++ b/fields/multi_list/lang/pl.txt @@ -0,0 +1,8 @@ +[admin] +name = "Multi list (Podwójne)" +delete = "Usuń element" +param = "Parametr" +value = "Znaczenie" +del_conf = "Czy na pewno chcesz usunąć ten element?" +del_head = "Usuń element..." +add = "Dodaj" \ No newline at end of file diff --git a/fields/multi_list/lang/ru.txt b/fields/multi_list/lang/ru.txt new file mode 100644 index 0000000..a6682b0 --- /dev/null +++ b/fields/multi_list/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мульти лист (Двойное)" +delete = "Удалить элемент" +param = "Параметр" +value = "Значение" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/multi_list/lang/ua.txt b/fields/multi_list/lang/ua.txt new file mode 100644 index 0000000..c1bd4b3 --- /dev/null +++ b/fields/multi_list/lang/ua.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мульти лист (Подвійне)" +delete = "Видалити елемент" +param = "Параметр" +value = "Значення" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент?" +del_head = "Видалення елемента..." +add = "Додати" \ No newline at end of file diff --git a/fields/multi_list/tpl/field-doc.tpl b/fields/multi_list/tpl/field-doc.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/multi_list/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list/tpl/field-req.tpl b/fields/multi_list/tpl/field-req.tpl new file mode 100644 index 0000000..ef6968b --- /dev/null +++ b/fields/multi_list/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list/tpl/field.tpl b/fields/multi_list/tpl/field.tpl new file mode 100644 index 0000000..e14b8ab --- /dev/null +++ b/fields/multi_list/tpl/field.tpl @@ -0,0 +1,29 @@ +{if $multi_list != 'load'} + {assign var=multi_list value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=multi_list value="load" scope="global"} +{/if} + +
      +{foreach from=$items key=key item=item} + +
      +     {if $key == 0}+{else}×{/if} +
      +
      + +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list_single/css/field.css b/fields/multi_list_single/css/field.css new file mode 100644 index 0000000..f714c6a --- /dev/null +++ b/fields/multi_list_single/css/field.css @@ -0,0 +1,18 @@ +.multi_lists_single { + position: relative; +} + +.multi_lists_single > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/multi_list_single/field.php b/fields/multi_list_single/field.php new file mode 100644 index 0000000..842da1a --- /dev/null +++ b/fields/multi_list_single/field.php @@ -0,0 +1,184 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = array(); + + $items = unserialize($field_value); + + if ($items != false) + { + $items = $items; + } + else + { + $items = explode(',', $default); + } + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $items = unserialize($field_value); + + if ($items != false) + { + foreach($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'save': + foreach ($field_value as $v) + { + if (! empty($v)) + { + $field_value_new[] = $v; + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + return unserialize($field_value); + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_list_single/js/field.js b/fields/multi_list_single/js/field.js new file mode 100644 index 0000000..d977cfe --- /dev/null +++ b/fields/multi_list_single/js/field.js @@ -0,0 +1,75 @@ +var MultiListSingle = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.s_lists(); + }, + + s_lists: function() { + this.s_lists_sortable(); + this.s_lists_del_item(); + this.s_lists_add(); + }, + + s_lists_update: function() { + this.s_lists_maxid(); + this.s_lists_del_item(); + AveAdmin.tooltip(); + }, + + s_lists_maxid: function(id) { + var maxid = 1; + $('#multi_lists_single_' + id).children('.multi_list_single').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + s_lists_del_item: function() { + $('.multi_list_single .DelSingleButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + s_list_del_conf, + s_list_del_head, + function(b) { + if (b) { + $('#list_' + id).remove(); + } + } + ); + }); + }, + + s_lists_add: function() { + $('.AddSingleButton').on('click', function(event) { + event.preventDefault(); + c_id = $(this).parent().parent('.multi_lists_single').attr("data-id"); + iid = MultiListSingle.s_lists_maxid(c_id); + $('#multi_lists_single_' + c_id + ':last').append( + '
      ' + + '  ×' + + '
      ' + + '
      ' + ); + + MultiListSingle.s_lists_update(); + }); + }, + + s_lists_sortable: function() { + $('.multi_lists_single').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + //$(".multi_lists_single").disableSelection(); + } +} + +$(document).ready(function() { + MultiListSingle.init(); +}); \ No newline at end of file diff --git a/fields/multi_list_single/lang/bg.txt b/fields/multi_list_single/lang/bg.txt new file mode 100644 index 0000000..82900d2 --- /dev/null +++ b/fields/multi_list_single/lang/bg.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мулти лист (Единичен)" +delete = "Изтриване на елемент" +param = "Параметър" +value = "Значение" +del_conf = "Сигурни ли сте, че желаете да изтриете този елемент?" +del_head = "Изтриване на елемента..." +add = "Добави" \ No newline at end of file diff --git a/fields/multi_list_single/lang/cz.txt b/fields/multi_list_single/lang/cz.txt new file mode 100644 index 0000000..ae020b6 --- /dev/null +++ b/fields/multi_list_single/lang/cz.txt @@ -0,0 +1,8 @@ +[admin] +name = "Multiseznam (Jediný)" +delete = "Odstranit prvek" +param = "Dokument" +value = "Id" +del_conf = "Opravdu chcete odstranit tento prvek?" +del_head = "Odstranění prvku..." +add = "Přidat" \ No newline at end of file diff --git a/fields/multi_list_single/lang/en.txt b/fields/multi_list_single/lang/en.txt new file mode 100644 index 0000000..54cef4f --- /dev/null +++ b/fields/multi_list_single/lang/en.txt @@ -0,0 +1,8 @@ +[admin] +name = "Multi List (Single)" +delete = "Delete element" +param = "Parametr" +value = "Value" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/multi_list_single/lang/pl.txt b/fields/multi_list_single/lang/pl.txt new file mode 100644 index 0000000..1e979bf --- /dev/null +++ b/fields/multi_list_single/lang/pl.txt @@ -0,0 +1,8 @@ +[admin] +name = "Multi list (Pojedyncze)" +delete = "Usuń element" +param = "Parametr" +value = "Znaczenie" +del_conf = "Czy na pewno chcesz usunąć ten element?" +del_head = "Usuń element..." +add = "Dodaj" \ No newline at end of file diff --git a/fields/multi_list_single/lang/ru.txt b/fields/multi_list_single/lang/ru.txt new file mode 100644 index 0000000..8bccc75 --- /dev/null +++ b/fields/multi_list_single/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мульти лист (Одиночное)" +delete = "Удалить элемент" +param = "Параметр" +value = "Значение" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/multi_list_single/lang/ua.txt b/fields/multi_list_single/lang/ua.txt new file mode 100644 index 0000000..397971b --- /dev/null +++ b/fields/multi_list_single/lang/ua.txt @@ -0,0 +1,8 @@ +[admin] +name = "Мульти лист (Одиночне)" +delete = "Видалити елемент" +param = "Параметр" +value = "Значення" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент?" +del_head = "Видалення елемента..." +add = "Додати" \ No newline at end of file diff --git a/fields/multi_list_single/tpl/field-doc.tpl b/fields/multi_list_single/tpl/field-doc.tpl new file mode 100644 index 0000000..7105c30 --- /dev/null +++ b/fields/multi_list_single/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list_single/tpl/field-req.tpl b/fields/multi_list_single/tpl/field-req.tpl new file mode 100644 index 0000000..7105c30 --- /dev/null +++ b/fields/multi_list_single/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list_single/tpl/field.tpl b/fields/multi_list_single/tpl/field.tpl new file mode 100644 index 0000000..060749b --- /dev/null +++ b/fields/multi_list_single/tpl/field.tpl @@ -0,0 +1,28 @@ +{if $multi_list_single != 'load'} + {assign var=multi_list_single value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=multi_list_single value="load" scope="global"} +{/if} + +
      +{foreach from=$items key=key item=item} + +
      +   {if $key == 0}+{else}×{/if} +
      +
      + +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list_triple/css/field.css b/fields/multi_list_triple/css/field.css new file mode 100644 index 0000000..929f949 --- /dev/null +++ b/fields/multi_list_triple/css/field.css @@ -0,0 +1,18 @@ +.multi_list_triples { + position: relative; +} + +.multi_list_triples > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/multi_list_triple/field.php b/fields/multi_list_triple/field.php new file mode 100644 index 0000000..050487d --- /dev/null +++ b/fields/multi_list_triple/field.php @@ -0,0 +1,223 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + + $items = array(); + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + $list[$k]['value2'] = (isset($list_item[2])) ? htmlspecialchars($list_item[2], ENT_QUOTES) : ''; + } + + $items = $list; + } + else + { + + $items = explode(',', $default); + + foreach ($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + $list[$k]['value2'] = (isset($list_item[2])) ? htmlspecialchars($list_item[2], ENT_QUOTES) : ''; + } + + $items = $list; + } + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = unserialize($field_value); + + if ($items != false) + { + foreach ($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'req': + $items = unserialize($field_value); + + if ($items != false) + { + foreach ($items as $list_item) + { + $list_item = clean_php($list_item); + $field_param = explode('|', $list_item); + + if ($list_item) + { + if ($tpl_empty) + { + $list_item = $field_param; + } + else + { + $list_item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $list_item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('field_count', count($res)); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'save': + foreach ($field_value as $v) + { + if(!empty($v['param'])) + { + $field_value_new[] = $v['param'] . '|' . $v['value'] . '|' . $v['value2']; + } + } + + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $items = unserialize($field_value); + + if ($items != false) + { + + foreach($items as $k => $v) + { + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars_decode($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars_decode($list_item[1], ENT_QUOTES) : ''; + $list[$k]['value2'] = (isset($list_item[2])) ? htmlspecialchars_decode($list_item[2], ENT_QUOTES) : ''; + } + + $items = $list; + } + + return $items; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_list_triple/js/field.js b/fields/multi_list_triple/js/field.js new file mode 100644 index 0000000..e4d5ca8 --- /dev/null +++ b/fields/multi_list_triple/js/field.js @@ -0,0 +1,75 @@ +var MultiListTriple = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.lists(); + }, + + lists: function() { + this.lists_sortable(); + this.lists_del_item(); + this.lists_add(); + }, + + lists_update: function() { + this.lists_maxid(); + this.lists_del_item(); + AveAdmin.tooltip(); + }, + + lists_maxid: function(id) { + var maxid = 1; + $('#multi_lists_triple_' + id).children('.multi_list_triple').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + lists_del_item: function() { + $('.multi_list_triple .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + list_del_conf, + list_del_head, + function(b) { + if (b) { + $('#list_' + id).remove(); + } + } + ); + }); + }, + + lists_add: function() { + $('.AddButton').on('click', function(event) { + event.preventDefault(); + c_id = $(this).parent().parent('.multi_lists_triple').attr("data-id"); + iid = MultiListTriple.lists_maxid(c_id); + $('#multi_lists_triple_' + c_id + ':last').append( + '
      ' + + '      ×' + + '
      ' + + '
      ' + ); + + MultiListTriple.lists_update(); + }); + }, + + lists_sortable: function() { + $('.multi_lists_triple').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + //$(".multi_lists_triple").disableSelection(); + } +} + +$(document).ready(function() { + MultiListTriple.init(); +}); \ No newline at end of file diff --git a/fields/multi_list_triple/lang/bg.txt b/fields/multi_list_triple/lang/bg.txt new file mode 100644 index 0000000..757e19e --- /dev/null +++ b/fields/multi_list_triple/lang/bg.txt @@ -0,0 +1,9 @@ +[admin] +name = "Мулти лист (Троен)" +delete = "Изтриване на елемент" +param = "Параметър" +value = "Значение" +value2 = "Значение 2" +del_conf = "Сигурно ли сте, че желаете да изтриете този елемент?" +del_head = "Изтриване на елемента..." +add = "Добави" \ No newline at end of file diff --git a/fields/multi_list_triple/lang/cz.txt b/fields/multi_list_triple/lang/cz.txt new file mode 100644 index 0000000..faa7bd0 --- /dev/null +++ b/fields/multi_list_triple/lang/cz.txt @@ -0,0 +1,9 @@ +[admin] +name = "Multiseznam (Trojitý)" +delete = "Odstranit prvek" +param = "Dokument" +value = "Id" +value2 = "Id 2" +del_conf = "Opravdu chcete odstranit tento prvek?" +del_head = "Odstranění prvku..." +add = "Přidat" \ No newline at end of file diff --git a/fields/multi_list_triple/lang/pl.txt b/fields/multi_list_triple/lang/pl.txt new file mode 100644 index 0000000..3fba90a --- /dev/null +++ b/fields/multi_list_triple/lang/pl.txt @@ -0,0 +1,9 @@ +[admin] +name = "Multi list (Potrójne)" +delete = "Usuń element" +param = "Parametr" +value = "Znaczenie" +value2 = "Znaczenie 2" +del_conf = "Czy na pewno chcesz usunąć ten element?" +del_head = "Usuń element..." +add = "Dodaj" \ No newline at end of file diff --git a/fields/multi_list_triple/lang/ru.txt b/fields/multi_list_triple/lang/ru.txt new file mode 100644 index 0000000..4d406a4 --- /dev/null +++ b/fields/multi_list_triple/lang/ru.txt @@ -0,0 +1,9 @@ +[admin] +name = "Мульти лист (Тройное)" +delete = "Удалить элемент" +param = "Параметр" +value = "Значение" +value2 = "Значение 2" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента..." +add = "Добавить" \ No newline at end of file diff --git a/fields/multi_list_triple/lang/ua.txt b/fields/multi_list_triple/lang/ua.txt new file mode 100644 index 0000000..9ccc9c8 --- /dev/null +++ b/fields/multi_list_triple/lang/ua.txt @@ -0,0 +1,9 @@ +[admin] +name = "Мульти лист (Потрійне)" +delete = "Видалити елемент" +param = "Параметр" +value = "Значення" +value2 = "Значення 2" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент?" +del_head = "Видалення елемента..." +add = "Додати" \ No newline at end of file diff --git a/fields/multi_list_triple/tpl/field-doc.tpl b/fields/multi_list_triple/tpl/field-doc.tpl new file mode 100644 index 0000000..54c683f --- /dev/null +++ b/fields/multi_list_triple/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}: {$list[2]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list_triple/tpl/field-req.tpl b/fields/multi_list_triple/tpl/field-req.tpl new file mode 100644 index 0000000..54c683f --- /dev/null +++ b/fields/multi_list_triple/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=list} +
      • {$list[0]}: {$list[1]}: {$list[2]}
      • +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_list_triple/tpl/field.tpl b/fields/multi_list_triple/tpl/field.tpl new file mode 100644 index 0000000..c2a0853 --- /dev/null +++ b/fields/multi_list_triple/tpl/field.tpl @@ -0,0 +1,30 @@ +{if $multi_list_triple != 'load'} + {assign var=multi_list_triple value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=multi_list_triple value="load" scope="global"} +{/if} + +
      +{foreach from=$items key=key item=item} + +
      +       {if $key == 0}+{else}×{/if} +
      +
      + +{/foreach} +
      \ No newline at end of file diff --git a/fields/multi_select/field.php b/fields/multi_select/field.php new file mode 100644 index 0000000..4b093fa --- /dev/null +++ b/fields/multi_select/field.php @@ -0,0 +1,166 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = array(); + + switch ($action) + { + case 'edit': + $items = array(); + + $items = explode(',', $default); + + $items = array_diff($items, array('')); + + @$field_value = unserialize($field_value); + + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $items = (isset($field_value)) + ? unserialize($field_value) + : array(); + + if ($items != false) + { + foreach($items as $item) + { + $item = clean_php($item); + + $field_param = explode('|', $item); + + if ($item) + { + if ($tpl_empty) + { + $item = $field_param[0]; + } + else + { + $item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'req': + $items = (isset($field_value)) ? unserialize($field_value) : array(); + + if ($items != false) + { + foreach($items as $item) + { + $item = clean_php($item); + + $field_param = explode('|', $item); + + if ($item) + { + if ($tpl_empty) + { + $item = $field_param[0]; + } + else + { + $item = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + } + $res[] = $item; + } + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $res); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return (!empty($res)) ? implode(PHP_EOL, $res) : $tpl; + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + return unserialize($field_value); + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/multi_select/lang/bg.txt b/fields/multi_select/lang/bg.txt new file mode 100644 index 0000000..36f4aa8 --- /dev/null +++ b/fields/multi_select/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] +name = "Мулти селект" +no_items = "Липсват стойности по подразбиране" \ No newline at end of file diff --git a/fields/multi_select/lang/cz.txt b/fields/multi_select/lang/cz.txt new file mode 100644 index 0000000..5503b6b --- /dev/null +++ b/fields/multi_select/lang/cz.txt @@ -0,0 +1,3 @@ +[admin] +name = "Multivýběr" +no_items = "Neexistuje žádná výchozí hodnota" \ No newline at end of file diff --git a/fields/multi_select/lang/en.txt b/fields/multi_select/lang/en.txt new file mode 100644 index 0000000..88dc91d --- /dev/null +++ b/fields/multi_select/lang/en.txt @@ -0,0 +1,3 @@ +[admin] +name = "Multi Select" +no_items = "No default value" \ No newline at end of file diff --git a/fields/multi_select/lang/pl.txt b/fields/multi_select/lang/pl.txt new file mode 100644 index 0000000..f348838 --- /dev/null +++ b/fields/multi_select/lang/pl.txt @@ -0,0 +1,3 @@ +[admin] +name = "Multi selekt" +no_items = "Brak znaczenia domyślnego" \ No newline at end of file diff --git a/fields/multi_select/lang/ru.txt b/fields/multi_select/lang/ru.txt new file mode 100644 index 0000000..ad3eb25 --- /dev/null +++ b/fields/multi_select/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Мульти селект" +no_items = "Нет значения по умолчанию" \ No newline at end of file diff --git a/fields/multi_select/lang/ua.txt b/fields/multi_select/lang/ua.txt new file mode 100644 index 0000000..4124a0e --- /dev/null +++ b/fields/multi_select/lang/ua.txt @@ -0,0 +1,3 @@ +[admin] +name = "Мульти селект" +no_items = "Немає значення по замовчуванню" \ No newline at end of file diff --git a/fields/multi_select/tpl/field-doc.tpl b/fields/multi_select/tpl/field-doc.tpl new file mode 100644 index 0000000..75fc3ea --- /dev/null +++ b/fields/multi_select/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=item} +
      • {$item}
      • +{/foreach} +
      diff --git a/fields/multi_select/tpl/field-req.tpl b/fields/multi_select/tpl/field-req.tpl new file mode 100644 index 0000000..75fc3ea --- /dev/null +++ b/fields/multi_select/tpl/field-req.tpl @@ -0,0 +1,5 @@ +
        +{foreach from=$field_value item=item} +
      • {$item}
      • +{/foreach} +
      diff --git a/fields/multi_select/tpl/field.tpl b/fields/multi_select/tpl/field.tpl new file mode 100644 index 0000000..027c0da --- /dev/null +++ b/fields/multi_select/tpl/field.tpl @@ -0,0 +1,11 @@ +{if $items} + +{else} +
        +
      • {#no_items#}
      • +
      +{/if} \ No newline at end of file diff --git a/fields/rubrics/field.php b/fields/rubrics/field.php new file mode 100644 index 0000000..bc7a030 --- /dev/null +++ b/fields/rubrics/field.php @@ -0,0 +1,86 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + $res = 0; + + if ($_REQUEST['action'] == 'new') + $field_value = 0; + + switch ($action) + { + case 'edit': + if (isset($default)) + { + $sql = $AVE_DB->Query(" + SELECT + id, title + FROM + ". PREFIX ."_rubric_templates + WHERE + rubric_id IN (" . $default . ") + "); + + $rubrics = array(); + + while($row = $sql->FetchAssocArray()) + array_push($rubrics, $row); + + $AVE_Template->assign('default', $default); + $AVE_Template->assign('rubrics', $rubrics); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('doc_id', (isset($_REQUEST['Id']) ? (int)$_REQUEST['Id'] : 0)); + $AVE_Template->assign('field_value', $field_value); + } + else + { + $AVE_Template->assign('error', $AVE_Template->get_config_vars('error')); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + $res = $field_value; + break; + + case 'req': + $res = $field_value; + break; + + case 'api': + return $field_value; + break; + + case 'name': + return $AVE_Template->get_config_vars('name'); + break; + } + return ($res ? $res : $field_value); +} +?> \ No newline at end of file diff --git a/fields/rubrics/lang/ru.txt b/fields/rubrics/lang/ru.txt new file mode 100644 index 0000000..99e94be --- /dev/null +++ b/fields/rubrics/lang/ru.txt @@ -0,0 +1,3 @@ +[admin] +name = "Шаблоны рубрики" +error = "Не задана рубрика" \ No newline at end of file diff --git a/fields/rubrics/tpl/field.tpl b/fields/rubrics/tpl/field.tpl new file mode 100644 index 0000000..7707437 --- /dev/null +++ b/fields/rubrics/tpl/field.tpl @@ -0,0 +1,16 @@ +{if $rubrics && !isset($error)} + + + +{else} + +
        +
      • {#error#}
      • +
      + +{/if} diff --git a/fields/single_line/field.php b/fields/single_line/field.php new file mode 100644 index 0000000..1c6246b --- /dev/null +++ b/fields/single_line/field.php @@ -0,0 +1,126 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + + $AVE_Template->config_load($lang_file, 'public'); + + if ($tpl_empty) + { + $field_value = clean_php($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function ($data) use ($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + + $AVE_Template->config_load($lang_file, 'public'); + + if ($tpl_empty) + { + $field_value = clean_php($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'save': + return $field_value; + + case 'api': + return $field_value; + + case 'name': + return $AVE_Template->get_config_vars('name'); + + default: + return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/single_line/lang/bg.txt b/fields/single_line/lang/bg.txt new file mode 100644 index 0000000..1bf9266 --- /dev/null +++ b/fields/single_line/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Едноредово" \ No newline at end of file diff --git a/fields/single_line/lang/cz.txt b/fields/single_line/lang/cz.txt new file mode 100644 index 0000000..18461b5 --- /dev/null +++ b/fields/single_line/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Jednořádkový" \ No newline at end of file diff --git a/fields/single_line/lang/en.txt b/fields/single_line/lang/en.txt new file mode 100644 index 0000000..d10bf19 --- /dev/null +++ b/fields/single_line/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Single Line" \ No newline at end of file diff --git a/fields/single_line/lang/pl.txt b/fields/single_line/lang/pl.txt new file mode 100644 index 0000000..308b776 --- /dev/null +++ b/fields/single_line/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Linia pojedyncza" \ No newline at end of file diff --git a/fields/single_line/lang/ru.txt b/fields/single_line/lang/ru.txt new file mode 100644 index 0000000..6b9c6ca --- /dev/null +++ b/fields/single_line/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однострочное" \ No newline at end of file diff --git a/fields/single_line/lang/ua.txt b/fields/single_line/lang/ua.txt new file mode 100644 index 0000000..05d7a4e --- /dev/null +++ b/fields/single_line/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однорядкове" \ No newline at end of file diff --git a/fields/single_line/tpl/field-doc.tpl b/fields/single_line/tpl/field-doc.tpl new file mode 100644 index 0000000..8166f56 --- /dev/null +++ b/fields/single_line/tpl/field-doc.tpl @@ -0,0 +1,5 @@ +{* + $field_id + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/single_line/tpl/field-req.tpl b/fields/single_line/tpl/field-req.tpl new file mode 100644 index 0000000..8166f56 --- /dev/null +++ b/fields/single_line/tpl/field-req.tpl @@ -0,0 +1,5 @@ +{* + $field_id + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/single_line/tpl/field.tpl b/fields/single_line/tpl/field.tpl new file mode 100644 index 0000000..5b96cef --- /dev/null +++ b/fields/single_line/tpl/field.tpl @@ -0,0 +1 @@ + diff --git a/fields/single_line_numeric/field.php b/fields/single_line_numeric/field.php new file mode 100644 index 0000000..5f7e96b --- /dev/null +++ b/fields/single_line_numeric/field.php @@ -0,0 +1,118 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + if ($tpl_empty) + { + $field_value = clean_php($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + if ($tpl_empty) + { + $field_value = clean_php($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + $AVE_Template->assign('field_default', $default); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'save': + $field_value = preg_replace('/[^\d.]/','',$field_value); + return $field_value; + + case 'api': + return $field_value; + + case 'name': + return $AVE_Template->get_config_vars('name'); + + default: return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/single_line_numeric/js/field.js b/fields/single_line_numeric/js/field.js new file mode 100644 index 0000000..dd1994e --- /dev/null +++ b/fields/single_line_numeric/js/field.js @@ -0,0 +1,26 @@ +$(document).ready(function() { + $(".field_numeric").keydown(function(event) { + var num_dot = $(this).attr('data-num-dot'); + var keyCode = window.event ? event.keyCode : event.which; + var foo = 0; + // prevent if already dot + if (keyCode != 8 && keyCode != 46) { + if ((foo == 0) && (keyCode != 190) && (keyCode < 96 || keyCode > 105) && (keyCode < 46 || keyCode > 59)) { + event.preventDefault(); + } // prevent if not number/dot + } + if ($(this).val().indexOf('.') > -1) { + if (keyCode == 190) event.preventDefault(); + } + $(this).keyup(function() { + this.value = this.value.replace(/[^0-9.]/i, ""); + if($(this).val().indexOf('.')!=-1){ + if($(this).val().split(".")[1].length >= num_dot){ + if( isNaN( parseFloat( this.value ) ) ) return; + this.value = parseFloat(this.value).toFixed(num_dot); + } + } + return this; + }); + }); +}); \ No newline at end of file diff --git a/fields/single_line_numeric/lang/bg.txt b/fields/single_line_numeric/lang/bg.txt new file mode 100644 index 0000000..51dcca4 --- /dev/null +++ b/fields/single_line_numeric/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Едноредово (Числово)" \ No newline at end of file diff --git a/fields/single_line_numeric/lang/cz.txt b/fields/single_line_numeric/lang/cz.txt new file mode 100644 index 0000000..67162c8 --- /dev/null +++ b/fields/single_line_numeric/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Jednořádkový (Číselný)" \ No newline at end of file diff --git a/fields/single_line_numeric/lang/en.txt b/fields/single_line_numeric/lang/en.txt new file mode 100644 index 0000000..fce8b0c --- /dev/null +++ b/fields/single_line_numeric/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Single line (Numbers)" \ No newline at end of file diff --git a/fields/single_line_numeric/lang/pl.txt b/fields/single_line_numeric/lang/pl.txt new file mode 100644 index 0000000..74abffa --- /dev/null +++ b/fields/single_line_numeric/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Linia pojedyncza (Numeryczne)" \ No newline at end of file diff --git a/fields/single_line_numeric/lang/ru.txt b/fields/single_line_numeric/lang/ru.txt new file mode 100644 index 0000000..b159408 --- /dev/null +++ b/fields/single_line_numeric/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однострочное (Числовое)" \ No newline at end of file diff --git a/fields/single_line_numeric/lang/ua.txt b/fields/single_line_numeric/lang/ua.txt new file mode 100644 index 0000000..37bf67d --- /dev/null +++ b/fields/single_line_numeric/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однорядкове (Числове)" \ No newline at end of file diff --git a/fields/single_line_numeric/tpl/field-doc.tpl b/fields/single_line_numeric/tpl/field-doc.tpl new file mode 100644 index 0000000..20c861d --- /dev/null +++ b/fields/single_line_numeric/tpl/field-doc.tpl @@ -0,0 +1 @@ +{$field_value} \ No newline at end of file diff --git a/fields/single_line_numeric/tpl/field-req.tpl b/fields/single_line_numeric/tpl/field-req.tpl new file mode 100644 index 0000000..20c861d --- /dev/null +++ b/fields/single_line_numeric/tpl/field-req.tpl @@ -0,0 +1 @@ +{$field_value} \ No newline at end of file diff --git a/fields/single_line_numeric/tpl/field.tpl b/fields/single_line_numeric/tpl/field.tpl new file mode 100644 index 0000000..dac7e27 --- /dev/null +++ b/fields/single_line_numeric/tpl/field.tpl @@ -0,0 +1,6 @@ +{if $single_line_numeric != 'load'} + {assign var=single_line_numeric value='' scope="global"} + + {assign var=single_line_numeric value="load" scope="global"} +{/if} + \ No newline at end of file diff --git a/fields/single_line_numeric_three/field.php b/fields/single_line_numeric_three/field.php new file mode 100644 index 0000000..ac85871 --- /dev/null +++ b/fields/single_line_numeric_three/field.php @@ -0,0 +1,140 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + if (! empty($field_value)) + $field_value = explode('|', $field_value); + + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + + if ($tpl_empty) + { + $value = array(); + + if (! empty($field_value)) + { + $value = array_diff(explode('|', $field_value), array('')); + $value = array_map('clean_php', $value); + } + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_value', $value); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + if ($tpl_empty) + { + $value = array(); + + if (! empty($field_value)) + { + $value = explode('|', $field_value); + $value = array_map('clean_php', $value); + } + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_value', $value); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'save': + $save = array(); + + if (is_array($field_value)) + { + foreach ($field_value AS $k => $v) + { + $save[] = preg_replace('/[^\d.]/', '', $v); + } + } + + return empty($save) ? '' : implode('|', $save); + + case 'api': + if (! empty($field_value)) + $field_value = explode('|', $field_value); + + return $field_value; + + case 'name': + return $AVE_Template->get_config_vars('name'); + + default: return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/single_line_numeric_three/js/field.js b/fields/single_line_numeric_three/js/field.js new file mode 100644 index 0000000..af84e5d --- /dev/null +++ b/fields/single_line_numeric_three/js/field.js @@ -0,0 +1,26 @@ +$(document).ready(function() { + $(".field_numeric").on('keydown', function(event) { + var num_dot = $(this).attr('data-num-dot'); + var keyCode = window.event ? event.keyCode : event.which; + var foo = 0; + // prevent if already dot + if (keyCode != 8 && keyCode != 46) { + if ((foo == 0) && (keyCode != 190) && (keyCode < 96 || keyCode > 105) && (keyCode < 46 || keyCode > 59)) { + event.preventDefault(); + } // prevent if not number/dot + } + if ($(this).val().indexOf('.') > -1) { + if (keyCode == 190) event.preventDefault(); + } + $(this).keyup(function() { + this.value = this.value.replace(/[^0-9.]/i, ""); + if($(this).val().indexOf('.')!=-1){ + if($(this).val().split(".")[1].length >= num_dot){ + if( isNaN( parseFloat( this.value ) ) ) return; + this.value = parseFloat(this.value).toFixed(num_dot); + } + } + return this; + }); + }); +}); \ No newline at end of file diff --git a/fields/single_line_numeric_three/lang/bg.txt b/fields/single_line_numeric_three/lang/bg.txt new file mode 100644 index 0000000..51dcca4 --- /dev/null +++ b/fields/single_line_numeric_three/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Едноредово (Числово)" \ No newline at end of file diff --git a/fields/single_line_numeric_three/lang/cz.txt b/fields/single_line_numeric_three/lang/cz.txt new file mode 100644 index 0000000..67162c8 --- /dev/null +++ b/fields/single_line_numeric_three/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Jednořádkový (Číselný)" \ No newline at end of file diff --git a/fields/single_line_numeric_three/lang/en.txt b/fields/single_line_numeric_three/lang/en.txt new file mode 100644 index 0000000..fce8b0c --- /dev/null +++ b/fields/single_line_numeric_three/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Single line (Numbers)" \ No newline at end of file diff --git a/fields/single_line_numeric_three/lang/pl.txt b/fields/single_line_numeric_three/lang/pl.txt new file mode 100644 index 0000000..74abffa --- /dev/null +++ b/fields/single_line_numeric_three/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Linia pojedyncza (Numeryczne)" \ No newline at end of file diff --git a/fields/single_line_numeric_three/lang/ru.txt b/fields/single_line_numeric_three/lang/ru.txt new file mode 100644 index 0000000..1cba424 --- /dev/null +++ b/fields/single_line_numeric_three/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однострочное (Числовое тройное)" \ No newline at end of file diff --git a/fields/single_line_numeric_three/lang/ua.txt b/fields/single_line_numeric_three/lang/ua.txt new file mode 100644 index 0000000..37bf67d --- /dev/null +++ b/fields/single_line_numeric_three/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однорядкове (Числове)" \ No newline at end of file diff --git a/fields/single_line_numeric_three/tpl/field-doc.tpl b/fields/single_line_numeric_three/tpl/field-doc.tpl new file mode 100644 index 0000000..e0b3cf7 --- /dev/null +++ b/fields/single_line_numeric_three/tpl/field-doc.tpl @@ -0,0 +1 @@ +{$field_value.0} - {$field_value.1} - {$field_value.2} \ No newline at end of file diff --git a/fields/single_line_numeric_three/tpl/field-req.tpl b/fields/single_line_numeric_three/tpl/field-req.tpl new file mode 100644 index 0000000..e0b3cf7 --- /dev/null +++ b/fields/single_line_numeric_three/tpl/field-req.tpl @@ -0,0 +1 @@ +{$field_value.0} - {$field_value.1} - {$field_value.2} \ No newline at end of file diff --git a/fields/single_line_numeric_three/tpl/field.tpl b/fields/single_line_numeric_three/tpl/field.tpl new file mode 100644 index 0000000..1e7d813 --- /dev/null +++ b/fields/single_line_numeric_three/tpl/field.tpl @@ -0,0 +1,8 @@ +{if $single_line_numeric != 'load'} + {assign var=single_line_numeric value='' scope="global"} + + {assign var=single_line_numeric value="load" scope="global"} +{/if} + + + \ No newline at end of file diff --git a/fields/single_line_numeric_two/field.php b/fields/single_line_numeric_two/field.php new file mode 100644 index 0000000..94b3d57 --- /dev/null +++ b/fields/single_line_numeric_two/field.php @@ -0,0 +1,140 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + if (! empty($field_value)) + $field_value = explode('|', $field_value); + + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + + if ($tpl_empty) + { + $value = array(); + + if (! empty($field_value)) + { + $value = array_diff(explode('|', $field_value), array('')); + $value = array_map('clean_php', $value); + } + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_value', $value); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + if ($tpl_empty) + { + $value = array(); + + if (! empty($field_value)) + { + $value = explode('|', $field_value); + $value = array_map('clean_php', $value); + } + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_value', $value); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'save': + $save = array(); + + if (is_array($field_value)) + { + foreach ($field_value AS $k => $v) + { + $save[] = preg_replace('/[^\d.]/', '', $v); + } + } + + return empty($save) ? '' : implode('|', $save); + + case 'api': + if (! empty($field_value)) + $field_value = explode('|', $field_value); + + return $field_value; + + case 'name': + return $AVE_Template->get_config_vars('name'); + + default: return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/single_line_numeric_two/js/field.js b/fields/single_line_numeric_two/js/field.js new file mode 100644 index 0000000..af84e5d --- /dev/null +++ b/fields/single_line_numeric_two/js/field.js @@ -0,0 +1,26 @@ +$(document).ready(function() { + $(".field_numeric").on('keydown', function(event) { + var num_dot = $(this).attr('data-num-dot'); + var keyCode = window.event ? event.keyCode : event.which; + var foo = 0; + // prevent if already dot + if (keyCode != 8 && keyCode != 46) { + if ((foo == 0) && (keyCode != 190) && (keyCode < 96 || keyCode > 105) && (keyCode < 46 || keyCode > 59)) { + event.preventDefault(); + } // prevent if not number/dot + } + if ($(this).val().indexOf('.') > -1) { + if (keyCode == 190) event.preventDefault(); + } + $(this).keyup(function() { + this.value = this.value.replace(/[^0-9.]/i, ""); + if($(this).val().indexOf('.')!=-1){ + if($(this).val().split(".")[1].length >= num_dot){ + if( isNaN( parseFloat( this.value ) ) ) return; + this.value = parseFloat(this.value).toFixed(num_dot); + } + } + return this; + }); + }); +}); \ No newline at end of file diff --git a/fields/single_line_numeric_two/lang/bg.txt b/fields/single_line_numeric_two/lang/bg.txt new file mode 100644 index 0000000..51dcca4 --- /dev/null +++ b/fields/single_line_numeric_two/lang/bg.txt @@ -0,0 +1,3 @@ +[admin] + +name = "Едноредово (Числово)" \ No newline at end of file diff --git a/fields/single_line_numeric_two/lang/cz.txt b/fields/single_line_numeric_two/lang/cz.txt new file mode 100644 index 0000000..67162c8 --- /dev/null +++ b/fields/single_line_numeric_two/lang/cz.txt @@ -0,0 +1,2 @@ +[admin] +name = "Jednořádkový (Číselný)" \ No newline at end of file diff --git a/fields/single_line_numeric_two/lang/en.txt b/fields/single_line_numeric_two/lang/en.txt new file mode 100644 index 0000000..fce8b0c --- /dev/null +++ b/fields/single_line_numeric_two/lang/en.txt @@ -0,0 +1,2 @@ +[admin] +name = "Single line (Numbers)" \ No newline at end of file diff --git a/fields/single_line_numeric_two/lang/pl.txt b/fields/single_line_numeric_two/lang/pl.txt new file mode 100644 index 0000000..74abffa --- /dev/null +++ b/fields/single_line_numeric_two/lang/pl.txt @@ -0,0 +1,2 @@ +[admin] +name = "Linia pojedyncza (Numeryczne)" \ No newline at end of file diff --git a/fields/single_line_numeric_two/lang/ru.txt b/fields/single_line_numeric_two/lang/ru.txt new file mode 100644 index 0000000..0ce29ac --- /dev/null +++ b/fields/single_line_numeric_two/lang/ru.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однострочное (Числовое двойное)" \ No newline at end of file diff --git a/fields/single_line_numeric_two/lang/ua.txt b/fields/single_line_numeric_two/lang/ua.txt new file mode 100644 index 0000000..37bf67d --- /dev/null +++ b/fields/single_line_numeric_two/lang/ua.txt @@ -0,0 +1,2 @@ +[admin] +name = "Однорядкове (Числове)" \ No newline at end of file diff --git a/fields/single_line_numeric_two/tpl/field-doc.tpl b/fields/single_line_numeric_two/tpl/field-doc.tpl new file mode 100644 index 0000000..a992a59 --- /dev/null +++ b/fields/single_line_numeric_two/tpl/field-doc.tpl @@ -0,0 +1 @@ +{$field_value.0} - {$field_value.1} \ No newline at end of file diff --git a/fields/single_line_numeric_two/tpl/field-req.tpl b/fields/single_line_numeric_two/tpl/field-req.tpl new file mode 100644 index 0000000..a992a59 --- /dev/null +++ b/fields/single_line_numeric_two/tpl/field-req.tpl @@ -0,0 +1 @@ +{$field_value.0} - {$field_value.1} \ No newline at end of file diff --git a/fields/single_line_numeric_two/tpl/field.tpl b/fields/single_line_numeric_two/tpl/field.tpl new file mode 100644 index 0000000..d748808 --- /dev/null +++ b/fields/single_line_numeric_two/tpl/field.tpl @@ -0,0 +1,7 @@ +{if $single_line_numeric != 'load'} + {assign var=single_line_numeric value='' scope="global"} + + {assign var=single_line_numeric value="load" scope="global"} +{/if} + + \ No newline at end of file diff --git a/fields/tags/field.php b/fields/tags/field.php new file mode 100644 index 0000000..90d8055 --- /dev/null +++ b/fields/tags/field.php @@ -0,0 +1,239 @@ + 0) + ? $rubric_id + : ($_REQUEST['rubric_id'] + ? (int)$_REQUEST['rubric_id'] + : $AVE_DB->Query("SELECT rubric_id FROM ".PREFIX."_documents WHERE Id = '".$_REQUEST['Id']."'")->GetCell()); + + $lang_file = $fld_dir . 'lang/' . (defined('ACP') + ? $_SESSION['admin_language'] + : $_SESSION['user_language']) . '.txt'; + + $AVE_Template->config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + $sql = " + SELECT DISTINCT + tag + FROM + ".PREFIX."_document_tags + WHERE + rubric_id = '".$rubric_id."' + ORDER BY tag ASC + "; + + $query = $AVE_DB->Query($sql); + + $field_tags = array(); + + while ($row = $query->GetCell()) + array_push($field_tags, $row); + + $field_value = explode('|', $field_value); + $field_value = array_diff($field_value, array('')); + + $total = count($field_tags); + + $field_points = array(ceil($total/4), 2*ceil($total/4), 3*ceil($total/4)); + + $AVE_Template->assign('field_points', $field_points); + $AVE_Template->assign('field_tags', $field_tags); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + case 'doc': + + $AVE_Template->config_load($lang_file, 'public'); + + if ($tpl_empty) + { + $field_value = explode('|', $field_value); + $field_value = array_diff($field_value, array('')); + $field_value = array_values($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_param = array_diff($field_param, array('')); + $field_param = array_values($field_param); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function ($data) use ($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'req': + + $AVE_Template->config_load($lang_file, 'public'); + + if ($tpl_empty) + { + $field_value = explode('|', $field_value); + $field_value = array_diff($field_value, array('')); + $field_value = array_values($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_param = array_diff($field_param, array('')); + $field_param = array_values($field_param); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if ($tpl_empty && $tpl_file) + { + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_default', $default); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + break; + + case 'save': + // Регистрируем хук + Hooks::register('DocumentAfterSave', 'afterTagsSave', 10); + + $field_value = tagsValue($field_value); + + if (! empty($field_value)) + $field_value = '|' . implode('|', $field_value) . '|'; + + return $field_value; + + case 'api': + if (! empty($field_value)) + { + $field_value = explode('|', $field_value); + $field_value = array_diff($field_value, ['']); + } + return $field_value; + + case 'name': + return $AVE_Template->get_config_vars('name'); + + default: + return $field_value; + } + } + + if (! function_exists('tagsValue')) + { + function tagsValue ($field_value) + { + // Если есть выделенные теги + if (! empty($field_value['tags'])) + $tags = $field_value['tags']; + else + $tags = array(); + + unset ($tags['other']); + + // Если есть теги через зяпятую + if (! empty($field_value['tags']['other'])) + { + $tags_new = explode(',', $field_value['tags']['other']); + $tags_new = array_map('trim', $tags_new); + } + else + $tags_new = array(); + + // Совмещаем массивы + $tags = array_merge($tags, $tags_new); + + // Делаем уникальные значения + $field_value = array_unique($tags); + + return $field_value; + } + } + + if (! function_exists('afterTagsSave')) + { + function afterTagsSave ($data) + { + global $AVE_Document; + + if (! $AVE_Document) + { + require_once BASE_DIR . '/class/class.docs.php'; + + $AVE_Document = new AVE_Document(); + } + + foreach ($data['feld'] AS $_k => $_v) + { + if (array_key_exists('tags', $_v)) + { + $tags = tagsValue($_v); + + if (! empty($tags)) + { + $tags = implode(',', $tags); + $AVE_Document->saveTags($data['document_id'], $data['rubric_id'], $tags); + } + } + } + } + } +?> \ No newline at end of file diff --git a/fields/tags/lang/ru.txt b/fields/tags/lang/ru.txt new file mode 100644 index 0000000..f36077a --- /dev/null +++ b/fields/tags/lang/ru.txt @@ -0,0 +1,4 @@ +[admin] +name = "Теги" +new = "Новые теги, через запятую" +notags = "Отсутвуют теги" \ No newline at end of file diff --git a/fields/tags/tpl/field-doc.tpl b/fields/tags/tpl/field-doc.tpl new file mode 100644 index 0000000..8d69782 --- /dev/null +++ b/fields/tags/tpl/field-doc.tpl @@ -0,0 +1,9 @@ +{* + $field_id + $field_value +*} +{if $field_value} +{foreach from=$field_value item=tag} +
    34. {$tag}
    35. +{/foreach} +{/if} \ No newline at end of file diff --git a/fields/tags/tpl/field-req.tpl b/fields/tags/tpl/field-req.tpl new file mode 100644 index 0000000..8166f56 --- /dev/null +++ b/fields/tags/tpl/field-req.tpl @@ -0,0 +1,5 @@ +{* + $field_id + $field_value +*} +{$field_value} \ No newline at end of file diff --git a/fields/tags/tpl/field.tpl b/fields/tags/tpl/field.tpl new file mode 100644 index 0000000..cdfb25d --- /dev/null +++ b/fields/tags/tpl/field.tpl @@ -0,0 +1,26 @@ +{if $field_tags} +
      +{foreach from=$field_tags item=tag name=tags} + +{if in_array($smarty.foreach.tags.index, $field_points)} +
      +
      +
      +{/if} +{/foreach} +
      +
      +{else} +
        +
      • {#notags#}
      • +
      +{/if} +
      +
      +
      +
      {#new#}
      + +
      +
      \ No newline at end of file diff --git a/fields/teasers/css/field.css b/fields/teasers/css/field.css new file mode 100644 index 0000000..0a676da --- /dev/null +++ b/fields/teasers/css/field.css @@ -0,0 +1,18 @@ +.multi_lists { + position: relative; +} + +.multi_lists > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/teasers/field.php b/fields/teasers/field.php new file mode 100644 index 0000000..a2fac27 --- /dev/null +++ b/fields/teasers/field.php @@ -0,0 +1,174 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + case 'edit': + + $items = array(); + + $items = unserialize($field_value); + + if($items != false){ + + foreach($items as $k => $v){ + $list_item = explode('|', $v); + + $list[$k]['param'] = (isset($list_item[0])) ? htmlspecialchars($list_item[0], ENT_QUOTES) : ''; + $list[$k]['value'] = (isset($list_item[1])) ? htmlspecialchars($list_item[1], ENT_QUOTES) : ''; + } + + $items = $list; + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + $AVE_Template->assign('doc_id', $_REQUEST['Id']); + $AVE_Template->assign('items', $items); + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + + return $AVE_Template->fetch($tpl_file); + + case 'save': + foreach ($field_value as $v) + { + if(! empty($v['value']) && ! empty($v['param'])) + { + $field_value_new[] = $v['param'] . ($v['value'] ? '|' . $v['value'] : ''); + } + } + if (isset($field_value_new)) + { + return @serialize($field_value_new); + } + else + { + return $field_value_new = ''; + } + break; + + case 'doc': + $items = (isset($field_value)) + ? unserialize($field_value) + : array(); + + $res = array(); + + if ($items != false) + { + foreach($items as $item) + { + $item = explode('|', $item); + + if ($item[1]) + $res[] = showteaser($item[1]); + } + } + + return (! empty($res)) + ? implode(PHP_EOL, $res) + : $tpl; + + break; + + case 'req': + return get_field_default($field_value, $action, $field_id, $tpl, $tpl_empty); + + case 'api' : + if (! empty($field_value)) + return unserialize($field_value); + + return $field_value; + break; + + case 'name' : + return $AVE_Template->get_config_vars('name'); + break; + + case 'search': + + $field_default = explode(',', $default); + + $zap_1 = ($field_default[0]) ? ',' : ''; + $zap_2 = ($field_default[0] && $field_default[1]) ? ',' : ''; + + $sel_1 = ($field_default[0]) ? 'b.field_value as b1' : ''; + $sel_2 = ($field_default[1]) ? 'c.field_value as c1' : ''; + + $from_1 = ($field_default[0]) ? PREFIX . '_document_fields b' : ''; + $from_2 = ($field_default[1]) ? PREFIX . '_document_fields c' : ''; + + $search_1 = ($field_default[0]) ? "AND (b.document_id=a.Id AND b.rubric_field_id = " . $field_default[0] . ")" : ''; + $search_2 = ($field_default[1]) ? "AND (c.document_id=a.Id AND c.rubric_field_id = " . $field_default[1] . ")" : ''; + + $or_1 = ($field_default[0]) ? "OR (UPPER(b.field_value) LIKE UPPER('%" . $_REQUEST['q'] . "%'))" : ''; + $or_2 = ($field_default[1]) ? "OR (UPPER(c.field_value) LIKE UPPER('%" . $_REQUEST['q'] . "%'))" : ''; + + $sql = $AVE_DB->Query(" + SELECT + a.Id, + a.document_title + $zap_1 + $sel_1 + $zap_2 + $sel_2 + FROM + " . PREFIX . "_documents a + $zap_1 + " . $from_1 . " + $zap_2 + " . $from_2 . " + WHERE + a.rubric_id = '" . $_REQUEST['rubric_id'] . "' + AND + a.document_status = 1 + " . $search_1 . " + " . $search_2 . " + AND + ( + (UPPER(document_title) LIKE UPPER('%" . $_REQUEST['q'] . "%')) + $or_1 + $or_2 + ) + GROUP BY a.Id + LIMIT 0,5 + "); + + $doc_finded = array(); + + while ($row = $sql->FetchRow()) + { + $doc_finded[] = array( + 'doc_id' => $row->Id, + 'doc_title' => $row->document_title, + 'doc_name' => (($field_default[0]) ? $row->b1 : $row->document_title), + 'doc_article' => (($field_default[1]) ? $row->c1 : '') + ); + } + + echo json_encode($doc_finded); + exit; + + default: + return $field_value; + } + + return ($res ? $res : $field_value); + } +?> \ No newline at end of file diff --git a/fields/teasers/js/field.js b/fields/teasers/js/field.js new file mode 100644 index 0000000..bede30f --- /dev/null +++ b/fields/teasers/js/field.js @@ -0,0 +1,142 @@ +var Teasers = { + + init: false, + + init: function() { + if (this.initialized) return; + this.initialized = true; + + this.Analoque_items(); + }, + + Analoque_items: function() { + this.Analoque_sortable(); + this.Analoque_del_item(); + this.Analoque_add(); + this.Analoque_search(); + }, + + Analoque_update: function() { + this.Analoque_maxid(); + this.Analoque_del_item(); + this.Analoque_search(); + AveAdmin.tooltip(); + }, + + /** + * @return {number} + */ + Analoque_maxid: function(id) + { + var maxid = 1; + $('#analoque_lists_' + id).children('.analoque_list').each(function() { + maxid = Math.max(maxid, parseInt($(this).attr("data-id")) + 1); + }); + return maxid; + }, + + Analoque_del_item: function() + { + $('.analoque_list .DelButton').on('click', function(event) { + event.preventDefault(); + var id = $(this).attr('data-id'); + jConfirm( + analoque_del_conf, + analoque_del_head, + function(b) { + if (b) { + $('#analoque_list_' + id).remove(); + } + } + ); + }); + }, + + Analoque_add: function() + { + $('.AddButton').on('click', function() { + c_id = $(this).parent().parent('.analoque_lists').attr("data-id"); + d_id = $(this).parent().parent('.analoque_lists').attr("data-docid"); + i_id = Teasers.Analoque_maxid(d_id + '_' + c_id); + $('#analoque_lists_' + d_id + '_' + c_id + ':last').append( + '
      ' + + '  Id:   ×' + + '
      ' + + '
      ' + ); + + Teasers.Analoque_update(); + }); + }, + + Analoque_sortable: function() { + $('.analoque_lists').sortable({ + handle: ".handle", + placeholder: "ui-state-highlight grey_bg" + }); + }, + + /** + * @return {boolean} + */ + Analoque_search: function() { + + var res_search = false; + + $('.search_analoque').on('input', function(event) + { + event.preventDefault(); + + var query = $(this); + + var did = query.attr('data-docid'); + var fid = query.attr('data-fieldid'); + var kid = query.attr('data-id'); + var field_id_input = $('.field_' + did + '_' + fid + '_' + kid); + + if (res_search) + return false; + + res_search = true; + + query.autocomplete("index.php?do=fields&field=teasers&type=search&doc_id=" + did + "&field_id=" + fid, { + width: query.outerWidth(), + max: 5, + dataType: "json", + matchContains: "word", + scroll: true, + scrollHeight: 200, + parse: function(data) { + res_search = false; + + if (typeof data === 'object') + { + return $.map(data, function(row) { + return { + data: row, + value: row.doc_title, + result: query.val() + } + }); + } + + return false; + }, + formatItem: function(item) { + return '
      ' + item.doc_article + ' ' + item.doc_name + '
      '; + } + }).result(function(e, item) { + query.val(item.doc_name); + field_id_input.val(item.doc_id); + }); + + return false; + }); + + return false; + } +} + +$(document).ready(function() { + Teasers.init(); +}); diff --git a/fields/teasers/lang/bg.txt b/fields/teasers/lang/bg.txt new file mode 100644 index 0000000..bc6a9e5 --- /dev/null +++ b/fields/teasers/lang/bg.txt @@ -0,0 +1,8 @@ +[admin] +name = "Аналогични продукти" +delete = "Изтриване на елемент" +param = "Продукт" +value = "Id" +del_conf = "Сигурни ли сте, че желаете да изтриете този елемент (продукт)?" +del_head = "Изтриване на елемент (продукт) ..." +add = "Добави" \ No newline at end of file diff --git a/fields/teasers/lang/cz.txt b/fields/teasers/lang/cz.txt new file mode 100644 index 0000000..7a68fac --- /dev/null +++ b/fields/teasers/lang/cz.txt @@ -0,0 +1,8 @@ +[admin] +name = "Podobné produkty" +delete = "Odstranit prvek" +param = "Zboží" +value = "ID" +del_conf = "Opravdu chcete odstranit tento prvek (zboží)?" +del_head = "Odsranění prvku (zboží)..." +add = "Přidat" \ No newline at end of file diff --git a/fields/teasers/lang/pl.txt b/fields/teasers/lang/pl.txt new file mode 100644 index 0000000..11e1625 --- /dev/null +++ b/fields/teasers/lang/pl.txt @@ -0,0 +1,8 @@ +[admin] +name = "Podobne produkty" +delete = "Usuń element" +param = "Produkt" +value = "ID" +del_conf = "Czy na pewno chcesz usunąć ten element (produkt)?" +del_head = "Usunięcie elementu (produktu) ..." +add = "Dodaj" \ No newline at end of file diff --git a/fields/teasers/lang/ru.txt b/fields/teasers/lang/ru.txt new file mode 100644 index 0000000..c6c544b --- /dev/null +++ b/fields/teasers/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Тизеры" +delete = "Удалить элемент" +param = "Документ" +value = "Id" +del_conf = "Вы уверены, что хотите удалить данный элемент?" +del_head = "Удаление элемента ..." +add = "Добавить" \ No newline at end of file diff --git a/fields/teasers/lang/ua.txt b/fields/teasers/lang/ua.txt new file mode 100644 index 0000000..185d633 --- /dev/null +++ b/fields/teasers/lang/ua.txt @@ -0,0 +1,8 @@ +[admin] +name = "Аналогічні товари" +delete = "Видалити елемент" +param = "Товар" +value = "Id" +del_conf = "Ви впевнені, що бажаєте видалити цей елемент (товар)?" +del_head = "Видаленя елемента (товара)..." +add = "Додати" \ No newline at end of file diff --git a/fields/teasers/tpl/field.tpl b/fields/teasers/tpl/field.tpl new file mode 100644 index 0000000..11fdf93 --- /dev/null +++ b/fields/teasers/tpl/field.tpl @@ -0,0 +1,29 @@ +{if $analoque != 'load'} + {assign var=teasers value='' scope="global"} + {if $smarty.request.outside} + + {else} + + {/if} + + + {assign var=teasers value="load" scope="global"} +{/if} + +
      +{foreach from=$items key=key item=item} + +
      +   Id:   {if $key == 0}+{else}×{/if} +
      +
      + +{/foreach} +
      \ No newline at end of file diff --git a/fields/text_to_image/.htaccess b/fields/text_to_image/.htaccess new file mode 100644 index 0000000..524e0de --- /dev/null +++ b/fields/text_to_image/.htaccess @@ -0,0 +1,4 @@ +Deny from all + + Allow from all + \ No newline at end of file diff --git a/fields/text_to_image/class.txtimage.php b/fields/text_to_image/class.txtimage.php new file mode 100644 index 0000000..c00f629 --- /dev/null +++ b/fields/text_to_image/class.txtimage.php @@ -0,0 +1,279 @@ +do_cache === true){ + if(!is_dir($this->cache_folder)){ + if(!mkdir($this->cache_folder, 0755)){ + $this->do_cache = false; + } + if(!is_writable($this->cache_folder)){ + $this->do_cache = false; + } + } + else { + if(!is_writable($this->cache_folder)){ + $this->do_cache = false; + if(!chmod($this->cache_folder, 0755)){ + $this->do_cache = false; + } + else { + if(is_writable($this->cache_folder)){ + $this->do_cache = true; + } + } + } + } + } + else { + $this->do_cache = false; + } + } + + + private function cache($text, $font, $size, $color, $trans = 0, $shadow = false, $shadow_off = false) + { + if($this->do_cache){ + $hash = md5($text . $font . $size . $color . $trans . $shadow . $shadow_off); + if(file_exists($this->cache_folder . '/' . $hash . '.png')){ + $image = file_get_contents($this->cache_folder . '/' . $hash . '.png'); + $text = file_get_contents($this->cache_folder . '/' . $hash . '.txt'); + if($this->return_as_html !== true){ + return $image; + } + else { + if ($this->embed_image) { + return ''.$text.''; + } + else { + return ''.$text.''; + } + } + } + else { + return false; + } + } + else { + return false; + } + } + + public function generate($text, $font, $size, $color, $display_alt = 1, $trans = 0, $shadow = false, $shadow_off = false) + { + + $cache = $this->cache($text, $font, $size, $color, $trans, $shadow, $shadow_off); + if($cache !== false){ return $cache; } + if ($display_alt == 1){ + $text = ( !empty($text) ? trim(urldecode($text)) : "Заполните все поля!" ); + $textWeb = str_replace(array("\n", "\r\n", "\r"), " ", $text); + } + else { + $text = ( !empty($text) ? trim(urldecode($text)) : "Нет сопоставлений" ); + $textWeb = str_replace(array("\n", "\r\n", "\r"), " ", ''); + } + if(file_exists($font)){ $font = $font; } + elseif(file_exists($font.'.ttf')){ $font = $font.'.ttf'; } + elseif(file_exists($font.'.otf')){ $font = $font.'.otf'; } + elseif(file_exists(BASE_DIR . '/fields/text_to_image/fonts/'.$font.'')){ $font = BASE_DIR . '/fields/text_to_image/fonts/'.$font.''; } + elseif(file_exists(BASE_DIR . '/fields/text_to_image/fonts/'.$font.'.ttf')){ $font = BASE_DIR . '/fields/text_to_image/fonts/'.$font.'.ttf'; } + elseif(file_exists(BASE_DIR . '/fields/text_to_image/fonts/'.$font.'.otf')){ $font = BASE_DIR . '/fields/text_to_image/fonts/'.$font.'.otf'; } + else { + $error_image = "iVBORw0KGgoAAAANSUhEUgAAAI0AAAANCAYAAACU7u19AAAEB0lEQVRYhe2YT2jcRR"; + $error_image.= "THP7MsEkppaYzFxjStpIdQBVu81NsDe+il4MFrVUSlerClYlOqJRSpMZUGVFqLPVQt"; + $error_image.= "VA+CB5uDCuEdaj14EFEqGMH4b6mkVSyhlBIyHn5v4+z4m9ndbMCU5AvLb2fem/e+78"; + $error_image.= "3Mm9/8YAXLHl7kWDv6FS9yolMjK7jtUWlV0YuMVxIDWjaygmWHSjUn9SJdwBHgL+BO"; + $error_image.= "4KhTvRnI33Cq+8raXuQs8C3wgFN93Is8BvQA9wDjTnXCi5wzHYD7TO8OYNh8rjOft7"; + $error_image.= "zIQYrFPAu861SvepFRpzqU4b8XWA1sAD52qhczPL62YT841QvGf9L8rbM8nIjjBb4v"; + $error_image.= "8THPy4tsBd5yqg97kUeBfmA38AlQc6ofNovD7Iw61SEvcsypvlR/Brlu4OpUZzM8qs"; + $error_image.= "ArlmOAbV7kEDAXxPpIGVeA7KIBngNOOtWaF+mz9lggn/QiW5zqj15kPfBHILviVMe8"; + $error_image.= "yAiAU30/SvaE6Ry3vhETPwOccapTXmQz8JQXuQ5cdKqXIn7ZiuhUTwc+R8xGisdYNH"; + $error_image.= "zGqb5qeluN13/iLfMR8XoBuGx8PjK9DZG/Vip7JfFMcT2V4mHyc071so0ZcKqvheOd"; + $error_image.= "6qkEVypArxc5GP6APpNvdKo1C/g3it0Z4gKwy/7vAj4zR9UmibiRkW1yqlPmcwrYCG"; + $error_image.= "wvWTBE3J9MGfQiPcB0mzzmK6oldxOJeFM+vMhO4AtgJuOn5Tja5JrjMVBfMIY/c+Nj"; + $error_image.= "VCnKzvHISX3X3+1Fng9E10I9qwb3WvPBYBdv499jBy+yGthLUf5mgd4cqRLMJfprQa"; + $error_image.= "W634scCHeFF1lDUWq7gac75DFXFm/sIxqzx47cEfLIxrEAxPmKeaTymRrfgGbHU82p"; + $error_image.= "vtlEZ8aLrIr6dgNvB+1hYNSpXoWGRdkqmpZvp/qdF9kT9V0HXvQi/RQleaADHnUODf"; + $error_image.= "GW+Dhttp8A3mvDfjKOBWA+Xwvkkcv3XLPJmPQig010PgeGgK+Cvn6neiVod9UnylCN"; + $error_image.= "niF+tXcZbCJ+B77xIjtyJGwiZ8tkTvUXipKb4lGGrsD2IPCzNcviDX0ArAIecqoTOc"; + $error_image.= "5lyMWxAK4pHj9F89qdGF+GfVXKS1G97x3gZS9SPzPP27tNiEvAB8B2c7ofWO9FDpi8"; + $error_image.= "Dzhpu3qaYqK22LegLxM+j3qRaYob27Ddng55EaFI6Hl71+oNblVrgflvTnYL22927w"; + $error_image.= "LGgVsRj57Id4g1XuQwjbenhngTPgAGgWdLYku1k3GU6OyI3jtzXFM86jn+29qbg9vT"; + $error_image.= "WoqTIcX1CIsBL3Im+P/6ohj9n5GLI4x3KaDTnLf7utDxRzwv0g3Ugq6zndpcyiiJd9"; + $error_image.= "lhMb787gQ+rTeiq9ztjNQNoiHeJYJmt6FFHf8PmykzDVQO9iwAAAAASUVORK5CYII="; + + if($this->return_as_html !== true){ + return base64_decode($error_image); + } + else { + return 'Ошибка при загрузке шрифта!'; + } + } + + $sizes = $this->getfontbox($size, 0, $font, $text); + $colors = $this->color($color); + + if ($shadow !== false) { + if (is_numeric($shadow) && $shadow <= 4) { + if ($shadow_off != false) { + $i_base = $shadow_off; + } + $im = imagecreatetruecolor($sizes['width']+$shadow+$i_base+1, $sizes['height']+$shadow+$i_base+1); + } + else { + $im = imagecreatetruecolor($sizes['width'], $sizes['height']); + } + } + else { + $im = imagecreatetruecolor($sizes['width'], $sizes['height']); + } + imagesavealpha($im, true); + + if (is_numeric($trans) && $trans <= 127 && $trans >= 0) { + + } + + + $color = imagecolorallocatealpha($im, $colors[0], $colors[1], $colors[2], $trans); + + $trans_color = imagecolorallocatealpha($im, 0, 0, 0, 127); + imagefill($im, 0, 0, $trans_color); + + if ($shadow !== false && $shadow <= 4) { + if ($shadow_off != false) { + $i_base = $shadow_off; + } + else { + $i_base = 0; + } + for ($i=$i_base,$o=64; $i < $shadow+$i_base; $i++,$o+=16) { + $shadow_color = imagecolorallocatealpha($im, 100, 100, 100, $o); + imagettftext($im, $size, 0, $sizes['left']+$i+1, $sizes['top']+$i+1, $shadow_color, $font, $text); + } + } + + imagettftext($im, $size, 0, $sizes['left'], $sizes['top'], $color, $font, $text); + + ob_start(); + imagepng($im); + $image = ob_get_clean(); + imagedestroy($im); + + if($this->do_cache){ + $hash = md5($text . $font . $size . $color . $shadow); + file_put_contents($this->cache_folder . '/' . $hash . '.png', $image); + file_put_contents($this->cache_folder . '/' . $hash . '.txt', $textWeb); + } + + if($this->return_as_html !== true){ + return $image; + } + else { + if ($this->embed_image == true) { + return ''.$textWeb.''; + } + else { + if ($this->do_cache == false) { + return ''.$textWeb.''; + } + else { + return ''.$textWeb.''; + } + } + } + } + + private function getfontbox($font_size, $font_angle, $font_file, $text) + { + $box = imagettfbbox($font_size, $font_angle, $font_file, $text); + if( !$box ) return false; + $min_x = min( array($box[0], $box[2], $box[4], $box[6]) ); + $max_x = max( array($box[0], $box[2], $box[4], $box[6]) ); + $min_y = min( array($box[1], $box[3], $box[5], $box[7]) ); + $max_y = max( array($box[1], $box[3], $box[5], $box[7]) ); + $width = ( $max_x - $min_x ); + $height = ( $max_y - $min_y ); + $left = abs( $min_x ) + $width; + $top = abs( $min_y ) + $height; + $img = @imagecreatetruecolor( $width << 2, $height << 2 ); + $white = imagecolorallocate( $img, 255, 255, 255 ); + $black = imagecolorallocate( $img, 0, 0, 0 ); + imagefilledrectangle($img, 0, 0, imagesx($img), imagesy($img), $black); + imagettftext( $img, $font_size, + $font_angle, $left, $top, + $white, $font_file, $text); + $rleft = $w4 = $width<<2; + $rright = 0; + $rbottom = 0; + $rtop = $h4 = $height<<2; + for( $x = 0; $x < $w4; $x++ ) + for( $y = 0; $y < $h4; $y++ ) + if( imagecolorat( $img, $x, $y ) ){ + $rleft = min( $rleft, $x ); + $rright = max( $rright, $x ); + $rtop = min( $rtop, $y ); + $rbottom = max( $rbottom, $y ); + } + imagedestroy( $img ); + return array( "left" => $left - $rleft, + "top" => $top - $rtop, + "width" => $rright - $rleft + 1, + "height" => $rbottom - $rtop + 1 ); + } + + private function color($color) + { + if($color[0].$color[1].$color[2] == "rgb"){ + preg_match("/^rgb\((\d*),\s(\d*),\s(\d*)\)$/", $color, $colors); + return array($colors[1], $colors[2], $colors[3]); + } + else { + if ($color[0] == '#') + $color = substr($color, 1); + + if (strlen($color) == 6) + list($r, $g, $b) = array($color[0].$color[1], + $color[2].$color[3], + $color[4].$color[5]); + elseif (strlen($color) == 3) + list($r, $g, $b) = array($color[0].$color[0], $color[1].$color[1], $color[2].$color[2]); + else + return false; + + $r = hexdec($r); $g = hexdec($g); $b = hexdec($b); + + return array($r, $g, $b); + } + } + +} +?> \ No newline at end of file diff --git a/fields/text_to_image/css/field.css b/fields/text_to_image/css/field.css new file mode 100644 index 0000000..d38a6dd --- /dev/null +++ b/fields/text_to_image/css/field.css @@ -0,0 +1,18 @@ +.get_field_text_to_image { + position: relative; +} + +.get_field_text_to_image > .ui-state-highlight { + display: inline-block; + margin: 3px; + width: 450px; + height: 26px; + background-color: rgba(255,255,255,0.5); !important; + border: solid 1px #eaeaea; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + position: relative; + text-align: center; + padding: 0 !important; +} \ No newline at end of file diff --git a/fields/text_to_image/field.php b/fields/text_to_image/field.php new file mode 100644 index 0000000..d4c3896 --- /dev/null +++ b/fields/text_to_image/field.php @@ -0,0 +1,128 @@ +config_load($lang_file, 'lang'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + $AVE_Template->config_load($lang_file, 'admin'); + + switch ($action) + { + // Отображение поля в административной части + case 'edit': + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin', $_tpl); + + return $AVE_Template->fetch($tpl_file); + break; + + // Отображение поля в документах + case 'doc': + + $AVE_Template->config_load($lang_file, 'public'); + + if ($tpl_empty) + { + $field_value = clean_php($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if($tpl_empty && $tpl_file){ + $AVE_Template->assign('field_value', $field_value); + return $AVE_Template->fetch($tpl_file); + } + return $field_value; + break; + + // Отображение поля в запросах + case 'req': + + $AVE_Template->config_load($lang_file, 'public'); + + if ($tpl_empty) + { + $field_value = clean_php($field_value); + } + else + { + $field_param = explode('|', $field_value); + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if($tpl_empty && $tpl_file){ + $AVE_Template->assign('field_value', $field_value); + return $AVE_Template->fetch($tpl_file); + } + return $field_value; + break; + + // Сохранение поля в административной части + case 'save': + return $field_value; + // Тип | Имя поля в административной части + case 'name': + return $AVE_Template->get_config_vars('name'); + + case 'api': + return $field_value; + + default: return $field_value; + } + } +?> \ No newline at end of file diff --git a/fields/text_to_image/fonts/CoreSansNR27.ttf b/fields/text_to_image/fonts/CoreSansNR27.ttf new file mode 100644 index 0000000..72e0f8e Binary files /dev/null and b/fields/text_to_image/fonts/CoreSansNR27.ttf differ diff --git a/fields/text_to_image/fonts/CoreSansNR37.ttf b/fields/text_to_image/fonts/CoreSansNR37.ttf new file mode 100644 index 0000000..6d9a421 Binary files /dev/null and b/fields/text_to_image/fonts/CoreSansNR37.ttf differ diff --git a/fields/text_to_image/fonts/CoreSansNR47.ttf b/fields/text_to_image/fonts/CoreSansNR47.ttf new file mode 100644 index 0000000..26b7309 Binary files /dev/null and b/fields/text_to_image/fonts/CoreSansNR47.ttf differ diff --git a/fields/text_to_image/fonts/Cuprum-Bold.ttf b/fields/text_to_image/fonts/Cuprum-Bold.ttf new file mode 100644 index 0000000..df9a372 Binary files /dev/null and b/fields/text_to_image/fonts/Cuprum-Bold.ttf differ diff --git a/fields/text_to_image/fonts/Cuprum-Italic.ttf b/fields/text_to_image/fonts/Cuprum-Italic.ttf new file mode 100644 index 0000000..619065f Binary files /dev/null and b/fields/text_to_image/fonts/Cuprum-Italic.ttf differ diff --git a/fields/text_to_image/fonts/Cuprum-Regular.ttf b/fields/text_to_image/fonts/Cuprum-Regular.ttf new file mode 100644 index 0000000..7434c52 Binary files /dev/null and b/fields/text_to_image/fonts/Cuprum-Regular.ttf differ diff --git a/fields/text_to_image/js/jscolor.js b/fields/text_to_image/js/jscolor.js new file mode 100644 index 0000000..2bdd460 --- /dev/null +++ b/fields/text_to_image/js/jscolor.js @@ -0,0 +1,1844 @@ +/** + * jscolor - JavaScript Color Picker + * + * @link http://jscolor.com + * @license For open source use: GPLv3 + * For commercial use: JSColor Commercial License + * @author Jan Odvarko + * @version 2.0.4 + * + * See usage examples at http://jscolor.com/examples/ + */ + + +"use strict"; + + +if (!window.jscolor) { window.jscolor = (function () { + + +var jsc = { + + + register : function () { + jsc.attachDOMReadyEvent(jsc.init); + jsc.attachEvent(document, 'mousedown', jsc.onDocumentMouseDown); + jsc.attachEvent(document, 'touchstart', jsc.onDocumentTouchStart); + jsc.attachEvent(window, 'resize', jsc.onWindowResize); + }, + + + init : function () { + if (jsc.jscolor.lookupClass) { + jsc.jscolor.installByClassName(jsc.jscolor.lookupClass); + } + }, + + + tryInstallOnElements : function (elms, className) { + var matchClass = new RegExp('(^|\\s)(' + className + ')(\\s*(\\{[^}]*\\})|\\s|$)', 'i'); + + for (var i = 0; i < elms.length; i += 1) { + if (elms[i].type !== undefined && elms[i].type.toLowerCase() == 'color') { + if (jsc.isColorAttrSupported) { + // skip inputs of type 'color' if supported by the browser + continue; + } + } + var m; + if (!elms[i].jscolor && elms[i].className && (m = elms[i].className.match(matchClass))) { + var targetElm = elms[i]; + var optsStr = null; + + var dataOptions = jsc.getDataAttr(targetElm, 'jscolor'); + if (dataOptions !== null) { + optsStr = dataOptions; + } else if (m[4]) { + optsStr = m[4]; + } + + var opts = {}; + if (optsStr) { + try { + opts = (new Function ('return (' + optsStr + ')'))(); + } catch(eParseError) { + jsc.warn('Error parsing jscolor options: ' + eParseError + ':\n' + optsStr); + } + } + targetElm.jscolor = new jsc.jscolor(targetElm, opts); + } + } + }, + + + isColorAttrSupported : (function () { + var elm = document.createElement('input'); + if (elm.setAttribute) { + elm.setAttribute('type', 'color'); + if (elm.type.toLowerCase() == 'color') { + return true; + } + } + return false; + })(), + + + isCanvasSupported : (function () { + var elm = document.createElement('canvas'); + return !!(elm.getContext && elm.getContext('2d')); + })(), + + + fetchElement : function (mixed) { + return typeof mixed === 'string' ? document.getElementById(mixed) : mixed; + }, + + + isElementType : function (elm, type) { + return elm.nodeName.toLowerCase() === type.toLowerCase(); + }, + + + getDataAttr : function (el, name) { + var attrName = 'data-' + name; + var attrValue = el.getAttribute(attrName); + if (attrValue !== null) { + return attrValue; + } + return null; + }, + + + attachEvent : function (el, evnt, func) { + if (el.addEventListener) { + el.addEventListener(evnt, func, false); + } else if (el.attachEvent) { + el.attachEvent('on' + evnt, func); + } + }, + + + detachEvent : function (el, evnt, func) { + if (el.removeEventListener) { + el.removeEventListener(evnt, func, false); + } else if (el.detachEvent) { + el.detachEvent('on' + evnt, func); + } + }, + + + _attachedGroupEvents : {}, + + + attachGroupEvent : function (groupName, el, evnt, func) { + if (!jsc._attachedGroupEvents.hasOwnProperty(groupName)) { + jsc._attachedGroupEvents[groupName] = []; + } + jsc._attachedGroupEvents[groupName].push([el, evnt, func]); + jsc.attachEvent(el, evnt, func); + }, + + + detachGroupEvents : function (groupName) { + if (jsc._attachedGroupEvents.hasOwnProperty(groupName)) { + for (var i = 0; i < jsc._attachedGroupEvents[groupName].length; i += 1) { + var evt = jsc._attachedGroupEvents[groupName][i]; + jsc.detachEvent(evt[0], evt[1], evt[2]); + } + delete jsc._attachedGroupEvents[groupName]; + } + }, + + + attachDOMReadyEvent : function (func) { + var fired = false; + var fireOnce = function () { + if (!fired) { + fired = true; + func(); + } + }; + + if (document.readyState === 'complete') { + setTimeout(fireOnce, 1); // async + return; + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireOnce, false); + + // Fallback + window.addEventListener('load', fireOnce, false); + + } else if (document.attachEvent) { + // IE + document.attachEvent('onreadystatechange', function () { + if (document.readyState === 'complete') { + document.detachEvent('onreadystatechange', arguments.callee); + fireOnce(); + } + }) + + // Fallback + window.attachEvent('onload', fireOnce); + + // IE7/8 + if (document.documentElement.doScroll && window == window.top) { + var tryScroll = function () { + if (!document.body) { return; } + try { + document.documentElement.doScroll('left'); + fireOnce(); + } catch (e) { + setTimeout(tryScroll, 1); + } + }; + tryScroll(); + } + } + }, + + + warn : function (msg) { + if (window.console && window.console.warn) { + window.console.warn(msg); + } + }, + + + preventDefault : function (e) { + if (e.preventDefault) { e.preventDefault(); } + e.returnValue = false; + }, + + + captureTarget : function (target) { + // IE + if (target.setCapture) { + jsc._capturedTarget = target; + jsc._capturedTarget.setCapture(); + } + }, + + + releaseTarget : function () { + // IE + if (jsc._capturedTarget) { + jsc._capturedTarget.releaseCapture(); + jsc._capturedTarget = null; + } + }, + + + fireEvent : function (el, evnt) { + if (!el) { + return; + } + if (document.createEvent) { + var ev = document.createEvent('HTMLEvents'); + ev.initEvent(evnt, true, true); + el.dispatchEvent(ev); + } else if (document.createEventObject) { + var ev = document.createEventObject(); + el.fireEvent('on' + evnt, ev); + } else if (el['on' + evnt]) { // alternatively use the traditional event model + el['on' + evnt](); + } + }, + + + classNameToList : function (className) { + return className.replace(/^\s+|\s+$/g, '').split(/\s+/); + }, + + + // The className parameter (str) can only contain a single class name + hasClass : function (elm, className) { + if (!className) { + return false; + } + return -1 != (' ' + elm.className.replace(/\s+/g, ' ') + ' ').indexOf(' ' + className + ' '); + }, + + + // The className parameter (str) can contain multiple class names separated by whitespace + setClass : function (elm, className) { + var classList = jsc.classNameToList(className); + for (var i = 0; i < classList.length; i += 1) { + if (!jsc.hasClass(elm, classList[i])) { + elm.className += (elm.className ? ' ' : '') + classList[i]; + } + } + }, + + + // The className parameter (str) can contain multiple class names separated by whitespace + unsetClass : function (elm, className) { + var classList = jsc.classNameToList(className); + for (var i = 0; i < classList.length; i += 1) { + var repl = new RegExp( + '^\\s*' + classList[i] + '\\s*|' + + '\\s*' + classList[i] + '\\s*$|' + + '\\s+' + classList[i] + '(\\s+)', + 'g' + ); + elm.className = elm.className.replace(repl, '$1'); + } + }, + + + getStyle : function (elm) { + return window.getComputedStyle ? window.getComputedStyle(elm) : elm.currentStyle; + }, + + + setStyle : (function () { + var helper = document.createElement('div'); + var getSupportedProp = function (names) { + for (var i = 0; i < names.length; i += 1) { + if (names[i] in helper.style) { + return names[i]; + } + } + }; + var props = { + borderRadius: getSupportedProp(['borderRadius', 'MozBorderRadius', 'webkitBorderRadius']), + boxShadow: getSupportedProp(['boxShadow', 'MozBoxShadow', 'webkitBoxShadow']) + }; + return function (elm, prop, value) { + switch (prop.toLowerCase()) { + case 'opacity': + var alphaOpacity = Math.round(parseFloat(value) * 100); + elm.style.opacity = value; + elm.style.filter = 'alpha(opacity=' + alphaOpacity + ')'; + break; + default: + elm.style[props[prop]] = value; + break; + } + }; + })(), + + + setBorderRadius : function (elm, value) { + jsc.setStyle(elm, 'borderRadius', value || '0'); + }, + + + setBoxShadow : function (elm, value) { + jsc.setStyle(elm, 'boxShadow', value || 'none'); + }, + + + getElementPos : function (e, relativeToViewport) { + var x=0, y=0; + var rect = e.getBoundingClientRect(); + x = rect.left; + y = rect.top; + if (!relativeToViewport) { + var viewPos = jsc.getViewPos(); + x += viewPos[0]; + y += viewPos[1]; + } + return [x, y]; + }, + + + getElementSize : function (e) { + return [e.offsetWidth, e.offsetHeight]; + }, + + + // get pointer's X/Y coordinates relative to viewport + getAbsPointerPos : function (e) { + if (!e) { e = window.event; } + var x = 0, y = 0; + if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) { + // touch devices + x = e.changedTouches[0].clientX; + y = e.changedTouches[0].clientY; + } else if (typeof e.clientX === 'number') { + x = e.clientX; + y = e.clientY; + } + return { x: x, y: y }; + }, + + + // get pointer's X/Y coordinates relative to target element + getRelPointerPos : function (e) { + if (!e) { e = window.event; } + var target = e.target || e.srcElement; + var targetRect = target.getBoundingClientRect(); + + var x = 0, y = 0; + + var clientX = 0, clientY = 0; + if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) { + // touch devices + clientX = e.changedTouches[0].clientX; + clientY = e.changedTouches[0].clientY; + } else if (typeof e.clientX === 'number') { + clientX = e.clientX; + clientY = e.clientY; + } + + x = clientX - targetRect.left; + y = clientY - targetRect.top; + return { x: x, y: y }; + }, + + + getViewPos : function () { + var doc = document.documentElement; + return [ + (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0), + (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0) + ]; + }, + + + getViewSize : function () { + var doc = document.documentElement; + return [ + (window.innerWidth || doc.clientWidth), + (window.innerHeight || doc.clientHeight), + ]; + }, + + + redrawPosition : function () { + + if (jsc.picker && jsc.picker.owner) { + var thisObj = jsc.picker.owner; + + var tp, vp; + + if (thisObj.fixed) { + // Fixed elements are positioned relative to viewport, + // therefore we can ignore the scroll offset + tp = jsc.getElementPos(thisObj.targetElement, true); // target pos + vp = [0, 0]; // view pos + } else { + tp = jsc.getElementPos(thisObj.targetElement); // target pos + vp = jsc.getViewPos(); // view pos + } + + var ts = jsc.getElementSize(thisObj.targetElement); // target size + var vs = jsc.getViewSize(); // view size + var ps = jsc.getPickerOuterDims(thisObj); // picker size + var a, b, c; + switch (thisObj.position.toLowerCase()) { + case 'left': a=1; b=0; c=-1; break; + case 'right':a=1; b=0; c=1; break; + case 'top': a=0; b=1; c=-1; break; + default: a=0; b=1; c=1; break; + } + var l = (ts[b]+ps[b])/2; + + // compute picker position + if (!thisObj.smartPosition) { + var pp = [ + tp[a], + tp[b]+ts[b]-l+l*c + ]; + } else { + var pp = [ + -vp[a]+tp[a]+ps[a] > vs[a] ? + (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) : + tp[a], + -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ? + (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) : + (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c) + ]; + } + + var x = pp[a]; + var y = pp[b]; + var positionValue = thisObj.fixed ? 'fixed' : 'absolute'; + var contractShadow = + (pp[0] + ps[0] > tp[0] || pp[0] < tp[0] + ts[0]) && + (pp[1] + ps[1] < tp[1] + ts[1]); + + jsc._drawPosition(thisObj, x, y, positionValue, contractShadow); + } + }, + + + _drawPosition : function (thisObj, x, y, positionValue, contractShadow) { + var vShadow = contractShadow ? 0 : thisObj.shadowBlur; // px + + jsc.picker.wrap.style.position = positionValue; + jsc.picker.wrap.style.left = x + 'px'; + jsc.picker.wrap.style.top = y + 'px'; + + jsc.setBoxShadow( + jsc.picker.boxS, + thisObj.shadow ? + new jsc.BoxShadow(0, vShadow, thisObj.shadowBlur, 0, thisObj.shadowColor) : + null); + }, + + + getPickerDims : function (thisObj) { + var displaySlider = !!jsc.getSliderComponent(thisObj); + var dims = [ + 2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.width + + (displaySlider ? 2 * thisObj.insetWidth + jsc.getPadToSliderPadding(thisObj) + thisObj.sliderSize : 0), + 2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.height + + (thisObj.closable ? 2 * thisObj.insetWidth + thisObj.padding + thisObj.buttonHeight : 0) + ]; + return dims; + }, + + + getPickerOuterDims : function (thisObj) { + var dims = jsc.getPickerDims(thisObj); + return [ + dims[0] + 2 * thisObj.borderWidth, + dims[1] + 2 * thisObj.borderWidth + ]; + }, + + + getPadToSliderPadding : function (thisObj) { + return Math.max(thisObj.padding, 1.5 * (2 * thisObj.pointerBorderWidth + thisObj.pointerThickness)); + }, + + + getPadYComponent : function (thisObj) { + switch (thisObj.mode.charAt(1).toLowerCase()) { + case 'v': return 'v'; break; + } + return 's'; + }, + + + getSliderComponent : function (thisObj) { + if (thisObj.mode.length > 2) { + switch (thisObj.mode.charAt(2).toLowerCase()) { + case 's': return 's'; break; + case 'v': return 'v'; break; + } + } + return null; + }, + + + onDocumentMouseDown : function (e) { + if (!e) { e = window.event; } + var target = e.target || e.srcElement; + + if (target._jscLinkedInstance) { + if (target._jscLinkedInstance.showOnClick) { + target._jscLinkedInstance.show(); + } + } else if (target._jscControlName) { + jsc.onControlPointerStart(e, target, target._jscControlName, 'mouse'); + } else { + // Mouse is outside the picker controls -> hide the color picker! + if (jsc.picker && jsc.picker.owner) { + jsc.picker.owner.hide(); + } + } + }, + + + onDocumentTouchStart : function (e) { + if (!e) { e = window.event; } + var target = e.target || e.srcElement; + + if (target._jscLinkedInstance) { + if (target._jscLinkedInstance.showOnClick) { + target._jscLinkedInstance.show(); + } + } else if (target._jscControlName) { + jsc.onControlPointerStart(e, target, target._jscControlName, 'touch'); + } else { + if (jsc.picker && jsc.picker.owner) { + jsc.picker.owner.hide(); + } + } + }, + + + onWindowResize : function (e) { + jsc.redrawPosition(); + }, + + + onParentScroll : function (e) { + // hide the picker when one of the parent elements is scrolled + if (jsc.picker && jsc.picker.owner) { + jsc.picker.owner.hide(); + } + }, + + + _pointerMoveEvent : { + mouse: 'mousemove', + touch: 'touchmove' + }, + _pointerEndEvent : { + mouse: 'mouseup', + touch: 'touchend' + }, + + + _pointerOrigin : null, + _capturedTarget : null, + + + onControlPointerStart : function (e, target, controlName, pointerType) { + var thisObj = target._jscInstance; + + jsc.preventDefault(e); + jsc.captureTarget(target); + + var registerDragEvents = function (doc, offset) { + jsc.attachGroupEvent('drag', doc, jsc._pointerMoveEvent[pointerType], + jsc.onDocumentPointerMove(e, target, controlName, pointerType, offset)); + jsc.attachGroupEvent('drag', doc, jsc._pointerEndEvent[pointerType], + jsc.onDocumentPointerEnd(e, target, controlName, pointerType)); + }; + + registerDragEvents(document, [0, 0]); + + if (window.parent && window.frameElement) { + var rect = window.frameElement.getBoundingClientRect(); + var ofs = [-rect.left, -rect.top]; + registerDragEvents(window.parent.window.document, ofs); + } + + var abs = jsc.getAbsPointerPos(e); + var rel = jsc.getRelPointerPos(e); + jsc._pointerOrigin = { + x: abs.x - rel.x, + y: abs.y - rel.y + }; + + switch (controlName) { + case 'pad': + // if the slider is at the bottom, move it up + switch (jsc.getSliderComponent(thisObj)) { + case 's': if (thisObj.hsv[1] === 0) { thisObj.fromHSV(null, 100, null); }; break; + case 'v': if (thisObj.hsv[2] === 0) { thisObj.fromHSV(null, null, 100); }; break; + } + jsc.setPad(thisObj, e, 0, 0); + break; + + case 'sld': + jsc.setSld(thisObj, e, 0); + break; + } + + jsc.dispatchFineChange(thisObj); + }, + + + onDocumentPointerMove : function (e, target, controlName, pointerType, offset) { + return function (e) { + var thisObj = target._jscInstance; + switch (controlName) { + case 'pad': + if (!e) { e = window.event; } + jsc.setPad(thisObj, e, offset[0], offset[1]); + jsc.dispatchFineChange(thisObj); + break; + + case 'sld': + if (!e) { e = window.event; } + jsc.setSld(thisObj, e, offset[1]); + jsc.dispatchFineChange(thisObj); + break; + } + } + }, + + + onDocumentPointerEnd : function (e, target, controlName, pointerType) { + return function (e) { + var thisObj = target._jscInstance; + jsc.detachGroupEvents('drag'); + jsc.releaseTarget(); + // Always dispatch changes after detaching outstanding mouse handlers, + // in case some user interaction will occur in user's onchange callback + // that would intrude with current mouse events + jsc.dispatchChange(thisObj); + }; + }, + + + dispatchChange : function (thisObj) { + if (thisObj.valueElement) { + if (jsc.isElementType(thisObj.valueElement, 'input')) { + jsc.fireEvent(thisObj.valueElement, 'change'); + } + } + }, + + + dispatchFineChange : function (thisObj) { + if (thisObj.onFineChange) { + var callback; + if (typeof thisObj.onFineChange === 'string') { + callback = new Function (thisObj.onFineChange); + } else { + callback = thisObj.onFineChange; + } + callback.call(thisObj); + } + }, + + + setPad : function (thisObj, e, ofsX, ofsY) { + var pointerAbs = jsc.getAbsPointerPos(e); + var x = ofsX + pointerAbs.x - jsc._pointerOrigin.x - thisObj.padding - thisObj.insetWidth; + var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth; + + var xVal = x * (360 / (thisObj.width - 1)); + var yVal = 100 - (y * (100 / (thisObj.height - 1))); + + switch (jsc.getPadYComponent(thisObj)) { + case 's': thisObj.fromHSV(xVal, yVal, null, jsc.leaveSld); break; + case 'v': thisObj.fromHSV(xVal, null, yVal, jsc.leaveSld); break; + } + }, + + + setSld : function (thisObj, e, ofsY) { + var pointerAbs = jsc.getAbsPointerPos(e); + var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth; + + var yVal = 100 - (y * (100 / (thisObj.height - 1))); + + switch (jsc.getSliderComponent(thisObj)) { + case 's': thisObj.fromHSV(null, yVal, null, jsc.leavePad); break; + case 'v': thisObj.fromHSV(null, null, yVal, jsc.leavePad); break; + } + }, + + + _vmlNS : 'jsc_vml_', + _vmlCSS : 'jsc_vml_css_', + _vmlReady : false, + + + initVML : function () { + if (!jsc._vmlReady) { + // init VML namespace + var doc = document; + if (!doc.namespaces[jsc._vmlNS]) { + doc.namespaces.add(jsc._vmlNS, 'urn:schemas-microsoft-com:vml'); + } + if (!doc.styleSheets[jsc._vmlCSS]) { + var tags = ['shape', 'shapetype', 'group', 'background', 'path', 'formulas', 'handles', 'fill', 'stroke', 'shadow', 'textbox', 'textpath', 'imagedata', 'line', 'polyline', 'curve', 'rect', 'roundrect', 'oval', 'arc', 'image']; + var ss = doc.createStyleSheet(); + ss.owningElement.id = jsc._vmlCSS; + for (var i = 0; i < tags.length; i += 1) { + ss.addRule(jsc._vmlNS + '\\:' + tags[i], 'behavior:url(#default#VML);'); + } + } + jsc._vmlReady = true; + } + }, + + + createPalette : function () { + + var paletteObj = { + elm: null, + draw: null + }; + + if (jsc.isCanvasSupported) { + // Canvas implementation for modern browsers + + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + + var drawFunc = function (width, height, type) { + canvas.width = width; + canvas.height = height; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var hGrad = ctx.createLinearGradient(0, 0, canvas.width, 0); + hGrad.addColorStop(0 / 6, '#F00'); + hGrad.addColorStop(1 / 6, '#FF0'); + hGrad.addColorStop(2 / 6, '#0F0'); + hGrad.addColorStop(3 / 6, '#0FF'); + hGrad.addColorStop(4 / 6, '#00F'); + hGrad.addColorStop(5 / 6, '#F0F'); + hGrad.addColorStop(6 / 6, '#F00'); + + ctx.fillStyle = hGrad; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + var vGrad = ctx.createLinearGradient(0, 0, 0, canvas.height); + switch (type.toLowerCase()) { + case 's': + vGrad.addColorStop(0, 'rgba(255,255,255,0)'); + vGrad.addColorStop(1, 'rgba(255,255,255,1)'); + break; + case 'v': + vGrad.addColorStop(0, 'rgba(0,0,0,0)'); + vGrad.addColorStop(1, 'rgba(0,0,0,1)'); + break; + } + ctx.fillStyle = vGrad; + ctx.fillRect(0, 0, canvas.width, canvas.height); + }; + + paletteObj.elm = canvas; + paletteObj.draw = drawFunc; + + } else { + // VML fallback for IE 7 and 8 + + jsc.initVML(); + + var vmlContainer = document.createElement('div'); + vmlContainer.style.position = 'relative'; + vmlContainer.style.overflow = 'hidden'; + + var hGrad = document.createElement(jsc._vmlNS + ':fill'); + hGrad.type = 'gradient'; + hGrad.method = 'linear'; + hGrad.angle = '90'; + hGrad.colors = '16.67% #F0F, 33.33% #00F, 50% #0FF, 66.67% #0F0, 83.33% #FF0' + + var hRect = document.createElement(jsc._vmlNS + ':rect'); + hRect.style.position = 'absolute'; + hRect.style.left = -1 + 'px'; + hRect.style.top = -1 + 'px'; + hRect.stroked = false; + hRect.appendChild(hGrad); + vmlContainer.appendChild(hRect); + + var vGrad = document.createElement(jsc._vmlNS + ':fill'); + vGrad.type = 'gradient'; + vGrad.method = 'linear'; + vGrad.angle = '180'; + vGrad.opacity = '0'; + + var vRect = document.createElement(jsc._vmlNS + ':rect'); + vRect.style.position = 'absolute'; + vRect.style.left = -1 + 'px'; + vRect.style.top = -1 + 'px'; + vRect.stroked = false; + vRect.appendChild(vGrad); + vmlContainer.appendChild(vRect); + + var drawFunc = function (width, height, type) { + vmlContainer.style.width = width + 'px'; + vmlContainer.style.height = height + 'px'; + + hRect.style.width = + vRect.style.width = + (width + 1) + 'px'; + hRect.style.height = + vRect.style.height = + (height + 1) + 'px'; + + // Colors must be specified during every redraw, otherwise IE won't display + // a full gradient during a subsequential redraw + hGrad.color = '#F00'; + hGrad.color2 = '#F00'; + + switch (type.toLowerCase()) { + case 's': + vGrad.color = vGrad.color2 = '#FFF'; + break; + case 'v': + vGrad.color = vGrad.color2 = '#000'; + break; + } + }; + + paletteObj.elm = vmlContainer; + paletteObj.draw = drawFunc; + } + + return paletteObj; + }, + + + createSliderGradient : function () { + + var sliderObj = { + elm: null, + draw: null + }; + + if (jsc.isCanvasSupported) { + // Canvas implementation for modern browsers + + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + + var drawFunc = function (width, height, color1, color2) { + canvas.width = width; + canvas.height = height; + + ctx.clearRect(0, 0, canvas.width, canvas.height); + + var grad = ctx.createLinearGradient(0, 0, 0, canvas.height); + grad.addColorStop(0, color1); + grad.addColorStop(1, color2); + + ctx.fillStyle = grad; + ctx.fillRect(0, 0, canvas.width, canvas.height); + }; + + sliderObj.elm = canvas; + sliderObj.draw = drawFunc; + + } else { + // VML fallback for IE 7 and 8 + + jsc.initVML(); + + var vmlContainer = document.createElement('div'); + vmlContainer.style.position = 'relative'; + vmlContainer.style.overflow = 'hidden'; + + var grad = document.createElement(jsc._vmlNS + ':fill'); + grad.type = 'gradient'; + grad.method = 'linear'; + grad.angle = '180'; + + var rect = document.createElement(jsc._vmlNS + ':rect'); + rect.style.position = 'absolute'; + rect.style.left = -1 + 'px'; + rect.style.top = -1 + 'px'; + rect.stroked = false; + rect.appendChild(grad); + vmlContainer.appendChild(rect); + + var drawFunc = function (width, height, color1, color2) { + vmlContainer.style.width = width + 'px'; + vmlContainer.style.height = height + 'px'; + + rect.style.width = (width + 1) + 'px'; + rect.style.height = (height + 1) + 'px'; + + grad.color = color1; + grad.color2 = color2; + }; + + sliderObj.elm = vmlContainer; + sliderObj.draw = drawFunc; + } + + return sliderObj; + }, + + + leaveValue : 1<<0, + leaveStyle : 1<<1, + leavePad : 1<<2, + leaveSld : 1<<3, + + + BoxShadow : (function () { + var BoxShadow = function (hShadow, vShadow, blur, spread, color, inset) { + this.hShadow = hShadow; + this.vShadow = vShadow; + this.blur = blur; + this.spread = spread; + this.color = color; + this.inset = !!inset; + }; + + BoxShadow.prototype.toString = function () { + var vals = [ + Math.round(this.hShadow) + 'px', + Math.round(this.vShadow) + 'px', + Math.round(this.blur) + 'px', + Math.round(this.spread) + 'px', + this.color + ]; + if (this.inset) { + vals.push('inset'); + } + return vals.join(' '); + }; + + return BoxShadow; + })(), + + + // + // Usage: + // var myColor = new jscolor( [, ]) + // + + jscolor : function (targetElement, options) { + + // General options + // + this.value = null; // initial HEX color. To change it later, use methods fromString(), fromHSV() and fromRGB() + this.valueElement = targetElement; // element that will be used to display and input the color code + this.styleElement = targetElement; // element that will preview the picked color using CSS backgroundColor + this.required = true; // whether the associated text can be left empty + this.refine = true; // whether to refine the entered color code (e.g. uppercase it and remove whitespace) + this.hash = false; // whether to prefix the HEX color code with # symbol + this.uppercase = true; // whether to uppercase the color code + this.onFineChange = null; // called instantly every time the color changes (value can be either a function or a string with javascript code) + this.activeClass = 'jscolor-active'; // class to be set to the target element when a picker window is open on it + this.minS = 0; // min allowed saturation (0 - 100) + this.maxS = 100; // max allowed saturation (0 - 100) + this.minV = 0; // min allowed value (brightness) (0 - 100) + this.maxV = 100; // max allowed value (brightness) (0 - 100) + + // Accessing the picked color + // + this.hsv = [0, 0, 100]; // read-only [0-360, 0-100, 0-100] + this.rgb = [255, 255, 255]; // read-only [0-255, 0-255, 0-255] + + // Color Picker options + // + this.width = 181; // width of color palette (in px) + this.height = 101; // height of color palette (in px) + this.showOnClick = true; // whether to display the color picker when user clicks on its target element + this.mode = 'HSV'; // HSV | HVS | HS | HV - layout of the color picker controls + this.position = 'bottom'; // left | right | top | bottom - position relative to the target element + this.smartPosition = true; // automatically change picker position when there is not enough space for it + this.sliderSize = 16; // px + this.crossSize = 8; // px + this.closable = false; // whether to display the Close button + this.closeText = 'Close'; + this.buttonColor = '#000000'; // CSS color + this.buttonHeight = 18; // px + this.padding = 12; // px + this.backgroundColor = '#FFFFFF'; // CSS color + this.borderWidth = 1; // px + this.borderColor = '#BBBBBB'; // CSS color + this.borderRadius = 8; // px + this.insetWidth = 1; // px + this.insetColor = '#BBBBBB'; // CSS color + this.shadow = true; // whether to display shadow + this.shadowBlur = 15; // px + this.shadowColor = 'rgba(0,0,0,0.2)'; // CSS color + this.pointerColor = '#4C4C4C'; // px + this.pointerBorderColor = '#FFFFFF'; // px + this.pointerBorderWidth = 1; // px + this.pointerThickness = 2; // px + this.zIndex = 1000; + this.container = null; // where to append the color picker (BODY element by default) + + + for (var opt in options) { + if (options.hasOwnProperty(opt)) { + this[opt] = options[opt]; + } + } + + + this.hide = function () { + if (isPickerOwner()) { + detachPicker(); + } + }; + + + this.show = function () { + drawPicker(); + }; + + + this.redraw = function () { + if (isPickerOwner()) { + drawPicker(); + } + }; + + + this.importColor = function () { + if (!this.valueElement) { + this.exportColor(); + } else { + if (jsc.isElementType(this.valueElement, 'input')) { + if (!this.refine) { + if (!this.fromString(this.valueElement.value, jsc.leaveValue)) { + if (this.styleElement) { + this.styleElement.style.backgroundImage = this.styleElement._jscOrigStyle.backgroundImage; + this.styleElement.style.backgroundColor = this.styleElement._jscOrigStyle.backgroundColor; + this.styleElement.style.color = this.styleElement._jscOrigStyle.color; + } + this.exportColor(jsc.leaveValue | jsc.leaveStyle); + } + } else if (!this.required && /^\s*$/.test(this.valueElement.value)) { + this.valueElement.value = ''; + if (this.styleElement) { + this.styleElement.style.backgroundImage = this.styleElement._jscOrigStyle.backgroundImage; + this.styleElement.style.backgroundColor = this.styleElement._jscOrigStyle.backgroundColor; + this.styleElement.style.color = this.styleElement._jscOrigStyle.color; + } + this.exportColor(jsc.leaveValue | jsc.leaveStyle); + + } else if (this.fromString(this.valueElement.value)) { + // managed to import color successfully from the value -> OK, don't do anything + } else { + this.exportColor(); + } + } else { + // not an input element -> doesn't have any value + this.exportColor(); + } + } + }; + + + this.exportColor = function (flags) { + if (!(flags & jsc.leaveValue) && this.valueElement) { + var value = this.toString(); + if (this.uppercase) { value = value.toUpperCase(); } + if (this.hash) { value = '#' + value; } + + if (jsc.isElementType(this.valueElement, 'input')) { + this.valueElement.value = value; + } else { + this.valueElement.innerHTML = value; + } + } + if (!(flags & jsc.leaveStyle)) { + if (this.styleElement) { + this.styleElement.style.backgroundImage = 'none'; + this.styleElement.style.backgroundColor = '#' + this.toString(); + this.styleElement.style.color = this.isLight() ? '#000' : '#FFF'; + } + } + if (!(flags & jsc.leavePad) && isPickerOwner()) { + redrawPad(); + } + if (!(flags & jsc.leaveSld) && isPickerOwner()) { + redrawSld(); + } + }; + + + // h: 0-360 + // s: 0-100 + // v: 0-100 + // + this.fromHSV = function (h, s, v, flags) { // null = don't change + if (h !== null) { + if (isNaN(h)) { return false; } + h = Math.max(0, Math.min(360, h)); + } + if (s !== null) { + if (isNaN(s)) { return false; } + s = Math.max(0, Math.min(100, this.maxS, s), this.minS); + } + if (v !== null) { + if (isNaN(v)) { return false; } + v = Math.max(0, Math.min(100, this.maxV, v), this.minV); + } + + this.rgb = HSV_RGB( + h===null ? this.hsv[0] : (this.hsv[0]=h), + s===null ? this.hsv[1] : (this.hsv[1]=s), + v===null ? this.hsv[2] : (this.hsv[2]=v) + ); + + this.exportColor(flags); + }; + + + // r: 0-255 + // g: 0-255 + // b: 0-255 + // + this.fromRGB = function (r, g, b, flags) { // null = don't change + if (r !== null) { + if (isNaN(r)) { return false; } + r = Math.max(0, Math.min(255, r)); + } + if (g !== null) { + if (isNaN(g)) { return false; } + g = Math.max(0, Math.min(255, g)); + } + if (b !== null) { + if (isNaN(b)) { return false; } + b = Math.max(0, Math.min(255, b)); + } + + var hsv = RGB_HSV( + r===null ? this.rgb[0] : r, + g===null ? this.rgb[1] : g, + b===null ? this.rgb[2] : b + ); + if (hsv[0] !== null) { + this.hsv[0] = Math.max(0, Math.min(360, hsv[0])); + } + if (hsv[2] !== 0) { + this.hsv[1] = hsv[1]===null ? null : Math.max(0, this.minS, Math.min(100, this.maxS, hsv[1])); + } + this.hsv[2] = hsv[2]===null ? null : Math.max(0, this.minV, Math.min(100, this.maxV, hsv[2])); + + // update RGB according to final HSV, as some values might be trimmed + var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]); + this.rgb[0] = rgb[0]; + this.rgb[1] = rgb[1]; + this.rgb[2] = rgb[2]; + + this.exportColor(flags); + }; + + + this.fromString = function (str, flags) { + var m; + if (m = str.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i)) { + // HEX notation + // + + if (m[1].length === 6) { + // 6-char notation + this.fromRGB( + parseInt(m[1].substr(0,2),16), + parseInt(m[1].substr(2,2),16), + parseInt(m[1].substr(4,2),16), + flags + ); + } else { + // 3-char notation + this.fromRGB( + parseInt(m[1].charAt(0) + m[1].charAt(0),16), + parseInt(m[1].charAt(1) + m[1].charAt(1),16), + parseInt(m[1].charAt(2) + m[1].charAt(2),16), + flags + ); + } + return true; + + } else if (m = str.match(/^\W*rgba?\(([^)]*)\)\W*$/i)) { + var params = m[1].split(','); + var re = /^\s*(\d*)(\.\d+)?\s*$/; + var mR, mG, mB; + if ( + params.length >= 3 && + (mR = params[0].match(re)) && + (mG = params[1].match(re)) && + (mB = params[2].match(re)) + ) { + var r = parseFloat((mR[1] || '0') + (mR[2] || '')); + var g = parseFloat((mG[1] || '0') + (mG[2] || '')); + var b = parseFloat((mB[1] || '0') + (mB[2] || '')); + this.fromRGB(r, g, b, flags); + return true; + } + } + return false; + }; + + + this.toString = function () { + return ( + (0x100 | Math.round(this.rgb[0])).toString(16).substr(1) + + (0x100 | Math.round(this.rgb[1])).toString(16).substr(1) + + (0x100 | Math.round(this.rgb[2])).toString(16).substr(1) + ); + }; + + + this.toHEXString = function () { + return '#' + this.toString().toUpperCase(); + }; + + + this.toRGBString = function () { + return ('rgb(' + + Math.round(this.rgb[0]) + ',' + + Math.round(this.rgb[1]) + ',' + + Math.round(this.rgb[2]) + ')' + ); + }; + + + this.isLight = function () { + return ( + 0.213 * this.rgb[0] + + 0.715 * this.rgb[1] + + 0.072 * this.rgb[2] > + 255 / 2 + ); + }; + + + this._processParentElementsInDOM = function () { + if (this._linkedElementsProcessed) { return; } + this._linkedElementsProcessed = true; + + var elm = this.targetElement; + do { + // If the target element or one of its parent nodes has fixed position, + // then use fixed positioning instead + // + // Note: In Firefox, getComputedStyle returns null in a hidden iframe, + // that's why we need to check if the returned style object is non-empty + var currStyle = jsc.getStyle(elm); + if (currStyle && currStyle.position.toLowerCase() === 'fixed') { + this.fixed = true; + } + + if (elm !== this.targetElement) { + // Ensure to attach onParentScroll only once to each parent element + // (multiple targetElements can share the same parent nodes) + // + // Note: It's not just offsetParents that can be scrollable, + // that's why we loop through all parent nodes + if (!elm._jscEventsAttached) { + jsc.attachEvent(elm, 'scroll', jsc.onParentScroll); + elm._jscEventsAttached = true; + } + } + } while ((elm = elm.parentNode) && !jsc.isElementType(elm, 'body')); + }; + + + // r: 0-255 + // g: 0-255 + // b: 0-255 + // + // returns: [ 0-360, 0-100, 0-100 ] + // + function RGB_HSV (r, g, b) { + r /= 255; + g /= 255; + b /= 255; + var n = Math.min(Math.min(r,g),b); + var v = Math.max(Math.max(r,g),b); + var m = v - n; + if (m === 0) { return [ null, 0, 100 * v ]; } + var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m); + return [ + 60 * (h===6?0:h), + 100 * (m/v), + 100 * v + ]; + } + + + // h: 0-360 + // s: 0-100 + // v: 0-100 + // + // returns: [ 0-255, 0-255, 0-255 ] + // + function HSV_RGB (h, s, v) { + var u = 255 * (v / 100); + + if (h === null) { + return [ u, u, u ]; + } + + h /= 60; + s /= 100; + + var i = Math.floor(h); + var f = i%2 ? h-i : 1-(h-i); + var m = u * (1 - s); + var n = u * (1 - s * f); + switch (i) { + case 6: + case 0: return [u,n,m]; + case 1: return [n,u,m]; + case 2: return [m,u,n]; + case 3: return [m,n,u]; + case 4: return [n,m,u]; + case 5: return [u,m,n]; + } + } + + + function detachPicker () { + jsc.unsetClass(THIS.targetElement, THIS.activeClass); + jsc.picker.wrap.parentNode.removeChild(jsc.picker.wrap); + delete jsc.picker.owner; + } + + + function drawPicker () { + + // At this point, when drawing the picker, we know what the parent elements are + // and we can do all related DOM operations, such as registering events on them + // or checking their positioning + THIS._processParentElementsInDOM(); + + if (!jsc.picker) { + jsc.picker = { + owner: null, + wrap : document.createElement('div'), + box : document.createElement('div'), + boxS : document.createElement('div'), // shadow area + boxB : document.createElement('div'), // border + pad : document.createElement('div'), + padB : document.createElement('div'), // border + padM : document.createElement('div'), // mouse/touch area + padPal : jsc.createPalette(), + cross : document.createElement('div'), + crossBY : document.createElement('div'), // border Y + crossBX : document.createElement('div'), // border X + crossLY : document.createElement('div'), // line Y + crossLX : document.createElement('div'), // line X + sld : document.createElement('div'), + sldB : document.createElement('div'), // border + sldM : document.createElement('div'), // mouse/touch area + sldGrad : jsc.createSliderGradient(), + sldPtrS : document.createElement('div'), // slider pointer spacer + sldPtrIB : document.createElement('div'), // slider pointer inner border + sldPtrMB : document.createElement('div'), // slider pointer middle border + sldPtrOB : document.createElement('div'), // slider pointer outer border + btn : document.createElement('div'), + btnT : document.createElement('span') // text + }; + + jsc.picker.pad.appendChild(jsc.picker.padPal.elm); + jsc.picker.padB.appendChild(jsc.picker.pad); + jsc.picker.cross.appendChild(jsc.picker.crossBY); + jsc.picker.cross.appendChild(jsc.picker.crossBX); + jsc.picker.cross.appendChild(jsc.picker.crossLY); + jsc.picker.cross.appendChild(jsc.picker.crossLX); + jsc.picker.padB.appendChild(jsc.picker.cross); + jsc.picker.box.appendChild(jsc.picker.padB); + jsc.picker.box.appendChild(jsc.picker.padM); + + jsc.picker.sld.appendChild(jsc.picker.sldGrad.elm); + jsc.picker.sldB.appendChild(jsc.picker.sld); + jsc.picker.sldB.appendChild(jsc.picker.sldPtrOB); + jsc.picker.sldPtrOB.appendChild(jsc.picker.sldPtrMB); + jsc.picker.sldPtrMB.appendChild(jsc.picker.sldPtrIB); + jsc.picker.sldPtrIB.appendChild(jsc.picker.sldPtrS); + jsc.picker.box.appendChild(jsc.picker.sldB); + jsc.picker.box.appendChild(jsc.picker.sldM); + + jsc.picker.btn.appendChild(jsc.picker.btnT); + jsc.picker.box.appendChild(jsc.picker.btn); + + jsc.picker.boxB.appendChild(jsc.picker.box); + jsc.picker.wrap.appendChild(jsc.picker.boxS); + jsc.picker.wrap.appendChild(jsc.picker.boxB); + } + + var p = jsc.picker; + + var displaySlider = !!jsc.getSliderComponent(THIS); + var dims = jsc.getPickerDims(THIS); + var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize); + var padToSliderPadding = jsc.getPadToSliderPadding(THIS); + var borderRadius = Math.min( + THIS.borderRadius, + Math.round(THIS.padding * Math.PI)); // px + var padCursor = 'crosshair'; + + // wrap + p.wrap.style.clear = 'both'; + p.wrap.style.width = (dims[0] + 2 * THIS.borderWidth) + 'px'; + p.wrap.style.height = (dims[1] + 2 * THIS.borderWidth) + 'px'; + p.wrap.style.zIndex = THIS.zIndex; + + // picker + p.box.style.width = dims[0] + 'px'; + p.box.style.height = dims[1] + 'px'; + + p.boxS.style.position = 'absolute'; + p.boxS.style.left = '0'; + p.boxS.style.top = '0'; + p.boxS.style.width = '100%'; + p.boxS.style.height = '100%'; + jsc.setBorderRadius(p.boxS, borderRadius + 'px'); + + // picker border + p.boxB.style.position = 'relative'; + p.boxB.style.border = THIS.borderWidth + 'px solid'; + p.boxB.style.borderColor = THIS.borderColor; + p.boxB.style.background = THIS.backgroundColor; + jsc.setBorderRadius(p.boxB, borderRadius + 'px'); + + // IE hack: + // If the element is transparent, IE will trigger the event on the elements under it, + // e.g. on Canvas or on elements with border + p.padM.style.background = + p.sldM.style.background = + '#FFF'; + jsc.setStyle(p.padM, 'opacity', '0'); + jsc.setStyle(p.sldM, 'opacity', '0'); + + // pad + p.pad.style.position = 'relative'; + p.pad.style.width = THIS.width + 'px'; + p.pad.style.height = THIS.height + 'px'; + + // pad palettes (HSV and HVS) + p.padPal.draw(THIS.width, THIS.height, jsc.getPadYComponent(THIS)); + + // pad border + p.padB.style.position = 'absolute'; + p.padB.style.left = THIS.padding + 'px'; + p.padB.style.top = THIS.padding + 'px'; + p.padB.style.border = THIS.insetWidth + 'px solid'; + p.padB.style.borderColor = THIS.insetColor; + + // pad mouse area + p.padM._jscInstance = THIS; + p.padM._jscControlName = 'pad'; + p.padM.style.position = 'absolute'; + p.padM.style.left = '0'; + p.padM.style.top = '0'; + p.padM.style.width = (THIS.padding + 2 * THIS.insetWidth + THIS.width + padToSliderPadding / 2) + 'px'; + p.padM.style.height = dims[1] + 'px'; + p.padM.style.cursor = padCursor; + + // pad cross + p.cross.style.position = 'absolute'; + p.cross.style.left = + p.cross.style.top = + '0'; + p.cross.style.width = + p.cross.style.height = + crossOuterSize + 'px'; + + // pad cross border Y and X + p.crossBY.style.position = + p.crossBX.style.position = + 'absolute'; + p.crossBY.style.background = + p.crossBX.style.background = + THIS.pointerBorderColor; + p.crossBY.style.width = + p.crossBX.style.height = + (2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; + p.crossBY.style.height = + p.crossBX.style.width = + crossOuterSize + 'px'; + p.crossBY.style.left = + p.crossBX.style.top = + (Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2) - THIS.pointerBorderWidth) + 'px'; + p.crossBY.style.top = + p.crossBX.style.left = + '0'; + + // pad cross line Y and X + p.crossLY.style.position = + p.crossLX.style.position = + 'absolute'; + p.crossLY.style.background = + p.crossLX.style.background = + THIS.pointerColor; + p.crossLY.style.height = + p.crossLX.style.width = + (crossOuterSize - 2 * THIS.pointerBorderWidth) + 'px'; + p.crossLY.style.width = + p.crossLX.style.height = + THIS.pointerThickness + 'px'; + p.crossLY.style.left = + p.crossLX.style.top = + (Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2)) + 'px'; + p.crossLY.style.top = + p.crossLX.style.left = + THIS.pointerBorderWidth + 'px'; + + // slider + p.sld.style.overflow = 'hidden'; + p.sld.style.width = THIS.sliderSize + 'px'; + p.sld.style.height = THIS.height + 'px'; + + // slider gradient + p.sldGrad.draw(THIS.sliderSize, THIS.height, '#000', '#000'); + + // slider border + p.sldB.style.display = displaySlider ? 'block' : 'none'; + p.sldB.style.position = 'absolute'; + p.sldB.style.right = THIS.padding + 'px'; + p.sldB.style.top = THIS.padding + 'px'; + p.sldB.style.border = THIS.insetWidth + 'px solid'; + p.sldB.style.borderColor = THIS.insetColor; + + // slider mouse area + p.sldM._jscInstance = THIS; + p.sldM._jscControlName = 'sld'; + p.sldM.style.display = displaySlider ? 'block' : 'none'; + p.sldM.style.position = 'absolute'; + p.sldM.style.right = '0'; + p.sldM.style.top = '0'; + p.sldM.style.width = (THIS.sliderSize + padToSliderPadding / 2 + THIS.padding + 2 * THIS.insetWidth) + 'px'; + p.sldM.style.height = dims[1] + 'px'; + p.sldM.style.cursor = 'default'; + + // slider pointer inner and outer border + p.sldPtrIB.style.border = + p.sldPtrOB.style.border = + THIS.pointerBorderWidth + 'px solid ' + THIS.pointerBorderColor; + + // slider pointer outer border + p.sldPtrOB.style.position = 'absolute'; + p.sldPtrOB.style.left = -(2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; + p.sldPtrOB.style.top = '0'; + + // slider pointer middle border + p.sldPtrMB.style.border = THIS.pointerThickness + 'px solid ' + THIS.pointerColor; + + // slider pointer spacer + p.sldPtrS.style.width = THIS.sliderSize + 'px'; + p.sldPtrS.style.height = sliderPtrSpace + 'px'; + + // the Close button + function setBtnBorder () { + var insetColors = THIS.insetColor.split(/\s+/); + var outsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1]; + p.btn.style.borderColor = outsetColor; + } + p.btn.style.display = THIS.closable ? 'block' : 'none'; + p.btn.style.position = 'absolute'; + p.btn.style.left = THIS.padding + 'px'; + p.btn.style.bottom = THIS.padding + 'px'; + p.btn.style.padding = '0 15px'; + p.btn.style.height = THIS.buttonHeight + 'px'; + p.btn.style.border = THIS.insetWidth + 'px solid'; + setBtnBorder(); + p.btn.style.color = THIS.buttonColor; + p.btn.style.font = '12px sans-serif'; + p.btn.style.textAlign = 'center'; + try { + p.btn.style.cursor = 'pointer'; + } catch(eOldIE) { + p.btn.style.cursor = 'hand'; + } + p.btn.onmousedown = function () { + THIS.hide(); + }; + p.btnT.style.lineHeight = THIS.buttonHeight + 'px'; + p.btnT.innerHTML = ''; + p.btnT.appendChild(document.createTextNode(THIS.closeText)); + + // place pointers + redrawPad(); + redrawSld(); + + // If we are changing the owner without first closing the picker, + // make sure to first deal with the old owner + if (jsc.picker.owner && jsc.picker.owner !== THIS) { + jsc.unsetClass(jsc.picker.owner.targetElement, THIS.activeClass); + } + + // Set the new picker owner + jsc.picker.owner = THIS; + + // The redrawPosition() method needs picker.owner to be set, that's why we call it here, + // after setting the owner + if (jsc.isElementType(container, 'body')) { + jsc.redrawPosition(); + } else { + jsc._drawPosition(THIS, 0, 0, 'relative', false); + } + + if (p.wrap.parentNode != container) { + container.appendChild(p.wrap); + } + + jsc.setClass(THIS.targetElement, THIS.activeClass); + } + + + function redrawPad () { + // redraw the pad pointer + switch (jsc.getPadYComponent(THIS)) { + case 's': var yComponent = 1; break; + case 'v': var yComponent = 2; break; + } + var x = Math.round((THIS.hsv[0] / 360) * (THIS.width - 1)); + var y = Math.round((1 - THIS.hsv[yComponent] / 100) * (THIS.height - 1)); + var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize); + var ofs = -Math.floor(crossOuterSize / 2); + jsc.picker.cross.style.left = (x + ofs) + 'px'; + jsc.picker.cross.style.top = (y + ofs) + 'px'; + + // redraw the slider + switch (jsc.getSliderComponent(THIS)) { + case 's': + var rgb1 = HSV_RGB(THIS.hsv[0], 100, THIS.hsv[2]); + var rgb2 = HSV_RGB(THIS.hsv[0], 0, THIS.hsv[2]); + var color1 = 'rgb(' + + Math.round(rgb1[0]) + ',' + + Math.round(rgb1[1]) + ',' + + Math.round(rgb1[2]) + ')'; + var color2 = 'rgb(' + + Math.round(rgb2[0]) + ',' + + Math.round(rgb2[1]) + ',' + + Math.round(rgb2[2]) + ')'; + jsc.picker.sldGrad.draw(THIS.sliderSize, THIS.height, color1, color2); + break; + case 'v': + var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 100); + var color1 = 'rgb(' + + Math.round(rgb[0]) + ',' + + Math.round(rgb[1]) + ',' + + Math.round(rgb[2]) + ')'; + var color2 = '#000'; + jsc.picker.sldGrad.draw(THIS.sliderSize, THIS.height, color1, color2); + break; + } + } + + + function redrawSld () { + var sldComponent = jsc.getSliderComponent(THIS); + if (sldComponent) { + // redraw the slider pointer + switch (sldComponent) { + case 's': var yComponent = 1; break; + case 'v': var yComponent = 2; break; + } + var y = Math.round((1 - THIS.hsv[yComponent] / 100) * (THIS.height - 1)); + jsc.picker.sldPtrOB.style.top = (y - (2 * THIS.pointerBorderWidth + THIS.pointerThickness) - Math.floor(sliderPtrSpace / 2)) + 'px'; + } + } + + + function isPickerOwner () { + return jsc.picker && jsc.picker.owner === THIS; + } + + + function blurValue () { + THIS.importColor(); + } + + + // Find the target element + if (typeof targetElement === 'string') { + var id = targetElement; + var elm = document.getElementById(id); + if (elm) { + this.targetElement = elm; + } else { + jsc.warn('Could not find target element with ID \'' + id + '\''); + } + } else if (targetElement) { + this.targetElement = targetElement; + } else { + jsc.warn('Invalid target element: \'' + targetElement + '\''); + } + + if (this.targetElement._jscLinkedInstance) { + jsc.warn('Cannot link jscolor twice to the same element. Skipping.'); + return; + } + this.targetElement._jscLinkedInstance = this; + + // Find the value element + this.valueElement = jsc.fetchElement(this.valueElement); + // Find the style element + this.styleElement = jsc.fetchElement(this.styleElement); + + var THIS = this; + var container = + this.container ? + jsc.fetchElement(this.container) : + document.getElementsByTagName('body')[0]; + var sliderPtrSpace = 3; // px + + // For BUTTON elements it's important to stop them from sending the form when clicked + // (e.g. in Safari) + if (jsc.isElementType(this.targetElement, 'button')) { + if (this.targetElement.onclick) { + var origCallback = this.targetElement.onclick; + this.targetElement.onclick = function (evt) { + origCallback.call(this, evt); + return false; + }; + } else { + this.targetElement.onclick = function () { return false; }; + } + } + + /* + var elm = this.targetElement; + do { + // If the target element or one of its offsetParents has fixed position, + // then use fixed positioning instead + // + // Note: In Firefox, getComputedStyle returns null in a hidden iframe, + // that's why we need to check if the returned style object is non-empty + var currStyle = jsc.getStyle(elm); + if (currStyle && currStyle.position.toLowerCase() === 'fixed') { + this.fixed = true; + } + + if (elm !== this.targetElement) { + // attach onParentScroll so that we can recompute the picker position + // when one of the offsetParents is scrolled + if (!elm._jscEventsAttached) { + jsc.attachEvent(elm, 'scroll', jsc.onParentScroll); + elm._jscEventsAttached = true; + } + } + } while ((elm = elm.offsetParent) && !jsc.isElementType(elm, 'body')); + */ + + // valueElement + if (this.valueElement) { + if (jsc.isElementType(this.valueElement, 'input')) { + var updateField = function () { + THIS.fromString(THIS.valueElement.value, jsc.leaveValue); + jsc.dispatchFineChange(THIS); + }; + jsc.attachEvent(this.valueElement, 'keyup', updateField); + jsc.attachEvent(this.valueElement, 'input', updateField); + jsc.attachEvent(this.valueElement, 'blur', blurValue); + this.valueElement.setAttribute('autocomplete', 'off'); + } + } + + // styleElement + if (this.styleElement) { + this.styleElement._jscOrigStyle = { + backgroundImage : this.styleElement.style.backgroundImage, + backgroundColor : this.styleElement.style.backgroundColor, + color : this.styleElement.style.color + }; + } + + if (this.value) { + // Try to set the color from the .value option and if unsuccessful, + // export the current color + this.fromString(this.value) || this.exportColor(); + } else { + this.importColor(); + } + } + +}; + + +//================================ +// Public properties and methods +//================================ + + +// By default, search for all elements with class="jscolor" and install a color picker on them. +// +// You can change what class name will be looked for by setting the property jscolor.lookupClass +// anywhere in your HTML document. To completely disable the automatic lookup, set it to null. +// +jsc.jscolor.lookupClass = 'jscolor'; + + +jsc.jscolor.installByClassName = function (className) { + var inputElms = document.getElementsByTagName('input'); + var buttonElms = document.getElementsByTagName('button'); + + jsc.tryInstallOnElements(inputElms, className); + jsc.tryInstallOnElements(buttonElms, className); +}; + + +jsc.register(); + + +return jsc.jscolor; + + +})(); } diff --git a/fields/text_to_image/lang/bg.txt b/fields/text_to_image/lang/bg.txt new file mode 100644 index 0000000..2933309 --- /dev/null +++ b/fields/text_to_image/lang/bg.txt @@ -0,0 +1,8 @@ +[admin] +name = "Текст в изображение" +TXT_IMG_TEXT = "Текст, който ще бъде преобразуван е изображение" +TXT_IMG_SIZE = "Размер шрифта" +TXT_IMG_COLOR = "Цвят на текста" +TXT_IMG_ALT = "Текст alt" +TXT_IMG_BTN = "Преобразуване" +TXT_IMG_EXIST = "Текущо значение на полето:" \ No newline at end of file diff --git a/fields/text_to_image/lang/cz.txt b/fields/text_to_image/lang/cz.txt new file mode 100644 index 0000000..8db1c70 --- /dev/null +++ b/fields/text_to_image/lang/cz.txt @@ -0,0 +1,8 @@ +[admin] +name = "Text u zobrazení" +TXT_IMG_TEXT = "Text, který bude přenes do obrazu" +TXT_IMG_SIZE = "Velikost písma" +TXT_IMG_COLOR = "Barva textu" +TXT_IMG_ALT = "Dosazení textu v alt" +TXT_IMG_BTN = "Transformovat" +TXT_IMG_EXIST = "Aktuální hodnota pole:" \ No newline at end of file diff --git a/fields/text_to_image/lang/en.txt b/fields/text_to_image/lang/en.txt new file mode 100644 index 0000000..d047749 --- /dev/null +++ b/fields/text_to_image/lang/en.txt @@ -0,0 +1,8 @@ +[admin] +name = "Текст в изображение" +TXT_IMG_TEXT = "Текст, который будет преобразован в изображение" +TXT_IMG_SIZE = "Размер шрифта" +TXT_IMG_COLOR = "Цвет текста" +TXT_IMG_ALT = "Подстановка текста в alt" +TXT_IMG_BTN = "Преобразовать" +TXT_IMG_EXIST = "Текущее значение поля:" \ No newline at end of file diff --git a/fields/text_to_image/lang/pl.txt b/fields/text_to_image/lang/pl.txt new file mode 100644 index 0000000..9647dee --- /dev/null +++ b/fields/text_to_image/lang/pl.txt @@ -0,0 +1,8 @@ +[admin] +name = "Tekst w obrazku" +TXT_IMG_TEXT = "Tekst który zostanie przekształcony w obrazek" +TXT_IMG_SIZE = "Rozmiar czcionki" +TXT_IMG_COLOR = "Kolor tekstu" +TXT_IMG_ALT = "Substytucja tekstu w alt" +TXT_IMG_BTN = "Transformować" +TXT_IMG_EXIST = "Aktualne znaczenie pola:" \ No newline at end of file diff --git a/fields/text_to_image/lang/ru.txt b/fields/text_to_image/lang/ru.txt new file mode 100644 index 0000000..d047749 --- /dev/null +++ b/fields/text_to_image/lang/ru.txt @@ -0,0 +1,8 @@ +[admin] +name = "Текст в изображение" +TXT_IMG_TEXT = "Текст, который будет преобразован в изображение" +TXT_IMG_SIZE = "Размер шрифта" +TXT_IMG_COLOR = "Цвет текста" +TXT_IMG_ALT = "Подстановка текста в alt" +TXT_IMG_BTN = "Преобразовать" +TXT_IMG_EXIST = "Текущее значение поля:" \ No newline at end of file diff --git a/fields/text_to_image/lang/ua.txt b/fields/text_to_image/lang/ua.txt new file mode 100644 index 0000000..90cd776 --- /dev/null +++ b/fields/text_to_image/lang/ua.txt @@ -0,0 +1,8 @@ +[admin] +name = "Текст у зображення" +TXT_IMG_TEXT = "Текст, який буде трансформований у зображення" +TXT_IMG_SIZE = "Розмір шрифта" +TXT_IMG_COLOR = "Колір текста" +TXT_IMG_ALT = "Підстановка текста в alt" +TXT_IMG_BTN = "Трансформувати" +TXT_IMG_EXIST = "Поточне значення поля:" \ No newline at end of file diff --git a/fields/text_to_image/res.php b/fields/text_to_image/res.php new file mode 100644 index 0000000..4223f2f --- /dev/null +++ b/fields/text_to_image/res.php @@ -0,0 +1,42 @@ +return_as_html = true; + +// определяем вывод изображения: либо в виде кода base64, либо файл .png +// если true - тогда выводим кодом, если false - тогда выводим файл.png - но в этом режиме кеш +// изображений должен быть обязательно включен! +$ti->embed_image = false; + +// устанавливаем - будут ли сохранятся/кешироваться изображения, true - да , false- нет. +$ti->do_cache = true; + +// путь до папки, где лежат сохраненные изображения (см. файл class.txtimage.php)если хотите изменить то меняйте в файле класса так же... +$ti->cache_folder = '../../uploads/txtimages'; + +// Преобразуем обычный текст в изображение +echo $ti->generate("$a", "$b", "$c", "$d", $e); +?> \ No newline at end of file diff --git a/fields/text_to_image/tpl/field-doc.tpl b/fields/text_to_image/tpl/field-doc.tpl new file mode 100644 index 0000000..20c861d --- /dev/null +++ b/fields/text_to_image/tpl/field-doc.tpl @@ -0,0 +1 @@ +{$field_value} \ No newline at end of file diff --git a/fields/text_to_image/tpl/field-req.tpl b/fields/text_to_image/tpl/field-req.tpl new file mode 100644 index 0000000..20c861d --- /dev/null +++ b/fields/text_to_image/tpl/field-req.tpl @@ -0,0 +1 @@ +{$field_value} \ No newline at end of file diff --git a/fields/text_to_image/tpl/field.tpl b/fields/text_to_image/tpl/field.tpl new file mode 100644 index 0000000..56d9afe --- /dev/null +++ b/fields/text_to_image/tpl/field.tpl @@ -0,0 +1,73 @@ +{if $get_field_text_to_image != 'load'} + {assign var=get_field_text_to_image value='' scope="global"} + + + {assign var=get_field_text_to_image value="load" scope="global"} +{/if} +
      +
      +   +   +{#TXT_IMG_SIZE#}   +   +{#TXT_IMG_COLOR#}   +   +
      +{#TXT_IMG_ALT#} + +    +    +  +
      {#TXT_IMG_BTN#}
         + +
      +
      + + \ No newline at end of file diff --git a/fields/youtube/field.php b/fields/youtube/field.php new file mode 100644 index 0000000..96efd84 --- /dev/null +++ b/fields/youtube/field.php @@ -0,0 +1,224 @@ +config_load($lang_file, 'lang'); + $AVE_Template->config_load($lang_file, 'admin'); + $AVE_Template->assign('config_vars', $AVE_Template->get_config_vars()); + + $result = 0; + + switch ($action) + { + + // Отображение поля в административной части + case 'edit': + $video = explode('|', $field_value); + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'admin'); + + $AVE_Template->assign('field_dir', $fld_name); + $AVE_Template->assign('video', $video); + $AVE_Template->assign('rubric_id', $rubric_id); + $AVE_Template->assign('doc_id', (int)$_REQUEST['Id']); + $AVE_Template->assign('field_id', $field_id); + $AVE_Template->assign('field_value', $field_value); + + return $AVE_Template->fetch($tpl_file); + + // Отображение поля в документах + case 'doc': + $field_value = clean_php($field_value); + + $field_param = explode('|', $field_value); + + if (! empty($field_param[0])) + $url = youtube_url_parser($field_param[0], $field_param[4]); + + if (! $tpl_empty) + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'doc', $_tpl); + + if($tpl_empty && $tpl_file) + { + $AVE_Template->assign('param', $field_param); + $AVE_Template->assign('video_url', $url); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + + // Отображение поля в запросах + case 'req': + $field_value = clean_php($field_value); + + $field_param = explode('|', $field_value); + + if (! empty($field_param[0])) + $url = youtube_url_parser($field_param[0], $field_param[4]); + + if (! $tpl_empty) + { + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + + $tpl_file = get_field_tpl($tpl_dir, $field_id, 'req', $_tpl); + + if($tpl_empty && $tpl_file) + { + $AVE_Template->assign('param', $field_param); + $AVE_Template->assign('video_url', $url); + return $AVE_Template->fetch($tpl_file); + } + + return $field_value; + + // Сохранение поля в административной части + case 'save': + if (isset($field_value) && $field_value['url'] != '' ) + { + $field_value = htmlspecialchars(implode("|", $field_value), ENT_QUOTES); + } + else + { + $field_value = ''; + } + break; + + case 'api': + if (empty($field_value)) + return $field_value; + + $_video = explode('|', $field_value); + + $video = [ + 'url' => (isset($_video[0]) ? $_video[0] : ''), + 'width' => (isset($_video[1]) ? $_video[1] : ''), + 'height' => (isset($_video[2]) ? $_video[2] : ''), + 'fullscreen' => (isset($_video[3]) ? $_video[3] : ''), + 'source' => (isset($_video[4]) ? $_video[4] : '') + ]; + + return $video; + break; + + // Тип/Имя поля в административной части + case 'name' : + return $AVE_Template->get_config_vars('name'); + } + + return ($result ? $result : $field_value); + } + + // Check YouTube link + if (! function_exists('youtube_url_parser')) + { + function youtube_url_parser($url, $source = 'embed') + { + // Parse URL + $p_url = parse_url($url); + + // Find host + $host = $p_url['host']; + + // Check if youtube + if ($host == 'www.youtube.com') { + + if (preg_match('/[\\?\\&]v=([^\\?\\&]+)/', $url, $match)) + { + $vid = $match[1]; + + if ($source == 'embed') + { + return 'https://www.youtube.com/v/'.$vid; + } + else + { + return 'https://www.youtube.com/embed/'.$vid; + } + + } + else + { + return $url; + } + + // Check the new video url + } + else if ($host == 'youtu.be') + { + if (preg_match('/^(http|https):\/\/youtu\.be\/(.*)/i', $url, $match)) + { + $vid = $match[2]; + + if ($source == 'embed') + { + return 'https://www.youtube.com/v/'.$vid; + } + else + { + return 'https://www.youtube.com/embed/'.$vid; + } + } + else + { + return $url; + } + } + // Nothing just return the url + else + { + return $url; + } + } + } +?> \ No newline at end of file diff --git a/fields/youtube/lang/bg.txt b/fields/youtube/lang/bg.txt new file mode 100644 index 0000000..d6f8fcb --- /dev/null +++ b/fields/youtube/lang/bg.txt @@ -0,0 +1,9 @@ +[admin] +name = "YouTube" +f_url = "Линк" +f_width = "Ширина" +f_height = "Височина" +f_fullscreen = "На цял екран" +f_allow = "Разреши" +f_forbidden = "Забрани" +f_metod = "Метод на вмъкване" diff --git a/fields/youtube/lang/cz.txt b/fields/youtube/lang/cz.txt new file mode 100644 index 0000000..8bc8292 --- /dev/null +++ b/fields/youtube/lang/cz.txt @@ -0,0 +1,9 @@ +[admin] +name = "YouTube" +f_url = "Ссылка" +f_width = "Ширина" +f_height = "Высота" +f_fullscreen = "Полноэкранный режим" +f_allow = "Разрешить" +f_forbidden = "Запретить" +f_metod = "Метод вставки" \ No newline at end of file diff --git a/fields/youtube/lang/en.txt b/fields/youtube/lang/en.txt new file mode 100644 index 0000000..2b76c11 --- /dev/null +++ b/fields/youtube/lang/en.txt @@ -0,0 +1,9 @@ +[admin] +name = "YouTube" +f_url = "Url" +f_width = "Width" +f_height = "Height" +f_fullscreen = "Fullscreen" +f_allow = "Allow" +f_forbidden = "Forbidden" +f_metod = "Metod" \ No newline at end of file diff --git a/fields/youtube/lang/pl.txt b/fields/youtube/lang/pl.txt new file mode 100644 index 0000000..2b76c11 --- /dev/null +++ b/fields/youtube/lang/pl.txt @@ -0,0 +1,9 @@ +[admin] +name = "YouTube" +f_url = "Url" +f_width = "Width" +f_height = "Height" +f_fullscreen = "Fullscreen" +f_allow = "Allow" +f_forbidden = "Forbidden" +f_metod = "Metod" \ No newline at end of file diff --git a/fields/youtube/lang/ru.txt b/fields/youtube/lang/ru.txt new file mode 100644 index 0000000..8bc8292 --- /dev/null +++ b/fields/youtube/lang/ru.txt @@ -0,0 +1,9 @@ +[admin] +name = "YouTube" +f_url = "Ссылка" +f_width = "Ширина" +f_height = "Высота" +f_fullscreen = "Полноэкранный режим" +f_allow = "Разрешить" +f_forbidden = "Запретить" +f_metod = "Метод вставки" \ No newline at end of file diff --git a/fields/youtube/lang/ua.txt b/fields/youtube/lang/ua.txt new file mode 100644 index 0000000..2b76c11 --- /dev/null +++ b/fields/youtube/lang/ua.txt @@ -0,0 +1,9 @@ +[admin] +name = "YouTube" +f_url = "Url" +f_width = "Width" +f_height = "Height" +f_fullscreen = "Fullscreen" +f_allow = "Allow" +f_forbidden = "Forbidden" +f_metod = "Metod" \ No newline at end of file diff --git a/fields/youtube/tpl/field-doc.tpl b/fields/youtube/tpl/field-doc.tpl new file mode 100644 index 0000000..dabc99e --- /dev/null +++ b/fields/youtube/tpl/field-doc.tpl @@ -0,0 +1,14 @@ +{if $param.4 == 'embed'} + + + + + + + + +{else} + + + +{/if} \ No newline at end of file diff --git a/fields/youtube/tpl/field-req.tpl b/fields/youtube/tpl/field-req.tpl new file mode 100644 index 0000000..dabc99e --- /dev/null +++ b/fields/youtube/tpl/field-req.tpl @@ -0,0 +1,14 @@ +{if $param.4 == 'embed'} + + + + + + + + +{else} + + + +{/if} \ No newline at end of file diff --git a/fields/youtube/tpl/field.tpl b/fields/youtube/tpl/field.tpl new file mode 100644 index 0000000..55f3d3b --- /dev/null +++ b/fields/youtube/tpl/field.tpl @@ -0,0 +1,24 @@ +
      + {#f_url#}: + +
      + +
      + {#f_width#}: px +          + {#f_height#}: px +
      + +
      + {#f_fullscreen#}: + +          + {#f_metod#}: + +
      \ No newline at end of file diff --git a/functions/.htaccess b/functions/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/functions/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/functions/func.block.php b/functions/func.block.php new file mode 100644 index 0000000..85e8171 --- /dev/null +++ b/functions/func.block.php @@ -0,0 +1,105 @@ +Query(" + SELECT + block_text + FROM + " . PREFIX . "_blocks + WHERE + " . (is_numeric($id) ? 'id' : 'block_alias') . " = '" . $id . "' + LIMIT 1 + ")->GetCell(); + + if ($cache_file) + file_put_contents($cache_file, $return); + } + + //-- парсим теги + $search = array( + '[tag:mediapath]', + '[tag:path]', + '[tag:docid]' + ); + + $replace = array( + ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', + ABS_PATH, + get_current_document_id() + ); + + $return = str_replace($search, $replace, $return); + + $return = preg_replace_callback('/\[tag:home]/', 'get_home_link', $return); + $return = preg_replace_callback('/\[tag:breadcrumb]/', 'get_breadcrumb', $return); + $return = preg_replace_callback('/\[tag:request:([A-Za-z0-9-_]{1,20}+)\]/', 'request_parse', $return); + + if (isset($_REQUEST['id']) && $_REQUEST['id'] != '') + { + //-- парсим теги полей документа в шаблоне рубрики + $return = preg_replace_callback('/\[tag:fld:([a-zA-Z0-9-_]+)\]\[([0-9]+)]\[([0-9]+)]/', 'get_field_element', $return); + $return = preg_replace_callback('/\[tag:fld:([a-zA-Z0-9-_]+)(|[:(\d)])+?\]/', 'document_get_field', $return); + $return = preg_replace_callback('/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', 'watermarks', $return); + $return = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $return); + } + + // Парсим блоки + $return = preg_replace_callback('/\[tag:block:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_block', $return); + // Парсим ситемные блоки + $return = preg_replace_callback('/\[tag:sysblock:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_sysblock', $return); + + $gen_time = Debug::endTime('BLOCK_' . $id); + + $GLOBALS['block_generate']['BLOCKS'][$id] = $gen_time; + + return $return; + } + + return false; + } +?> \ No newline at end of file diff --git a/functions/func.breadcrumbs.php b/functions/func.breadcrumbs.php new file mode 100644 index 0000000..f020fd0 --- /dev/null +++ b/functions/func.breadcrumbs.php @@ -0,0 +1,191 @@ +document_breadcrum_title, + $bread_show_host ? HOST . '/' . ltrim($lang_home_alias->document_alias, '/') : $lang_home_alias->document_alias, + 1 + ]; + + $link = str_replace($search, $replace, $bread_link_template); + + $bread_crumb = $lang_home_alias + ? sprintf($bread_link_box, $link) + : ''; + + if ($bread_sepparator_use) + $bread_crumb .= $bread_sepparator; + + unset ($search, $replace, $link, $sql, $lang_home_alias); + } + + if ($curent_document == 1 || $curent_document == PAGE_NOT_FOUND_ID) + $noprint = 1; + + $row_document = getDocument($curent_document); + + $current = new stdClass(); + + $current->document_breadcrum_title = (empty($row_document->document_breadcrum_title) + ? stripslashes(htmlspecialchars_decode($row_document->document_title)) + : stripslashes(htmlspecialchars_decode($row_document->document_breadcrum_title))); + + $row_document->document_parent = (isset($AVE_Core->curentdoc->document_parent) && $AVE_Core->curentdoc->document_parent != 0) + ? $AVE_Core->curentdoc->document_parent + : $row_document->document_parent; + + if (isset($row_document->document_parent) && $row_document->document_parent != 0) + { + $i = 0; + + $current->document_parent = $row_document->document_parent; + + while ($current->document_parent != 0) + { + $row_doc = getDocument($current->document_parent); + + $current->document_parent = $row_doc->document_parent; + + if ($row_doc->document_parent == $row_doc->Id) + { + echo "Ошибка! Вы указали в качестве родительского документа текущий документ.
      "; + $current->document_parent = 1; + } + + if ($row_doc->document_status==1 && $row_document->document_parent != 0) + { + $crumb['document_breadcrum_title'][$i] = (empty($row_doc->document_breadcrum_title) + ? stripslashes(htmlspecialchars_decode($row_doc->document_title)) + : stripslashes(htmlspecialchars_decode($row_doc->document_breadcrum_title))); + + $crumb['document_alias'][$i] = $row_doc->document_alias; + $crumb['Id'][$i] = $row_doc->Id; + + $i++; + } + + if ($row_doc->document_parent == 0 AND $row_doc->Id != 1) + $current->document_parent = 1; + } + + $length = count($crumb['document_breadcrum_title']); + + $crumb['document_breadcrum_title'] = array_reverse($crumb['document_breadcrum_title']); + + $crumb['document_alias'] = array_reverse($crumb['document_alias']); + + $crumb['Id'] = array_reverse($crumb['Id']); + + for ($n = 0; $n < $length; $n++) + { + if ($crumb['Id'][$n] != 1) + { + $number = $n; + + if ($bread_show_main) + $number = $number + 1; + + $url = rewrite_link('index.php?id=' . $crumb['Id'][$n] . '&doc=' . $crumb['document_alias'][$n]); + + $search = ['[name]', '[link]', '[count]']; + $replace = [$crumb['document_breadcrum_title'][$n], $bread_show_host ? HOST . '/' . ltrim($url, '/') : $url, $number]; + + $link = str_replace($search, $replace, $bread_link_template); + + $bread_crumb .= sprintf($bread_link_box, $link); + + if (get_settings('bread_link_box_last') == 1) + { + if ($bread_sepparator_use) + $bread_crumb .= $bread_sepparator; + } + else + { + if ($n != $length - 1) + if ($bread_sepparator_use) + $bread_crumb .= $bread_sepparator; + } + + unset($search, $replace, $link, $row_doc); + } + } + } + + // Последний элемент + if ((isset($AVE_Core->curentdoc->bread_link_box_last) && $AVE_Core->curentdoc->bread_link_box_last == 0)) + $bread_crumb .= ''; + else if (get_settings('bread_link_box_last') == 1 || (isset($AVE_Core->curentdoc->bread_link_box_last) && $AVE_Core->curentdoc->bread_link_box_last == 1)) + $bread_crumb .= str_replace('[count]', $number+1, sprintf($bread_self_box, $current->document_breadcrum_title)); + + if (! $noprint) + $crumbs[$curent_document] = sprintf($bread_box, $bread_crumb); + else + $crumbs[$curent_document] = ''; + + unset($bread_crumb); + + return $crumbs[$curent_document]; + } +?> \ No newline at end of file diff --git a/functions/func.common.php b/functions/func.common.php new file mode 100644 index 0000000..248eb40 --- /dev/null +++ b/functions/func.common.php @@ -0,0 +1,1421 @@ + 0 ? false : true; + } + + + /** + * Очистка текста от програмного кода + * + * @param string $text исходный текст + * @return string очищенный текст + */ + function clean_php($text) + { + return str_replace(array('', 'Системное сообщение: ' . $message . ''; + } + + + /** + * Сообщение о запрете распечатки страницы + * + */ + function print_error() + { + display_notice('Запрашиваемая страница не может быть распечатана.'); + exit; + } + + + /** + * Сообщение о проблемах доступа к файлам модуля + * + */ + function module_error() + { + display_notice('Запрашиваемый модуль не может быть загружен.'); + exit; + } + + + /** + * Получение основных настроек + * + * @param string $field параметр настройки, если не указан - все параметры + * @return mixed + */ + function get_settings($field = '') + { + global $AVE_DB; + + static $settings = null; + + if ($settings === null) + $settings = $AVE_DB->Query(" + SELECT + # SETTINGS + * + FROM + " . PREFIX . "_settings + ", -1, 'settings', true, '.settings')->FetchAssocArray(); + + if ($field == '') + return $settings; + + return isset($settings[$field]) + ? $settings[$field] + : null; + } + + + /** + * Формирование URL редиректа + * + * @param string|mixed $exclude + * @return string URL + */ + function get_redirect_link($exclude = '') + { + global $AVE_Core; + + $link = 'index.php'; + + if (! empty($_GET)) + { + if ($exclude != '' && ! is_array($exclude)) + $exclude = explode(',', $exclude); + + if (empty($exclude)) + $exclude = array(); + + $exclude[] = 'url'; + + $params = array(); + + foreach($_GET as $key => $value) + { + if (! in_array($key, $exclude)) + { + if ($key == 'doc') + { + $params[] = 'doc=' . (empty($AVE_Core->curentdoc->document_alias) ? prepare_url($AVE_Core->curentdoc->document_title) : $AVE_Core->curentdoc->document_alias); + } + else + { + if (! is_array($value)) + { + $params[] = @urlencode($key) . '=' . @urlencode($value); + } + else + { + foreach($value AS $k => $v) + { + $params[] = @urlencode($k) . '=' . @urlencode($v); + } + } + } + } + } + + if (sizeof($params)) + $link .= '?' . implode('&', $params); + } + + return $link; + } + + /** + * Ссылка на главную страницу + * + * @return string ссылка + */ + function get_home_link() + { + return HOST . ABS_PATH . ($_SESSION['user_language'] == DEFAULT_LANGUAGE + ? '' + : $_SESSION['accept_langs'][$_SESSION['user_language']] . URL_SUFF); + } + + + /** + * Ссылка на страницу версии для печати + * + * @return string ссылка + */ + function get_print_link() + { + /* + $link = get_redirect_link('print'); + $link .= (strpos($link, '?')===false ? '?print=1' : '&print=1'); + */ + /* Временное решение */ + $link = ABS_PATH."index.php?id=".get_current_document_id()."&print=1"; + + return $link; + } + + + /** + * + * + * @return string ссылка + */ + function get_referer_link() + { + static $link = null; + + if ($link === null) + { + if (isset($_SERVER['HTTP_REFERER'])) + { + $link = parse_url($_SERVER['HTTP_REFERER']); + $link = (trim($link['host']) == $_SERVER['SERVER_NAME']); + } + $link = ($link === true ? $_SERVER['HTTP_REFERER'] : get_home_link()); + } + + return $link; + } + + + /** + * Замена некоторых символов на их сущности + * замена и исправление HTML-тегов + * + * @param string|mixed $string + * @return string|mixed + */ + function pretty_chars($string) + { + return preg_replace(array("'©'" , "'®'"), + array('©', '®'), $string); + } + + + /** + * Подготовка URL + * + * @param string $url + * @return string + */ + function prepare_url($url) + { + $new_url = strip_tags($url); + + // спецсимволы + $table = array( + '«' => '', + '»' => '', + '—' => '', + '–' => '', + '“' => '', + '”' => '' + ); + + $new_url = str_replace(array_keys($table), array_values($table), $new_url); + + if (defined('TRANSLIT_URL') && TRANSLIT_URL) + $new_url = translit_string(trim(_strtolower($new_url))); + + $new_url = preg_replace( + array( + '/^[\/-]+|[\/-]+$|^[\/_]+|[\/_]+$|[^\.a-zа-яеёA-ZА-ЯЕЁ0-9\/_-]/u', + '/--+/', + '/-*\/+-*/', + '/\/\/+/' + ), + array( + '-', + '-', + '/', + '/' + ), + $new_url + ); + + $new_url = trim($new_url, '-'); + + if (substr(URL_SUFF, 0, 1) != '/' && substr($url, -1) == '/') + $new_url = $new_url . "/"; + + return mb_strtolower(rtrim($new_url, '.'), 'UTF-8'); + } + + + /** + * Формирование ЧПУ для документов + * + * @param string $s ссылка или текст с ссылками + * @return string + */ + function rewrite_link($s) + { + if (!REWRITE_MODE) + return $s; + + $doc_regex = '/index.php(?:\?)id=(?:[0-9]+)&(?:amp;)*doc='.(TRANSLIT_URL ? '([\.a-z0-9\/_-]+)' : '([\.a-zа-яёїєі0-9\/_-]+)'); + $page_regex = '&(?:amp;)*(artpage|apage|page)=([{s}0-9]+)'; + + $s = preg_replace($doc_regex.$page_regex.$page_regex.$page_regex.'/', ABS_PATH.'$1/$2-$3/$4-$5/$6-$7'.URL_SUFF, $s); + $s = preg_replace($doc_regex.$page_regex.$page_regex.'/', ABS_PATH.'$1/$2-$3/$4-$5'.URL_SUFF, $s); + $s = preg_replace($doc_regex.$page_regex.'/', ABS_PATH.'$1/$2-$3'.URL_SUFF, $s); + $s = preg_replace($doc_regex.'/', ABS_PATH.'$1'.URL_SUFF, $s); + //$s = preg_replace('/'.preg_quote(URL_SUFF, '/').'[?|&](?:amp;)*print=1/', '/print'.URL_SUFF, $s); + + return $s; + } + + + /** + * Возвращаем полный домен сайта + * + * @return mixed|string + */ + function getSiteUrl() + { + $protocol = isset($_SERVER['HTTPS']) + ? 'https' + : 'http'; + + $url = $protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + + $url = parse_url($url); + + $url = $url['scheme'] . '://' . $url['host']; + + return $url; + } + + + /** + * Преобразует первый символ в верхний регистр + * @param string $str - строка + * @param string $encoding - кодировка, по-умолчанию UTF-8 + * @return string + */ + function ucfirst_utf8($str, $encoding='utf-8') + { + $str = mb_ereg_replace('^[\ ]+', '', $str); + $str = mb_strtoupper(mb_substr($str, 0, 1, $encoding), $encoding) . mb_substr($str, 1, mb_strlen($str), $encoding); + return $str; + } + + + /** + * Вывод статистики + * + * @param int $t + * @param int $m + * @param int $q + * @param int $l + * + * @return string + */ + function get_statistic($t=0, $m=0, $q=0, $l=0) + { + global $AVE_DB; + + $s = ''; + + if ($t) + $s .= "\n
      Время генерации: " . number_format(microtime_diff(START_MICROTIME, microtime()), 3, ',', ' ') . ' сек.'; + + if ($m && function_exists('memory_get_peak_usage')) + $s .= "\n
      Использовано памяти: " . Debug::formatSize(memory_get_usage() - START_MEMORY); + + if ($m && function_exists('memory_get_peak_usage')) + $s .= "\n
      Пиковое значение: " . Debug::formatSize(memory_get_peak_usage()); + + if ($q && (defined('SQL_PROFILING') && SQL_PROFILING)) + $s .= "\n
      Количество запросов: " . $AVE_DB->DBProfilesGet('count') . ' шт. за ' . $AVE_DB->DBProfilesGet('time') . ' сек.'; + + if ($l && (defined('SQL_PROFILING') && SQL_PROFILING)) + $s .= $AVE_DB->DBProfilesGet('list'); + + return $s; + } + + + /** + * Комментарии в SMARTY + * + * @param $tpl_source + * @param $smarty + * + * @return string + */ + function add_template_comment($tpl_source, &$smarty) + { + return "\n\n\n".$tpl_source."\n\n\n"; + } + + + /** + * Получения списка стран + * + * @param int $status статус стран входящих в список + *
        + *
      • 1 - активные страны
      • + *
      • 0 - неактивные страны
      • + *
      + * если не указано возвращает список стран без учета статуса + * + * @return array + */ + function get_country_list($status = null) + { + global $AVE_DB; + + $countries = array(); + $sql = $AVE_DB->Query(" + SELECT + country_code, + country_name, + country_status + FROM " . PREFIX . "_countries + " . (($status != '') ? "WHERE country_status = '" . $status . "'" : '') . " + ORDER BY country_name ASC + "); + while ($row = $sql->FetchRow()) array_push($countries, $row); + + return $countries; + } + + + /** + * Получение списка изображений из заданной папки + * @param string $path путь до директории с изображениями + * @return array + */ + function image_multi_import($path) + { + $images_ext = array('jpg', 'jpeg', 'png', 'gif', 'webp'); + + $dir = BASE_DIR . "/" . $path; + + $dir_abs = "/" . $path; + + $files = array(); + $thumbs = array(); + + if ($handle = opendir($dir)) + { + while (false !== ($file = readdir($handle))) + { + $nameParts = explode('.', $file); + $ext = strtolower(end($nameParts)); + + if ($file != "." && $file != ".." && in_array($ext, $images_ext)) + { + if (! is_dir($dir . "/" . $file)) + { + $files[] = $file; + $thumbs[] = make_thumbnail(array('link' => $dir_abs . $file, 'size' => 't128x128')); + } + } + } + closedir($handle); + } + + //$return = array( + // 'files' => $files, + // 'thumbs' => $thumbs + //); + + return $files; + } + + + /** + * Получение списка файлов из заданной папки + * @param string $path путь до директории с файлами + * @return array + */ + function file_multi_import($path) + { + $dir = BASE_DIR . "/" . $path; + + $files = array(); + + if ($handle = opendir($dir)) + { + while (false !== ($file = readdir($handle))) + { + $nameParts = explode('.', $file); + $ext = strtolower(end($nameParts)); + + if ($file != "." && $file != ".." && $ext == "php" || $ext == "inc") + { + if (! is_dir($dir . "/" . $file)) + $files[] = $file; + } + } + closedir($handle); + } + + return $files; + } + + + /** + * Replace PHP_EOL constant + * + * @category PHP + * @package PHP_Compat + * @license LGPL - http://www.gnu.org/licenses/lgpl.html + * @copyright 2004-2007 Aidan Lister , Arpad Ray + * @link http://php.net/reserved.constants.core + * @author Aidan Lister + * @version $Revision: 1.3 $ + * @since PHP 5.0.2 + */ + if (! defined('PHP_EOL')) + { + switch (strtoupper(substr(PHP_OS, 0, 3))) + { + // Windows + case 'WIN': + define('PHP_EOL', "\r\n"); + break; + + // Mac + case 'DAR': + define('PHP_EOL', "\r"); + break; + + // Unix + default: + define('PHP_EOL', "\n"); + } + } + + + /** + * Функция записывает в указанную папку .htaccess с содержанием "Deny from all" + * + * @param $dir + */ + function write_htaccess_deny($dir) + { + $file = $dir . '/.htaccess'; + + if (! file_exists($file)) + { + if (! is_dir($dir)) + @mkdir($dir); + + @file_put_contents($dir . '/.htaccess','Deny from all'); + } + } + + + /** + * Функция которая паникует если приблизились к memory_limit + * + * @return bool превышение лимита использования памяти + */ + function memory_panic() + { + if (defined('MEMORY_LIMIT_PANIC') && MEMORY_LIMIT_PANIC != -1) + { + $use_mem = memory_get_usage(); + $lim = MEMORY_LIMIT_PANIC * 1024 * 1024; + return ($use_mem > $lim ? true : false); + } + else + return false; + } + + + /** + * Первод Array в Object + * + * @param array $array + * @return array obj + */ + function array2object($array) + { + if (is_array($array)) + { + $obj = new StdClass(); + foreach ($array as $key => $val) + { + $obj->$key = $val; + } + } + else + $obj = $array; + + return $obj; + } + + + /** + * Первод Object в Array + * + * @param array $object + * @return array + */ + function object2array($object) + { + $object = (array)$object; + + if ($object === array()) + return $object; + + foreach($object as $key => &$value) + { + if ((is_object($value) || is_array($value))) + { + $object[$key] = object2array($value); + } + } + + return $object; + } + + + /** + * Sort a 2 dimensional array based on 1 or more indexes. + * + * msort() can be used to sort a rowset like array on one or more + * 'headers' (keys in the 2th array). + * + * @param array $array The array to sort. + * @param string|array $key The index(es) to sort the array on. + * @param int $sort_flags The optional parameter to modify the sorting + * @param int $sort_way The optional parameter to modify the sorting as DESC or ASC + * behavior. This parameter does not work when + * supplying an array in the $key parameter. + * + * @return array The sorted array. + */ + function msort($array, $key, $sort_flags = SORT_REGULAR, $sort_way = SORT_ASC) + { + if (is_array($array) && count($array) > 0) + { + if (! empty($key)) + { + $mapping = array(); + + foreach ($array as $k => $v) + { + $sort_key = ''; + + if ( !is_array($key)) + { + $sort_key = $v[$key]; + } + else + { + // @TODO This should be fixed, now it will be sorted as string + foreach ($key as $key_key) { + $sort_key .= $v[$key_key]; + } + + $sort_flags = SORT_STRING; + } + + $mapping[$k] = $sort_key; + } + + switch ($sort_way) + { + case SORT_ASC: + asort($mapping, $sort_flags); + break; + + case SORT_DESC: + arsort($mapping, $sort_flags); + break; + } + + $sorted = array(); + + foreach ($mapping as $k => $v) + { + $sorted[] = $array[$k]; + } + + return $sorted; + } + } + return $array; + } + + + /** + * Функция возвращает каноническое имя страницы + * + * @param string $url текущий УРЛ + * @return string + */ + function canonical($url) + { + $link = preg_replace('/^(.+?)(\?.*?)?(#.*)?$/', '$1$3', $url); + return $link; + } + + + /** + * Функция поиска автора документа, для autocmplite + * + * @param string $string + * @param $limit + */ + function findautor($string, $limit) + { + global $AVE_DB; + + $search = " + AND (UPPER(email) LIKE UPPER('%" . $string . "%') + OR UPPER(email) = UPPER('" . $string . "') + OR Id = '" . intval($string) . "' + OR UPPER(user_name) LIKE UPPER('" . $string . "%') + OR UPPER(firstname) LIKE UPPER('" . $string . "%') + OR UPPER(lastname) LIKE UPPER('" . $string . "%')) + "; + + $limit = (!empty($limit)) ? 'LIMIT 0,'.$limit : ''; + + $sql = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_users + WHERE 1" + . $search + . $limit + ); + + $users = array(); + + while ($row = $sql->FetchRow()) + { + $ava=getAvatar($row->Id,40); + $users[]=array( + 'userid'=>$row->Id, + 'login'=>$row->user_name, + 'email'=>$row->email, + 'lastname'=>$row->lastname, + 'firstname'=>$row->firstname, + 'avatar'=>($ava ? $ava : ABS_PATH.'admin/templates/images/user.png') + ); + } + + echo json_encode($users); + } + + + /** + * Функция поиска ключевых слов + * + * @param string $string - запрос + * @return string + */ + function searchKeywords($string) + { + global $AVE_DB; + + $search = " + AND (UPPER(keyword) LIKE UPPER('" . $string . "%')) + "; + + $sql = $AVE_DB->Query(" + SELECT * + FROM " . PREFIX . "_document_keywords + WHERE 1" + . $search + ); + + while ($row = $sql->FetchRow()) + { + $keyword = $row->keyword; + echo "$keyword\n"; + } + } + + + /** + * Функция поиска тегов + * + * @return string + */ + function searchTags() + { + global $AVE_DB; + + $sql = $AVE_DB->Query(" + SELECT DISTINCT + tag + FROM + " . PREFIX . "_document_tags + "); + + $tags = array(); + + //$ii = 0; + + while ($row = $sql->GetCell()) + $tags[]['value'] = $row; + + echo json_encode($tags); + exit; + } + + + /** + * Формирование строки из случайных символов + * + * @param int $length количество символов в строке + * @param string $chars набор символов для формирования строки + * @return string сформированная строка + */ + function make_random_string($length = 16, $chars = '') + { + if ($chars == '') + { + $chars = 'abcdefghijklmnopqrstuvwxyz'; + $chars .= 'ABCDEFGHIJKLMNOPRQSTUVWXYZ'; + $chars .= '~!@#$%^&*()-_=+{[;:/?.,]}'; + $chars .= '0123456789'; + } + + $clen = strlen($chars) - 1; + + $string = ''; + while (strlen($string) < $length) $string .= $chars[mt_rand(0, $clen)]; + + return $string; + } + + + /** + * Функция preg_replace для кириллицы + * если заменять русские символы в строке UTF-8 при помощи preg_replace, то появляются вопросы + * + * @param mixed $pattern шаблон заменяемой части строки + * @param mixed $replacement на что заменяем + * @param mixed $string входящая строка + * @param int $limit максимум вхождений + * mixed preg_replace_ru ( mixed pattern, mixed replacement, mixed subject [, int limit] ) + * + * @return mixed + */ + function preg_replace_ru($pattern="", $replacement="", $string="", $limit=-1) + { + $string = iconv('UTF-8', 'cp1251', $string); + $string = preg_replace($pattern, $replacement, $string, $limit); + return iconv('cp1251', 'UTF-8', $string); + } + + + /** + * Создание cookie + * + * @param string $cookie_domain + */ + function set_cookie_domain($cookie_domain = '') + { + global $cookie_domain; + + if ($cookie_domain == '' && defined('COOKIE_DOMAIN') && COOKIE_DOMAIN != '') + { + $cookie_domain = COOKIE_DOMAIN; + } + elseif ($cookie_domain == '' && !empty($_SERVER['HTTP_HOST'])) + { + $cookie_domain = htmlspecialchars($_SERVER['HTTP_HOST'], ENT_QUOTES); + } + + // Удаляем ведущие www. и номер порта в имени домена для использования в cookie. + $cookie_domain = ltrim($cookie_domain, '.'); + if (strpos($cookie_domain, 'www.') === 0) + { + $cookie_domain = substr($cookie_domain, 4); + } + $cookie_domain = explode(':', $cookie_domain); + $cookie_domain = '.'. $cookie_domain[0]; + + // В соответствии с RFC 2109, имя домена для cookie должно быть второго или более уровня. + // Для хостов 'localhost' или указанных IP-адресом имя домена для cookie не устанавливается. + if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) + { + ini_set('session.cookie_domain', $cookie_domain); + } + + ini_set('session.cookie_path', ABS_PATH); + } + + + /** + * Функция проверяет наличие Ajax запроса + * + * @return bool + */ + function isAjax() + { + return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')); + } + + + /** + * Функция делает html в 1 строчку, удаляет лишние пробелы, комментарии и т.д. + * + * @param $data + * + * @return string + */ + function compress_htlm($data) + { + $search = array( + '/\>[^\S ]+/s', // strip whitespaces after tags, except space + '/[^\S ]+\/' // Remove HTML comments + ); + + $replace = array( + '>', + '<', + '\\1', + '' + ); + + $data = preg_replace($search, $replace, $data); + + return $data; + } + + + /** + * Функция делает компрессию данных + * + * @param $data + * + */ + function output_compress($data) + { + global $AVE_DB; + + $Gzip = strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false; + + if (defined('HTML_COMPRESSION') && HTML_COMPRESSION) + $data = compress_htlm($data); + + if (isset($_REQUEST['sysblock'])) + define('ONLYCONTENT', true); + + //-- Вывод статистики загрузки и запросов SQL (только для администраторов) + if (! defined('ONLYCONTENT') && UGROUP == 1) + { + if (defined('PROFILING') && PROFILING == 'light') + { + $data .= "\r\n" . ""; + $data .= "\r\n" . ""; + $data .= "\r\n" . ""; + + if (defined('SQL_PROFILING') && SQL_PROFILING) + $data .= "\r\n" . ""; + } + else if (defined('PROFILING') && PROFILING == 'full') { + $data .= Debug::displayInfo(); + } + } + + if ($Gzip && (defined('GZIP_COMPRESSION') && GZIP_COMPRESSION)) + { + $data = gzencode($data, 9); + header ('Content-Encoding: gzip'); + } + + if (UGROUP !== 1 && (defined('PROFILING') && PROFILING == 'full')) + { + $data .= "\r\n" . ""; + $data .= "\r\n" . ""; + $data .= "\r\n" . ""; + + if (defined('SQL_PROFILING') && SQL_PROFILING) + $data .= "\r\n" . ""; + } + + header ('X-Engine: AVE.cms'); + header ('X-Engine-Copyright: 2007-' . date('Y') . ' (c) AVE.cms'); + header ('X-Engine-Site: https://www.ave-cms.ru'); + + header ('Content-Type: text/html; charset=utf-8'); + header ('Cache-Control: must-revalidate'); + if (defined('OUTPUT_EXPIRE') && OUTPUT_EXPIRE) + { + $expire = 'Expires: ' . gmdate ("D, d M Y H:i:s", time() + OUTPUT_EXPIRE_OFFSET) . ' GMT'; + header ($expire); + } + header ('Content-Length: ' . strlen($data)); + header ('Vary: Accept-Encoding'); + + echo $data; + } + + + /** + * Функция создает короткий URL документа для редиректа + * После выполения функции нужно очистить кеш данного документа + * + * @param int $length + * @param $doc_id + * + * @return bool + */ + function gen_short_link ($length, $doc_id) + { + global $AVE_DB; + + if (! is_numeric($doc_id)) + return false; + + if (! $length) + $length = 1; + + // Проврека на существование редиректа для данного документа + $check_doc = $AVE_DB->Query(" + SELECT + id + FROM + " . PREFIX . "_document_alias_history + WHERE + document_id = '" . $doc_id . "' + ")->GetCell(); + + // Если редирект отсутствует + if (! $check_doc) + { + $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $short_link = ''; + + for ($i = 0; $i < $length; $i++) + $short_link .= $characters[rand(0, strlen($characters) - 1)]; + + // Проеряем есть такое редирект уже + $exists = $AVE_DB->Query(" + SELECT + id + FROM + " . PREFIX . "_document_alias_history + WHERE + document_alias = '" . $short_link . "' + ")->GetCell(); + + // Если есть, повторяем генерацию + if ($exists) + { + gen_short_link($length, $doc_id); + } + // Иначе заносим в БД + else + { + $AVE_DB->Query(" + INSERT INTO + " . PREFIX . "_document_alias_history + SET + document_id = '" . $doc_id . "', + document_alias = '" . $short_link . "', + document_alias_author = '" . $_SESSION['user_id'] . "', + document_alias_changed = '" . time() . "' + "); + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_documents + SET + document_short_alias = '" . $short_link . "' + WHERE + Id = '" . $doc_id . "' + "); + } + } + + return true; + } + + + /** + * Функция возвращает данные в формате JSON + * + * @param $data + * @param bool $exit + */ + function _json ($data, $exit = false) + { + header("Content-Type: application/json;charset=utf-8"); + + $json = json_encode($data); + + if ($json === false) + { + $json = json_encode(array("jsonError", json_last_error_msg())); + + if ($json === false) + { + $json = '{"jsonError": "unknown"}'; + } + + http_response_code(500); + } + + echo $json; + + if ($exit) + exit; + } + + + /** + * _base64_encode() + * + * @param string $input + * @return + */ + function _base64_encode($input) + { + return strtr(base64_encode($input), '+/=', '-_,'); + } + + + /** + * _base64_decode() + * + * @param string $input + * @return + */ + function _base64_decode($input) + { + return base64_decode(strtr($input, '-_,', '+/=')); + } + + + /** + * Функция принимает строку, и возвращает + * адрес первого изображения, которую найдет + * + * @param $data + * + * @return string + */ + function getImgSrc($data) + { + $_req_exp = '/()/u'; + + preg_match_all($_req_exp, $data, $images); + + $host = $images[2][0]; + + if (preg_match("/(src=)('|\")(.+?)('|\")/u", $host, $matches) == 1) + $host = $matches[3]; + + preg_match('@/index\.php\?.*thumb=(.*?)\&@i', $host, $matches); + + if (isset($matches[1])) + { + return $matches[1]; + } + else + { + preg_match('/(.+)' . THUMBNAIL_DIR . '\/(.+)-.\d+x\d+(\..+)/u', $host, $matches); + + if (isset($matches[1])) + return $matches[1] . $matches[2] . $matches[3]; + else + return $host; + } + } + + + function getIp () + { + $ip = false; + $ipa = array(); + + if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) + $ipa[] = trim(strtok($_SERVER['HTTP_X_FORWARDED_FOR'], ',')); + + if (isset($_SERVER['HTTP_CLIENT_IP'])) + $ipa[] = $_SERVER['HTTP_CLIENT_IP']; + + if (isset($_SERVER['REMOTE_ADDR'])) + $ipa[] = $_SERVER['REMOTE_ADDR']; + + if (isset($_SERVER['HTTP_X_REAL_IP'])) + $ipa[] = $_SERVER['HTTP_X_REAL_IP']; + + //-- Проверяем ip-адреса на валидность начиная с приоритетного. + foreach ($ipa as $ips) + { + //-- Если ip валидный обрываем цикл, назначаем ip адрес и возвращаем его + if (isValidIp($ips)) + { + //-- Localhost IP6 + if ($ips == '::1') + $ips = '127.0.0.1'; + + $ip = $ips; + break; + } + } + + return $ip; + } + + + function isValidIp ($ip = null) + { + //-- Если ip-адрес попадает под регулярное выражение, возвращаем true + if (preg_match('#^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$#', $ip)) + return true; + + //-- Localhost IP6 + if ($ip == '::1') + return true; + + //-- Иначе возвращаем false + return false; + } + + if (! function_exists('getExtension')) + { + function getExtension($path) + { + return strtolower(substr(strrchr($path, "."), 1)); + } + } + + + if (! function_exists('fixSerialize')) + { + function fixSerialize($string) + { + $fixed = preg_replace_callback( + '/s:([0-9]+):\"(.*?)\";/', + function ($matches) { + return "s:".strlen($matches[2]).':"'.$matches[2].'";'; + }, + $string + ); + + return $fixed; + } + } +?> \ No newline at end of file diff --git a/functions/func.custom.php b/functions/func.custom.php new file mode 100644 index 0000000..eddd14b --- /dev/null +++ b/functions/func.custom.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/functions/func.documents.php b/functions/func.documents.php new file mode 100644 index 0000000..9812292 --- /dev/null +++ b/functions/func.documents.php @@ -0,0 +1,182 @@ +  + // Chrome
       
      + // FF
       
      + $pages = preg_split('#
       
      #i', $text); + $total_page = @sizeof($pages); + + if ($total_page > 1) + { + $text = @$pages[get_current_page('artpage')-1]; + + $page_nav = ' {t} '; + $page_nav = get_pagination($total_page, 'artpage', $page_nav, get_settings('navi_box')); + + $text .= rewrite_link($page_nav); + } + + $pages = ''; + + return $pages . $text; + } + + /** + * Получить идентификатор текущего документа + * + * @return int идентификатор текущего документа + */ + function get_current_document_id() + { + $_REQUEST['id'] = (isset($_REQUEST['id']) && is_numeric($_REQUEST['id'])) + ? $_REQUEST['id'] + : 1; + + return $_REQUEST['id']; + } + + /** + * Получить идентификатор родительского документа + * + * @return int идентификатор родительского документа + */ + function get_parent_document_id () + { + global $AVE_DB; + return $AVE_DB->Query("SELECT document_parent FROM " . PREFIX . "_documents WHERE Id = '".get_current_document_id()."' ")->GetCell(); + } + + /** + * Функция отдаёт основные параметры дока + * + * @param int $doc_id - номер id документа + * @param string $key - параметр документа + * + * @return string | bool | array + */ + function get_document ($doc_id , $key ='') + { + $doc_id = (int)$doc_id; + + if ($doc_id < 1) + return []; +/* + if (defined('USE_STATIC_DATA') && USE_STATIC_DATA) + static $get_documents_data = []; + else + $get_documents_data = []; +*/ + + + if (! (Registry::stored('documents', $doc_id))) + $documents_data = getDocument($doc_id); + else + $documents_data = Registry::get('documents', $doc_id); + + if (! is_object($documents_data)) + return false; + + $documents_data = object2array($documents_data); + + $documents_data['doc_title'] = $documents_data['document_title'] = htmlspecialchars_decode($documents_data['document_title'], ENT_QUOTES); + + $documents_data['feld'] = []; + + if (isset($key) && $key != '') + return $documents_data[$key]; + else + return $documents_data; + } + + + /** + * Функция отдаёт основные параметры дока + * + * @param int $doc_id - номер id документа + * + * @return object | bool + */ + function getDocument ($doc_id) + { + global $AVE_DB; + + if (! defined('USE_STATIC_DATA') || ! USE_STATIC_DATA) + Registry::clean(); + + $doc_id = (int)$doc_id; + + if ($doc_id < 1) + return false; + + $documents = Registry::get('documents'); + + $sql = " + SELECT + # DOCUMENT = $doc_id + doc.* + FROM + " . PREFIX . "_documents AS doc + LEFT JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = doc.rubric_id + WHERE + doc.Id = '" . $doc_id . "' + "; + + $cache_time = (defined('CACHE_DOC_FILE') && CACHE_DOC_FILE) + ? -1 + : 0; + + $data = $AVE_DB->Query($sql, $cache_time, 'dat_' . $doc_id, true, '.data')->FetchRow(); + + if (! is_object($data)) + return false; + + $documents[$data->Id] = $data; + + Registry::set('documents', $documents); + + unset ($documents); + + return Registry::get('documents', $doc_id); + } + + + function DocumentBeforeSave ($data) + { + return $data; + } + + + function DocumentAfterSave ($data) + { + return $data; + } +?> \ No newline at end of file diff --git a/functions/func.fields.php b/functions/func.fields.php new file mode 100644 index 0000000..12e8078 --- /dev/null +++ b/functions/func.fields.php @@ -0,0 +1,954 @@ +read())) + { + $field_dir = $d->path . '/' . $entry; + + if (is_dir($field_dir) && file_exists($field_dir . '/field.php')) + { + require_once ($field_dir . '/field.php'); + } + } + + $d->Close(); + } + + + /** + * Проверка папок /fields/ в модулях, на наличие полей + */ + if (is_dir(BASE_DIR . '/modules/')) + { + $d = dir(BASE_DIR . '/modules'); + + while (false !== ($entry = $d->read())) + { + $module_dir = $d->path . '/' . $entry; + + if (is_dir($module_dir) && file_exists($module_dir . '/field.php')) + require_once($module_dir . '/field.php'); + } + + $d->Close(); + } + + + /** + * Поле по умолчанию + * + * @param $field_value + * @param $action + * @param int $field_id + * @param string $tpl + * @param int $tpl_empty + * @param null $maxlength + * @param array $document_fields + * @param int $rubric_id + * @param null $default + * + * @return string + */ + function get_field_default ($field_value, $action, $field_id=0, $tpl='', $tpl_empty=0, &$maxlength=null, $document_fields=array(), $rubric_id=0, $default=null, $_tpl=null) + { + switch ($action) + { + case 'edit': + return ''; + case 'doc': + case 'req': + if (! $tpl_empty) + { + $field_param = explode('|', $field_value); + + $field_value = preg_replace_callback( + '/\[tag:parametr:(\d+)\]/i', + function($data) use($field_param) + { + return $field_param[(int)$data[1]]; + }, + $tpl + ); + } + return $field_value; + + default: + return $field_value; + } + } + + + /** + * Возвращаем тип поля + * + * @param string $type + * + * @return mixed + */ + function get_field_type ($type = '') + { + static $fields; + + if (is_array($fields)) + return $fields; + + $arr = get_defined_functions(); + + $fields = []; + $field = []; + + foreach ($arr['user'] as $v) + { + if (trim(substr($v, 0, strlen('get_field_'))) == 'get_field_') + { + $d = ''; + + $name = @$v('', 'name', '', '', 0, $d); + + $id = substr($v, strlen('get_field_')); + + if ($name != false && is_string($name)) + $fields[] = ['id' => $id, 'name' => $name]; + + if (! empty($type) && $id == $type) + $field = ['id' => $id, 'name' => $name]; + } + else + continue; + } + + $fields = msort($fields, ['name']); + + return (! empty($type)) + ? $field + : $fields; + } + + + /** + * Возвращаем алиас по номеру поля + * + * @param $id + * @return string + */ + function get_field_alias ($field_id) + { + if (! Registry::stored('fields_params', $field_id)) + _get_field_params($field_id); + + $alias = Registry::get('fields_params', $field_id); + + $alias = $alias['rubric_field_alias'] ? $alias['rubric_field_alias'] : $field_id; + + return $alias; + } + + + /** + * Возвращаем номер поля по рубрике и алиасу + * + * @param $rubric_id + * @param $alias + * + * @return string + */ + function get_field_num ($rubric_id, $alias) + { + global $AVE_DB; + + static $alias_field_id = []; + + if (isset($alias_field_id[$rubric_id][$alias])) + return $alias_field_id[$rubric_id][$alias]; + + $sql = " + SELECT + Id + FROM + " . PREFIX . "_rubric_fields + WHERE + (rubric_field_alias = '" . addslashes($alias) . "' + OR Id = '" . intval($alias) . "') + AND + rubric_id = " . intval($rubric_id) + ; + + $alias_field_id[$rubric_id][$alias] = $AVE_DB->Query($sql)->GetCell(); + + return $alias_field_id[$rubric_id][$alias]; + } + + + /** + * Возвращаем значение по умолчанию, для поля + * + * @param $id + * + * @return string + */ + function get_field_default_value ($id) + { + global $AVE_DB; + + static $alias_field_id = []; + + if (isset($alias_field_id[$id])) + return $alias_field_id[$id]; + + $sql = " + SELECT + rubric_field_default + FROM + " . PREFIX . "_rubric_fields + WHERE + Id = ".intval($id) + ; + + $alias_field_id[$id] = $AVE_DB->Query($sql)->GetCell(); + + return $alias_field_id[$id]; + } + + + /** + * Возвращаем шаблон tpl или пусто + * + * @param string $dir папка шаблона + * @param int $field_id идентификатор поля + * @param string $type тип поля + * @param int $_tpl номер шаблона + * + * @return string + */ + function get_field_tpl ($dir = '', $field_id = 0, $type = 'admin', $_tpl = null) + { + if (! $type) + return false; + + $alias_field_id = get_field_alias($field_id); + + // Если существует файл с ID поля и ID шаблона + if (file_exists($dir.'field-'.$type.'-'.$field_id.'-'.$_tpl.'.tpl')) + $tpl = $dir.'field-'.$type.'-'.$field_id.'-'.$_tpl.'.tpl'; + // Если существует файл с аласом поля и ID шаблона + else if (file_exists($dir.'field-'.$type.'-'.$alias_field_id.'-'.$_tpl.'.tpl')) + $tpl = $dir.'field-'.$type.'-'.$alias_field_id.'-'.$_tpl.'.tpl'; + // Если существует файл с ID поля + else if (file_exists($dir.'field-'.$type.'-'.$field_id.'.tpl')) + $tpl = $dir.'field-'.$type.'-'.$field_id.'.tpl'; + // Если существует файл с алиасом поля + else if (file_exists($dir.'field-'.$type.'-'.$alias_field_id.'.tpl')) + $tpl = $dir.'field-'.$type.'-'.$alias_field_id.'.tpl'; + // Если существует файл c типом поля + else if (file_exists($dir.'field-'.$type.'.tpl')) + $tpl = $dir.'field-'.$type.'.tpl'; + // Если существует файл c ID поля + else if (file_exists($dir.'field-'.$field_id.'.tpl')) + $tpl = $dir.'field-'.$field_id.'.tpl'; + // Иначе + else + $tpl = $dir.'field.tpl'; + + return $tpl; + } + + + /** + * Формирование поля документа в соответствии с шаблоном отображения + * + * @param int $field_id идентификатор поля + * @param int $document_id + * + * @param null $_tpl + * + * @param null $maxlength + * + * @return string + */ + function document_get_field ($field_id, $document_id = null, $_tpl = null, $maxlength = null) + { + global $AVE_Core; + + if (! $_tpl && is_array($field_id)) + $_tpl = $field_id[2]; + + if (is_array($field_id)) + $field_id = $field_id[1]; + + $document_fields = get_document_fields(empty($document_id) + ? $AVE_Core->curentdoc->Id + : intval($document_id)); + + if (! is_array($document_fields[$field_id])) + $field_id = intval($document_fields[$field_id]); + + if (empty($document_fields[$field_id])) + return ''; + + $field_value = trim($document_fields[$field_id]['field_value']); + + $tpl_field_empty = $document_fields[$field_id]['tpl_field_empty']; + + // ToDo + // if ($field_value == '' && $tpl_field_empty) return ''; + + $field_type = $document_fields[$field_id]['rubric_field_type']; + + $rubric_field_template = trim($document_fields[$field_id]['rubric_field_template']); + + $rubric_field_default = $document_fields[$field_id]['rubric_field_default']; + + // ToDo + // $field_value = parse_hide($field_value); + // $field_value = ($length != '') ? truncate_text($field_value, $length, '…', true) : $field_value; + + $func = 'get_field_' . $field_type; + + if (! is_callable($func)) + $func = 'get_field_default'; + + $field_value = $func($field_value, 'doc', $field_id, $rubric_field_template, $tpl_field_empty, $maxlength, $document_fields, RUB_ID, $rubric_field_default, $_tpl); + + return $field_value; + } + + + /** + * Функция получения содержимого поля для обработки в шаблоне рубрики + * + * @param int $field_id идентификатор поля, для [tag:fld:12] $field_id = 12 + * @param int $length необязательный параметр, + * количество возвращаемых символов содержимого поля. + * если данный параметр указать со знаком минус + * содержимое поля будет очищено от HTML-тегов. + * @return string + */ + function document_get_field_value ($field_id, $length = 0) + { + if (! is_numeric($field_id)) + return ''; + + $doc_id = get_current_document_id(); + + $document_fields = get_document_fields($doc_id); + + $field_value = trim($document_fields[$field_id]['field_value']); + + if ($field_value != '') + { + $field_value = strip_tags($field_value); // "

      " + + if (is_numeric($length) && $length != 0) + { + if ($length < 0) + { + $field_value = strip_tags($field_value); + $field_value = preg_replace('/ +/', ' ', $field_value); + $field_value = trim($field_value); + $length = abs($length); + } + + $field_value = truncate_text($field_value, $length, '…'); + } + } + + return $field_value; + } + + + /** + * Возвращаем истинное значение поля для документа + * + * @param int $document_id id документа + * @param string $field id поля или его алиас + * + * @return string + */ + function get_document_field ($document_id, $field) + { + if (Registry::stored($document_id, $field)) + $document_fields = Registry::get($document_id, $field); + else + $document_fields = get_document_fields($document_id); + + if (! is_array($document_fields[$field])) + $field = intval($document_fields[$field]); + + if (empty($document_fields[$field])) + return false; + + $field_value = $document_fields[$field]['field_value']; + + return $field_value; + } + + + /** + * Функция возвращает массив со значениями полей + * + * @param $document_id + * @param array $values если надо вернуть документ с произвольными значениями - используется для ревизий документов + * @internal param int $id id документа + * @return mixed + */ + function get_document_fields ($document_id, $values = null) + { + global $AVE_DB, $AVE_Core; //$request_documents + + if (! is_numeric($document_id)) + return false; + + if (! defined('USE_STATIC_DATA') || ! USE_STATIC_DATA) + Registry::clean(); + + if (Registry::stored('fields', $document_id)) + return Registry::get('fields', $document_id); + + $document_fields = Registry::get('fields'); + $fields_param = Registry::get('fields_param'); + + if (Registry::stored('rubric_changeds')) + $rubric_changed_fields = Registry::get('rubric_changeds'); + else + $rubric_changed_fields = get_rubrics_changes(); + + if (! isset($AVE_Core) || $AVE_Core->curentdoc->Id != $document_id) + { + $rubric_id = get_document($document_id, 'rubric_id'); + + $cache_time = $rubric_changed_fields[$rubric_id]['rubric_changed_fields']; + } + else + { + $cache_time = $AVE_Core->curentdoc->rubric_changed_fields; + } + + if ($cache_time == 0) + $cache_time = -1; + + if (! isset($document_fields[$document_id])) + { + $document_fields[$document_id] = false; + + $where = "WHERE doc_field.document_id = '" . $document_id . "'"; + + $query = " + SELECT + doc.document_author_id, + doc_field.Id, + doc_field.document_id, + doc_field.rubric_field_id, + doc_field.field_value, + text_field.field_value AS field_value_more, + rub_field.rubric_id, + rub_field.rubric_field_alias, + rub_field.rubric_field_type, + rub_field.rubric_field_default, + rub_field.rubric_field_numeric, + rub_field.rubric_field_title, + rub_field.rubric_field_template, + rub_field.rubric_field_template_request + FROM + " . PREFIX . "_document_fields AS doc_field + JOIN + " . PREFIX . "_rubric_fields AS rub_field + ON doc_field.rubric_field_id = rub_field.Id + LEFT JOIN + " . PREFIX . "_document_fields_text AS text_field + ON (doc_field.rubric_field_id = text_field.rubric_field_id AND doc_field.document_id = text_field.document_id) + JOIN + " . PREFIX . "_documents AS doc + ON doc.Id = doc_field.document_id + " . $where . " + # DOC FIELDS = $document_id + "; + + $cache_id = (int)$document_id; + $cache_id = 'documents/' . (floor($cache_id / 1000)) . '/' . $cache_id; + + $cache_file = md5($query) . '.fields'; + + $cache_dir = BASE_DIR . '/tmp/cache/sql/' . (trim($cache_id) > '' + ? trim($cache_id) . '/' + : substr($cache_file, 0, 2) . '/' . substr($cache_file, 2, 2) . '/' . substr($cache_file, 4, 2) . '/'); + + // Наличие файла + if (file_exists($cache_dir . $cache_file)) + { + // Получаем время создания файла + $file_time = filemtime($cache_dir . $cache_file); + + // Сравниваем временные метки + if (! $cache_time || $cache_time > $file_time || $cache_time == 0) + unlink($cache_dir . $cache_file); + } + + $cache_time = (defined('CACHE_DOC_FILE') && CACHE_DOC_FILE) + ? -1 + : 0; + + $sql = $AVE_DB->Query($query, $cache_time, 'fld_' . $document_id, true, '.fields'); + + // Вдруг памяти мало!!!! + if (memory_panic() && (count($document_fields) > 3)) + $document_fields = []; + + while ($row = $sql->FetchAssocArray()) + { + $row['tpl_req_empty'] = (trim($row['rubric_field_template_request']) == ''); + $row['tpl_field_empty'] = (trim($row['rubric_field_template']) == ''); + + $row['field_value'] = (string)$row['field_value'] . (string)$row['field_value_more']; + + if ($values) + $row['field_value'] = (isset($values[$row['rubric_field_id']]) + ? $values[$row['rubric_field_id']] + : $row['field_value']); + + if ($row['field_value'] === '') + { + $row['rubric_field_template_request'] = preg_replace('/\[tag:if_notempty](.*?)\[\/tag:if_notempty]/si', '', $row['rubric_field_template_request']); + $row['rubric_field_template_request'] = trim(str_replace(['[tag:if_empty]','[/tag:if_empty]'], '', $row['rubric_field_template_request'])); + + $row['rubric_field_template'] = preg_replace('/\[tag:if_notempty](.*?)\[\/tag:if_notempty]/si', '', $row['rubric_field_template']); + $row['rubric_field_template'] = trim(str_replace(['[tag:if_empty]','[/tag:if_empty]'], '', $row['rubric_field_template'])); + } + else + { + $row['rubric_field_template_request'] = preg_replace('/\[tag:if_empty](.*?)\[\/tag:if_empty]/si', '', $row['rubric_field_template_request']); + $row['rubric_field_template_request'] = trim(str_replace(['[tag:if_notempty]','[/tag:if_notempty]'], '', $row['rubric_field_template_request'])); + + $row['rubric_field_template'] = preg_replace('/\[tag:if_empty](.*?)\[\/tag:if_empty]/si', '', $row['rubric_field_template']); + $row['rubric_field_template'] = trim(str_replace(['[tag:if_notempty]','[/tag:if_notempty]'], '', $row['rubric_field_template'])); + } + + + //$document_fields[$row['document_id']][$row['rubric_field_id']] = $row; + $document_fields[$row['document_id']][$row['rubric_field_alias']] = $row['rubric_field_id']; + + + $document_fields[$document_id][$row['rubric_field_id']] = [ + 'Id' => $row['Id'], + 'document_id' => $row['document_id'], + 'document_author_id' => $row['document_author_id'], + 'rubric_field_id' => $row['rubric_field_id'], + 'field_value' => $row['field_value'], + 'field_value_more' => $row['field_value_more'], + 'tpl_req_empty' => $row['tpl_req_empty'], + 'tpl_field_empty' => $row['tpl_field_empty'], + 'rubric_id' => $row['rubric_id'], + 'rubric_field_alias' => $row['rubric_field_alias'], + 'rubric_field_type' => $row['rubric_field_type'], + 'rubric_field_default' => $row['rubric_field_default'], + 'rubric_field_numeric' => $row['rubric_field_numeric'], + 'rubric_field_title' => $row['rubric_field_title'], + 'rubric_field_template' => $row['rubric_field_template'], + 'rubric_field_template_request' => $row['rubric_field_template_request'], + ]; + + $fields_param[$row['rubric_field_id']] = [ + 'rubric_id' => $row['rubric_id'], + 'rubric_field_alias' => $row['rubric_field_alias'], + 'rubric_field_type' => $row['rubric_field_type'], + 'rubric_field_default' => $row['rubric_field_default'], + 'rubric_field_numeric' => $row['rubric_field_numeric'], + 'rubric_field_title' => $row['rubric_field_title'], + ]; + } + } + + Registry::set('fields', $document_fields); + + if (! Registry::stored('fields_param', $row['rubric_field_id'])) + Registry::set('fields_param', $fields_param); + + unset ($document_fields, $rubric_changed_fields, $fields_param); + + return Registry::get('fields', $document_id); + } + + + /** + * Возвращает содержимое поля документа по номеру + * + * @param int $field_id ([tag:fld:X]) - номер поля + * @param int $doc_id + * @param int $parametr ([tag:parametr:X]) - часть поля + * + * @return string + */ + function get_field ($field_id, $doc_id = null, $parametr = null) + { + global $req_item_id; + + //-- Если не передан $doc_id, то проверяем реквест + if (! $doc_id && $req_item_id) + $doc_id = $req_item_id; + //-- Или берём для текущего дока + elseif (! $doc_id && $_REQUEST['id'] > 0) + $doc_id = $_REQUEST['id']; + //-- Возвращаем FALSE, если не число + elseif (! is_numeric($doc_id)) + return false; + + //-- Забираем из базы массив полей + $field = get_document_field ($doc_id, $field_id); + + //-- Возвращаем нужную часть поля + if ($parametr !== null) + { + $field = explode("|", $field); + $field = array_values(array_diff($field, array(''))); + $field = $field[$parametr]; + } + + return $field; + } + + + /** + * Возвращает содержимое поля документа по номеру + * + * @param int $field_id ([tag:fld:X]) - номер поля + * @param int $doc_id + * @param int $parametr ([tag:parametr:X]) - часть поля + * + * @return mixed + */ + function get_true_field ($field_id, $doc_id = null, $parametr = null) + { + global $req_item_id, $AVE_DB; + + //-- Если не передан $doc_id, то проверяем реквест + if (! $doc_id && $req_item_id) + $doc_id = $req_item_id; + //-- Или берём для текущего дока + elseif (! $doc_id && $_REQUEST['id'] > 0) + $doc_id = $_REQUEST['id']; + //-- Возвращаем FALSE, если не число + elseif (! is_numeric($doc_id)) + return false; + + //-- Забираем поле из базы + $sql = " + SELECT + doc_field.field_value, + text_field.field_value AS field_value_more + FROM + " . PREFIX . "_document_fields AS doc_field + LEFT JOIN + " . PREFIX . "_document_fields_text AS text_field + ON (doc_field.rubric_field_id = text_field.rubric_field_id AND doc_field.document_id = text_field.document_id) + WHERE + doc_field.document_id = '" . $doc_id . "' + AND + doc_field.rubric_field_id = '" . $field_id . "' + "; + + $query = $AVE_DB->Query($sql)->FetchRow(); + + $field = (string)$query->field_value . (string)$query->field_value_more; + + unset ($sql, $query); + + //-- Возвращаем нужную часть поля + if ($parametr !== null) + { + $field = explode("|", $field); + $field = array_values(array_diff($field, array(''))); + $field = $field[$parametr]; + } + + return $field; + } + + + /** + * Возвращает элемент сериализованного поля по номеру и ключу + * + * @param int $field_id ([tag:fld:X]) - номер поля + * @param int $item_id - номер элемента + * @param int $doc_id ([tag:docid]) - id документа + * @param int $parametr ([tag:parametr:X]) - номер параметра элемента + * @return string + */ + function get_element ($field_id, $item_id = 0, $parametr = null, $doc_id = null) + { + global $req_item_id; + + //-- Если не передан $doc_id, то проверяем реквест + if (! $doc_id && $req_item_id) + $doc_id = $req_item_id; + //-- Или берём для текущего дока + elseif (! $doc_id && $_REQUEST['id'] > 0) + $doc_id = $_REQUEST['id']; + //-- Возвращаем FALSE, если не число + elseif (! is_numeric($doc_id)) + return false; + + //-- Забираем из базы поле + $field = get_field($field_id, $doc_id); + $field = unserialize($field); + + // возвращаем нужную часть поля + if ($parametr !== null) + { + $field = $field[$item_id]; + $field = explode("|", $field); + $field = $field[$parametr]; + } + else + { + $field = $field[$item_id]; + $field = explode("|", $field); + $field = $field[0]; + } + + return $field; + } + + + /** + * Возвращает сериализованны(й|е) элемент(ы) поля + * + * @param int $field_id ([tag:fld:X]) - номер поля + * @param int $item_id - номер элемента + * @param int $doc_id ([tag:docid]) - id документа + * @return mixed + */ + function get_serialize ($field_id, $item_id = null, $doc_id = null) + { + global $req_item_id; + + //-- Если не передан $doc_id, то проверяем реквест + if (! $doc_id && $req_item_id) + $doc_id = $req_item_id; + //-- Или берём для текущего дока + elseif (! $doc_id && $_REQUEST['id'] > 0) + $doc_id = $_REQUEST['id']; + //-- Возвращаем FALSE, если не число + elseif (! is_numeric($doc_id)) + return false; + + //-- Забираем поле + $field = get_field($field_id, $doc_id); + $field = unserialize($field); + + $field_data = array(); + + //-- Если получили массив из данных, собираем новый + if (! empty($field)) + foreach ($field AS $k => $v) + $field_data[$k] = explode('|', $v); + //-- Иначе возвращаем FALSE + else + return false; + + unset($field); + + //-- Если пришло $item_id + if (is_numeric($item_id)) + return $field_data[$item_id]; + else + return $field_data; + } + + + /** + * Возвращает элемент сериализованного поля по номеру и ключу, через тег [tag:fld:XXX][XXX][XXX] + * + * @return string + */ + function get_field_element () + { + $param = func_get_args(); + + // Field ID + $param_1 = isset($param[0]) ? $param[0] : null; + // Item ID + $param_2 = isset($param[1]) ? $param[1] : null; + // Param ID + $param_3 = isset($param[2]) ? $param[2] : null; + // Document ID + $param_4 = isset($param[3]) ? $param[3] : null; + + $return = get_element($param_1, $param_2, $param_3, $param_4); + + return $return; + } + + + /** + * Возвращает наименование поля документа по номеру + * + * @param int $field_id ([tag:fld:X]) - номер поля + * @param int $doc_id + * + * @return string + */ + function get_field_name ($field_id, $doc_id = null) + { + global $req_item_id; + + //-- Если не передан $doc_id, то проверяем реквест + if (! $doc_id && $req_item_id) + $doc_id = $req_item_id; + //-- Или берём для текущего дока + elseif (! $doc_id && $_REQUEST['id'] > 0) + $doc_id = $_REQUEST['id']; + //-- Возвращаем FALSE, если не число + elseif (! is_numeric($doc_id)) + return false; + + $document_fields = get_document_fields($doc_id); + + if (empty($document_fields[$field_id])) + return false; + + $field_name = $document_fields[$field_id]['rubric_field_title']; + + return $field_name; + } + + + /** + * Возвращает параметры поля + * + * @param int $field_id ([tag:fld:X]) - номер поля + * + * @return void + */ + function _get_field_params ($field_id) + { + global $AVE_DB; + + if (Registry::stored('fields_params', $field_id)) + return Registry::get('fields_params', $field_id); + + $fields_param = Registry::get('fields_params'); + + $query = " + SELECT + rubric_id, + rubric_field_alias, + rubric_field_type, + rubric_field_default, + rubric_field_numeric, + rubric_field_title + FROM + " . PREFIX . "_rubric_fields + WHERE + Id = '" . $field_id . "' + LIMIT 0,1 + # FIELDS PARAMS = $field_id + "; + + $row = $AVE_DB->Query($query)->FetchAssocArray(); + + $fields_param[$field_id] = [ + 'rubric_id' => $row['rubric_id'], + 'rubric_field_alias' => $row['rubric_field_alias'], + 'rubric_field_type' => $row['rubric_field_type'], + 'rubric_field_default' => $row['rubric_field_default'], + 'rubric_field_numeric' => $row['rubric_field_numeric'], + 'rubric_field_title' => $row['rubric_field_title'], + ]; + + Registry::set('fields_params', $fields_param); + + unset ($query, $row, $fields_param); + } + + + /** + * Возвращает поле документа по номеру + * + * @param int $field_id ([tag:fld:X]) - номер поля + * @param int $doc_id + * @param int $parametr знчение + * + * @return mixed + */ + function get_full_field ($field_id, $doc_id = null, $parametr = null) + { + global $req_item_id, $AVE_DB; + + //-- Если не передан $doc_id, то проверяем реквест + if (! $doc_id && $req_item_id) + $doc_id = $req_item_id; + //-- Или берём для текущего дока + elseif (! $doc_id && $_REQUEST['id'] > 0) + $doc_id = $_REQUEST['id']; + //-- Возвращаем FALSE, если не число + elseif (! is_numeric($doc_id)) + return false; + + //-- Забираем поле из базы + $sql = " + SELECT + doc.document_author_id, + doc_field.document_id, + doc_field.rubric_field_id, + doc_field.field_value, + doc_field.field_number_value, + text_field.field_value AS field_value_more, + rub_field.rubric_field_alias, + rub_field.rubric_field_type, + rub_field.rubric_field_default, + rub_field.rubric_field_title, + rub_field.rubric_field_template, + rub_field.rubric_field_template_request + FROM + " . PREFIX . "_document_fields AS doc_field + JOIN + " . PREFIX . "_rubric_fields AS rub_field + ON doc_field.rubric_field_id = rub_field.Id + LEFT JOIN + " . PREFIX . "_document_fields_text AS text_field + ON (doc_field.rubric_field_id = text_field.rubric_field_id AND doc_field.document_id = text_field.document_id) + JOIN + " . PREFIX . "_documents AS doc + ON doc.Id = doc_field.document_id + WHERE + doc_field.document_id = '" . $doc_id . "' + AND + doc_field.rubric_field_id = '" . $field_id . "' + "; + + $field = $AVE_DB->Query($sql)->FetchRow(); + + $field->field_value = (string)$field->field_value . (string)$field->field_value_more; + + unset ($sql); + + //-- Возвращаем нужную часть + if ($parametr !== null) + return $field[$parametr]; + + return $field; + } +?> \ No newline at end of file diff --git a/functions/func.helpers.php b/functions/func.helpers.php new file mode 100644 index 0000000..66a78de --- /dev/null +++ b/functions/func.helpers.php @@ -0,0 +1,873 @@ + c" + * - корректно обрабатывается "грязный" html, когда в значениях атрибутов тагов могут встречаться символы < > + * - корректно обрабатывается разбитый html + * - вырезаются комментарии, скрипты, стили, PHP, Perl, ASP код, MS Word таги, CDATA + * - автоматически форматируется текст, если он содержит html код + * - защита от подделок типа: "<script>alert('hi')script>" + * + * @param string $s + * @param array $allowable_tags Массив тагов, которые не будут вырезаны + * Пример: 'b' -- таг останется с атрибутами, '' -- таг останется без атрибутов + * @param bool $is_format_spaces Форматировать пробелы и переносы строк? + * Вид текста на выходе (plain) максимально приближеется виду текста в браузере на входе. + * Другими словами, грамотно преобразует text/html в text/plain. + * Текст форматируется только в том случае, если были вырезаны какие-либо таги. + * @param array $pair_tags массив имён парных тагов, которые будут удалены вместе с содержимым + * см. значения по умолчанию + * @param array $para_tags массив имён парных тагов, которые будут восприниматься как параграфы (если $is_format_spaces = true) + * см. значения по умолчанию + * @return string + */ + include (BASE_DIR . '/lib/StripTagsSmart/strip_tags_smart.php'); + + + /** + * Вычисление разницы между двумя метками времени + * + * @param string $a начальная метка + * @param string $b конечная метка + * @return int время между метками + */ + if (! function_exists('microtime_diff')) + { + function microtime_diff($a, $b) + { + list($a_dec, $a_sec) = explode(' ', $a); + list($b_dec, $b_sec) = explode(' ', $b); + + return $b_sec - $a_sec + $b_dec - $a_dec; + } + } + + + /** + * Функция меняет кодировку файла + * + * @param string $path + * @param string $to + */ + if (! function_exists('file_encoding')) + { + function file_encoding($path, $to='utf') + { + $f = file_get_contents($path); + $f = mb_convert_encoding($f,$to == 'utf' ? 'UTF-8' : 'CP1251', $to == 'utf' ? 'CP1251' : 'UTF-8'); + file_put_contents($path, $f); + } + } + + + /** + * Replace array_combine() + * + * @category PHP + * @package PHP_Compat + * @license LGPL - http://www.gnu.org/licenses/lgpl.html + * @copyright 2004-2007 Aidan Lister , Arpad Ray + * @link http://php.net/function.array_combine + * @author Aidan Lister + * @version $Revision: 1.23 $ + * @since PHP 5 + * @require PHP 4.0.0 (user_error) + * + * @param $keys + * @param $values + * + * @return array|bool + */ + function php_compat_array_combine($keys, $values) + { + if (! is_array($keys)) + { + user_error('array_combine() expects parameter 1 to be array, ' . gettype($keys) . ' given', E_USER_WARNING); + return false; + } + + if (! is_array($values)) + { + user_error('array_combine() expects parameter 2 to be array, ' . gettype($values) . ' given', E_USER_WARNING); + return false; + } + + $key_count = count($keys); + $value_count = count($values); + + if ($key_count !== $value_count) + { + user_error('array_combine() Both parameters should have equal number of elements', E_USER_WARNING); + return false; + } + + if ($key_count === 0 || $value_count === 0) + { + user_error('array_combine() Both parameters should have number of elements at least 0', E_USER_WARNING); + return false; + } + + $keys = array_values($keys); + $values = array_values($values); + + $combined = array(); + + for ($i = 0; $i < $key_count; $i++) + { + $combined[$keys[$i]] = $values[$i]; + } + + return $combined; + } + + // Define + if (! function_exists('array_combine')) + { + function array_combine($keys, $values) + { + return php_compat_array_combine($keys, $values); + } + } + + + /** + * post() + * + * @param mixed $var + * @return string + */ + if (! function_exists('post')) + { + function post($var) + { + return (isset($_POST[$var])) + ? $_POST[$var] + : ''; + } + } + + + /** + * get() + * + * @param mixed $var + * @return string + */ + if (! function_exists('get')) + { + function get($var) + { + return (isset($_GET[$var])) + ? $_GET[$var] + : ''; + } + } + + + /** + * sanitize() + * + * @param mixed $string + * @param bool $trim + * @param bool $int + * @param bool $str + * @return mixed|string + */ + if (! function_exists('sanitize')) + { + function sanitize($string, $trim = false, $int = false, $str = false) + { + $string = filter_var($string, FILTER_SANITIZE_STRING); + $string = trim($string); + $string = stripslashes($string); + $string = strip_tags($string); + $string = str_replace( + array( + '‘', + '’', + '“', + '”' + ), + array( + "'", + "'", + '"', + '"' + ), + $string + ); + + if ($trim) + $string = substr($string, 0, $trim); + if ($int) + $string = preg_replace("/[^0-9\s]/", "", $string); + if ($str) + $string = preg_replace("/[^a-zA-Z\s]/", "", $string); + + return $string; + } + } + + + /** + * cleanSanitize() + * + * @param mixed $string + * @param bool $trim + * @param string $end_char + * @return mixed|string + */ + if (! function_exists('cleanSanitize')) + { + function cleanSanitize($string, $trim = false, $end_char = '…') + { + $string = cleanOut($string); + $string = filter_var($string, FILTER_SANITIZE_STRING); + $string = trim($string); + $string = stripslashes($string); + $string = strip_tags($string); + $string = str_replace(array( + '‘', + '’', + '“', + '”'), array( + "'", + "'", + '"', + '"'), $string); + + if ($trim) { + if (strlen($string) < $trim) + { + return $string; + } + + $string = preg_replace("/\s+/", ' ', str_replace(array( + "\r\n", + "\r", + "\n"), ' ', $string)); + + if (strlen($string) <= $trim) + { + return $string; + } + + $out = ""; + + foreach (explode(' ', trim($string)) as $val) + { + $out .= $val . ' '; + + if (strlen($out) >= $trim) + { + $out = trim($out); + return (strlen($out) == strlen($string)) ? $out : $out . $end_char; + } + } + } + + return $string; + } + } + + + /** + * Функция обрезает текст до заданной величины + * + * @param mixed $string + * @param int $length Длинна + * @param string $etc Окончание + * @param bool $break_words Дробить слова на символы + * @param bool $middle Вырезает середину, оставляет начало + разделитель + конец + * @return mixed|string + */ + if (! function_exists('trancate')) + { + function truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false) + { + if ($length == 0) + return ''; + + if (mb_strlen($string) > $length) + { + $length -= min($length, mb_strlen($etc)); + + if (! $break_words && ! $middle) + { + $string = preg_replace('/\s+?(\S+)?$/', '', mb_substr($string, 0, $length + 1)); + } + + if (! $middle) + { + return mb_substr($string, 0, $length) . $etc; + } + else + { + return mb_substr($string, 0, $length / 2) . $etc . mb_substr($string, - $length / 2); + } + } + else + { + return $string; + } + } + } + + + /** + * Функция обрезает текст до заданной величины, не бьет слова + * + * @param mixed $str + * @param int $n Длинна + * @param mixed $end_char Окончание + * @return mixed|string + */ + if (! function_exists('truncate_text')) + { + function truncate_text($str, $n = 100, $end_char = '…') + { + if (strlen($str) < $n) + { + return $str; + } + + $str = preg_replace("/\s+/", ' ', str_replace(array( + "\r\n", + "\r", + "\n"), ' ', $str)); + + if (strlen($str) <= $n) + { + return $str; + } + + $out = ""; + foreach (explode(' ', trim($str)) as $val) + { + $out .= $val . ' '; + + if (strlen($out) >= $n) + { + $out = trim($out); + return (strlen($out) == strlen($str)) + ? $out + : $out . $end_char; + } + } + return $str; + } + } + + + /** + * Swap named HTML entities with numeric entities. + * + * @see http://www.lazycat.org/software/html_entity_decode_full.phps + * + * @param $matches + * @param bool $destroy + * + * @return mixed|string + */ + function convert_entity($matches, $destroy = true) + { + $table = array( + 'Aacute' => 'Á', 'aacute' => 'á', 'Acirc' => 'Â', 'acirc' => 'â', 'acute' => '´', + 'AElig' => 'Æ', 'aelig' => 'æ', 'Agrave' => 'À', 'agrave' => 'à', 'alefsym' => 'ℵ', + 'Alpha' => 'Α', 'alpha' => 'α', 'amp' => '&', 'and' => '∧', 'ang' => '∠', + 'Aring' => 'Å', 'aring' => 'å', 'asymp' => '≈', 'Atilde' => 'Ã', 'atilde' => 'ã', + 'Auml' => 'Ä', 'auml' => 'ä', 'bdquo' => '„', 'Beta' => 'Β', 'beta' => 'β', + 'brvbar' => '¦', 'bull' => '•', 'cap' => '∩', 'Ccedil' => 'Ç', 'ccedil' => 'ç', + 'cedil' => '¸', 'cent' => '¢', 'Chi' => 'Χ', 'chi' => 'χ', 'circ' => 'ˆ', + 'clubs' => '♣', 'cong' => '≅', 'copy' => '©', 'crarr' => '↵', 'cup' => '∪', + 'curren' => '¤', 'dagger' => '†', 'Dagger' => '‡', 'darr' => '↓', 'dArr' => '⇓', + 'deg' => '°', 'Delta' => 'Δ', 'delta' => 'δ', 'diams' => '♦', 'divide' => '÷', + 'Eacute' => 'É', 'eacute' => 'é', 'Ecirc' => 'Ê', 'ecirc' => 'ê', 'Egrave' => 'È', + 'egrave' => 'è', 'empty' => '∅', 'emsp' => ' ', 'ensp' => ' ', 'Epsilon' => 'Ε', + 'epsilon' => 'ε', 'equiv' => '≡', 'Eta' => 'Η', 'eta' => 'η', 'ETH' => 'Ð', + 'eth' => 'ð', 'Euml' => 'Ë', 'euml' => 'ë', 'euro' => '€', 'exist' => '∃', + 'fnof' => 'ƒ', 'forall' => '∀', 'frac12' => '½', 'frac14' => '¼', 'frac34' => '¾', + 'frasl' => '⁄', 'Gamma' => 'Γ', 'gamma' => 'γ', 'ge' => '≥', 'gt' => '>', + 'harr' => '↔', 'hArr' => '⇔', 'hearts' => '♥', 'hellip' => '…', 'Iacute' => 'Í', + 'iacute' => 'í', 'Icirc' => 'Î', 'icirc' => 'î', 'iexcl' => '¡', 'Igrave' => 'Ì', + 'igrave' => 'ì', 'image' => 'ℑ', 'infin' => '∞', 'int' => '∫', 'Iota' => 'Ι', + 'iota' => 'ι', 'iquest' => '¿', 'isin' => '∈', 'Iuml' => 'Ï', 'iuml' => 'ï', + 'Kappa' => 'Κ', 'kappa' => 'κ', 'Lambda' => 'Λ', 'lambda' => 'λ', 'lang' => '〈', + 'laquo' => '«', 'larr' => '←', 'lArr' => '⇐', 'lceil' => '⌈', 'ldquo' => '“', + 'le' => '≤', 'lfloor' => '⌊', 'lowast' => '∗', 'loz' => '◊', 'lrm' => '‎', + 'lsaquo' => '‹', 'lsquo' => '‘', 'lt' => '<', 'macr' => '¯', 'mdash' => '—', + 'micro' => 'µ', 'middot' => '·', 'minus' => '−', 'Mu' => 'Μ', 'mu' => 'μ', + 'nabla' => '∇', 'nbsp' => ' ', 'ndash' => '–', 'ne' => '≠', 'ni' => '∋', + 'not' => '¬', 'notin' => '∉', 'nsub' => '⊄', 'Ntilde' => 'Ñ', 'ntilde' => 'ñ', + 'Nu' => 'Ν', 'nu' => 'ν', 'Oacute' => 'Ó', 'oacute' => 'ó', 'Ocirc' => 'Ô', + 'ocirc' => 'ô', 'OElig' => 'Œ', 'oelig' => 'œ', 'Ograve' => 'Ò', 'ograve' => 'ò', + 'oline' => '‾', 'Omega' => 'Ω', 'omega' => 'ω', 'Omicron' => 'Ο', 'omicron' => 'ο', + 'oplus' => '⊕', 'or' => '∨', 'ordf' => 'ª', 'ordm' => 'º', 'Oslash' => 'Ø', + 'oslash' => 'ø', 'Otilde' => 'Õ', 'otilde' => 'õ', 'otimes' => '⊗', 'Ouml' => 'Ö', + 'ouml' => 'ö', 'para' => '¶', 'part' => '∂', 'permil' => '‰', 'perp' => '⊥', + 'Phi' => 'Φ', 'phi' => 'φ', 'Pi' => 'Π', 'pi' => 'π', 'piv' => 'ϖ', + 'plusmn' => '±', 'pound' => '£', 'prime' => '′', 'Prime' => '″', 'prod' => '∏', + 'prop' => '∝', 'Psi' => 'Ψ', 'psi' => 'ψ', 'quot' => '"', 'radic' => '√', + 'rang' => '〉', 'raquo' => '»', 'rarr' => '→', 'rArr' => '⇒', 'rceil' => '⌉', + 'rdquo' => '”', 'real' => 'ℜ', 'reg' => '®', 'rfloor' => '⌋', 'Rho' => 'Ρ', + 'rho' => 'ρ', 'rlm' => '‏', 'rsaquo' => '›', 'rsquo' => '’', 'sbquo' => '‚', + 'Scaron' => 'Š', 'scaron' => 'š', 'sdot' => '⋅', 'sect' => '§', 'shy' => '­', + 'Sigma' => 'Σ', 'sigma' => 'σ', 'sigmaf' => 'ς', 'sim' => '∼', 'spades' => '♠', + 'sub' => '⊂', 'sube' => '⊆', 'sum' => '∑', 'sup' => '⊃', 'sup1' => '¹', + 'sup2' => '²', 'sup3' => '³', 'supe' => '⊇', 'szlig' => 'ß', 'Tau' => 'Τ', + 'tau' => 'τ', 'there4' => '∴', 'Theta' => 'Θ', 'theta' => 'θ', 'thetasym' => 'ϑ', + 'thinsp' => ' ', 'THORN' => 'Þ', 'thorn' => 'þ', 'tilde' => '˜', 'times' => '×', + 'trade' => '™', 'Uacute' => 'Ú', 'uacute' => 'ú', 'uarr' => '↑', 'uArr' => '⇑', + 'Ucirc' => 'Û', 'ucirc' => 'û', 'Ugrave' => 'Ù', 'ugrave' => 'ù', 'uml' => '¨', + 'upsih' => 'ϒ', 'Upsilon' => 'Υ', 'upsilon' => 'υ', 'Uuml' => 'Ü', 'uuml' => 'ü', + 'weierp' => '℘', 'Xi' => 'Ξ', 'xi' => 'ξ', 'Yacute' => 'Ý', 'yacute' => 'ý', + 'yen' => '¥', 'Yuml' => 'Ÿ', 'yuml' => 'ÿ', 'Zeta' => 'Ζ', 'zeta' => 'ζ', + 'zwj' => '‍', 'zwnj' => '‌' + ); + + if (isset($table[$matches[1]])) + return $table[$matches[1]]; + else + return $destroy + ? '' + : $matches[0]; + } + + + /** + * stripTags() + * + * @param mixed $start + * @param mixed $end + * @param mixed $string + * @return string + */ + if (! function_exists('stripTags')) + { + function stripTags($start, $end, $string) + { + $string = stristr($string, $start); + $doend = stristr($string, $end); + return substr($string, strlen($start), -strlen($doend)); + } + } + + + /** + * stripExt() + * + * @param mixed $filename + * @return string + */ + if (! function_exists('stripExt')) + { + function stripExt($filename) + { + if (strpos($filename, ".") === false) + return ucwords($filename); + else + return substr(ucwords($filename), 0, strrpos($filename, ".")); + } + } + + + /** + * Очиста текста + * + * @param mixed $text + * @return string + */ + if (! function_exists('cleanOut')) + { + function cleanOut($text) + { + $text = strtr($text, array( + '\r\n' => "", + '\r' => "", + '\n' => "")); + $text = html_entity_decode($text, ENT_QUOTES, 'UTF-8'); + $text = str_replace('
      ', '
      ', $text); + return stripslashes($text); + } + } + + + /** + * Сравнение двух чисел + * + * @param mixed $float1 + * @param mixed $float2 + * @param string $operator + * @return bool + */ + if (! function_exists('compareFloatNumbers')) + { + function compareFloatNumbers($float1, $float2, $operator='=') + { + // Check numbers to 5 digits of precision + $epsilon = 0.00001; + + $float1 = (float)$float1; + $float2 = (float)$float2; + + switch ($operator) + { + // equal + case "=": + case "eq": + if (abs($float1 - $float2) < $epsilon) { + return true; + } + break; + // less than + case "<": + case "lt": + if (abs($float1 - $float2) < $epsilon) { + return false; + } else { + if ($float1 < $float2) { + return true; + } + } + break; + // less than or equal + case "<=": + case "lte": + if (compareFloatNumbers($float1, $float2, '<') || compareFloatNumbers($float1, $float2, '=')) { + return true; + } + break; + // greater than + case ">": + case "gt": + if (abs($float1 - $float2) < $epsilon) { + return false; + } else { + if ($float1 > $float2) { + return true; + } + } + break; + // greater than or equal + case ">=": + case "gte": + if (compareFloatNumbers($float1, $float2, '>') || compareFloatNumbers($float1, $float2, '=')) { + return true; + } + break; + + case "<>": + case "!=": + case "ne": + if (abs($float1 - $float2) > $epsilon) { + return true; + } + break; + default: + die("Unknown operator '".$operator."' in compareFloatNumbers()"); + } + + return false; + } + } + + + /** + * Поиск значения по массиву + * + * @param $array + * @param $key + * @param bool $value + * @return bool + */ + if (!function_exists('searchforValue')) + { + function searchforValue($array, $key, $value) + { + if($array) + { + foreach ($array as $val) + { + if ($val->$key == $value) + return true; + } + } + + return false; + } + } + + + /** + * Поиск в массиве + * + * @param mixed $array + * @param mixed $val1 + * @param mixed $val2 + * @return array|int + */ + if (! function_exists('findInArray')) + { + function findInArray($array, $val1, $val2) + { + if ($array) + { + $result = array(); + + foreach ($array as $val) + { + if ($val->$val1 == $val2) + $result[] = $val; + } + + return ($result) + ? $result + : 0; + } + + return 0; + } + } + + + /** + * Скачать файл + * + * @param $fileLocation + * @param $fileName + * @param int $maxSpeed + * @return bool + */ + if (! function_exists('downloadFile')) + { + function downloadFile($fileLocation, $fileName, $maxSpeed = 5120) + { + if (connection_status() != 0) + return (false); + + $extension = strtolower(substr($fileName, strrpos($fileName, '.') + 1)); + + /* List of File Types */ + $fileTypes['swf'] = 'application/x-shockwave-flash'; + $fileTypes['pdf'] = 'application/pdf'; + $fileTypes['exe'] = 'application/octet-stream'; + $fileTypes['zip'] = 'application/zip'; + $fileTypes['doc'] = 'application/msword'; + $fileTypes['xls'] = 'application/vnd.ms-excel'; + $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; + $fileTypes['gif'] = 'image/gif'; + $fileTypes['png'] = 'image/png'; + $fileTypes['webp'] = 'image/webp'; + $fileTypes['jpeg'] = 'image/jpg'; + $fileTypes['jpg'] = 'image/jpg'; + $fileTypes['rar'] = 'application/rar'; + + $fileTypes['ra'] = 'audio/x-pn-realaudio'; + $fileTypes['ram'] = 'audio/x-pn-realaudio'; + $fileTypes['ogg'] = 'audio/x-pn-realaudio'; + + $fileTypes['wav'] = 'video/x-msvideo'; + $fileTypes['wmv'] = 'video/x-msvideo'; + $fileTypes['avi'] = 'video/x-msvideo'; + $fileTypes['asf'] = 'video/x-msvideo'; + $fileTypes['divx'] = 'video/x-msvideo'; + + $fileTypes['mp3'] = 'audio/mpeg'; + $fileTypes['mp4'] = 'audio/mpeg'; + $fileTypes['mpeg'] = 'video/mpeg'; + $fileTypes['mpg'] = 'video/mpeg'; + $fileTypes['mpe'] = 'video/mpeg'; + $fileTypes['mov'] = 'video/quicktime'; + $fileTypes['swf'] = 'video/quicktime'; + $fileTypes['3gp'] = 'video/quicktime'; + $fileTypes['m4a'] = 'video/quicktime'; + $fileTypes['aac'] = 'video/quicktime'; + $fileTypes['m3u'] = 'video/quicktime'; + + $contentType = $fileTypes[$extension]; + + header("Cache-Control: public"); + header("Content-Transfer-Encoding: binary\n"); + header('Content-Type: $contentType'); + + $contentDisposition = 'attachment'; + + if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) + { + $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); + header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); + } + else + { + header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); + } + + header("Accept-Ranges: bytes"); + + $range = 0; + $size = filesize($fileLocation); + + if (isset($_SERVER['HTTP_RANGE'])) + { + list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); + str_replace($range, "-", $range); + $size2 = $size - 1; + $new_length = $size - $range; + header("HTTP/1.1 206 Partial Content"); + header("Content-Length: $new_length"); + header("Content-Range: bytes $range$size2/$size"); + } + else + { + $size2 = $size - 1; + header("Content-Range: bytes 0-$size2/$size"); + header("Content-Length: " . $size); + } + + if ($size == 0) + die('Zero byte file! Aborting download'); + + $fp = fopen("$fileLocation", "rb"); + + fseek($fp, $range); + + while (! feof($fp) and (connection_status() == 0)) + { + set_time_limit(0); + print (fread($fp, 1024 * $maxSpeed)); + flush(); + ob_flush(); + sleep(1); + } + + fclose($fp); + + exit; + + //return ((connection_status() == 0) and !connection_aborted()); + } + } + + + /** + * Конвертируем hex color в decimal color + * @param string $hexcolor Значение цвета в HEX. Example: #A9B7D3 + * @return array|bool + */ + if (! function_exists('color_h2d')) + { + function color_h2d($hexcolor) + { + if(mb_strlen($hexcolor) != 7 || mb_strpos($hexcolor, "#") === false) + return false; + + return array( "r" => hexdec(mb_substr($hexcolor, 1, 2)), + "g" => hexdec(mb_substr($hexcolor, 3, 2)), + "b" => hexdec(mb_substr($hexcolor, 5, 2))); + } + } +?> \ No newline at end of file diff --git a/functions/func.hidden.php b/functions/func.hidden.php new file mode 100644 index 0000000..17820fe --- /dev/null +++ b/functions/func.hidden.php @@ -0,0 +1,49 @@ + 0) + { + for ($i=0; $i <= $count_matches; $i++) + { + + $hidden_text = substr(@$matches[$i][3], 1); + + if ($hidden_text == "") + $hidden_text = trim(get_settings('hidden_text')); + + $data = preg_replace('/\[tag:hide:(\d+,)*'. UGROUP .'(,\d+)*(:.*?)?].*?\[\/tag:hide]/s', $hidden_text, $data, 1); + } + } + + $data = preg_replace('/\[tag:hide:\d+(,\d+)*.*?](.*?)\[\/tag:hide]/s', '\\2', $data); + + return $data; + } +?> \ No newline at end of file diff --git a/functions/func.locale.php b/functions/func.locale.php new file mode 100644 index 0000000..a76ee7f --- /dev/null +++ b/functions/func.locale.php @@ -0,0 +1,851 @@ + 'A', + 'Б' => 'B', + 'В' => 'V', + 'Г' => 'G', + 'Д' => 'D', + 'Е' => 'E', + 'Ё' => 'YO', + 'Ж' => 'ZH', + 'З' => 'Z', + 'И' => 'I', + 'Й' => 'J', + 'К' => 'K', + 'Л' => 'L', + 'М' => 'M', + 'Н' => 'N', + 'О' => 'O', + 'П' => 'P', + 'Р' => 'R', + 'С' => 'S', + 'Т' => 'T', + 'У' => 'U', + 'Ф' => 'F', + 'Х' => 'H', + 'Ц' => 'C', + 'Ч' => 'CH', + 'Ш' => 'SH', + 'Щ' => 'CSH', + 'Ь' => '', + 'Ы' => 'Y', + 'Ъ' => '', + 'Э' => 'E', + 'Ю' => 'YU', + 'Я' => 'YA', + //-- Строчные + 'а' => 'a', + 'б' => 'b', + 'в' => 'v', + 'г' => 'g', + 'д' => 'd', + 'е' => 'e', + 'ё' => 'yo', + 'ж' => 'zh', + 'з' => 'z', + 'и' => 'i', + 'й' => 'j', + 'к' => 'k', + 'л' => 'l', + 'м' => 'm', + 'н' => 'n', + 'о' => 'o', + 'п' => 'p', + 'р' => 'r', + 'с' => 's', + 'т' => 't', + 'у' => 'u', + 'ф' => 'f', + 'х' => 'h', + 'ц' => 'c', + 'ч' => 'ch', + 'ш' => 'sh', + 'щ' => 'csh', + 'ь' => '', + 'ы' => 'y', + 'ъ' => '', + 'э' => 'e', + 'ю' => 'yu', + 'я' => 'ya', + ); + break; + + //болгарский + case 'bg': + $table = array( + //-- Заглавные + 'А' => 'A', + 'Б' => 'B', + 'В' => 'V', + 'Г' => 'G', + 'Д' => 'D', + 'Е' => 'E', + 'Ё' => 'YO', + 'Ж' => 'ZH', + 'З' => 'Z', + 'И' => 'I', + 'Й' => 'J', + 'К' => 'K', + 'Л' => 'L', + 'М' => 'M', + 'Н' => 'N', + 'О' => 'O', + 'П' => 'P', + 'Р' => 'R', + 'С' => 'S', + 'Т' => 'T', + 'У' => 'U', + 'Ф' => 'F', + 'Х' => 'H', + 'Ц' => 'C', + 'Ч' => 'CH', + 'Ш' => 'SH', + 'Щ' => 'SHT', + 'Ь' => 'Y', + 'Ы' => 'Y', + 'Ъ' => 'A', + 'Э' => 'E', + 'Ю' => 'YU', + 'Я' => 'YA', + //-- Строчные + 'а' => 'a', + 'б' => 'b', + 'в' => 'v', + 'г' => 'g', + 'д' => 'd', + 'е' => 'e', + 'ё' => 'yo', + 'ж' => 'zh', + 'з' => 'z', + 'и' => 'i', + 'й' => 'j', + 'к' => 'k', + 'л' => 'l', + 'м' => 'm', + 'н' => 'n', + 'о' => 'o', + 'п' => 'p', + 'р' => 'r', + 'с' => 's', + 'т' => 't', + 'у' => 'u', + 'ф' => 'f', + 'х' => 'h', + 'ц' => 'c', + 'ч' => 'ch', + 'ш' => 'sh', + 'щ' => 'sht', + 'ь' => 'a', + 'ы' => 'y', + 'ъ' => 'a', + 'э' => 'e', + 'ю' => 'yu', + 'я' => 'ya', + ); + break; + + //-- українська мова: + case 'ua': + $table = array( + //-- Заглавные + 'А' => 'A', + 'Б' => 'B', + 'В' => 'V', + 'Г' => 'G', + 'Д' => 'D', + 'Е' => 'E', + 'Є' => 'IE', + 'Ж' => 'J', + 'З' => 'Z', + 'И' => 'Y', + 'І' => 'I', + 'Й' => 'I', + 'К' => 'K', + 'Л' => 'L', + 'М' => 'M', + 'Н' => 'N', + 'О' => 'O', + 'П' => 'P', + 'Р' => 'R', + 'С' => 'S', + 'Т' => 'T', + 'У' => 'U', + 'Ф' => 'F', + 'Х' => 'H', + 'Ц' => 'C', + 'Ч' => 'CH', + 'Ш' => 'SH', + 'Щ' => 'CSH', + 'Ь' => '', + 'Ю' => 'IU', + 'Я' => 'IA', + //-- Строчные + 'а' => 'a', + 'б' => 'b', + 'в' => 'v', + 'г' => 'g', + 'д' => 'd', + 'е' => 'e', + 'є' => 'ie', + 'ж' => 'j', + 'з' => 'z', + 'и' => 'y', + 'і' => 'i', + 'й' => 'i', + 'к' => 'k', + 'л' => 'l', + 'м' => 'm', + 'н' => 'n', + 'о' => 'o', + 'п' => 'p', + 'р' => 'r', + 'с' => 's', + 'т' => 't', + 'у' => 'u', + 'ф' => 'f', + 'х' => 'h', + 'ц' => 'c', + 'ч' => 'ch', + 'ш' => 'sh', + 'щ' => 'csh', + 'ь' => '', + 'ю' => 'iu', + 'я' => 'ia', + ); + break; + + case 'uk': + $table = array( + //-- Заглавные + 'А' => 'A', + 'Б' => 'B', + 'В' => 'V', + 'Г' => 'G', + 'Ґ' => 'G', + 'Д' => 'D', + 'Е' => 'E', + 'Є' => 'IE', + 'Ж' => 'J', + 'З' => 'Z', + 'И' => 'Y', + 'І' => 'I', + 'Й' => 'I', + 'К' => 'K', + 'Л' => 'L', + 'М' => 'M', + 'Н' => 'N', + 'О' => 'O', + 'П' => 'P', + 'Р' => 'R', + 'С' => 'S', + 'Т' => 'T', + 'У' => 'U', + 'Ф' => 'F', + 'Х' => 'H', + 'Ц' => 'C', + 'Ч' => 'CH', + 'Ш' => 'SH', + 'Щ' => 'CSH', + 'Ь' => '', + 'Ю' => 'IU', + 'Я' => 'IA', + //-- Строчные + 'а' => 'a', + 'б' => 'b', + 'в' => 'v', + 'г' => 'g', + 'ґ' => 'g', + 'д' => 'd', + 'е' => 'e', + 'є' => 'ie', + 'ж' => 'j', + 'з' => 'z', + 'и' => 'y', + 'і' => 'i', + 'й' => 'i', + 'к' => 'k', + 'л' => 'l', + 'м' => 'm', + 'н' => 'n', + 'о' => 'o', + 'п' => 'p', + 'р' => 'r', + 'с' => 's', + 'т' => 't', + 'у' => 'u', + 'ф' => 'f', + 'х' => 'h', + 'ц' => 'c', + 'ч' => 'ch', + 'ш' => 'sh', + 'щ' => 'csh', + 'ь' => '', + 'ю' => 'iu', + 'я' => 'ia', + ); + break; + + //-- polski język + case 'pl': + $table = array( + 'Ą' => 'ya', + 'ą' => 'ya', + 'Ć' => 'ya', + 'ć' => 'ya', + 'Ę' => 'ya', + 'ę' => 'ya', + 'Ł' => 'ya', + 'ł' => 'ya', + 'Ń' => 'ya', + 'ń' => 'ya', + 'Ó' => 'ya', + 'ó' => 'ya', + 'Ś' => 'ya', + 'ś' => 'ya', + 'Ź' => 'ya', + 'ź' => 'ya', + 'Ż' => 'ya', + 'ż' => 'ya', + ); + break; + } + + $string = str_replace(array_keys($table), array_values($table), $string); + + switch ($language) + { + default: + case 'ru': + $replace = array( + 'ье'=>'ye', + 'ъе'=>'ye', + 'ьи'=>'yi', + 'ъи'=>'yi', + 'ъо'=>'yo', + 'ьо'=>'yo', + 'ё'=>'yo', + 'ю'=>'yu', + 'я'=>'ya', + 'ж'=>'zh', + 'х'=>'kh', + 'ц'=>'ts', + 'ч'=>'ch', + 'ш'=>'sh', + 'щ'=>'shch', + 'ъ'=>'', + 'ь'=>'', + 'є'=>'ye' + ); + break; + + case 'bg': + $replace = array( + 'ье'=>'ye', + 'ъе'=>'ye', + 'ьи'=>'yi', + 'ъи'=>'yi', + 'ъо'=>'yo', + 'ьо'=>'yo', + 'ё'=>'yo', + 'ю'=>'yu', + 'я'=>'ya', + 'ж'=>'zh', + 'ц'=>'ts', + 'ч'=>'ch', + 'ш'=>'sh', + 'щ'=>'sht', + 'ъ'=>'a', + 'ь'=>'a' + ); + break; + } + + $string = strtr($string, $replace); + + switch ($language) + { + default: + case 'ru': + $search = 'абвгдезийклмнопрстуфыэі'; + $replace = 'abvgdeziyklmnoprstufyei'; + break; + + case 'ua': + $search = 'абвгґдеєжзиійїклмнопрстуфхцчшщьюя'; + $replace = 'abvggdeejzyiiklmnoprstufhccssua'; + break; + + case 'uk': + $search = 'абвгґдеєжзиійїклмнопрстуфхцчшщьюя'; + $replace = 'abvggdeejzyiiklmnoprstufhccssua'; + break; + + case 'bg': + $search = 'абвгдезийклмнопрстуфыэіъ'; + $replace = 'abvgdeziyklmnoprstufyeia'; + break; + } + + $string = strtr($string, $search, $replace); + + return trim($string, '-'); + } + + + /** + * Исправление форматирования даты + * Функцию можно использовать в шаблонах Smarty как модификатор + * + * @param string $string - дата отформатированная в соответствии с текущей локалью + * @param string $language - язык + * @return string + */ + function pretty_date($string, $language = '') + { + // пытаемся решить проблему для кодировки дат на лок. серверах + if (! mb_check_encoding($string, 'UTF-8')) + { + $string = iconv('Windows-1251', 'UTF-8', $string); + } + + if ($language == '') + { + $language = (defined('ACP') && ACP) + ? $_SESSION['admin_language'] + : $_SESSION['user_language']; + } + + $language = strtolower($language); + + switch ($language) + { + default: + case 'ru': + $pretty = array( + 'Январь' =>'января', 'Февраль' =>'февраля', 'Март' =>'марта', + 'Апрель' =>'апреля', 'Май' =>'мая', 'Июнь' =>'июня', + 'Июль' =>'июля', 'Август' =>'августа', 'Сентябрь'=>'сентября', + 'Октябрь' =>'октября', 'Ноябрь' =>'ноября', 'Декабрь' =>'декабря', + + 'воскресенье'=>'Воскресенье', 'понедельник'=>'Понедельник', 'вторник' =>'Вторник', + 'среда' =>'Среда', 'четверг' =>'Четверг', 'пятница' =>'Пятница', + 'суббота' =>'Суббота' + ); + break; + + case 'ua': + case 'uk': + $pretty = array( + 'Січень' =>'січня', 'Лютий' =>'лютого', 'Березень'=>'березня', + 'Квітень'=>'квітня', 'Травень' =>'травня', 'Червень' =>'червня', + 'Липень' =>'липня', 'Серпень' =>'серпня', 'Вересень'=>'вересня', + 'Жовтень'=>'жовтня', 'Листопад' =>'листопада', 'Грудень' =>'грудня', + + 'неділя' =>'Неділя', 'понеділок'=>'Понеділок', 'вівторок'=>'Вівторок', + 'середа' =>'Середа', 'четвер' =>'Четвер', 'п’ятниця'=>'П’ятниця', + 'субота' =>'Субота' + ); + break; + } + + return (isset($pretty) + ? strtr($string, $pretty) + : $string); + } + + + /** + * Функция перевода даты с en на ru + * + * @param string $data данные + * @return string + */ + function translate_date($data) + { + $language = (defined('ACP') && ACP) + ? $_SESSION['admin_language'] + : $_SESSION['user_language']; + + $language = strtolower($language); + + switch ($language) + { + default: + case 'ru': + $data = strtr($data, array( + 'January'=>'Января', + 'February'=>'Февраля', + 'March'=>'Марта', + 'April'=>'Апреля', + 'May'=>'Мая', + 'June'=>'Июня', + 'July'=>'Июля', + 'August'=>'Августа', + 'September'=>'Сентября', + 'October'=>'Октября', + 'November'=>'Ноября', + 'December'=>'Декабря', + + 'Jan'=>'Янв', + 'Feb'=>'Фев', + 'Mar'=>'Мрт', + 'Apr'=>'Апр', + 'May'=>'Май', + 'Jun'=>'Июн', + 'Jul'=>'Июл', + 'Aug'=>'Авг', + 'Sep'=>'Сен', + 'Oct'=>'Окт', + 'Nov'=>'Нбр', + 'Dec'=>'Дек', + + 'Monday'=>'Понедельник', + 'Tuesday'=>'Вторник', + 'Wednesday'=>'Среда', + 'Thursday'=>'Четверг', + 'Friday'=>'Пятница', + 'Saturday'=>'Суббота', + 'Sunday'=>'Воскресенье', + + 'Mon'=>'Пн', + 'Tue'=>'Вт', + 'Wed'=>'Ср', + 'Thu'=>'Чт', + 'Fri'=>'Пт', + 'Sat'=>'Сб', + 'Sun'=>'Вс' + )); + break; + + + case 'ua': + case 'uk': + $data = strtr($data, array( + 'January'=>'Січня', + 'February'=>'Лютого', + 'March'=>'Березня', + 'April'=>'Квітня', + 'May'=>'Травня', + 'June'=>'Червня', + 'July'=>'Липня', + 'August'=>'Серпня', + 'September'=>'Вересня', + 'October'=>'Жовтня', + 'November'=>'Листопада', + 'December'=>'Грудня', + + 'Jan'=>'Січ', + 'Feb'=>'Лют', + 'Mar'=>'Бер', + 'Apr'=>'Кві', + 'May'=>'Тра', + 'Jun'=>'Чер', + 'Jul'=>'Лип', + 'Aug'=>'Сер', + 'Sep'=>'Вер', + 'Oct'=>'Жов', + 'Nov'=>'Лис', + 'Dec'=>'Гру', + + 'Monday'=>'Понеділок', + 'Tuesday'=>'Вівторок', + 'Wednesday'=>'Середа', + 'Thursday'=>'Четвер', + 'Friday'=>'П’ятниця', + 'Saturday'=>'Субота', + 'Sunday'=>'Неділя', + + 'Mon'=>'Пн', + 'Tue'=>'Вт', + 'Wed'=>'Ср', + 'Thu'=>'Чт', + 'Fri'=>'Пт', + 'Sat'=>'Сб', + 'Sun'=>'Нд' + )); + break; + + case 'bg': + $data = strtr($data, array( + 'January'=>'Януари', + 'February'=>'Февруари', + 'March'=>'Март', + 'April'=>'Април', + 'May'=>'Май', + 'June'=>'Юни', + 'July'=>'Юли', + 'August'=>'Август', + 'September'=>'Септември', + 'October'=>'Октомври', + 'November'=>'Нември', + 'December'=>'Декември', + + 'Jan'=>'Яну', + 'Feb'=>'Фев', + 'Mar'=>'Мрт', + 'Apr'=>'Апр', + 'May'=>'Май', + 'Jun'=>'Юни', + 'Jul'=>'Юли', + 'Aug'=>'Авг', + 'Sep'=>'Сеп', + 'Oct'=>'Окт', + 'Nov'=>'Ное', + 'Dec'=>'Дек', + + 'Monday'=>'Понеделник', + 'Tuesday'=>'Вторник', + 'Wednesday'=>'Сряда', + 'Thursday'=>'Четвъртък', + 'Friday'=>'Петък', + 'Saturday'=>'Събота', + 'Sunday'=>'Неделя', + + 'Mon'=>'Пн', + 'Tue'=>'Вт', + 'Wed'=>'Ср', + 'Thu'=>'Чт', + 'Fri'=>'Пт', + 'Sat'=>'Сб', + 'Sun'=>'Нд' + )); + break; + } + + return $data; + } + + + /** + * Подготовка имени файла или директории + * + * @param string $st + * @return string + */ + function prepare_fname($st) + { + $st = strip_tags($st); + + $st = strtr($st,'ABCDEFGHIJKLMNOPQRSTUVWXYZАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЪЫЭЮЯ', + 'abcdefghijklmnopqrstuvwxyzабвгдеёжзийклмнопрстуфхцчшщьъыэюя'); + + $st = translit_string(trim($st)); + + $st = preg_replace(array('/[^a-z0-9_-]/', '/--+/'), '-', $st); + + return trim($st, '-'); + } + + + /** + * Отображение даты в фармате + * 25 дней/минут/секунд назад + * и т.д. + * + * @param string $date (TIMESTAMP) + * @return string + */ + function human_date($date) + { + $stf = 0; + $cur_time = time(); + $diff = $cur_time - $date; + + $language = (defined('ACP') && ACP) + ? $_SESSION['admin_language'] + : $_SESSION['user_language']; + + $language = strtolower($language); + + switch ($language) + { + default: + case 'ru': + $seconds = array('секунда', 'секунды', 'секунд'); + $minutes = array('минута', 'минуты', 'минут'); + $hours = array('час', 'часа', 'часов'); + $days = array('день', 'дня', 'дней'); + $weeks = array('неделя', 'недели', 'недель' ); + $months = array('месяц', 'месяца', 'месяцев'); + $years = array('год', 'года', 'лет'); + $decades = array('десятилетие', 'десятилетия', 'десятилетий'); + $ago = 'назад'; + break; + + case 'ua': + case 'uk': + $seconds = array('секунда', 'секунди', 'секунд'); + $minutes = array('хвилина', 'хвилини', 'хвилин'); + $hours = array('година', 'години', 'годин'); + $days = array('день', 'дня', 'днів'); + $weeks = array('тиждень', 'тижня', 'тижнів' ); + $months = array('месяць', 'місяця', 'місяців'); + $years = array('рік', 'року', 'років'); + $decades = array('десятиріччя', 'десятиріччя', 'десятиріч'); + $ago = 'назад'; + break; + + case 'en': + $seconds = array('second', 'seconds', 'seconds'); + $minutes = array('minute', 'minutes', 'minutes'); + $hours = array('hour', 'hours', 'hours'); + $days = array('day', 'days', 'days'); + $weeks = array('week', 'weeks', 'weeks' ); + $months = array('month', 'months', 'months'); + $years = array('year', 'years', 'years'); + $decades = array('decade', 'decades', 'decades'); + $ago = 'ago'; + break; + } + + $phrase = array($seconds, $minutes, $hours, $days, $weeks, $months, $years, $decades); + + $length = array(1, 60, 3600, 86400, 604800, 2630880, 31570560, 315705600); + + for ($i = sizeof($length) - 1; ($i >= 0) && (($no = $diff / $length[ $i ]) <= 1 ); $i --) + { + ; + } + + if ($i < 0) + { + $i = 0; + } + + $_time = $cur_time - ($diff % $length[$i]); + + $no = floor($no); + + $value = sprintf("%d %s ", $no, date_phrase($no, $phrase[$i])); + + if (($stf == 1) && ($i >= 1) && (($cur_time - $_time) > 0)) + { + $value .= time_ago($_time); + } + + return $value . $ago; + } + + + function date_phrase($number, $titles) + { + $cases = array( 2, 0, 1, 1, 1, 2 ); + + return $titles[($number % 100 > 4 && $number % 100 < 20) + ? 2 + : $cases[min($number % 10, 5)]]; + } +?> \ No newline at end of file diff --git a/functions/func.login.php b/functions/func.login.php new file mode 100644 index 0000000..914bc5e --- /dev/null +++ b/functions/func.login.php @@ -0,0 +1,346 @@ +Query(" + SELECT + usr.Id, + usr.user_group, + usr.user_name, + usr.firstname, + usr.lastname, + usr.email, + usr.country, + usr.password, + usr.salt, + usr.status, + grp.user_group_permission + FROM + " . PREFIX . "_users AS usr + LEFT JOIN + " . PREFIX . "_user_groups AS grp + ON grp.user_group = usr.user_group + WHERE + email = '" . $login . "' + OR + user_name = '" . $login . "' + LIMIT 1 + ")->FetchRow(); + + if (! (isset($row->password) && $row->password == md5(md5($password . $row->salt)))) + return 2; + + if ($row->status != '1') + return 3; + + $salt = make_random_string(); + + $hash = md5(md5($password . $salt)); + + $time = time(); + + $u_ip = ($attach_ip == 1) + ? ip2long($_SERVER['REMOTE_ADDR']) + : 0; + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_users + SET + last_visit = '" . $time . "', + password = '" . $hash . "', + salt = '" . $salt . "', + user_ip = '" . (int)$u_ip . "' + WHERE + Id = '" . $row->Id . "' + "); + + $_SESSION['user_id'] = $row->Id; + $_SESSION['user_name'] = get_username($row->user_name, $row->firstname, $row->lastname); + $_SESSION['user_firstname'] = $row->firstname; + $_SESSION['user_lastname'] = $row->lastname; + $_SESSION['user_pass'] = $hash; + $_SESSION['user_group'] = $row->user_group; + $_SESSION['user_email'] = $row->email; + $_SESSION['user_country'] = strtoupper($row->country); + $_SESSION['user_language'] = strtolower($row->country); + $_SESSION['user_ip'] = addslashes($_SERVER['REMOTE_ADDR']); + + $user_group_permissions = explode('|', preg_replace('/\s+/', '', $row->user_group_permission)); + + foreach ($user_group_permissions as $user_group_permission) + $_SESSION[$user_group_permission] = 1; + + if ($keep_in == 1) + { + $expire = $time + COOKIE_LIFETIME; + + $auth = md5($_SERVER['HTTP_USER_AGENT'].md5($row->Id)); + + $sql = " + DELETE FROM + " . PREFIX . "_users_session + WHERE + `hash`='" . addslashes($auth) . "'"; + + $AVE_DB->Query($sql); + + $sql = " + INSERT INTO + " . PREFIX . "_users_session + (`user_id`,`hash`,`ip`,`agent`,`last_activ`) + values + ('" . $row->Id . "','" . addslashes($auth) . "','" . (int)$u_ip . "','" . addslashes($_SERVER['HTTP_USER_AGENT']) . "','" . time() . "') + "; + + $AVE_DB->Query($sql); + + @setcookie('auth', $auth, $expire, ABS_PATH, $cookie_domain); + } + + unset($row, $user_group_permissions, $sql); + + return true; + } + + /** + * Logout + */ + function user_logout() + { + global $cookie_domain; + + // уничтожаем куку + @setcookie('auth', '', 0, ABS_PATH, $cookie_domain); + + // уничтожаем сессию + @session_destroy(); + session_unset(); + $_SESSION = array(); + } + + + /** + * Авторизация Session + * + * @return bool + */ + function auth_sessions() + { + global $AVE_DB; + + if (empty($_SESSION['user_id']) || empty($_SESSION['user_pass'])) + return false; + + $referer = false; + + if (isset($_SERVER['HTTP_REFERER'])) + { + $referer = parse_url($_SERVER['HTTP_REFERER']); + $referer = (trim($referer['host']) === $_SERVER['SERVER_NAME']); + } + + // Если не наш REFERER или изменился IP-адрес + // сверяем данные сессии с данными базы данных + if ($referer === false || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR']) + { + $verified = $AVE_DB->Query(" + SELECT 1 + FROM + " . PREFIX . "_users + WHERE + Id = '" . (int)$_SESSION['user_id'] . "' + AND + password = '" . addslashes($_SESSION['user_pass']) . "' + LIMIT 1 + ")->NumRows(); + + if (! $verified) + return false; + + $_SESSION['user_ip'] = addslashes($_SERVER['REMOTE_ADDR']); + } + + define('UID', $_SESSION['user_id']); + define('UGROUP', $_SESSION['user_group']); + define('UNAME', $_SESSION['user_name']); + + return true; + } + + + /** + * Авторизация Coockie + * + * @return bool + */ + function auth_cookie() + { + global $AVE_DB, $cookie_domain; + + if (empty($_COOKIE['auth'])) + return false; + + $sql = " + SELECT + user_id + FROM + " . PREFIX . "_users_session + WHERE + hash = '" . addslashes($_COOKIE['auth']) . "' + AND + agent = '" . addslashes($_SERVER['HTTP_USER_AGENT']) . "' + "; + + $user_id = $AVE_DB->Query($sql)->GetCell(); + + if ((int)$user_id == 0) + { + @setcookie('auth', '', 0, ABS_PATH, $cookie_domain); + return false; + } + + $row = $AVE_DB->Query(" + SELECT + usr.user_group, + usr.user_name, + usr.firstname, + usr.lastname, + usr.email, + usr.country, + usr.password, + usr.status, + usrs.ip AS ip, + grp.user_group_permission + FROM + " . PREFIX . "_users AS usr + LEFT JOIN + " . PREFIX . "_user_groups AS grp + ON grp.user_group = usr.user_group + LEFT JOIN + " . PREFIX . "_users_session AS usrs + ON usr.Id = usrs.user_id + WHERE + usr.Id = '" . $user_id . "' + AND + usrs.hash = '" . $_COOKIE['auth'] . "' + LIMIT 1 + ")->FetchRow(); + + if (empty($row)) + return false; + + $row->ip = long2ip($row->ip); + + if (USER_IP) + { + if (($row->ip !== '0.0.0.0' && $row->ip !== $_SERVER['REMOTE_ADDR'])) + { + $sql = " + DELETE FROM + " . PREFIX . "_users_session + WHERE + hash = '" . addslashes($_COOKIE['auth']) . "'"; + + $AVE_DB->Query($sql); + } + + @setcookie('auth', '', 0, ABS_PATH, $cookie_domain); + return false; + } + + $AVE_DB->Query(" + UPDATE + " . PREFIX . "_users_session + SET + last_activ = '" . time() . "', + ip = '" . (int)ip2long($_SERVER['REMOTE_ADDR']) . "' + WHERE + Id = '" . $row->Id . "' + "); + + $_SESSION['user_id'] = (int)$user_id; + $_SESSION['user_name'] = get_username($row->user_name, $row->firstname, $row->lastname); + $_SESSION['user_firstname'] = $row->firstname; + $_SESSION['user_lastname'] = $row->lastname; + $_SESSION['user_pass'] = $row->password; + $_SESSION['user_group'] = (int)$row->user_group; + $_SESSION['user_email'] = $row->email; + $_SESSION['user_country'] = strtoupper($row->country); + $_SESSION['user_language'] = strtolower($row->country); + $_SESSION['user_ip'] = addslashes($_SERVER['REMOTE_ADDR']); + + $user_group_permissions = explode('|', preg_replace('/\s+/', '', $row->user_group_permission)); + + foreach ($user_group_permissions as $user_group_permission) + $_SESSION[$user_group_permission] = 1; + + define('UID', $_SESSION['user_id']); + define('UGROUP', $_SESSION['user_group']); + define('UNAME', $_SESSION['user_name']); + + return true; + } + + + /** + * Удаление профиля пользователя на сайте + * + * @param string $user_id идентификатор пользователя + */ + function user_delete($user_id) + { + global $AVE_DB; + + if ($user_id == 1) + return false; + + $AVE_DB->Query(" + DELETE + FROM + " . PREFIX . "_users + WHERE + Id = '" . $user_id . "' + "); + } + +?> \ No newline at end of file diff --git a/functions/func.logs.php b/functions/func.logs.php new file mode 100644 index 0000000..bd332c6 --- /dev/null +++ b/functions/func.logs.php @@ -0,0 +1,112 @@ + time(), + 'log_ip' => $_SERVER['REMOTE_ADDR'], + 'log_url' => $_SERVER['REQUEST_URI'], + 'log_user_id' => ($_SESSION['user_id'] ?? '0'), + 'log_user_name' => ($_SESSION['user_name'] ?? 'Anonymous'), + 'log_text' => $message, + 'log_type' => (int)$typ, + 'log_rubric' => (int)$rub + ]; + + if ($f_log = @fopen($logfile, 'ab')) + { + if (flock($f_log, LOCK_EX)) + { + fputcsv($f_log, $logData); + flock($f_log, LOCK_UN); + } + + fclose($f_log); + } + } + + /** + * Запись события в лог для Sql ошибок + * + * @param string $message Текст сообщения + * @return void + */ + function reportSqlLog($message) + { + $logfile = BASE_DIR . '/tmp/logs/sql.csv'; + + $logData = [ + 'log_time' => time(), + 'log_ip' => $_SERVER['REMOTE_ADDR'], + 'log_url' => $_SERVER['REQUEST_URI'], + 'log_user_id' => $_SESSION['user_id'], + 'log_user_name' => $_SESSION['user_name'], + 'log_text' => base64_encode(serialize($message)) + ]; + + if ($f_log = @fopen($logfile, 'ab')) + { + if (flock($f_log, LOCK_EX)) + { + fputcsv($f_log, $logData); + flock($f_log, LOCK_UN); + } + + fclose($f_log); + } + } + + /** + * Запись события в лог для 404 ошибок + * + * @param string $message Текст сообщения + * @return void + */ + function report404() + { + $logfile = BASE_DIR . '/tmp/logs/404.csv'; + + $logData = [ + 'log_time' => time(), + 'log_ip' => @$_SERVER['REMOTE_ADDR'], + 'log_query' => @$_SERVER['REQUEST_URI'], + 'log_user_agent' => @$_SERVER['HTTP_USER_AGENT'], + 'log_user_referer' => ($_SERVER['HTTP_REFERER'] ?? ''), + 'log_request_uri' => @$_SERVER['REQUEST_URI'] + ]; + + if ($f_log = @fopen($logfile, 'ab')) + { + if (flock($f_log, LOCK_EX)) + { + fputcsv($f_log, $logData); + flock($f_log, LOCK_UN); + } + + fclose($f_log); + } + } + +?> \ No newline at end of file diff --git a/functions/func.mail.php b/functions/func.mail.php new file mode 100644 index 0000000..b1ddd09 --- /dev/null +++ b/functions/func.mail.php @@ -0,0 +1,252 @@ +
      ' . nl2br(get_settings('mail_signature')); + } + else + { + $signature = "\r\n\r\n" . get_settings('mail_signature'); + } + } + else $signature = ''; + + // Составляем тело письма + $body = stripslashes($body) . $signature; + + if ($type == 'text/html') + { + $body = str_replace(array("\t","\r","\n"),'',$body); + $body = str_replace(array(' ','> <'),array(' ','><'),$body); + } + + // Формируем письмо + $message = Swift_Message::newInstance($subject) + -> setFrom(array($from_email => $from_name)) + -> setTo($to) + -> setContentType($type) + -> setBody($body) + -> setMaxLineLength((int)get_settings('mail_word_wrap')); + + // Прикрепляем вложения + if ($attach) + { + foreach ($attach as $attach_file) + { + $message -> attach(Swift_Attachment::fromPath(trim($attach_file))); + } + } + + // Выбираем метод отправки и формируем транспорт + switch (get_settings('mail_type')) + { + default: + case 'mail': + $transport = Swift_MailTransport::newInstance(); + break; + + case 'smtp': + $transport = Swift_SmtpTransport::newInstance(stripslashes(get_settings('mail_host')), (int)get_settings('mail_port')); + + // Добавляем шифрование + $smtp_encrypt = get_settings('mail_smtp_encrypt'); + if($smtp_encrypt) + $transport + ->setEncryption(strtolower(stripslashes($smtp_encrypt))); + + // Имя пользователя/пароль + $smtp_user = get_settings('mail_smtp_login'); + $smtp_pass = get_settings('mail_smtp_pass'); + if($smtp_user) + $transport + ->setUsername(stripslashes($smtp_user)) + ->setPassword(stripslashes($smtp_pass)); + break; + + case 'sendmail': + $transport = Swift_SendmailTransport::newInstance(get_settings('mail_sendmail_path')); + break; + } + + // Сохраняем вложения в ATTACH_DIR, если просили + if ($attach && $saveattach) + { + $attach_dir = BASE_DIR . '/tmp/' . ATTACH_DIR . '/'; + foreach ($attach as $file_path) + { + if ($file_path && file_exists($file_path)) + { + $file_name = basename($file_path); + $file_name = str_replace(' ','',mb_strtolower(trim($file_name))); + if (file_exists($attach_dir . $file_name)) + { + $file_name = rand(1000, 9999) . '_' . $file_name; + } + $file_path_new = $attach_dir . $file_name; + if (!@move_uploaded_file($file_path,$file_path_new)) + { + copy($file_path,$file_path_new); + } + } + } + } + + // Отправляем письмо + /** @var $transport TYPE_NAME */ + $mailer = Swift_Mailer::newInstance($transport); + + if (!@$mailer -> send($message, $failures)) + { + reportLog('Не удалось отправить письма следующим адресатам: ' . implode(',',$failures)); + return $failures; + } + + } + } + + if ( ! function_exists('safe_mailto')) + { + function safe_mailto($email, $title = '', $attributes = '') + { + $title = (string) $title; + + if ($title == "") + { + $title = $email; + } + + for ($i = 0; $i < 16; $i++) + { + $x[] = substr(' $val) + { + $x[] = ' '.$key.'="'; + for ($i = 0; $i < strlen($val); $i++) + { + $x[] = "|".ord(substr($val, $i, 1)); + } + $x[] = '"'; + } + } + else + { + for ($i = 0; $i < strlen($attributes); $i++) + { + $x[] = substr($attributes, $i, 1); + } + } + } + + $x[] = '>'; + + $temp = array(); + + for ($i = 0; $i < strlen($title); $i++) + { + $ordinal = ord($title[$i]); + + if ($ordinal < 128) + { + $x[] = "|".$ordinal; + } + else + { + if (count($temp) == 0) + { + $count = ($ordinal < 224) ? 2 : 3; + } + + $temp[] = $ordinal; + if (count($temp) == $count) + { + $number = ($count == 3) ? (($temp['0'] % 16) * 4096) + (($temp['1'] % 64) * 64) + ($temp['2'] % 64) : (($temp['0'] % 32) * 64) + ($temp['1'] % 64); + $x[] = "|".$number; + $count = 1; + $temp = array(); + } + } + } + + $x[] = '<'; $x[] = '/'; $x[] = 'a'; $x[] = '>'; + + $x = array_reverse($x); + ob_start(); + + ?> \ No newline at end of file diff --git a/functions/func.modulglobals.php b/functions/func.modulglobals.php new file mode 100644 index 0000000..7e57841 --- /dev/null +++ b/functions/func.modulglobals.php @@ -0,0 +1,72 @@ + + * tpl_dir путь к папке с шаблонами модуля + * theme_folder имя папки с файлами дизайна + * config_vars массив с языковыми переменными модуля + * + * Формирует и передаёт в шаблонизатор: + *

      +	 *      $tpl_dir     путь к папке с шаблонами модуля
      +	 *      $mod_dir     имя папки с модулями
      +	 *      $config_vars массив с языковыми переменными модуля
      +	 * 
      + * Регистрирует в шаблонизаторе функцию in_array + * + * @param string $modulepath имя папки модуля + * @param string $lang_section секция языкового файла + */ + function set_module_globals($modulepath, $lang_section = false) + { + global $mod, $AVE_Template; + + $tpl_dir = BASE_DIR . '/modules/' . $modulepath . '/templates/'; + $lang_file = BASE_DIR . '/modules/' . $modulepath . '/lang/' . $_SESSION['user_language'] . '.txt'; + + if (!file_exists($lang_file)) + { + $lang_file = BASE_DIR . '/modules/' . $modulepath . '/lang/ru.txt'; + } + + if (!file_exists($lang_file)) + { + display_notice('Ошибка! Отсутствует языковой файл. Пожалуйста, проверьте язык, установленный по умолчанию, в файле '.ABS_PATH.'inc/config.php'); + exit; + } + + if ($lang_section === false) + { + $AVE_Template->config_load($lang_file); + } + else + { + $AVE_Template->config_load($lang_file, $lang_section); + } + + $config_vars = $AVE_Template->get_config_vars(); + + $AVE_Template->assign('tpl_dir', $tpl_dir); + $AVE_Template->assign('mod_dir', BASE_DIR . '/modules'); + $AVE_Template->assign('config_vars', $config_vars); + + $mod['tpl_dir'] = $tpl_dir; + $mod['theme_folder'] = defined('THEME_FOLDER') ? THEME_FOLDER : DEFAULT_THEME_FOLDER; + $mod['config_vars'] = $config_vars; + + $AVE_Template->register_function('in_array', 'in_array'); + } + +?> \ No newline at end of file diff --git a/functions/func.navigation.php b/functions/func.navigation.php new file mode 100644 index 0000000..217ba9c --- /dev/null +++ b/functions/func.navigation.php @@ -0,0 +1,519 @@ +Query($sql, -1, 'nav_' . $navi_id, true, '.navigation')->FetchRow(); + + $navigation->user_group = explode(',',$navigation->user_group); + + return $navigation; + } + + + /** + * Функция обработки навигации + * + * @param int $navi_tag - идентификатор меню навигации + * @return mixed|string + */ + function parse_navigation($navi_tag) + { + global $AVE_DB, $AVE_Core; + + // Извлекаем id из аргумента + $navi_id = $navi_tag[1]; + + Debug::startTime('NAVIAGTION_' . $navi_id); + + $navi_menu = get_navigations($navi_id); + + $expnad_ext = $navi_menu->expand_ext; + + // извлекаем level из аргумента + $navi_print_level = (! empty($navi_tag[2])) + ? $navi_tag[2] + : ''; + + $navi = ''; + + if (! $navi_menu) + { + echo 'Menu ', $navi_id, ' not found!'; + return ''; + } + + // выставляем гостевую группу по дефолту + if (! defined('UGROUP')) + define('UGROUP', 2); + + // выходим, если навиг. не предназначена для текущей группы + if (! in_array(UGROUP, $navi_menu->user_group)) + return false; + + // Находим активный пункт (связь текущего открытого документа и навигации). Нас интересуют: + // 1) документы, которые сами связаны с пунктом меню + // 2) пункты навигации, у которых ссылка совпадает с алиасом дока + // 3) текущий level, текущий id + // возвращаем в $navi_active через запятую id пунктов: + // 1) активный пункт + // 2) родители активного пункта + // после ; через запятую все level-ы текущего пути, чтобы потом взять max + // после ; id текущего пункта + + // id текущего документа. Если не задан, то главная страница + $doc_active_id = (int)(($_REQUEST['id']) + ? $_REQUEST['id'] + : 1); + + // алиас текущего документа + $alias = ltrim(isset($AVE_Core->curentdoc->document_alias) + ? $AVE_Core->curentdoc->document_alias + : ''); + + // запрос для выборки по текущему алиасу + $sql_doc_active_alias = ''; + + $url_suff = ''; + + if (defined('URL_SUFF') AND URL_SUFF) + { + $url_suff = " + OR nav.alias = '" . $alias . URL_SUFF . "' + OR nav.alias = '/" . $alias . URL_SUFF . "' + "; + } + + if ($AVE_Core->curentdoc->Id == $doc_active_id) + { + $sql_doc_active_alias = " + OR nav.alias = '" . $alias . "' + OR nav.alias = '/" . $alias . "' + " . $url_suff . " + "; + } + + $navi_active = $AVE_DB->Query(" + SELECT + CONCAT_WS( + ';', + CONCAT_WS(',', nav.navigation_item_id, nav.parent_id, nav2.parent_id), + CONCAT_WS(',', nav.level), + nav.navigation_item_id + ) + FROM + " . PREFIX . "_navigation_items AS nav + JOIN + " . PREFIX . "_documents AS doc + LEFT JOIN + " . PREFIX . "_navigation_items AS nav2 + ON + nav2.navigation_item_id = nav.parent_id + WHERE + nav.status = 1 + AND + nav.navigation_id = '" . $navi_menu->navigation_id . "' + AND + doc.Id = " . $doc_active_id . " + AND ( + nav.document_id = '" . $doc_active_id . "'" . + $sql_doc_active_alias . " + OR + nav.navigation_item_id = doc.document_linked_navi_id + ) + ")->GetCell(); + + $navi_active = @explode(';', $navi_active); + + // готовим 2 переменные с путём + if ($navi_active[0]) + $navi_active_way = @explode(',', $navi_active[0]); + + $navi_active_way[] = '0'; + + $navi_active_way_str = implode(',', $navi_active_way); + + // текущий уровень + $navi_active_level = (int)max(@explode(',', (isset($navi_active[1]) + ? (int)$navi_active[1] + : 0)))+1; + + // текущий id + $navi_active_id = (isset($navi_active[2]) + ? (int)$navi_active[2] + : 0); + + // если просят вывести какие-то конкретные уровни: + $sql_navi_level = ''; + $sql_navi_active = ''; + + if ($navi_print_level) + { + $sql_navi_level = ' AND level IN (' . $navi_print_level . ') '; + $sql_navi_active = ' AND parent_id IN (' . $navi_active_way_str . ') '; + } + + // обычное использование навигации + else + { + switch ($navi_menu->expand_ext) + { + // текущий и родительский уровни + case 0: + $sql_navi_active = ' AND parent_id IN (' . $navi_active_way_str . ') '; + $navi_parent = 0; + break; + + // все уровни + case 1: + $navi_parent = 0; + break; + + // только текущий уровень + case 2: + $sql_navi_level = ' AND level = ' . $navi_active_level . ' '; + $navi_parent = $navi_active_id; + break; + } + } + + $cache_items = BASE_DIR . '/tmp/cache/sql/navigations/' . $navi_id . '/items.cache'; + + $navi_items = []; + + // Если включен DEV MODE, то отключаем кеширование запросов + if (defined('DEV_MODE') AND DEV_MODE || $expnad_ext != 1) + $cache_items = null; + + if (empty($navi_print_level)) + { + //-- Проверяем есть файл кеша, если есть пропускам запрос к БД + if (! file_exists($cache_items)) + { + //-- Запрос пунктов меню + $sql = " + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + status = '1' + AND + navigation_id = '" . $navi_menu->navigation_id . "'" . + $sql_navi_level . + $sql_navi_active . " + ORDER BY + position ASC + "; + + $sql_navi_items = $AVE_DB->Query($sql); + + while ($row_navi_items = $sql_navi_items->FetchAssocArray()) + $navi_items[$row_navi_items['parent_id']][] = $row_navi_items; + + if ($cache_items) + file_put_contents($cache_items, serialize($navi_items)); + } + else + { + $navi_items = unserialize(file_get_contents($cache_items)); + } + } + else + { + //-- Запрос пунктов меню + $sql = " + SELECT + * + FROM + " . PREFIX . "_navigation_items + WHERE + status = '1' + AND + navigation_id = '" . $navi_menu->navigation_id . "'" . + $sql_navi_level . " + ORDER BY + position ASC + "; + + $sql_navi_items = $AVE_DB->Query($sql); + + while ($row_navi_items = $sql_navi_items->FetchAssocArray()) + { + $navi_items[$row_navi_items['parent_id']][] = $row_navi_items; + } + + $keys = array_keys($navi_items); + $navi_parent = ! empty($keys) + ? $keys[0] + : 0; + } + + // Парсим теги в шаблонах пунктов + $navi_item_tpl = array( + 1 => array( + 'inactive' => $navi_menu->level1, + 'active' => $navi_menu->level1_active + ), + 2 => array( + 'inactive' => $navi_menu->level2, + 'active' => $navi_menu->level2_active + ), + 3 => array( + 'inactive' => $navi_menu->level3, + 'active' => $navi_menu->level3_active + ) + ); + + // запускаем рекурсивную сборку навигации + if ($navi_items) + $navi = printNavi($navi_menu, $navi_items, $navi_active_way, $navi_item_tpl, $navi_parent); + + // преобразуем все ссылке в коде + $navi = rewrite_link($navi); + + // удаляем переводы строк и табуляции + $navi = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $navi); + $navi = str_replace(array("\n","\r"),'',$navi); + + $gen_time = Debug::endTime('NAVIAGTION_' . $navi_id); + + $GLOBALS['block_generate']['NAVIAGTIONS'][$navi_id] = $gen_time; + + return $navi; + } + + + /** + * Рекурсивная функция для формирования меню навигации + * + * @param object $navi_menu меню (шаблоны, параметры) + * @param array $navi_items (пункты по родителям) + * @param array $navi_active_way ("активный путь") + * @param array $navi_item_tpl (шаблоны пунктов) + * @param int $parent (исследуемый родитель, изначально 0 - верхний уровень) + * @return string $navi - готовый код навигации + */ + function printNavi ($navi_menu, $navi_items, $navi_active_way, $navi_item_tpl, $parent = 0) + { + // выясняем уровень + $navi_item_level = $navi_items[$parent][0]['level']; + + // собираем каждый пункт в данном родителе -> в переменной $item + + $x = 0; + $items_count = count($navi_items[$parent]); + + foreach ($navi_items[$parent] as $row) + { + $x++; + $last_item = ($x == $items_count ? true : false); + $item_num = $x; + + // Проверяем пункт меню на принадлежность к "активному пути" и выбираем шаблон + $item = (in_array($row['navigation_item_id'], $navi_active_way)) + ? $navi_item_tpl[$navi_item_level]['active'] + : $navi_item_tpl[$navi_item_level]['inactive']; + + ################### ПАРСИМ ТЕГИ ################### + // id + @$item = str_replace('[tag:linkid]', $row['navigation_item_id'], $item); + // название + @$item = str_replace('[tag:linkname]', $row['title'], $item); + //Путь + $item = str_replace('[tag:path]', ABS_PATH, $item); + // ссылка + if ($row['document_id']) + { + //запрещаем слешь в конце ссылки + //$item = str_replace('[tag:link]', 'index.php?id=' . $row['document_id'] . "&doc=" . ((!$row['alias']) ? prepare_url($row['title']) : trim($row['alias'], '/')), $item); + //разрешаем слешь в конце ссылки + $item = str_replace('[tag:link]', 'index.php?id=' . $row['document_id'] . "&doc=" . ((!$row['alias']) ? prepare_url($row['title']) : trim($row['alias'])), $item); + + $item = str_ireplace('"//"', '"/"', str_ireplace('///', '/', rewrite_link($item))); + } + else + { + $item = str_replace('[tag:link]', $row['alias'], $item); + } + + if (start_with('www.', $row['alias'])) + $item = str_replace('www.', 'http://www.', $item); + + // target + $item = str_replace('[tag:target]', $row['target'], $item); + // описание + @$item = str_replace('[tag:desc]', stripslashes($row['description']), $item); + // изображение + @$item = str_replace('[tag:img]', stripslashes($row['image']), $item); + + if ($row['image'] != '') + { + @$img = explode('.', $row['image']); + @$row['image_act'] = $img[0] . "_act.".$img[1]; + @$item = str_replace('[tag:img_act]', stripslashes($row['image_act']), $item); + } + + if ($row['css_id'] != '') + { + @$item = str_replace('[tag:css_id]', stripslashes($row['css_id']), $item); + } + else + { + @$item = str_replace('[tag:css_id]', '', $item); + } + + if ($row['css_class'] != '') + { + @$item = str_replace('[tag:css_class]', stripslashes($row['css_class']), $item); + } + else + { + @$item = str_replace('[tag:css_class]', '', $item); + } + + if ($row['css_style'] != '') + { + @$item = str_replace('[tag:css_style]', stripslashes($row['css_style']), $item); + } + else + { + @$item = str_replace('[tag:css_style]', '', $item); + } + + $item = '<'.'?php $item_num = ' . var_export($item_num, true) . '; ?'.'>' . $item; + $item = '<'.'?php $last_item = ' . var_export($last_item, true) . '; ?'.'>' . $item; + + $item = str_replace('[tag:if_first]', '<'.'?php if(isset($item_num) && $item_num===1) { ?'.'>', $item); + $item = str_replace('[tag:if_not_first]', '<'.'?php if(isset($item_num) && $item_num!==1) { ?'.'>', $item); + + $item = str_replace('[tag:if_last]', '<'.'?php if(isset($last_item) && $last_item) { ?'.'>', $item); + $item = str_replace('[tag:if_not_last]', '<'.'?php if(isset($item_num) && !$last_item) { ?'.'>', $item); + + $item = str_replace('[tag:if_sub_level]', '<'.'?php if (isset($exist_level) && $exist_level) { ?'.'>', $item); + $item = str_replace('[tag:if_no_sub_level]', '<'.'?php if (isset($exist_level) && !$exist_level) { ?'.'>', $item); + + $item = preg_replace('/\[tag:if_every:([0-9-]+)\]/u', '<'.'?php if(isset($item_num) && !($item_num % $1)){ '.'?'.'>', $item); + $item = preg_replace('/\[tag:if_not_every:([0-9-]+)\]/u', '<'.'?php if(isset($item_num) && ($item_num % $1)){ '.'?'.'>', $item); + + $item = str_replace('[tag:/if]', '<'.'?php } ?>', $item); + $item = str_replace('[tag:if_else]', '<'.'?php }else{ ?>', $item); + + ################### //ПАРСИМ ТЕГИ ################## + + // Удаляем ошибочные теги + @$item = preg_replace('/\[tag:([a-zA-Z0-9-_]+)\]/', '', $item); + + // Определяем тег для вставки следующего уровня + switch ($navi_item_level) + { + case 1 : + $tag = '[tag:level:2]'; + $tag_exist = '[tag:level:2:exist]'; + break; + + case 2 : + $tag = '[tag:level:3]'; + $tag_exist = '[tag:level:3:exist]'; + break; + + default: + $tag = ''; + $tag_exist = 0; + } + + // Если есть подуровень, то заново запускаем для него функцию и вставляем вместо тега + if (! empty($navi_items[$row['navigation_item_id']])) + { + $item = '<'.'?php $exist_level = true; ?'.'>' . $item; + $item_sublevel = printNavi($navi_menu, $navi_items, $navi_active_way, $navi_item_tpl, $row['navigation_item_id']); + $item = @str_replace($tag, $item_sublevel, $item); + $item = @str_replace($tag_exist, 1, $item); + } + // Если нет подуровня, то удаляем тег + else + { + $item = '<'.'?php $exist_level = false; ?'.'>' . $item; + $item = @str_replace(@$tag,'',$item); + $item = @str_replace($tag_exist, 0, $item); + } + + // Подставляем в переменную навигации готовый пункт + if (empty($navi)) + $navi = ''; + + $navi .= eval2var(' ?'.'>' . $item . '<'.'?php '); + } + + // Вставляем все пункты уровня в шаблон уровня + switch ($navi_item_level) + { + case 1 : + $navi = str_replace("[tag:content]", $navi, $navi_menu->level1_begin); + break; + case 2 : + $navi = str_replace("[tag:content]", $navi, $navi_menu->level2_begin); + break; + case 3 : + $navi = str_replace("[tag:content]", $navi, $navi_menu->level3_begin); + break; + } + + // Возвращаем сформированный уровень + return $navi; + } + + + /** + * Проверка прав доступа к навигации по группе пользователя + * + * @param int $id идентификатор меню навигации + * @return boolean + */ + function check_navi_permission ($id) + { + $navigation = get_navigations($id); + + if (empty($navigation->user_group)) + return false; + + if (! defined('UGROUP')) + define('UGROUP', 2); + + if (! in_array(UGROUP, $navigation->user_group)) + return false; + + return true; + } +?> \ No newline at end of file diff --git a/functions/func.pagination.php b/functions/func.pagination.php new file mode 100644 index 0000000..5520837 --- /dev/null +++ b/functions/func.pagination.php @@ -0,0 +1,141 @@ + 5 && $curent_page > 3) + { + $first = str_replace('data-pagination="{s}"', 'data-pagination="1"', $template_label); + + $nav .= sprintf($link_box, str_replace(array('{s}', '{t}'), $start_label, str_replace(array('&'. $type .'={s}', '&' . $type .'={s}', '/' . $type . '-{s}'), '', $first))); + if ($separator_label != '') + $nav .= sprintf($separator_box, $separator_label); + } + + // Предыдущая + if ($curent_page > 1) + { + if ($curent_page - 1 == 1) + $nav .= sprintf($link_box, str_replace(array('{s}', '{t}'), $prev_label, str_replace(array('&'. $type .'={s}', '&' . $type .'={s}', '/' . $type . '-{s}'), '', $template_label))); + else + $nav .= sprintf($link_box, str_replace('{t}', $prev_label, str_replace('{s}', ($curent_page - 1), $template_label))); + } + + foreach($pages as $val) + { + if ($val >= 1 && $val <= $total_pages) + { + if ($curent_page == $val) + { + // Текущий номер страницы (активная страница) + $nav .= sprintf($link_box, sprintf($active_box, str_replace(array('{s}', '{t}'), $val, $curent_page))); + } + else + { + if ($val == 1) + { + // Страница номер 1 + $nav .= sprintf($link_box, str_replace(array('{s}', '{t}'), $val, str_replace(array('&'.$type.'={s}','&'.$type.'={s}','/'.$type.'-{s}'), '', $template_label))); + } + else + { + // Остальные неактивные номера страниц + $nav .= sprintf($link_box, str_replace(array('{s}', '{t}'), $val, $template_label)); + } + } + } + } + + // Следующая + if ($curent_page < $total_pages) + { + $nav .= sprintf($link_box, str_replace('{t}', $next_label, str_replace('{s}', ($curent_page + 1), $template_label))); + } + + // Последняя + if ($total_pages > 5 && ($curent_page < $total_pages-2)) + { + if ($separator_label != '') + $nav .= sprintf($separator_box, $separator_label); + + $nav .= sprintf($link_box, str_replace('{t}', $end_label, str_replace('{s}', $total_pages, $template_label))); + } + + // Страница ХХХ из ХХХ + if ($nav != '') + { + if ($total_label != '') + $nav = sprintf($total_box, sprintf($total_label, $curent_page, $total_pages)) . $nav; + + // Оборачиваем в общий контейнер + if ($navi_box != '') + $nav = sprintf($navi_box, $nav); + } + + return $nav; + } + +?> \ No newline at end of file diff --git a/functions/func.parserequest.php b/functions/func.parserequest.php new file mode 100644 index 0000000..cebc359 --- /dev/null +++ b/functions/func.parserequest.php @@ -0,0 +1,939 @@ +item_num = $item_num; + $this->is_last = $is_last; + $this->row = $row; + $this->rubric_id = $rubric_id; + $this->items_count = $items_count; + } + + /** + * Основной метод для обработки всех условных тегов в строке. + * + * @param string $content Строка с тегами, например, '[tag:if_first]...[/tag:if]' + * @return string Обработанная строка + */ + public function process(string $content): string + { + // Сначала обрабатываем теги if_notempty и if_empty + $processed_content = preg_replace_callback( + '/\\[tag:(if_notempty|if_empty):rfld:([a-zA-Z0-9-_]+)]\\[(more|esc|img|strip|[0-9-]+)](.*?)\\[tag:\\/if]/s', + function ($matches) { + $tag_type = $matches[1]; + $field_name = $matches[2]; + $format = $matches[3]; + $inner_content = $matches[4]; + + $parts = explode('[tag:if_else]', $inner_content); + $true_content = $parts[0]; + $false_content = $parts[1] ?? ''; + + $field_value = ''; + if (defined('USE_GET_FIELDS') && USE_GET_FIELDS) { + $field_value = htmlspecialchars(get_field($field_name, (int)$this->row->Id), ENT_QUOTES); + } else { + $field_value = htmlspecialchars(request_get_document_field($field_name, (int)$this->row->Id, $format, $this->rubric_id), ENT_QUOTES); + } + + $condition = ($tag_type === 'if_notempty' && $field_value !== '') || ($tag_type === 'if_empty' && $field_value === ''); + + return $condition ? $true_content : $false_content; + }, + $content + ); + + // Затем обрабатываем остальные условные теги + $processed_content = preg_replace_callback( + '/\\[tag:(if_first|if_not_first|if_last|if_not_last|if_every:([0-9-]+)|if_not_every:([0-9-]+))](.*?)\\[tag:\\/if]/s', + function ($matches) { + $tag = $matches[1]; + $inner_content = $matches[4]; + + $parts = explode('[tag:if_else]', $inner_content); + $true_content = $parts[0]; + $false_content = $parts[1] ?? ''; + + $condition = false; + + if ($tag === 'if_first') { + $condition = ($this->item_num === 1); + } elseif ($tag === 'if_not_first') { + $condition = ($this->item_num !== 1); + } elseif ($tag === 'if_last') { + $condition = $this->is_last; + } elseif (strpos($tag, 'if_not_last') === 0) { + $condition = !$this->is_last; + } elseif (strpos($tag, 'if_every') === 0) { + $mod = (int)($matches[2] ?? 0); + $condition = ($this->item_num > 0 && $mod > 0 && ($this->item_num % $mod) === 0); + } elseif (strpos($tag, 'if_not_every') === 0) { + $mod = (int)($matches[3] ?? 0); + $condition = ($this->item_num > 0 && $mod > 0 && ($this->item_num % $mod) !== 0); + } + + return $condition ? $true_content : $false_content; + }, + $processed_content + ); + + return $processed_content; + } +} + +/** + * Функция для обработки тегов с использованием TagProcessor. + * + * @param string $items Строка с тегами. + * @param int $item_num Текущий номер элемента. + * @param bool $is_last Флаг, указывающий, является ли элемент последним. + * @param object $row Объект с данными документа. + * @param int $items_count Общее количество элементов на текущей странице. + * @return string Обработанная строка. + */ +function request_process_tags($items, $item_num, $is_last, $row, $items_count) +{ + // Создаем экземпляр обработчика, передавая общее количество + $processor = new TagProcessor($item_num, $is_last, $row, (int)$row->rubric_id, $items_count); + + // Обрабатываем содержимое и возвращаем результат + return $processor->process($items); +} + +/** + * Достаем настройки запроса + * + * @param string|int $id Идентификатор или псевдоним запроса + * @return object|string Объект с настройками запроса или пустая строка в случае ошибки + */ +function request_get_settings ($id) +{ + global $AVE_DB; + + // Получаем информацию о запросе + $sql = " + SELECT + #REQUEST SETTINGS = " . $id . " + * + FROM + " . PREFIX . "_request + WHERE + " . (is_numeric($id) ? 'Id' : 'request_alias') . " = '" . $id . "' + "; + + // Выполняем запрос с учетом кеширования + $reqest_settings = $AVE_DB->Query($sql, -1, 'rqs_' . $id, true, '.settings')->FetchRow(); + + // Выходим, если нет запроса + if (! is_object($reqest_settings)) + return ''; + else + return $reqest_settings; +} + +/** + * Обработка условий запроса. + * Возвращает строку условий в SQL-формате. + * + * @param int|string $id ID или алиас запроса. + * + * @return string Возвращает строку SQL-условия. + */ +function request_get_condition_sql_string($id) +{ + global $AVE_DB, $AVE_Core; + + // Используем request_get_settings() для получения ID и настроек запроса. + $request_settings = request_get_settings($id); + + // Выходим, если запрос не найден. + if (!is_object($request_settings)) { + return ''; + } + + $from = []; + $where = []; + $retval = ''; + $i = 0; + + if (!defined('ACP')) + { + $doc = 'doc_' . $AVE_Core->curentdoc->Id; + + if (isset($_POST['req_' . $id])) + { + $_SESSION[$doc]['req_' . $id] = $_POST['req_' . $id]; + } + elseif (isset($_SESSION[$doc]['req_' . $id])) + { + $_POST['req_' . $id] = $_SESSION[$doc]['req_' . $id]; + } + } + + // Теперь мы можем безопасно запросить условия, используя гарантированный ID. + $sql_ak = $AVE_DB->Query( + " + SELECT + condition_field_id, + condition_value, + condition_compare, + condition_join + FROM " . PREFIX . "_request_conditions + WHERE + request_id = '" . $request_settings->Id . "' + AND condition_status = '1' + ORDER BY + condition_position ASC; + ", + -1, + 'rqc_' . $request_settings->Id, + true, + '.conditions' + ); + + if (!empty($_POST['req_' . $id]) && is_array($_POST['req_' . $id])) + { + foreach ($_POST['req_' . $id] as $fid => $val) + { + if (!($val != '' && isset($_SESSION['val_' . $fid]) && in_array($val, $_SESSION['val_' . $fid]))) continue; + + if ($i) $from[] = "JOIN " . PREFIX . "_document_fields AS t$i ON t$i.document_id = t0.document_id"; + + $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value = '" . $AVE_DB->Escape($val) . "'"; + + ++$i; + } + } + + while ($row_ak = $sql_ak->FetchRow()) + { + $fid = $row_ak->condition_field_id; + + if (isset($_POST['req_' . $id]) && isset($_POST['req_' . $id][$fid])) continue; + + if ($i) $from[] = "JOIN " . PREFIX . "_document_fields AS t$i ON t$i.document_id = t0.document_id"; + + $val = $row_ak->condition_value; + + switch ($row_ak->condition_compare) + { + case ' <': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value < '" . $AVE_DB->Escape($val) . "'"; break; + case ' >': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value > '" . $AVE_DB->Escape($val) . "'"; break; + case '<=': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value <= '" . $AVE_DB->Escape($val) . "'"; break; + case '>=': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value >= '" . $AVE_DB->Escape($val) . "'"; break; + case '==': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value = '" . $AVE_DB->Escape($val) . "'"; break; + case '!=': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value != '" . $AVE_DB->Escape($val) . "'"; break; + case '%%': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value LIKE '%" . $AVE_DB->Escape($val) . "%'"; break; + case '%': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value LIKE '" . $AVE_DB->Escape($val) . "%'"; break; + case '--': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value NOT LIKE '%" . $AVE_DB->Escape($val) . "%'"; break; + case '!-': $where[] = "t$i.rubric_field_id = " . $fid . " AND t$i.field_value NOT LIKE '" . $AVE_DB->Escape($val) . "%'"; break; + } + + if ($i || $row_ak->condition_join == 'AND') ++$i; + } + + if (!empty($where)) + { + $from = ' FROM ' . PREFIX . '_document_fields AS t0 ' . implode(' ', $from); + $where = ' WHERE ' . (($i) ? implode(' AND ', $where) : '(' . implode(') OR(', $where) . ')'); + $retval = 'AND a.Id = ANY(SELECT t0.document_id' . $from . $where . ')'; + } + + if (defined('ACP')) + { + $AVE_DB->Query(" + UPDATE " . PREFIX . "_request + SET request_where_cond = '" . addslashes($retval) . "' + WHERE Id = '" . $request_settings->Id . "' + "); + } + + return $retval; +} + +/** + * Функция обработки тэгов полей с использованием шаблонов + * в соответствии с типом поля + * + * @param int $rubric_id идентификатор рубрики + * @param int $document_id идентификатор документа + * @param int $maxlength максимальное количество символов обрабатываемого поля + * @return string + */ + function request_get_document_field ($field_id, $document_id, $maxlength = null, $rubric_id = 0) + { + if (! is_numeric($document_id) || $document_id < 1) + return ''; + + $_maxlength = $maxlength; + + $document_fields = get_document_fields($document_id); + + // ToDo + if (! is_array($document_fields[$field_id])) + $field_id = intval($document_fields[$field_id]); + + if (empty($document_fields[$field_id])) + return ''; + + $field_value = trim($document_fields[$field_id]['field_value']); + + if ($field_value == '' && $document_fields[$field_id]['tpl_req_empty']) + return ''; + + $func = 'get_field_' . $document_fields[$field_id]['rubric_field_type']; + + if (! is_callable($func)) + $func = 'get_field_default'; + + $field_value = $func($field_value, 'req', $field_id, $document_fields[$field_id]['rubric_field_template_request'], $document_fields[$field_id]['tpl_req_empty'], $_maxlength, $document_fields, $rubric_id, $document_fields[$field_id]['rubric_field_default']); + + if ($maxlength != '') + { + if ($maxlength == 'more' || $maxlength == 'esc'|| $maxlength == 'img' || $maxlength == 'strip') + { + if ($maxlength == 'more') + { + // ToDo - Вывести в настройки или в настройки самого запроса + $teaser = explode('', $field_value); + $field_value = $teaser[0]; + } + elseif ($maxlength == 'esc') + { + $field_value = addslashes($field_value); + } + elseif ($maxlength == 'img') + { + $field_value = getImgSrc($field_value); + } + elseif ($maxlength == 'strip') + { + $field_value = str_replace(array("\r\n","\n","\r"), " ", $field_value); + $field_value = strip_tags($field_value, REQUEST_STRIP_TAGS); + $field_value = preg_replace('/ +/', ' ', $field_value); + $field_value = trim($field_value); + } + } + elseif (is_numeric($maxlength)) + { + if ($maxlength < 0) + { + $field_value = str_replace(array("\r\n","\n","\r"), " ", $field_value); + $field_value = strip_tags($field_value, REQUEST_STRIP_TAGS); + $field_value = preg_replace('/ +/', ' ', $field_value); + $field_value = trim($field_value); + + $maxlength = abs($maxlength); + } + // ToDo - сделать настройки окончаний = Уже есть в Доп настройках + if ($maxlength != 0) + { + $field_value = truncate($field_value, $maxlength, REQUEST_ETC, REQUEST_BREAK_WORDS); + } + + } + else + return false; + } + + return $field_value; + } + +function showteaser ($id, $tparams = '') + { + $item = showrequestelement($id, '', $tparams); + $item = str_replace('[tag:path]', ABS_PATH, $item); + $item = str_replace('[tag:mediapath]', ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', $item); + + return $item; + } + + // Функция получения уникальных параметров для каждого тизера + function f_params_of_teaser ($id_param_array,$num) + { + global $params_of_teaser; + return $params_of_teaser[$id_param_array][$num]; + } + +// Функция получения элемента запроса +function showrequestelement ($mixed, $template = '', $tparams = '', $req_item_num = null, $items_count = null, $is_last = null) +{ + global + $AVE_DB, + $params_of_teaser, + $use_cache, + $request_id, + $request_changed, + $request_changed_elements; + + if (is_array($mixed)) { + $row = intval($mixed[1]); + } else if (is_numeric($mixed)) { + $row = intval($mixed); + } + + $row = (is_object($mixed) ? $mixed : getDocument($row)); + + unset ($mixed); + + if (! $row) { + return ''; + } + + $tparams_id = ''; + if ($tparams != '') { + $tparams_id = $row->Id . md5($tparams); + $params_of_teaser[$tparams_id] = []; + $tparams = trim($tparams,'[]:'); + $params_of_teaser[$tparams_id] = explode('|',$tparams); + } + + $sql = " + SELECT + rubric_teaser_template + FROM + " . PREFIX . "_rubrics + WHERE + Id = '" . intval($row->rubric_id) . "' + "; + + $template = ($template > '' + ? $template + : $AVE_DB->Query($sql)->GetCell()); + + $hash = 'g-' . UGROUP; + $hash .= 'r-' . $request_id; + $hash .= 't-' . $row->Id; + + if ($req_item_num !== null && $items_count !== null) { + $hash .= 'num-' . $req_item_num; + $hash .= 'total-' . $items_count; + } + + $hash = md5($hash); + + $cache_id = 'requests/elements/' . (floor($row->Id / 1000)) . '/' . $row->Id; + $cachefile_docid = BASE_DIR . '/tmp/cache/sql/' . $cache_id . '/' . $hash . '.element'; + + if (file_exists($cachefile_docid) && isset($use_cache) && $use_cache == 1) { + $check_file = $request_changed_elements; + if ($check_file > filemtime($cachefile_docid)) { + unlink ($cachefile_docid); + } + } else { + if (file_exists($cachefile_docid)) { + unlink ($cachefile_docid); + } + } + + if (defined('DEV_MODE') AND DEV_MODE) { + $cachefile_docid = null; + } + + if (! file_exists($cachefile_docid)) { + $link = rewrite_link('index.php?id=' . $row->Id . '&doc=' . (empty($row->document_alias) ? prepare_url($row->document_title) : $row->document_alias)); + $item = $template; + + // Обработка всех условных тегов через TagProcessor + if ($req_item_num !== null && $items_count !== null) { + $tagProcessor = new TagProcessor($req_item_num, $is_last, $row, (int)$row->rubric_id, $items_count); + $item = $tagProcessor->process($item); + } + + // Парсим теги визуальных блоков + $item = preg_replace_callback('/\[tag:block:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_block', $item); + + // Парсим теги системных блоков + $item = preg_replace_callback('/\[tag:sysblock:([A-Za-z0-9-_]{1,20}+)(|:\{(.*?)\})\]/', + function ($m) { + return parse_sysblock($m[1], $m[2]); + }, + $item); + + // Парсим элементы полей + $item = preg_replace_callback('/\[tag:rfld:([a-zA-Z0-9-_]+)\]\[([0-9]+)]\[([0-9]+)]/', + function ($m) use ($row) { + return get_field_element($m[1], $m[2], $m[3], (int)$row->Id); + }, + $item); + + // Парсим теги полей + $item = preg_replace_callback('/\[tag:rfld:([a-zA-Z0-9-_]+)\]\[(more|esc|img|strip|[0-9-]+)]/', + function ($match) use ($row) { + return request_get_document_field($match[1], (int)$row->Id, $match[2], (int)$row->rubric_id); + }, + $item); + + // Повторно парсим теги полей + $item = preg_replace_callback('/\[tag:rfld:([a-zA-Z0-9-_]+)\]\[(more|esc|img|strip|[0-9-]+)]/', + function ($m) use ($row) { + return request_get_document_field($m[1], (int)$row->Id, $m[2], (int)$row->rubric_id); + }, + $item); + + // Возвращаем поле документа из БД (document_***) + $item = preg_replace_callback('/\[tag:doc:([a-zA-Z0-9-_]+)\]/u', + function ($m) use ($row) { + return isset($row->{$m[1]}) ? $row->{$m[1]} : null; + }, + $item + ); + + // Если пришел вызов на активацию языковых файлов + $item = preg_replace_callback( + '/\[tag:langfile:([a-zA-Z0-9-_]+)\]/u', + function ($m) { + global $AVE_Template; + return $AVE_Template->get_config_vars($m[1]); + }, + $item + ); + + // Абсолютный путь + $item = str_replace('[tag:path]', ABS_PATH, $item); + + // Путь к папке шаблона + $item = str_replace('[tag:mediapath]', ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', $item); + + // Watermarks + $item = preg_replace_callback('/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', + function ($m) { + watermarks($m[1], $m[2], $m[3]); + }, + $item); + + // Удаляем ошибочные теги полей документа и языковые, в шаблоне рубрики + $item = preg_replace('/\[tag:doc:\d*\]/', '', $item); + $item = preg_replace('/\[tag:langfile:\d*\]/', '', $item); + + // Делаем линки на миниатюры + $item = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $item); + + // Если был вызов тизера, ищем параметры + if ($tparams != '') { + $item = preg_replace_callback('/\[tparam:([0-9]+)\]/', + function ($m) use ($tparams_id) { + return f_params_of_teaser($tparams_id, $m[1]); + }, + $item); + } else { + $item = preg_replace('/\[tparam:([0-9]+)\]/', '', $item); + } + + $item = str_replace('[tag:domain]', getSiteUrl(), $item); + $item = str_replace('[tag:link]', $link, $item); + $item = str_replace('[tag:docid]', $row->Id, $item); + $item = str_replace('[tag:itemid]', $row->Id, $item); + $item = str_replace('[tag:docitemnum]', $req_item_num, $item); + $item = str_replace('[tag:adminlink]', 'index.php?do=docs&action=edit&rubric_id=' . $row->rubric_id . '&Id=' . $row->Id . '&cp=' . session_id() . '', $item); + $item = str_replace('[tag:doctitle]', stripslashes(htmlspecialchars_decode($row->document_title)), $item); + $item = str_replace('[tag:docparent]', $row->document_parent, $item); + $item = str_replace('[tag:doclang]', $row->document_lang, $item); + $item = str_replace('[tag:docdate]', translate_date(strftime(DATE_FORMAT, $row->document_published)), $item); + $item = str_replace('[tag:doctime]', translate_date(strftime(TIME_FORMAT, $row->document_published)), $item); + $item = str_replace('[tag:humandate]', human_date($row->document_published), $item); + + $item = preg_replace_callback('/\[tag:date:([a-zA-Z0-9-. \/]+)\]/', + function ($m) use ($row) { + return translate_date(date($m[1], $row->document_published)); + }, + $item); + + if (preg_match('/\[tag:docauthor]/u', $item)) { + $item = str_replace('[tag:docauthor]', get_username_by_id($row->document_author_id), $item); + } + + $item = str_replace('[tag:docauthorid]', $row->document_author_id, $item); + + $item = preg_replace_callback('/\[tag:docauthoravatar:(\d+)\]/', + function ($m) use ($row) { + return getAvatar(intval($row->document_author_id), $m[1]); + }, + $item); + + if (isset($use_cache) && $use_cache == 1) { + if (! file_exists(dirname($cachefile_docid))) { + @mkdir(dirname($cachefile_docid), 0777, true); + } + file_put_contents($cachefile_docid, $item); + } + } else { + $item = file_get_contents($cachefile_docid); + } + + // Кол-во просмотров + $item = str_replace('[tag:docviews]', $row->document_count_view, $item); + + Registry::remove('documents', $row->Id); + Registry::remove('fields', $row->Id); + Registry::remove('fields_param', $row->Id); + + unset($row, $template); + + return $item; +} + +/** + * Парсинг запроса + * + * @param int|string $id Идентификатор или псевдоним запроса + * @return string + */ +function request_parse($id) +{ + global $AVE_Core, $AVE_DB, $request_documents; + + // Начальная проверка ID + if (is_array($id)) { + $id = $id[1]; + } + + // Получаем информацию о запросе. Эта функция должна создать .settings файл + $request = request_get_settings($id); + + // Выходим, если запрос не найден + if (!is_object($request)) { + return ''; + } + + // Фиксируем время начала генерации запроса + Debug::startTime('request_' . $id); + + // Инициализация переменных из настроек запроса + $limit = ($request->request_items_per_page < 1) ? 1 : $request->request_items_per_page; + $main_template = $request->request_template_main; + $item_template = $request->request_template_item; + $request_order_by = $request->request_order_by; + $request_order_by_nat = intval($request->request_order_by_nat); + $request_asc_desc = $request->request_asc_desc; + + // Генерируем строку условий + $where_cond = request_get_condition_sql_string($request->Id); + $where_cond = str_replace('%%PREFIX%%', PREFIX, $where_cond); + + // Динамическое формирование WHERE-части запросов + $where_common = " + a.Id != '1' + AND a.Id != '" . PAGE_NOT_FOUND_ID . "' + AND a.rubric_id = '" . (int)$request->rubric_id . "' + AND a.document_deleted != '1' + AND a.document_status != '0' + " . $hide_current_condition . " + " . $owner_condition . " + " . $lang_condition . " + " . $where_cond . " + " . $doctime . " + "; + + // Определение частей запроса в зависимости от наличия модуля комментариев и нативной сортировки + $join_comment = !empty($AVE_Core->install_modules['comment']->Status) + ? "LEFT JOIN " . PREFIX . "_modul_comment_info AS b ON b.document_id = a.Id" + : ""; + $select_comment_count = !empty($AVE_Core->install_modules['comment']->Status) + ? ", COUNT(b.document_id) AS nums" + : ""; + $group_by_doc_id = !empty($AVE_Core->install_modules['comment']->Status) + ? "GROUP BY a.Id" + : ""; + + if ($request_order_by_nat != 0) { + $join_fields = "LEFT JOIN " . PREFIX . "_document_fields AS d ON a.Id = d.document_id"; + $where_fields = "AND d.rubric_field_id = " . intval($request_order_by_nat); + $select_fields = ", d.field_value, d.rubric_field_id"; + $order_by = "ORDER BY d.field_value " . ($request_asc_desc === 'DESC' ? 'DESC' : 'ASC'); + } else { + $join_fields = ""; + $where_fields = ""; + $select_fields = ""; + $order_by = "ORDER BY " . $request_order_by . " " . $request_asc_desc; + } + + $num_items = 0; + $num_pages = 0; + $start = 0; + + // Условное выполнение запроса для подсчета общего количества элементов + if ($request->request_show_pagination == 1 || $request->request_count_items == 1) { + // Формируем запрос для подсчета количества элементов + $count_sql = " + SELECT COUNT(*) + FROM " . PREFIX . "_documents AS a + " . $join_fields . " + WHERE + " . $where_common . " + " . $where_fields . " + "; + + // Получаем общее количество элементов, используя кеширование + $num_items = $AVE_DB->Query($count_sql, (int)$request->request_cache_lifetime, 'rqs_' . $id, true, '.count')->GetCell(); + } + + // Если пагинация включена, вычисляем количество страниц и начальную позицию + if ($request->request_show_pagination == 1) { + $num_pages = ceil($num_items / $limit); + $start = get_current_page('page') * $limit - $limit; + } + + // Формируем финальный запрос для выборки данных + $main_sql_query = " + SELECT + a.Id, + a.document_title, + a.document_alias, + a.document_parent, + a.document_author_id, + a.document_count_view, + a.document_published, + a.document_lang + " . $select_comment_count . " + " . $select_fields . " + FROM + " . PREFIX . "_documents AS a + " . $join_comment . " + " . $join_fields . " + WHERE + " . $where_common . " + " . $where_fields . " + " . $group_by_doc_id . " + " . $order_by . " + LIMIT " . $start . "," . $limit . " + "; + + // Отладочный вывод SQL-запроса, если это необходимо + if ($request->request_show_sql == 1) { + $return = Debug::_print($main_sql_query); + return $return; + } + + // Выполняем запрос с кешированием, создавая файл .request + Debug::startTime('SQL'); + $q = $AVE_DB->Query($main_sql_query, (int)$request->request_cache_lifetime, 'rqs_' . $id, true, '.request'); + $GLOBALS['block_generate']['REQUESTS'][$id]['SQL'] = Debug::endTime('SQL'); + + $rows = array(); + $request_documents = array(); + while ($row = $q->FetchRow()) { + array_push($request_documents, $row->Id); + array_push($rows, $row); + } + + // Условное отображение контента + if ($q->NumRows() > 0) { + $main_template = preg_replace('/\[tag:if_empty](.*?)\[\/tag:if_empty]/si', '', $main_template); + $main_template = str_replace(array('[tag:if_notempty]','[/tag:if_notempty]'), '', $main_template); + } else { + $main_template = preg_replace('/\[tag:if_notempty](.*?)\[\/tag:if_notempty]/si', '', $main_template); + $main_template = str_replace(array('[tag:if_empty]','[/tag:if_empty]'), '', $main_template); + } + + // Формирование пагинации + $pagination = ''; + if ($request->request_show_pagination == 1 && $num_pages > 1) { + @$GLOBALS['page_id'][$_REQUEST['id']]['page'] = (isset($GLOBALS['page_id'][$_REQUEST['id']]['page']) && $GLOBALS['page_id'][$_REQUEST['id']]['page'] > $num_pages) ? @$GLOBALS['page_id'][$_REQUEST['id']]['page'] : $num_pages; + $queries = ($request->request_use_query == 1 || (isset($params['ADD_GET']) && $params['ADD_GET'] == 1)) ? ((isset($_SERVER['QUERY_STRING'])) ? '?' . $_SERVER['QUERY_STRING'] : '') : ''; + $pagination_base = 'index.php?id=' . $AVE_Core->curentdoc->Id . '&doc=' . (empty($AVE_Core->curentdoc->document_alias) ? prepare_url($AVE_Core->curentdoc->document_title) : $AVE_Core->curentdoc->document_alias) . '&page={s}'; + $pagination_params = ((isset($_REQUEST['artpage']) && is_numeric($_REQUEST['artpage'])) ? '&artpage=' . $_REQUEST['artpage'] : '') . ((isset($_REQUEST['apage']) && is_numeric($_REQUEST['apage'])) ? '&apage=' . $_REQUEST['apage'] : ''); + $pagination_full = $pagination_base . $pagination_params . clean_php($queries); + $pagination_id = (isset($params['PAGINATION']) && $params['PAGINATION'] > 0) ? $params['PAGINATION'] : $request->request_pagination; + $pagination = AVE_Paginations::getPagination($num_pages, 'page', $pagination_full, $pagination_id); + + // Костыли для главной страницы + $pagination = str_ireplace('"//"', '"/"', str_ireplace('///', '/', rewrite_link($pagination))); + $pagination = str_ireplace('"//' . URL_SUFF . '"', '"/"', $pagination); + if ($request->request_use_query == 1 || (isset($params['ADD_GET']) && $params['ADD_GET'] == 1)) { + $pagination = preg_replace('/(?request_cache_elements; + + $request_id = $request->Id; + + $request_changed = $request->request_changed; + $request_changed_elements = $request->request_changed_elements; + + Debug::startTime('ELEMENTS_ALL'); + + foreach ($rows as $row) { + $x++; + $last_item = ($x == $items_count); + $req_item_num = $x; + + // Передаем элемент для обработки и кэширования в showrequestelement. + $items .= showrequestelement($row, $item_template, '', $req_item_num, $items_count, $last_item); + } + + $GLOBALS['block_generate']['REQUESTS'][$id]['ELEMENTS']['ALL'] = Debug::endTime('ELEMENTS_ALL'); + + // Обработка основного шаблона + $main_template = str_replace('[tag:pages]', $pagination, $main_template); + $main_template = str_replace('[tag:docid]', $AVE_Core->curentdoc->Id, $main_template); + $main_template = str_replace('[tag:pagetitle]', stripslashes(htmlspecialchars_decode($AVE_Core->curentdoc->document_title)), $main_template); + $main_template = str_replace('[tag:pages:curent]', get_current_page('page'), $main_template); + $main_template = str_replace('[tag:pages:total]', $num_pages, $main_template); + $main_template = str_replace('[tag:doctotal]', $num_items, $main_template); + $main_template = str_replace('[tag:doconpage]', $x, $main_template); + $main_template = str_replace('[tag:docdate]', pretty_date(strftime(DATE_FORMAT, $AVE_Core->curentdoc->document_published)), $main_template); + $main_template = str_replace('[tag:doctime]', pretty_date(strftime(TIME_FORMAT, $AVE_Core->curentdoc->document_published)), $main_template); + $main_template = str_replace('[tag:docauthor]', get_username_by_id($AVE_Core->curentdoc->document_author_id), $main_template); + $main_template = preg_replace_callback('/\[tag:dropdown:([,0-9]+)\]/', function($m) use ($request) { + return request_get_dropdown($m[1], (int)$request->rubric_id, (int)$request->Id); + }, $main_template); + $main_template = preg_replace_callback('/\[tag:date:([a-zA-Z0-9-. \/]+)\]/', function ($match) use ($AVE_Core) { + return translate_date(date($match[1], $AVE_Core->curentdoc->document_published)); + }, $main_template); + $main_template = preg_replace_callback('/\[tag:langfile:([a-zA-Z0-9-_]+)\]/u', function ($match) { + global $AVE_Template; + return $AVE_Template->get_config_vars($match[1]); + }, $main_template); + $main_template = preg_replace_callback('/\[tag:sysblock:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_sysblock', $main_template); + $main_template = preg_replace_callback('/\[tag:block:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_block', $main_template); + + $return = str_replace('[tag:content]', $items, $main_template); + $return = str_replace('[tag:path]', ABS_PATH, $return); + $return = str_replace('[tag:mediapath]', ABS_PATH . 'templates/' . THEME_FOLDER . '/', $return); + $return = $AVE_Core->coreModuleTagParse($return); + + // Фиксируем время генерации запроса + $GLOBALS['block_generate']['REQUESTS'][$id]['TIME'] = Debug::endTime('request_' . $id); + + if ($request->request_show_statistic) { + $return .= "

      Найдено: $num_items
      Показано: $items_count
      Время генерации: " . Debug::endTime('request_' . $id) . " сек
      Пиковое значение: " . number_format(memory_get_peak_usage() / 1024, 0, ',', ' ') . ' Kb
      '; + } + + return $return; +} + +/** + * Функция получения содержимого поля для обработки в шаблоне запроса + *
      + * Пример использования в шаблоне:
      + *   
    36. + * + *
    37. + *
      + * + * @param int $rubric_id идентификатор поля, для [tag:rfld:12][150] $rubric_id = 12 + * @param int $document_id идентификатор документа к которому принадлежит поле. + * @param int $maxlength необязательный параметр, количество возвращаемых символов. + * Если данный параметр указать со знаком минус + * содержимое поля будет очищено от HTML-тэгов. + * @return string + */ +function request_get_document_field_value($rubric_id, $document_id, $maxlength = 0) +{ + if (!is_numeric($rubric_id) || $rubric_id < 1 || !is_numeric($document_id) || $document_id < 1) return ''; + + $document_fields = get_document_fields($document_id); + + $field_value = isset($document_fields[$rubric_id]) ? $document_fields[$rubric_id]['field_value'] : ''; + + if (!empty($field_value)) + { + $field_value = strip_tags($field_value, '

      '); + $field_value = str_replace('[tag:mediapath]', ABS_PATH . 'templates/' . THEME_FOLDER . '/', $field_value); + } + + if (is_numeric($maxlength) && $maxlength != 0) + { + if ($maxlength < 0) + { + $field_value = str_replace(array("\r\n", "\n", "\r"), ' ', $field_value); + $field_value = strip_tags($field_value); + $field_value = preg_replace('/ +/', ' ', $field_value); + $maxlength = abs($maxlength); + } + $field_value = substr($field_value, 0, $maxlength) . (strlen($field_value) > $maxlength ? '... ' : ''); + } + + return $field_value; +} + +/** + * Функция формирования выпадающих списков + * для управления условиями запроса в публичной части + * + * @param string $dropdown_ids идентификаторы полей + * типа выпадающий список указанные через запятую + * @param int $rubric_id идентификатор рубрики + * @param int $request_id идентификатор запроса + * @return string + */ +function request_get_dropdown($dropdown_ids, $rubric_id, $request_id) +{ + global $AVE_Core, $AVE_DB, $AVE_Template; + + // Получаем настройки запроса + $request_settings = request_get_settings($request_id); + + if (!is_object($request_settings)) { + return ''; + } + + $dropdown_ids = explode(',', preg_replace('/[^,\\d]/', '', $dropdown_ids)); + $dropdown_ids[] = 0; + $dropdown_ids = implode(',', $dropdown_ids); + $doc = 'doc_' . $AVE_Core->curentdoc->Id; + $control = array(); + + // Для кеширования, используем $request_id в качестве уникального идентификатора. + $sql = $AVE_DB->Query( + " + SELECT + Id, + rubric_field_title, + rubric_field_default + FROM " . PREFIX . "_rubric_fields + WHERE Id IN(" . $dropdown_ids . ") + AND rubric_id = '" . $rubric_id . "' + AND rubric_field_type = 'drop_down' + ", -1, 'rqs_' . $request_id, true, '.dropdown'); + + while ($row = $sql->FetchRow()) + { + $dropdown['titel'] = $row->rubric_field_title; + $dropdown['selected'] = isset($_SESSION[$doc]['req_' . $request_id][$row->Id]) ? $_SESSION[$doc]['req_' . $request_id][$row->Id] : ''; + $dropdown['options'] = $_SESSION['val_' . $row->Id] = explode(',', $row->rubric_field_default); + $control[$row->Id] = $dropdown; + } + + $AVE_Template->assign('request_id', $request_id); + $AVE_Template->assign('ctrlrequest', $control); + return $AVE_Template->fetch(BASE_DIR . '/templates/' . THEME_FOLDER . '/tpl/request/public.tpl'); +} + +?> \ No newline at end of file diff --git a/functions/func.rubrics.php b/functions/func.rubrics.php new file mode 100644 index 0000000..a6a841a --- /dev/null +++ b/functions/func.rubrics.php @@ -0,0 +1,53 @@ +Query($query); + + $rubrics = []; + + while ($row = $sql->FetchAssocArray()) + $rubrics[$row['Id']] = $row; + + if ($cache_file) + file_put_contents($cache_file, serialize($rubrics)); + } + + Registry::set('rubric_changes', $rubrics); + + return Registry::get('rubric_changes'); + } +?> \ No newline at end of file diff --git a/functions/func.sysblock.php b/functions/func.sysblock.php new file mode 100644 index 0000000..fe25ba0 --- /dev/null +++ b/functions/func.sysblock.php @@ -0,0 +1,193 @@ +Query(" + SELECT + sysblock_text + FROM + " . PREFIX . "_sysblocks + WHERE + " . (is_numeric($id) ? 'id' : 'sysblock_alias') . " = '" . $id . "' + LIMIT 1 + ")->GetCell(); + + if ($cache_file) + file_put_contents($cache_file, $return); + } + + //-- парсим теги + $search = array( + '[tag:mediapath]', + '[tag:path]', + '[tag:docid]' + ); + + $replace = array( + ABS_PATH . 'templates/' . ((defined('THEME_FOLDER') === false) ? DEFAULT_THEME_FOLDER : THEME_FOLDER) . '/', + ABS_PATH, + get_current_document_id() + ); + + $return = str_replace($search, $replace, $return); + + $return = preg_replace_callback('/\[tag:home]/', 'get_home_link', $return); + $return = preg_replace_callback('/\[tag:breadcrumb]/', 'get_breadcrumb', $return); + $return = preg_replace_callback('/\[tag:request:([A-Za-z0-9-_]{1,20}+)\]/', 'request_parse', $return); + + if (isset($_REQUEST['id']) && $_REQUEST['id'] != '') + { + //-- парсим теги полей документа в шаблоне рубрики + $return = preg_replace_callback('/\[tag:fld:([a-zA-Z0-9-_]+)\]\[([0-9]+)]\[([0-9]+)]/', 'get_field_element', $return); + $return = preg_replace_callback('/\[tag:fld:([a-zA-Z0-9-_]+)(|[:(\d)])+?\]/', 'document_get_field', $return); + $return = preg_replace_callback('/\[tag:watermark:(.+?):([a-zA-Z]+):([0-9]+)\]/', 'watermarks', $return); + $return = preg_replace_callback('/\[tag:([r|c|f|t|s]\d+x\d+r*):(.+?)]/', 'callback_make_thumbnail', $return); + } + + $return = preg_replace_callback('/\[tag:block:([A-Za-z0-9-_]{1,20}+)\]/', 'parse_block', $return); + + // Парсим теги системных блоков + $return = preg_replace_callback('/\[tag:sysblock:([A-Za-z0-9-_]{1,20}+)(|:\{(.*?)\})\]/', + function ($m) + { + return parse_sysblock($m[1], $m[2]); + }, + $return); + + // Если был вызов + if ($sysParams != '') + { + // Заменяем + $return = preg_replace_callback('/\[sys:param:([A-Za-z0-9-+_]+)\]/', + function ($m) use ($sparams_id) + { + return params_of_sysblocks($sparams_id, $m[1]); + }, + $return); + } + else + { + // Если чистый запрос тизера, просто вытираем tparam + $return = preg_replace('/\[sysparam:([A-Za-z0-9-+_]+)\]/', '', $return); + } + + if ($sysblock_eval) + $return = eval2var('?'.'>' . $return . '<'.'?php '); + + $GLOBALS['block_generate']['SYSBLOCK'][$id] = Debug::endTime('SYSBLOCK_' . $id); + + return $return; + } + + return false; + } + + + /** + * Функция получения уникальных параметров для каждого + * + * @param $id + * @param $el + * @return string + */ + function params_of_sysblocks($id, $el) + { + global $sysParams; + + if (isset($sysParams[$id][$el])) + return $sysParams[$id][$el]; + else + return false; + } + + + /** + * Получение основных настроек сисблока + * + * @param $param string параметр настройки, если не указан - все параметры + * @return mixed + */ + function _getSysBlock($id, $param = '') + { + global $AVE_DB; + + $sys_block = null; + + if ($sys_block === null) + { + $sql = " + SELECT + * + FROM + " . PREFIX . "_sysblocks + WHERE + " . (is_numeric($id) ? 'id' : 'sysblock_alias') . " = '" . $id . "' + "; + + $sys_block = $AVE_DB->Query($sql, -1, 'sysblocks/' . $id)->FetchAssocArray(); + } + + if ($param == '') + return $sys_block; + + return isset($sys_block[$param]) + ? $sys_block[$param] + : null; + } +?> \ No newline at end of file diff --git a/functions/func.thumbnails.php b/functions/func.thumbnails.php new file mode 100644 index 0000000..853f8ca --- /dev/null +++ b/functions/func.thumbnails.php @@ -0,0 +1,97 @@ + + |

    38. link - путь к оригиналу
    39. + |
    40. size - размер миниатюры
    41. + | + | + | make_thumbnail(array('link' => URL, 'size' => SIZE)); + | + | @return string + */ + function make_thumbnail ($params) + { + if (empty($params['link'])) + return false; + + if ((strpos($params['link'], '/http://') === 0 || strpos($params['link'], '/https://') === 0)) + { + $md5 = md5($params['link']); + + $path = BASE_DIR . ABS_PATH . UPLOAD_DIR . '/ext/' . substr($md5, 0, 4); + + if (! is_dir($path)) + { + if (! is_dir(dirname($path))) + mkdir(dirname($path), 0777, true); + + mkdir($path, 0777, true); + } + + $link = ABS_PATH . UPLOAD_DIR . '/ext/' . substr($md5, 0, 4) . '/' . $md5 . '.jpg'; + + if (! file_exists(BASE_DIR . $link)) + file_put_contents(BASE_DIR . $link . '.tmp', $params['link']); + + $params['link'] = $link; + } + + if (isset($params['size'])) + { + $size = $params['size']; + + if (! preg_match('/^[r|c|f|t|s]\d+x\d+r*$/', $size)) + return false; + } + else + { + $size = 't128x128'; + } + + $nameParts = explode('.', basename($params['link'])); + + $countParts = count($nameParts); + + if ($countParts < 2) + return false; + + $nameParts[$countParts-2] .= '-' . $size; + + return dirname($params['link']) . '/' . THUMBNAIL_DIR . '/' . implode('.', $nameParts); + } + + + /* + |---------------------------------------------------------------------------------- + | Формирование ссылки на миниатюру определённого размера + |---------------------------------------------------------------------------------- + | @param array $params - параметры + | + | @return string + */ + function callback_make_thumbnail ($params) + { + return ((is_array($params) && isset($params[2])) + ? make_thumbnail(array('size' => $params[1], 'link' => $params[2])) + : ''); + } +?> \ No newline at end of file diff --git a/functions/func.users.php b/functions/func.users.php new file mode 100644 index 0000000..00d2421 --- /dev/null +++ b/functions/func.users.php @@ -0,0 +1,262 @@ +user_name); + + $avatar = (file_exists(BASE_DIR . $avatar . '.jpg') + ? $avatar . '.jpg' + : (file_exists(BASE_DIR . $avatar . '.png') + ? $avatar . '.png' + : (file_exists(BASE_DIR . $avatar .'.gif') + ? $avatar . '.gif' + : ''))); + + $result[$id] = $avatar; + } + + $avatar = $result[$id]; + + $src = (file_exists(BASE_DIR . $avatar) + ? make_thumbnail(array('link' => $avatar,'size' => 'c' . $size . 'x' . $size)) + : make_thumbnail(array('link' => $AVE_DB->Query("SELECT default_avatar FROM " . PREFIX . "_user_groups WHERE user_group=" . (int)$user->user_group)->GetCell(), 'size' => 'c' . $size . 'x' . $size)) + ); + + return $src; + } + + + /** + * Устанавливаем аватар пользователю + * + * @param int $id Ид пользователя + * @param string $avatar путь до картинки которая будет аватаром + * @return bool установился аватар или нет + */ + function SetAvatar($id, $avatar) + { + if (! $avatar) + return false; + + if ($id === null) + $id = $_SESSION['user_id']; + + $user = get_user_rec_by_id($id); + + $file_ext = pathinfo($avatar, PATHINFO_EXTENSION); + + if (! $file_ext) + $file_ext = 'jpg'; + + if (! file_exists($avatar)) + return false; + + $new_avatar = BASE_DIR . '/' . UPLOAD_DIR . '/avatars/' . md5($user->user_name) . '.' . strtolower($file_ext); + + foreach (glob(BASE_DIR . '/' . UPLOAD_DIR . '/avatars/' . md5($user->user_name) . '.*') AS $filename) + @unlink($filename); + + //Чистим превьюшки + foreach (glob(BASE_DIR . '/' . UPLOAD_DIR . '/avatars/' . THUMBNAIL_DIR . '/' . md5($user->user_name) . '*.*') AS $filename) + @unlink($filename); + + @file_put_contents($new_avatar, file_get_contents($avatar)); + @unlink($avatar); + + return true; + } + + + /** + * Формирование строки имени пользователя + * При наличии всех параметров пытается сформировать строку Имя Фамилия + * Если задать $short=1 - формирует короткую форму И. Фамилия + * Когда отсутствует информация о Имени или Фамилии пытается сформировать + * строку на основе имеющихся данных, а если данных нет вообще - выводит + * имя анонимного пользователя которое задается в основных настройках системы. + * + * @todo добавить параметр 'anonymous' в настройки + * + * @param string $login логин пользователя + * @param string $first_name имя пользователя + * @param string $last_name фамилия пользователя + * @param int $short {0|1} признак формирования короткой формы + * @return string + */ + function get_username ($login = '', $first_name = '', $last_name = '', $short = 1) + { + if ($first_name != '' && $last_name != '') + { + if ($short == 1) + $first_name = mb_substr($first_name, 0, 1, 'utf-8') . '.'; + + return ucfirst_utf8(mb_strtolower($first_name)) . ' ' . ucfirst_utf8(mb_strtolower($last_name)); + } + elseif ($first_name != '' && $last_name == '') + { + return ucfirst_utf8(mb_strtolower($first_name)); + } + elseif ($first_name == '' && $last_name != '') + { + return ucfirst_utf8(mb_strtolower($last_name)); + } + elseif ($login != '') + { + return $login; + } + + return 'Anonymous'; + } + + + /** + * Возвращает запись для пользователя по идентификатору + * не делает лишних запросов + * + * @param int $id - идентификатор пользователя + * @return object + */ + function get_user_rec_by_id($id) + { + global $AVE_DB; + + static $users = array(); + + if (! isset($users[$id])) + { + $row = $AVE_DB->Query(" + SELECT + * + FROM " . PREFIX . "_users + WHERE Id = '" . (int)$id . "' + ")->FetchRow(); + + $users[$id] = $row; + } + + return $users[$id]; + } + + + /** + * Возвращает параметры группы пользователей по идентификатору + * не делает лишних запросов + * + * @param int $id - идентификатор группы + * @return object + */ + function get_usergroup_rec_by_id($id) + { + global $AVE_DB; + + static $usergroups = array(); + + if (! isset($usergroups[$id])) + { + $row = $AVE_DB->Query(" + SELECT + * + FROM " . PREFIX . "_user_groups + WHERE user_group = '" . (int)$id . "' + ")->FetchRow(); + + $usergroups[$id] = $row; + } + + return $usergroups[$id]; + + } + + + /** + * Возвращает login пользователя по его идентификатору + * + * @param int $id - идентификатор пользователя + * @return string + */ + function get_userlogin_by_id($id) + { + $rec = get_user_rec_by_id($id); + + return $rec->user_name; + } + + + /** + * Возвращает имя группы пользователя по его идентификатору + * + * @param int $id - идентификатор группы пользователя + * @return string + */ + function get_usergroup_by_id($id) + { + $rec = get_usergroup_rec_by_id($id); + + return $rec->user_group_name; + } + + + /** + * Возвращает email пользователя по его идентификатору + * + * @param int $id - идентификатор пользователя + * @return string + */ + function get_useremail_by_id($id) + { + $rec = get_user_rec_by_id($id); + + return $rec->email; + } + + + /** + * Возвращает имя пользователя по его идентификатору + * + * @param int $id - идентификатор пользователя + * @param int $param - Сокрашать имя (1 - да, 0 - нет) + * + * @return string + */ + function get_username_by_id($id, $param = 1) + { + $row = get_user_rec_by_id($id); + $row = (! empty($row)) + ? get_username($row->user_name, $row->firstname, $row->lastname, $param) + : get_username(); + + return $row; + } + +?> \ No newline at end of file diff --git a/functions/func.watermarks.php b/functions/func.watermarks.php new file mode 100644 index 0000000..2a87a7e --- /dev/null +++ b/functions/func.watermarks.php @@ -0,0 +1,224 @@ +> 8) . chr($length & 0xFF); + } + else + { + $retval .= chr(0x80) . + chr(0x04) . + chr(($length >> 24) & 0xFF) . + chr(($length >> 16) & 0xFF) . + chr(($length >> 8) & 0xFF) . + chr($length & 0xFF); + } + + return $retval . $value; + } + } + + + /** + * Функция накладывает watermark на заданный файл + * + * @param string $file URL Файла + * @param string $position Позиция + * @param int $transparency Прозарчность + * @return string link + */ + function watermarks ($file, $position='center', $transparency=100) + { + if (! defined('WATERMARKS_DIR') || ! defined('WATERMARKS_FILE')) + return $file; + + $save = true; + + $margin = 10; + + $file_info = pathinfo($file); + + $watermarkFile = BASE_DIR . '/' . WATERMARKS_FILE; + $watermarkDir = BASE_DIR . '/' . WATERMARKS_DIR; + + $imagePath = BASE_DIR . '/' . trim($file_info['dirname'], '/'); + $imageName = $file_info['basename']; + + $copyPath = $watermarkDir . '/' . trim($file_info['dirname'], '/'); + $copyName = $imageName; + + if (file_exists($watermarkDir . $file)) + return $file; + + if (! is_dir($watermarkDir)) + { + @mkdir($watermarkDir, 0777, true); + write_htaccess_deny($watermarkDir); + } + + if (file_exists("$copyPath/$copyName") || !file_exists("$imagePath/$imageName")) + $save = false; + + if (file_exists($watermarkFile) && file_exists("$imagePath/$imageName")) + { + $size_image = getimagesize("$imagePath/$imageName"); + $size_wtmrk = getimagesize($watermarkFile); + + list($xImage, $yImage) = $size_image; + list($xWtmrk, $yWtmrk) = $size_wtmrk; + + if ($xImage < $xWtmrk || $yImage < $yWtmrk) + $save = false; + else + $save = true; + } + + if (file_exists("$copyPath/$copyName")) + $save = false; + + if ($save) + { + if (! is_dir($copyPath) && !@mkdir($copyPath, 0777, true)) + return $file; + + require_once BASE_DIR.'/class/class.thumbnail.php'; + + $watermark = new Image_Toolbox("$imagePath/$imageName"); + + if (rename("$imagePath/$imageName", "$copyPath/$copyName")) + { + $old = umask(0); + chmod("$copyPath/$copyName", 0777); + umask($old); + } + + switch ($position) + { + case 'top': + case 'topcenter': + $xLogoPosition = 'center -'; + $yLogoPosition = 'top +'.$margin; + break; + + case 'topleft': + $xLogoPosition = 'left +'.$margin; + $yLogoPosition = 'top +'.$margin; + break; + + case 'topright': + $xLogoPosition = 'right -'.$margin; + $yLogoPosition = 'top +'.$margin; + break; + + case 'center': + $xLogoPosition = 'center -'; + $yLogoPosition = 'center -'; + break; + + case 'centerleft': + $xLogoPosition = 'left +'.$margin; + $yLogoPosition = 'center -'; + break; + + case 'centerright': + $xLogoPosition = 'right -'.$margin; + $yLogoPosition = 'center -'; + break; + + case 'bottom': + case 'bottomcenter': + $xLogoPosition = 'center -'; + $yLogoPosition = 'bottom -'.$margin; + break; + + case 'bottomleft': + $xLogoPosition = 'left +'.$margin; + $yLogoPosition = 'bottom -'.$margin; + break; + + case 'bottomright': + $xLogoPosition = 'right -'.$margin; + $yLogoPosition = 'bottom -'.$margin; + break; + + case 'repeat': + $xLogoPosition = 'repeat '; + $yLogoPosition = 'repeat '; + break; + + default: + $xLogoPosition = 'center -'; + $yLogoPosition = 'center -'; + break; + } + + $watermark->addImage($watermarkFile); + $watermark->blend($xLogoPosition, $yLogoPosition, IMAGE_TOOLBOX_BLEND_COPY, $transparency); + $watermark->save("$imagePath/$imageName"); + + if ($watermark->_img['main']['type'] == 2) + { + // $image = getimagesize("$imagePath/$imageName", $info); Not used + + if (! isset($info['APP13'])) + { + $sitename = get_settings('site_name'); + + // установка IPTC тэгов + $iptc = array( + '2#120' => iconv("UTF-8","WINDOWS-1251",$sitename), + '2#116' => "http://".$_SERVER['SERVER_NAME'] + ); + + // Преобразование IPTC тэгов в двоичный код + $data = ''; + + foreach ($iptc AS $tag => $string) + { + $tag = substr($tag, 2); + $data .= iptc_make_tag(2, $tag, $string); + } + + // Встраивание IPTC данных + $content = iptcembed($data, "$imagePath/$imageName"); + + // запись нового изображения в файл + $fp = fopen("$imagePath/$imageName", "wb"); + fwrite($fp, $content); + fclose($fp); + } + } + + unset($watermark); + } + + return $file; + } +?> \ No newline at end of file diff --git a/inc/antispam.php b/inc/antispam.php new file mode 100644 index 0000000..f9c1e8b --- /dev/null +++ b/inc/antispam.php @@ -0,0 +1,77 @@ + \ No newline at end of file diff --git a/inc/captcha.php b/inc/captcha.php new file mode 100644 index 0000000..d388f56 --- /dev/null +++ b/inc/captcha.php @@ -0,0 +1,25 @@ +getKeyString(); +?> \ No newline at end of file diff --git a/inc/config.php b/inc/config.php new file mode 100644 index 0000000..b4f2cb1 --- /dev/null +++ b/inc/config.php @@ -0,0 +1,614 @@ +Ave-Cms.Ru '.'© 2007-' . date('Y')); + + $themes = []; + + foreach (glob(dirname(dirname(__FILE__)) . '/templates/*') AS $filename) + if (is_dir($filename)) + $themes[] = basename($filename); + + unset ($filename); + + $codemirror = [ + 'default', + '3024-day', + '3024-night', + 'abcdef', + 'ambiance', + 'base16-dark', + 'base16-light', + 'bespin', + 'blackboard', + 'cobalt', + 'colorforth', + 'dracula', + 'duotone-dark', + 'duotone-light', + 'eclipse', + 'elegant', + 'erlang-dark', + 'hopscotch', + 'icecoder', + 'isotope', + 'lesser-dark', + 'liquibyte', + 'material', + 'mbo', + 'mdn-like', + 'midnight', + 'monokai', + 'neat', + 'neo', + 'night', + 'panda-syntax', + 'paraiso-dark', + 'paraiso-light', + 'pastel-on-dark', + 'railscasts', + 'rubyblue', + 'seti', + 'solarized', + 'the-matrix', + 'tomorrow-night-bright', + 'tomorrow-night-eighties', + 'ttcn', + 'twilight', + 'vibrant-ink', + 'xq-dark', + 'xq-light', + 'yeti', + 'zenburn' + ]; + + /* ======================================================================================================== */ + + //-- Использовать IP для автологина на сайте + $GLOBALS['CMS_CONFIG']['_CONST_AUTH']['USER_IP'] = [ + 'DESCR' => 'Следить за IP при автологине на сайте', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Использовать IP для автологина на сайте + $GLOBALS['CMS_CONFIG']['_CONST_AUTH']['ADMIN_CAPTCHA'] = [ + 'DESCR' => 'Использовать CAPTCHA при входе в панель управления', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Использовать ЧПУ Адреса вида index.php будут преобразованы в /home + $GLOBALS['CMS_CONFIG']['_CONST_URL']['REWRITE_MODE'] = [ + 'DESCR' => 'Использовать ЧПУ Адреса вида index.php будут преобразованы в /home', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Cуффикс ЧПУ, к примеру .html + $GLOBALS['CMS_CONFIG']['_CONST_URL']['URL_SUFF'] = [ + 'DESCR' => 'Cуффикс ЧПУ, к примеру .html', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Использовать транслит в ЧПУ адреса вида /страница/ поменяються на /stranica/ + $GLOBALS['CMS_CONFIG']['_CONST_URL']['TRANSLIT_URL'] = [ + 'DESCR' => 'Использовать транслит в ЧПУ адреса вида /страница поменяються на /stranica', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + // Тема публичной части + $GLOBALS['CMS_CONFIG']['_CONST_THEMES']['DEFAULT_THEME_FOLDER'] = [ + 'DESCR' => 'Тема публичной части', + 'DEFAULT' => $themes[0], + 'TYPE' => 'dropdown', + 'VARIANT' => $themes + ]; + + // Тема панели администратора + $GLOBALS['CMS_CONFIG']['_CONST_THEMES']['DEFAULT_THEME_FOLDER_COLOR'] = [ + 'DESCR' => 'Тема панели администратора', + 'DEFAULT' => 'default', + 'TYPE' => 'dropdown', + 'VARIANT' => ['default'] + ]; + + // Цветовая схема Codemirror + $GLOBALS['CMS_CONFIG']['_CONST_THEMES']['CODEMIRROR_THEME'] = [ + 'DESCR' => 'Цветовая схема Codemirror', + 'DEFAULT' => 'dracula', + 'TYPE' => 'dropdown', + 'VARIANT' => $codemirror + ]; + + //-- Использовать плавающее боковое меню + $GLOBALS['CMS_CONFIG']['_CONST_THEMES']['ADMIN_MENU'] = [ + 'DESCR' => 'Использовать плавающее боковое меню', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Показывать меню в шапке с действиями + $GLOBALS['CMS_CONFIG']['_CONST_THEMES']['ADMIN_MENU_QUICK_ADD'] = [ + 'DESCR' => 'Показывать меню в шапке с действиями', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Использовать всплывающие "Действия" в системе + $GLOBALS['CMS_CONFIG']['_CONST_THEMES']['ADMIN_EDITMENU'] = [ + 'DESCR' => 'Использовать всплывающие "Действия" в системе', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Директория для хранения вложений + $GLOBALS['CMS_CONFIG']['_CONST_FOLDERS']['ATTACH_DIR'] = [ + 'DESCR' => 'Директория для хранения вложений /tmp/XXX', + 'DEFAULT' => 'attachments', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Директория для хранения вложений + $GLOBALS['CMS_CONFIG']['_CONST_FOLDERS']['UPLOAD_DIR'] = [ + 'DESCR' => 'Директория для хранения вложений /XXX', + 'DEFAULT' => 'uploads', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Директория для хранения миниатюр Галерей /UPLOAD_DIR/XXX + $GLOBALS['CMS_CONFIG']['_CONST_FOLDERS']['UPLOAD_GALLERY_DIR'] = [ + 'DESCR' => 'Директория для хранения миниатюр Галерей /UPLOAD_DIR/XXX', + 'DEFAULT' => 'uploads/gallery', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Директория для хранения миниатюр изображений /UPLOAD_DIR/XXX + $GLOBALS['CMS_CONFIG']['_CONST_THUMBS']['THUMBNAIL_DIR'] = [ + 'DESCR' => 'Директория для хранения миниатюр изображений /UPLOAD_DIR/XXX', + 'DEFAULT' => 'th', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Разрешенные методы и размеры для миниатюр (через запятую) + $GLOBALS['CMS_CONFIG']['_CONST_THUMBS']['THUMBNAIL_SIZES'] = [ + 'DESCR' => 'Разрешенные методы и размеры для миниатюр (через запятую)', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Качество сжатие JPG миниатюр + $GLOBALS['CMS_CONFIG']['_CONST_THUMBS']['JPG_QUALITY'] = [ + 'DESCR' => 'Качество сжатие JPG миниатюр', + 'DEFAULT' => 90, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + //-- Создавать progressive JPG + $GLOBALS['CMS_CONFIG']['_CONST_THUMBS']['JPG_PROGRESSIVE'] = [ + 'DESCR' => 'Создавать progressive JPG', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Генерировать миниатюрам IPTC + $GLOBALS['CMS_CONFIG']['_CONST_THUMBS']['THUMBNAIL_IPTC'] = [ + 'DESCR' => 'Генерировать миниатюрам IPTC', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Отдавать браузеру, что нужно кешировать изображение (60*60*24*14 - 2 недели) + $GLOBALS['CMS_CONFIG']['_CONST_THUMBS']['THUMBNAIL_CACHE_LIFETIME'] = [ + 'DESCR' => 'Отдавать браузеру, что нужно кешировать изображение (60*60*24*14 - 2 недели)', + 'DEFAULT' => 60*60*24*14, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Директория для хранения оригиналов изображений (watermark) + $GLOBALS['CMS_CONFIG']['_CONST_WATERMARKS']['WATERMARKS_DIR'] = [ + 'DESCR' => 'Директория для хранения оригиналов изображений (watermark) /XXX', + 'DEFAULT' => 'source', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Файл watermark + $GLOBALS['CMS_CONFIG']['_CONST_WATERMARKS']['WATERMARKS_FILE'] = [ + 'DESCR' => 'Файл watermark /UPLOAD_DIR/XXX', + 'DEFAULT' => 'watermark.png', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Метод хранение сессий + $GLOBALS['CMS_CONFIG']['_CONST_SESSIONS']['SESSION_SAVE_HANDLER'] = [ + 'DESCR' => 'Метод хранение сессий', + 'DEFAULT' => 'mysql', + 'TYPE' => 'dropdown', + 'VARIANT' => ['mysql', 'files', 'memcached'] + ]; + + //-- Время жизни сессии (60*60*24 - 24 часа) + $GLOBALS['CMS_CONFIG']['_CONST_SESSIONS']['SESSION_LIFETIME'] = [ + 'DESCR' => 'Время жизни сессии (60*60*24 - 24 часа)', + 'DEFAULT' => 60*60*24, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + //-- Время жизни cookie для автологина (60*60*24*14 - 2 недели) + $GLOBALS['CMS_CONFIG']['_CONST_SESSIONS']['COOKIE_LIFETIME'] = [ + 'DESCR' => 'Время жизни cookie для автологина (60*60*24*14 - 2 недели)', + 'DEFAULT' => 60*60*24*14, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Режим разработчика (Отключает кеширование SQL запросов в системе) + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['DEV_MODE'] = [ + 'DESCR' => 'Режим разработчика (Отключает кеширование SQL запросов в системе)', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Вывод общей статистики публичной части + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['PROFILING'] = [ + 'DESCR' => 'Вывод общей статистики публичной части', + 'DEFAULT' => 'off', + 'TYPE' => 'dropdown', + 'VARIANT' => ['off', 'light', 'full', 'dev'] + ]; + + //-- Вывод общей статистики в административной части + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['PROFILING_ADMIN'] = [ + 'DESCR' => 'Вывод общей статистики в административной части', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Собирать статистику выполненных запросов + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['SQL_PROFILING'] = [ + 'DESCR' => 'Собирать статистику выполненных SQL запросов', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Включить стандартную обработку ошибок PHP + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['PHP_DEBUGGING'] = [ + 'DESCR' => 'Включить стандартную обработку ошибок PHP', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Включить обработку ошибок PHP через обработчик cms + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['PHP_DEBUGGING_FILE'] = [ + 'DESCR' => 'Включить обработку ошибок PHP через обработчик системы', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Отправка писем с ошибками MySQL + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['SEND_SQL_ERROR'] = [ + 'DESCR' => 'Отправка писем с ошибками MySQL', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Принудительно проверять SQL запросы + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['SQL_QUERY_SANITIZE'] = [ + 'DESCR' => 'Принудительно проверять SQL запросы', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Пытаться очистить память если выходит за пределы ("-1" выключенно) в Мегабайтах (увеличивается нагрузка на MySQL) + $GLOBALS['CMS_CONFIG']['_CONST_DEV']['MEMORY_LIMIT_PANIC'] = [ + 'DESCR' => 'Пытаться очистить память если выходит за пределы ("-1" выключенно) в Мегабайтах (увеличивается нагрузка на MySQL)', + 'DEFAULT' => -1, + 'TYPE' => 'dropdown', + 'VARIANT' => ['-1','6','12','28','54','100'] + ]; + + /* ======================================================================================================== */ + + //-- Консоль отладки Smarty + $GLOBALS['CMS_CONFIG']['_CONST_SMARTY']['SMARTY_DEBUGGING'] = [ + 'DESCR' => 'Консоль отладки Smarty', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Контролировать изменения tpl файлов После настройки сайта установить - false + $GLOBALS['CMS_CONFIG']['_CONST_SMARTY']['SMARTY_COMPILE_CHECK'] = [ + 'DESCR' => 'Контролировать изменения tpl файлов После настройки сайта установить - false', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Создание папок для кэширования Установите это в false если ваше окружение PHP не разрешает создание директорий от имени Smarty. Поддиректории более эффективны, так что используйте их, если можете. + $GLOBALS['CMS_CONFIG']['_CONST_SMARTY']['SMARTY_USE_SUB_DIRS'] = [ + 'DESCR' => 'Создание папок для кэширования Установите это в false если ваше окружение PHP не разрешает создание директорий от имени Smarty. Поддиректории более эффективны, так что используйте их, если можете.', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Кэширование скомпилированных шаблонов документов + $GLOBALS['CMS_CONFIG']['_CONST_CACHE']['CACHE_DOC_TPL'] = [ + 'DESCR' => 'Кэширование скомпилированных шаблонов документов', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Кэширование информацию о документе и его полях + $GLOBALS['CMS_CONFIG']['_CONST_CACHE']['CACHE_DOC_FILE'] = [ + 'DESCR' => 'Кэширование информацию о документе и его полях', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Кэширование всей страницы + $GLOBALS['CMS_CONFIG']['_CONST_CACHE']['CACHE_DOC_FULL'] = [ + 'DESCR' => 'Кэширование всей страницы', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Кэширование всей страницы (для админа) + $GLOBALS['CMS_CONFIG']['_CONST_CACHE']['CACHE_DOC_FULL_ADMIN'] = [ + 'DESCR' => 'Кэширование всей страницы (для админа)', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Кэширование информацию о документе и его полях + $GLOBALS['CMS_CONFIG']['_CONST_CACHE']['SITEMAP_CACHE_LIFETIME'] = [ + 'DESCR' => 'Время жизни кеша для карты сайта', + 'DEFAULT' => 0, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Включить html компрессию + $GLOBALS['CMS_CONFIG']['_CONST_COMPRESSION']['HTML_COMPRESSION'] = [ + 'DESCR' => 'Включить html компрессию', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Включить gzip компрессию + $GLOBALS['CMS_CONFIG']['_CONST_COMPRESSION']['GZIP_COMPRESSION'] = [ + 'DESCR' => 'Включить gzip компрессию', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Отдавать заголовок на кеширование страницы + $GLOBALS['CMS_CONFIG']['_CONST_COMPRESSION']['OUTPUT_EXPIRE'] = [ + 'DESCR' => 'Отдавать заголовок на кеширование страницы', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Время жизни кеширования страницы (60*60 - 1 час) + $GLOBALS['CMS_CONFIG']['_CONST_COMPRESSION']['OUTPUT_EXPIRE_OFFSET'] = [ + 'DESCR' => 'Время жизни кеширования страницы (60*60 - 1 час)', + 'DEFAULT' => 0, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Адрес Memcached сервера + $GLOBALS['CMS_CONFIG']['_CONST_MEMCACHED']['MEMCACHED_SERVER'] = [ + 'DESCR' => 'Адрес Memcached сервера', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Порт Memcached сервера + $GLOBALS['CMS_CONFIG']['_CONST_MEMCACHED']['MEMCACHED_PORT'] = [ + 'DESCR' => 'Порт Memcached сервера', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Окончание в полях запроса + $GLOBALS['CMS_CONFIG']['_CONST_REQUEST']['REQUEST_ETC'] = [ + 'DESCR' => 'Окончание в полях запроса', + 'DEFAULT' => '...', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Разбивать слова при выводе полей в запросе + $GLOBALS['CMS_CONFIG']['_CONST_REQUEST']['REQUEST_BREAK_WORDS'] = [ + 'DESCR' => 'Разбивать слова при выводе полей в запросе', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- При - у поля, оставляем теги в результате + $GLOBALS['CMS_CONFIG']['_CONST_REQUEST']['REQUEST_STRIP_TAGS'] = [ + 'DESCR' => 'При - (минус) у поля, оставлять html теги в результате', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Создание резервной копии базы данных со сжатием + $GLOBALS['CMS_CONFIG']['_CONST_DATABASE']['DB_EXPORT_GZ'] = [ + 'DESCR' => 'Создание резервной копии базы данных со сжатием .gz', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Использовать префикс при экспорте бд + $GLOBALS['CMS_CONFIG']['_CONST_DATABASE']['DB_EXPORT_PREFIX'] = [ + 'DESCR' => 'Использовать префикс при экспорте бд', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Шаблон имени файла экспорта бд (%SERVER%,%DATE%,%TIME%) + $GLOBALS['CMS_CONFIG']['_CONST_DATABASE']['DB_EXPORT_TPL'] = [ + 'DESCR' => 'Шаблон имени файла экспорта бд (%SERVER%, %DATE%, %TIME%)', + 'DEFAULT' => '%SERVER%_DB_BackUP_%DATE%_%TIME%', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + /* ======================================================================================================== */ + + //-- Yandex MAP API KEY + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['YANDEX_MAP_API_KEY'] = [ + 'DESCR' => 'Yandex MAP API KEY', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Google MAP API KEY + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['GOOGLE_MAP_API_KEY'] = [ + 'DESCR' => 'Google MAP API KEY', + 'DEFAULT' => '', + 'TYPE' => 'string', + 'VARIANT' => '' + ]; + + //-- Показывать кто был онлайн в течении: (Значение по умолчанию 24 часа) + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['USERS_TIME_SHOW'] = [ + 'DESCR' => 'Показывать кто был онлайн в течении: (Значение по умолчанию 24 часа)', + 'DEFAULT' => 60*60*24, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + //-- Использовать проверку в полях на пусто, только исходные данные, исключая шаблон поля + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['USE_GET_FIELDS'] = [ + 'DESCR' => 'Использовать, проверку в полях на "пусто", только исходные данные, исключая шаблон поля', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Использовать статитчное хранение полей в памяти + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['USE_STATIC_DATA'] = [ + 'DESCR' => 'Использовать статитчное хранение в памяти, данных документа и полей', + 'DEFAULT' => true, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Шифровать сериализованные кешированные данные + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['USE_ENCODE_SERIALIZE'] = [ + 'DESCR' => 'Шифровать сериализованные кешированные данные', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + //-- Кол-во дней для хранения системных событий + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['LOG_DAYS_LIMIT'] = [ + 'DESCR' => 'Кол-во дней для хранения системных событий', + 'DEFAULT' => 14*60*24*14, + 'TYPE' => 'integer', + 'VARIANT' => '' + ]; + + //-- Проверка наличия новых версий + $GLOBALS['CMS_CONFIG']['_CONST_OTHER']['CHECK_VERSION'] = [ + 'DESCR' => 'Проверка наличия новых версий', + 'DEFAULT' => false, + 'TYPE' => 'bool', + 'VARIANT' => '' + ]; + + unset ($themes, $codemirror); + + if (file_exists(dirname(dirname(__FILE__)) . '/config/config.inc.php')) + include_once(dirname(dirname(__FILE__)) . '/config/config.inc.php'); + + foreach ($GLOBALS['CMS_CONFIG'] AS $key => $const) + foreach ($const AS $k => $v) + if(! defined($k)) + define($k, $v['DEFAULT']); + + unset ($key, $const, $k, $v); +?> \ No newline at end of file diff --git a/inc/dump.php b/inc/dump.php new file mode 100644 index 0000000..32c42fa --- /dev/null +++ b/inc/dump.php @@ -0,0 +1,30 @@ + + + + +Plupload - Form dump + + + +

      Post dump

      + + + + + + + + + + + $value) { ?> + + + + + + +
      NameValue
      + + + diff --git a/inc/errors.php b/inc/errors.php new file mode 100644 index 0000000..3df046f --- /dev/null +++ b/inc/errors.php @@ -0,0 +1,104 @@ +%s

      Message: %s
      File: %s
      Line: %s + ', $error_level, nl2br($error_message), $error_file, $error_line); + + switch ($error_level) { + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_PARSE: + $color = '#f05050'; + errorLogs($error, "Fatal", $color); + break; + case E_USER_ERROR: + case E_RECOVERABLE_ERROR: + $color = '#f05050'; + errorLogs($error, "Error", $color); + break; + case E_WARNING: + case E_CORE_WARNING: + case E_COMPILE_WARNING: + case E_USER_WARNING: + $color = '#fad733'; + errorLogs($error, "Warning", $color); + break; + case E_NOTICE: + case E_USER_NOTICE: + $color = '#23b7e5'; + errorLogs($error, "Info", $color); + break; + case E_STRICT: + $color = '#edf1f2'; + errorLogs($error, "Debug", $color); + break; + default: + $color = '#fad733'; + errorLogs($error, "Warning", $color); + } + } + + function shutdownHandler() + { + $lasterror = error_get_last(); + + switch ($lasterror['type']) + { + case E_ERROR: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + case E_RECOVERABLE_ERROR: + case E_CORE_WARNING: + case E_COMPILE_WARNING: + case E_PARSE: + $color = '#f05050'; + $error = + sprintf(' + [SHUTDOWN] Lvl: %s
      Message: %s
      File: %s
      Line: %s + ', $lasterror['type'], nl2br($lasterror['message']), $lasterror['file'], $lasterror['line']); + errorLogs($error, "Fatal", $color); + } + } + + function errorLogs($error, $errlvl, $color) + { + $render = ' +
      +
      + ' . $errlvl .' +
      +
      ' + . $error . + '
      +
      + '; + + echo $render; + } +?> \ No newline at end of file diff --git a/inc/fonts/ft16.ttf b/inc/fonts/ft16.ttf new file mode 100644 index 0000000..d2f8b67 Binary files /dev/null and b/inc/fonts/ft16.ttf differ diff --git a/inc/index.php b/inc/index.php new file mode 100644 index 0000000..cab759a --- /dev/null +++ b/inc/index.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/inc/init.php b/inc/init.php new file mode 100644 index 0000000..a840c29 --- /dev/null +++ b/inc/init.php @@ -0,0 +1,448 @@ + 1, + '_GET' => 1, + '_POST' => 1, + '_COOKIE' => 1, + '_FILES' => 1, + '_SERVER' => 1, + '_REQUEST' => 1, + 'GLOBALS' => 1 + ]; + + foreach ($GLOBALS AS $key => $value) + { + if (! isset($allowed[$key])) + unset($GLOBALS[$key]); + } + } + + $_GET = add_slashes($_GET); + $_POST = add_slashes($_POST); + $_REQUEST = array_merge($_POST, $_GET); + $_COOKIE = add_slashes($_COOKIE); + + unsetGlobals(); + + if (isset($HTTP_POST_VARS)) + { + $_GET = $HTTP_GET_VARS; + $_POST = $HTTP_POST_VARS; + $_REQUEST = array_merge($_POST, $_GET); + $_COOKIE = $HTTP_COOKIE_VARS; + } + +/** + * Слешевание (для глобальных массивов) + * рекурсивно обрабатывает вложенные массивы + * + * @param mixed $array обрабатываемый массив или строка + * @return mixed обработанный массив или строка + */ +function add_slashes($array) +{ + // Если не массив, но строка, просто добавляем слеши и возвращаем + if (!is_array($array)) { + return addslashes($array); + } + + // Если это массив, обрабатываем его рекурсивно + @reset($array); + foreach ($array as $_k => $_v) + { + if (is_string($_v)) + $array[$_k] = addslashes($_v); + elseif (is_array($_v)) + $array[$_k] = add_slashes($_v); + } + + return $array; +} + + function isSSL() + { + if (isset($_SERVER['HTTPS'])) + { + if ('on' == strtolower($_SERVER['HTTPS'])) + return true; + + if ('1' == $_SERVER['HTTPS']) + return true; + } + elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) + { + return true; + } + + return false; + } + + + function setHost() + { + if (isset($_SERVER['HTTP_HOST'])) + { + // Все символы $_SERVER['HTTP_HOST'] приводим к строчным и проверяем + // на наличие запрещённых символов в соответствии с RFC 952 и RFC 2181. + $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']); + + if (! preg_match('/^\[?(?:[a-z0-9-:\]_]+\.?)+$/', $_SERVER['HTTP_HOST'])) + { + // $_SERVER['HTTP_HOST'] не соответствует спецификациям. + // Возможно попытка взлома, даём отлуп статусом 400. + header('HTTP/1.1 400 Bad Request'); + exit; + } + } + else + { + $_SERVER['HTTP_HOST'] = ''; + } + + $ssl = isSSL(); + $schema = ($ssl) ? 'https://' : 'http://'; + $host = str_replace(':' . $_SERVER['SERVER_PORT'], '', $_SERVER['HTTP_HOST']); + $port = ($_SERVER['SERVER_PORT'] == '80' || $_SERVER['SERVER_PORT'] == '443' || $ssl) + ? '' + : ':' . $_SERVER['SERVER_PORT']; + + define('HOST', $schema . $host . $port); + + $abs_path = dirname((!strstr($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_NAME']) && (@php_sapi_name() == 'cgi')) + ? $_SERVER['PHP_SELF'] + : $_SERVER['SCRIPT_NAME']); + + if (defined('ACP')) + $abs_path = dirname($abs_path); + + define('ABS_PATH', rtrim(str_replace("\\", "/", $abs_path), '/') . '/'); + } + + setHost(); + + set_include_path (get_include_path() . '/' . BASE_DIR . '/lib'); + + ini_set ('arg_separator.output', '&'); + ini_set ('session.cache_limiter', 'none'); + ini_set ('session.cookie_lifetime', 60*60*24*14); + ini_set ('session.gc_maxlifetime', 60*24); + ini_set ('session.use_cookies', 1); + ini_set ('session.use_only_cookies', 1); + ini_set ('session.use_trans_sid', 0); + ini_set ('url_rewriter.tags', ''); + + if (SESSION_SAVE_HANDLER == 'memcached') + { + ini_set ('session.lazy_write', 0); + ini_set ('session.save_handler', 'memcached'); + ini_set ('session.save_path', MEMCACHED_SERVER.':'.MEMCACHED_PORT . '?persistent=1&weight=1&timeout=1&retry_interval=15'); + } + + //-- Переключение для нормальной работы с русскими буквами в некоторых функциях + mb_internal_encoding("UTF-8"); + + //-- Подкючаем необходимые файлы функций + require_once (BASE_DIR . '/functions/func.breadcrumbs.php'); // Хлебные крошки + require_once (BASE_DIR . '/functions/func.common.php'); // Основные функции + require_once (BASE_DIR . '/functions/func.locale.php'); // Языковые функции + require_once (BASE_DIR . '/functions/func.rubrics.php'); // Функции по работе с рубриками + require_once (BASE_DIR . '/functions/func.documents.php'); // Функции по работе с документами + require_once (BASE_DIR . '/functions/func.fields.php'); // Функции по работе с полями + require_once (BASE_DIR . '/functions/func.helpers.php'); // Второстепенные функции + require_once (BASE_DIR . '/functions/func.hidden.php'); // Парс тега [hide] + require_once (BASE_DIR . '/functions/func.login.php'); // Авторизация пользователей + require_once (BASE_DIR . '/functions/func.logs.php'); // Системные сообщения + require_once (BASE_DIR . '/functions/func.mail.php'); // Отправка писем + require_once (BASE_DIR . '/functions/func.navigation.php'); // Функции по работе с меню навигации + require_once (BASE_DIR . '/functions/func.pagination.php'); // Постраничная навигация + require_once (BASE_DIR . '/functions/func.parserequest.php'); // Функции по работе с запросами + require_once (BASE_DIR . '/functions/func.block.php'); // Функции по работе с визуальными блоками + require_once (BASE_DIR . '/functions/func.sysblock.php'); // Функции по работе с системными блоками + require_once (BASE_DIR . '/functions/func.thumbnails.php'); // Функции по работе с превьюшками изображений + require_once (BASE_DIR . '/functions/func.users.php'); // Функции по работе с пользователями + require_once (BASE_DIR . '/functions/func.watermarks.php'); // Функции по работе с водными знаками + + //-- Logs Class + require(BASE_DIR . '/class/class.logs.php'); + + + //-- Создание папок и файлов + foreach ([ATTACH_DIR, 'cache', 'backup', 'logs', 'session', 'update'] AS $dir) + write_htaccess_deny(BASE_DIR . '/tmp/' . $dir); + + foreach (['combine', 'module', 'redactor', 'smarty', 'sql', 'tpl'] AS $dir) + write_htaccess_deny(BASE_DIR . '/tmp/cache/' . $dir); + + //-- Шаблоны + write_htaccess_deny(BASE_DIR . '/templates/' . DEFAULT_THEME_FOLDER . '/include/'); + + global $AVE_DB; + + //-- Класс для работы с MySQL (Global $AVE_DB) + require_once (BASE_DIR . '/class/class.database.php'); + + //-- Если не существует объекта по работе с БД + if (! isset($AVE_DB)) + { + //-- Подключаем конфигурационный файл с параметрами подключения + require_once (BASE_DIR . '/config/db.config.php'); + + //-- Если параметры не указаны, прерываем работу + if (! isset($config) OR empty($config)) + die('No database config'); + + //-- Если константа префикса таблиц не задана, принудительно определяем ее на основании параметров в файле db.config.php + if (! defined('PREFIX')) + define('PREFIX', $config['dbpref']); + + //-- Создаем объект для работы с БД + try { + $AVE_DB = AVE_DB::getInstance($config) + //-- Назначаем кодировку + ->setCharset('utf8') + //-- Назначаем БД + ->setDatabaseName($config['dbname']) + //-- SQL Mode + ->setSqlMode(); + } + catch (AVE_DB_Exception $e) + { + ob_start(); + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + header('Retry-After: 3600'); + header('X-Powered-By:'); + echo $e->getMessage(); + die; + } + + unset ($config); + } + + //-- Устанавливаем обновления системы + if ($AVE_DB) + { + $updaters = (glob(BASE_DIR . '/tmp/update/*.update.php')); + + if ($updaters) + { + sort ($updaters); + + foreach ($updaters as $ufile) + { + @eval(' ?'.'>' . @file_get_contents($ufile) . 'Query(" + UPDATE + " . PREFIX . "_users + SET + last_visit = '" . time() . "' + WHERE + Id = '" . intval($_SESSION['user_id']) . "' + "); + } + + //-- Запоминаем язык браузера + $browlang = $_SERVER['HTTP_ACCEPT_LANGUAGE']; + $browlang = explode('-', $browlang); + $browlang = $browlang[0]; + + $_SESSION['accept_langs'] = array(); + + $sql = " + SELECT + # LANGS + * + FROM + " . PREFIX . "_settings_lang + WHERE + lang_status = '1' + ORDER BY + lang_default ASC + "; + + $query = $AVE_DB->Query($sql, -1, 'langs', true, '.langs'); + + while ($row = $query->FetchRow()) + { + if (trim($row->lang_key) > '') + { + $_SESSION['accept_langs'][trim($row->lang_key)] = trim($row->lang_alias_pref); + + if (! @defined('DEFAULT_LANGUAGE') && $row->lang_default == 1) + define('DEFAULT_LANGUAGE', trim($row->lang_key)); + } + } + + //-- Язык пользователя + $_SESSION['user_language'] = (! empty($_SESSION['user_language']) + ? $_SESSION['user_language'] + :(isset($_SESSION['accept_langs'][$browlang]) + ? $browlang + : DEFAULT_LANGUAGE)); + + define('DATE_FORMAT', get_settings('date_format')); + define('TIME_FORMAT', get_settings('time_format')); + define('PAGE_NOT_FOUND_ID', (int)get_settings('page_not_found_id')); + + //-- Вывод данных документа без общего шаблона + if (isset($_REQUEST['onlycontent']) && 1 == $_REQUEST['onlycontent']) + define('ONLYCONTENT', 1); + + //-- Язык системы + set_locale(); + + //-- Класс Шаблонов SMARTY + require (BASE_DIR . '/class/class.template.php'); + + //-- Класс пагинации + require (BASE_DIR . '/class/class.paginations.php'); + + // Класс UTM + require (BASE_DIR . '/class/class.utm.php'); + $AVE_Utm = new UTMCookie; + + $AVE_Utm->save_parameters(); + + //-- Класс Модулей + require (BASE_DIR . '/class/class.modules.php'); + $AVE_Module = AVE_Module::init(); +?> \ No newline at end of file diff --git a/inc/rss.php b/inc/rss.php new file mode 100644 index 0000000..01f75dd --- /dev/null +++ b/inc/rss.php @@ -0,0 +1,141 @@ +Query(" + SELECT + rss.*, + rubric_title + FROM + " . PREFIX . "_module_rss AS rss + LEFT JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = rss.rss_rubric_id + WHERE + rss.id = '" . $_GET['id'] . "' +")->FetchRow(); + +if ($rss_settings !== false) +{ + $rss_settings->rss_site_name = htmlspecialchars($rss_settings->rss_site_name, ENT_QUOTES); + $rss_settings->rss_site_description = htmlspecialchars($rss_settings->rss_site_description, ENT_QUOTES); + + $doctime = get_settings('use_doctime') + ? ("AND document_published <= " . time() . " AND (document_expire = 0 OR document_expire >= " . time() . ")") : ''; + + // Получаем ID, URL и Дату публикации для документов, которые соответсвуют нашей рубрики + // Количество выборки ограничиваем значением установленным для канала + $sql_doc = $AVE_DB->Query(" + SELECT + Id, + document_title, + document_alias, + document_published + FROM " . PREFIX . "_documents + WHERE Id != 1 + AND Id != '" . PAGE_NOT_FOUND_ID . "' + AND rubric_id = '" . $rss_settings->rss_rubric_id . "' + AND document_status = '1' + AND document_deleted != '1' + " . $doctime . " + ORDER BY document_published DESC, Id DESC + LIMIT " . $rss_settings->rss_item_on_page + ); + + // Формируем массивы, которые будут хранить инфу + $rss_item = array(); + $rss_items = array(); + + // Выполянем обработку полученных из БД данных + while ($row_doc = $sql_doc->FetchRow()) + { + $sql_fields = $AVE_DB->Query(" + SELECT + rubric_field_id, + field_value + FROM " . PREFIX . "_document_fields + WHERE document_id = '" . $row_doc->Id . "' + AND (rubric_field_id = '" . $rss_settings->rss_title_id . "' + OR rubric_field_id = '" . $rss_settings->rss_description_id . "') + "); + while ($row_fields = $sql_fields->FetchRow()) + { + if ($row_fields->rubric_field_id == $rss_settings->rss_title_id) + { + $rss_item['Title'] = $row_fields->field_value; + } + + if ($row_fields->rubric_field_id == $rss_settings->rss_description_id) + { + if ($rss_settings->rss_description_lenght == 0) + { + $teaser = explode('', $row_fields->field_value); + $rss_item['description'] = $teaser[0]; + } + else + { + if (mb_strlen($row_fields->field_value) > $rss_settings->rss_description_lenght) + { + $rss_item['description'] = mb_substr($row_fields->field_value, 0, $rss_settings->rss_description_lenght) . '…'; + } + else + { + $rss_item['description'] = $row_fields->field_value; + } + } + $rss_item['description'] = parse_hide($rss_item['description']); + } + } + + $link_doc = !empty($row_doc->document_alias) ? $row_doc->document_alias : prepare_url($row_doc->document_title); + $link = rewrite_link('index.php?id=' . $row_doc->Id . '&doc=' . $link_doc); + $rss_item['link'] = $rss_settings->rss_site_url . mb_substr($link, mb_strlen(ABS_PATH)); + + $rss_item['pubDate'] = $row_doc->document_published ? date('r', $row_doc->document_published) : date('r', time()); + + array_push($rss_items, $rss_item); + } +} + +// Ну а тут собственно шлем заголовок, что у нас документ XML и в путь... выводим данные +header("Content-Type: application/xml"); +header("Cache-Control: no-cache"); +header("Pragma: no-cache"); +echo ''; +?> + + + +<?php echo $rss_settings->rss_site_name; ?> +rss_site_url; ?> +ru-ru +rss_site_description; ?> +rubric_title; ?>]]> +AVE.cms + + + <![CDATA[<?php echo $rss_item['Title']; ?>]]> + + + ]]> + + + + + diff --git a/inc/sitemap.php b/inc/sitemap.php new file mode 100644 index 0000000..cc16fc6 --- /dev/null +++ b/inc/sitemap.php @@ -0,0 +1,193 @@ + UNIX_TIMESTAMP()' + : ''; + + // Начало + $_start = 0; + // Конец + $_end = 2000; + + // Часть + $parts = 1; + + $changefreq = array( + '0' => 'always', + '1' => 'hourly', + '2' => 'daily', + '3' => 'weekly', + '4' => 'monthly', + '5' => 'yearly', + '6' => 'never' + ); + + if (! isset($_REQUEST['id'])): + + // Вытаскиваем кол-во документов + $sql = " + SELECT STRAIGHT_JOIN + COUNT(doc.Id) AS count + FROM + " . PREFIX . "_documents AS doc + LEFT JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = doc.rubric_id + LEFT JOIN + " . PREFIX . "_rubric_templates AS tmpl + ON tmpl.rubric_id = rub.Id + LEFT JOIN + " . PREFIX . "_rubric_permissions AS rubperm + ON rubperm.rubric_id = rub.Id + WHERE + # Не пустой шаблон + (rub.rubric_template NOT LIKE '' OR tmpl.template NOT LIKE '') + # Статус документа = 1 + AND doc.document_status = 1 + # Документ не удален + AND doc.document_deleted = 1 + $publish + # Документ не равен 1 + AND doc.Id != 1 + # Документ не равен 404 ошибке + AND doc.Id != " . PAGE_NOT_FOUND_ID . " + # Документы разрешены для индексации + AND (document_meta_robots NOT LIKE '%noindex%' or document_meta_robots NOT LIKE '%nofollow%') + # Разрешены для просмотра гостям + AND (rubperm.user_group_id = 2 AND rubperm.rubric_permission LIKE '%docread%') + "; + + $num = $AVE_DB->Query($sql, SITEMAP_CACHE_LIFETIME, 'sitemap')->GetCell(); + + if ($num > $_end) + $parts = ceil($num/$_end); + + header ('Content-type: text/xml'); + + echo '' . PHP_EOL; + echo '' . PHP_EOL; + + for ($i = 1; $i <= $parts; $i++): +?> + + + + +'; + else: +?> + 1) + $_start = ((int)$_REQUEST['id']-1) * $_end; + + $sql = " + SELECT STRAIGHT_JOIN + doc.Id, + doc.document_alias, + doc.document_published, + doc.document_changed, + doc.document_sitemap_freq, + doc.document_sitemap_pr + FROM + " . PREFIX . "_documents AS doc + LEFT JOIN + " . PREFIX . "_rubrics AS rub + ON rub.Id = doc.rubric_id + LEFT JOIN + " . PREFIX . "_rubric_templates AS tmpl + ON tmpl.rubric_id = rub.Id + LEFT JOIN + " . PREFIX . "_rubric_permissions AS rubperm + ON rubperm.rubric_id = rub.Id + WHERE + # Не пустой шаблон + (rub.rubric_template NOT LIKE '' OR tmpl.template NOT LIKE '') + # Статус документа = 1 + AND doc.document_status = 1 + # Документ не удален + AND doc.document_deleted = 1 + $publish + # Документ не равен 1 + AND doc.Id != 1 + # Документ не равен 404 ошибке + AND doc.Id != " . PAGE_NOT_FOUND_ID . " + # Документы разрешены для индексации + AND (document_meta_robots NOT LIKE '%noindex%' or document_meta_robots NOT LIKE '%nofollow%') + # Разрешены для просмотра гостям + AND (rubperm.user_group_id = 2 AND rubperm.rubric_permission LIKE '%docread%') + GROUP BY doc.Id + ORDER BY doc.document_published ASC + LIMIT ".$_start.",".$_end."; + "; + + $res = $AVE_DB->Query($sql, SITEMAP_CACHE_LIFETIME, 'sitemap', true, '.limit'); + + if (! $res->NumRows() && (int)$_REQUEST['id'] != 1) + { + report404(); + $AVE_DB->clearCurrentCache('sitemap', $sql, '.limit'); + header ($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true); + exit; + } + + header ('Content-type: text/xml'); + + echo '' . PHP_EOL; + echo '' . PHP_EOL; + if ((int)$_REQUEST['id'] == 1): +?> + + + + weekly + 0.8 + + +FetchAssocArray()): + $document_alias = $abs_path . $row['document_alias'] . URL_SUFF; + $document_alias = HOST . str_ireplace($abs_path . '/' . URL_SUFF, '/', $document_alias); + $date = $row["document_published"] ? date("c", $row["document_published"]) : date("c"); +?> + + + + + + + + + \ No newline at end of file diff --git a/inc/stdimage/gear.css b/inc/stdimage/gear.css new file mode 100644 index 0000000..7adc336 --- /dev/null +++ b/inc/stdimage/gear.css @@ -0,0 +1,41 @@ +/** + * @file + * Stylesheet for the Contextual module. + */ + +/** + * Contextual links. + */ +div.contextual-links-wrapper:hover { + background: #F9F9F9; + outline: #EFEFEF dashed 1px; +} +html div.contextual-links-wrapper { + display: block; + position: relative; +} +a.contextual-links-trigger { + display: block; + background: #E0E0E0 url(gear.png) no-repeat 2px 0; + border: 1px solid transparent; + height: 18px; + margin: 0; + padding: 0 2px; + outline: none; + text-indent: 34px; /* LTR */ + width: 20px; + overflow: hidden; + position: absolute; + -khtml-border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + right: 0px; + opacity: 0.7; +} + +a.contextual-links-trigger:hover, +div.contextual-links-active a.contextual-links-trigger { + background: #EFEFEF url(gear.png) no-repeat 2px -18px; +} + diff --git a/inc/stdimage/gear.png b/inc/stdimage/gear.png new file mode 100644 index 0000000..48eedcc Binary files /dev/null and b/inc/stdimage/gear.png differ diff --git a/inc/thumb.php b/inc/thumb.php new file mode 100644 index 0000000..b233e18 --- /dev/null +++ b/inc/thumb.php @@ -0,0 +1,361 @@ +> 8) . chr($length & 0xFF); + } + else + { + $retval .= chr(0x80) . + chr(0x04) . + chr(($length >> 24) & 0xFF) . + chr(($length >> 16) & 0xFF) . + chr(($length >> 8) & 0xFF) . + chr($length & 0xFF); + } + + return $retval . $value; + } + } + + /** + * Creates directory + * + * @param string $path Path to create + * @param integer $mode Optional permissions + * @return boolean Success + */ + if (! function_exists('_mkdir')) + { + function _mkdir ($path, $mode = 0777) + { + $old = umask(0); + $res = @mkdir($path, $mode); + umask($old); + + return $res; + } + } + + /** + * Creates directories recursively + * + * @param string $path Path to create + * @param integer $mode Optional permissions + * @return boolean Success + */ + if (! function_exists('rmkdir')) + { + function rmkdir ($path, $mode = 0777) + { + return is_dir($path) || (mkdir(dirname($path), $mode) && _mkdir($path, $mode)); + } + } + + if (filesize(BASE_DIR . '/config/config.inc.php')) + require_once BASE_DIR . '/config/config.inc.php'; + + require_once BASE_DIR . '/inc/config.php'; + + //-- Разрешенные расширения файлов + $allowedExt = [ + 'jpg', + 'jpeg', + 'png', + 'webp', + 'gif', + 'JPG', + 'JPEG', + 'PNG', + 'GIF', + 'WEBP' + ]; + + //-- Разрешенные размеры миниатюр + $allowedSize = (defined('THUMBNAIL_SIZES') && THUMBNAIL_SIZES != '') + ? explode(',', trim(THUMBNAIL_SIZES)) + : []; + + //-- Разрешения для админпанели + $allowedAdmin = [ + 't128x128', + 'f128x128' + ]; + + //-- Ссылка на файл + $imagefile = urldecode($_SERVER['REQUEST_URI']); + + //-- Вызов чере $_GET параметры + //-- ToDo + if (! empty($_REQUEST['thumb'])) + { + $imagefile = '/'. + rtrim( + dirname($_REQUEST['thumb']) + . '/' . THUMBNAIL_DIR . '/' + . (str_replace( + '.', + (empty($_REQUEST['mode']) + ? '-t' + : '-' . $_REQUEST['mode']) . ((empty($_REQUEST['width']) && empty($_REQUEST['height'])) + ? '128' + : intval(@$_REQUEST['width'])) . 'x' . ((empty($_REQUEST['width']) && empty($_REQUEST['height'])) + ? '128' + : intval(@$_REQUEST['height'])) . '.', + basename($_REQUEST['thumb']) + ) + ), + '/'); + } + + //-- Если пришел прямой вызов файла, то сразу отрубаем его + if ($_SERVER['REQUEST_URI'] == '/inc/thumb.php') + { + die('No image'); + } + + //-- Если файл существует, показываем его + if (file_exists(BASE_DIR . $imagefile)) + { + $img_data = @getimagesize(BASE_DIR . $imagefile); + + header('max-age=315360000, public', true); + header('Content-Type:' . $img_data['mime'], true); + header('Cache-Control: max-age=:315360000', true); + header("Expires: " . gmdate("D, d M Y H:i:s", time() + THUMBNAIL_CACHE_LIFETIME) . " GMT"); + header("Content-Length: " . (string) filesize(BASE_DIR . $imagefile), true); + + readfile(BASE_DIR . $imagefile); + + exit; + } + + require_once BASE_DIR . '/inc/init.php'; + + list(, $thumbPath) = explode('/' . UPLOAD_DIR . '/', dirname($imagefile), 2); + + $lenThumbDir = strlen(THUMBNAIL_DIR); + + // -- + if ($lenThumbDir && substr($thumbPath, -$lenThumbDir) != THUMBNAIL_DIR) + { + if (! file_exists(BASE_DIR . $imagefile)) + { + report404(); + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + } + exit(0); + } + + $thumbPath = BASE_DIR . '/' . UPLOAD_DIR . '/' . $thumbPath; + $imagePath = $lenThumbDir ? dirname($thumbPath) : $thumbPath; + + $thumbName = basename($imagefile); + $nameParts = explode('.', $thumbName); + $countParts = count($nameParts); + + if ($countParts < 2 || ! in_array(strtolower(end($nameParts)), $allowedExt)) + { + exit(0); + } + + $matches = []; + + //-- Смотрим переданные параметры + preg_match('/-(r|c|f|t|s)(\d+)x(\d+)(r)*$/i', $nameParts[$countParts-2], $matches); + + //-- Если нет параметров, отдаем 404 + if (! isset($matches[0])) + { + report404(); + + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + exit(0); + } + + $check = ltrim($matches[0], '-'); + + //-- Проверяем разрешен ли данный размер для миниатюры + if (! empty($allowedSize) && ! in_array($check, $allowedSize)) + { + if (! in_array($check, $allowedAdmin)) + { + report404(); + + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + exit(0); + } + } + + //-- Если есть параметр rotate + if (isset($matches[4])) + { + list ($size, $method, $width, $height, $rotate) = $matches; + } + //-- Иначе + else + { + list ($size, $method, $width, $height) = $matches; + $rotate = false; + } + + $nameParts[$countParts-2] = substr($nameParts[$countParts-2], 0, -strlen($size)); + $imageName = implode('.', $nameParts); + + $save = true; + + if (! file_exists("$imagePath/$imageName")) + { + $l = "$imagePath/$imageName"; + + if (file_exists($l . '.tmp')) + { + $url = trim(file_get_contents($l . '.tmp'), ABS_PATH); + + $img = CURL_file_get_contents($url); + + if ($img) + { + file_put_contents("$imagePath/$imageName", $img); + + //setEXIFF("$imagePath/$imageName"); + + $save = true; + } + + @unlink($l . '.tmp'); + } + } + + if (! file_exists("$imagePath/$imageName")) + { + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + + report404(); + + $imageName = 'noimage.png'; + + if (! file_exists("$imagePath/$imageName")) + $imagePath = BASE_DIR . '/' . UPLOAD_DIR . '/images'; + + if (! file_exists("$imagePath/$imageName")) + exit(0); + + $save = false; + } + + define('IMAGE_TOOLBOX_DEFAULT_JPEG_QUALITY', JPG_QUALITY); + + require BASE_DIR . '/class/class.thumbnail.php'; + + $thumb = new Image_Toolbox("$imagePath/$imageName"); + + //-- Методы генерации миниатюр + switch ($method) + { + case 'r': + $thumb->newOutputSize((int)$width, (int)$height, 0, (boolean)$rotate); + break; + + case 'c': + $thumb->newOutputSize((int)$width, (int)$height, 1, (boolean)$rotate); + break; + + case 'f': + $thumb->newOutputSize((int)$width, (int)$height, 2, false, '#ffffff'); + break; + + case 't': + $thumb->newOutputSize((int)$width, (int)$height, 3, false); + break; + + case 's': + $thumb->newOutputSize((int)$width, (int)$height, 4, (boolean)$rotate); + break; + } + + //Blend + //$thumb->addImage(BASE_DIR . '/' . 'uploads/gallery/watermark.gif'); + //$thumb->blend('right -10', 'bottom -10', IMAGE_TOOLBOX_BLEND_COPY, 70); + + //Text + //$thumb->addText('Мой текст', BASE_DIR . '/inc/fonts/ft16.ttf', 16, '#709536', 'right -10', 'bottom -10'); + //if ($width > 200){ + // $thumb->addImage(BASE_DIR . '/' . 'uploads/gallery/watermark.gif'); + // $thumb->blend('right -10', 'bottom -10', IMAGE_TOOLBOX_BLEND_COPY, 70); + //} + + $thumb->output(); + + //-- Если можно сохранять миниатюру + if ($save) + { + if (! file_exists($thumbPath) && ! mkdir($thumbPath, 0777, true)) + exit(0); + + if ($thumb->save("$thumbPath/$thumbName")) + { + $old = umask(0); + chmod("$thumbPath/$thumbName", 0777); + umask($old); + } + + if ($thumb->_img['main']['type'] == 2) + { + $image = getimagesize("$thumbPath/$thumbName", $info); + + if (! isset($info['APP13'])) + { + //-- Если в настройках разрешена генерация IPTC тегов для миниатюр + if (THUMBNAIL_IPTC) + { + $sitename= get_settings('site_name'); + + // установка IPTC тэгов + $iptc = [ + '2#120' => iconv("UTF-8", "WINDOWS-1251", $sitename), + '2#116' => HOST + ]; + + // Преобразование IPTC тэгов в двоичный код + $data = ''; + + foreach($iptc AS $tag => $string) + { + $tag = substr($tag, 2); + $data .= iptc_make_tag(2, $tag, $string); + } + + // Встраивание IPTC данных + $content = iptcembed($data, "$thumbPath/$thumbName"); + + // запись нового изображения в файл + $fp = fopen("$thumbPath/$thumbName", "wb"); + fwrite($fp, $content); + fclose($fp); + } + } + } + } +?> \ No newline at end of file diff --git a/inc/upload.php b/inc/upload.php new file mode 100644 index 0000000..eb8fe0c --- /dev/null +++ b/inc/upload.php @@ -0,0 +1,146 @@ + \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..6625e1c --- /dev/null +++ b/index.php @@ -0,0 +1,173 @@ +coreUrlParse($_SERVER['REQUEST_URI']); + + $GLOBALS['page_id'] = [(isset($_REQUEST['id']) + ? $_REQUEST['id'] + : '') + => ['page' => floatval(0)]]; + + //-- Если пришел вызов на показ ревизии документа + if (! empty($_REQUEST['revission'])) + { + $sql = " + SELECT + doc_data + FROM + " . PREFIX . "_document_rev + WHERE + doc_id = '" . (int)$_REQUEST['id'] . "' + AND + doc_revision = '" . (int)$_REQUEST['revission'] . "' + LIMIT 1 + "; + + $res = $AVE_DB->Query($sql)->GetCell(); + + $res = @unserialize($res); + + $flds = get_document_fields((int)$_REQUEST['id'], $res); + } + + //-- Собираем страницу + + $AVE_Core->coreSiteFetch(get_current_document_id()); + + Debug::startTime('CONTENT'); + + $content = ob_get_clean(); + + if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') && (defined('GZIP_COMPRESSION') && GZIP_COMPRESSION)) + ob_start('ob_gzhandler'); + else + ob_start(); + + Debug::$_document_content = $content; + + Debug::startTime('EVALCONTENT'); + + eval (' '.'?>' . $content . ' @$GLOBALS['page_id'][$_REQUEST['id']]['page'])) + ) + OR + ( + isset($_REQUEST['apage']) + && is_numeric($_REQUEST['apage']) + && ($_REQUEST['apage'] < 2 OR ($_REQUEST['apage'] > @$GLOBALS['page_id'][$_REQUEST['id']]['apage'])) + ) + OR + ( + isset($_REQUEST['artpage']) + && is_numeric($_REQUEST['artpage']) + && ($_REQUEST['artpage'] < 2 OR ($_REQUEST['artpage'] > @$GLOBALS['page_id'][$_REQUEST['id']]['artpage'])) + ) + ) + ) + { + if ($_REQUEST['id'] == 1) + header ('Location:' . ABS_PATH); + else + header ('Location:' . ABS_PATH . $AVE_Core->curentdoc->document_alias . URL_SUFF); + exit; + } + + $GLOBALS['block_generate']['DOCUMENT']['CONTENT'] = Debug::endTime('CONTENT'); + $GLOBALS['block_generate']['INIT']['CODEEND'] = Debug::endTime('CODEEND'); + + //-- Вывод конечного результата + output_compress($render); + + $AVE_DB->Close(); \ No newline at end of file diff --git a/install/.htaccess b/install/.htaccess new file mode 100644 index 0000000..c995ef0 --- /dev/null +++ b/install/.htaccess @@ -0,0 +1,27 @@ +###################### AVE.CMS_HTACCESS_BEGIN ########################## +# Options: +# -MultiViews: Turns off multiviews so it doesn't interfer with our rewrite rules +# -Indexes: Stop directory listings +# +FollowSymlinks: Let out rewrite rules work + +Options -Indexes +FollowSymLinks +AddDefaultCharset utf-8 + + + php_value default_charset utf-8 + + # Этот параметр устанавливает максимальное время в секундах, позволяющее скрипту запускаться прежде, чем он завершается синтаксическим анализатором. + php_value max_execution_time 3000 + + # Максимальное время загрузки данных для скрипта, в том числе и файлов из формы + php_value max_input_time 3000 + + # Ограничивает максимальный объем данных, получаемых от пользователя методом POST + php_value post_max_size 32M + + # Устанавливает максимальный размер файла, который может быть получен методом POST (меньше, чем post_max_size) + php_value upload_max_filesize 32M + + + +####################### AVE.CMS_HTACCESS_END ########################### \ No newline at end of file diff --git a/install/data_base.sql b/install/data_base.sql new file mode 100644 index 0000000..0db7ad8 --- /dev/null +++ b/install/data_base.sql @@ -0,0 +1,373 @@ +INSERT INTO `%%PRFX%%_countries` VALUES + (1, 'AF', 'Афганистан', '2', '2'), + (2, 'AL', 'Албания', '2', '2'), + (3, 'DZ', 'Алжир', '2', '2'), + (4, 'AS', 'Американское Самоа', '2', '2'), + (5, 'AD', 'Андорра', '2', '2'), + (6, 'AO', 'Ангола', '2', '2'), + (7, 'AI', 'Ангвилла', '2', '2'), + (8, 'AQ', 'Антарктика', '2', '2'), + (9, 'AG', 'Антигуа и Барбуда', '2', '2'), + (10, 'AR', 'Аргентина', '2', '2'), + (11, 'AM', 'Армения', '2', '2'), + (12, 'AW', 'Аруба', '2', '2'), + (13, 'AU', 'Австралия', '2', '2'), + (14, 'AT', 'Австрия', '2', '1'), + (15, 'AZ', 'Азербайджан', '2', '2'), + (16, 'BS', 'Содружество Багамских островов', '2', '2'), + (17, 'BH', 'Бахрейн', '2', '2'), + (18, 'BD', 'Бангладеш', '2', '2'), + (19, 'BB', 'Барбадос', '2', '2'), + (20, 'BY', 'Беларусь', '1', '2'), + (21, 'BE', 'Бельгия', '2', '1'), + (22, 'BZ', 'Белиц', '2', '2'), + (23, 'BJ', 'Бенин', '2', '2'), + (24, 'BM', 'Бермудские острова', '2', '2'), + (25, 'BT', 'Бутан', '2', '2'), + (26, 'BO', 'Боливия', '2', '2'), + (27, 'BA', 'Босния и Герцеговина', '2', '1'), + (28, 'BW', 'Ботсвана', '2', '2'), + (29, 'BV', 'Остров Бювет', '2', '2'), + (30, 'BR', 'Бразилия', '2', '2'), + (31, 'IO', 'Британские территории в Индийском океане', '2', '2'), + (32, 'VG', 'Виргинские острова (Британия)', '2', '2'), + (33, 'BN', 'Бруней Дарусаллам', '2', '2'), + (34, 'BG', 'Болгария', '2', '2'), + (35, 'BF', 'Буркина-Фасо', '2', '2'), + (36, 'BI', 'Бурунди', '2', '2'), + (37, 'KH', 'Камбоджа', '2', '2'), + (38, 'CM', 'Камерун', '2', '2'), + (39, 'CA', 'Канада', '2', '2'), + (40, 'CV', 'Кейп-Верд', '2', '2'), + (41, 'KY', 'Кайманские острова', '2', '2'), + (42, 'CF', 'Центральная Африканская Республика', '2', '2'), + (43, 'TD', 'Чад', '2', '2'), + (44, 'CL', 'Чили', '2', '2'), + (45, 'CN', 'Китай', '2', '2'), + (46, 'CX', 'Рождественские острова', '2', '2'), + (47, 'CC', 'Кокосовые острова', '2', '2'), + (48, 'CO', 'Колумбия', '2', '2'), + (49, 'KM', 'Коморос', '2', '2'), + (50, 'CG', 'Конго', '2', '2'), + (51, 'CK', 'Острова Кука', '2', '2'), + (52, 'CR', 'Коста-Рика', '2', '2'), + (53, 'CI', 'Кот-д Ивуар (Берег Слоновой Кости)', '2', '2'), + (54, 'HR', 'Хорватия', '2', '1'), + (55, 'CU', 'Куба', '2', '2'), + (56, 'CY', 'Кипр', '2', '2'), + (57, 'CZ', 'Чешская Республика', '2', '1'), + (58, 'DK', 'Дания', '2', '1'), + (59, 'DJ', 'Джибути', '2', '2'), + (60, 'DM', 'Доминика', '2', '2'), + (61, 'DO', 'Доминиканская Республика', '2', '2'), + (62, 'TP', 'Восточный Тимор', '2', '2'), + (63, 'EC', 'Эквадор', '2', '2'), + (64, 'EG', 'Египет', '2', '2'), + (65, 'SV', 'Эль-Сальвадор', '2', '2'), + (66, 'GQ', 'Экваториальная Гвинея', '2', '2'), + (67, 'ER', 'Эритрея', '2', '2'), + (68, 'EE', 'Эстония', '2', '1'), + (69, 'ET', 'Эфиопия', '2', '2'), + (70, 'FK', 'Фолклендские острова', '2', '2'), + (71, 'FO', 'Острова Фаро', '2', '2'), + (72, 'FJ', 'Фиджи', '2', '2'), + (73, 'FI', 'Финляндия', '2', '2'), + (74, 'FR', 'Франция', '2', '1'), + (75, 'FX', 'Франция, Столица', '2', '1'), + (76, 'GF', 'Французская Гвиана', '2', '2'), + (77, 'PF', 'Французская Полинезия', '2', '2'), + (78, 'TF', 'Французские южные территории', '2', '2'), + (79, 'GA', 'Габон', '2', '2'), + (80, 'GM', 'Гамбия', '2', '2'), + (81, 'GE', 'Грузия', '2', '2'), + (82, 'DE', 'Германия', '2', '1'), + (83, 'GH', 'Гана', '2', '2'), + (84, 'GI', 'Гибралтар', '2', '2'), + (85, 'GR', 'Греция', '2', '1'), + (86, 'GL', 'Гренландия', '2', '2'), + (87, 'GD', 'Гренада', '2', '2'), + (88, 'GP', 'Гваделупа', '2', '2'), + (89, 'GU', 'Гуам', '2', '2'), + (90, 'GT', 'Гватемала', '2', '2'), + (91, 'GN', 'Гвинея', '2', '2'), + (92, 'GW', 'Гвинея-Биссау', '2', '2'), + (93, 'GY', 'Гайана', '2', '2'), + (94, 'HT', 'Гаити', '2', '2'), + (95, 'HM', 'Острова Хирт и Макдоналдс', '2', '2'), + (96, 'HN', 'Гондурас', '2', '2'), + (97, 'HK', 'Гонгконг', '2', '2'), + (98, 'HU', 'Венгрия', '2', '2'), + (99, 'IS', 'Исландия', '2', '2'), + (100, 'IN', 'Индия', '2', '2'), + (101, 'ID', 'Индонезия', '2', '2'), + (102, 'IQ', 'Ирак', '2', '2'), + (103, 'IE', 'Ирландия', '2', '1'), + (104, 'IR', 'Иран', '2', '2'), + (105, 'IL', 'Израиль', '2', '2'), + (106, 'IT', 'Италия', '2', '1'), + (107, 'JM', 'Ямайка', '2', '2'), + (108, 'JP', 'Япония', '2', '2'), + (109, 'JO', 'Иордан', '2', '2'), + (110, 'KZ', 'Казахстан', '2', '2'), + (111, 'KE', 'Кения', '2', '2'), + (112, 'KI', 'Кирибати', '2', '2'), + (113, 'KP', 'КНДР', '2', '2'), + (114, 'KR', 'Республика Корея', '2', '2'), + (115, 'KW', 'Кувейт', '2', '2'), + (116, 'KG', 'Киргизстан', '2', '2'), + (117, 'LA', 'Лаосская НДР', '2', '2'), + (118, 'LV', 'Латвия', '2', '2'), + (119, 'LB', 'Ливан', '2', '2'), + (120, 'LS', 'Лесото', '2', '2'), + (121, 'LR', 'Либерия', '2', '2'), + (122, 'LY', 'Ливийская Арабская Джамахерия', '2', '2'), + (123, 'LI', 'Лихтенштейн', '2', '1'), + (124, 'LT', 'Литва', '2', '2'), + (125, 'LU', 'Люксембург', '2', '1'), + (126, 'MO', 'Макао', '2', '2'), + (127, 'MK', 'Македония', '2', '1'), + (128, 'MG', 'Мадагаскар', '2', '2'), + (129, 'MW', 'Малави', '2', '2'), + (130, 'MY', 'Малайзия', '2', '2'), + (131, 'MV', 'Мальдивы', '2', '2'), + (132, 'ML', 'Мали', '2', '2'), + (133, 'MT', 'Мальта', '2', '2'), + (134, 'MH', 'Маршалловы острова', '2', '2'), + (135, 'MQ', 'Мартиника', '2', '2'), + (136, 'MR', 'Мавритания', '2', '2'), + (137, 'MU', 'Маврикий', '2', '2'), + (138, 'YT', 'Майотта', '2', '2'), + (139, 'MX', 'Мексика', '2', '2'), + (140, 'FM', 'Микронезия', '2', '2'), + (141, 'MD', 'Молдова', '2', '2'), + (142, 'MC', 'Монако', '2', '2'), + (143, 'MN', 'Монголия', '2', '2'), + (144, 'MS', 'Монтсеррат', '2', '2'), + (145, 'MA', 'Марокко', '2', '2'), + (146, 'MZ', 'Мозамбик', '2', '2'), + (147, 'MM', 'Мьянма', '2', '2'), + (148, 'NA', 'Намибия', '2', '2'), + (149, 'NR', 'Науру', '2', '2'), + (150, 'NP', 'Непал', '2', '2'), + (151, 'NL', 'Нидерланды', '2', '1'), + (152, 'AN', 'Антильские острова', '2', '2'), + (153, 'NC', 'Новая Каледония', '2', '2'), + (154, 'NZ', 'Новая Зеландия', '2', '2'), + (155, 'NI', 'Никарагуа', '2', '2'), + (156, 'NE', 'Нигер', '2', '2'), + (157, 'NG', 'Нигерия', '2', '2'), + (158, 'NU', 'Нию', '2', '2'), + (159, 'NF', 'Остров Норфолк', '2', '2'), + (160, 'MP', 'Остров Северной марины', '2', '2'), + (161, 'NO', 'Норвегия', '2', '1'), + (162, 'OM', 'Оман', '2', '2'), + (163, 'PK', 'Пакистан', '2', '2'), + (164, 'PW', 'Палау', '2', '2'), + (165, 'PA', 'Панама', '2', '2'), + (166, 'PG', 'Папуа-Новая Гвинея', '2', '2'), + (167, 'PY', 'Парагвай', '2', '2'), + (168, 'PE', 'Перу', '2', '2'), + (169, 'PH', 'Филипинны', '2', '2'), + (170, 'PN', 'Остров Питкаирн', '2', '2'), + (171, 'PL', 'Польша', '2', '1'), + (172, 'PT', 'Португалия', '2', '1'), + (173, 'PR', 'Пуэрто-Рико', '2', '2'), + (174, 'QA', 'Катар', '2', '2'), + (175, 'RE', 'Остров Воссоединения', '2', '2'), + (176, 'RO', 'Румыния', '2', '1'), + (177, 'RU', 'Россия', '1', '2'), + (178, 'RW', 'Руанда', '2', '2'), + (179, 'LC', 'Остров Святого Луки', '2', '2'), + (180, 'WS', 'Самоа', '2', '2'), + (181, 'SM', 'Сан-Марино', '2', '1'), + (182, 'ST', 'Сан-Томе и Принсипи', '2', '2'), + (183, 'SA', 'Саудовская Аравия', '2', '2'), + (184, 'SN', 'Сенегал', '2', '2'), + (185, 'SC', 'Сейшельские Острова', '2', '2'), + (186, 'SL', 'Сьерра Леоне', '2', '2'), + (187, 'SG', 'Сингапур', '2', '2'), + (188, 'SK', 'Словацкая Республика', '2', '1'), + (189, 'SI', 'Словения', '2', '1'), + (190, 'SB', 'Соломоновы Острова', '2', '2'), + (191, 'SO', 'Сомали', '2', '2'), + (192, 'ZA', 'Южная Африка', '2', '2'), + (193, 'ES', 'Испания', '2', '1'), + (194, 'LK', 'Шри-Ланка', '2', '2'), + (195, 'SH', 'Остров Святой Елены', '2', '2'), + (196, 'KN', 'Сент-Кикс и Невис', '2', '2'), + (197, 'PM', 'Остров Святого Петра', '2', '2'), + (198, 'VC', 'Сент-Винсент и Гренадины', '2', '2'), + (199, 'SD', 'Cудан', '2', '2'), + (200, 'SR', 'Суринам', '2', '2'), + (201, 'SJ', 'Острова Свалбард и Жан-Мейен', '2', '2'), + (202, 'SZ', 'Свазиленд', '2', '2'), + (203, 'SE', 'Швеция', '2', '1'), + (204, 'CH', 'Швейцария', '2', '2'), + (205, 'SY', 'Сирийская Арабская Республика', '2', '2'), + (206, 'TW', 'Тайвань', '2', '2'), + (207, 'TJ', 'Таджикистан', '2', '2'), + (208, 'TZ', 'Танзания', '2', '2'), + (209, 'TH', 'Таиланд', '2', '2'), + (210, 'TG', 'Того', '2', '2'), + (211, 'TK', 'Токелау', '2', '2'), + (212, 'TO', 'Тонга', '2', '2'), + (213, 'TT', 'Тринидад и Тобаго', '2', '2'), + (214, 'TN', 'Тунис', '2', '2'), + (215, 'TR', 'Турция', '2', '1'), + (216, 'TM', 'Туркменистан', '2', '2'), + (217, 'TC', 'Острова Теркс и Кайкос', '2', '2'), + (218, 'TV', 'Тувалу', '2', '2'), + (219, 'UG', 'Уганда', '2', '2'), + (220, 'UA', 'Украина', '1', '2'), + (221, 'AE', 'Объединённые Арабские Эмираты', '2', '2'), + (222, 'GB', 'Великобритания', '2', '1'), + (223, 'US', 'Соединённые Штаты Америки', '2', '2'), + (224, 'VI', 'Виргинские острова (США)', '2', '2'), + (225, 'UY', 'Уругвай', '2', '2'), + (226, 'UZ', 'Узбекистан', '2', '2'), + (227, 'VU', 'Вануату', '2', '2'), + (228, 'VA', 'Ватикан', '2', '2'), + (229, 'VE', 'Венесуэла', '2', '2'), + (230, 'VN', 'Вьетнам', '2', '2'), + (231, 'WF', 'Острова Уэльс и Фортуны', '2', '2'), + (232, 'EH', 'Западная Сахара', '2', '2'), + (233, 'YE', 'Йемен', '2', '2'), + (234, 'YU', 'Югославия', '2', '2'), + (235, 'ZR', 'Заир', '2', '2'), + (236, 'ZM', 'Замбия', '2', '2'), + (237, 'ZW', 'Зимбабве', '2', '2');#inst# + +INSERT INTO `%%PRFX%%_document_fields` VALUES + (1, 1, 1, 0, 'Поздравляем!', '0'), + (2, 2, 1, 0, '

      Установка %%SITENAME%% прошла успешно!

      ', '0'), + (3, 1, 2, 0, 'Ошибка 404', '0'), + (4, 2, 2, 0, 'Извините, запрошенный Вами документ не найден.', '0');#inst# + +INSERT INTO `%%PRFX%%_documents` VALUES + (1, 1, 0, 0, '/', '0', '', 'Главная', 'Главная страница', '0', '0', '0', '1', '0', '', '', 'index,follow', '3', '0.5', '1', '0', '0', '0', '0', '', '', 'ru', '1', '', '0', '0'), + (2, 1, 0, 0, '404-dokument-ne-najden', '0', '', '404 - Документ не найден', 'Ошибка 404', '0', '0', '0', '1', '0', '', '', 'noindex,nofollow', '6', '0', '1', '0', '0', '0', '0', '', '', 'ru', '2', '', '0', '0');#inst# + +INSERT INTO `%%PRFX%%_navigation` VALUES + (1,'main','Основное меню','
    42. \n [tag:linkname]\n
    43. ','','','
    44. \n [tag:linkname]\n
    45. ','','','
        \n[tag:content]\n
      ','','','','','','','','1,2,3,4,5','1');#inst# + +INSERT INTO `%%PRFX%%_navigation_items` VALUES + (1,1,1,'/','Главная','','_self','','','','','0','1','0','1');#inst# + +INSERT INTO `%%PRFX%%_rubric_fields` VALUES + (1, 1, 0, 'header', 'Заголовок', 'single_line', '0', '1', '', '0', '', '', ''), + (2, 1, 0, 'text', 'Текст', 'multi_line', '0', '2', '', '0', '', '', '');#inst# + +INSERT INTO `%%PRFX%%_rubric_permissions` VALUES + (1, 1, 1, 'alles'), + (2, 1, 2, 'docread'), + (3, 1, 3, 'docread'), + (4, 1, 4, 'docread'), + (5, 1, 5, 'docread');#inst# + +INSERT INTO `%%PRFX%%_rubrics` VALUES + (1,'Основные страницы','','0','

      [tag:fld:header]

      \n[tag:fld:text]','1','1','0','1','','','','','','','','0','','0','0',UNIX_TIMESTAMP(),UNIX_TIMESTAMP());#inst# + +INSERT INTO `%%PRFX%%_settings` VALUES + ( + '1', + '%%SITENAME%%', + 'mail', + 'text/plain', + '465', + 'smtp.gmail.com', + 'yourusername@gmail.com', + 'yourpassword', + 'ssl', + '/usr/sbin/sendmail', + '800', + '%%EMAIL%%', + '%%USERNAME%%', + 'Здравствуйте %NAME%,\r\nВаша регистрация на сайте %HOST%. \r\n\r\nТеперь Вы можете войти на %HOST% со следующими данными:: \r\n\r\nПароль: %PASSWORD%\r\nE-Mail: %EMAIL%\r\n\r\n--------------------------------------------------\r\n%EMAILSIGNATURE%\r\n\r\n', + 'С уважением,\r\nслужба поддержки', + '2', + '

      Ошибка...

      \r\n

      \r\nУ Вас нет прав на просмотр этого документа!.\r\n

      ', + '
        %s
      ', + 'Первая «', + '» Последняя', + '…', + '»', + '«', + 'Страница %d из %d', + '
    46. %s
    47. ', + '%s', + '%s', + '
    48. %s
    49. ', + '
        %s
      ', + '1', + '0', + '
    50.  → 
    51. ', + '0', + '', + '[name]', + '
    52. %s
    53. ', + '1', + '%d %B %Y', + '%d %B %Y, %H:%M', + 'RU', + '0', + '
      \n Содержимое скрыто.\n
      ' +);#inst# + +INSERT INTO `%%PRFX%%_settings_lang` VALUES + (1, 'ru', 'Русский', 'ru', '1', '1'), + (2, 'en', 'English', 'en', '0', '0'), + (3, 'ua', 'Українська', 'ua', '0', '0'), + (4, 'de', 'Deutsch', 'de', '0', '0'), + (5, 'it', 'Italian', 'it', '0', '0'), + (6, 'fr', 'France', 'fr', '0', '0'), + (7, 'sp', 'Spanish', 'sp', '0', '0'), + (8, 'kz', 'Казахский', 'kz', '0', '0'), + (9, 'by', 'Беларуская', 'by', '0', '0'), + (10, 'pl', 'Polski', 'pl', '0', '0'), + (11, 'bg', 'Български', 'bg', '0', '0');#inst# + +INSERT INTO `%%PRFX%%_templates` VALUES + (1,'Основной шаблон','\n\n \n \n\n \n \n \n\n \n\n \n\n \n \n\n \n \n\n [tag:rubheader]\n\n [tag:title] - [tag:sitename]\n \n \n \n
      \n \n
      \n\n \n
      \n
      \n
      \n [tag:maincontent]\n
      \n
      \n
      \n\n \n
      \n
      \n Создано при помощи [tag:version]\n
      \n
      \n\n \n \n\n [tag:rubfooter]\n \n',1,UNIX_TIMESTAMP());#inst# + +INSERT INTO `%%PRFX%%_user_groups` VALUES + (1, 'Администраторы', '1', '0', '', 'alles'), + (2, 'Анонимные пользователи', '1', '0', '', ''), + (3, 'Модераторы', '1', '0', '', ''), + (4, 'Зарегистрированные', '1', '0', '', '');#inst# + +INSERT INTO `%%PRFX%%_users` + SET + `Id` = 1, + `password` = '%%PASS%%', + `email` = '%%EMAIL%%', + `street` = '', + `street_nr` = '', + `zipcode` = '', + `city` = '', + `phone` = '', + `telefax` = '', + `description` = '', + `firstname` = '', + `lastname` = '', + `user_name` = '%%USERNAME%%', + `user_group` = 1, + `user_group_extra` = '', + `reg_time` = UNIX_TIMESTAMP(), + `status` = 1, + `last_visit` = UNIX_TIMESTAMP(), + `country` = 'RU', + `birthday` = '', + `deleted` = '0', + `del_time` = 0, + `emc` = '0', + `reg_ip` = '0', + `new_pass` = '', + `company` = '', + `taxpay` = '0', + `salt` = '%%SALT%%', + `new_salt` = '', + `user_ip` = 0;#inst# + +INSERT INTO `%%PRFX%%_paginations` (`id`, `pagination_name`, `pagination_box`, `pagination_start_label`, `pagination_end_label`, `pagination_separator_box`, `pagination_separator_label`, `pagination_next_label`, `pagination_prev_label`, `pagination_link_box`, `pagination_active_link_box`, `pagination_link_template`, `pagination_link_active_template`) +VALUES + (1, 'Общий шаблон', '
        %s
      ', '', '', '
    54. %s
    55. ', '…', '', '', '
    56. %s
    57. ', '
    58. %s
    59. ', '[name]', '[name]');#inst# \ No newline at end of file diff --git a/install/eula/bg.tpl b/install/eula/bg.tpl new file mode 100644 index 0000000..153ecbd --- /dev/null +++ b/install/eula/bg.tpl @@ -0,0 +1,100 @@ +
      + +AVE.cms - Web publishing software (Content managment system) +

      +Copyright 2014 by the contributors +

      +AVE.cms is released under the GPL +

      + + GNU GENERAL PUBLIC LICENSE
      + Версия 2, июнь 1991г. +

      +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +

      +Всеки може да копира и разпространява буквални копия на този лиценз, но промяната му не се допуска. +

      +
      +

      Преамбула

      +

      +Лицензите за повечето програми са направени така, че да Ви отнемат свободата за ползването и промяната им. В контраст на това GNU GPL е предназначен да гарантира Вашата свобода да споделяте и променяте свободния софтуер - да осигурите този софтуер да бъде свободен за всичките му потребители. Този общ публичен лиценз защитава повечето програми на Фондацията за свободен софтуер и всеки друг софтуер, за който авторите му решат да използват лиценза. (Другите програми на Фондацията за свободен софтуер се защитават от GNU LGPL.) Вие също можете да го прилагате към програмите си. +

      +Когато говорим за свободен софтуер, имаме предвид свободата, а не цената. Нашият GPL е направен така, че да Ви осигури свободата да разпространявате копия на свободен софтуер (и да взимате такса за тази услуга, ако желаете), също да Ви предостави изходните текстове на програмите или възможността да ги получите, ако искате, също да Ви позволи да променяте софтуера или да използвате части от него за създаването на нови свободни програми; също и да сте наясно как да правите тези неща. +

      +За да защитим Вашите права, се налага да направим ограничения, които забраняват на който и да е да Ви откаже тези права или да Ви помоли да се откажете от тях. Тези ограничения водят и до определени отговорности за Вас, ако разпространявате копия на свободен софтуер, или ако го променяте. +

      +Например, ако разпространявате копия на някаква програма, безплатно или срещу заплащане, трябва да предоставите на получателя всички права, които имате и Вие. Трябва да сте сигурен, че той, както и Вие, ще получи или може да получи изходните текстове на програмата. Освен това трябва да му покажете тези условия, за да може той да си знае правата. +

      +Ние защитаваме Вашите права по два начина: (1) чрез авторски права за софтуера и (2) предлагаме Ви това Разрешение, което дава законно основание за копиране, разпространение и/или промяна на софтуера. +

      +Също, за защита на всички автори и всеки от нас, ние искаме да сме сигурни, че всеки разбира, че няма никаква гаранция за работата на свободния софтуер. Ако програмата е променена от някой и предоставена на друг, ние изискваме получателят да знае, че това което има не е оригинала, тъй че всички проблеми, предизвикани от промените не трябва да се отразят на репутацията на оригиналния автор. +

      +Накрая, всяка свободна програма се третира еднакво от софтуерните патенти. Искаме да предотвратим опасността разпространителите на свободни програми да придобият патентни разрешения, приватизирайки по този начин програмите. За да се предпазим от това, ние искаме всеки издаден патент да разрешава свободно ползване от всички, или да не се издава въобще. +

      Правилата, условията и изисквания за копиране, разпространяване и промяна на свободния софтуер следват: +

      +Условия за копиране, разпространение и модификация според GNU Общ Публичен Лиценз +

      +0. Този Лиценз е приложим за всяка програма или друг продукт, които съдържат бележка, поставена от притежателя на авторското право, казваща, че те могат да бъдат разпространявани под условията на този Общ Публичен Лиценз. Под "Програмата" по нататък се има предвид всяка такава програма или продукт, а "продукт базиран на Програмата" означава или самата Програма, или всякакъв друг продукт. произхождащ от програмата според закона за авторското право, т.е. например, продукт съдържащ Програмата или част от нея, или дословно, или с модификации и/или преведена на друг език.(От тук нататък преводът се включва без ограничения в термина модификация). Обръщението към всеки обхванат от този лиценз е "Вие". +

      +Дейности различаващи се от копиране, разпространение и модификация не са обхванати от този лиценз, т.е. те са извън неговата сфера на действие.Акта на стартиране на Програмата не е ограничен, а изходната информация на Програмата се обхваща само ако нейното съдържание се състои от продукт базиран на Програмата(независим от получения при стартиране на Програмата) . Дали това е така зависи от това какво прави Програмата. +

      +1. Вие можете да копирате и разпространиявате дословни копия от изходния код на Програмата такъв, какъвто го получавате, на всякаква среда, при условие, че поставите на всяко копие подходяща бележка за авторските права и отказ от даване на гаранция, че прилагате всички бележки отнасящи се до този Лиценз и до липсата на всякаква гаранция, и че всеки получател на Програмата получава и копие от този Лиценз заедно с нея. +

      +Вие можете да таксувате физическия акт на прехвърляне на копие и по свое усмотрение да предлагате гаранция в замяна на тази такса. . +

      +2. Вие можете да модифицирате вашето копие или копия на Програмата или някаква част от нея, създавайки по този начин продукт базиран на Програмата, и да разпространявате такива модификации или продукти под условията, упоменати в Част 1 по горе, при условие че спазвате и следните условия: +

      +а) Вие трябва да направите така, че модифицираните файлове да съдържат на видно място бележки указващи, че Вие сте модифицирали файловете и датата на всяка модификация. +

      +b) Вие трябва да направите така, че всеки продукт или работа, които разпространявате или публикувате, които като цяло или в отделни свои части съдържат или ца произлезли от Програмата или някоя нейна част да бъдат лицензирани цялостно като безплатни за всички според условията на този Лиценз. +

      +c)Ако модифицираната програма нормално приема команди интерактивно по време на работа Вие трябва да направите така, че при започване на работа за такава интерактивна употреба по най-обикновения начин, тя да изписва съобщение включващо подходяща бележка за авторските права и бележка, че не се дава никаква гаранция (или че Вие давате гаранция) и че потребителите могат да разпространяват програмата съгласно тук упоменатите условия и обяснение как може да се види копие на този Лиценз.(Изключение: ако самата Програма е интерактивна но нормално не изписва такова съобщение не е задължително вашият продукт базиран на Програмата да изписва съобщението.) +

      +Тези изисквания са приложими за модифицираната работа като цяло. Ако различими части от тази работа не са произлезли от Програмата и могат да бъдат считани за независими и отделни продукти тогава този Лиценз и неговите условия не важат за тези части ако Вие ги разпространявате като отделен продукт. Ако, обаче, Вие разпространявате гореспоменатите части като част от продукт, базиран на Програмата то разпространението на този продукт трябва да се извършва според условията на този Лиценз и по този начин всяко лице, обхванато от него да притежава всички гарантирани от него права върху цялата програма и всички нейни части независимо кой ги е написал. +

      +По този начин целта на тази секция е не да оспорва или предявява претенции за правата върху софтуера написан изцяло от вас, а да упражнява контрол върху разпространението на продукти произхождащи от една или повече Програми. +

      +В допълнение, простото натрупване на други продукти небазирани на Програмата заедно с Програмата (или продукт, базиран на Програмата) на една и съща единица от среда за съхранение или разпространение на информация не вкарва другите продукти в обхвата на този Лиценз. +

      +3. Вие можете да копирате или разпространявате Програмата (или продукт, базиран на нея според условията на Част 2) във вид на обектен код или в изпълнима форма съобразявайки се с условията поставени в Части 1 и 2 по-горе като спазвате и следните условия: +

      +a) Да я разпространявате с пълния и, машинно читаем изходен код, който трябва да бъде разпространяван в съгласие с условията поставени в Части 1 и 2 по-горе, на среда обикновено използвана за размяна на софтуер или +

      +b) Да я разпространявате с писмено предложение, важащо поне за три години, даващо право на всеки да получи от вас и разпространява по условията на Части 1 и 2 пълно машинно читаемо копие от съответния изходен код, на цена не по-голяма от вашите разходи по физическото възпроизвеждане на кода или +

      +c) Да я разпространявате с информацията за предложението за разпространение на съответния изходен код, което сте получили.( Това е позволено само за некомерсиални дистрибуции и само ако Вие сте получили програмата във вид на обектен код или в изпълним вид придружена от такова предложение в съответствие със секция б по-горе.) +

      +Под изходен код на продукта се има предвид тази форма на продукта която е предпочитана за извършването на модификации върху него. За продукт в изпълним вид под пълен изходен код се има предвид целия изходен код на всички модули, които продукта съдържа заедно с всички свързани с продукта файлове определящи интерфейса и скриптовете използвани за контрол над компилирането и инсталирането на продукта в изпълним вид. Изключение представляват всички модули, които обикновено се разпространяват (или като изходен код или в изпълним вид) заедно с основни компоненти (компилатор, ядро и т.н.) на операционната система, за която е предназначен продукта в изпълним вид, чиито изходен код може да не придружава продукта освен ако някой от тях не придружава самия продукт. +

      +Ако разпространението на изпълними файлове или обектен код се извършва чрез предлагане на достъп с разрешение за копиране от определено място то трябва да се предлага еквивалентен достъп с възможност за копиране на изходния код, въпреки че трети лица не са задължени да копират изходния код заедно с обектния такъв. +

      +4. Вие не можете да копирате, разпространявате, променяте или прелицензирате Програмата по всякакъв друг начин, който не е изрично представен в този Лиценз. Всякакъв друг опит за промяна, прелицензиране, копиране и разпространение на Програмате е забранен и автоматично елиминира правата, които този Лиценз Ви дава. Лица, които са получили копия или права от вас по условията на този Лиценз ще запазят правата си дотогава докато се придържат към него. +

      +5. Вие не сте длъжен да приемате този Лиценз, тъй като не сте го подписвали. Разбира се, нищо друго не ви дава права да модифицирате или разпространявате Програмата или продукти произхождащи от нея. Тези действия са забранени от закона ако вие не приемете този Лиценз. Ето защо, модифицирайки или разпространявайки Програмата( или продукт базиран на Програмата) Вие автоматично приемате всички условия на този Лиценз за копиране, модифициране и разпространение на Програмата и продукти базирани на нея. +

      +6. Всеки път, когато Вие разпространявате Програмата(или продукт, базиран на Програмата) получателят и автоматично получава разрешение от оригиналния притежател на лиценза да копира, разпространява или модифицира Програмата обект на тези условия. Вие не можете да налагате каквито и да било ограничения възпрепятстващи получателя да упражнява правата гарантирани му тук. Вие не сте отговорен за налагане на подчинение на този Лиценз на трети лица. +

      +7. Ако като последствие от съдебно решение или обвинение в нарушение на патента или по някаква друга причина (неограничена само до въпроси свързани с патента) Ви е наложено спазването на условия (дали чрез съдебна заповед, съглашение или по друг начин), които противоречат на условията на лицензен този, те не ви освобождават от условията на този Лиценз. Ако Вие не можете да разпространявате Програмата по начин, който удовлетворява задълженията Ви по този Лиценз и всякакви други уместни задължения, то като последствие Вие не можете да разпространявате Програмата въобще. Например ако патентен лизенз не позволява безплатно разпространение на Програмата от тези, които получават нейни копия директно или индиретно чрез Вас единственият начин по който можете да удовлетворите него и този Лиценз е да се оттеглите изцяло от разпространението на Програмата. +

      +Ако някаква част от тази секция е невалидна или неприложима при определени обстоятелства, духът на тази секция е считан за приложим и секцията като цяло е считана за приложима при други условия. +

      +Целта на тази секция не е да ви подбужда да нарушавате някакви патентни или други права за собственост, а да защити цялостта на системата за разпространение на безплатен софтуер наложена от практиката на публичните лицензи. Много хора са дали своя щедър принос към широкообхватния софтуер, разпространяван в съответствие с последователното приложение на тази система, но само авторът може да избира дали той или тя ще разпространява софтуер чрез някаква друга система, а потребителите на лицнеза не могат да налагат този избор. +

      +Целта на тази секция е да направи абсолиутно ясно това, което е считано за следствие от останалата част на този Лиценз. +

      +8. Ако разпространението или употребата на Програмата е ограничено в определени страни или чрез патенти или чрез авторско право на интерфейса, оригиналният притежател на авторското право, който поставя Програмата под този Лиценз, може да добави изрично ограничение за географското разпространение изключващо тези страни така че разпространението е позволено само във или между страни не изключени по този начин. В този случай този Лиценз се обединява ограничението все едно то е включено в текста му. +

      +9. Фондацията за Безплатен Софтуер си запазва правото да публикува ревизирани и/или нови версии на Общия Публичен Лиценз. Такива нови версии ще бъдат подобни по смисъл с настоящата версия, но могат да се различават по отделни свои детайли, които касаят нововъзникнали проблеми. +

      +Всяка версия има номер, отличаващ я от другите. Ако Програмата уточнява номер на версия на този Лиценз, който се отнася до него и "всяка следваща версия" Вие имате избора да следвате условията на споменатата версия или на всяка следваща версия публикувана от Фондацията за Безплатен Софтуер. Ако Програмата не определя номер на версия на този Лиценз Вие можете да изберете всяка версия някога публикувана от Фондацията за Безплатен Софтуер. +

      +10. Ако желаете да съчетаете части от Програмата с други безплатни програми, разпространявани под други условия, контактувайте с авторите им и ги питайте за разрешение. За софтуер, чиито авторски права са притежание на Фондацията за Безплатен Софтуер пишете на Фондацията - понякога правим изключения. Нашето решение ще бъде повлияно от постигането на две цели - запазването на свободния статус на нашия безплатен софтуер и подпомагането на обмяната и преизползването на софтуер като цяло. +

      +НЯМА ГАРАНЦИЯ +

      +11. ТЪЙ КАТО ПРОГРАМАТА Е ЛИЦЕНЗИРАНА КАТО СВОБОДНА НЕ СЕ ДАВА НИКАКВА ГАРАНЦИЯ ЗА НЕЯ ДО СТЕПЕНТА ПОЗВОЛЕНА ОТ СЪОТВЕТНИЯ ЗАКОН. ПРИТЕЖАТЕЛИТЕ НА АВТОРСКИТЕ ПРАВА И/ИЛИ ДРУГИ ЛИЦА ПРЕДОСТАВЯТ ПРОГРАМАТА "КАКВАТО Е" БЕЗ КАКВАТО И ДА Е ГАРАНЦИЯ ПРЯКО ИЗРАЗЕНА ИЛИ ПО ПОДРАЗБИРАНЕ, ВКЛЮЧВАЩА, НО НЕ ОГРАНИЧЕНА ДО, ГАРАНЦИИТЕ ПО ПОДРАЗБИРАНЕ НАЛОЖЕНИ ОТ ПРОДАВАЕМОСТТА ИЛИ ПРИЛОЖИМОСТТА ЗА ОПРЕДЕЛЕНА ЦЕЛ, ОСВЕН АКО ОБРАТНОТО НЕ Е ПИСМЕНО ПОТВЪРДЕНО. ВИЕ ПОЕМАТЕ ЦЕЛИЯ РИСК ЗА КАЧЕСТВОТО И ПРЕДСТАВЯНЕТО НА ПРОГРАМАТА. АКО ПРОГРАМАТА СЕ ОКАЖЕ ДЕФЕКТНА ВИЕ ПОЕМАТЕ ЦЕНАТА НА ЦЯЛОТО НЕОБХОДИМО ОБСЛУЖВАНЕ, ВЪЗСТАНОВЯВАНЕ ИЛИ ПОПРАВКА. +

      +12. ПРИ НИКАКВИ ОБСТОЯТЕЛСТВА, ОСВЕН ПРИ СКЛЮЧЕНО ПИСМЕНО СЪГЛАШЕНИЕ ИЛИ ПРИ НАЛИЧИЕ НА СЪОТВЕТНОТО ИЗИСКВАНЕ В СЪЩЕСТВУВАЩИЯ ЗАКОН, НИКОЙ ОТ СОБСТВЕНИЦИТЕ НА АВТОРСКИТЕ ПРАВА ИЛИ КОЕТО И ДА Е ДРУГО ЛИЦЕ, ИМАЩО ПРАВО ДА РАЗПРОСТРАНЯВА ИЛИ МОДИФИЦИРА ПРОГРАМАТА СПОРЕД ИЗЛОЖЕНИТЕ ПО-ГОРЕ УСЛОВИЯ НЯМА ДА НОСИ ЗАДЪЛЖЕНИЯ КЪМ ВАС ЗАРАДИ ЩЕТИТЕ, КОИТО СТЕ ПОНЕСЛИ В СЛЕДСТВИЕ НА ВСЯКАКВИ ОБЩИ, СПЕЦИФИЧНИ И ИНЦИДЕНТНИ ПОРАЖЕНИЯ, ИЛИ ТАКИВА ВЪЗНИКНАЛИ ЗАРАДИ НЕВЪЗМОЖНОСТ ДА СЕ ИЗПОЛЗВА ПРОГРАМАТА. ПОРАЖЕНИяТА ВКЛЮЧВАТ, НО НЕ СА ОГРАНИЧЕНИ ДО: ЗАГУБА НА ДАННИ, НЕПРАВИЛНО ПРЕДСТАВЕНА ИНФОРМАЦИЯ, ЗАГУБИ ПРЕТЪРПЕНИ ОТ ВАС ИЛИ ДРУГИ ЛИЦА ИЛИ НЕВЪЗМОЖНОСТ НА ПРОГРАМАТА ДА РАБОТИ С ВСЯКАКВИ ДРУГИ ПРОГРАМИ. ГОРНОТО Е В СИЛА ДОРИ АКО СОБСТВЕНИКА НА АВТОРСКИТЕ ПРАВА ИЛИ ЛИЦАТА, РАЗПРОСТРАНЯВАЛИ И МОДИФИЦИРАЛИ ПРОГРАМАТА, СПОРЕД ТОЗИ ЛИЦЕНЗ СА БИЛИ УВЕДОМЕНИ ЗА ВЪЗМОЖНОСТТА ДА БЪДАТ НАНЕСЕНИ ТАКИВА ПОРАЖЕНИЯ. +

      +
      \ No newline at end of file diff --git a/install/eula/ru.tpl b/install/eula/ru.tpl new file mode 100644 index 0000000..0daeab6 --- /dev/null +++ b/install/eula/ru.tpl @@ -0,0 +1,321 @@ +
      + +AVE.cms - Web publishing software (Content managment system) +

      +Copyright 2014 by the contributors +

      +AVE.cms is released under the GPL +

      + + GNU GENERAL PUBLIC LICENSE
      + Версия 2, июнь 1991г. +

      +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +

      +Каждый вправе копировать и распространять экземпляры настоящей Лицензии без +внесения изменений в ее текст. +

      +
      +

      Преамбула

      +

      +Большинство лицензий на программное обеспечение лишаeт вас права распространять и +вносить изменения в это программное обеспечение. Стандартная Общественная Лицензия +GNU, напротив, разработана с целью гарантировать вам право совместно использовать и +вносить изменения в свободное программное обеспечение, т.е. обеспечить свободный +доступ к программному обеспечению для всех пользователей. Условия настоящей +Стандартной Общественной Лицензии применяются к большей части программного +обеспечения Free Software Foundation, а также к любому другому программному обеспечению +по желанию его автора. (К некоторому программному обеспечению Free Software Foundation +применяются условия Стандартной Общественной Лицензии GNU для Библиотек). Вы также +можете применять Стандартную Общественную Лицензию к разработанному вами +программному обеспечению. +

      +Говоря о свободном программном обеспечении, мы имеем в виду свободу, а не +безвозмездность. Настоящая Стандартная Общественная Лицензия разработана с целью +гарантировать вам право распространять экземпляры свободного программного +обеспечения (и при желании получать за это вознаграждение), право получать исходный +текст программного обеспечения или иметь возможность его получить, право вносить +изменения в программное обеспечение или использовать его части в новом свободном +программном обеспечении, а также право знать, что вы имеете все вышеперечисленные +права. +

      +Чтобы защитить ваши права, мы вводим ряд ограничений с тем, чтобы никто не имел +возможности лишить вас этих прав или обратиться к вам с предложением отказаться от +этих прав. Данные ограничения налагают на вас определенные обязанности в случае, +если вы распространяете экземпляры программного обеспечения или модифицируете +программное обеспечение. +

      +Например, если вы распространяете экземпляры такого программного обеспечения за +плату или бесплатно, вы обязаны передать новым обладателям все права в том же объеме, +в каком они принадлежат вам. Вы обязаны обеспечить получение новыми обладателями +программы ее исходного текста или возможность его получить. Вы также обязаны +ознакомить их с условиями настоящей Лицензии. +

      +Для защиты ваших прав мы: (1) оставляем за собой авторские права на программное +обеспечение и (2) предлагаем вам использовать настоящую Лицензию, в соответствии +с условиями которой вы вправе воспроизводить, распространять и/или модифицировать +программное обеспечение. +

      +Кроме того, для защиты как нашей репутации, так и репутации других авторов +программного обеспечения, мы уведомляем всех пользователей, что на данное +программное обеспечение никаких гарантий не предоставляется. Те, кто приобрел +программное обеспечение, с внесенными в него третьими лицами изменениями, должны +знать, что они получают не оригинал, в силу чего автор оригинала не несет +ответственности за ошибки в работе программного обеспечения, допущенные третьими +лицами при внесении изменений. +

      +Наконец, программное обеспечение перестает быть свободным в случае, если лицо +приобретает на него исключительные права [1]. Недопустимо, чтобы лица, +распространяющие свободное программное обеспечение, могли приобрести +исключительные права на использование данного программного обеспечения и +зарегистрировать их в Патентном ведомстве. Чтобы избежать этого, мы заявляем, что +обладатель исключительных прав обязан предоставить любому лицу права на +использование программного обеспечения либо не приобретать исключительных прав +вообще. +

      +Ниже изложены условия воспроизведения, распространения и модификации программного +обеспечения. +

      +Условия воспроизведения, распространения и модификации +

      +0. Условия настоящей Лицензии применяются ко всем видам программного обеспечения +или любому иному произведению, которое содержит указание правообладателя на то, что +данное произведение может распространяться на условиях Стандартной Общественной +Лицензии. Под термином "Программа" далее понимается любое подобное программное +обеспечение или иное произведение. Под термином "произведение, производное от +Программы" понимается Программа или любое иное производное произведение в +соответствии с законодательством об авторском праве [2], т.е. произведение, +включающее в себя Программу или ее часть, как с внесенными в ее текст изменениями, +так и без них и/или переведенную на другой язык. (Здесь и далее, понятие "модификация" +включает в себя понятие перевода в самом широком смысле). Каждый приобретатель +экземпляра Программы именуется в дальнейшем "Лицензиат". +

      +Действие настоящей Лицензии не распространяется на осуществление иных прав, кроме +воспроизведения, распространения и модификации программного обеспечения. Не +устанавливается ограничений на запуск Программы. Условия Лицензии +распространяются на выходные данные из Программы только в том случае, если их +содержание составляет произведение, производное от Программы (независимо от того, +было ли такое произведение создано в результате запуска Программы). Это зависит от +того, какие функции выполняет Программа. +

      +1. Лицензиат вправе изготовлять и распространять экземпляры исходного текста +Программы в том виде, в каком он его получил, без внесения в него изменений на любом +носителе, при соблюдении следующих условий: на каждом экземпляре помещен знак +охраны авторского права и уведомление об отсутствии гарантий; оставлены без +изменений все уведомления, относящиеся к настоящей Лицензии и отсутствию гарантий; +вместе с экземпляром Программы приобретателю передается копия настоящей Лицензии. +

      +Лицензиат вправе взимать плату за передачу экземпляра Программы, а также вправе за +плату оказывать услуги по гарантийной поддержке Программы. +

      +2. Лицензиат вправе модифицировать свой экземпляр или экземпляры Программы +полностью или любую ее часть. Данные действия Лицензиата влекут за собой создание +произведения, производного от Программы. Лицензиат вправе изготовлять и +распространять экземпляры такого произведения, производного от Программы, или +собственно экземпляры изменений в соответствии с пунктом 1 настоящей Лицензии при +соблюдении следующих условий: +

      +а) файлы, измененные Лицензиатом, должны содержать хорошо заметную пометку, что они +были изменены, а также дату внесения изменений; +

      +b) при распространении или публикации Лицензиатом любого произведения, которое +содержит Программу или ее часть или является производным от Программы или от ее +части, Лицензиат обязан передавать права на использование данного произведения +третьим лицам на условиях настоящей Лицензии, при этом Лицензиат не вправе +требовать уплаты каких-либо лицензионных платежей. Распространяемое произведение +лицензируется как одно целое; +

      +c) если модифицированная Программа при запуске обычно читает команды в +интерактивном режиме, Лицензиат обязан обеспечить вывод на экран дисплея или +печатающее устройство сообщения, которое должно включать в себя: +знак охраны авторского права; +уведомление об отсутствии гарантий на Программу (или иное, если Лицензиат +предоставляет гарантии); +указание на то, что пользователи вправе распространять экземпляры Программы в +соответствии с условиями настоящей Лицензии, а также на то, каким образом +пользователь может ознакомиться с текстом настоящей Лицензии. (Исключение: если +оригинальная Программа является интерактивной, но не выводит в своем обычном режиме +работы сообщение такого рода, то вывод подобного сообщения произведением, +производным от Программы, в этом случае не обязателен). +

      +Вышеуказанные условия применяются к модифицированному произведению, производному +от Программы, в целом. В случае если отдельные части данного произведения не +являются производными от Программы, являются результатом творческой деятельности и +могут быть использованы как самостоятельное произведение, Лицензиат вправе +распространять отдельно такое произведение на иных лицензионных условиях. В случае +если Лицензиат распространяет вышеуказанные части в составе произведения, +производного от Программы, то условия настоящей Лицензии применяются к +произведению в целом, при этом права, приобретаемые сублицензиатами на основании +Лицензии, передаются им в отношении всего произведения, включая все его части, +независимо от того, кто является их авторами. +

      +Целью настоящего пункта 2 не является заявление прав или оспаривание прав на +произведение, созданное исключительно Лицензиатом. Целью настоящего пункта +является обеспечение права контролировать распространение произведений, +производных от Программы, и составных произведений, производных от Программы. +

      +Размещение произведения, которое не является производным от Программы, на одном +устройстве для хранения информации или носителе вместе с Программой или +произведением, производным от Программы, не влечет за собой распространения условий +настоящей Лицензии на такое произведение. +

      +3. Лицензиат вправе воспроизводить и распространять экземпляры Программы или +произведения, которое является производным от Программы, в соответствии с пунктом 2 +настоящей Лицензии, в виде объектного кода или в исполняемой форме в соответствии с +условиями п.п.1 и 2 настоящей Лицензии при соблюдении одного из перечисленных ниже +условий: +

      +а) к экземпляру должен прилагаться соответствующий полный исходный текст в +машиночитаемой форме, который должен распространяться в соответствии с условиями +п.п. 1 и 2 настоящей Лицензии на носителе, обычно используемом для передачи +программного обеспечения, либо +

      +b) к экземпляру должно прилагаться действительное в течение трех лет предложение в +письменной форме к любому третьему лицу передать за плату, не превышающую стоимость +осуществления собственно передачи, экземпляр соответствующего полного исходного +текста в машиночитаемой форме в соответствии с условиями п.п. 1 и 2 настоящей Лицензии +на носителе, обычно используемом для передачи программного обеспечения, либо +

      +c) к экземпляру должна прилагаться полученная Лицензиатом информация о предложении, +в соответствии с которым можно получить соответствующий исходный текст. (Данное +положение применяется исключительно в том случае, если Лицензиат осуществляет +некоммерческое распространение программы, при этом программа была получена самим +Лицензиатом в виде объектного кода или в исполняемой форме и сопровождалась +предложением, соответствующим условиям пп.b п.3 настоящей Лицензии). +

      +Под исходным текстом произведения понимается такая форма произведения, которая +наиболее удобна для внесения изменений. Под полным исходным текстом исполняемого +произведения понимается исходный текст всех составляющих произведение модулей, а +также всех файлов, связанных с описанием интерфейса, и сценариев, предназначенных +для управления компиляцией и установкой исполняемого произведения. Однако, в +качестве особого исключения, распространяемый исходный текст может не включать +того, что обычно распространяется (в виде исходного текста или в бинарной форме) с +основными компонентами (компилятор, ядро и т.д.) операционной системы, в которой +работает исполняемое произведение, за исключением случаев, когда исполняемое +произведение сопровождается таким компонентом. +

      +В случае если произведение в виде объектного кода или в исполняемой форме +распространяется путем предоставления доступа для копирования его из +определенного места, обеспечение равноценного доступа для копирования исходного +текста из этого же места удовлетворяет требованиям распространения исходного +текста, даже если третьи лица при этом не обязаны копировать исходный текст вместе с +объектным кодом произведения. +

      +4. Лицензиат вправе воспроизводить, модифицировать, распространять или передавать +права на использование Программы только на условиях настоящей Лицензии. Любое +воспроизведение, модификация, распространение или передача прав на иных условиях +являются недействительными и автоматически ведут к расторжению настоящей Лицензии +и прекращению всех прав Лицензиата, предоставленных ему настоящей Лицензией. При +этом права третьих лиц, которым Лицензиат в соответствии с настоящей Лицензией +передал экземпляры Программы или права на нее, сохраняются в силе при условии +полного соблюдения ими настоящей Лицензии. +

      +5. Лицензиат не обязан присоединяться к настоящей Лицензии, поскольку он ее не +подписал. Однако только настоящая Лицензия предоставляет право распространять или +модифицировать Программу или произведение, производное от Программы. Подобные +действия нарушают действующее законодательство, если они не осуществляются в +соответствии с настоящей Лицензией. Если Лицензиат внес изменения или осуществил +распространение экземпляров Программы или произведения, производного от Программы, +Лицензиат тем самым подтвердил свое присоединение к настоящей Лицензии в целом, +включая условия, определяющие порядок воспроизведения, распространения или +модификации Программы или произведения, производного от Программы. +

      +6. При распространении экземпляров Программы или произведения, производного от +Программы, первоначальный лицензиар автоматически передает приобретателю такого +экземпляра право воспроизводить, распространять и модифицировать Программу в +соответствии с условиями настоящей Лицензии. Лицензиат не вправе ограничивать +каким-либо способом осуществление приобретателями полученных ими прав. Лицензиат +не несет ответственности за несоблюдение условий настоящей Лицензии третьими +лицами. +

      +7. Лицензиат не освобождается от исполнения обязательств в соответствии с настоящей +Лицензией в случае, если в результате решения суда или заявления о нарушении +исключительных прав или в связи с наступлением иных обстоятельств, не связанных +непосредственно с нарушением исключительных прав, на Лицензиата на основании +решения суда, договора или ином основании возложены обязательства, которые +противоречат условиям настоящей Лицензии. В этом случае Лицензиат не вправе +распространять экземпляры Программы, если он не может одновременно исполнить +условия настоящей Лицензии и возложенные на него указанным выше способом +обязательства. Например, если по условиям лицензионного соглашения сублицензиатам +не может быть предоставлено право бесплатного распространения экземпляров +Программы, которые они приобрели напрямую или через третьих лиц у Лицензиата, то в +этом случае Лицензиат обязан отказаться от распространения экземпляров Программы. +

      +Если любое положение настоящего пункта при наступлении конкретных обстоятельств +будет признано недействительным или неприменимым, настоящий пункт применяется за +исключением такого положения. Настоящий пункт применяется в целом при прекращении +вышеуказанных обстоятельств или их отсутствии. +

      +Целью данного пункта не является принуждение Лицензиата к нарушению патента или +заявления на иные права собственности или к оспариванию действительности такого +заявления. Единственной целью данного пункта является защита неприкосновенности +системы распространения свободного программного обеспечения, которая +обеспечивается за счет общественного лицензирования. Многие люди внесли свой +щедрый вклад в создание большого количества программного обеспечения, которое +распространяется через данную систему в надежде на ее длительное и +последовательное применение. Лицензиат не вправе вынуждать автора распространять +программное обеспечение через данную систему. Право выбора системы распространения +программного обеспечения принадлежит исключительно его автору. +

      +Настоящий пункт 7 имеет целью четко определить те цели, которые преследуют все +остальные положения настоящей Лицензии. +

      +8. В том случае если распространение и/или использование Программы в отдельных +государствах ограничено соглашениями в области патентных или авторских прав, +первоначальный правообладатель, распространяющий Программу на условиях настоящей +Лицензии, вправе ограничить территорию распространения Программы, указав только те +государства, на территории которых допускается распространение Программы без +ограничений, обусловленных такими соглашениями. В этом случае такое указание в +отношении территорий определенных государств признается одним из условий +настоящей Лицензии. +

      +9. Free Software Foundation может публиковать исправленные и/или новые версии настоящей +Стандартной Общественной Лицензии. Такие версии могут быть дополнены различными +нормами, регулирующими правоотношения, которые возникли после опубликования +предыдущих версий, однако в них будут сохранены основные принципы, закрепленные в +настоящей версии. +

      +Каждой версии присваивается свой собственный номер. Если указано, что Программа +распространяется в соответствии с определенной версией, т.е. указан ее номер, или +любой более поздней версией настоящей Лицензии, Лицензиат вправе присоединиться к +любой из этих версий Лицензии, опубликованных Free Software Foundation. Если Программа не +содержит такого указания на номер версии Лицензии Лицензиат вправе присоединиться +к любой из версий Лицензии, опубликованных когда-либо Free Software Foundation. +

      +10. В случае если Лицензиат намерен включить часть Программы в другое свободное +программное обеспечение, которое распространяется на иных условиях, чем в настоящей +Лицензии, ему следует испросить письменное разрешение на это у автора программного +обеспечения. Разрешение в отношении программного обеспечения, права на которое +принадлежат Free Software Foundation, следует испрашивать у Free Software Foundation. +В некоторых случаях Free Software Foundation делает исключения. При принятии решения +Free Software Foundation будет руководствоваться двумя целями: сохранение статуса свободного +для любого произведения, производного от свободного программного обеспечения Free Software +Foundation и обеспечение наиболее широкого совместного использования программного +обеспечения. +

      +
      +

      ОТСУТСТВИЕ ГАРАНТИЙНЫХ ОБЯЗАТЕЛЬСТВ

      +

      +11. ПОСКОЛЬКУ НАСТОЯЩАЯ ПРОГРАММА РАСПРОСТРАНЯЕТСЯ БЕСПЛАТНО, ГАРАНТИИ НА НЕЕ НЕ +ПРЕДОСТАВЛЯЮТСЯ В ТОЙ СТЕПЕНИ, В КАКОЙ ЭТО ДОПУСКАЕТСЯ ПРИМЕНИМЫМ ПРАВОМ. НАСТОЯЩАЯ +ПРОГРАММА ПОСТАВЛЯЕТСЯ НА УСЛОВИЯХ "КАК ЕСТЬ". ЕСЛИ ИНОЕ НЕ УКАЗАНО В ПИСЬМЕННОЙ +ФОРМЕ, АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ НЕ ПРИНИМАЕТ НА СЕБЯ НИКАКИХ ГАРАНТИЙНЫХ +ОБЯЗАТЕЛЬСТВ, КАК ЯВНО ВЫРАЖЕННЫХ, ТАК И ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ПРОГРАММЫ, В +ТОМ ЧИСЛЕ ПОДРАЗУМЕВАЕМУЮ ГАРАНТИЮ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ И ПРИГОДНОСТИ +ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ, А ТАКЖЕ ЛЮБЫЕ ИНЫЕ ГАРАНТИИ. ВСЕ РИСКИ, +СВЯЗАННЫЕ С КАЧЕСТВОМ И ПРОИЗВОДИТЕЛЬНОСТЬЮ ПРОГРАММЫ, НЕСЕТ ЛИЦЕНЗИАТ. В СЛУЧАЕ +ЕСЛИ В ПРОГРАММЕ БУДУТ ОБНАРУЖЕНЫ НЕДОСТАТКИ, ВСЕ РАСХОДЫ, СВЯЗАННЫЕ С ТЕХНИЧЕСКИМ +ОБСЛУЖИВАНИЕМ, РЕМОНТОМ ИЛИ ИСПРАВЛЕНИЕМ ПРОГРАММЫ, НЕСЕТ ЛИЦЕНЗИАТ. +

      +12. ЕСЛИ ИНОЕ НЕ ПРЕДУСМОТРЕНО ПРИМЕНЯЕМЫМ ПРАВОМ ИЛИ НЕ СОГЛАСОВАНО СТОРОНАМИ В +ДОГОВОРЕ В ПИСЬМЕННОЙ ФОРМЕ, АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ, КОТОРЫЙ МОДИФИЦИРУЕТ +И/ИЛИ РАСПРОСТРАНЯЕТ ПРОГРАММУ НА УСЛОВИЯХ НАСТОЯЩЕЙ ЛИЦЕНЗИИ, НЕ НЕСЕТ +ОТВЕТСТВЕННОСТИ ПЕРЕД ЛИЦЕНЗИАТОМ ЗА УБЫТКИ, ВКЛЮЧАЯ ОБЩИЕ, РЕАЛЬНЫЕ, ПРЕДВИДИМЫЕ И +КОСВЕННЫЕ УБЫТКИ (В ТОМ ЧИСЛЕ УТРАТУ ИЛИ ИСКАЖЕНИЕ ИНФОРМАЦИИ, УБЫТКИ, ПОНЕСЕННЫЕ +ЛИЦЕНЗИАТОМ ИЛИ ТРЕТЬИМИ ЛИЦАМИ, НЕВОЗМОЖНОСТЬ РАБОТЫ ПРОГРАММЫ С ЛЮБОЙ ДРУГОЙ +ПРОГРАММОЙ И ИНЫЕ УБЫТКИ). АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ В СООТВЕТСТВИИ С +НАСТОЯЩИМ ПУНКТОМ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ДАЖЕ В ТОМ СЛУЧАЕ, ЕСЛИ ОНИ БЫЛИ +ПРЕДУПРЕЖДЕНЫ О ВОЗМОЖНОСТИ ВОЗНИКНОВЕНИЯ ТАКИХ УБЫТКОВ. +

      +
      \ No newline at end of file diff --git a/install/exit.html b/install/exit.html new file mode 100644 index 0000000..701ee7d --- /dev/null +++ b/install/exit.html @@ -0,0 +1,67 @@ + + + + + + + Установка AVE.cms отменена... + + + + + + + + + +
      +
      +
      Установка AVE.cms отменена...
      +
      +
      + + \ No newline at end of file diff --git a/install/index.php b/install/index.php new file mode 100644 index 0000000..ed280e5 --- /dev/null +++ b/install/index.php @@ -0,0 +1,740 @@ + 0) + { + $cLastAlpha = strtolower(substr($str, -1)); + $size = intval($str); + switch($cLastAlpha) + { + case 't': + $size *= 1024; + case 'g': + $size *= 1024; + case 'm': + $size *= 1024; + case 'k': + $size *= 1024; + } + } + else + { + $size = 0; + } + return $size; +} + + +/** + * Get GD version + * @return string + */ +function getGdVersion() +{ + if (function_exists('gd_info')) + { + $gd_info = @gd_info(); + return preg_replace('/[^0-9\.]/', '', $gd_info['GD Version']); + } + + return NULL; +} + + +/** + * Get PCRE version + * @return string + */ +function getPcreVersion() +{ + defined('PCRE_VERSION') + ? list($version) = explode(' ', constant('PCRE_VERSION')) + : $version = NULL; + + return $version; +} + + +/** + * Get MySQL version + * @return string + */ +function getMySQLVersion() { + $output = mysqli_get_client_info(); + preg_match('@[0-9]+\.[0-9]+\.[0-9]+@', $output, $version); + return $version[0]; +} + + +/** + * @param $level + * @param $text + * + * @return string + */ +function check_param($level, $text) +{ + $level = intval($level); + + switch ($level) + { + //Параметр не соответствует. + case 2: + $img = 'ico_delete'; + break; + //Несоответствие, не влияющее на функционирование системы. + case 1: + $img = 'ico_ok'; + break; + //Параметр соответствует. + case 0: + $img = 'ico_ok_green'; + break; + //По умолчанию + default: + $img = 'ico_ok_noproblem'; + break; + } + + return $img; +} + + +/* @subpackage install */ + + +error_reporting(E_ERROR); +ini_set('display_errors', 7); + +global $config; + +ob_start(); + +define('SETUP', 1); + +define('BASE_DIR', str_replace("\\", "/", dirname(dirname(__FILE__)))); + +//-- Debug Class +require (BASE_DIR . '/class/class.debug.php'); +$Debug = new Debug; + +if (! is_writable(BASE_DIR . '/tmp/cache/smarty/')) + die('Cache folder is not writeable!'); + +include (BASE_DIR . '/config/db.config.php'); +include (BASE_DIR . '/inc/config.php'); +include (BASE_DIR . '/functions/func.common.php'); +include (BASE_DIR . '/functions/func.logs.php'); +include (BASE_DIR . '/functions/func.helpers.php'); + +// require_once (BASE_DIR . '/class/Smarty.class.php'); + +include (BASE_DIR . '/class/class.template.php'); + + $abs_path = dirname((!strstr($_SERVER['PHP_SELF'], $_SERVER['SCRIPT_NAME']) && (@php_sapi_name() == 'cgi')) + ? $_SERVER['PHP_SELF'] + : $_SERVER['SCRIPT_NAME']); + + if (defined('ACP')) + $abs_path = dirname($abs_path); + +define('ABS_PATH', rtrim(str_replace("\\", "/", $abs_path), '/') . '/'); +define('DATE_FORMAT', '%d %B %Y'); +define('TIME_FORMAT', '%d %B %Y, %H:%M'); +define('PAGE_NOT_FOUND_ID', '2'); + +$AVE_Template = new AVE_Template(BASE_DIR . '/install/tpl/'); + +$lang_file = BASE_DIR . '/install/lang/ru.txt'; + +$AVE_Template->config_load($lang_file); + +$ver = APP_NAME . ' v' . APP_VERSION; + +$db_connect = check_db_connect($config['dbhost'], $config['dbuser'], $config['dbpass'], $config['dbname']); +$check_installed = check_installed($config['dbpref']); + +if ((true === $db_connect) && $_REQUEST['step'] != 'finish' && check_installed($config['dbpref'])) +{ + echo '
      ' . $AVE_Template->get_config_vars('installed') . '
      '; + exit; +}; + +$error_is_required = array(); + +check_required(); +check_writable(); + +// include_once(BASE_DIR . '/inc/errors.php'); + +$count_error = sizeof((array) $error_is_required); + +if (1 == $count_error) +{ + $AVE_Template->assign('error_header', $AVE_Template->get_config_vars('erroro')); +} +elseif ($count_error > 1) + { + $AVE_Template->assign('error_header', $AVE_Template->get_config_vars('erroro_more')); + } + +if ($count_error > 0 && ! (isset($_REQUEST['force']) && 1 == $_REQUEST['force'])) +{ + $AVE_Template->assign('error_is_required', $error_is_required); + $AVE_Template->display('error.tpl'); + exit; +} + +$_REQUEST['step'] = isset($_REQUEST['step']) ? $_REQUEST['step'] : ''; + +// Минимальные требования к системе +define('PHP_version', '8.0'); +define('MySQL_version', '8.0'); +define('GD_version', '2.0'); +define('PCRE_version', '7.0'); +define('JSON', $AVE_Template->get_config_vars('mess_on')); +define('MbString', $AVE_Template->get_config_vars('mess_on')); +define('SimpleXML', $AVE_Template->get_config_vars('mess_on')); +define('Iconv', $AVE_Template->get_config_vars('mess_on')); +define('XSLT', $AVE_Template->get_config_vars('mess_supported')); +define('Data_limit', '2'); // Mb +define('TIME_limit', '30'); // Sec +define('DISC_space', '30'); // Mb +define('RAM_space', '32M'); // Mb +define('SAFE_MODE', $AVE_Template->get_config_vars('mess_off')); +define('REGISTER_GLOBALS', $AVE_Template->get_config_vars('mess_off')); +define('MAGIC_QUOTES_GPC', $AVE_Template->get_config_vars('mess_off')); + +switch ($_REQUEST['step']) +{ + //Начало + case '' : + + //Шаг 1 + case '1' : + $AVE_Template->display('step1.tpl'); + break; + + //Шаг 2 + case '2' : + $AVE_Template->display('step2.tpl'); + break; + + //Шаг 3 + case '3' : + $test['php_version'] = phpversion(); + $test['mysql_version'] = getMySQLVersion(); + $test['gd_version'] = getGdVersion(); + $test['pcre_version'] = getPcreVersion(); + $test['json'] = function_exists('json_encode') ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + $test['simplexml'] = function_exists('simplexml_load_string') ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + $test['mbstring'] = function_exists('mb_internal_encoding') ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + $test['iconv'] = function_exists('iconv') ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + $test['xslt'] = (function_exists('xslt_create') || function_exists('domxml_xslt_stylesheet') || (class_exists('DomDocument') && class_exists('XsltProcessor'))) ? XSLT : $AVE_Template->get_config_vars('mess_unsupported'); + $test['data_limit'] = ini_get('post_max_size') ? ini_get('post_max_size') : $AVE_Template->get_config_vars('mess_undefined'); + $test['time_limit'] = ini_get('max_execution_time') ? ini_get('max_execution_time') : $AVE_Template->get_config_vars('mess_undefined'); + $test['disk_space'] = round(@disk_free_space($_SERVER['DOCUMENT_ROOT']) / 1024 / 1024, 2); + $test['memmory_limit'] = ini_get('memory_limit') ? ini_get('memory_limit') : $AVE_Template->get_config_vars('mess_undefined'); + $test['s_m'] = (ini_get('safe_mode') == 1) ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + $test['r_g'] = (ini_get('register_globals') == 1) ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + $test['m_q'] = (ini_get('magic_quotes_gpc') == 1 || ini_get('magic_quotes_runtime') == 1 || ini_get('magic_quotes_sybase') == 1) ? $AVE_Template->get_config_vars('mess_on') : $AVE_Template->get_config_vars('mess_off'); + + $check['php_version'] = check_param(version_compare(phpversion(), PHP_version, ">=") ? 0 : 2, $test['php_version']); + $check['mysql_version'] = check_param(version_compare(getMySQLVersion(), MySQL_version, ">=") ? 0 : 2, $test['mysql_version']); + $check['gd_version'] = check_param(version_compare($test['gd_version'], GD_version, ">=") ? 0 : 2, $test['gd_version']); + $check['pcre_version'] = check_param(version_compare($test['pcre_version'], PCRE_version, ">=") ? 0 : 2, $test['pcre_version']); + $check['mbstring'] = check_param(function_exists('mb_internal_encoding') ? 0 : 2, $test['mbstring']); + $check['json'] = check_param(function_exists('json_encode') ? 0 : 2, $test['json']); + $check['simplexml'] = check_param(function_exists('simplexml_load_string') ? 0 : 2, $test['simplexml']); + $check['iconv'] = check_param(function_exists('iconv') ? 0 : 2, $test['iconv']); + $check['xslt'] = check_param(($test['xslt'] == XSLT) ? 0 : 2, $test['xslt']); + $check['data_limit'] = check_param(($test['data_limit'] != $AVE_Template->get_config_vars('mess_undefined') && version_compare($test['data_limit'], Data_limit, ">=")) ? 0 : 2, $test['data_limit']); + $check['time_limit'] = check_param(($test['time_limit'] != $AVE_Template->get_config_vars('mess_undefined') && $test['time_limit'] >= TIME_limit) ? 0 : 2, ($test['time_limit'] != $AVE_Template->get_config_vars('mess_undefined')) ? $test['time_limit'] . " " . $AVE_Template->get_config_vars('seconds') : $t_l); + $check['disk_space'] = check_param(($test['disk_space'] != $AVE_Template->get_config_vars('mess_undefined') && $test['disk_space'] >= DISC_space) ? 0 : 2, ($test['disk_space'] != $AVE_Template->get_config_vars('mess_undefined')) ? $test['disk_space'].$AVE_Template->get_config_vars('megabytes') : $test['disk_space']); + $check['memmory_limit'] = check_param(($test['memmory_limit'] != $AVE_Template->get_config_vars('mess_undefined') && convertSizeToBytes($test['memmory_limit']) >= convertSizeToBytes(RAM_space)) ? 0 : (($test['memmory_limit'] != $AVE_Template->get_config_vars('mess_undefined')) ? 2 : 1), $test['memmory_limit']); + $check['s_m'] = check_param(($test['s_m'] == SAFE_MODE) ? 0 : 1, $test['s_m']); + $check['r_g'] = check_param(($test['r_g'] == REGISTER_GLOBALS) ? 0 : 1, $test['r_g']); + $check['m_q'] = check_param(($test['m_q'] == MAGIC_QUOTES_GPC) ? 0 : 1, $test['m_q']); + + $AVE_Template->assign('check', $check); + $AVE_Template->assign('test', $test); + $AVE_Template->display('step3.tpl'); + break; + + //Шаг 4 + case '4' : + if (!empty($_POST['dbname']) && !empty($_POST['dbprefix'])) + { + $db_connect = check_db_connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], $_POST['dbname']); + + if (true === $db_connect) { + $mysql_connect = @mysqli_connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass']); + @mysqli_select_db($mysql_connect, $_POST['dbname']); + } + + // Очищаем бд (по префиксу) + if (isset($_REQUEST["dbclean"]) && $_REQUEST["dbclean"] == "1") { + + if (false === $db_connect) + { + $AVE_Template->assign('warning', $AVE_Template->get_config_vars('database_not_connect')); + $AVE_Template->display('step4.tpl'); + exit; + } + + clean_db($_POST['dbname'], $_POST['dbprefix'], $mysql_connect); + } + + // Создать новую БД + if (isset($_REQUEST['dbcreat'])) + { + $link = check_mysql_connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass']); + + if (false === $link) + { + $AVE_Template->assign('warning', $AVE_Template->get_config_vars('database_not_connect')); + $AVE_Template->display('step4.tpl'); + exit; + } + else + { + $mysqli_connect = @mysqli_connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass']); + } + + if (false === $db_connect) + { + @mysqli_query($mysqli_connect, "SET collation_server = 'utf8_general_ci'"); + @mysqli_query($mysqli_connect, "SET character_set_server = 'utf8'"); + + $sql = 'CREATE DATABASE ' . $_POST['dbname']; + + if (false === check_mysql_query($mysqli_connect, $sql)) + // Исправлено: передаем переменную $mysqli_connect + $AVE_Template->assign('warning', $AVE_Template->get_config_vars('error_is_create') . mysqli_error($mysqli_connect) . "\n"); + } + } + + $check_installed = check_installed($_POST['dbpref']); + + $connect = check_db_connect($_POST['dbhost'], $_POST['dbuser'], $_POST['dbpass'], $_POST['dbname']); + + $config = [ + 'dbhost' => $_POST['dbhost'], + 'dbuser' => $_POST['dbuser'], + 'dbpass' => $_POST['dbpass'], + 'dbname' => $_POST['dbname'], + 'dbpref' => $_POST['dbprefix'], + 'dbport' => null, + 'dbsock' => null + ]; + + if (true === $connect && false === $check_installed) + { + if (! @is_writeable(BASE_DIR . '/config/db.config.php')) + { + $AVE_Template->assign('config_isnt_writeable', 1); + $AVE_Template->display('error.tpl'); + exit; + } + + $fp = @fopen(BASE_DIR . '/config/db.config.php', 'w+'); + + // Записываем данные для подключения + @fwrite($fp, " \"" . stripslashes(trim($_POST['dbhost'])) . "\",\n" + . "\t\t'dbuser' => \"" . stripslashes(trim($_POST['dbuser'])) . "\",\n" + . "\t\t'dbpass' => \"" . stripslashes(trim($_POST['dbpass'])) . "\",\n" + . "\t\t'dbname' => \"" . stripslashes(trim($_POST['dbname'])) . "\",\n" + . "\t\t'dbpref' => \"" . stripslashes(trim($_POST['dbprefix'])) . "\",\n" + . "\t\t'dbport' => null,\n" + . "\t\t'dbsock' => null\n" + . "\t];\n" + . "?>" + ); + + @fclose($fp); + + //-- Если параметры не указаны, прерываем работу + if (! file_exists(BASE_DIR . '/config/db.config.php') || ! filesize(BASE_DIR . '/config/db.config.php')) + die('Not writing config file'); + + // Класс для работы с БД + require_once (BASE_DIR . '/class/class.database.php'); + + //-- Подключаем конфигурационный файл с параметрами подключения + require_once (BASE_DIR . '/config/db.config.php'); + + //-- Если не существует объекта по работе с БД + if (! isset($AVE_DB)) + { + //-- Если параметры не указаны, прерываем работу + if (! isset($config) || empty($config)) + die('No config data'); + + //-- Если константа префикса таблиц не задана, принудительно определяем ее на основании параметров в файле db.config.php + if (! defined('PREFIX')) + define('PREFIX', $config['dbpref']); + + //-- Создаем объект для работы с БД + try { + $AVE_DB = AVE_DB::getInstance($config) + //-- Назначаем кодировку + ->setCharset('utf8') + //-- Назначаем БД + ->setDatabaseName($config['dbname']); + } + catch (AVE_DB_Exception $e) + { + ob_start(); + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + header('Retry-After: 3600'); + header('X-Powered-By:'); + echo $e->getMessage(); + die; + } + + unset ($config); + } + + // Открываем файл структуры БД + $filename = BASE_DIR . '/install/structure_base.sql'; + + $handle = fopen($filename, 'r'); + $db_structure = fread($handle, filesize($filename)); + + fclose($handle); + + // Подставляем префикс + $db_structure = str_replace('%%PRFX%%', $_POST['dbprefix'], $db_structure); + + // Массив запросов + $ar = explode('#inst#', $db_structure); + + foreach ($ar as $sql) + if (! empty($sql)) + $AVE_DB->Query($sql); + + $AVE_Template->display('step5.tpl'); + exit; + } + elseif (true === $connect && true === $check_installed) + $AVE_Template->assign('installed', $AVE_Template->get_config_vars('database_installed')); + else + $AVE_Template->assign('warning', $AVE_Template->get_config_vars('database_not_connect')); + } + else + { + $dbpref = make_random_string(5, 'abcdefghijklmnopqrstuvwxyz0123456789'); + $AVE_Template->assign('dbpref', $dbpref); + } + + $AVE_Template->display('step4.tpl'); + break; + + case '5' : + $_POST['email'] = chop($_POST['email']); + $_POST['username'] = chop($_POST['username']); + + $regex_username = '/[^\w-]/'; + $regex_password = '/[^\x20-\xFF]/'; + $regex_email = '/^[\w.-]+@[a-z0-9.-]+\.(?:[a-z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)$/i'; + + // Класс для работы с БД + require_once (BASE_DIR . '/class/class.database.php'); + + //-- Если не существует объекта по работе с БД + if (! isset($AVE_DB)) + { + //-- Подключаем конфигурационный файл с параметрами подключения + require_once (BASE_DIR . '/config/db.config.php'); + + //-- Если параметры не указаны, прерываем работу + if (! isset($config)) + exit; + + //-- Если константа префикса таблиц не задана, принудительно определяем ее на основании параметров в файле db.config.php + if (! defined('PREFIX')) + define('PREFIX', $config['dbpref']); + + //-- Создаем объект для работы с БД + try { + $AVE_DB = AVE_DB::getInstance($config) + //-- Назначаем кодировку + ->setCharset('utf8') + //-- Назначаем БД + ->setDatabaseName($config['dbname']); + } + catch (AVE_DB_Exception $e) + { + ob_start(); + header('HTTP/1.1 503 Service Temporarily Unavailable'); + header('Status: 503 Service Temporarily Unavailable'); + header('Retry-After: 3600'); + header('X-Powered-By:'); + echo $e->getMessage(); + die; + } + } + + $errors = array(); + if ($_POST['email'] == '') array_push($errors, $AVE_Template->get_config_vars('noemail')); + if (! preg_match($regex_email, $_POST['email'])) array_push($errors, $AVE_Template->get_config_vars('email_no_specialchars')); + if (empty($_POST['pass']) || preg_match($regex_password, $_POST['pass'])) array_push($errors, $AVE_Template->get_config_vars('check_pass')); + if (strlen($_POST['pass']) < 5) array_push($errors, $AVE_Template->get_config_vars('pass_too_small')); + if (empty($_POST['username']) || preg_match($regex_username, $_POST['username'])) array_push($errors, $AVE_Template->get_config_vars('check_username')); + + $AVE_Template->assign('errors', $errors); + + if (true === $db_connect && ! sizeof($errors)) + { + if (isset($_POST['demo']) && 1 == $_POST['demo']) + $filename = BASE_DIR . '/install/data_demo.sql'; + else + $filename = BASE_DIR . '/install/data_base.sql'; + + $handle = fopen($filename, 'r'); + $dbin = fread($handle, filesize($filename)); + fclose($handle); + + $salt = make_random_string(); + $hash = md5(md5($_POST['pass'] . $salt)); + + $dbin = str_replace('%%SITENAME%%', $ver, $dbin); + $dbin = str_replace('%%PRFX%%', $config['dbpref'], $dbin); + $dbin = str_replace('%%EMAIL%%', $_POST['email'], $dbin); + $dbin = str_replace('%%SALT%%', $salt, $dbin); + $dbin = str_replace('%%PASS%%', $hash, $dbin); + $dbin = str_replace('%%TIME%%', time(), $dbin); + $dbin = str_replace('%%FIRSTNAME%%', $_POST['firstname'], $dbin); + $dbin = str_replace('%%LASTNAME%%', $_POST['lastname'], $dbin); + $dbin = str_replace('%%USERNAME%%', $_POST['username'], $dbin); + + $ar = explode('#inst#', $dbin); + + foreach ($ar as $sql) + if (! empty($sql)) + $AVE_DB->Query($sql); + + $AVE_Template->display('step6.tpl'); + + exit; + } + + $AVE_Template->display('step5.tpl'); + break; +} +?> diff --git a/install/lang/bg.js b/install/lang/bg.js new file mode 100644 index 0000000..7528f34 --- /dev/null +++ b/install/lang/bg.js @@ -0,0 +1,2 @@ +var cancelTitle = "Прекъсване на инсталацията"; +var cancelConfirm = "Сигурни ли сте, че желаете да прекратите инсталацията?"; \ No newline at end of file diff --git a/install/lang/bg.txt b/install/lang/bg.txt new file mode 100644 index 0000000..7208d97 --- /dev/null +++ b/install/lang/bg.txt @@ -0,0 +1,128 @@ +install = "Инсталиране" + +oficial_site = "Сайт" +support = "Техническа поддръжка" + +bread_information = "Информация за система за управление на сайт AVE.CMS" +bread_lictexttitle = "Лицензно съглашение" +bread_server = "Проверка за съответствие на сървъра" +bread_database_setting = "Настройка на параметрите за свързване с базата данни" +bread_install_type = "Избор на типа на инсталация" +bread_stepstatus = "Създаване на Администраторски профил" +bread_install_finish = "Инсталацията завърши успешно!" + +step_info = "Информация за система за управление на сайт AVE.CMS" +step_data_1 = "Инсталационната прогрма ще провери дали софтера на сървъра отговаря на системните изисквания на AVE.CMS, ще инсталира и конфигурира системата." +step_data_2 = "При възникнали проблеми, моля обърнете си към техническата поддръжка." +step_data_3 = "Благодарим за избора на системата за управление на сайтове AVE.CMS!" + +database_setting_desc = "Моля, въведете параметрите, необходими за връзка с данновия сървър." +install_help = "Помощ за инсталацията" +install_step = "Стъпка" + +install_demo = "Демо съдържание" +install_clear = "Празна версия на системата" +install_setting_desc = "Изберете типа на исталация на системата" + +loginstar = "Полета обозначени с * са задължителни за попълване." + +field_host = "В полето трябва да се въведе името или IP адреса на данновия сървър. По подразбиране се използва "localhost"." +field_user = "В полето трябва да се въведе името на потребителя за връзка с данновия сървър. По подразбиране "root"." +field_pass = "В полето трябва да се въведе паролата за връзка с данновия сървър. По подразбиране "без парола"." +field_name = "В полето трябва да въведе наименованието на базата данни." +field_prf = "В полето трябва да се въведе префикса за всички таблици в базата данни. Може да използвате произволно буквеноцифрова комбинация. По подразбиране се генерира случайна комбинация." +field_setting_desc = "Демо съдържание - системата се инсталира с модули и примерни данни. Препоръчва се за първоначално запознаване със системата." +database_setting = "Моля, въведете параметрите за връзка с данновия сървър." +database_setting_foot = "Ако всички параметри са верно въведени и вие сте готови да продължите инсталацията, натиснете "Запази и продължи". За прекратяване на инсталацията натиснете "Прекъсни инсталацията"." +database_clean = "При изчистване на базата данни, цялата информация в нея ще бъде изтрита!" +database_setting_save = "Запази и продължи" +database_not_checked = "Не установявайте този флаг, ако базата е вече създадена!" + +exit = "Прекъсни инсталацията" + +lic_text = "Моля, внимателно прочетете лицензионното съглашение, преди да продължите инсталацията." +lic_agree = "Приемам лицензионното съглашение." +lic_msg = "Ако приемате лицензионното съглашение, натиснете "Продължи инсталацията". За прекратяване на инсталацията натиснете "Прекъсни инсталацията"." +lic_ok = "Продължи инсталацията" + +dbserver = "Адрес на данновия сървър:" +dbuser = "Потребител на базата данни:" +dbname = "Наименование на базата данни:" +dbpass = "Парола за базата данни:" +dbprefix = "Префикс за таблиците:" +dbcreat = "Създай базата данни:" +dbclear = "Изчистване на базата данни:" + +admin_create = "Административния профил е успешно създаден." +header_logindata = "Моля, бъдете много внимателни при попълването на полетата." +login_data = "Данни за профила:" +login_field = "Полетата, маркирани с * са задължителни за попълване." +username = "Име на потребител" +email = "Имейл" +password = "Парола" + + +noemail = "Моля, въведете имейл адрес." +email_no_specialchars = "Грешка! Имейла съдържа недопустими символи." +nopass = "Моля, въведете парола" +pass_no_specialchars = "Грешка! Паролата съдържа специални символи." +install_finish_body = "
      • Задължително изтрийте папка
        /install/

      • • За преход в административния панел натиснете тук

        • За преход към сайта натиснете тук
      " + +structure = "Създаване на структурата на базата данни:" +erroro = "Възникна грешка..." +erroro_more = "Възникнаха грешки..." +secondchance = "Моля, отстранете всички грешки и пробвайте отново." +warning_force = "Внимание! Ако продължите инсталацията, въпреки предупрежденията, системата може да не работи правилно." +button_setup_next = "Продължи инсталацията" +button_setup_final = "Завърши инсталацията" +help_icon = "" +confirm_exit = "Сигурни ли сте, че желаете да прекъснете инсталацията?" + +templates_c_notwritable = "
      Ошибка!
      Инсталацията не може да продължи защото липсват права за запис в папка /cache/smarty/.
      Моля, променете правата с помощта на вашия FTP клиент." + +database_not_connect = "Не може да се установи съединение с базата данни. Моля проверете параметрите." +database_installed = "• Установена е връзка с базата данни, но в нея са открити таблици с въведения от вас префикс.
      • Моля, променете префикса, или установете флага 'Изчистване на базата данни' (ще бъдат изтрити само таблиците с указания от вас префикс)." +installed = "Внимание, системата е вече инсталирана. Ако е необходимо да направите допълнителна инсталация, моля използвайте друга база данни.

      За преминете към сайта, Натиснете тук" +error_is_required = "Файл '" +error_is_required_2 = "' не съществува." +error_is_writeable = "Папката '" +error_is_writeable_2 = "' няма права за запис." +phpversion_toold = "Текущата PHP версия е остаряла. За работата на системата е необхДля работы системы требуется версия не по-ниска от: " +force = "Игнорирай предупрежденията" +force_impossibly = "невъзможно!" +config_isnt_writeable = "Грешка! Файлът '/inc/db.config.php' няма права за запис.
      Моля, променете правата на файла с помощта на вашия FTP-клиент." +check_pass = "Моля, проверете паролата." +pass_too_small = "Въведената парола е много къса, минималната дължина на паролата е 5 символа." +check_username = "Моля, проверете Името на потребителя." +check_name = "Моля, проверете вашето Име." +check_last_name = "Моля, проверете вашата Фамилия." +error_reload = "Проба за продължаване на инсталацията" + +mess_on = "Включено" +mess_off = "Изключено" +mess_supported = "Поддържа се" +mess_unsupported = "Не се поддържа" +mess_undefined = "Неопределено" +seconds = "сек." +megabytes = "М" + +col_parametr = "Параметър" +col_requered = "Изисква се" +col_have = "Открито" + +php_version = "Версия PHP" +mysql_version = "Версия MySQL" +gd_version = "Версия GD" +prce_version = "Версия PCRE" +mbstring = "Multibyte String" +json = "JSON" +simple_xml = "SimpleXML" +iconv = "Iconv" +xslt = "Поддръка на XSLT" +max_upload = "Максимален размер за качване" +max_time = "Максимално време за изпълнение" +disk_space = "Дисково пространство" +memmory_limit = "Обем памет" +php_safe = "Защитен режим на PHP" +register_globals = "Глобални променливи" +magic_qoutes = "Магически кавички" \ No newline at end of file diff --git a/install/lang/ru.js b/install/lang/ru.js new file mode 100644 index 0000000..50221d9 --- /dev/null +++ b/install/lang/ru.js @@ -0,0 +1,2 @@ +var cancelTitle = "Отмена установки"; +var cancelConfirm = "Вы уверены, что хотите отменить установку?"; \ No newline at end of file diff --git a/install/lang/ru.txt b/install/lang/ru.txt new file mode 100644 index 0000000..1220341 --- /dev/null +++ b/install/lang/ru.txt @@ -0,0 +1,130 @@ +install = "Установка" + +oficial_site = "Официальный сайт" +support = "Служба технической поддержки" + +bread_information = "Информация о системе управления сайтом AVE.CMS" +bread_lictexttitle = "Лицензионное соглашение" +bread_server = "Проверка соответствия параметров сервера" +bread_database_setting = "Настройка параметров для соединения с базой данных" +bread_install_type = "Выбор типа установки" +bread_stepstatus = "Создание учетной записи Администратора" +bread_install_finish = "Установка успешно завершена!" + +step_info = "Информация о системе управления сайтом AVE.CMS" +step_data_1 = "Программа установки проверит соответствие программного обеспечения на сервере системным требованиям AVE.CMS, произведет установку и первоначальное конфигурирование системы управления сайтом AVE.CMS." +step_data_2 = "В случае возникновения вопросов или неточностей в работе системы управления сайтом AVE.CMS, просим обращаться в службу технической поддержки." +step_data_3 = "Благодарим за выбор системы управления сайтом AVE.CMS!" + +database_setting_desc = "Пожалуйста, укажите параметры, необходимые для установки соединения с сервером базы данных." +install_help = "Помощь в установке" +install_step = "Шаг" + +install_demo = "Демонстрационный контент" +install_clear = "Чистая версия системы" +install_setting_desc = "Выберите тип установки системы" + +loginstar = "Поля отмеченные * обязательны для заполнения." + +field_host = "В данном поле необходимо указать имя или IP адрес сервера базы данных. По умолчанию используется "localhost"." +field_user = "В данном поле необходимо указать имя пользователя для соединения с базой данных. По умолчанию "root"." +field_pass = "В данном поле необходимо указать пароль для соединения с базой данных. По умолчанию "без пароля"." +field_name = "В данном поле необходимо указать название используемой базы данных." +field_prf = "В данном поле необходимо указать префикс, который будет установлен для всех таблиц в базе данных. Вы можете использоваь любое, буквенно - цифровое значение. По умолчанию значение сгенерировано случайно." +field_setting_desc = "Демонстрационный контент - система с установленными модулями и некоторыми примерами данных. Рекомендуется для первой установки и ознакомления с системой." +database_setting = "Пожалуйста, укажите параметры, необходимые для установки соединения с сервером базы данных." +database_setting_foot = "Если все параметры указаны верно и вы готовы продолжить установку, нажмите "Сохранить и продолжить". Для прекращения установки нажмите "Отменить установку"." +database_clean = "При очищении базы данных все данные из нее будут удалены!" +database_setting_save = "Сохранить и продолжить" +database_not_checked = "Не устанавливайте этот флажок, если база данных уже создана!" + +exit = "Отменить установку" + +lic_text = "Пожалуйста, внимательно прочитайте лицензионное соглашение, прежде чем продолжить установку." +lic_agree = "Принимаю лицензионное соглашение." +lic_msg = "Если вы принимаете лицензионное соглашение, нажмите "Продолжить установку". Для прекращения установки нажмите "Отменить установку"." +lic_ok = "Продолжить установку" + +dbserver = "Адрес сервера базы данных:" +dbuser = "Имя пользователя базы данных:" +dbname = "Название базы данных:" +dbpass = "Пароль базы данных:" +dbprefix = "Префикс для таблиц:" +dbcreat = "Создать базу данных:" +dbclear = "Очистить базу данных:" + +admin_create = "Учетная запись Администратора успешно создана." +header_logindata = "Пожалуйста, будьте предельно внимательны при заполнении полей." +login_data = "Данные для учетной записи:" +login_field = "Поля отмеченные * обязательны для заполнения." +username = "Имя пользователя" +email = "E-mail" +password = "Пароль" + + +noemail = "Пожалуйста, укажите E-mail адрес." +email_no_specialchars = "Ошибка! E-mail адрес содержит недопустимые символы." +nopass = "Пожалуйста, укажите пароль" +pass_no_specialchars = "Ошибка! Пароль содержит специальные символы." +install_finish_body = "
      • Удалите, пожалуйста, папку
        /install/

      • • Для перехода в панель управления нажмите здесь

        • Для перехода на сайт нажмите здесь
      " + +structure = "Создание структуры базы данных:" +erroro = "Возникла ошибка..." +erroro_more = "Возникли ошибки..." +secondchance = "Пожалуйста, устраните все ошибки и попробуйте снова." +warning_force = "Внимание! Если вы продолжите установку, несмотря на все предупреждения об ошибках, программное обеспечение может работать некорректно." +button_setup_next = "Продолжить установку" +button_setup_final = "Завершить установку" +help_icon = "" +confirm_exit = "Вы уверены, что хотите отменить установку?" + +templates_c_notwritable = "
      Ошибка!
      Невозможно продолжить установку системы по причине отсутствия прав на запись в папку /cache/smarty/.
      Пожалуйста, измените права с помощью Вашего FTP клиента." + +database_not_connect = "Невозможно установить соединение с базой данных. Пожалуйста, проверьте параметры." +database_installed = "• Соединение с базой данных установлено, однако в ней обнаружены таблицы с указанным Вами префиксом.
      • Пожалуйста, измените префикс либо отметьте галочкой 'Очистить базу данных' (будут удалены только таблицы с указанным Вами префиксом)." +installed = "Внимание, система уже установлена. Если вам необходимо выполнить дополнительную установку, пожалуйста, используйте другую базу данных.

      Чтобы перейти на сайт, нажмите здесь" +error_is_link = "Ошибка соединения: " +error_is_create = "Ошибка при создании базы данных: " +error_is_required = "Файл '" +error_is_required_2 = "' не существует." +error_is_writeable = "Папка '" +error_is_writeable_2 = "' не имеет прав на запись." +phpversion_toold = "Текущая версия PHP устарела. Для работы системы требуется версия не ниже: " +force = "Игнорировать предупреждения" +force_impossibly = "невозможно!" +config_isnt_writeable = "Ошибка! Файл '/config/db.config.php' не имеет прав на запись.
      Пожалуйста, измените права на файл с помощью вашего FTP-клиента." +check_pass = "Пожалуйста, проверьте пароль." +pass_too_small = "Указанный пароль слишком короткий, минимальная длина пароля должна быть не менее 5 символов." +check_username = "Пожалуйста, проверьте Имя пользователя." +check_name = "Пожалуйста, проверьте Ваше Имя." +check_last_name = "Пожалуйста, проверьте Вашу Фамилию." +error_reload = "Попытаться продолжить установку" + +mess_on = "Включено" +mess_off = "Отключено" +mess_supported = "Поддерживается" +mess_unsupported = "Не поддерживается" +mess_undefined = "Неопределено" +seconds = "сек." +megabytes = "М" + +col_parametr = "Параметр" +col_requered = "Требуется" +col_have = "Имеется" + +php_version = "Версия PHP" +mysql_version = "Версия MySQL" +gd_version = "Версия GD" +prce_version = "Версия PCRE" +mbstring = "Multibyte String" +json = "JSON" +simple_xml = "SimpleXML" +iconv = "Iconv" +xslt = "Поддержка XSLT" +max_upload = "Максимальный размер загружаемых данных" +max_time = "Максимальное время исполнения" +disk_space = "Дисковое пространство" +memmory_limit = "Объем памяти" +php_safe = "Защищённый режим PHP" +register_globals = "Глобальные переменные" +magic_qoutes = "Магические кавычки" \ No newline at end of file diff --git a/install/structure_base.sql b/install/structure_base.sql new file mode 100644 index 0000000..1dfb626 --- /dev/null +++ b/install/structure_base.sql @@ -0,0 +1,592 @@ +CREATE TABLE `%%PRFX%%_blocks` ( + `id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `block_name` varchar(255) NOT NULL, + `block_description` tinytext NOT NULL, + `block_alias` varchar(20) NOT NULL, + `block_text` longtext NOT NULL, + `block_active` enum('0','1') NOT NULL DEFAULT '1', + `block_author_id` int(10) unsigned NOT NULL DEFAULT '1', + `block_created` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `block_alias` (`block_alias`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_countries` ( + `Id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `country_code` char(2) NOT NULL DEFAULT 'RU', + `country_name` char(50) NOT NULL, + `country_status` enum('1','2') NOT NULL DEFAULT '2', + `country_eu` enum('1','2') NOT NULL DEFAULT '2', + PRIMARY KEY (`Id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_document_alias_history` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `document_id` int(10) unsigned NOT NULL DEFAULT '0', + `document_alias` varchar(255) NOT NULL, + `document_alias_author` mediumint(5) unsigned NOT NULL DEFAULT '1', + `document_alias_changed` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`), + UNIQUE KEY `alias` (`document_alias`), + KEY `document_id` (`document_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_document_fields` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `rubric_field_id` mediumint(5) unsigned NOT NULL DEFAULT '0', + `document_id` int(10) unsigned NOT NULL DEFAULT '0', + `field_number_value` decimal(18,4) NOT NULL DEFAULT '0.0000', + `field_value` varchar(500) NOT NULL, + `document_in_search` enum('1','0') NOT NULL DEFAULT '1', + PRIMARY KEY (`Id`), + KEY `document_id` (`document_id`), + KEY `field_value` (`field_value`(333)), + KEY `rubric_field_id` (`rubric_field_id`), + KEY `queries` (`document_id`,`rubric_field_id`), + KEY `requests_num` (`rubric_field_id`,`field_number_value`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_document_fields_text` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `rubric_field_id` mediumint(5) unsigned NOT NULL DEFAULT '0', + `document_id` int(10) unsigned NOT NULL DEFAULT '0', + `field_value` longtext NOT NULL, + PRIMARY KEY (`Id`), + KEY `document_id` (`document_id`), + KEY `field_id` (`rubric_field_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_document_keywords` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `document_id` int(11) NOT NULL, + `keyword` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + KEY `document_id` (`document_id`), + KEY `keyword` (`keyword`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_document_remarks` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `document_id` int(10) unsigned NOT NULL DEFAULT '0', + `remark_first` enum('0','1') NOT NULL DEFAULT '0', + `remark_title` varchar(255) NOT NULL, + `remark_text` text NOT NULL, + `remark_author_id` int(10) unsigned NOT NULL DEFAULT '1', + `remark_published` int(10) unsigned NOT NULL DEFAULT '0', + `remark_status` enum('1','0') NOT NULL DEFAULT '1', + `remark_author_email` varchar(255) NOT NULL, + PRIMARY KEY (`Id`), + KEY `document_id` (`document_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_document_rev` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `doc_id` mediumint(5) unsigned NOT NULL DEFAULT '0', + `doc_revision` int(10) unsigned NOT NULL DEFAULT '0', + `doc_data` longtext NOT NULL, + `user_id` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`), + KEY `doc_id` (`doc_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_document_tags` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `rubric_id` int(3) NOT NULL, + `document_id` int(11) NOT NULL, + `tag` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + KEY `rubric_id` (`rubric_id`), + KEY `document_id` (`document_id`), + KEY `tag` (`tag`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_documents` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` mediumint(5) unsigned NOT NULL DEFAULT '0', + `rubric_tmpl_id` mediumint(5) unsigned NOT NULL DEFAULT '0', + `document_parent` int(10) unsigned NOT NULL DEFAULT '0', + `document_alias` varchar(255) NOT NULL, + `document_alias_history` enum('0','1','2') NOT NULL DEFAULT '0', + `document_short_alias` varchar(10) NOT NULL DEFAULT '', + `document_title` varchar(255) NOT NULL, + `document_breadcrum_title` varchar(255) NOT NULL, + `document_published` int(10) unsigned NOT NULL DEFAULT '0', + `document_expire` int(10) unsigned NOT NULL DEFAULT '0', + `document_changed` int(10) unsigned NOT NULL DEFAULT '0', + `document_author_id` mediumint(5) unsigned NOT NULL DEFAULT '1', + `document_in_search` enum('1','0') NOT NULL DEFAULT '1', + `document_meta_keywords` text NOT NULL, + `document_meta_description` text NOT NULL, + `document_meta_robots` enum('index,follow','index,nofollow','noindex,nofollow') NOT NULL DEFAULT 'index,follow', + `document_sitemap_freq` tinyint(1) NOT NULL DEFAULT '3', + `document_sitemap_pr` float NOT NULL DEFAULT '0.5', + `document_status` enum('1','0') NOT NULL DEFAULT '1', + `document_deleted` enum('0','1') NOT NULL DEFAULT '0', + `document_count_print` int(10) unsigned NOT NULL DEFAULT '0', + `document_count_view` int(10) unsigned NOT NULL DEFAULT '0', + `document_linked_navi_id` mediumint(5) unsigned NOT NULL DEFAULT '0', + `document_teaser` text NOT NULL, + `document_tags` text NOT NULL, + `document_lang` varchar(5) NOT NULL, + `document_lang_group` int(10) NOT NULL DEFAULT '0', + `document_property` text, + `document_rating` int(1) unsigned NOT NULL DEFAULT '0', + `document_position` int(10) NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`), + UNIQUE KEY `alias` (`document_alias`), + KEY `rubric_id` (`rubric_id`), + KEY `parent` (`document_parent`), + KEY `published` (`document_published`), + KEY `expire` (`document_expire`), + KEY `status` (`document_status`), + KEY `deleted` (`document_deleted`), + KEY `count_view` (`document_count_view`), + KEY `request_cond` (`Id`,`rubric_id`,`document_status`,`document_deleted`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_module` ( + `Id` smallint(3) unsigned NOT NULL AUTO_INCREMENT, + `ModuleName` char(50) NOT NULL, + `ModuleStatus` enum('1','0') NOT NULL DEFAULT '1', + `ModuleAveTag` char(255) NOT NULL, + `ModulePHPTag` char(255) NOT NULL, + `ModuleFunction` char(255) NOT NULL, + `ModuleIsFunction` enum('1','0') NOT NULL DEFAULT '1', + `ModuleSysName` char(50) NOT NULL, + `ModuleVersion` char(20) NOT NULL DEFAULT '1.0', + `ModuleTemplate` smallint(3) unsigned NOT NULL DEFAULT '1', + `ModuleAdminEdit` enum('0','1') NOT NULL DEFAULT '0', + `ModuleSettings` text, + PRIMARY KEY (`Id`), + UNIQUE KEY `name` (`ModuleName`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_modules_aliases` ( + `id` tinyint(5) unsigned NOT NULL AUTO_INCREMENT, + `document_id` int(10) NOT NULL DEFAULT '0', + `module_name` char(50) NOT NULL DEFAULT '', + `module_action` varchar(255) NOT NULL DEFAULT '', + `module_link` varchar(500) NOT NULL DEFAULT '', + `module_link_name` varchar(255) NOT NULL DEFAULT '', + `module_url` varchar(255) NOT NULL DEFAULT '', + `module_admin` enum('0','1') NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + UNIQUE KEY `url` (`module_url`), + KEY `name` (`module_name`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_navigation` ( + `navigation_id` smallint(3) unsigned NOT NULL AUTO_INCREMENT, + `alias` varchar(20) NOT NULL, + `title` varchar(255) NOT NULL, + `level1` text NOT NULL, + `level2` text NOT NULL, + `level3` text NOT NULL, + `level1_active` text NOT NULL, + `level2_active` text NOT NULL, + `level3_active` text NOT NULL, + `level1_begin` text NOT NULL, + `level1_end` text NOT NULL, + `level2_begin` text NOT NULL, + `level2_end` text NOT NULL, + `level3_begin` text NOT NULL, + `level3_end` text NOT NULL, + `begin` text NOT NULL, + `end` text NOT NULL, + `user_group` text NOT NULL, + `expand_ext` enum('0','1','2') DEFAULT '1', + PRIMARY KEY (`navigation_id`), + KEY `alias` (`alias`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_navigation_items` ( + `navigation_item_id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `navigation_id` smallint(3) unsigned NOT NULL DEFAULT '0', + `document_id` int(11) DEFAULT NULL, + `alias` char(255) NOT NULL, + `title` char(255) NOT NULL, + `description` text NOT NULL, + `target` enum('_blank','_self','_parent','_top') NOT NULL DEFAULT '_self', + `image` varchar(255) NOT NULL, + `css_style` varchar(255) DEFAULT NULL, + `css_id` varchar(50) DEFAULT NULL, + `css_class` varchar(255) DEFAULT NULL, + `parent_id` mediumint(5) unsigned NOT NULL, + `level` enum('1','2','3') NOT NULL DEFAULT '1', + `position` smallint(3) unsigned NOT NULL DEFAULT '1', + `status` enum('1','0') NOT NULL DEFAULT '1', + PRIMARY KEY (`navigation_item_id`), + KEY `navi_id` (`navigation_id`), + KEY `document_alias` (`document_id`), + KEY `status` (`status`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_paginations` ( + `id` tinyint(1) unsigned NOT NULL AUTO_INCREMENT, + `pagination_name` tinytext, + `pagination_box` varchar(255) NOT NULL, + `pagination_start_label` varchar(255) NOT NULL, + `pagination_end_label` varchar(255) NOT NULL, + `pagination_separator_box` varchar(255) NOT NULL, + `pagination_separator_label` varchar(255) NOT NULL, + `pagination_next_label` varchar(255) NOT NULL, + `pagination_prev_label` varchar(255) NOT NULL, + `pagination_link_box` varchar(255) NOT NULL, + `pagination_active_link_box` varchar(255) NOT NULL, + `pagination_link_template` varchar(255) DEFAULT NULL, + `pagination_link_active_template` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_request` ( + `Id` smallint(3) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `request_alias` varchar(20) NOT NULL, + `request_items_per_page` smallint(3) unsigned NOT NULL, + `request_title` varchar(255) NOT NULL, + `request_template_item` text NOT NULL, + `request_template_main` text NOT NULL, + `request_order_by` varchar(255) NOT NULL, + `request_order_by_nat` int(10) NOT NULL DEFAULT '0', + `request_author_id` int(10) unsigned NOT NULL DEFAULT '1', + `request_created` int(10) unsigned NOT NULL, + `request_description` tinytext NOT NULL, + `request_asc_desc` enum('ASC','DESC') NOT NULL DEFAULT 'DESC', + `request_show_pagination` enum('0','1') NOT NULL DEFAULT '0', + `request_pagination` smallint(3) unsigned NOT NULL DEFAULT '1', + `request_use_query` enum('0','1') NOT NULL DEFAULT '0', + `request_count_items` enum('0','1') NOT NULL DEFAULT '0', + `request_where_cond` text NOT NULL, + `request_hide_current` enum('0','1') NOT NULL DEFAULT '1', + `request_only_owner` enum('0','1') NOT NULL DEFAULT '0', + `request_cache_lifetime` int(11) NOT NULL DEFAULT '0', + `request_lang` enum('1','0') NOT NULL DEFAULT '0', + `request_cache_elements` enum('0','1') NOT NULL DEFAULT '0', + `request_show_statistic` enum('0','1') NOT NULL DEFAULT '0', + `request_external` enum('0','1') NOT NULL DEFAULT '0', + `request_ajax` enum('0','1') NOT NULL DEFAULT '0', + `request_show_sql` enum('0','1') NOT NULL DEFAULT '0', + `request_changed` int(10) unsigned NOT NULL DEFAULT '0', + `request_changed_elements` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`), + KEY `id` (`rubric_id`), + KEY `alias` (`request_alias`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_request_conditions` ( + `Id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `request_id` smallint(3) unsigned NOT NULL, + `condition_compare` char(30) NOT NULL, + `condition_field_id` int(10) NOT NULL, + `condition_value` varchar(1000) NOT NULL, + `condition_join` enum('OR','AND') NOT NULL DEFAULT 'AND', + `condition_position` smallint(3) unsigned NOT NULL DEFAULT '1', + `condition_status` enum('0','1') NOT NULL DEFAULT '1', + PRIMARY KEY (`Id`), + KEY `request_id` (`request_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_rubric_breadcrumb` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `box` varchar(500) NOT NULL DEFAULT '', + `show_main` enum('1','0') NOT NULL DEFAULT '1', + `show_host` enum('1','0') NOT NULL DEFAULT '1', + `sepparator` varchar(255) NOT NULL, + `sepparator_use` enum('1','0') NOT NULL DEFAULT '1', + `link_box` varchar(500) NOT NULL DEFAULT '', + `link_template` varchar(500) NOT NULL DEFAULT '', + `self_box` varchar(500) NOT NULL DEFAULT '', + `link_box_last` enum('1','0') NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `rubric_id` (`rubric_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_rubric_fields` ( + `Id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `rubric_field_group` smallint(3) unsigned NOT NULL, + `rubric_field_alias` varchar(20) NOT NULL, + `rubric_field_title` varchar(255) NOT NULL, + `rubric_field_type` varchar(75) NOT NULL, + `rubric_field_numeric` enum('0','1') NOT NULL DEFAULT '0', + `rubric_field_position` smallint(3) unsigned NOT NULL DEFAULT '1', + `rubric_field_default` text NOT NULL, + `rubric_field_search` enum('0','1') NOT NULL DEFAULT '1', + `rubric_field_template` text NOT NULL, + `rubric_field_template_request` text NOT NULL, + `rubric_field_description` text NOT NULL, + PRIMARY KEY (`Id`), + KEY `rubric_id` (`rubric_id`), + KEY `field_type` (`rubric_field_type`), + KEY `field_alias` (`rubric_field_alias`), + KEY `rubgroups` (`rubric_id`,`rubric_field_group`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_rubric_fields_group` ( + `Id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `group_position` smallint(3) unsigned NOT NULL, + `group_title` varchar(255) NOT NULL, + `group_description` text NOT NULL, + PRIMARY KEY (`Id`), + KEY `rubric_id` (`rubric_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_rubric_permissions` ( + `Id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `user_group_id` smallint(3) unsigned NOT NULL, + `rubric_permission` char(255) NOT NULL, + PRIMARY KEY (`Id`), + KEY `rubric_id` (`rubric_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_rubric_templates` ( + `id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `title` varchar(255) NOT NULL, + `template` longtext NOT NULL, + `author_id` int(10) unsigned NOT NULL DEFAULT '1', + `created` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `rubric_id` (`rubric_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_rubrics` ( + `Id` smallint(3) unsigned NOT NULL AUTO_INCREMENT, + `rubric_title` varchar(255) NOT NULL, + `rubric_alias` varchar(255) NOT NULL, + `rubric_alias_history` enum('0','1') NOT NULL DEFAULT '0', + `rubric_template` longtext NOT NULL, + `rubric_template_id` smallint(3) unsigned NOT NULL DEFAULT '1', + `rubric_author_id` int(10) unsigned NOT NULL DEFAULT '1', + `rubric_created` int(10) unsigned NOT NULL DEFAULT '0', + `rubric_docs_active` int(1) unsigned NOT NULL DEFAULT '1', + `rubric_start_code` text NOT NULL, + `rubric_code_start` text NOT NULL, + `rubric_code_end` text NOT NULL, + `rubric_teaser_template` text NOT NULL, + `rubric_admin_teaser_template` text NOT NULL, + `rubric_header_template` text NOT NULL, + `rubric_footer_template` text NOT NULL, + `rubric_linked_rubric` varchar(255) NOT NULL DEFAULT '0', + `rubric_description` text NOT NULL, + `rubric_meta_gen` enum('0','1') NOT NULL DEFAULT '0', + `rubric_position` int(11) unsigned NOT NULL DEFAULT '100', + `rubric_changed` int(10) NOT NULL DEFAULT '0', + `rubric_changed_fields` int(10) NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`), + KEY `template_id` (`rubric_template_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_sessions` ( + `sesskey` varchar(32) NOT NULL, + `expiry` int(10) unsigned NOT NULL DEFAULT '0', + `value` text NOT NULL, + `Ip` varchar(35) NOT NULL, + `expire_datum` varchar(25) NOT NULL, + PRIMARY KEY (`sesskey`), + KEY `expiry` (`expiry`), + KEY `expire_datum` (`expire_datum`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_settings` ( + `Id` tinyint(1) unsigned NOT NULL AUTO_INCREMENT, + `site_name` varchar(255) NOT NULL, + `mail_type` enum('mail','smtp','sendmail') NOT NULL DEFAULT 'mail', + `mail_content_type` enum('text/plain','text/html') NOT NULL DEFAULT 'text/plain', + `mail_port` smallint(3) unsigned NOT NULL DEFAULT '25', + `mail_host` varchar(255) NOT NULL, + `mail_smtp_login` varchar(255) NOT NULL, + `mail_smtp_pass` varchar(255) NOT NULL, + `mail_smtp_encrypt` varchar(255) DEFAULT NULL, + `mail_sendmail_path` varchar(255) NOT NULL DEFAULT '/usr/sbin/sendmail', + `mail_word_wrap` smallint(3) NOT NULL DEFAULT '50', + `mail_from` varchar(255) NOT NULL, + `mail_from_name` varchar(255) NOT NULL, + `mail_new_user` text NOT NULL, + `mail_signature` text NOT NULL, + `page_not_found_id` int(10) unsigned NOT NULL DEFAULT '2', + `message_forbidden` text NOT NULL, + `navi_box` varchar(255) NOT NULL, + `start_label` varchar(255) NOT NULL, + `end_label` varchar(255) NOT NULL, + `separator_label` varchar(255) NOT NULL, + `next_label` varchar(255) NOT NULL, + `prev_label` varchar(255) NOT NULL, + `total_label` varchar(255) NOT NULL, + `link_box` varchar(255) NOT NULL, + `total_box` varchar(255) NOT NULL, + `active_box` varchar(255) NOT NULL, + `separator_box` varchar(255) NOT NULL, + `bread_box` varchar(500) NOT NULL DEFAULT '', + `bread_show_main` enum('1','0') NOT NULL DEFAULT '1', + `bread_show_host` enum('1','0') NOT NULL DEFAULT '1', + `bread_sepparator` varchar(255) NOT NULL, + `bread_sepparator_use` enum('1','0') NOT NULL DEFAULT '1', + `bread_link_box` varchar(500) NOT NULL DEFAULT '', + `bread_link_template` varchar(500) NOT NULL DEFAULT '', + `bread_self_box` varchar(500) NOT NULL DEFAULT '', + `bread_link_box_last` enum('1','0') NOT NULL DEFAULT '1', + `date_format` varchar(25) NOT NULL DEFAULT '%d.%m.%Y', + `time_format` varchar(25) NOT NULL DEFAULT '%d.%m.%Y, %H:%M', + `default_country` char(2) NOT NULL DEFAULT 'RU', + `use_doctime` enum('1','0') NOT NULL DEFAULT '1', + `hidden_text` text NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_settings_lang` ( + `Id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `lang_key` varchar(2) NOT NULL DEFAULT 'ru', + `lang_name` char(50) NOT NULL, + `lang_alias_pref` varchar(10) NOT NULL, + `lang_default` enum('1','0') NOT NULL DEFAULT '0', + `lang_status` enum('1','0') NOT NULL, + PRIMARY KEY (`Id`), + UNIQUE KEY `lang_key` (`lang_key`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_settings_menu` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) DEFAULT NULL, + `link` varchar(255) DEFAULT NULL, + `position` int(3) DEFAULT NULL, + `status` enum('0','1') DEFAULT '1', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_sysblocks` ( + `id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `sysblock_group_id` int(3) unsigned NOT NULL DEFAULT '0', + `sysblock_name` varchar(255) NOT NULL, + `sysblock_description` varchar(255) DEFAULT NULL, + `sysblock_alias` varchar(20) NOT NULL, + `sysblock_text` longtext NOT NULL, + `sysblock_active` enum('0','1') NOT NULL DEFAULT '1', + `sysblock_eval` enum('0','1') NOT NULL DEFAULT '1', + `sysblock_external` enum('0','1') NOT NULL DEFAULT '0', + `sysblock_ajax` enum('0','1') NOT NULL DEFAULT '0', + `sysblock_visual` enum('0','1') NOT NULL DEFAULT '0', + `sysblock_author_id` int(10) unsigned NOT NULL DEFAULT '1', + `sysblock_created` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `alias` (`sysblock_alias`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_sysblocks_groups` ( + `id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `position` smallint(3) unsigned NOT NULL, + `title` varchar(255) NOT NULL DEFAULT '', + `description` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_templates` ( + `Id` smallint(3) unsigned NOT NULL AUTO_INCREMENT, + `template_title` varchar(255) NOT NULL, + `template_text` longtext NOT NULL, + `template_author_id` int(10) unsigned NOT NULL DEFAULT '1', + `template_created` int(10) unsigned NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_user_groups` ( + `user_group` smallint(3) unsigned NOT NULL AUTO_INCREMENT, + `user_group_name` char(50) NOT NULL, + `status` enum('1','0') NOT NULL DEFAULT '1', + `set_default_avatar` enum('1','0') NOT NULL DEFAULT '0', + `default_avatar` char(255) NOT NULL, + `user_group_permission` longtext NOT NULL, + PRIMARY KEY (`user_group`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;#inst# + + +CREATE TABLE `%%PRFX%%_users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `password` char(32) NOT NULL, + `email` char(100) NOT NULL, + `street` char(100) NOT NULL, + `street_nr` char(10) NOT NULL, + `zipcode` char(15) NOT NULL, + `city` char(100) NOT NULL, + `phone` char(35) NOT NULL, + `telefax` char(35) NOT NULL, + `description` char(255) NOT NULL, + `firstname` char(50) NOT NULL, + `lastname` char(50) NOT NULL, + `user_name` char(50) NOT NULL, + `user_group` smallint(3) unsigned NOT NULL DEFAULT '4', + `user_group_extra` char(255) NOT NULL, + `reg_time` int(10) unsigned NOT NULL, + `status` enum('1','0') NOT NULL DEFAULT '1', + `last_visit` int(10) unsigned NOT NULL, + `country` char(2) NOT NULL DEFAULT 'RU', + `birthday` char(10) NOT NULL, + `deleted` enum('0','1') NOT NULL DEFAULT '0', + `del_time` int(10) unsigned NOT NULL, + `emc` char(32) NOT NULL, + `reg_ip` char(20) NOT NULL, + `new_pass` char(32) NOT NULL, + `company` char(255) NOT NULL, + `taxpay` enum('0','1') NOT NULL DEFAULT '0', + `salt` char(16) NOT NULL, + `new_salt` char(16) NOT NULL, + `user_ip` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`Id`), + UNIQUE KEY `email` (`email`), + UNIQUE KEY `name` (`user_name`), + KEY `group` (`user_group`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_users_session` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `hash` varchar(255) NOT NULL, + `ip` int(32) unsigned NOT NULL, + `agent` varchar(255) NOT NULL, + `last_activ` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + KEY `user_id` (`user_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# + + +CREATE TABLE `%%PRFX%%_view_count` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `document_id` int(11) NOT NULL, + `day_id` int(11) NOT NULL, + `count` int(11) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;#inst# \ No newline at end of file diff --git a/install/tpl/css/fix.css b/install/tpl/css/fix.css new file mode 100644 index 0000000..2bae458 --- /dev/null +++ b/install/tpl/css/fix.css @@ -0,0 +1,4 @@ +.rowElem > label { + padding: 0 0 0 5px; + width: 20%; +} \ No newline at end of file diff --git a/install/tpl/error.tpl b/install/tpl/error.tpl new file mode 100644 index 0000000..17169f1 --- /dev/null +++ b/install/tpl/error.tpl @@ -0,0 +1,183 @@ + + + + + + + + {$error_header} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + +
      + +
      +
      + +
      + +
      {#install#} {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION}
      + + + + +
      +
      {$error_header}
      +
      + +
      + {foreach from=$error_is_required item="inc"} +
        +
      • + {$inc} +
      • +
      + {/foreach} +
      + + {if $config_isnt_writeable == 1} +
        +
      • + {#config_isnt_writeable#} +
      • +
      +
      + {/if} + +
        +
      • + {#secondchance#} +
      • +
      + + +
      +
      +
        +
      • + {#warning_force#} +
      • +
      +
      + +
      +
      +
      +   +
      +
      +
      + +
      +
      + +   + +
      +
      + + {if $config_isnt_writeable != 1} + + {/if} + +
      +
      + +
      +
      + + + + + \ No newline at end of file diff --git a/install/tpl/js/main.js b/install/tpl/js/main.js new file mode 100644 index 0000000..8f10ce0 --- /dev/null +++ b/install/tpl/js/main.js @@ -0,0 +1,135 @@ +/* + * Name: Ave.cms Install Scripts + * Written by: Ave.cms - (http://www.ave-cms.ru) + * Version: 1.0a + */ + +(function($) { + $.fn.addTipsy = function() { + this.find(' .topDir').tipsy({fade: false, gravity: 's', opacity: 0.9}); + this.find(' .topleftDir').tipsy({fade: false, gravity: 'se', opacity: 0.9}); + this.find(' .toprightDir').tipsy({fade: false, gravity: 'sw', opacity: 0.9}); + this.find(' .botDir').tipsy({fade: false, gravity: 'n', opacity: 0.9}); + this.find(' .bottomDir').tipsy({fade: false, gravity: 'n', opacity: 0.9}); + this.find(' .botleftDir').tipsy({fade: false, gravity: 'ne', opacity: 0.9}); + this.find(' .botrightDir').tipsy({fade: false, gravity: 'nw', opacity: 0.9}); + this.find(' .leftDir').tipsy({fade: false, gravity: 'e', opacity: 0.9}); + this.find(' .rightDir').tipsy({fade: false, gravity: 'w', opacity: 0.9}); + }; +})(jQuery); + +var AveInstall = { + + initialized: false, + + initialize: function() { + + if (this.initialized) return; + this.initialized = true; + + this.build(); + this.events(); + + }, + + build: function() { + + this.add_tipsy(); + this.placeholder(); + this.transform(); + this.ui_totop(); + this.link_hover(); + this.cancel(); + + }, + + events: function() { + + $.ajaxSetup({ + cache: false, + error: function(jqXHR, exception) { + if (jqXHR.status === 0) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus,{theme: 'error'}); + } else if (jqXHR.status == 404) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus404,{theme: 'error'}); + } else if (jqXHR.status == 401) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus401,{theme: 'error'}); + } else if (jqXHR.status == 500) { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatus500,{theme: 'error'}); + } else if (exception === 'parsererror') { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusJSON,{theme: 'error'}); + } else if (exception === 'timeout') { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusTimeOut,{theme: 'error'}); + } else if (exception === 'abort') { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusAbort,{theme: 'error'}); + } else { + $.alerts._overlay('hide'); + $.jGrowl(ajaxErrorStatusMess + jqXHR.responseText,{theme: 'error'}); + } + } + }); + + }, + + + ui_totop: function() { + + $().UItoTop({ easingType: 'easeOutQuart' }); + }, + + link_hover: function() { + $('.actions a').hover(function(){ + $(this).animate({opacity: 1.0},100); + },function(){ + $(this).animate({opacity: 0.5},100); + }); + }, + + placeholder: function() { + $('input[placeholder], textarea[placeholder]').placeholder(); + }, + + transform: function() { + $(".mainForm").jqTransform({imgPath:"../images"}); + }, + + cancel: function() { + + $("#ask-cancel").click( function(e) { + e.preventDefault(); + var thisHref = 'exit.html'; + var title = cancelTitle; + var confirm = cancelConfirm; + jConfirm( + confirm, + title, + function(b){ + if (b){ + $.alerts._overlay('hide'); + $.alerts._overlay('show'); + window.location = thisHref; + } + } + ); + }); + }, + + add_tipsy: function() { + $('body').addTipsy(); + } + +}; + + +$(window).load(function () { + + AveInstall.initialize(); + +}); \ No newline at end of file diff --git a/install/tpl/step1.tpl b/install/tpl/step1.tpl new file mode 100644 index 0000000..ecce8d0 --- /dev/null +++ b/install/tpl/step1.tpl @@ -0,0 +1,125 @@ + + + + + + + + {#bread_information#} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      {#install#} {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION}
      + + + + +
      +
      {#bread_information#}
      {#install_step#} 1
      +
      +

      {#step_info#}

      +

      {#step_data_1#}

      +

      {#step_data_2#}

      +

      {#step_data_3#}

      +
      +
      + +
      +
      + +   + +
      +
      + + + + +
      +
      + +
      +
      + + + + + + + \ No newline at end of file diff --git a/install/tpl/step2.tpl b/install/tpl/step2.tpl new file mode 100644 index 0000000..dd46673 --- /dev/null +++ b/install/tpl/step2.tpl @@ -0,0 +1,139 @@ + + + + + + + + {#bread_lictexttitle#} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      {#install#} {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION}
      + + + +
      +
      {#bread_lictexttitle#}
      {#install_step#} 2
      +
      + {include file="../eula/ru.tpl"} +
      +
      +
      + +
      +
      + +
      +
      + +   + +
      +
      + + + + +
      +
      + +
      +
      + + + + + + + + + \ No newline at end of file diff --git a/install/tpl/step3.tpl b/install/tpl/step3.tpl new file mode 100644 index 0000000..6e3b01f --- /dev/null +++ b/install/tpl/step3.tpl @@ -0,0 +1,241 @@ + + + + + + + + {#bread_server#} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      {#install#} {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION}
      + + + +
      +
      {#bread_server#}
      {#install_step#} 3
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {* + + + + + + + *} + + + + + + + + + + + + + {* + + + + + + + *} + + + + + + + {* + + + + + + + *} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#col_parametr#}{#col_requered#}{#col_have#}
      {#php_version#}:{$smarty.const.PHP_version}{$test.php_version}
      {#mysql_version#}:{$smarty.const.MySQL_version}{$test.mysql_version}
      {#gd_version#}:{$smarty.const.GD_version}{$test.gd_version}
      {#prce_version#}:{$smarty.const.PCRE_version}{$test.pcre_version}
      {#mbstring#}:{$smarty.const.MbString}{$test.mbstring}
      {#json#}:{$smarty.const.JSON}{$test.json}
      {#simple_xml#}:{$smarty.const.SimpleXML}{$test.simplexml}
      {#iconv#}:{$smarty.const.Iconv}{$test.iconv}
      {#xslt#}:{$smarty.const.XSLT}{$test.xslt}
      {#max_upload#}:{$smarty.const.Data_limit}M{$test.data_limit}
      {#max_time#}:{$smarty.const.TIME_limit} {#seconds#}{$test.time_limit} {#seconds#}
      {#disk_space#}:{$smarty.const.DISC_space}M{$test.disk_space}M
      {#memmory_limit#}:{$smarty.const.RAM_space}{$test.memmory_limit}
      {#php_safe#}:{$smarty.const.SAFE_MODE}{$test.s_m}
      {#register_globals#}:{$smarty.const.REGISTER_GLOBALS}{$test.r_g}
      {#magic_qoutes#}:{$smarty.const.MAGIC_QUOTES_GPC}{$test.m_q}
      + + +
      + +
      +
      + +   + +
      +
      + + + + +
      +
      + +
      +
      + + + + + + + \ No newline at end of file diff --git a/install/tpl/step4.tpl b/install/tpl/step4.tpl new file mode 100644 index 0000000..2deffa8 --- /dev/null +++ b/install/tpl/step4.tpl @@ -0,0 +1,193 @@ + + + + + + + + {#bread_database_setting#} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      {#install#} {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION}
      + + + +
      + {if $warning} +
        +
      • + {$warning} +
      • +
      + {elseif $installed} +
        +
      • + {$installed} +
      • +
      + {/if} +
      + +
      +
      {#bread_database_setting#}
      {#install_step#} 4
      +
      {#database_setting#}
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      ?{#col_parametr#}{#col_requered#}
      [?]{#dbserver#}
      [?]{#dbuser#}
      [?]{#dbpass#}
      [?]{#dbname#}
      [?]{#dbprefix#}
      [?]{#dbcreat#}
      [?]{#dbclear#}
      +
        +
      • {#database_setting_foot#}
      • +
      +
      + + +
      + +
      +
      + +   + +
      +
      + + + + +
      +
      + +
      +
      + + + + + + + \ No newline at end of file diff --git a/install/tpl/step5.tpl b/install/tpl/step5.tpl new file mode 100644 index 0000000..a719606 --- /dev/null +++ b/install/tpl/step5.tpl @@ -0,0 +1,166 @@ + + + + + + + + {#bread_stepstatus#} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      {#install#} {$version_setup}
      + + + +
      + {if $errors} +
        + +
      • + {foreach from=$errors item="error"} + • {$error}
        + {/foreach} +
      • + +
      + {/if} +
      + +
      +
      {#bread_stepstatus#}
      {#install_step#} 5
      +
      {#header_logindata#}
      + + + + + + + + + + + + + + + + + + + + + + + + + + +
      {#col_parametr#}{#col_requered#}
      * {#username#}:
      * {#email#}:
      * {#password#}:
      +
        +
      • {#loginstar#}
      • +
      +
      + + +
      + +
      +
      + +   + +
      +
      + + + + +
      +
      + +
      +
      + + + + + + + \ No newline at end of file diff --git a/install/tpl/step6.tpl b/install/tpl/step6.tpl new file mode 100644 index 0000000..bd13092 --- /dev/null +++ b/install/tpl/step6.tpl @@ -0,0 +1,106 @@ + + + + + + + + {#bread_install_finish#} - {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
      +
      +
      + +
      +
      +
      +
      +
      +
      + + +
      + +
      +
      + +
      + +
      {#install#} {$smarty.const.APP_NAME} v{$smarty.const.APP_VERSION}
      + + + +
      + {#install_finish_body#} +
      + +
      + +
      +
      + + + + + + + \ No newline at end of file diff --git a/lib/Smarty/.htaccess b/lib/Smarty/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/lib/Smarty/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/lib/Smarty/Config_File.class.php b/lib/Smarty/Config_File.class.php new file mode 100644 index 0000000..6d8c298 --- /dev/null +++ b/lib/Smarty/Config_File.class.php @@ -0,0 +1,393 @@ + + * @access public + * @package Smarty + */ + +/* $Id$ */ + +/** + * Config file reading class + * @package Smarty + */ +class Config_File { + /**#@+ + * Options + * @var boolean + */ + /** + * Controls whether variables with the same name overwrite each other. + */ + var $overwrite = true; + + /** + * Controls whether config values of on/true/yes and off/false/no get + * converted to boolean values automatically. + */ + var $booleanize = true; + + /** + * Controls whether hidden config sections/vars are read from the file. + */ + var $read_hidden = true; + + /** + * Controls whether or not to fix mac or dos formatted newlines. + * If set to true, \r or \r\n will be changed to \n. + */ + var $fix_newlines = true; + /**#@-*/ + + /** @access private */ + var $_config_path = ""; + var $_config_data = array(); + /**#@-*/ + + /** + * Constructs a new config file class. + * + * @param string $config_path (optional) path to the config files + */ + public function __construct($config_path = NULL) + { + if (isset($config_path)) + $this->set_path($config_path); + } + + + /** + * Set the path where configuration files can be found. + * + * @param string $config_path path to the config files + */ + function set_path($config_path) + { + if (!empty($config_path)) { + if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { + $this->_trigger_error_msg("Bad config file path '$config_path'"); + return; + } + if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { + $config_path .= DIRECTORY_SEPARATOR; + } + + $this->_config_path = $config_path; + } + } + + + /** + * Retrieves config info based on the file, section, and variable name. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @param string $var_name (optional) variable to get info for + * @return string|array a value or array of values + */ + function get($file_name, $section_name = NULL, $var_name = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) + $this->load_file($file_name, false); + } + + if (!empty($var_name)) { + if (empty($section_name)) { + return $this->_config_data[$file_name]["vars"][$var_name]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) + return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; + else + return array(); + } + } else { + if (empty($section_name)) { + return (array)$this->_config_data[$file_name]["vars"]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) + return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; + else + return array(); + } + } + } + + + /** + * Retrieves config info based on the key. + * + * @param $file_name string config key (filename/section/var) + * @return string|array same as get() + * @uses get() retrieves information from config file and returns it + */ + function &get_key($config_key) + { + list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); + $result = &$this->get($file_name, $section_name, $var_name); + return $result; + } + + /** + * Get all loaded config file names. + * + * @return array an array of loaded config file names + */ + function get_file_names() + { + return array_keys($this->_config_data); + } + + + /** + * Get all section names from a loaded file. + * + * @param string $file_name config file to get section names from + * @return array an array of section names from the specified file + */ + function get_section_names($file_name) + { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + return array_keys($this->_config_data[$file_name]["sections"]); + } + + + /** + * Get all global or section variable names. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @return array an array of variables names from the specified file/section + */ + function get_var_names($file_name, $section = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + if (empty($section)) + return array_keys($this->_config_data[$file_name]["vars"]); + else + return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); + } + + + /** + * Clear loaded config data for a certain file or all files. + * + * @param string $file_name file to clear config data for + */ + function clear($file_name = NULL) + { + if ($file_name === NULL) + $this->_config_data = array(); + else if (isset($this->_config_data[$file_name])) + $this->_config_data[$file_name] = array(); + } + + + /** + * Load a configuration file manually. + * + * @param string $file_name file name to load + * @param boolean $prepend_path whether current config path should be + * prepended to the filename + */ + function load_file($file_name, $prepend_path = true) + { + if ($prepend_path && $this->_config_path != "") + $config_file = $this->_config_path . $file_name; + else + $config_file = $file_name; + + ini_set('track_errors', true); + $fp = @fopen($config_file, "r"); + if (!is_resource($fp)) { + $this->_trigger_error_msg("Could not open config file '$config_file'"); + return false; + } + + $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; + fclose($fp); + + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * Store the contents of a file manually. + * + * @param string $config_file file name of the related contents + * @param string $contents the file-contents to parse + */ + function set_file_contents($config_file, $contents) + { + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * parse the source of a configuration file manually. + * + * @param string $contents the file-contents to parse + */ + function parse_contents($contents) + { + if($this->fix_newlines) { + // fix mac/dos formatted newlines + $contents = preg_replace('!\r\n?!', "\n", $contents); + } + + $config_data = array(); + $config_data['sections'] = array(); + $config_data['vars'] = array(); + + /* reference to fill with data */ + $vars =& $config_data['vars']; + + /* parse file line by line */ + preg_match_all('!^.*\r?\n?!m', $contents, $match); + $lines = $match[0]; + for ($i=0, $count=count($lines); $i<$count; $i++) { + $line = $lines[$i]; + if (empty($line)) continue; + + if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { + /* section found */ + if (substr($match[1], 0, 1) == '.') { + /* hidden section */ + if ($this->read_hidden) { + $section_name = substr($match[1], 1); + } else { + /* break reference to $vars to ignore hidden section */ + unset($vars); + $vars = array(); + continue; + } + } else { + $section_name = $match[1]; + } + if (!isset($config_data['sections'][$section_name])) + $config_data['sections'][$section_name] = array('vars' => array()); + $vars =& $config_data['sections'][$section_name]['vars']; + continue; + } + + if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { + /* variable found */ + $var_name = rtrim($match[1]); + if (strpos($match[2], '"""') === 0) { + /* handle multiline-value */ + $lines[$i] = substr($match[2], 3); + $var_value = ''; + while ($i<$count) { + if (($pos = strpos($lines[$i], '"""')) === false) { + $var_value .= $lines[$i++]; + } else { + /* end of multiline-value */ + $var_value .= substr($lines[$i], 0, $pos); + break; + } + } + $booleanize = false; + + } else { + /* handle simple value */ + $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); + $booleanize = $this->booleanize; + + } + $this->_set_config_var($vars, $var_name, $var_value, $booleanize); + } + /* else unparsable line / means it is a comment / means ignore it */ + } + return $config_data; + } + + /**#@+ @access private */ + /** + * @param array &$container + * @param string $var_name + * @param mixed $var_value + * @param boolean $booleanize determines whether $var_value is converted to + * to true/false + */ + function _set_config_var(&$container, $var_name, $var_value, $booleanize) + { + if (substr($var_name, 0, 1) == '.') { + if (!$this->read_hidden) + return; + else + $var_name = substr($var_name, 1); + } + + if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { + $this->_trigger_error_msg("Bad variable name '$var_name'"); + return; + } + + if ($booleanize) { + if (preg_match("/^(on|true|yes)$/i", $var_value)) + $var_value = true; + else if (preg_match("/^(off|false|no)$/i", $var_value)) + $var_value = false; + } + + if (!isset($container[$var_name]) || $this->overwrite) + $container[$var_name] = $var_value; + else { + settype($container[$var_name], 'array'); + $container[$var_name][] = $var_value; + } + } + + /** + * @uses trigger_error() creates a PHP warning/error + * @param string $error_msg + * @param integer $error_type one of + */ + function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Config_File error: $error_msg", $error_type); + } + /**#@-*/ +} + +?> diff --git a/lib/Smarty/Smarty.class.php b/lib/Smarty/Smarty.class.php new file mode 100644 index 0000000..a06e8ff --- /dev/null +++ b/lib/Smarty/Smarty.class.php @@ -0,0 +1,1968 @@ + + * @author Andrei Zmievski + * @package Smarty + * @version 2.6.31-dev + */ + +/* $Id$ */ + +/** + * DIR_SEP isn't used anymore, but third party apps might + */ +if(!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * if not defined, include_path will be used. Sets SMARTY_DIR only if user + * application has not already defined it. + */ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +if (!defined('SMARTY_CORE_DIR')) { + define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); +} + +define('SMARTY_PHP_PASSTHRU', 0); +define('SMARTY_PHP_QUOTE', 1); +define('SMARTY_PHP_REMOVE', 2); +define('SMARTY_PHP_ALLOW', 3); + +/** + * @package Smarty + */ +class Smarty +{ + /**#@+ + * Smarty Configuration Section + */ + + /** + * The name of the directory where templates are located. + * + * @var string + */ + var $template_dir = 'templates'; + + /** + * The directory where compiled templates are located. + * + * @var string + */ + var $compile_dir = 'cache/smarty'; + + /** + * The directory where config files are located. + * + * @var string + */ + var $config_dir = 'configs'; + + /** + * An array of directories searched for plugins. + * + * @var array + */ + var $plugins_dir = array('plugins'); + + /** + * If debugging is enabled, a debug console window will display + * when the page loads (make sure your browser allows unrequested + * popup windows) + * + * @var boolean + */ + var $debugging = false; + + /** + * When set, smarty does uses this value as error_reporting-level. + * + * @var integer + */ + var $error_reporting = null; + + /** + * This is the path to the debug console template. If not set, + * the default one will be used. + * + * @var string + */ + var $debug_tpl = ''; + + /** + * This determines if debugging is enable-able from the browser. + *
        + *
      • NONE => no debugging control allowed
      • + *
      • URL => enable debugging when SMARTY_DEBUG is found in the URL.
      • + *
      + * @link http://www.foo.dom/index.php?SMARTY_DEBUG + * @var string + */ + var $debugging_ctrl = 'NONE'; + + /** + * This tells Smarty whether to check for recompiling or not. Recompiling + * does not need to happen unless a template or config file is changed. + * Typically you enable this during development, and disable for + * production. + * + * @var boolean + */ + var $compile_check = true; + + /** + * This forces templates to compile every time. Useful for development + * or debugging. + * + * @var boolean + */ + var $force_compile = false; + + /** + * This enables template caching. + *
        + *
      • 0 = no caching
      • + *
      • 1 = use class cache_lifetime value
      • + *
      • 2 = use cache_lifetime in cache file
      • + *
      + * @var integer + */ + var $caching = 0; + + /** + * The name of the directory for cache files. + * + * @var string + */ + var $cache_dir = 'cache'; + + /** + * This is the number of seconds cached content will persist. + *
        + *
      • 0 = always regenerate cache
      • + *
      • -1 = never expires
      • + *
      + * + * @var integer + */ + var $cache_lifetime = 3600; + + /** + * Only used when $caching is enabled. If true, then If-Modified-Since headers + * are respected with cached content, and appropriate HTTP headers are sent. + * This way repeated hits to a cached page do not send the entire page to the + * client every time. + * + * @var boolean + */ + var $cache_modified_check = false; + + /** + * This determines how Smarty handles "" tags in templates. + * possible values: + *
        + *
      • SMARTY_PHP_PASSTHRU -> print tags as plain text
      • + *
      • SMARTY_PHP_QUOTE -> escape tags as entities
      • + *
      • SMARTY_PHP_REMOVE -> remove php tags
      • + *
      • SMARTY_PHP_ALLOW -> execute php tags
      • + *
      + * + * @var integer + */ + var $php_handling = SMARTY_PHP_PASSTHRU; + + /** + * This enables template security. When enabled, many things are restricted + * in the templates that normally would go unchecked. This is useful when + * untrusted parties are editing templates and you want a reasonable level + * of security. (no direct execution of PHP in templates for example) + * + * @var boolean + */ + var $security = false; + + /** + * This is the list of template directories that are considered secure. This + * is used only if {@link $security} is enabled. One directory per array + * element. {@link $template_dir} is in this list implicitly. + * + * @var array + */ + var $secure_dir = array(); + + /** + * These are the security settings for Smarty. They are used only when + * {@link $security} is enabled. + * + * @var array + */ + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'sizeof', + 'in_array', 'is_array', + 'true', 'false', 'null'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count'), + 'ALLOW_CONSTANTS' => false, + 'ALLOW_SUPER_GLOBALS' => true + ); + + /** + * This is an array of directories where trusted php scripts reside. + * {@link $security} is disabled during their inclusion/execution. + * + * @var array + */ + var $trusted_dir = array(); + + /** + * The left delimiter used for the template tags. + * + * @var string + */ + var $left_delimiter = '{'; + + /** + * The right delimiter used for the template tags. + * + * @var string + */ + var $right_delimiter = '}'; + + /** + * The order in which request variables are registered, similar to + * variables_order in php.ini E = Environment, G = GET, P = POST, + * C = Cookies, S = Server + * + * @var string + */ + var $request_vars_order = 'EGPCS'; + + /** + * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) + * are uses as request-vars or $_*[]-vars. note: if + * request_use_auto_globals is true, then $request_vars_order has + * no effect, but the php-ini-value "gpc_order" + * + * @var boolean + */ + var $request_use_auto_globals = true; + + /** + * Set this if you want different sets of compiled files for the same + * templates. This is useful for things like different languages. + * Instead of creating separate sets of templates per language, you + * set different compile_ids like 'en' and 'de'. + * + * @var string + */ + var $compile_id = null; + + /** + * This tells Smarty whether or not to use sub dirs in the cache/ and + * templates_c/ directories. sub directories better organized, but + * may not work well with PHP safe mode enabled. + * + * @var boolean + * + */ + var $use_sub_dirs = false; + + /** + * This is a list of the modifiers to apply to all template variables. + * Put each modifier in a separate array element in the order you want + * them applied. example: array('escape:"htmlall"'); + * + * @var array + */ + var $default_modifiers = array(); + + /** + * This is the resource type to be used when not specified + * at the beginning of the resource path. examples: + * $smarty->display('file:index.tpl'); + * $smarty->display('db:index.tpl'); + * $smarty->display('index.tpl'); // will use default resource type + * {include file="file:index.tpl"} + * {include file="db:index.tpl"} + * {include file="index.tpl"} {* will use default resource type *} + * + * @var array + */ + var $default_resource_type = 'file'; + + /** + * The function used for cache file handling. If not set, built-in caching is used. + * + * @var null|string function name + */ + var $cache_handler_func = null; + + /** + * This indicates which filters are automatically loaded into Smarty. + * + * @var array array of filter names + */ + var $autoload_filters = array(); + + /**#@+ + * @var boolean + */ + /** + * This tells if config file vars of the same name overwrite each other or not. + * if disabled, same name variables are accumulated in an array. + */ + var $config_overwrite = true; + + /** + * This tells whether or not to automatically booleanize config file variables. + * If enabled, then the strings "on", "true", and "yes" are treated as boolean + * true, and "off", "false" and "no" are treated as boolean false. + */ + var $config_booleanize = true; + + /** + * This tells whether hidden sections [.foobar] are readable from the + * tempalates or not. Normally you would never allow this since that is + * the point behind hidden sections: the application can access them, but + * the templates cannot. + */ + var $config_read_hidden = false; + + /** + * This tells whether or not automatically fix newlines in config files. + * It basically converts \r (mac) or \r\n (dos) to \n + */ + var $config_fix_newlines = true; + /**#@-*/ + + /** + * If a template cannot be found, this PHP function will be executed. + * Useful for creating templates on-the-fly or other special action. + * + * @var string function name + */ + var $default_template_handler_func = ''; + + /** + * The file that contains the compiler class. This can a full + * pathname, or relative to the php_include path. + * + * @var string + */ + var $compiler_file = 'Smarty_Compiler.class.php'; + + /** + * The class used for compiling templates. + * + * @var string + */ + var $compiler_class = 'Smarty_Compiler'; + + /** + * The class used to load config vars. + * + * @var string + */ + var $config_class = 'Config_File'; + +/**#@+ + * END Smarty Configuration Section + * There should be no need to touch anything below this line. + * @access private + */ + /** + * where assigned template vars are kept + * + * @var array + */ + var $_tpl_vars = array(); + + /** + * stores run-time $smarty.* vars + * + * @var null|array + */ + var $_smarty_vars = null; + + /** + * keeps track of sections + * + * @var array + */ + var $_sections = array(); + + /** + * keeps track of foreach blocks + * + * @var array + */ + var $_foreach = array(); + + /** + * keeps track of tag hierarchy + * + * @var array + */ + var $_tag_stack = array(); + + /** + * configuration object + * + * @var Config_file + */ + var $_conf_obj = null; + + /** + * loaded configuration settings + * + * @var array + */ + var $_config = array(array('vars' => array(), 'files' => array())); + + /** + * md5 checksum of the string 'Smarty' + * + * @var string + */ + var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; + + /** + * Smarty version number + * + * @var string + */ + var $_version = '2.6.31'; + + /** + * current template inclusion depth + * + * @var integer + */ + var $_inclusion_depth = 0; + + /** + * for different compiled templates + * + * @var string + */ + var $_compile_id = null; + + /** + * text in URL to enable debug mode + * + * @var string + */ + var $_smarty_debug_id = 'SMARTY_DEBUG'; + + /** + * debugging information for debug console + * + * @var array + */ + var $_smarty_debug_info = array(); + + /** + * info that makes up a cache file + * + * @var array + */ + var $_cache_info = array(); + + /** + * default file permissions + * + * @var integer + */ + var $_file_perms = 0644; + + /** + * default dir permissions + * + * @var integer + */ + var $_dir_perms = 0771; + + /** + * registered objects + * + * @var array + */ + var $_reg_objects = array(); + + /** + * table keeping track of plugins + * + * @var array + */ + var $_plugins = array( + 'modifier' => array(), + 'function' => array(), + 'block' => array(), + 'compiler' => array(), + 'prefilter' => array(), + 'postfilter' => array(), + 'outputfilter' => array(), + 'resource' => array(), + 'insert' => array()); + + + /** + * cache serials + * + * @var array + */ + var $_cache_serials = array(); + + /** + * name of optional cache include file + * + * @var string + */ + var $_cache_include = null; + + /** + * indicate if the current code is used in a compiled + * include + * + * @var string + */ + var $_cache_including = false; + + /** + * plugin filepath cache + * + * @var array + */ + var $_filepaths_cache = array(); + /**#@-*/ + /** + * The class constructor. + */ + public function __construct() + { + $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] + : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); + } + + /** + * assigns values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to assign + */ + function assign($tpl_var, $value = null) + { + if (is_array($tpl_var)){ + foreach ($tpl_var as $key => $val) { + if ($key != '') { + $this->_tpl_vars[$key] = $val; + } + } + } else { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = $value; + } + } + + /** + * assigns values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to assign + */ + function assign_by_ref($tpl_var, &$value) + { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = &$value; + } + + /** + * appends values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to append + */ + function append($tpl_var, $value=null, $merge=false) + { + if (is_array($tpl_var)) { + // $tpl_var is an array, ignore $value + foreach ($tpl_var as $_key => $_val) { + if ($_key != '') { + if(!@is_array($this->_tpl_vars[$_key])) { + settype($this->_tpl_vars[$_key],'array'); + } + if($merge && is_array($_val)) { + foreach($_val as $_mkey => $_mval) { + $this->_tpl_vars[$_key][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$_key][] = $_val; + } + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if($merge && is_array($value)) { + foreach($value as $_mkey => $_mval) { + $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$tpl_var][] = $value; + } + } + } + } + + /** + * appends values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to append + */ + function append_by_ref($tpl_var, &$value, $merge=false) + { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if ($merge && is_array($value)) { + foreach($value as $_key => $_val) { + $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; + } + } else { + $this->_tpl_vars[$tpl_var][] = &$value; + } + } + } + + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + function clear_assign($tpl_var) + { + if (is_array($tpl_var)) + foreach ($tpl_var as $curr_var) + unset($this->_tpl_vars[$curr_var]); + else + unset($this->_tpl_vars[$tpl_var]); + } + + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + */ + function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['function'][$function] = + array($function_impl, null, null, false, $cacheable, $cache_attrs); + + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + function unregister_function($function) + { + unset($this->_plugins['function'][$function]); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object &$object_impl the referenced PHP object to register + * @param null|array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param null|array $block_functs list of methods that are block format + */ + function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->_reg_objects[$object] = + array(&$object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + function unregister_object($object) + { + unset($this->_reg_objects[$object]); + } + + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + */ + function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['block'][$block] = + array($block_impl, null, null, false, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + function unregister_block($block) + { + unset($this->_plugins['block'][$block]); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + */ + function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->_plugins['compiler'][$function] = + array($function_impl, null, null, false, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + function unregister_compiler_function($function) + { + unset($this->_plugins['compiler'][$function]); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + function register_modifier($modifier, $modifier_impl) + { + $this->_plugins['modifier'][$modifier] = + array($modifier_impl, null, null, false); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + function unregister_modifier($modifier) + { + unset($this->_plugins['modifier'][$modifier]); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + function register_resource($type, $functions) + { + if (count($functions)==4) { + $this->_plugins['resource'][$type] = + array($functions, false); + + } elseif (count($functions)==5) { + $this->_plugins['resource'][$type] = + array(array(array(&$functions[0], $functions[1]) + ,array(&$functions[0], $functions[2]) + ,array(&$functions[0], $functions[3]) + ,array(&$functions[0], $functions[4])) + ,false); + + } else { + $this->trigger_error("malformed function-list for '$type' in register_resource"); + + } + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + function unregister_resource($type) + { + unset($this->_plugins['resource'][$type]); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callback $function + */ + function register_prefilter($function) + { + $this->_plugins['prefilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a prefilter function + * + * @param callback $function + */ + function unregister_prefilter($function) + { + unset($this->_plugins['prefilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callback $function + */ + function register_postfilter($function) + { + $this->_plugins['postfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a postfilter function + * + * @param callback $function + */ + function unregister_postfilter($function) + { + unset($this->_plugins['postfilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callback $function + */ + function register_outputfilter($function) + { + $this->_plugins['outputfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters an outputfilter function + * + * @param callback $function + */ + function unregister_outputfilter($function) + { + unset($this->_plugins['outputfilter'][$this->_get_filter_name($function)]); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + function load_filter($type, $name) + { + switch ($type) { + case 'output': + $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + break; + + case 'pre': + case 'post': + if (!isset($this->_plugins[$type . 'filter'][$name])) + $this->_plugins[$type . 'filter'][$name] = false; + break; + } + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + if (!isset($tpl_file)) + $compile_id = null; + + $_auto_id = $this->_get_auto_id($cache_id, $compile_id); + + if (!empty($this->cache_handler_func)) { + return call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $_auto_id, + 'exp_time' => $exp_time); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + } + + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_all_cache($exp_time = null) + { + return $this->clear_cache(null, null, null, $exp_time); + } + + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + if (!$this->caching) + return false; + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + $_params = array( + 'tpl_file' => $tpl_file, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + return smarty_core_read_cache_file($_params, $this); + } + + + /** + * clear all the assigned template variables. + * + */ + function clear_all_assign() + { + $this->_tpl_vars = array(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + $_params = array('auto_base' => $this->compile_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $compile_id, + 'exp_time' => $exp_time, + 'extensions' => array('.inc', '.php')); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + function template_exists($tpl_file) + { + $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); + return $this->_fetch_resource_info($_params); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_template_vars($name=null) + { + if(!isset($name)) { + return $this->_tpl_vars; + } elseif(isset($this->_tpl_vars[$name])) { + return $this->_tpl_vars[$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_config_vars($name=null) + { + if(!isset($name) && is_array($this->_config[0])) { + return $this->_config[0]['vars']; + } else if(isset($this->_config[0]['vars'][$name])) { + return $this->_config[0]['vars'][$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + $msg = htmlentities($error_msg); + trigger_error("Smarty error: $msg", $error_type); + } + + + /** + * executes & displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + /** + * executes & returns or displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + static $_cache_info = array(); + + $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) + ? $this->error_reporting : error_reporting() & ~E_NOTICE); + + if (!$this->debugging && $this->debugging_ctrl == 'URL') { + $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + if (@strstr($_query_string, $this->_smarty_debug_id)) { + if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { + // enable debugging for this browser session + @setcookie('SMARTY_DEBUG', true); + $this->debugging = true; + } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { + // disable debugging for this browser session + @setcookie('SMARTY_DEBUG', false); + $this->debugging = false; + } else { + // enable debugging for this page + $this->debugging = true; + } + } else { + $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); + } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $resource_name, + 'depth' => 0); + $_included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + + $this->_compile_id = $compile_id; + $this->_inclusion_depth = 0; + + if ($this->caching) { + // save old cache_info, initialize cache_info + array_push($_cache_info, $this->_cache_info); + $this->_cache_info = array(); + $_params = array( + 'tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => null + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + if (smarty_core_read_cache_file($_params, $this)) { + $_smarty_results = $_params['results']; + if (!empty($this->_cache_info['insert_tags'])) { + $_params = array('plugins' => $this->_cache_info['insert_tags']); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + } + if (!empty($this->_cache_info['cache_serials'])) { + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); + $_smarty_results = smarty_core_process_compiled_include($_params, $this); + } + + + if ($display) { + if ($this->debugging) + { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + $_smarty_results .= smarty_core_display_debug_console($_params, $this); + } + if ($this->cache_modified_check) { + $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); + $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; + if (@count($this->_cache_info['insert_tags']) == 0 + && !$this->_cache_serials + && $_gmt_mtime == $_last_modified_date) { + if (php_sapi_name()=='cgi') + header('Status: 304 Not Modified'); + else + header('HTTP/1.1 304 Not Modified'); + + } else { + header('Last-Modified: '.$_gmt_mtime); + echo $_smarty_results; + } + } else { + echo $_smarty_results; + } + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return true; + } else { + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return $_smarty_results; + } + } else { + $this->_cache_info['template'][$resource_name] = true; + if ($this->cache_modified_check && $display) { + header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); + } + } + } + + // load filters that are marked as autoload + if (count($this->autoload_filters)) { + foreach ($this->autoload_filters as $_filter_type => $_filters) { + foreach ($_filters as $_filter) { + $this->load_filter($_filter_type, $_filter); + } + } + } + + $_smarty_compile_path = $this->_get_compile_path($resource_name); + + // if we just need to display the results, don't perform output + // buffering - for speed + $_cache_including = $this->_cache_including; + $this->_cache_including = false; + if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + } else { + ob_start(); + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + $_smarty_results = ob_get_contents(); + ob_end_clean(); + + foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { + $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); + } + } + + if ($this->caching) { + $_params = array('tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); + smarty_core_write_cache_file($_params, $this); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + + if ($this->_cache_serials) { + // strip nocache-tags from output + $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' + ,'' + ,$_smarty_results); + } + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + } + $this->_cache_including = $_cache_including; + + if ($display) { + if (isset($_smarty_results)) { echo $_smarty_results; } + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console($_params, $this); + } + error_reporting($_smarty_old_error_level); + return; + } else { + error_reporting($_smarty_old_error_level); + if (isset($_smarty_results)) { return $_smarty_results; } + } + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + require_once($this->_get_plugin_filepath('function', 'config_load')); + smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + function &get_registered_object($name) { + if (!isset($this->_reg_objects[$name])) + $this->_trigger_fatal_error("'$name' is not a registered object"); + + if (!is_object($this->_reg_objects[$name][0])) + $this->_trigger_fatal_error("registered '$name' is not an object"); + + return $this->_reg_objects[$name][0]; + } + + /** + * clear configuration values + * + * @param string $var + */ + function clear_config($var = null) + { + if(!isset($var)) { + // clear all values + $this->_config = array(array('vars' => array(), + 'files' => array())); + } else { + unset($this->_config[0]['vars'][$var]); + } + } + + /** + * get filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ + function _get_plugin_filepath($type, $name) + { + $_params = array('type' => $type, 'name' => $name); + require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); + return smarty_core_assemble_plugin_filepath($_params, $this); + } + + /** + * test if resource needs compiling + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _is_compiled($resource_name, $compile_path) + { + if (!$this->force_compile && file_exists($compile_path)) { + if (!$this->compile_check) { + // no need to check compiled file + return true; + } else { + // get file source and timestamp + $_params = array('resource_name' => $resource_name, 'get_source'=>false); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + if ($_params['resource_timestamp'] <= filemtime($compile_path)) { + // template not expired, no recompile + return true; + } else { + // compile template + return false; + } + } + } else { + // compiled template does not exist, or forced compile + return false; + } + } + + /** + * compile the template + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _compile_resource($resource_name, $compile_path) + { + + $_params = array('resource_name' => $resource_name); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + + $_source_content = $_params['source_content']; + $_cache_include = substr($compile_path, 0, -4).'.inc'; + + if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { + // if a _cache_serial was set, we also have to write an include-file: + if ($this->_cache_include_info) { + require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); + smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); + } + + $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $this); + + return true; + } else { + return false; + } + + } + + /** + * compile the given source + * + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return boolean + */ + function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) + { + if (file_exists(SMARTY_DIR . $this->compiler_file)) { + require_once(SMARTY_DIR . $this->compiler_file); + } else { + // use include_path + require_once($this->compiler_file); + } + + + $smarty_compiler = new $this->compiler_class; + + $smarty_compiler->template_dir = $this->template_dir; + $smarty_compiler->compile_dir = $this->compile_dir; + $smarty_compiler->plugins_dir = $this->plugins_dir; + $smarty_compiler->config_dir = $this->config_dir; + $smarty_compiler->force_compile = $this->force_compile; + $smarty_compiler->caching = $this->caching; + $smarty_compiler->php_handling = $this->php_handling; + $smarty_compiler->left_delimiter = $this->left_delimiter; + $smarty_compiler->right_delimiter = $this->right_delimiter; + $smarty_compiler->_version = $this->_version; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security_settings = $this->security_settings; + $smarty_compiler->trusted_dir = $this->trusted_dir; + $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; + $smarty_compiler->_reg_objects = &$this->_reg_objects; + $smarty_compiler->_plugins = &$this->_plugins; + $smarty_compiler->_tpl_vars = &$this->_tpl_vars; + $smarty_compiler->default_modifiers = $this->default_modifiers; + $smarty_compiler->compile_id = $this->_compile_id; + $smarty_compiler->_config = $this->_config; + $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; + + if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { + $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; + } + $smarty_compiler->_cache_include = $cache_include_path; + + + $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); + + if ($smarty_compiler->_cache_serial) { + $this->_cache_include_info = array( + 'cache_serial'=>$smarty_compiler->_cache_serial + ,'plugins_code'=>$smarty_compiler->_plugins_code + ,'include_file_path' => $cache_include_path); + + } else { + $this->_cache_include_info = null; + + } + + return $_results; + } + + /** + * Get the compile path for this resource + * + * @param string $resource_name + * @return string results of {@link _get_auto_filename()} + */ + function _get_compile_path($resource_name) + { + return $this->_get_auto_filename($this->compile_dir, $resource_name, + $this->_compile_id) . '.php'; + } + + /** + * fetch the template info. Gets timestamp, and source + * if get_source is true + * + * sets $source_content to the source of the template, and + * $resource_timestamp to its time stamp + * @param string $resource_name + * @param string $source_content + * @param integer $resource_timestamp + * @param boolean $get_source + * @param boolean $quiet + * @return boolean + */ + + function _fetch_resource_info(&$params) + { + if(!isset($params['get_source'])) { $params['get_source'] = true; } + if(!isset($params['quiet'])) { $params['quiet'] = false; } + + $_return = false; + $_params = array('resource_name' => $params['resource_name']) ; + if (isset($params['resource_base_path'])) + $_params['resource_base_path'] = $params['resource_base_path']; + else + $_params['resource_base_path'] = $this->template_dir; + + if ($this->_parse_resource_name($_params)) { + $_resource_type = $_params['resource_type']; + $_resource_name = $_params['resource_name']; + switch ($_resource_type) { + case 'file': + if ($params['get_source']) { + $params['source_content'] = $this->_read_file($_resource_name); + } + $params['resource_timestamp'] = filemtime($_resource_name); + $_return = is_file($_resource_name) && is_readable($_resource_name); + break; + + default: + // call resource functions to fetch the template source and timestamp + if ($params['get_source']) { + $_source_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], + array($_resource_name, &$params['source_content'], &$this)); + } else { + $_source_return = true; + } + + $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], + array($_resource_name, &$params['resource_timestamp'], &$this)); + + $_return = $_source_return && $_timestamp_return; + break; + } + } + + if (!$_return) { + // see if we can get a template with the default template handler + if (!empty($this->default_template_handler_func)) { + if (!is_callable($this->default_template_handler_func)) { + $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); + } else { + $_return = call_user_func_array( + $this->default_template_handler_func, + array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); + } + } + } + + if (!$_return) { + if (!$params['quiet']) { + $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); + } + } else if ($_return && $this->security) { + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if (!smarty_core_is_secure($_params, $this)) { + if (!$params['quiet']) + $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); + $params['source_content'] = null; + $params['resource_timestamp'] = null; + return false; + } + } + return $_return; + } + + + /** + * parse out the type and name from the resource + * + * @param string $resource_base_path + * @param string $resource_name + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + function _parse_resource_name(&$params) + { + + // split tpl_path by the first colon + $_resource_name_parts = explode(':', $params['resource_name'], 2); + + if (count($_resource_name_parts) == 1) { + // no resource type given + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $_resource_name_parts[0]; + } else { + if(strlen($_resource_name_parts[0]) == 1) { + // 1 char is not resource type, but part of filepath + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $params['resource_name']; + } else { + $params['resource_type'] = $_resource_name_parts[0]; + $params['resource_name'] = $_resource_name_parts[1]; + } + } + + if ($params['resource_type'] == 'file') { + if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { + // relative pathname to $params['resource_base_path'] + // use the first directory where the file is found + foreach ((array)$params['resource_base_path'] as $_curr_path) { + $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; + if (file_exists($_fullpath) && is_file($_fullpath)) { + $params['resource_name'] = $_fullpath; + return true; + } + // didn't find the file, try include_path + $_params = array('file_path' => $_fullpath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $this)) { + $params['resource_name'] = $_params['new_file_path']; + return true; + } + } + return false; + } else { + /* absolute path */ + return file_exists($params['resource_name']); + } + } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { + $_params = array('type' => $params['resource_type']); + require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); + smarty_core_load_resource_plugin($_params, $this); + } + + return true; + } + + + /** + * Handle modifiers + * + * @param string|null $modifier_name + * @param array|null $map_array + * @return string result of modifiers + */ + function _run_mod_handler() + { + $_args = func_get_args(); + list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); + list($_func_name, $_tpl_file, $_tpl_line) = + $this->_plugins['modifier'][$_modifier_name]; + + $_var = $_args[0]; + foreach ($_var as $_key => $_val) { + $_args[0] = $_val; + $_var[$_key] = call_user_func_array($_func_name, $_args); + } + return $_var; + } + + /** + * Remove starting and ending quotes from the string + * + * @param string $string + * @return string + */ + function _dequote($string) + { + if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') && + substr($string, -1) == substr($string, 0, 1)) + return substr($string, 1, -1); + else + return $string; + } + + + /** + * read in a file + * + * @param string $filename + * @return string + */ + function _read_file($filename) + { + if ( file_exists($filename) && is_readable($filename) && ($fd = @fopen($filename, 'rb')) ) { + $contents = ''; + while (!feof($fd)) { + $contents .= fread($fd, 8192); + } + fclose($fd); + return $contents; + } else { + return false; + } + } + + /** + * get a concrete filename for automagically created content + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @return string + * @staticvar string|null + * @staticvar string|null + */ + function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) + { + $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; + $_return = $auto_base . DIRECTORY_SEPARATOR; + + if(isset($auto_id)) { + // make auto_id safe for directory names + $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); + // split into separate directories + $_return .= $auto_id . $_compile_dir_sep; + } + + if(isset($auto_source)) { + // make source name safe for filename + $_filename = urlencode(basename($auto_source)); + $_crc32 = sprintf('%08X', crc32($auto_source)); + // prepend %% to avoid name conflicts with + // with $params['auto_id'] names + $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . + substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; + $_return .= '%%' . $_crc32 . '%%' . $_filename; + } + + return $_return; + } + + /** + * unlink a file, possibly using expiration time + * + * @param string $resource + * @param integer $exp_time + */ + function _unlink($resource, $exp_time = null) + { + if(isset($exp_time)) { + if(time() - @filemtime($resource) >= $exp_time) { + return @unlink($resource); + } + } else { + return @unlink($resource); + } + } + + /** + * returns an auto_id for auto-file-functions + * + * @param string $cache_id + * @param string $compile_id + * @return string|null + */ + function _get_auto_id($cache_id=null, $compile_id=null) { + if (isset($cache_id)) + return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; + elseif(isset($compile_id)) + return $compile_id; + else + return null; + } + + /** + * trigger Smarty plugin error + * + * @param string $error_msg + * @param string $tpl_file + * @param integer $tpl_line + * @param string $file + * @param integer $line + * @param integer $error_type + */ + function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, + $file = null, $line = null, $error_type = E_USER_ERROR) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = ''; + } + if (isset($tpl_line) && isset($tpl_file)) { + $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); + } else { + $this->trigger_error($error_msg . $info, $error_type); + } + } + + + /** + * callback function for preg_replace, to call a non-cacheable block + * @return string + */ + function _process_compiled_include_callback($match) { + $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; + ob_start(); + $_func($this); + $_ret = ob_get_contents(); + ob_end_clean(); + return $_ret; + } + + + /** + * called for included templates + * + * @param string $_smarty_include_tpl_file + * @param string $_smarty_include_vars + */ + + // $_smarty_include_tpl_file, $_smarty_include_vars + + function _smarty_include($params) + { + if ($this->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $params['smarty_include_tpl_file'], + 'depth' => ++$this->_inclusion_depth); + $included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); + + // config vars are treated as local, so push a copy of the + // current ones onto the front of the stack + array_unshift($this->_config, $this->_config[0]); + + $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); + + + if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) + || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + + // pop the local vars off the front of the stack + array_shift($this->_config); + + $this->_inclusion_depth--; + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; + } + + if ($this->caching) { + $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; + } + } + + + /** + * get or set an array of cached attributes for function that is + * not cacheable + * @return array + */ + function &_smarty_cache_attrs($cache_serial, $count) { + $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; + + if ($this->_cache_including) { + /* return next set of cache_attrs */ + $_return = current($_cache_attrs); + next($_cache_attrs); + return $_return; + + } else { + /* add a reference to a new set of cache_attrs */ + $_cache_attrs[] = array(); + return $_cache_attrs[count($_cache_attrs)-1]; + + } + + } + + + /** + * wrapper for include() retaining $this + * @return mixed + */ + function _include($filename, $once=false, $params=null) + { + if ($once) { + return include_once($filename); + } else { + return include($filename); + } + } + + + /** + * wrapper for eval() retaining $this + * @return mixed + */ + function _eval($code, $params=null) + { + return eval($code); + } + + /** + * Extracts the filter name from the given callback + * + * @param callback $function + * @return string + */ + function _get_filter_name($function) + { + if (is_array($function)) { + $_class_name = (is_object($function[0]) ? + get_class($function[0]) : $function[0]); + return $_class_name . '_' . $function[1]; + } + else { + return $function; + } + } + + /**#@-*/ + +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/Smarty_Compiler.class.php b/lib/Smarty/Smarty_Compiler.class.php new file mode 100644 index 0000000..904601d --- /dev/null +++ b/lib/Smarty/Smarty_Compiler.class.php @@ -0,0 +1,2365 @@ + + * @author Andrei Zmievski + * @version 2.6.25-dev + * @copyright 2001-2005 New Digital Group, Inc. + * @package Smarty + */ + +/* $Id$ */ + +/** + * Template compiling class + * @package Smarty + */ +class Smarty_Compiler extends Smarty { + + // internal vars + /**#@+ + * @access private + */ + var $_folded_blocks = array(); // keeps folded template blocks + var $_current_file = null; // the current template being compiled + var $_current_line_no = 1; // line number for error messages + var $_capture_stack = array(); // keeps track of nested capture buffers + var $_plugin_info = array(); // keeps track of plugins to load + var $_init_smarty_vars = false; + var $_permitted_tokens = array('true','false','yes','no','on','off','null'); + var $_db_qstr_regexp = null; // regexps are setup in the constructor + var $_si_qstr_regexp = null; + var $_qstr_regexp = null; + var $_func_regexp = null; + var $_reg_obj_regexp = null; + var $_var_bracket_regexp = null; + var $_num_const_regexp = null; + var $_dvar_guts_regexp = null; + var $_dvar_regexp = null; + var $_cvar_regexp = null; + var $_svar_regexp = null; + var $_avar_regexp = null; + var $_mod_regexp = null; + var $_var_regexp = null; + var $_parenth_param_regexp = null; + var $_func_call_regexp = null; + var $_obj_ext_regexp = null; + var $_obj_start_regexp = null; + var $_obj_params_regexp = null; + var $_obj_call_regexp = null; + var $_cacheable_state = 0; + var $_cache_attrs_count = 0; + var $_nocache_count = 0; + var $_cache_serial = null; + var $_cache_include = null; + + var $_strip_depth = 0; + var $_additional_newline = "\n"; + + /**#@-*/ + /** + * The class constructor. + */ + public function __construct() + { + // matches double quoted strings: + // "foobar" + // "foo\"bar" + $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; + + // matches single quoted strings: + // 'foobar' + // 'foo\'bar' + $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; + + // matches single or double quoted strings + $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; + + // matches bracket portion of vars + // [0] + // [foo] + // [$bar] + $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; + + // matches numerical constants + // 30 + // -12 + // 13.22 + $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; + + // matches $ vars (not objects): + // $foo + // $foo.bar + // $foo.bar.foobar + // $foo[0] + // $foo[$bar] + // $foo[5][blah] + // $foo[5].bar[$foobar][4] + $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; + $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; + $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp + . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; + $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; + + // matches config vars: + // #foo# + // #foobar123_foo# + $this->_cvar_regexp = '\#\w+\#'; + + // matches section vars: + // %foo.bar% + $this->_svar_regexp = '\%\w+\.\w+\%'; + + // matches all valid variables (no quotes, no modifiers) + $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' + . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; + + // matches valid variable syntax: + // $foo + // $foo + // #foo# + // #foo# + // "text" + // "text" + $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; + + // matches valid object call (one level of object nesting allowed in parameters): + // $foo->bar + // $foo->bar() + // $foo->bar("text") + // $foo->bar($foo, $bar, "text") + // $foo->bar($foo, "foo") + // $foo->bar->foo() + // $foo->bar->foo->bar() + // $foo->bar($foo->bar) + // $foo->bar($foo->bar()) + // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) + $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; + $this->_obj_restricted_param_regexp = '(?:' + . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' + . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; + $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; + $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp + . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; + $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; + $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; + + // matches valid modifier syntax: + // |foo + // |@foo + // |foo:"bar" + // |foo:$bar + // |foo:"bar":$foobar + // |foo|bar + // |foo:$foo->bar + $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' + . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; + + // matches valid function name: + // foo123 + // _foo_bar + $this->_func_regexp = '[a-zA-Z_]\w*'; + + // matches valid registered object: + // foo->bar + $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; + + // matches valid parameter values: + // true + // $foo + // $foo|bar + // #foo# + // #foo#|bar + // "text" + // "text"|bar + // $foo->bar + $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' + . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; + + // matches valid parenthesised function parameters: + // + // "text" + // $foo, $bar, "text" + // $foo|bar, "foo"|bar, $foo->bar($foo)|bar + $this->_parenth_param_regexp = '(?:\((?:\w+|' + . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_param_regexp . ')))*)?\))'; + + // matches valid function call: + // foo() + // foo_bar($foo) + // _foo_bar($foo,"bar") + // foo123($foo,$foo->bar(),"foo") + $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' + . $this->_parenth_param_regexp . '))'; + } + + /** + * compile a resource + * + * sets $compiled_content to the compiled source + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return true + */ + function _compile_file($resource_name, $source_content, &$compiled_content) + { + + if ($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + + $this->_load_filters(); + + $this->_current_file = $resource_name; + $this->_current_line_no = 1; + $ldq = preg_quote($this->left_delimiter, '~'); + $rdq = preg_quote($this->right_delimiter, '~'); + + // run template source through prefilter functions + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) continue; + if ($prefilter[3] || is_callable($prefilter[0])) { + $source_content = call_user_func_array($prefilter[0], + array($source_content, &$this)); + $this->_plugins['prefilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); + } + } + } + + /* fetch all special blocks */ + $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; + + preg_match_all($search, $source_content, $match, PREG_SET_ORDER); + $this->_folded_blocks = $match; + + /* replace special blocks by "{php}" */ + $source_content = preg_replace_callback($search, array($this,'_preg_callback') + , $source_content); + + /* Gather all template tags. */ + preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); + $template_tags = $_match[1]; + /* Split content by template tags to obtain non-template content. */ + $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); + + /* loop through text blocks */ + for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { + /* match anything resembling php tags */ + if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { + /* replace tags with placeholders to prevent recursive replacements */ + $sp_match[1] = array_unique($sp_match[1]); + usort($sp_match[1], '_smarty_sort_length'); + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); + } + /* process each one */ + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + if ($this->php_handling == SMARTY_PHP_PASSTHRU) { + /* echo php contents */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', ''."\n", $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_QUOTE) { + /* quote php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_REMOVE) { + /* remove php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); + } else { + /* SMARTY_PHP_ALLOW, but echo non php starting tags */ + $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', ''."\n", $sp_match[1][$curr_sp]); + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); + } + } + } + } + + /* Compile the template tags into PHP code. */ + $compiled_tags = array(); + for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { + $this->_current_line_no += substr_count($text_blocks[$i], "\n"); + $compiled_tags[] = $this->_compile_tag($template_tags[$i]); + $this->_current_line_no += substr_count($template_tags[$i], "\n"); + } + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = end($this->_tag_stack); + $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); + return; + } + + /* Reformat $text_blocks between 'strip' and '/strip' tags, + removing spaces, tabs and newlines. */ + $strip = false; + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '{strip}') { + $compiled_tags[$i] = ''; + $strip = true; + /* remove leading whitespaces */ + $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); + } + if ($strip) { + /* strip all $text_blocks before the next '/strip' */ + for ($j = $i + 1; $j < $for_max; $j++) { + /* remove leading and trailing whitespaces of each line */ + $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); + if ($compiled_tags[$j] == '{/strip}') { + /* remove trailing whitespaces from the last text_block */ + $text_blocks[$j] = rtrim($text_blocks[$j]); + } + $text_blocks[$j] = ""\'", "\\"=>"\\\\")) . "'; ?>"; + if ($compiled_tags[$j] == '{/strip}') { + $compiled_tags[$j] = "\n"; /* slurped by php, but necessary + if a newline is following the closing strip-tag */ + $strip = false; + $i = $j; + break; + } + } + } + } + $compiled_content = ''; + + $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; + + /* Interleave the compiled contents and text blocks to get the final result. */ + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '') { + // tag result empty, remove first newline from following text block + $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); + } + // replace legit PHP tags with placeholder + $text_blocks[$i] = str_replace('\n", $compiled_content); + $compiled_content = preg_replace("~(?\n", $compiled_content); + + // recover legit tags + $compiled_content = str_replace($tag_guard, '_cache_serial)) { + $compiled_content = "_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; + } + + // run compiled template through postfilter functions + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) continue; + if ($postfilter[3] || is_callable($postfilter[0])) { + $compiled_content = call_user_func_array($postfilter[0], + array($compiled_content, &$this)); + $this->_plugins['postfilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); + } + } + } + + // put header at the top of the compiled template + $template_header = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; + + /* Emit code to load needed plugins. */ + $this->_plugins_code = ''; + if (count($this->_plugin_info)) { + $_plugins_params = "array('plugins' => array("; + foreach ($this->_plugin_info as $plugin_type => $plugins) { + foreach ($plugins as $plugin_name => $plugin_info) { + $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; + $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; + } + } + $_plugins_params .= '))'; + $plugins_code = "\n"; + $template_header .= $plugins_code; + $this->_plugin_info = array(); + $this->_plugins_code = $plugins_code; + } + + if ($this->_init_smarty_vars) { + $template_header .= "\n"; + $this->_init_smarty_vars = false; + } + + $compiled_content = $template_header . $compiled_content; + return true; + } + + /** + * Compile a template tag + * + * @param string $template_tag + * @return string + */ + function _compile_tag($template_tag) + { + /* Matched comment. */ + if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') + return ''; + + /* Split tag into two three parts: command, command modifiers and the arguments. */ + if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp + . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) + (?:\s+(.*))?$ + ~xs', $template_tag, $match)) { + $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $tag_command = $match[1]; + $tag_modifier = isset($match[2]) ? $match[2] : null; + $tag_args = isset($match[3]) ? $match[3] : null; + + if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { + /* tag name is a variable or object */ + $_return = $this->_parse_var_props($tag_command . $tag_modifier); + return "" . $this->_additional_newline; + } + + /* If the tag name is a registered object, we process it. */ + if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { + return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); + } + + switch ($tag_command) { + case 'include': + return $this->_compile_include_tag($tag_args); + + case 'include_php': + return $this->_compile_include_php_tag($tag_args); + + case 'if': + $this->_push_tag('if'); + return $this->_compile_if_tag($tag_args); + + case 'else': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); + else + $this->_push_tag('else'); + return ''; + + case 'elseif': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); + if ($_open_tag == 'if') + $this->_push_tag('elseif'); + return $this->_compile_if_tag($tag_args, true); + + case '/if': + $this->_pop_tag('if'); + return ''; + + case 'capture': + return $this->_compile_capture_tag(true, $tag_args); + + case '/capture': + return $this->_compile_capture_tag(false); + + case 'ldelim': + return $this->left_delimiter; + + case 'rdelim': + return $this->right_delimiter; + + case 'section': + $this->_push_tag('section'); + return $this->_compile_section_start($tag_args); + + case 'sectionelse': + $this->_push_tag('sectionelse'); + return ""; + break; + + case '/section': + $_open_tag = $this->_pop_tag('section'); + if ($_open_tag == 'sectionelse') + return ""; + else + return ""; + + case 'foreach': + $this->_push_tag('foreach'); + return $this->_compile_foreach_start($tag_args); + break; + + case 'foreachelse': + $this->_push_tag('foreachelse'); + return ""; + + case '/foreach': + $_open_tag = $this->_pop_tag('foreach'); + if ($_open_tag == 'foreachelse') + return ""; + else + return ""; + break; + + case 'strip': + case '/strip': + if (substr($tag_command, 0, 1)=='/') { + $this->_pop_tag('strip'); + if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ + $this->_additional_newline = "\n"; + return '{' . $tag_command . '}'; + } + } else { + $this->_push_tag('strip'); + if ($this->_strip_depth++==0) { /* outermost opening {strip} */ + $this->_additional_newline = ""; + return '{' . $tag_command . '}'; + } + } + return ''; + + case 'php': + /* handle folded tags replaced by {php} */ + $block = array_shift($this->_folded_blocks); + $this->_current_line_no += substr_count($block[0], "\n"); + /* the number of matched elements in the regexp in _compile_file() + determins the type of folded tag that was found */ + switch (count($block)) { + case 2: /* comment */ + return ''; + + case 3: /* literal */ + return ""\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; + + case 4: /* php */ + if ($this->security && !$this->security_settings['PHP_TAGS']) { + $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); + return; + } + return ''; + } + break; + + case 'insert': + return $this->_compile_insert_tag($tag_args); + + default: + if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { + return $output; + } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else { + $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); + } + + } + } + + + /** + * compile the custom compiler tag + * + * sets $output to the compiled custom compiler tag + * @param string $tag_command + * @param string $tag_args + * @param string $output + * @return boolean + */ + function _compile_compiler_tag($tag_command, $tag_args, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the compiler function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['compiler'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['compiler'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "compiler function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_compiler_' . $tag_command; + if (!is_callable($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); + } + } + + /* + * True return value means that we either found a plugin or a + * dynamically registered function. False means that we didn't and the + * compiler should now emit code to load custom function plugin for this + * tag. + */ + if ($found) { + if ($have_function) { + $output = call_user_func_array($plugin_func, array($tag_args, &$this)); + if($output != '') { + $output = '_push_cacheable_state('compiler', $tag_command) + . $output + . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; + } + } else { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + } + return true; + } else { + return false; + } + } + + + /** + * compile block function tag + * + * sets $output to compiled block function tag + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @param string $output + * @return boolean + */ + function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else + $start_tag = true; + + $found = false; + $have_function = true; + + /* + * First we check if the block function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['block'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['block'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "block function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_block_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* + * Even though we've located the plugin function, compilation + * happens only once, so the plugin will still need to be loaded + * at runtime for future requests. + */ + $this->_add_plugin('block', $tag_command); + + if ($start_tag) + $this->_push_tag($tag_command); + else + $this->_pop_tag($tag_command); + + if ($start_tag) { + $output = '_push_cacheable_state('block', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs=''; + $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); + $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; + $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; + $output .= 'while ($_block_repeat) { ob_start(); ?>'; + } else { + $output = '_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; + if ($tag_modifier != '') { + $this->_parse_modifiers($_out_tag_text, $tag_modifier); + } + $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; + $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; + } + + return true; + } + + function _preg_callback ($matches) { + return $this->_quote_replace($this->left_delimiter) + . 'php' + . str_repeat("\n", substr_count($matches[1], "\n")) + . $this->_quote_replace($this->right_delimiter); + } + /** + * compile custom function tag + * + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @return string + */ + function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the custom function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['function'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['function'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "custom function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_function_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* declare plugin to be loaded on display of the template that + we compile right now */ + $this->_add_plugin('function', $tag_command); + + $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs = ''; + $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); + + $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; + if($tag_modifier != '') { + $this->_parse_modifiers($output, $tag_modifier); + } + + if($output != '') { + $output = '_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; + } + + return true; + } + + /** + * compile a registered object tag + * + * @param string $tag_command + * @param array $attrs + * @param string $tag_modifier + * @return string + */ + function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else { + $start_tag = true; + } + + list($object, $obj_comp) = explode('->', $tag_command); + + $arg_list = array(); + if(count($attrs)) { + $_assign_var = false; + foreach ($attrs as $arg_name => $arg_value) { + if($arg_name == 'assign') { + $_assign_var = $arg_value; + unset($attrs['assign']); + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + if($this->_reg_objects[$object][2]) { + // smarty object argument format + $args = "array(".implode(',', (array)$arg_list)."), \$this"; + } else { + // traditional argument format + $args = implode(',', array_values($attrs)); + if (empty($args)) { + $args = ''; + } + } + + $prefix = ''; + $postfix = ''; + $newline = ''; + if(!is_object($this->_reg_objects[$object][0])) { + $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { + $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { + // method + if(in_array($obj_comp, $this->_reg_objects[$object][3])) { + // block method + if ($start_tag) { + $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; + $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; + $prefix .= "while (\$_block_repeat) { ob_start();"; + $return = null; + $postfix = ''; + } else { + $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; + $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; + $postfix = "} array_pop(\$this->_tag_stack);"; + } + } else { + // non-block method + $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; + } + } else { + // property + $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; + } + + if($return != null) { + if($tag_modifier != '') { + $this->_parse_modifiers($return, $tag_modifier); + } + + if(!empty($_assign_var)) { + $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; + } else { + $output = 'echo ' . $return . ';'; + $newline = $this->_additional_newline; + } + } else { + $output = ''; + } + + return '" . $newline; + } + + /** + * Compile {insert ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_insert_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $name = $this->_dequote($attrs['name']); + + if (empty($name)) { + return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!preg_match('~^\w+$~', $name)) { + return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!empty($attrs['script'])) { + $delayed_loading = true; + } else { + $delayed_loading = false; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $this->_add_plugin('insert', $name, $delayed_loading); + + $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; + + return "" . $this->_additional_newline; + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); + } + + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; + continue; + } else if ($arg_name == 'assign') { + $assign_var = $arg_value; + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $output = '_tpl_vars;\n"; + + + $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + $output .= "\$this->_smarty_include($_params);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars);\n"; + + if (isset($assign_var)) { + $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; + } + + $output .= ' ?>'; + + return $output; + + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_php_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); + $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; + + $arg_list = array(); + foreach($attrs as $arg_name => $arg_value) { + if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { + if(is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; + + return "" . $this->_additional_newline; + } + + + /** + * Compile {section ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_section_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + $output = '_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); + } + + $output .= "unset(\$this->_sections[$section_name]);\n"; + $section_props = "\$this->_sections[$section_name]"; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'loop': + $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; + break; + + case 'show': + if (is_bool($attr_value)) + $show_attr_value = $attr_value ? 'true' : 'false'; + else + $show_attr_value = "(bool)$attr_value"; + $output .= "{$section_props}['show'] = $show_attr_value;\n"; + break; + + case 'name': + $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; + break; + + case 'max': + case 'start': + $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; + break; + + case 'step': + $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; + break; + + default: + $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + } + + if (!isset($attrs['show'])) + $output .= "{$section_props}['show'] = true;\n"; + + if (!isset($attrs['loop'])) + $output .= "{$section_props}['loop'] = 1;\n"; + + if (!isset($attrs['max'])) + $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; + else + $output .= "if ({$section_props}['max'] < 0)\n" . + " {$section_props}['max'] = {$section_props}['loop'];\n"; + + if (!isset($attrs['step'])) + $output .= "{$section_props}['step'] = 1;\n"; + + if (!isset($attrs['start'])) + $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; + else { + $output .= "if ({$section_props}['start'] < 0)\n" . + " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . + "else\n" . + " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; + } + + $output .= "if ({$section_props}['show']) {\n"; + if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { + $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; + } else { + $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; + } + $output .= " if ({$section_props}['total'] == 0)\n" . + " {$section_props}['show'] = false;\n" . + "} else\n" . + " {$section_props}['total'] = 0;\n"; + + $output .= "if ({$section_props}['show']):\n"; + $output .= " + for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; + {$section_props}['iteration'] <= {$section_props}['total']; + {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; + $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; + $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; + $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; + $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; + + $output .= "?>"; + + return $output; + } + + + /** + * Compile {foreach ...} tag. + * + * @param string $tag_args + * @return string + */ + function _compile_foreach_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['from'])) { + return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $from = $attrs['from']; + + if (empty($attrs['item'])) { + return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $item = $this->_dequote($attrs['item']); + if (!preg_match('~^\w+$~', $item)) { + return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($attrs['key'])) { + $key = $this->_dequote($attrs['key']); + if (!preg_match('~^\w+$~', $key)) { + return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + $key_part = "\$this->_tpl_vars['$key'] => "; + } else { + $key = null; + $key_part = ''; + } + + if (isset($attrs['name'])) { + $name = $attrs['name']; + } else { + $name = null; + } + + $output = '_foreach[$name]"; + $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; + $output .= "if ({$foreach_props}['total'] > 0):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + $output .= " {$foreach_props}['iteration']++;\n"; + } else { + $output .= "if (count(\$_from)):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + } + $output .= '?>'; + + return $output; + } + + + /** + * Compile {capture} .. {/capture} tags + * + * @param boolean $start true if this is the {capture} tag + * @param string $tag_args + * @return string + */ + + function _compile_capture_tag($start, $tag_args = '') + { + $attrs = $this->_parse_attrs($tag_args); + + if ($start) { + $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; + $assign = isset($attrs['assign']) ? $attrs['assign'] : null; + $append = isset($attrs['append']) ? $attrs['append'] : null; + + $output = ""; + $this->_capture_stack[] = array($buffer, $assign, $append); + } else { + list($buffer, $assign, $append) = array_pop($this->_capture_stack); + $output = "_smarty_vars['capture'][$buffer] = ob_get_contents(); "; + if (isset($assign)) { + $output .= " \$this->assign($assign, ob_get_contents());"; + } + if (isset($append)) { + $output .= " \$this->append($append, ob_get_contents());"; + } + $output .= "ob_end_clean(); ?>"; + } + + return $output; + } + + /** + * Compile {if ...} tag + * + * @param string $tag_args + * @param boolean $elseif if true, uses elseif instead of if + * @return string + */ + function _compile_if_tag($tag_args, $elseif = false) + { + + /* Tokenize args for 'if' tag. */ + preg_match_all('~(?> + ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call + ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string + \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token + \b\w+\b | # valid word token + \S+ # anything else + )~x', $tag_args, $match); + + $tokens = $match[0]; + + if(empty($tokens)) { + $_error_msg = $elseif ? "'elseif'" : "'if'"; + $_error_msg .= ' statement requires arguments'; + $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); + } + + + // make sure we have balanced parenthesis + $token_count = array_count_values($tokens); + if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { + $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + + $is_arg_stack = array(); + + for ($i = 0; $i < count($tokens); $i++) { + + $token = &$tokens[$i]; + + switch (strtolower($token)) { + case '!': + case '%': + case '!==': + case '==': + case '===': + case '>': + case '<': + case '!=': + case '<>': + case '<<': + case '>>': + case '<=': + case '>=': + case '&&': + case '||': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + /* If last token was a ')', we operate on the parenthesized + expression. The start of the expression is on the stack. + Otherwise, we operate on the last encountered token. */ + if ($tokens[$i-1] == ')') { + $is_arg_start = array_pop($is_arg_stack); + if ($is_arg_start != 0) { + if (preg_match('~^' . $this->_func_regexp . '$~', $tokens[$is_arg_start-1])) { + $is_arg_start--; + } + } + } else + $is_arg_start = $i-1; + /* Construct the argument for 'is' expression, so it knows + what to operate on. */ + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + /* Pass all tokens from next one until the end to the + 'is' expression parsing function. The function will + return modified tokens, where the first one is the result + of the 'is' expression and the rest are the tokens it + didn't touch. */ + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + /* Replace the old tokens with the new ones. */ + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + /* Adjust argument start so that it won't change from the + current position for the next iteration. */ + $i = $is_arg_start; + break; + + default: + if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { + // function call + if($this->security && + !in_array($token, $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { + // variable function call + $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { + // object or variable + $token = $this->_parse_var_props($token); + } elseif(is_numeric($token)) { + // number, skip it + } else { + $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + } + } + + if ($elseif) + return ''; + else + return ''; + } + + + function _compile_arg_list($type, $name, $attrs, &$cache_code) { + $arg_list = array(); + + if (isset($type) && isset($name) + && isset($this->_plugins[$type]) + && isset($this->_plugins[$type][$name]) + && empty($this->_plugins[$type][$name][4]) + && is_array($this->_plugins[$type][$name][5]) + ) { + /* we have a list of parameters that should be cached */ + $_cache_attrs = $this->_plugins[$type][$name][5]; + $_count = $this->_cache_attrs_count++; + $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; + + } else { + /* no parameters are cached */ + $_cache_attrs = null; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + if (is_null($arg_value)) + $arg_value = 'null'; + if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { + $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; + } else { + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + return $arg_list; + } + + /** + * Parse is expression + * + * @param string $is_arg + * @param array $tokens + * @return array + */ + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') { + $negate_expr = true; + $expr_type = array_shift($tokens); + } else + $expr_type = $first_token; + + switch ($expr_type) { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "!(1 & $is_arg)"; + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "(1 & $is_arg)"; + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; + } else { + $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + + default: + $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if ($negate_expr) { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Parse attribute string + * + * @param string $tag_args + * @return array + */ + function _parse_attrs($tag_args) + { + + /* Tokenize tag attributes. */ + preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + ~x', $tag_args, $match); + $tokens = $match[0]; + + $attrs = array(); + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('~^\w+$~', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('~^(on|yes|true)$~', $token)) { + $token = 'true'; + } else if (preg_match('~^(off|no|false)$~', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { + /* treat integer literally */ + } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; + } + + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } + + $this->_parse_vars_props($attrs); + + return $attrs; + } + + /** + * compile multiple variables and section properties tokens into + * PHP code + * + * @param array $tokens + */ + function _parse_vars_props(&$tokens) + { + foreach($tokens as $key => $val) { + $tokens[$key] = $this->_parse_var_props($val); + } + } + + /** + * compile single variable and section properties token into + * PHP code + * + * @param string $val + * @param string $tag_attrs + * @return string + */ + function _parse_var_props($val) + { + $val = trim($val); + + if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { + // $ variable or object + $return = $this->_parse_var($match[1]); + $modifiers = $match[2]; + if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { + $_default_mod_string = implode('|',(array)$this->default_modifiers); + $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; + } + $this->_parse_modifiers($return, $modifiers); + return $return; + } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // double quoted text + preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + $return = $this->_expand_quoted_text($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // numerical constant + preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // single quoted text + preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // config var + return $this->_parse_conf_var($val); + } + elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // section var + return $this->_parse_section_prop($val); + } + elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { + // literal string + return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); + } + return $val; + } + + /** + * expand quoted text with embedded variables + * + * @param string $var_expr + * @return string + */ + function _expand_quoted_text($var_expr) + { + // if contains unescaped $, expand it + if(preg_match_all('~(?:\`(?_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?_parse_var(str_replace('`','',$_var)) . ')."'; + } + $var_expr = strtr($var_expr, $_replace); + $_return = preg_replace('~\.""|(?_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); + + if(count($_math_vars) > 1) { + $_first_var = ""; + $_complete_var = ""; + $_output = ""; + // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) + foreach($_math_vars as $_k => $_math_var) { + $_math_var = $_math_vars[$_k]; + + if(!empty($_math_var) || is_numeric($_math_var)) { + // hit a math operator, so process the stuff which came before it + if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { + $_has_math = true; + if(!empty($_complete_var) || is_numeric($_complete_var)) { + $_output .= $this->_parse_var($_complete_var); + } + + // just output the math operator to php + $_output .= $_math_var; + + if(empty($_first_var)) + $_first_var = $_complete_var; + + $_complete_var = ""; + } else { + $_complete_var .= $_math_var; + } + } + } + if($_has_math) { + if(!empty($_complete_var) || is_numeric($_complete_var)) + $_output .= $this->_parse_var($_complete_var); + + // get the modifiers working (only the last var from math + modifier is left) + $var_expr = $_complete_var; + } + } + + // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) + if(is_numeric(substr($var_expr, 0, 1))) + $_var_ref = $var_expr; + else + $_var_ref = substr($var_expr, 1); + + if(!$_has_math) { + + // get [foo] and .foo and ->foo and (...) pieces + preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); + + $_indexes = $match[0]; + $_var_name = array_shift($_indexes); + + /* Handle $smarty.* variable references as a special case. */ + if ($_var_name == 'smarty') { + /* + * If the reference could be compiled, use the compiled output; + * otherwise, fall back on the $smarty variable generated at + * run-time. + */ + if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { + $_output = $smarty_ref; + } else { + $_var_name = substr(array_shift($_indexes), 1); + $_output = "\$this->_smarty_vars['$_var_name']"; + } + } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { + // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers + if(count($_indexes) > 0) + { + $_var_name .= implode("", $_indexes); + $_indexes = array(); + } + $_output = $_var_name; + } else { + $_output = "\$this->_tpl_vars['$_var_name']"; + } + + foreach ($_indexes as $_index) { + if (substr($_index, 0, 1) == '[') { + $_index = substr($_index, 1, -1); + if (is_numeric($_index)) { + $_output .= "[$_index]"; + } elseif (substr($_index, 0, 1) == '$') { + if (strpos($_index, '.') !== false) { + $_output .= '[' . $this->_parse_var($_index) . ']'; + } else { + $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; + } + } else { + $_var_parts = explode('.', $_index); + $_var_section = $_var_parts[0]; + $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; + $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; + } + } else if (substr($_index, 0, 1) == '.') { + if (substr($_index, 1, 1) == '$') + $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; + else + $_output .= "['" . substr($_index, 1) . "']"; + } else if (substr($_index,0,2) == '->') { + if(substr($_index,2,2) == '__') { + $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif($this->security && substr($_index, 2, 1) == '_') { + $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif (substr($_index, 2, 1) == '$') { + if ($this->security) { + $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } else { + $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; + } + } else { + $_output .= $_index; + } + } elseif (substr($_index, 0, 1) == '(') { + $_index = $this->_parse_parenth_args($_index); + $_output .= $_index; + } else { + $_output .= $_index; + } + } + } + + return $_output; + } + + /** + * parse arguments in function call parenthesis + * + * @param string $parenth_args + * @return string + */ + function _parse_parenth_args($parenth_args) + { + preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); + $orig_vals = $match = $match[0]; + $this->_parse_vars_props($match); + $replace = array(); + for ($i = 0, $count = count($match); $i < $count; $i++) { + $replace[$orig_vals[$i]] = $match[$i]; + } + return strtr($parenth_args, $replace); + } + + /** + * parse configuration variable expression into PHP code + * + * @param string $conf_var_expr + */ + function _parse_conf_var($conf_var_expr) + { + $parts = explode('|', $conf_var_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + $var_name = substr($var_ref, 1, -1); + + $output = "\$this->_config[0]['vars']['$var_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + /** + * parse section property expression into PHP code + * + * @param string $section_prop_expr + * @return string + */ + function _parse_section_prop($section_prop_expr) + { + $parts = explode('|', $section_prop_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); + $section_name = $match[1]; + $prop_name = $match[2]; + + $output = "\$this->_sections['$section_name']['$prop_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + + /** + * parse modifier chain into PHP code + * + * sets $output to parsed modified chain + * @param string $output + * @param string $modifier_string + */ + function _parse_modifiers(&$output, $modifier_string) + { + preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); + list(, $_modifiers, $modifier_arg_strings) = $_match; + + for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { + $_modifier_name = $_modifiers[$_i]; + + if($_modifier_name == 'smarty') { + // skip smarty modifier + continue; + } + + preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); + $_modifier_args = $_match[1]; + + if (substr($_modifier_name, 0, 1) == '@') { + $_map_array = false; + $_modifier_name = substr($_modifier_name, 1); + } else { + $_map_array = true; + } + + if (empty($this->_plugins['modifier'][$_modifier_name]) + && !$this->_get_plugin_filepath('modifier', $_modifier_name) + && function_exists($_modifier_name)) { + if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } else { + $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); + } + } + $this->_add_plugin('modifier', $_modifier_name); + + $this->_parse_vars_props($_modifier_args); + + if($_modifier_name == 'default') { + // supress notifications of default modifier vars and args + if(substr($output, 0, 1) == '$') { + $output = '@' . $output; + } + if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { + $_modifier_args[0] = '@' . $_modifier_args[0]; + } + } + if (count($_modifier_args) > 0) + $_modifier_args = ', '.implode(', ', $_modifier_args); + else + $_modifier_args = ''; + + if ($_map_array) { + $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; + + } else { + + $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; + + } + } + } + + + /** + * add plugin + * + * @param string $type + * @param string $name + * @param boolean? $delayed_loading + */ + function _add_plugin($type, $name, $delayed_loading = null) + { + if (!isset($this->_plugin_info[$type])) { + $this->_plugin_info[$type] = array(); + } + if (!isset($this->_plugin_info[$type][$name])) { + $this->_plugin_info[$type][$name] = array($this->_current_file, + $this->_current_line_no, + $delayed_loading); + } + } + + + /** + * Compiles references of type $smarty.foo + * + * @param string $indexes + * @return string + */ + function _compile_smarty_ref(&$indexes) + { + /* Extract the reference name. */ + $_ref = substr($indexes[0], 1); + foreach($indexes as $_index_no=>$_index) { + if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { + $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + } + + switch ($_ref) { + case 'now': + $compiled_ref = 'time()'; + $_max_index = 1; + break; + + case 'foreach': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $_propname = substr($indexes[1], 1); + $_max_index = 1; + switch ($_propname) { + case 'index': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; + break; + + case 'first': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; + break; + + case 'last': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; + break; + + case 'show': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; + break; + + default: + unset($_max_index); + $compiled_ref = "\$this->_foreach[$_var]"; + } + break; + + case 'section': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = "\$this->_sections[$_var]"; + break; + + case 'get': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_GET"; + break; + + case 'post': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_POST"; + break; + + case 'cookies': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_COOKIE"; + break; + + case 'env': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_ENV"; + break; + + case 'server': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_SERVER"; + break; + + case 'session': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + $compiled_ref = "\$_SESSION"; + break; + + /* + * These cases are handled either at run-time or elsewhere in the + * compiler. + */ + case 'request': + if ($this->security && !$this->security_settings['ALLOW_SUPER_GLOBALS']) { + $this->_syntax_error("(secure mode) super global access not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + if ($this->request_use_auto_globals) { + $compiled_ref = "\$_REQUEST"; + break; + } else { + $this->_init_smarty_vars = true; + } + return null; + + case 'capture': + return null; + + case 'template': + $compiled_ref = "'" . addslashes($this->_current_file) . "'"; + $_max_index = 1; + break; + + case 'version': + $compiled_ref = "'$this->_version'"; + $_max_index = 1; + break; + + case 'const': + if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { + $this->_syntax_error("(secure mode) constants not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + array_shift($indexes); + if (preg_match('!^\.\w+$!', $indexes[0])) { + $compiled_ref = '@' . substr($indexes[0], 1); + } else { + $_val = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = '@constant(' . $_val . ')'; + } + $_max_index = 1; + break; + + case 'config': + $compiled_ref = "\$this->_config[0]['vars']"; + $_max_index = 3; + break; + + case 'ldelim': + $compiled_ref = "'$this->left_delimiter'"; + break; + + case 'rdelim': + $compiled_ref = "'$this->right_delimiter'"; + break; + + default: + $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if (isset($_max_index) && count($indexes) > $_max_index) { + $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + + array_shift($indexes); + return $compiled_ref; + } + + /** + * compiles call to plugin of type $type with name $name + * returns a string containing the function-name or method call + * without the paramter-list that would have follow to make the + * call valid php-syntax + * + * @param string $type + * @param string $name + * @return string + */ + function _compile_plugin_call($type, $name) { + if (isset($this->_plugins[$type][$name])) { + /* plugin loaded */ + if (is_array($this->_plugins[$type][$name][0])) { + return ((is_object($this->_plugins[$type][$name][0][0])) ? + "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ + : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ + ). $this->_plugins[$type][$name][0][1]; + + } else { + /* function callback */ + return $this->_plugins[$type][$name][0]; + + } + } else { + /* plugin not loaded -> auto-loadable-plugin */ + return 'smarty_'.$type.'_'.$name; + + } + } + + /** + * load pre- and post-filters + */ + function _load_filters() + { + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) { + unset($this->_plugins['prefilter'][$filter_name]); + $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) { + unset($this->_plugins['postfilter'][$filter_name]); + $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + } + + + /** + * Quote subpattern references + * + * @param string $string + * @return string + */ + function _quote_replace($string) + { + return strtr($string, array('\\' => '\\\\', '$' => '\\$')); + } + + /** + * display Smarty syntax error + * + * @param string $error_msg + * @param integer $error_type + * @param string $file + * @param integer $line + */ + function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) + { + $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); + } + + + /** + * check if the compilation changes from cacheable to + * non-cacheable state with the beginning of the current + * plugin. return php-code to reflect the transition. + * @return string + */ + function _push_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || 0<$this->_cacheable_state++) return ''; + if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); + $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' + . $this->_cache_serial . '#' . $this->_nocache_count + . '}\'; endif;'; + return $_ret; + } + + + /** + * check if the compilation changes from non-cacheable to + * cacheable state with the end of the current plugin return + * php-code to reflect the transition. + * @return string + */ + function _pop_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || --$this->_cacheable_state>0) return ''; + return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' + . $this->_cache_serial . '#' . ($this->_nocache_count++) + . '}\'; endif;'; + } + + + /** + * push opening tag-name, file-name and line-number on the tag-stack + * @param string the opening tag's name + */ + function _push_tag($open_tag) + { + array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); + } + + /** + * pop closing tag-name + * raise an error if this stack-top doesn't match with the closing tag + * @param string the closing tag's name + * @return string the opening tag's name + */ + function _pop_tag($close_tag) + { + $message = ''; + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = array_pop($this->_tag_stack); + if ($close_tag == $_open_tag) { + return $_open_tag; + } + if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { + return $this->_pop_tag($close_tag); + } + if ($close_tag == 'section' && $_open_tag == 'sectionelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($_open_tag == 'else' || $_open_tag == 'elseif') { + $_open_tag = 'if'; + } elseif ($_open_tag == 'sectionelse') { + $_open_tag = 'section'; + } elseif ($_open_tag == 'foreachelse') { + $_open_tag = 'foreach'; + } + $message = " expected {/$_open_tag} (opened line $_line_no)."; + } + $this->_syntax_error("mismatched tag {/$close_tag}.$message", + E_USER_ERROR, __FILE__, __LINE__); + } + +} + +/** + * compare to values by their string length + * + * @access private + * @param string $a + * @param string $b + * @return 0|-1|1 + */ +function _smarty_sort_length($a, $b) +{ + if($a == $b) + return 0; + + if(strlen($a) == strlen($b)) + return ($a > $b) ? -1 : 1; + + return (strlen($a) > strlen($b)) ? -1 : 1; +} + + +/* vim: set et: */ + +?> diff --git a/lib/Smarty/debug.tpl b/lib/Smarty/debug.tpl new file mode 100644 index 0000000..c05ef5d --- /dev/null +++ b/lib/Smarty/debug.tpl @@ -0,0 +1,157 @@ +{* Smarty *} +{* debug.tpl, last updated version 2.1.0 *} +{assign_debug_info} +{capture assign=debug_output} + + + + Smarty Debug Console +{literal} + +{/literal} + + + +

      Smarty Debug Console

      + +

      included templates & config files (load time in seconds)

      + +
      +{section name=templates loop=$_debug_tpls} + {section name=indent loop=$_debug_tpls[templates].depth}   {/section} + + {$_debug_tpls[templates].filename|escape:html} + {if isset($_debug_tpls[templates].exec_time)} + + ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}) + {if %templates.index% eq 0}(total){/if} + + {/if} +
      +{sectionelse} +

      no templates included

      +{/section} +
      + +

      assigned template variables

      + + + {section name=vars loop=$_debug_keys} + + + + {sectionelse} + + {/section} +
      {ldelim}${$_debug_keys[vars]|escape:'html'}{rdelim}{$_debug_vals[vars]|@debug_print_var}

      no template variables assigned

      + +

      assigned config file variables (outer template scope)

      + + + {section name=config_vars loop=$_debug_config_keys} + + + + {sectionelse} + + {/section} +
      {ldelim}#{$_debug_config_keys[config_vars]|escape:'html'}#{rdelim}{$_debug_config_vals[config_vars]|@debug_print_var}

      no config vars assigned

      + + +{/capture} +{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"} + {$debug_output} +{else} + +{/if} \ No newline at end of file diff --git a/lib/Smarty/internals/core.assemble_plugin_filepath.php b/lib/Smarty/internals/core.assemble_plugin_filepath.php new file mode 100644 index 0000000..22c0248 --- /dev/null +++ b/lib/Smarty/internals/core.assemble_plugin_filepath.php @@ -0,0 +1,65 @@ +_filepaths_cache[$_plugin_filename])) { + return $smarty->_filepaths_cache[$_plugin_filename]; + } + $_return = false; + + foreach ((array)$smarty->plugins_dir as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + // see if path is relative + if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) { + $_relative_paths[] = $_plugin_dir; + // relative path, see if it is in the SMARTY_DIR + if (@is_readable(SMARTY_DIR . $_plugin_filepath)) { + $_return = SMARTY_DIR . $_plugin_filepath; + break; + } + } + // try relative to cwd (or absolute) + if (@is_readable($_plugin_filepath)) { + $_return = $_plugin_filepath; + break; + } + } + + if($_return === false) { + // still not found, try PHP include_path + if(isset($_relative_paths)) { + foreach ((array)$_relative_paths as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + $_params = array('file_path' => $_plugin_filepath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_return = $_params['new_file_path']; + break; + } + } + } + } + $smarty->_filepaths_cache[$_plugin_filename] = $_return; + return $_return; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.assign_smarty_interface.php b/lib/Smarty/internals/core.assign_smarty_interface.php new file mode 100644 index 0000000..7e65a73 --- /dev/null +++ b/lib/Smarty/internals/core.assign_smarty_interface.php @@ -0,0 +1,43 @@ + + * Name: assign_smarty_interface
      + * Purpose: assign the $smarty interface variable + * @param array Format: null + * @param Smarty + */ +function smarty_core_assign_smarty_interface($params, &$smarty) +{ + if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) { + return; + } + + $_globals_map = array('g' => 'HTTP_GET_VARS', + 'p' => 'HTTP_POST_VARS', + 'c' => 'HTTP_COOKIE_VARS', + 's' => 'HTTP_SERVER_VARS', + 'e' => 'HTTP_ENV_VARS'); + + $_smarty_vars_request = array(); + + foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) { + if (isset($_globals_map[$_c])) { + $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]); + } + } + $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']); + + $smarty->_smarty_vars['request'] = $_smarty_vars_request; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.create_dir_structure.php b/lib/Smarty/internals/core.create_dir_structure.php new file mode 100644 index 0000000..3eecc49 --- /dev/null +++ b/lib/Smarty/internals/core.create_dir_structure.php @@ -0,0 +1,79 @@ +_dir_perms) && !is_dir($_new_dir)) { + $smarty->trigger_error("problem creating directory '" . $_new_dir . "'"); + return false; + } + $_new_dir .= '/'; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.display_debug_console.php b/lib/Smarty/internals/core.display_debug_console.php new file mode 100644 index 0000000..1a80f39 --- /dev/null +++ b/lib/Smarty/internals/core.display_debug_console.php @@ -0,0 +1,61 @@ + + * Name: display_debug_console
      + * Purpose: display the javascript debug console window + * @param array Format: null + * @param Smarty + */ +function smarty_core_display_debug_console($params, &$smarty) +{ + // we must force compile the debug template in case the environment + // changed between separate applications. + + if(empty($smarty->debug_tpl)) { + // set path to debug template from SMARTY_DIR + $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl'; + if($smarty->security && is_file($smarty->debug_tpl)) { + $smarty->secure_dir[] = realpath($smarty->debug_tpl); + } + $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl'; + } + + $_ldelim_orig = $smarty->left_delimiter; + $_rdelim_orig = $smarty->right_delimiter; + + $smarty->left_delimiter = '{'; + $smarty->right_delimiter = '}'; + + $_compile_id_orig = $smarty->_compile_id; + $smarty->_compile_id = null; + + $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl); + if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path)) + { + ob_start(); + $smarty->_include($_compile_path); + $_results = ob_get_contents(); + ob_end_clean(); + } else { + $_results = ''; + } + + $smarty->_compile_id = $_compile_id_orig; + + $smarty->left_delimiter = $_ldelim_orig; + $smarty->right_delimiter = $_rdelim_orig; + + return $_results; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.get_include_path.php b/lib/Smarty/internals/core.get_include_path.php new file mode 100644 index 0000000..4343241 --- /dev/null +++ b/lib/Smarty/internals/core.get_include_path.php @@ -0,0 +1,44 @@ + diff --git a/lib/Smarty/internals/core.get_microtime.php b/lib/Smarty/internals/core.get_microtime.php new file mode 100644 index 0000000..f1a28e0 --- /dev/null +++ b/lib/Smarty/internals/core.get_microtime.php @@ -0,0 +1,23 @@ + diff --git a/lib/Smarty/internals/core.get_php_resource.php b/lib/Smarty/internals/core.get_php_resource.php new file mode 100644 index 0000000..786d4e7 --- /dev/null +++ b/lib/Smarty/internals/core.get_php_resource.php @@ -0,0 +1,80 @@ +trusted_dir; + $smarty->_parse_resource_name($params, $smarty); + + /* + * Find out if the resource exists. + */ + + if ($params['resource_type'] == 'file') { + $_readable = false; + if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) { + $_readable = true; + } else { + // test for file in include_path + $_params = array('file_path' => $params['resource_name']); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_include_path = $_params['new_file_path']; + $_readable = true; + } + } + } else if ($params['resource_type'] != 'file') { + $_template_source = null; + $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0]) + && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0], + array($params['resource_name'], &$_template_source, &$smarty)); + } + + /* + * Set the error function, depending on which class calls us. + */ + if (method_exists($smarty, '_syntax_error')) { + $_error_funcc = '_syntax_error'; + } else { + $_error_funcc = 'trigger_error'; + } + + if ($_readable) { + if ($smarty->security) { + require_once(SMARTY_CORE_DIR . 'core.is_trusted.php'); + if (!smarty_core_is_trusted($params, $smarty)) { + $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted'); + return false; + } + } + } else { + $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable'); + return false; + } + + if ($params['resource_type'] == 'file') { + $params['php_resource'] = $params['resource_name']; + } else { + $params['php_resource'] = $_template_source; + } + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.is_secure.php b/lib/Smarty/internals/core.is_secure.php new file mode 100644 index 0000000..d54abd4 --- /dev/null +++ b/lib/Smarty/internals/core.is_secure.php @@ -0,0 +1,59 @@ +security || $smarty->security_settings['INCLUDE_ANY']) { + return true; + } + + if ($params['resource_type'] == 'file') { + $_rp = realpath($params['resource_name']); + if (isset($params['resource_base_path'])) { + foreach ((array)$params['resource_base_path'] as $curr_dir) { + if ( ($_cd = realpath($curr_dir)) !== false && + strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { + return true; + } + } + } + if (!empty($smarty->secure_dir)) { + foreach ((array)$smarty->secure_dir as $curr_dir) { + if ( ($_cd = realpath($curr_dir)) !== false) { + if($_cd == $_rp) { + return true; + } elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR) { + return true; + } + } + } + } + } else { + // resource is not on local file system + return call_user_func_array( + $smarty->_plugins['resource'][$params['resource_type']][0][2], + array($params['resource_name'], &$smarty)); + } + + return false; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.is_trusted.php b/lib/Smarty/internals/core.is_trusted.php new file mode 100644 index 0000000..4299731 --- /dev/null +++ b/lib/Smarty/internals/core.is_trusted.php @@ -0,0 +1,47 @@ +trusted_dir)) { + $_rp = realpath($params['resource_name']); + foreach ((array)$smarty->trusted_dir as $curr_dir) { + if (!empty($curr_dir) && is_readable ($curr_dir)) { + $_cd = realpath($curr_dir); + if (strncmp($_rp, $_cd, strlen($_cd)) == 0 + && substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { + $_smarty_trusted = true; + break; + } + } + } + } + + } else { + // resource is not on local file system + $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3], + array($params['resource_name'], $smarty)); + } + + return $_smarty_trusted; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.load_plugins.php b/lib/Smarty/internals/core.load_plugins.php new file mode 100644 index 0000000..6db1dc5 --- /dev/null +++ b/lib/Smarty/internals/core.load_plugins.php @@ -0,0 +1,125 @@ +_plugins[$_type][$_name]; + + /* + * We do not load plugin more than once for each instance of Smarty. + * The following code checks for that. The plugin can also be + * registered dynamically at runtime, in which case template file + * and line number will be unknown, so we fill them in. + * + * The final element of the info array is a flag that indicates + * whether the dynamically registered plugin function has been + * checked for existence yet or not. + */ + if (isset($_plugin)) { + if (empty($_plugin[3])) { + if (!is_callable($_plugin[0])) { + $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } else { + $_plugin[1] = $_tpl_file; + $_plugin[2] = $_tpl_line; + $_plugin[3] = true; + if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */ + } + } + continue; + } else if ($_type == 'insert') { + /* + * For backwards compatibility, we check for insert functions in + * the symbol table before trying to load them as a plugin. + */ + $_plugin_func = 'insert_' . $_name; + if (function_exists($_plugin_func)) { + $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false); + continue; + } + } + + $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name); + + if (! $_found = ($_plugin_file != false)) { + $_message = "could not load plugin file '$_type.$_name.php'\n"; + } + + /* + * If plugin file is found, it -must- provide the properly named + * plugin function. In case it doesn't, simply output the error and + * do not fall back on any other method. + */ + if ($_found) { + include_once $_plugin_file; + + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + continue; + } + } + /* + * In case of insert plugins, their code may be loaded later via + * 'script' attribute. + */ + else if ($_type == 'insert' && $_delayed_loading) { + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + $_found = true; + } + + /* + * Plugin specific processing and error checking. + */ + if (!$_found) { + if ($_type == 'modifier') { + /* + * In case modifier falls back on using PHP functions + * directly, we only allow those specified in the security + * context. + */ + if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) { + $_message = "(secure mode) modifier '$_name' is not allowed"; + } else { + if (!function_exists($_name)) { + $_message = "modifier '$_name' is not implemented"; + } else { + $_plugin_func = $_name; + $_found = true; + } + } + } else if ($_type == 'function') { + /* + * This is a catch-all situation. + */ + $_message = "unknown tag - '$_name'"; + } + } + + if ($_found) { + $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true); + } else { + // output error + $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.load_resource_plugin.php b/lib/Smarty/internals/core.load_resource_plugin.php new file mode 100644 index 0000000..a7d37d1 --- /dev/null +++ b/lib/Smarty/internals/core.load_resource_plugin.php @@ -0,0 +1,74 @@ +_plugins['resource'][$params['type']]; + if (isset($_plugin)) { + if (!$_plugin[1] && count($_plugin[0])) { + $_plugin[1] = true; + foreach ($_plugin[0] as $_plugin_func) { + if (!is_callable($_plugin_func)) { + $_plugin[1] = false; + break; + } + } + } + + if (!$_plugin[1]) { + $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__); + } + + return; + } + + $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']); + $_found = ($_plugin_file != false); + + if ($_found) { /* + * If the plugin file is found, it -must- provide the properly named + * plugin functions. + */ + include_once($_plugin_file); + + /* + * Locate functions that we require the plugin to provide. + */ + $_resource_ops = array('source', 'timestamp', 'secure', 'trusted'); + $_resource_funcs = array(); + foreach ($_resource_ops as $_op) { + $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__); + return; + } else { + $_resource_funcs[] = $_plugin_func; + } + } + + $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.process_cached_inserts.php b/lib/Smarty/internals/core.process_cached_inserts.php new file mode 100644 index 0000000..1d78edd --- /dev/null +++ b/lib/Smarty/internals/core.process_cached_inserts.php @@ -0,0 +1,71 @@ +_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis', + $params['results'], $match); + list($cached_inserts, $insert_args) = $match; + + for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) { + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $args = unserialize($insert_args[$i]); + $name = $args['name']; + + if (isset($args['script'])) { + $_params = array('resource_name' => $smarty->_dequote($args['script'])); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + $resource_type = $_params['resource_type']; + $php_resource = $_params['php_resource']; + + + if ($resource_type == 'file') { + $smarty->_include($php_resource, true); + } else { + $smarty->_eval($php_resource); + } + } + + $function_name = $smarty->_plugins['insert'][$name][0]; + if (empty($args['assign'])) { + $replace = $function_name($args, $smarty); + } else { + $smarty->assign($args['assign'], $function_name($args, $smarty)); + $replace = ''; + } + + $params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i])); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$name, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time); + } + } + + return $params['results']; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.process_compiled_include.php b/lib/Smarty/internals/core.process_compiled_include.php new file mode 100644 index 0000000..904d597 --- /dev/null +++ b/lib/Smarty/internals/core.process_compiled_include.php @@ -0,0 +1,37 @@ +_cache_including; + $smarty->_cache_including = true; + + $_return = $params['results']; + + foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { + $smarty->_include($_include_file_path, true); + } + + foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { + $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s', + array(&$smarty, '_process_compiled_include_callback'), + $_return); + } + $smarty->_cache_including = $_cache_including; + return $_return; +} + +?> diff --git a/lib/Smarty/internals/core.read_cache_file.php b/lib/Smarty/internals/core.read_cache_file.php new file mode 100644 index 0000000..c60e113 --- /dev/null +++ b/lib/Smarty/internals/core.read_cache_file.php @@ -0,0 +1,101 @@ +force_compile) { + // force compile enabled, always regenerate + return false; + } + + if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) { + list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']]; + return true; + } + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $params['results'] = $smarty->_read_file($_cache_file); + } + + if (empty($params['results'])) { + // nothing to parse (error?), regenerate cache + return false; + } + + $_contents = $params['results']; + $_info_start = strpos($_contents, "\n") + 1; + $_info_len = (int)substr($_contents, 0, $_info_start - 1); + $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len)); + $params['results'] = substr($_contents, $_info_start + $_info_len); + + if ($smarty->caching == 2 && isset ($_cache_info['expires'])){ + // caching by expiration time + if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) { + // cache expired, regenerate + return false; + } + } else { + // caching by lifetime + if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) { + // cache expired, regenerate + return false; + } + } + + if ($smarty->compile_check) { + $_params = array('get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['template']) as $_template_dep) { + $_params['resource_name'] = $_template_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // template file has changed, regenerate cache + return false; + } + } + + if (isset($_cache_info['config'])) { + $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['config']) as $_config_dep) { + $_params['resource_name'] = $_config_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // config file has changed, regenerate cache + return false; + } + } + } + } + + $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info); + + $smarty->_cache_info = $_cache_info; + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.rm_auto.php b/lib/Smarty/internals/core.rm_auto.php new file mode 100644 index 0000000..b251f64 --- /dev/null +++ b/lib/Smarty/internals/core.rm_auto.php @@ -0,0 +1,71 @@ + $params['auto_base'], + 'level' => 0, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']); + + if(isset($params['auto_source'])) { + if (isset($params['extensions'])) { + $_res = false; + foreach ((array)$params['extensions'] as $_extension) + $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']); + } else { + $_res = $smarty->_unlink($_tname, $params['exp_time']); + } + } elseif ($smarty->use_sub_dirs) { + $_params = array( + 'dirname' => $_tname, + 'level' => 1, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + // remove matching file names + $_handle = opendir($params['auto_base']); + $_res = true; + while (false !== ($_filename = readdir($_handle))) { + if($_filename == '.' || $_filename == '..') { + continue; + } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) { + $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']); + } + } + } + } + + return $_res; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.rmdir.php b/lib/Smarty/internals/core.rmdir.php new file mode 100644 index 0000000..2166c44 --- /dev/null +++ b/lib/Smarty/internals/core.rmdir.php @@ -0,0 +1,54 @@ + keep root) + * WARNING: no tests, it will try to remove what you tell it! + * + * @param string $dirname + * @param integer $level + * @param integer $exp_time + * @return boolean + */ + +// $dirname, $level = 1, $exp_time = null + +function smarty_core_rmdir($params, &$smarty) +{ + if(!isset($params['level'])) { $params['level'] = 1; } + if(!isset($params['exp_time'])) { $params['exp_time'] = null; } + + if($_handle = @opendir($params['dirname'])) { + + while (false !== ($_entry = readdir($_handle))) { + if ($_entry != '.' && $_entry != '..') { + if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) { + $_params = array( + 'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry, + 'level' => $params['level'] + 1, + 'exp_time' => $params['exp_time'] + ); + smarty_core_rmdir($_params, $smarty); + } + else { + $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']); + } + } + } + closedir($_handle); + } + + if ($params['level']) { + return @rmdir($params['dirname']); + } + return (bool)$_handle; + +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.run_insert_handler.php b/lib/Smarty/internals/core.run_insert_handler.php new file mode 100644 index 0000000..71c3845 --- /dev/null +++ b/lib/Smarty/internals/core.run_insert_handler.php @@ -0,0 +1,71 @@ +debugging) { + $_params = array(); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + if ($smarty->caching) { + $_arg_string = serialize($params['args']); + $_name = $params['args']['name']; + if (!isset($smarty->_cache_info['insert_tags'][$_name])) { + $smarty->_cache_info['insert_tags'][$_name] = array('insert', + $_name, + $smarty->_plugins['insert'][$_name][1], + $smarty->_plugins['insert'][$_name][2], + !empty($params['args']['script']) ? true : false); + } + return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5; + } else { + if (isset($params['args']['script'])) { + $_params = array('resource_name' => $smarty->_dequote($params['args']['script'])); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + + if ($_params['resource_type'] == 'file') { + $smarty->_include($_params['php_resource'], true); + } else { + $smarty->_eval($_params['php_resource']); + } + unset($params['args']['script']); + } + + $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0]; + $_content = $_funcname($params['args'], $smarty); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$params['args']['name'], + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + + if (!empty($params['args']["assign"])) { + $smarty->assign($params['args']["assign"], $_content); + } else { + return $_content; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.smarty_include_php.php b/lib/Smarty/internals/core.smarty_include_php.php new file mode 100644 index 0000000..30c6e76 --- /dev/null +++ b/lib/Smarty/internals/core.smarty_include_php.php @@ -0,0 +1,50 @@ + $params['smarty_file']); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + smarty_core_get_php_resource($_params, $smarty); + $_smarty_resource_type = $_params['resource_type']; + $_smarty_php_resource = $_params['php_resource']; + + if (!empty($params['smarty_assign'])) { + ob_start(); + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + $smarty->assign($params['smarty_assign'], ob_get_contents()); + ob_end_clean(); + } else { + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + } +} + + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.write_cache_file.php b/lib/Smarty/internals/core.write_cache_file.php new file mode 100644 index 0000000..fa3cdd7 --- /dev/null +++ b/lib/Smarty/internals/core.write_cache_file.php @@ -0,0 +1,96 @@ +_cache_info['timestamp'] = time(); + if ($smarty->cache_lifetime > -1){ + // expiration set + $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime; + } else { + // cache will never expire + $smarty->_cache_info['expires'] = -1; + } + + // collapse nocache.../nocache-tags + if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) { + // remove everything between every pair of outermost noache.../nocache-tags + // and replace it by a single nocache-tag + // this new nocache-tag will be replaced by dynamic contents in + // smarty_core_process_compiled_includes() on a cache-read + + $match_count = count($match[0]); + $results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE); + + $level = 0; + $j = 0; + for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) { + if ($results[$i] == $match[0][$j]) { + // nocache tag + if ($match[1][$j]) { // closing tag + $level--; + unset($results[$i]); + } else { // opening tag + if ($level++ > 0) unset($results[$i]); + } + $j++; + } elseif ($level > 0) { + unset($results[$i]); + } + } + $params['results'] = implode('', $results); + } + $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials; + + // prepend the cache header info into cache file + $_cache_info = serialize($smarty->_cache_info); + $params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results']; + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], $smarty->_cache_info['expires'])); + } else { + // use local cache file + + if(!@is_writable($smarty->cache_dir)) { + // cache_dir not writable, see if it exists + if(!@is_dir($smarty->cache_dir)) { + $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true); + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.write_compiled_include.php b/lib/Smarty/internals/core.write_compiled_include.php new file mode 100644 index 0000000..c14adb5 --- /dev/null +++ b/lib/Smarty/internals/core.write_compiled_include.php @@ -0,0 +1,91 @@ +caching && \!\$this->_cache_including\)\: echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\'; endif;'; + $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{/nocache\:(\\2)#(\\3)\}\'; endif;'; + + preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', + $params['compiled_content'], $_match_source, PREG_SET_ORDER); + + // no nocache-parts found: done + if (count($_match_source)==0) return; + + // convert the matched php-code to functions + $_include_compiled = "_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $_include_compiled .= " compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n"; + + $_compile_path = $params['include_file_path']; + + $smarty->_cache_serials[$_compile_path] = $params['cache_serial']; + $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>"; + + $_include_compiled .= $params['plugins_code']; + $_include_compiled .= "= 5.0) ? '_smarty' : 'this'; + for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) { + $_match =& $_match_source[$_i]; + $source = $_match[4]; + if ($this_varname == '_smarty') { + /* rename $this to $_smarty in the sourcecode */ + $tokens = token_get_all('\n"; + + $_params = array('filename' => $_compile_path, + 'contents' => $_include_compiled, 'create_dirs' => true); + + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + + +?> diff --git a/lib/Smarty/internals/core.write_compiled_resource.php b/lib/Smarty/internals/core.write_compiled_resource.php new file mode 100644 index 0000000..b902eff --- /dev/null +++ b/lib/Smarty/internals/core.write_compiled_resource.php @@ -0,0 +1,35 @@ +compile_dir)) { + // compile_dir not writable, see if it exists + if(!@is_dir($smarty->compile_dir)) { + $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true); + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/internals/core.write_file.php b/lib/Smarty/internals/core.write_file.php new file mode 100644 index 0000000..8a3a3b3 --- /dev/null +++ b/lib/Smarty/internals/core.write_file.php @@ -0,0 +1,54 @@ + $_dirname); + require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php'); + smarty_core_create_dir_structure($_params, $smarty); + } + + // write to tmp file, then rename it to avoid file locking race condition + $_tmp_file = tempnam($_dirname, 'wrt'); + + if (!($fd = @fopen($_tmp_file, 'wb'))) { + $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt'); + if (!($fd = @fopen($_tmp_file, 'wb'))) { + $smarty->trigger_error("problem writing temporary file '$_tmp_file'"); + return false; + } + } + + fwrite($fd, $params['contents']); + fclose($fd); + + if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) { + // On platforms and filesystems that cannot overwrite with rename() + // delete the file before renaming it -- because windows always suffers + // this, it is short-circuited to avoid the initial rename() attempt + @unlink($params['filename']); + @rename($_tmp_file, $params['filename']); + } + @chmod($params['filename'], $smarty->_file_perms); + + return true; +} + +/* vim: set expandtab: */ + +?> \ No newline at end of file diff --git a/lib/Smarty/plugins/block.textformat.php b/lib/Smarty/plugins/block.textformat.php new file mode 100644 index 0000000..8cd010a --- /dev/null +++ b/lib/Smarty/plugins/block.textformat.php @@ -0,0 +1,103 @@ + + * Name: textformat
      + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
      + * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array + *
      + * Params:   style: string (email)
      + *           indent: integer (0)
      + *           wrap: integer (80)
      + *           wrap_char string ("\n")
      + *           indent_char: string (" ")
      + *           wrap_boundary: boolean (true)
      + * 
      + * @author Monte Ohrt + * @param string contents of the block + * @param Smarty clever simulation of a method + * @return string string $content re-formatted + */ +function smarty_block_textformat($params, $content, &$smarty) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + $smarty->trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + + // split into paragraphs + $_paragraphs = preg_split('![\r\n][\r\n]!',$content); + $_output = ''; + + for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { + if ($_paragraphs[$_x] == '') { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]); + // indent first line + if($indent_first > 0) { + $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; + } + // wordwrap sentences + $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if($indent > 0) { + $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); + } + } + $_output = implode($wrap_char . $wrap_char, $_paragraphs); + + return $assign ? $smarty->assign($assign, $_output) : $_output; + +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/compiler.assign.php b/lib/Smarty/plugins/compiler.assign.php new file mode 100644 index 0000000..abef377 --- /dev/null +++ b/lib/Smarty/plugins/compiler.assign.php @@ -0,0 +1,40 @@ + + * Name: assign
      + * Purpose: assign a value to a template variable + * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} + * (Smarty online manual) + * @author Monte Ohrt (initial author) + * @author messju mohr (conversion to compiler function) + * @param string containing var-attribute and value-attribute + * @param Smarty_Compiler + */ +function smarty_compiler_assign($tag_attrs, &$compiler) +{ + $_params = $compiler->_parse_attrs($tag_attrs); + + if (!isset($_params['var'])) { + $compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING); + return; + } + + if (!isset($_params['value'])) { + $compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING); + return; + } + + return "\$this->assign({$_params['var']}, {$_params['value']});"; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.assign_debug_info.php b/lib/Smarty/plugins/function.assign_debug_info.php new file mode 100644 index 0000000..6540498 --- /dev/null +++ b/lib/Smarty/plugins/function.assign_debug_info.php @@ -0,0 +1,40 @@ + + * Name: assign_debug_info
      + * Purpose: assign debug info to the template
      + * @author Monte Ohrt + * @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, + * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} + * @param Smarty + */ +function smarty_function_assign_debug_info($params, &$smarty) +{ + $assigned_vars = $smarty->_tpl_vars; + ksort($assigned_vars); + if (@is_array($smarty->_config[0])) { + $config_vars = $smarty->_config[0]; + ksort($config_vars); + $smarty->assign("_debug_config_keys", array_keys($config_vars)); + $smarty->assign("_debug_config_vals", array_values($config_vars)); + } + + $included_templates = $smarty->_smarty_debug_info; + + $smarty->assign("_debug_keys", array_keys($assigned_vars)); + $smarty->assign("_debug_vals", array_values($assigned_vars)); + + $smarty->assign("_debug_tpls", $included_templates); +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.config_load.php b/lib/Smarty/plugins/function.config_load.php new file mode 100644 index 0000000..db89f63 --- /dev/null +++ b/lib/Smarty/plugins/function.config_load.php @@ -0,0 +1,142 @@ + + * Name: config_load
      + * Purpose: load config file vars + * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} + * (Smarty online manual) + * @author Monte Ohrt + * @author messju mohr (added use of resources) + * @param array Format: + *
      + * array('file' => required config file name,
      + *       'section' => optional config file section to load
      + *       'scope' => local/parent/global
      + *       'global' => overrides scope, setting to parent if true)
      + * 
      + * @param Smarty + */ +function smarty_function_config_load($params, &$smarty) +{ + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; + $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; + $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; + $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; + + if (!isset($_file) || strlen($_file) == 0) { + $smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($_scope)) { + if ($_scope != 'local' && + $_scope != 'parent' && + $_scope != 'global') { + $smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } else { + if ($_global) { + $_scope = 'parent'; + } else { + $_scope = 'local'; + } + } + + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + 'get_source' => false); + $smarty->_parse_resource_name($_params); + $_file_path = $_params['resource_type'] . ':' . $_params['resource_name']; + if (isset($_section)) + $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); + else + $_compile_file = $smarty->_get_compile_path($_file_path); + + if($smarty->force_compile || !file_exists($_compile_file)) { + $_compile = true; + } elseif ($smarty->compile_check) { + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + 'get_source' => false); + $_compile = $smarty->_fetch_resource_info($_params) && + $_params['resource_timestamp'] > filemtime($_compile_file); + } else { + $_compile = false; + } + + if($_compile) { + // compile config file + if(!is_object($smarty->_conf_obj)) { + require_once SMARTY_DIR . $smarty->config_class . '.class.php'; + $smarty->_conf_obj = new $smarty->config_class(); + $smarty->_conf_obj->overwrite = $smarty->config_overwrite; + $smarty->_conf_obj->booleanize = $smarty->config_booleanize; + $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; + $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; + } + + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + $_params['get_source'] = true); + if (!$smarty->_fetch_resource_info($_params)) { + return; + } + $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']); + $_config_vars = array_merge($smarty->_conf_obj->get($_file), + $smarty->_conf_obj->get($_file, $_section)); + if(function_exists('var_export')) { + $_output = ''; + } else { + $_output = ''\\\'', '\\'=>'\\\\')) . '\'); ?>'; + } + $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp'])); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $smarty); + } else { + include($_compile_file); + } + + if ($smarty->caching) { + $smarty->_cache_info['config'][$_file] = true; + } + + $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); + $smarty->_config[0]['files'][$_file] = true; + + if ($_scope == 'parent') { + $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); + $smarty->_config[1]['files'][$_file] = true; + } else if ($_scope == 'global') { + for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { + $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); + $smarty->_config[$i]['files'][$_file] = true; + } + } + + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'config', + 'filename' => $_file.' ['.$_section.'] '.$_scope, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.counter.php b/lib/Smarty/plugins/function.counter.php new file mode 100644 index 0000000..1f26db5 --- /dev/null +++ b/lib/Smarty/plugins/function.counter.php @@ -0,0 +1,80 @@ + + * Name: counter
      + * Purpose: print out a counter value + * @author Monte Ohrt + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array parameters + * @param Smarty + * @return string|null + */ +function smarty_function_counter($params, &$smarty) +{ + static $counters = array(); + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $smarty->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.cycle.php b/lib/Smarty/plugins/function.cycle.php new file mode 100644 index 0000000..80378b7 --- /dev/null +++ b/lib/Smarty/plugins/function.cycle.php @@ -0,0 +1,106 @@ + + * Name: cycle
      + * Date: May 3, 2002
      + * Purpose: cycle through given values
      + * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * + * Examples:
      + *
      + * {cycle values="#eeeeee,#d0d0d0d"}
      + * {cycle name=row values="one,two,three" reset=true}
      + * {cycle name=row}
      + * 
      + * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @version 1.3 + * @param array + * @param Smarty + * @return string|null + */ +function smarty_function_cycle($params, &$smarty) +{ + static $cycle_vars; + + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!in_array('values', array_keys($params))) { + if(!isset($cycle_vars[$name]['values'])) { + $smarty->trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $params['values'] ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $params['values']; + } + + if (isset($params['delimiter'])) { + $cycle_vars[$name]['delimiter'] = $params['delimiter']; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } + + if(is_array($cycle_vars[$name]['values'])) { + $cycle_array = $cycle_vars[$name]['values']; + } else { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.debug.php b/lib/Smarty/plugins/function.debug.php new file mode 100644 index 0000000..4345230 --- /dev/null +++ b/lib/Smarty/plugins/function.debug.php @@ -0,0 +1,35 @@ + + * Name: debug
      + * Date: July 1, 2002
      + * Purpose: popup debug window + * @link http://smarty.php.net/manual/en/language.function.debug.php {debug} + * (Smarty online manual) + * @author Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string output from {@link Smarty::_generate_debug_output()} + */ +function smarty_function_debug($params, &$smarty) +{ + if (isset($params['output'])) { + $smarty->assign('_smarty_debug_output', $params['output']); + } + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + return smarty_core_display_debug_console(null, $smarty); +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.eval.php b/lib/Smarty/plugins/function.eval.php new file mode 100644 index 0000000..ff0472d --- /dev/null +++ b/lib/Smarty/plugins/function.eval.php @@ -0,0 +1,49 @@ + + * Name: eval
      + * Purpose: evaluate a template variable as a template
      + * @link http://smarty.php.net/manual/en/language.function.eval.php {eval} + * (Smarty online manual) + * @author Monte Ohrt + * @param array + * @param Smarty + */ +function smarty_function_eval($params, &$smarty) +{ + + if (!isset($params['var'])) { + $smarty->trigger_error("eval: missing 'var' parameter"); + return; + } + + if($params['var'] == '') { + return; + } + + $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); + + ob_start(); + $smarty->_eval('?>' . $_var_compiled); + $_contents = ob_get_contents(); + ob_end_clean(); + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'], $_contents); + } else { + return $_contents; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.fetch.php b/lib/Smarty/plugins/function.fetch.php new file mode 100644 index 0000000..d72c7b1 --- /dev/null +++ b/lib/Smarty/plugins/function.fetch.php @@ -0,0 +1,221 @@ + + * Name: fetch
      + * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt + * @param array + * @param Smarty + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, &$smarty) +{ + if (empty($params['file'])) { + $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); + return; + } + + $content = ''; + if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { + $_params = array('resource_type' => 'file', 'resource_name' => $params['file']); + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if(!smarty_core_is_secure($_params, $smarty)) { + $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$smarty->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(!empty($uri_parts['user'])) { + $user = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + default: + $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)"); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = preg_split("!\r\n\r\n!",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $smarty->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0])); + } + } + } else { + $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'],$content); + } else { + return $content; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.html_checkboxes.php b/lib/Smarty/plugins/function.html_checkboxes.php new file mode 100644 index 0000000..ed8ad7f --- /dev/null +++ b/lib/Smarty/plugins/function.html_checkboxes.php @@ -0,0 +1,143 @@ + + * Type: function
      + * Name: html_checkboxes
      + * Date: 24.Feb.2003
      + * Purpose: Prints out a list of checkbox input types
      + * Input:
      + * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
      or   + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * Examples: + *
      + * {html_checkboxes values=$ids output=$names}
      + * {html_checkboxes values=$ids name='box' separator='
      ' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
      ' output=$names} + *
      + * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_map('strval', array_values((array)$_val)); + break; + + case 'checkboxes': + $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = array(); + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + if(!empty($params['assign'])) { + $smarty->assign($params['assign'], $_html_result); + } else { + return implode("\n",$_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator; + + return $_output; +} + +?> diff --git a/lib/Smarty/plugins/function.html_image.php b/lib/Smarty/plugins/function.html_image.php new file mode 100644 index 0000000..9abae72 --- /dev/null +++ b/lib/Smarty/plugins/function.html_image.php @@ -0,0 +1,142 @@ + + * Name: html_image
      + * Date: Feb 24, 2003
      + * Purpose: format HTML tags for the image
      + * Input:
      + * - file = file (and path) of image (required) + * - height = image height (optional, default actual height) + * - width = image width (optional, default actual width) + * - basedir = base directory for absolute paths, default + * is environment variable DOCUMENT_ROOT + * - path_prefix = prefix for path output (optional, default empty) + * + * Examples: {html_image file="/images/masthead.gif"} + * Output: + * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt + * @author credits to Duda - wrote first image function + * in repository, helped with lots of functionality + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_image($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $alt = ''; + $file = ''; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $path_prefix = ''; + $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; + foreach($params as $_key => $_val) { + switch($_key) { + case 'file': + case 'height': + case 'width': + case 'dpi': + case 'path_prefix': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if(!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = ''; + $suffix = ''; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file,0,1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if(!isset($params['width']) || !isset($params['height'])) { + if(!$_image_data = @getimagesize($_image_path)) { + if(!file_exists($_image_path)) { + $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if(!is_readable($_image_path)) { + $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + if ($smarty->security && + ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && + (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && + (!smarty_core_is_secure($_params, $smarty)) ) { + $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); + } + + if(!isset($params['width'])) { + $width = $_image_data[0]; + } + if(!isset($params['height'])) { + $height = $_image_data[1]; + } + + } + + if(isset($params['dpi'])) { + if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + $_resize = $dpi_default/$params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . ''.$alt.'' . $suffix; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/function.html_options.php b/lib/Smarty/plugins/function.html_options.php new file mode 100644 index 0000000..cebadde --- /dev/null +++ b/lib/Smarty/plugins/function.html_options.php @@ -0,0 +1,122 @@ + + * Name: html_options
      + * Input:
      + * - name (optional) - string default "select" + * - values (required if no options supplied) - array + * - options (required if no values supplied) - associative array + * - selected (optional) - string default not set + * - output (required if not options supplied) - array + * Purpose: Prints the list of
      !is", $source, $match); + $_pre_blocks = $match[0]; + $source = preg_replace("!]*?>.*?
      !is", + '@@@SMARTY:TRIM:PRE@@@', $source); + + // Pull out the textarea blocks + preg_match_all("!]*?>.*?!is", $source, $match); + $_textarea_blocks = $match[0]; + $source = preg_replace("!]*?>.*?!is", + '@@@SMARTY:TRIM:TEXTAREA@@@', $source); + + // remove all leading spaces, tabs and carriage returns NOT + // preceeded by a php close tag. + $source = trim(preg_replace('/((?)\n)[\s]+/m', '\1', $source)); + + // replace textarea blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); + + // replace pre blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); + + // replace script blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); + + return $source; +} + +function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) { + $_len = strlen($search_str); + $_pos = 0; + for ($_i=0, $_count=count($replace); $_i<$_count; $_i++) + if (($_pos=strpos($subject, $search_str, $_pos))!==false) + $subject = substr_replace($subject, $replace[$_i], $_pos, $_len); + else + break; + +} + +?> diff --git a/lib/Smarty/plugins/shared.escape_special_chars.php b/lib/Smarty/plugins/shared.escape_special_chars.php new file mode 100644 index 0000000..c07ce31 --- /dev/null +++ b/lib/Smarty/plugins/shared.escape_special_chars.php @@ -0,0 +1,31 @@ + + * Purpose: used by other smarty functions to escape + * special chars except for already escaped ones + * @author Monte Ohrt + * @param string + * @return string + */ +function smarty_function_escape_special_chars($string) +{ + if(!is_array($string)) { + $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); + $string = htmlspecialchars($string); + $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string); + } + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/Smarty/plugins/shared.make_timestamp.php b/lib/Smarty/plugins/shared.make_timestamp.php new file mode 100644 index 0000000..b42eb11 --- /dev/null +++ b/lib/Smarty/plugins/shared.make_timestamp.php @@ -0,0 +1,46 @@ + + * Purpose: used by other smarty functions to make a timestamp + * from a string. + * @author Monte Ohrt + * @param string + * @return string + */ +function smarty_make_timestamp($string) +{ + if(empty($string)) { + // use "now": + $time = time(); + + } elseif (preg_match('/^\d{14}$/', $string)) { + // it is mysql timestamp format of YYYYMMDDHHMMSS? + $time = mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2), + substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4)); + + } elseif (is_numeric($string)) { + // it is a numeric string, we handle it as timestamp + $time = (int)$string; + + } else { + // strtotime should handle it + $time = strtotime($string); + if ($time == -1 || $time === false) { + // strtotime() was not able to parse $string, use "now": + $time = time(); + } + } + return $time; + +} + +/* vim: set expandtab: */ + +?> diff --git a/lib/StripTagsSmart/strip_tags_smart.php b/lib/StripTagsSmart/strip_tags_smart.php new file mode 100644 index 0000000..88ab101 --- /dev/null +++ b/lib/StripTagsSmart/strip_tags_smart.php @@ -0,0 +1,208 @@ + c" + * - корректно обрабатывается "грязный" html, когда в значениях атрибутов тагов могут встречаться символы < > + * - корректно обрабатывается разбитый html + * - вырезаются комментарии, скрипты, стили, PHP, Perl, ASP код, MS Word таги, CDATA + * - автоматически форматируется текст, если он содержит html код + * - защита от подделок типа: "<script>alert('hi')script>" + * + * @param string $s + * @param array $allowable_tags Массив тагов, которые не будут вырезаны + * Пример: 'b' -- таг останется с атрибутами, '' -- таг останется без атрибутов + * @param bool $is_format_spaces Форматировать пробелы и переносы строк? + * Вид текста на выходе (plain) максимально приближеется виду текста в браузере на входе. + * Другими словами, грамотно преобразует text/html в text/plain. + * Текст форматируется только в том случае, если были вырезаны какие-либо таги. + * @param array $pair_tags массив имён парных тагов, которые будут удалены вместе с содержимым + * см. значения по умолчанию + * @param array $para_tags массив имён парных тагов, которые будут восприниматься как параграфы (если $is_format_spaces = true) + * см. значения по умолчанию + * @return string + * + * @license http://creativecommons.org/licenses/by-sa/3.0/ + * @author Nasibullin Rinat, http://orangetie.ru/ + * @charset ANSI + * @version 4.0.14 + */ +function strip_tags_smart( + /*string*/ $s, + array $allowable_tags = null, + /*boolean*/ $is_format_spaces = true, + array $pair_tags = array('script', 'style', 'map', 'iframe', 'frameset', 'object', 'applet', 'comment', 'button', 'textarea', 'select'), + array $para_tags = array('p', 'td', 'th', 'li', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'form', 'title', 'pre') +) +{ + //return strip_tags($s); + static $_callback_type = false; + static $_allowable_tags = array(); + static $_para_tags = array(); + #regular expression for tag attributes + #correct processes dirty and broken HTML in a singlebyte or multibyte UTF-8 charset! + static $re_attrs_fast_safe = '(?![a-zA-Z\d]) #statement, which follows after a tag + #correct attributes + (?> + [^>"\']+ + | (?<=[\=\x20\r\n\t]|\xc2\xa0) "[^"]*" + | (?<=[\=\x20\r\n\t]|\xc2\xa0) \'[^\']*\' + )* + #incorrect attributes + [^>]*+'; + + if (is_array($s)) + { + if ($_callback_type === 'strip_tags') + { + $tag = strtolower($s[1]); + if ($_allowable_tags) + { + #tag with attributes + if (array_key_exists($tag, $_allowable_tags)) return $s[0]; + + #tag without attributes + if (array_key_exists('<' . $tag . '>', $_allowable_tags)) + { + if (substr($s[0], 0, 2) === ''; + if (substr($s[0], -2) === '/>') return '<' . $tag . ' />'; + return '<' . $tag . '>'; + } + } + if ($tag === 'br') return "\r\n"; + if ($_para_tags && array_key_exists($tag, $_para_tags)) return "\r\n\r\n"; + return ''; + } + trigger_error('Unknown callback type "' . $_callback_type . '"!', E_USER_ERROR); + } + + if (($pos = strpos($s, '<')) === false || strpos($s, '>', $pos) === false) #speed improve + { + #tags are not found + return $s; + } + + $length = strlen($s); + + #unpaired tags (opening, closing, !DOCTYPE, MS Word namespace) + $re_tags = '~ <[/!]?+ + ( + [a-zA-Z][a-zA-Z\d]*+ + (?>:[a-zA-Z][a-zA-Z\d]*+)? + ) #1 + ' . $re_attrs_fast_safe . ' + > + ~sxSX'; + + $patterns = array( + '/<([\?\%]) .*? \\1>/sxSX', #встроенный PHP, Perl, ASP код + '/<\!\[CDATA\[ .*? \]\]>/sxSX', #блоки CDATA + #'/<\!\[ [\x20\r\n\t]* [a-zA-Z] .*? \]>/sxSX', #:DEPRECATED: MS Word таги типа ... + + '/<\!--.*?-->/sSX', #комментарии + + #MS Word таги типа "...", + #условное выполнение кода для IE типа "" + #условное выполнение кода для IE типа " HTML " + #см. http://www.tigir.com/comments.htm + '/ <\! (?:--)?+ + \[ + (?> [^\]"\']+ | "[^"]*" | \'[^\']*\' )* + \] + (?:--)?+ + > + /sxSX', + ); + if ($pair_tags) + { + #парные таги вместе с содержимым: + foreach ($pair_tags as $k => $v) $pair_tags[$k] = preg_quote($v, '/'); + $patterns[] = '/ <((?i:' . implode('|', $pair_tags) . '))' . $re_attrs_fast_safe . '(? + .*? + <\/(?i:\\1)' . $re_attrs_fast_safe . '> + /sxSX'; + } + #d($patterns); + + $i = 0; #защита от зацикливания + $max = 99; + while ($i < $max) + { + $s2 = preg_replace($patterns, '', $s); + if (preg_last_error() !== PREG_NO_ERROR) + { + $i = 999; + break; + } + + if ($i == 0) + { + $is_html = ($s2 != $s || preg_match($re_tags, $s2)); + if (preg_last_error() !== PREG_NO_ERROR) + { + $i = 999; + break; + } + if ($is_html) + { + if ($is_format_spaces) + { + /* + В библиотеке PCRE для PHP \s - это любой пробельный символ, а именно класс символов [\x09\x0a\x0c\x0d\x20\xa0] или, по другому, [\t\n\f\r \xa0] + Если \s используется с модификатором /u, то \s трактуется как [\x09\x0a\x0c\x0d\x20] + Браузер не делает различия между пробельными символами, друг за другом подряд идущие символы воспринимаются как один + */ + #$s2 = str_replace(array("\r", "\n", "\t"), ' ', $s2); + #$s2 = strtr($s2, "\x09\x0a\x0c\x0d", ' '); + $s2 = preg_replace('/ [\x09\x0a\x0c\x0d]++ + | <((?i:pre|textarea))' . $re_attrs_fast_safe . '(? + .+? + <\/(?i:\\1)' . $re_attrs_fast_safe . '> + \K + /sxSX', ' ', $s2); + if (preg_last_error() !== PREG_NO_ERROR) + { + $i = 999; + break; + } + } + + #массив тагов, которые не будут вырезаны + if ($allowable_tags) $_allowable_tags = array_flip($allowable_tags); + + #парные таги, которые будут восприниматься как параграфы + if ($para_tags) $_para_tags = array_flip($para_tags); + } + }#if + + #tags processing + if ($is_html) + { + $_callback_type = 'strip_tags'; + $s2 = preg_replace_callback($re_tags, __FUNCTION__, $s2); + $_callback_type = false; + if (preg_last_error() !== PREG_NO_ERROR) + { + $i = 999; + break; + } + } + + if ($s === $s2) break; + $s = $s2; $i++; + }#while + if ($i >= $max) $s = strip_tags($s); #too many cycles for replace... + + if ($is_format_spaces && strlen($s) !== $length) + { + #remove a duplicate spaces + $s = preg_replace('/\x20\x20++/sSX', ' ', trim($s)); + #remove a spaces before and after new lines + $s = str_replace(array("\r\n\x20", "\x20\r\n"), "\r\n", $s); + #replace 3 and more new lines to 2 new lines + $s = preg_replace('/[\r\n]{3,}+/sSX', "\r\n\r\n", $s); + } + return $s; +} +?> \ No newline at end of file diff --git a/lib/SwiftMailer/classes/Swift.php b/lib/SwiftMailer/classes/Swift.php new file mode 100644 index 0000000..82c381b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift.php @@ -0,0 +1,80 @@ +createDependenciesFor('mime.attachment') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new Attachment. + * + * @param string|Swift_OutputByteStream $data + * @param string $filename + * @param string $contentType + * + * @return Swift_Mime_Attachment + */ + public static function newInstance($data = null, $filename = null, $contentType = null) + { + return new self($data, $filename, $contentType); + } + + /** + * Create a new Attachment from a filesystem path. + * + * @param string $path + * @param string $contentType optional + * + * @return Swift_Mime_Attachment + */ + public static function fromPath($path, $contentType = null) + { + return self::newInstance()->setFile( + new Swift_ByteStream_FileByteStream($path), + $contentType + ); + } +} diff --git a/lib/SwiftMailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/lib/SwiftMailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php new file mode 100644 index 0000000..a7b0e3a --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php @@ -0,0 +1,181 @@ +_filters[$key] = $filter; + } + + /** + * Remove an already present StreamFilter based on its $key. + * + * @param string $key + */ + public function removeFilter($key) + { + unset($this->_filters[$key]); + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + * + * @throws Swift_IoException + * + * @return int + */ + public function write($bytes) + { + $this->_writeBuffer .= $bytes; + foreach ($this->_filters as $filter) { + if ($filter->shouldBuffer($this->_writeBuffer)) { + return; + } + } + $this->_doWrite($this->_writeBuffer); + + return ++$this->_sequence; + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + */ + public function commit() + { + $this->_doWrite($this->_writeBuffer); + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + if ($this->_writeBuffer !== '') { + $stream->write($this->_writeBuffer); + } + unset($this->_mirrors[$k]); + } + } + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + */ + public function flushBuffers() + { + if ($this->_writeBuffer !== '') { + $this->_doWrite($this->_writeBuffer); + } + $this->_flush(); + + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } + + /** Run $bytes through all filters */ + private function _filter($bytes) + { + foreach ($this->_filters as $filter) { + $bytes = $filter->filter($bytes); + } + + return $bytes; + } + + /** Just write the bytes to the stream */ + private function _doWrite($bytes) + { + $this->_commit($this->_filter($bytes)); + + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + + $this->_writeBuffer = ''; + } +} diff --git a/lib/SwiftMailer/classes/Swift/ByteStream/ArrayByteStream.php b/lib/SwiftMailer/classes/Swift/ByteStream/ArrayByteStream.php new file mode 100644 index 0000000..ef05a6d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/ByteStream/ArrayByteStream.php @@ -0,0 +1,182 @@ +_array = $stack; + $this->_arraySize = count($stack); + } elseif (is_string($stack)) { + $this->write($stack); + } else { + $this->_array = array(); + } + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the + * remaining bytes are given instead. If no bytes are remaining at all, boolean + * false is returned. + * + * @param int $length + * + * @return string + */ + public function read($length) + { + if ($this->_offset == $this->_arraySize) { + return false; + } + + // Don't use array slice + $end = $length + $this->_offset; + $end = $this->_arraySize < $end ? $this->_arraySize : $end; + $ret = ''; + for (; $this->_offset < $end; ++$this->_offset) { + $ret .= $this->_array[$this->_offset]; + } + + return $ret; + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + */ + public function write($bytes) + { + $to_add = str_split($bytes); + foreach ($to_add as $value) { + $this->_array[] = $value; + } + $this->_arraySize = count($this->_array); + + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + unset($this->_mirrors[$k]); + } + } + } + + /** + * Move the internal read pointer to $byteOffset in the stream. + * + * @param int $byteOffset + * + * @return bool + */ + public function setReadPointer($byteOffset) + { + if ($byteOffset > $this->_arraySize) { + $byteOffset = $this->_arraySize; + } elseif ($byteOffset < 0) { + $byteOffset = 0; + } + + $this->_offset = $byteOffset; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + */ + public function flushBuffers() + { + $this->_offset = 0; + $this->_array = array(); + $this->_arraySize = 0; + + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/ByteStream/FileByteStream.php b/lib/SwiftMailer/classes/Swift/ByteStream/FileByteStream.php new file mode 100644 index 0000000..9ed8523 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/ByteStream/FileByteStream.php @@ -0,0 +1,231 @@ +_path = $path; + $this->_mode = $writable ? 'w+b' : 'rb'; + + if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { + $this->_quotes = true; + } + } + + /** + * Get the complete path to the file. + * + * @return string + */ + public function getPath() + { + return $this->_path; + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the + * remaining bytes are given instead. If no bytes are remaining at all, boolean + * false is returned. + * + * @param int $length + * + * @throws Swift_IoException + * + * @return string|bool + */ + public function read($length) + { + $fp = $this->_getReadHandle(); + if (!feof($fp)) { + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + $bytes = fread($fp, $length); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_offset = ftell($fp); + + // If we read one byte after reaching the end of the file + // feof() will return false and an empty string is returned + if ($bytes === '' && feof($fp)) { + $this->_resetReadHandle(); + + return false; + } + + return $bytes; + } + + $this->_resetReadHandle(); + + return false; + } + + /** + * Move the internal read pointer to $byteOffset in the stream. + * + * @param int $byteOffset + * + * @return bool + */ + public function setReadPointer($byteOffset) + { + if (isset($this->_reader)) { + $this->_seekReadStreamToPosition($byteOffset); + } + $this->_offset = $byteOffset; + } + + /** Just write the bytes to the file */ + protected function _commit($bytes) + { + fwrite($this->_getWriteHandle(), $bytes); + $this->_resetReadHandle(); + } + + /** Not used */ + protected function _flush() + { + } + + /** Get the resource for reading */ + private function _getReadHandle() + { + if (!isset($this->_reader)) { + $pointer = @fopen($this->_path, 'rb'); + if (!$pointer) { + throw new Swift_IoException( + 'Unable to open file for reading ['.$this->_path.']' + ); + } + $this->_reader = $pointer; + if ($this->_offset != 0) { + $this->_getReadStreamSeekableStatus(); + $this->_seekReadStreamToPosition($this->_offset); + } + } + + return $this->_reader; + } + + /** Get the resource for writing */ + private function _getWriteHandle() + { + if (!isset($this->_writer)) { + if (!$this->_writer = fopen($this->_path, $this->_mode)) { + throw new Swift_IoException( + 'Unable to open file for writing ['.$this->_path.']' + ); + } + } + + return $this->_writer; + } + + /** Force a reload of the resource for reading */ + private function _resetReadHandle() + { + if (isset($this->_reader)) { + fclose($this->_reader); + $this->_reader = null; + } + } + + /** Check if ReadOnly Stream is seekable */ + private function _getReadStreamSeekableStatus() + { + $metas = stream_get_meta_data($this->_reader); + $this->_seekable = $metas['seekable']; + } + + /** Streams in a readOnly stream ensuring copy if needed */ + private function _seekReadStreamToPosition($offset) + { + if ($this->_seekable === null) { + $this->_getReadStreamSeekableStatus(); + } + if ($this->_seekable === false) { + $currentPos = ftell($this->_reader); + if ($currentPos < $offset) { + $toDiscard = $offset - $currentPos; + fread($this->_reader, $toDiscard); + + return; + } + $this->_copyReadStream(); + } + fseek($this->_reader, $offset, SEEK_SET); + } + + /** Copy a readOnly Stream to ensure seekability */ + private function _copyReadStream() + { + if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) { + /* We have opened a php:// Stream Should work without problem */ + } elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) { + /* We have opened a tmpfile */ + } else { + throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available'); + } + $currentPos = ftell($this->_reader); + fclose($this->_reader); + $source = fopen($this->_path, 'rb'); + if (!$source) { + throw new Swift_IoException('Unable to open file for copying ['.$this->_path.']'); + } + fseek($tmpFile, 0, SEEK_SET); + while (!feof($source)) { + fwrite($tmpFile, fread($source, 4096)); + } + fseek($tmpFile, $currentPos, SEEK_SET); + fclose($source); + $this->_reader = $tmpFile; + } +} diff --git a/lib/SwiftMailer/classes/Swift/ByteStream/TemporaryFileByteStream.php b/lib/SwiftMailer/classes/Swift/ByteStream/TemporaryFileByteStream.php new file mode 100644 index 0000000..1c9a80c --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/ByteStream/TemporaryFileByteStream.php @@ -0,0 +1,42 @@ +getPath())) === false) { + throw new Swift_IoException('Failed to get temporary file content.'); + } + + return $content; + } + + public function __destruct() + { + if (file_exists($this->getPath())) { + @unlink($this->getPath()); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterReader.php b/lib/SwiftMailer/classes/Swift/CharacterReader.php new file mode 100644 index 0000000..3d5e854 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterReader.php @@ -0,0 +1,67 @@ + + */ +interface Swift_CharacterReader +{ + const MAP_TYPE_INVALID = 0x01; + const MAP_TYPE_FIXED_LEN = 0x02; + const MAP_TYPE_POSITIONS = 0x03; + + /** + * Returns the complete character map. + * + * @param string $string + * @param int $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return int + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars); + + /** + * Returns the mapType, see constants. + * + * @return int + */ + public function getMapType(); + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param integer[] $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size); + + /** + * Returns the number of bytes which should be read to start each character. + * + * For fixed width character sets this should be the number of octets-per-character. + * For multibyte character sets this will probably be 1. + * + * @return int + */ + public function getInitialByteSize(); +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/lib/SwiftMailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php new file mode 100644 index 0000000..6a18e1d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php @@ -0,0 +1,97 @@ + + */ +class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader +{ + /** + * The number of bytes in a single character. + * + * @var int + */ + private $_width; + + /** + * Creates a new GenericFixedWidthReader using $width bytes per character. + * + * @param int $width + */ + public function __construct($width) + { + $this->_width = $width; + } + + /** + * Returns the complete character map. + * + * @param string $string + * @param int $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return int + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) + { + $strlen = strlen($string); + // % and / are CPU intensive, so, maybe find a better way + $ignored = $strlen % $this->_width; + $ignoredChars = $ignored ? substr($string, -$ignored) : ''; + $currentMap = $this->_width; + + return ($strlen - $ignored) / $this->_width; + } + + /** + * Returns the mapType. + * + * @return int + */ + public function getMapType() + { + return self::MAP_TYPE_FIXED_LEN; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size) + { + $needed = $this->_width - $size; + + return $needed > -1 ? $needed : -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return int + */ + public function getInitialByteSize() + { + return $this->_width; + } +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterReader/UsAsciiReader.php b/lib/SwiftMailer/classes/Swift/CharacterReader/UsAsciiReader.php new file mode 100644 index 0000000..67da48f --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterReader/UsAsciiReader.php @@ -0,0 +1,84 @@ + "\x07F") { + // Invalid char + $currentMap[$i + $startOffset] = $string[$i]; + } + } + + return $strlen; + } + + /** + * Returns mapType. + * + * @return int mapType + */ + public function getMapType() + { + return self::MAP_TYPE_INVALID; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size) + { + $byte = reset($bytes); + if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) { + return 0; + } + + return -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return int + */ + public function getInitialByteSize() + { + return 1; + } +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterReader/Utf8Reader.php b/lib/SwiftMailer/classes/Swift/CharacterReader/Utf8Reader.php new file mode 100644 index 0000000..7379bda --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterReader/Utf8Reader.php @@ -0,0 +1,176 @@ + + */ +class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader +{ + /** Pre-computed for optimization */ + private static $length_map = array( + // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x0N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x2N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x4N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x6N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7N + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x8N + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9N + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xAN + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBN + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xCN + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDN + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEN + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0, // 0xFN + ); + + private static $s_length_map = array( + "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, + "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, + "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, + "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, + "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, + "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, + "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, + "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, + "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, + "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, + "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, + "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, + "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, + "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, + "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, + "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, + "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, + "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, + "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, + "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, + "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, + "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, + "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, + "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, + "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, + "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, + "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, + "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, + "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, + "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, + "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, + "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, + ); + + /** + * Returns the complete character map. + * + * @param string $string + * @param int $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return int + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) + { + if (!isset($currentMap['i']) || !isset($currentMap['p'])) { + $currentMap['p'] = $currentMap['i'] = array(); + } + + $strlen = strlen($string); + $charPos = count($currentMap['p']); + $foundChars = 0; + $invalid = false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::$s_length_map[$char]; + if ($size == 0) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } else { + if ($invalid == true) { + /* We mark the chars as invalid and start a new char */ + $currentMap['p'][$charPos + $foundChars] = $startOffset + $i; + $currentMap['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + } + + return $foundChars; + } + + /** + * Returns mapType. + * + * @return int mapType + */ + public function getMapType() + { + return self::MAP_TYPE_POSITIONS; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param int $size + * + * @return int + */ + public function validateByteSequence($bytes, $size) + { + if ($size < 1) { + return -1; + } + $needed = self::$length_map[$bytes[0]] - $size; + + return $needed > -1 ? $needed : -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return int + */ + public function getInitialByteSize() + { + return 1; + } +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterReaderFactory.php b/lib/SwiftMailer/classes/Swift/CharacterReaderFactory.php new file mode 100644 index 0000000..15b6c69 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterReaderFactory.php @@ -0,0 +1,26 @@ +init(); + } + + public function __wakeup() + { + $this->init(); + } + + public function init() + { + if (count(self::$_map) > 0) { + return; + } + + $prefix = 'Swift_CharacterReader_'; + + $singleByte = array( + 'class' => $prefix.'GenericFixedWidthReader', + 'constructor' => array(1), + ); + + $doubleByte = array( + 'class' => $prefix.'GenericFixedWidthReader', + 'constructor' => array(2), + ); + + $fourBytes = array( + 'class' => $prefix.'GenericFixedWidthReader', + 'constructor' => array(4), + ); + + // Utf-8 + self::$_map['utf-?8'] = array( + 'class' => $prefix.'Utf8Reader', + 'constructor' => array(), + ); + + //7-8 bit charsets + self::$_map['(us-)?ascii'] = $singleByte; + self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte; + self::$_map['windows-?125[0-9]'] = $singleByte; + self::$_map['cp-?[0-9]+'] = $singleByte; + self::$_map['ansi'] = $singleByte; + self::$_map['macintosh'] = $singleByte; + self::$_map['koi-?7'] = $singleByte; + self::$_map['koi-?8-?.+'] = $singleByte; + self::$_map['mik'] = $singleByte; + self::$_map['(cork|t1)'] = $singleByte; + self::$_map['v?iscii'] = $singleByte; + + //16 bits + self::$_map['(ucs-?2|utf-?16)'] = $doubleByte; + + //32 bits + self::$_map['(ucs-?4|utf-?32)'] = $fourBytes; + + // Fallback + self::$_map['.*'] = $singleByte; + } + + /** + * Returns a CharacterReader suitable for the charset applied. + * + * @param string $charset + * + * @return Swift_CharacterReader + */ + public function getReaderFor($charset) + { + $charset = trim(strtolower($charset)); + foreach (self::$_map as $pattern => $spec) { + $re = '/^'.$pattern.'$/D'; + if (preg_match($re, $charset)) { + if (!array_key_exists($pattern, self::$_loaded)) { + $reflector = new ReflectionClass($spec['class']); + if ($reflector->getConstructor()) { + $reader = $reflector->newInstanceArgs($spec['constructor']); + } else { + $reader = $reflector->newInstance(); + } + self::$_loaded[$pattern] = $reader; + } + + return self::$_loaded[$pattern]; + } + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterStream.php b/lib/SwiftMailer/classes/Swift/CharacterStream.php new file mode 100644 index 0000000..717924f --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterStream.php @@ -0,0 +1,89 @@ +setCharacterReaderFactory($factory); + $this->setCharacterSet($charset); + } + + /** + * Set the character set used in this CharacterStream. + * + * @param string $charset + */ + public function setCharacterSet($charset) + { + $this->_charset = $charset; + $this->_charReader = null; + } + + /** + * Set the CharacterReaderFactory for multi charset support. + * + * @param Swift_CharacterReaderFactory $factory + */ + public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) + { + $this->_charReaderFactory = $factory; + } + + /** + * Overwrite this character stream using the byte sequence in the byte stream. + * + * @param Swift_OutputByteStream $os output stream to read from + */ + public function importByteStream(Swift_OutputByteStream $os) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory + ->getReaderFor($this->_charset); + } + + $startLength = $this->_charReader->getInitialByteSize(); + while (false !== $bytes = $os->read($startLength)) { + $c = array(); + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $c[] = self::$_byteMap[$bytes[$i]]; + } + $size = count($c); + $need = $this->_charReader + ->validateByteSequence($c, $size); + if ($need > 0 && + false !== $bytes = $os->read($need)) { + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $c[] = self::$_byteMap[$bytes[$i]]; + } + } + $this->_array[] = $c; + ++$this->_array_size; + } + } + + /** + * Import a string a bytes into this CharacterStream, overwriting any existing + * data in the stream. + * + * @param string $string + */ + public function importString($string) + { + $this->flushContents(); + $this->write($string); + } + + /** + * Read $length characters from the stream and move the internal pointer + * $length further into the stream. + * + * @param int $length + * + * @return string + */ + public function read($length) + { + if ($this->_offset == $this->_array_size) { + return false; + } + + // Don't use array slice + $arrays = array(); + $end = $length + $this->_offset; + for ($i = $this->_offset; $i < $end; ++$i) { + if (!isset($this->_array[$i])) { + break; + } + $arrays[] = $this->_array[$i]; + } + $this->_offset += $i - $this->_offset; // Limit function calls + $chars = false; + foreach ($arrays as $array) { + $chars .= implode('', array_map('chr', $array)); + } + + return $chars; + } + + /** + * Read $length characters from the stream and return a 1-dimensional array + * containing there octet values. + * + * @param int $length + * + * @return integer[] + */ + public function readBytes($length) + { + if ($this->_offset == $this->_array_size) { + return false; + } + $arrays = array(); + $end = $length + $this->_offset; + for ($i = $this->_offset; $i < $end; ++$i) { + if (!isset($this->_array[$i])) { + break; + } + $arrays[] = $this->_array[$i]; + } + $this->_offset += ($i - $this->_offset); // Limit function calls + + return call_user_func_array('array_merge', $arrays); + } + + /** + * Write $chars to the end of the stream. + * + * @param string $chars + */ + public function write($chars) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory->getReaderFor( + $this->_charset); + } + + $startLength = $this->_charReader->getInitialByteSize(); + + $fp = fopen('php://memory', 'w+b'); + fwrite($fp, $chars); + unset($chars); + fseek($fp, 0, SEEK_SET); + + $buffer = array(0); + $buf_pos = 1; + $buf_len = 1; + $has_datas = true; + do { + $bytes = array(); + // Buffer Filing + if ($buf_len - $buf_pos < $startLength) { + $buf = array_splice($buffer, $buf_pos); + $new = $this->_reloadBuffer($fp, 100); + if ($new) { + $buffer = array_merge($buf, $new); + $buf_len = count($buffer); + $buf_pos = 0; + } else { + $has_datas = false; + } + } + if ($buf_len - $buf_pos > 0) { + $size = 0; + for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) { + ++$size; + $bytes[] = $buffer[$buf_pos++]; + } + $need = $this->_charReader->validateByteSequence( + $bytes, $size); + if ($need > 0) { + if ($buf_len - $buf_pos < $need) { + $new = $this->_reloadBuffer($fp, $need); + + if ($new) { + $buffer = array_merge($buffer, $new); + $buf_len = count($buffer); + } + } + for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) { + $bytes[] = $buffer[$buf_pos++]; + } + } + $this->_array[] = $bytes; + ++$this->_array_size; + } + } while ($has_datas); + + fclose($fp); + } + + /** + * Move the internal pointer to $charOffset in the stream. + * + * @param int $charOffset + */ + public function setPointer($charOffset) + { + if ($charOffset > $this->_array_size) { + $charOffset = $this->_array_size; + } elseif ($charOffset < 0) { + $charOffset = 0; + } + $this->_offset = $charOffset; + } + + /** + * Empty the stream and reset the internal pointer. + */ + public function flushContents() + { + $this->_offset = 0; + $this->_array = array(); + $this->_array_size = 0; + } + + private function _reloadBuffer($fp, $len) + { + if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) { + $buf = array(); + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $buf[] = self::$_byteMap[$bytes[$i]]; + } + + return $buf; + } + + return false; + } + + private static function _initializeMaps() + { + if (!isset(self::$_charMap)) { + self::$_charMap = array(); + for ($byte = 0; $byte < 256; ++$byte) { + self::$_charMap[$byte] = chr($byte); + } + self::$_byteMap = array_flip(self::$_charMap); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/CharacterStream/NgCharacterStream.php b/lib/SwiftMailer/classes/Swift/CharacterStream/NgCharacterStream.php new file mode 100644 index 0000000..58bd140 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/CharacterStream/NgCharacterStream.php @@ -0,0 +1,267 @@ + + */ +class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream +{ + /** + * The char reader (lazy-loaded) for the current charset. + * + * @var Swift_CharacterReader + */ + private $_charReader; + + /** + * A factory for creating CharacterReader instances. + * + * @var Swift_CharacterReaderFactory + */ + private $_charReaderFactory; + + /** + * The character set this stream is using. + * + * @var string + */ + private $_charset; + + /** + * The data's stored as-is. + * + * @var string + */ + private $_datas = ''; + + /** + * Number of bytes in the stream. + * + * @var int + */ + private $_datasSize = 0; + + /** + * Map. + * + * @var mixed + */ + private $_map; + + /** + * Map Type. + * + * @var int + */ + private $_mapType = 0; + + /** + * Number of characters in the stream. + * + * @var int + */ + private $_charCount = 0; + + /** + * Position in the stream. + * + * @var int + */ + private $_currentPos = 0; + + /** + * Constructor. + * + * @param Swift_CharacterReaderFactory $factory + * @param string $charset + */ + public function __construct(Swift_CharacterReaderFactory $factory, $charset) + { + $this->setCharacterReaderFactory($factory); + $this->setCharacterSet($charset); + } + + /* -- Changing parameters of the stream -- */ + + /** + * Set the character set used in this CharacterStream. + * + * @param string $charset + */ + public function setCharacterSet($charset) + { + $this->_charset = $charset; + $this->_charReader = null; + $this->_mapType = 0; + } + + /** + * Set the CharacterReaderFactory for multi charset support. + * + * @param Swift_CharacterReaderFactory $factory + */ + public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) + { + $this->_charReaderFactory = $factory; + } + + /** + * @see Swift_CharacterStream::flushContents() + */ + public function flushContents() + { + $this->_datas = null; + $this->_map = null; + $this->_charCount = 0; + $this->_currentPos = 0; + $this->_datasSize = 0; + } + + /** + * @see Swift_CharacterStream::importByteStream() + * + * @param Swift_OutputByteStream $os + */ + public function importByteStream(Swift_OutputByteStream $os) + { + $this->flushContents(); + $blocks = 512; + $os->setReadPointer(0); + while (false !== ($read = $os->read($blocks))) { + $this->write($read); + } + } + + /** + * @see Swift_CharacterStream::importString() + * + * @param string $string + */ + public function importString($string) + { + $this->flushContents(); + $this->write($string); + } + + /** + * @see Swift_CharacterStream::read() + * + * @param int $length + * + * @return string + */ + public function read($length) + { + if ($this->_currentPos >= $this->_charCount) { + return false; + } + $ret = false; + $length = $this->_currentPos + $length > $this->_charCount ? $this->_charCount - $this->_currentPos : $length; + switch ($this->_mapType) { + case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: + $len = $length * $this->_map; + $ret = substr($this->_datas, + $this->_currentPos * $this->_map, + $len); + $this->_currentPos += $length; + break; + + case Swift_CharacterReader::MAP_TYPE_INVALID: + $ret = ''; + for (; $this->_currentPos < $length; ++$this->_currentPos) { + if (isset($this->_map[$this->_currentPos])) { + $ret .= '?'; + } else { + $ret .= $this->_datas[$this->_currentPos]; + } + } + break; + + case Swift_CharacterReader::MAP_TYPE_POSITIONS: + $end = $this->_currentPos + $length; + $end = $end > $this->_charCount ? $this->_charCount : $end; + $ret = ''; + $start = 0; + if ($this->_currentPos > 0) { + $start = $this->_map['p'][$this->_currentPos - 1]; + } + $to = $start; + for (; $this->_currentPos < $end; ++$this->_currentPos) { + if (isset($this->_map['i'][$this->_currentPos])) { + $ret .= substr($this->_datas, $start, $to - $start).'?'; + $start = $this->_map['p'][$this->_currentPos]; + } else { + $to = $this->_map['p'][$this->_currentPos]; + } + } + $ret .= substr($this->_datas, $start, $to - $start); + break; + } + + return $ret; + } + + /** + * @see Swift_CharacterStream::readBytes() + * + * @param int $length + * + * @return int[] + */ + public function readBytes($length) + { + $read = $this->read($length); + if ($read !== false) { + $ret = array_map('ord', str_split($read, 1)); + + return $ret; + } + + return false; + } + + /** + * @see Swift_CharacterStream::setPointer() + * + * @param int $charOffset + */ + public function setPointer($charOffset) + { + if ($this->_charCount < $charOffset) { + $charOffset = $this->_charCount; + } + $this->_currentPos = $charOffset; + } + + /** + * @see Swift_CharacterStream::write() + * + * @param string $chars + */ + public function write($chars) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory->getReaderFor( + $this->_charset); + $this->_map = array(); + $this->_mapType = $this->_charReader->getMapType(); + } + $ignored = ''; + $this->_datas .= $chars; + $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored); + if ($ignored !== false) { + $this->_datasSize = strlen($this->_datas) - strlen($ignored); + } else { + $this->_datasSize = strlen($this->_datas); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/ConfigurableSpool.php b/lib/SwiftMailer/classes/Swift/ConfigurableSpool.php new file mode 100644 index 0000000..4ae5bac --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/ConfigurableSpool.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Base class for Spools (implements time and message limits). + * + * @author Fabien Potencier + */ +abstract class Swift_ConfigurableSpool implements Swift_Spool +{ + /** The maximum number of messages to send per flush */ + private $_message_limit; + + /** The time limit per flush */ + private $_time_limit; + + /** + * Sets the maximum number of messages to send per flush. + * + * @param int $limit + */ + public function setMessageLimit($limit) + { + $this->_message_limit = (int) $limit; + } + + /** + * Gets the maximum number of messages to send per flush. + * + * @return int The limit + */ + public function getMessageLimit() + { + return $this->_message_limit; + } + + /** + * Sets the time limit (in seconds) per flush. + * + * @param int $limit The limit + */ + public function setTimeLimit($limit) + { + $this->_time_limit = (int) $limit; + } + + /** + * Gets the time limit (in seconds) per flush. + * + * @return int The limit + */ + public function getTimeLimit() + { + return $this->_time_limit; + } +} diff --git a/lib/SwiftMailer/classes/Swift/DependencyContainer.php b/lib/SwiftMailer/classes/Swift/DependencyContainer.php new file mode 100644 index 0000000..8c1074a --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/DependencyContainer.php @@ -0,0 +1,373 @@ +_store); + } + + /** + * Test if an item is registered in this container with the given name. + * + * @see register() + * + * @param string $itemName + * + * @return bool + */ + public function has($itemName) + { + return array_key_exists($itemName, $this->_store) + && isset($this->_store[$itemName]['lookupType']); + } + + /** + * Lookup the item with the given $itemName. + * + * @see register() + * + * @param string $itemName + * + * @throws Swift_DependencyException If the dependency is not found + * + * @return mixed + */ + public function lookup($itemName) + { + if (!$this->has($itemName)) { + throw new Swift_DependencyException( + 'Cannot lookup dependency "'.$itemName.'" since it is not registered.' + ); + } + + switch ($this->_store[$itemName]['lookupType']) { + case self::TYPE_ALIAS: + return $this->_createAlias($itemName); + case self::TYPE_VALUE: + return $this->_getValue($itemName); + case self::TYPE_INSTANCE: + return $this->_createNewInstance($itemName); + case self::TYPE_SHARED: + return $this->_createSharedInstance($itemName); + } + } + + /** + * Create an array of arguments passed to the constructor of $itemName. + * + * @param string $itemName + * + * @return array + */ + public function createDependenciesFor($itemName) + { + $args = array(); + if (isset($this->_store[$itemName]['args'])) { + $args = $this->_resolveArgs($this->_store[$itemName]['args']); + } + + return $args; + } + + /** + * Register a new dependency with $itemName. + * + * This method returns the current DependencyContainer instance because it + * requires the use of the fluid interface to set the specific details for the + * dependency. + * + * @see asNewInstanceOf(), asSharedInstanceOf(), asValue() + * + * @param string $itemName + * + * @return Swift_DependencyContainer + */ + public function register($itemName) + { + $this->_store[$itemName] = array(); + $this->_endPoint = &$this->_store[$itemName]; + + return $this; + } + + /** + * Specify the previously registered item as a literal value. + * + * {@link register()} must be called before this will work. + * + * @param mixed $value + * + * @return Swift_DependencyContainer + */ + public function asValue($value) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_VALUE; + $endPoint['value'] = $value; + + return $this; + } + + /** + * Specify the previously registered item as an alias of another item. + * + * @param string $lookup + * + * @return Swift_DependencyContainer + */ + public function asAliasOf($lookup) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_ALIAS; + $endPoint['ref'] = $lookup; + + return $this; + } + + /** + * Specify the previously registered item as a new instance of $className. + * + * {@link register()} must be called before this will work. + * Any arguments can be set with {@link withDependencies()}, + * {@link addConstructorValue()} or {@link addConstructorLookup()}. + * + * @see withDependencies(), addConstructorValue(), addConstructorLookup() + * + * @param string $className + * + * @return Swift_DependencyContainer + */ + public function asNewInstanceOf($className) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_INSTANCE; + $endPoint['className'] = $className; + + return $this; + } + + /** + * Specify the previously registered item as a shared instance of $className. + * + * {@link register()} must be called before this will work. + * + * @param string $className + * + * @return Swift_DependencyContainer + */ + public function asSharedInstanceOf($className) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_SHARED; + $endPoint['className'] = $className; + + return $this; + } + + /** + * Specify a list of injected dependencies for the previously registered item. + * + * This method takes an array of lookup names. + * + * @see addConstructorValue(), addConstructorLookup() + * + * @param array $lookups + * + * @return Swift_DependencyContainer + */ + public function withDependencies(array $lookups) + { + $endPoint = &$this->_getEndPoint(); + $endPoint['args'] = array(); + foreach ($lookups as $lookup) { + $this->addConstructorLookup($lookup); + } + + return $this; + } + + /** + * Specify a literal (non looked up) value for the constructor of the + * previously registered item. + * + * @see withDependencies(), addConstructorLookup() + * + * @param mixed $value + * + * @return Swift_DependencyContainer + */ + public function addConstructorValue($value) + { + $endPoint = &$this->_getEndPoint(); + if (!isset($endPoint['args'])) { + $endPoint['args'] = array(); + } + $endPoint['args'][] = array('type' => 'value', 'item' => $value); + + return $this; + } + + /** + * Specify a dependency lookup for the constructor of the previously + * registered item. + * + * @see withDependencies(), addConstructorValue() + * + * @param string $lookup + * + * @return Swift_DependencyContainer + */ + public function addConstructorLookup($lookup) + { + $endPoint = &$this->_getEndPoint(); + if (!isset($this->_endPoint['args'])) { + $endPoint['args'] = array(); + } + $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup); + + return $this; + } + + /** Get the literal value with $itemName */ + private function _getValue($itemName) + { + return $this->_store[$itemName]['value']; + } + + /** Resolve an alias to another item */ + private function _createAlias($itemName) + { + return $this->lookup($this->_store[$itemName]['ref']); + } + + /** Create a fresh instance of $itemName */ + private function _createNewInstance($itemName) + { + $reflector = new ReflectionClass($this->_store[$itemName]['className']); + if ($reflector->getConstructor()) { + return $reflector->newInstanceArgs( + $this->createDependenciesFor($itemName) + ); + } + + return $reflector->newInstance(); + } + + /** Create and register a shared instance of $itemName */ + private function _createSharedInstance($itemName) + { + if (!isset($this->_store[$itemName]['instance'])) { + $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName); + } + + return $this->_store[$itemName]['instance']; + } + + /** Get the current endpoint in the store */ + private function &_getEndPoint() + { + if (!isset($this->_endPoint)) { + throw new BadMethodCallException( + 'Component must first be registered by calling register()' + ); + } + + return $this->_endPoint; + } + + /** Get an argument list with dependencies resolved */ + private function _resolveArgs(array $args) + { + $resolved = array(); + foreach ($args as $argDefinition) { + switch ($argDefinition['type']) { + case 'lookup': + $resolved[] = $this->_lookupRecursive($argDefinition['item']); + break; + case 'value': + $resolved[] = $argDefinition['item']; + break; + } + } + + return $resolved; + } + + /** Resolve a single dependency with an collections */ + private function _lookupRecursive($item) + { + if (is_array($item)) { + $collection = array(); + foreach ($item as $k => $v) { + $collection[$k] = $this->_lookupRecursive($v); + } + + return $collection; + } + + return $this->lookup($item); + } +} diff --git a/lib/SwiftMailer/classes/Swift/DependencyException.php b/lib/SwiftMailer/classes/Swift/DependencyException.php new file mode 100644 index 0000000..799d38d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/DependencyException.php @@ -0,0 +1,27 @@ +createDependenciesFor('mime.embeddedfile') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new EmbeddedFile. + * + * @param string|Swift_OutputByteStream $data + * @param string $filename + * @param string $contentType + * + * @return Swift_Mime_EmbeddedFile + */ + public static function newInstance($data = null, $filename = null, $contentType = null) + { + return new self($data, $filename, $contentType); + } + + /** + * Create a new EmbeddedFile from a filesystem path. + * + * @param string $path + * + * @return Swift_Mime_EmbeddedFile + */ + public static function fromPath($path) + { + return self::newInstance()->setFile( + new Swift_ByteStream_FileByteStream($path) + ); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Encoder.php b/lib/SwiftMailer/classes/Swift/Encoder.php new file mode 100644 index 0000000..2073abc --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Encoder.php @@ -0,0 +1,28 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + + if (0 != $firstLineOffset) { + $firstLine = substr( + $encodedString, 0, $maxLineLength - $firstLineOffset + )."\r\n"; + $encodedString = substr( + $encodedString, $maxLineLength - $firstLineOffset + ); + } + + return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } + + /** + * Does nothing. + */ + public function charsetChanged($charset) + { + } +} diff --git a/lib/SwiftMailer/classes/Swift/Encoder/QpEncoder.php b/lib/SwiftMailer/classes/Swift/Encoder/QpEncoder.php new file mode 100644 index 0000000..8a81fe3 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Encoder/QpEncoder.php @@ -0,0 +1,300 @@ + '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', + 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', + 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', + 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', + 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', + 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', + 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', + 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', + 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', + 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', + 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', + 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', + 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', + 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', + 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', + 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', + 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', + 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', + 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', + 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', + 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', + 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', + 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', + 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', + 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', + 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', + 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', + 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', + 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', + 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', + 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', + 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', + 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', + 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', + 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', + 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', + 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', + 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', + 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', + 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', + 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', + 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', + 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', + 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', + 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', + 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', + 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', + 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', + 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', + 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', + 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', + 255 => '=FF', + ); + + protected static $_safeMapShare = array(); + + /** + * A map of non-encoded ascii characters. + * + * @var string[] + */ + protected $_safeMap = array(); + + /** + * Creates a new QpEncoder for the given CharacterStream. + * + * @param Swift_CharacterStream $charStream to use for reading characters + * @param Swift_StreamFilter $filter if input should be canonicalized + */ + public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) + { + $this->_charStream = $charStream; + if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $this->initSafeMap(); + self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + } else { + $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + } + $this->_filter = $filter; + } + + public function __sleep() + { + return array('_charStream', '_filter'); + } + + public function __wakeup() + { + if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $this->initSafeMap(); + self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + } else { + $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + } + } + + protected function getSafeMapShareId() + { + return get_class($this); + } + + protected function initSafeMap() + { + foreach (array_merge( + array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { + $this->_safeMap[$byte] = chr($byte); + } + } + + /** + * Takes an unencoded string and produces a QP encoded string from it. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + * + * @param string $string to encode + * @param int $firstLineOffset, optional + * @param int $maxLineLength, optional 0 indicates the default of 76 chars + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $lines = array(); + $lNo = 0; + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $size = $lineLen = 0; + + $this->_charStream->flushContents(); + $this->_charStream->importString($string); + + // Fetching more than 4 chars at one is slower, as is fetching fewer bytes + // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 + // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes + while (false !== $bytes = $this->_nextSequence()) { + // If we're filtering the input + if (isset($this->_filter)) { + // If we can't filter because we need more bytes + while ($this->_filter->shouldBuffer($bytes)) { + // Then collect bytes into the buffer + if (false === $moreBytes = $this->_nextSequence(1)) { + break; + } + + foreach ($moreBytes as $b) { + $bytes[] = $b; + } + } + // And filter them + $bytes = $this->_filter->filter($bytes); + } + + $enc = $this->_encodeByteSequence($bytes, $size); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + ($i === false ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if ($i === false) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + + return $this->_standardize(implode("=\r\n", $lines)); + } + + /** + * Updates the charset used. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charStream->setCharacterSet($charset); + } + + /** + * Encode the given byte array into a verbatim QP form. + * + * @param integer[] $bytes + * @param int $size + * + * @return string + */ + protected function _encodeByteSequence(array $bytes, &$size) + { + $ret = ''; + $size = 0; + foreach ($bytes as $b) { + if (isset($this->_safeMap[$b])) { + $ret .= $this->_safeMap[$b]; + ++$size; + } else { + $ret .= self::$_qpMap[$b]; + $size += 3; + } + } + + return $ret; + } + + /** + * Get the next sequence of bytes to read from the char stream. + * + * @param int $size number of bytes to read + * + * @return integer[] + */ + protected function _nextSequence($size = 4) + { + return $this->_charStream->readBytes($size); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + * + * @param string $string + * + * @return string + */ + protected function _standardize($string) + { + $string = str_replace(array("\t=0D=0A", ' =0D=0A', '=0D=0A'), + array("=09\r\n", "=20\r\n", "\r\n"), $string + ); + switch ($end = ord(substr($string, -1))) { + case 0x09: + case 0x20: + $string = substr_replace($string, self::$_qpMap[$end], -1); + } + + return $string; + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_charStream = clone $this->_charStream; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Encoder/Rfc2231Encoder.php b/lib/SwiftMailer/classes/Swift/Encoder/Rfc2231Encoder.php new file mode 100644 index 0000000..b0215e8 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Encoder/Rfc2231Encoder.php @@ -0,0 +1,92 @@ +_charStream = $charStream; + } + + /** + * Takes an unencoded string and produces a string encoded according to + * RFC 2231 from it. + * + * @param string $string + * @param int $firstLineOffset + * @param int $maxLineLength optional, 0 indicates the default of 75 bytes + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + $lines = array(); + $lineCount = 0; + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $this->_charStream->flushContents(); + $this->_charStream->importString($string); + + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (false !== $char = $this->_charStream->read(4)) { + $encodedChar = rawurlencode($char); + if (0 != strlen($currentLine) + && strlen($currentLine.$encodedChar) > $thisLineLength) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } + + /** + * Updates the charset used. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charStream->setCharacterSet($charset); + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_charStream = clone $this->_charStream; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Encoding.php b/lib/SwiftMailer/classes/Swift/Encoding.php new file mode 100644 index 0000000..253977b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Encoding.php @@ -0,0 +1,64 @@ +lookup($key); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/CommandEvent.php b/lib/SwiftMailer/classes/Swift/Events/CommandEvent.php new file mode 100644 index 0000000..7dc381d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/CommandEvent.php @@ -0,0 +1,65 @@ +_command = $command; + $this->_successCodes = $successCodes; + } + + /** + * Get the command which was sent to the server. + * + * @return string + */ + public function getCommand() + { + return $this->_command; + } + + /** + * Get the numeric response codes which indicate success for this command. + * + * @return integer[] + */ + public function getSuccessCodes() + { + return $this->_successCodes; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/CommandListener.php b/lib/SwiftMailer/classes/Swift/Events/CommandListener.php new file mode 100644 index 0000000..7545404 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/CommandListener.php @@ -0,0 +1,24 @@ +_source = $source; + } + + /** + * Get the source object of this event. + * + * @return object + */ + public function getSource() + { + return $this->_source; + } + + /** + * Prevent this Event from bubbling any further up the stack. + * + * @param bool $cancel, optional + */ + public function cancelBubble($cancel = true) + { + $this->_bubbleCancelled = $cancel; + } + + /** + * Returns true if this Event will not bubble any further up the stack. + * + * @return bool + */ + public function bubbleCancelled() + { + return $this->_bubbleCancelled; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/ResponseEvent.php b/lib/SwiftMailer/classes/Swift/Events/ResponseEvent.php new file mode 100644 index 0000000..2e92ba9 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/ResponseEvent.php @@ -0,0 +1,65 @@ +_response = $response; + $this->_valid = $valid; + } + + /** + * Get the response which was received from the server. + * + * @return string + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Get the success status of this Event. + * + * @return bool + */ + public function isValid() + { + return $this->_valid; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/ResponseListener.php b/lib/SwiftMailer/classes/Swift/Events/ResponseListener.php new file mode 100644 index 0000000..c40919d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/ResponseListener.php @@ -0,0 +1,24 @@ +_message = $message; + $this->_result = self::RESULT_PENDING; + } + + /** + * Get the Transport used to send the Message. + * + * @return Swift_Transport + */ + public function getTransport() + { + return $this->getSource(); + } + + /** + * Get the Message being sent. + * + * @return Swift_Mime_Message + */ + public function getMessage() + { + return $this->_message; + } + + /** + * Set the array of addresses that failed in sending. + * + * @param array $recipients + */ + public function setFailedRecipients($recipients) + { + $this->_failedRecipients = $recipients; + } + + /** + * Get an recipient addresses which were not accepted for delivery. + * + * @return string[] + */ + public function getFailedRecipients() + { + return $this->_failedRecipients; + } + + /** + * Set the result of sending. + * + * @param int $result + */ + public function setResult($result) + { + $this->_result = $result; + } + + /** + * Get the result of this Event. + * + * The return value is a bitmask from + * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED} + * + * @return int + */ + public function getResult() + { + return $this->_result; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/SendListener.php b/lib/SwiftMailer/classes/Swift/Events/SendListener.php new file mode 100644 index 0000000..d922e1b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/SendListener.php @@ -0,0 +1,31 @@ +_eventMap = array( + 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener', + 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener', + 'Swift_Events_SendEvent' => 'Swift_Events_SendListener', + 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener', + 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener', + ); + } + + /** + * Create a new SendEvent for $source and $message. + * + * @param Swift_Transport $source + * @param Swift_Mime_Message + * + * @return Swift_Events_SendEvent + */ + public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message) + { + return new Swift_Events_SendEvent($source, $message); + } + + /** + * Create a new CommandEvent for $source and $command. + * + * @param Swift_Transport $source + * @param string $command That will be executed + * @param array $successCodes That are needed + * + * @return Swift_Events_CommandEvent + */ + public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array()) + { + return new Swift_Events_CommandEvent($source, $command, $successCodes); + } + + /** + * Create a new ResponseEvent for $source and $response. + * + * @param Swift_Transport $source + * @param string $response + * @param bool $valid If the response is valid + * + * @return Swift_Events_ResponseEvent + */ + public function createResponseEvent(Swift_Transport $source, $response, $valid) + { + return new Swift_Events_ResponseEvent($source, $response, $valid); + } + + /** + * Create a new TransportChangeEvent for $source. + * + * @param Swift_Transport $source + * + * @return Swift_Events_TransportChangeEvent + */ + public function createTransportChangeEvent(Swift_Transport $source) + { + return new Swift_Events_TransportChangeEvent($source); + } + + /** + * Create a new TransportExceptionEvent for $source. + * + * @param Swift_Transport $source + * @param Swift_TransportException $ex + * + * @return Swift_Events_TransportExceptionEvent + */ + public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex) + { + return new Swift_Events_TransportExceptionEvent($source, $ex); + } + + /** + * Bind an event listener to this dispatcher. + * + * @param Swift_Events_EventListener $listener + */ + public function bindEventListener(Swift_Events_EventListener $listener) + { + foreach ($this->_listeners as $l) { + // Already loaded + if ($l === $listener) { + return; + } + } + $this->_listeners[] = $listener; + } + + /** + * Dispatch the given Event to all suitable listeners. + * + * @param Swift_Events_EventObject $evt + * @param string $target method + */ + public function dispatchEvent(Swift_Events_EventObject $evt, $target) + { + $this->_prepareBubbleQueue($evt); + $this->_bubble($evt, $target); + } + + /** Queue listeners on a stack ready for $evt to be bubbled up it */ + private function _prepareBubbleQueue(Swift_Events_EventObject $evt) + { + $this->_bubbleQueue = array(); + $evtClass = get_class($evt); + foreach ($this->_listeners as $listener) { + if (array_key_exists($evtClass, $this->_eventMap) + && ($listener instanceof $this->_eventMap[$evtClass])) { + $this->_bubbleQueue[] = $listener; + } + } + } + + /** Bubble $evt up the stack calling $target() on each listener */ + private function _bubble(Swift_Events_EventObject $evt, $target) + { + if (!$evt->bubbleCancelled() && $listener = array_shift($this->_bubbleQueue)) { + $listener->$target($evt); + $this->_bubble($evt, $target); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/TransportChangeEvent.php b/lib/SwiftMailer/classes/Swift/Events/TransportChangeEvent.php new file mode 100644 index 0000000..a8972fd --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/TransportChangeEvent.php @@ -0,0 +1,27 @@ +getSource(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/TransportChangeListener.php b/lib/SwiftMailer/classes/Swift/Events/TransportChangeListener.php new file mode 100644 index 0000000..253165d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/TransportChangeListener.php @@ -0,0 +1,45 @@ +_exception = $ex; + } + + /** + * Get the TransportException thrown. + * + * @return Swift_TransportException + */ + public function getException() + { + return $this->_exception; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Events/TransportExceptionListener.php b/lib/SwiftMailer/classes/Swift/Events/TransportExceptionListener.php new file mode 100644 index 0000000..cc3c099 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Events/TransportExceptionListener.php @@ -0,0 +1,24 @@ +createDependenciesFor('transport.failover') + ); + + $this->setTransports($transports); + } + + /** + * Create a new FailoverTransport instance. + * + * @param Swift_Transport[] $transports + * + * @return Swift_FailoverTransport + */ + public static function newInstance($transports = array()) + { + return new self($transports); + } +} diff --git a/lib/SwiftMailer/classes/Swift/FileSpool.php b/lib/SwiftMailer/classes/Swift/FileSpool.php new file mode 100644 index 0000000..c82c5db --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/FileSpool.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages on the filesystem. + * + * @author Fabien Potencier + * @author Xavier De Cock + */ +class Swift_FileSpool extends Swift_ConfigurableSpool +{ + /** The spool directory */ + private $_path; + + /** + * File WriteRetry Limit. + * + * @var int + */ + private $_retryLimit = 10; + + /** + * Create a new FileSpool. + * + * @param string $path + * + * @throws Swift_IoException + */ + public function __construct($path) + { + $this->_path = $path; + + if (!file_exists($this->_path)) { + if (!mkdir($this->_path, 0777, true)) { + throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->_path)); + } + } + } + + /** + * Tests if this Spool mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Spool mechanism. + */ + public function start() + { + } + + /** + * Stops this Spool mechanism. + */ + public function stop() + { + } + + /** + * Allow to manage the enqueuing retry limit. + * + * Default, is ten and allows over 64^20 different fileNames + * + * @param int $limit + */ + public function setRetryLimit($limit) + { + $this->_retryLimit = $limit; + } + + /** + * Queues a message. + * + * @param Swift_Mime_Message $message The message to store + * + * @throws Swift_IoException + * + * @return bool + */ + public function queueMessage(Swift_Mime_Message $message) + { + $ser = serialize($message); + $fileName = $this->_path.'/'.$this->getRandomString(10); + for ($i = 0; $i < $this->_retryLimit; ++$i) { + /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */ + $fp = @fopen($fileName.'.message', 'x'); + if (false !== $fp) { + if (false === fwrite($fp, $ser)) { + return false; + } + + return fclose($fp); + } else { + /* The file already exists, we try a longer fileName */ + $fileName .= $this->getRandomString(1); + } + } + + throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->_path)); + } + + /** + * Execute a recovery if for any reason a process is sending for too long. + * + * @param int $timeout in second Defaults is for very slow smtp responses + */ + public function recover($timeout = 900) + { + foreach (new DirectoryIterator($this->_path) as $file) { + $file = $file->getRealPath(); + + if (substr($file, -16) == '.message.sending') { + $lockedtime = filectime($file); + if ((time() - $lockedtime) > $timeout) { + rename($file, substr($file, 0, -8)); + } + } + } + } + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent e-mail's + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) + { + $directoryIterator = new DirectoryIterator($this->_path); + + /* Start the transport only if there are queued files to send */ + if (!$transport->isStarted()) { + foreach ($directoryIterator as $file) { + if (substr($file->getRealPath(), -8) == '.message') { + $transport->start(); + break; + } + } + } + + $failedRecipients = (array) $failedRecipients; + $count = 0; + $time = time(); + foreach ($directoryIterator as $file) { + $file = $file->getRealPath(); + + if (substr($file, -8) != '.message') { + continue; + } + + /* We try a rename, it's an atomic operation, and avoid locking the file */ + if (rename($file, $file.'.sending')) { + $message = unserialize(file_get_contents($file.'.sending')); + + $count += $transport->send($message, $failedRecipients); + + unlink($file.'.sending'); + } else { + /* This message has just been catched by another process */ + continue; + } + + if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) { + break; + } + + if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) { + break; + } + } + + return $count; + } + + /** + * Returns a random string needed to generate a fileName for the queue. + * + * @param int $count + * + * @return string + */ + protected function getRandomString($count) + { + // This string MUST stay FS safe, avoid special chars + $base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-'; + $ret = ''; + $strlen = strlen($base); + for ($i = 0; $i < $count; ++$i) { + $ret .= $base[((int) rand(0, $strlen - 1))]; + } + + return $ret; + } +} diff --git a/lib/SwiftMailer/classes/Swift/FileStream.php b/lib/SwiftMailer/classes/Swift/FileStream.php new file mode 100644 index 0000000..0b24db1 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/FileStream.php @@ -0,0 +1,24 @@ +setFile( + new Swift_ByteStream_FileByteStream($path) + ); + + return $image; + } +} diff --git a/lib/SwiftMailer/classes/Swift/InputByteStream.php b/lib/SwiftMailer/classes/Swift/InputByteStream.php new file mode 100644 index 0000000..56efc75 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/InputByteStream.php @@ -0,0 +1,75 @@ +_stream = $stream; + } + + /** + * Set a string into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param string $string + * @param int $mode + */ + public function setString($nsKey, $itemKey, $string, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $this->_contents[$nsKey][$itemKey] = $string; + break; + case self::MODE_APPEND: + if (!$this->hasKey($nsKey, $itemKey)) { + $this->_contents[$nsKey][$itemKey] = ''; + } + $this->_contents[$nsKey][$itemKey] .= $string; + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + } + } + + /** + * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_OutputByteStream $os + * @param int $mode + */ + public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $this->clearKey($nsKey, $itemKey); + case self::MODE_APPEND: + if (!$this->hasKey($nsKey, $itemKey)) { + $this->_contents[$nsKey][$itemKey] = ''; + } + while (false !== $bytes = $os->read(8192)) { + $this->_contents[$nsKey][$itemKey] .= $bytes; + } + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + } + } + + /** + * Provides a ByteStream which when written to, writes data to $itemKey. + * + * NOTE: The stream will always write in append mode. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $writeThrough + * + * @return Swift_InputByteStream + */ + public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) + { + $is = clone $this->_stream; + $is->setKeyCache($this); + $is->setNsKey($nsKey); + $is->setItemKey($itemKey); + if (isset($writeThrough)) { + $is->setWriteThroughStream($writeThrough); + } + + return $is; + } + + /** + * Get data back out of the cache as a string. + * + * @param string $nsKey + * @param string $itemKey + * + * @return string + */ + public function getString($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + return $this->_contents[$nsKey][$itemKey]; + } + } + + /** + * Get data back out of the cache as a ByteStream. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $is to write the data to + */ + public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) + { + $this->_prepareCache($nsKey); + $is->write($this->getString($nsKey, $itemKey)); + } + + /** + * Check if the given $itemKey exists in the namespace $nsKey. + * + * @param string $nsKey + * @param string $itemKey + * + * @return bool + */ + public function hasKey($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + + return array_key_exists($itemKey, $this->_contents[$nsKey]); + } + + /** + * Clear data for $itemKey in the namespace $nsKey if it exists. + * + * @param string $nsKey + * @param string $itemKey + */ + public function clearKey($nsKey, $itemKey) + { + unset($this->_contents[$nsKey][$itemKey]); + } + + /** + * Clear all data in the namespace $nsKey if it exists. + * + * @param string $nsKey + */ + public function clearAll($nsKey) + { + unset($this->_contents[$nsKey]); + } + + /** + * Initialize the namespace of $nsKey if needed. + * + * @param string $nsKey + */ + private function _prepareCache($nsKey) + { + if (!array_key_exists($nsKey, $this->_contents)) { + $this->_contents[$nsKey] = array(); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/KeyCache/DiskKeyCache.php b/lib/SwiftMailer/classes/Swift/KeyCache/DiskKeyCache.php new file mode 100644 index 0000000..453f50a --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/KeyCache/DiskKeyCache.php @@ -0,0 +1,321 @@ +_stream = $stream; + $this->_path = $path; + + if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { + $this->_quotes = true; + } + } + + /** + * Set a string into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param string $string + * @param int $mode + * + * @throws Swift_IoException + */ + public function setString($nsKey, $itemKey, $string, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + break; + case self::MODE_APPEND: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + break; + } + fwrite($fp, $string); + $this->_freeHandle($nsKey, $itemKey); + } + + /** + * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_OutputByteStream $os + * @param int $mode + * + * @throws Swift_IoException + */ + public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + break; + case self::MODE_APPEND: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); + break; + default: + throw new Swift_SwiftException( + 'Invalid mode ['.$mode.'] used to set nsKey='. + $nsKey.', itemKey='.$itemKey + ); + break; + } + while (false !== $bytes = $os->read(8192)) { + fwrite($fp, $bytes); + } + $this->_freeHandle($nsKey, $itemKey); + } + + /** + * Provides a ByteStream which when written to, writes data to $itemKey. + * + * NOTE: The stream will always write in append mode. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $writeThrough + * + * @return Swift_InputByteStream + */ + public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) + { + $is = clone $this->_stream; + $is->setKeyCache($this); + $is->setNsKey($nsKey); + $is->setItemKey($itemKey); + if (isset($writeThrough)) { + $is->setWriteThroughStream($writeThrough); + } + + return $is; + } + + /** + * Get data back out of the cache as a string. + * + * @param string $nsKey + * @param string $itemKey + * + * @throws Swift_IoException + * + * @return string + */ + public function getString($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + $str = ''; + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $str .= $bytes; + } + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_freeHandle($nsKey, $itemKey); + + return $str; + } + } + + /** + * Get data back out of the cache as a ByteStream. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $is to write the data to + */ + public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) + { + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $is->write($bytes); + } + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_freeHandle($nsKey, $itemKey); + } + } + + /** + * Check if the given $itemKey exists in the namespace $nsKey. + * + * @param string $nsKey + * @param string $itemKey + * + * @return bool + */ + public function hasKey($nsKey, $itemKey) + { + return is_file($this->_path.'/'.$nsKey.'/'.$itemKey); + } + + /** + * Clear data for $itemKey in the namespace $nsKey if it exists. + * + * @param string $nsKey + * @param string $itemKey + */ + public function clearKey($nsKey, $itemKey) + { + if ($this->hasKey($nsKey, $itemKey)) { + $this->_freeHandle($nsKey, $itemKey); + unlink($this->_path.'/'.$nsKey.'/'.$itemKey); + } + } + + /** + * Clear all data in the namespace $nsKey if it exists. + * + * @param string $nsKey + */ + public function clearAll($nsKey) + { + if (array_key_exists($nsKey, $this->_keys)) { + foreach ($this->_keys[$nsKey] as $itemKey => $null) { + $this->clearKey($nsKey, $itemKey); + } + if (is_dir($this->_path.'/'.$nsKey)) { + rmdir($this->_path.'/'.$nsKey); + } + unset($this->_keys[$nsKey]); + } + } + + /** + * Initialize the namespace of $nsKey if needed. + * + * @param string $nsKey + */ + private function _prepareCache($nsKey) + { + $cacheDir = $this->_path.'/'.$nsKey; + if (!is_dir($cacheDir)) { + if (!mkdir($cacheDir)) { + throw new Swift_IoException('Failed to create cache directory '.$cacheDir); + } + $this->_keys[$nsKey] = array(); + } + } + + /** + * Get a file handle on the cache item. + * + * @param string $nsKey + * @param string $itemKey + * @param int $position + * + * @return resource + */ + private function _getHandle($nsKey, $itemKey, $position) + { + if (!isset($this->_keys[$nsKey][$itemKey])) { + $openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b'; + $fp = fopen($this->_path.'/'.$nsKey.'/'.$itemKey, $openMode); + $this->_keys[$nsKey][$itemKey] = $fp; + } + if (self::POSITION_START == $position) { + fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET); + } elseif (self::POSITION_END == $position) { + fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END); + } + + return $this->_keys[$nsKey][$itemKey]; + } + + private function _freeHandle($nsKey, $itemKey) + { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT); + fclose($fp); + $this->_keys[$nsKey][$itemKey] = null; + } + + /** + * Destructor. + */ + public function __destruct() + { + foreach ($this->_keys as $nsKey => $null) { + $this->clearAll($nsKey); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/KeyCache/KeyCacheInputStream.php b/lib/SwiftMailer/classes/Swift/KeyCache/KeyCacheInputStream.php new file mode 100644 index 0000000..af80bdc --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/KeyCache/KeyCacheInputStream.php @@ -0,0 +1,51 @@ +_keyCache = $keyCache; + } + + /** + * Specify a stream to write through for each write(). + * + * @param Swift_InputByteStream $is + */ + public function setWriteThroughStream(Swift_InputByteStream $is) + { + $this->_writeThrough = $is; + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + * @param Swift_InputByteStream $is optional + */ + public function write($bytes, Swift_InputByteStream $is = null) + { + $this->_keyCache->setString( + $this->_nsKey, $this->_itemKey, $bytes, Swift_KeyCache::MODE_APPEND + ); + if (isset($is)) { + $is->write($bytes); + } + if (isset($this->_writeThrough)) { + $this->_writeThrough->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Not used. + */ + public function bind(Swift_InputByteStream $is) + { + } + + /** + * Not used. + */ + public function unbind(Swift_InputByteStream $is) + { + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + */ + public function flushBuffers() + { + $this->_keyCache->clearKey($this->_nsKey, $this->_itemKey); + } + + /** + * Set the nsKey which will be written to. + * + * @param string $nsKey + */ + public function setNsKey($nsKey) + { + $this->_nsKey = $nsKey; + } + + /** + * Set the itemKey which will be written to. + * + * @param string $itemKey + */ + public function setItemKey($itemKey) + { + $this->_itemKey = $itemKey; + } + + /** + * Any implementation should be cloneable, allowing the clone to access a + * separate $nsKey and $itemKey. + */ + public function __clone() + { + $this->_writeThrough = null; + } +} diff --git a/lib/SwiftMailer/classes/Swift/LoadBalancedTransport.php b/lib/SwiftMailer/classes/Swift/LoadBalancedTransport.php new file mode 100644 index 0000000..fdba9df --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/LoadBalancedTransport.php @@ -0,0 +1,45 @@ +createDependenciesFor('transport.loadbalanced') + ); + + $this->setTransports($transports); + } + + /** + * Create a new LoadBalancedTransport instance. + * + * @param array $transports + * + * @return Swift_LoadBalancedTransport + */ + public static function newInstance($transports = array()) + { + return new self($transports); + } +} diff --git a/lib/SwiftMailer/classes/Swift/MailTransport.php b/lib/SwiftMailer/classes/Swift/MailTransport.php new file mode 100644 index 0000000..858ca81 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/MailTransport.php @@ -0,0 +1,45 @@ +createDependenciesFor('transport.mail') + ); + + $this->setExtraParams($extraParams); + } + + /** + * Create a new MailTransport instance. + * + * @param string $extraParams To be passed to mail() + * + * @return Swift_MailTransport + */ + public static function newInstance($extraParams = '-f%s') + { + return new self($extraParams); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mailer.php b/lib/SwiftMailer/classes/Swift/Mailer.php new file mode 100644 index 0000000..6411546 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mailer.php @@ -0,0 +1,114 @@ +_transport = $transport; + } + + /** + * Create a new Mailer instance. + * + * @param Swift_Transport $transport + * + * @return Swift_Mailer + */ + public static function newInstance(Swift_Transport $transport) + { + return new self($transport); + } + + /** + * Create a new class instance of one of the message services. + * + * For example 'mimepart' would create a 'message.mimepart' instance + * + * @param string $service + * + * @return object + */ + public function createMessage($service = 'message') + { + return Swift_DependencyContainer::getInstance() + ->lookup('message.'.$service); + } + + /** + * Send the given Message like it would be sent in a mail client. + * + * All recipients (with the exception of Bcc) will be able to see the other + * recipients this message was sent to. + * + * Recipient/sender data will be retrieved from the Message object. + * + * The return value is the number of recipients who were accepted for + * delivery. + * + * @param Swift_Mime_Message $message + * @param array $failedRecipients An array of failures by-reference + * + * @return int The number of successful recipients. Can be 0 which indicates failure + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + + if (!$this->_transport->isStarted()) { + $this->_transport->start(); + } + + $sent = 0; + + try { + $sent = $this->_transport->send($message, $failedRecipients); + } catch (Swift_RfcComplianceException $e) { + foreach ($message->getTo() as $address => $name) { + $failedRecipients[] = $address; + } + } + + return $sent; + } + + /** + * Register a plugin using a known unique key (e.g. myPlugin). + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_transport->registerPlugin($plugin); + } + + /** + * The Transport used to send messages. + * + * @return Swift_Transport + */ + public function getTransport() + { + return $this->_transport; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mailer/ArrayRecipientIterator.php b/lib/SwiftMailer/classes/Swift/Mailer/ArrayRecipientIterator.php new file mode 100644 index 0000000..e3e6cad --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mailer/ArrayRecipientIterator.php @@ -0,0 +1,55 @@ +_recipients = $recipients; + } + + /** + * Returns true only if there are more recipients to send to. + * + * @return bool + */ + public function hasNext() + { + return !empty($this->_recipients); + } + + /** + * Returns an array where the keys are the addresses of recipients and the + * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL). + * + * @return array + */ + public function nextRecipient() + { + return array_splice($this->_recipients, 0, 1); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mailer/RecipientIterator.php b/lib/SwiftMailer/classes/Swift/Mailer/RecipientIterator.php new file mode 100644 index 0000000..650f3ec --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mailer/RecipientIterator.php @@ -0,0 +1,32 @@ + 'Foo') or ('foo@bar' => NULL). + * + * @return array + */ + public function nextRecipient(); +} diff --git a/lib/SwiftMailer/classes/Swift/MemorySpool.php b/lib/SwiftMailer/classes/Swift/MemorySpool.php new file mode 100644 index 0000000..2cafb67 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/MemorySpool.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in memory. + * + * @author Fabien Potencier + */ +class Swift_MemorySpool implements Swift_Spool +{ + protected $messages = array(); + private $flushRetries = 3; + + /** + * Tests if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * @param int $retries + */ + public function setFlushRetries($retries) + { + $this->flushRetries = $retries; + } + + /** + * Stores a message in the queue. + * + * @param Swift_Mime_Message $message The message to store + * + * @return bool Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_Message $message) + { + //clone the message to make sure it is not changed while in the queue + $this->messages[] = clone $message; + + return true; + } + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) + { + if (!$this->messages) { + return 0; + } + + if (!$transport->isStarted()) { + $transport->start(); + } + + $count = 0; + $retries = $this->flushRetries; + while ($retries--) { + try { + while ($message = array_pop($this->messages)) { + $count += $transport->send($message, $failedRecipients); + } + } catch (Swift_TransportException $exception) { + if ($retries) { + // re-queue the message at the end of the queue to give a chance + // to the other messages to be sent, in case the failure was due to + // this message and not just the transport failing + array_unshift($this->messages, $message); + + // wait half a second before we try again + usleep(500000); + } else { + throw $exception; + } + } + } + + return $count; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Message.php b/lib/SwiftMailer/classes/Swift/Message.php new file mode 100644 index 0000000..5f75b93 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Message.php @@ -0,0 +1,291 @@ +createDependenciesFor('mime.message') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setSubject($subject); + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new Message. + * + * @param string $subject + * @param string $body + * @param string $contentType + * @param string $charset + * + * @return Swift_Message + */ + public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null) + { + return new self($subject, $body, $contentType, $charset); + } + + /** + * Add a MimePart to this Message. + * + * @param string|Swift_OutputByteStream $body + * @param string $contentType + * @param string $charset + * + * @return Swift_Mime_SimpleMessage + */ + public function addPart($body, $contentType = null, $charset = null) + { + return $this->attach(Swift_MimePart::newInstance( + $body, $contentType, $charset + )); + } + + /** + * Detach a signature handler from a message. + * + * @param Swift_Signer $signer + * + * @return Swift_Message + */ + public function attachSigner(Swift_Signer $signer) + { + if ($signer instanceof Swift_Signers_HeaderSigner) { + $this->headerSigners[] = $signer; + } elseif ($signer instanceof Swift_Signers_BodySigner) { + $this->bodySigners[] = $signer; + } + + return $this; + } + + /** + * Attach a new signature handler to the message. + * + * @param Swift_Signer $signer + * + * @return Swift_Message + */ + public function detachSigner(Swift_Signer $signer) + { + if ($signer instanceof Swift_Signers_HeaderSigner) { + foreach ($this->headerSigners as $k => $headerSigner) { + if ($headerSigner === $signer) { + unset($this->headerSigners[$k]); + + return $this; + } + } + } elseif ($signer instanceof Swift_Signers_BodySigner) { + foreach ($this->bodySigners as $k => $bodySigner) { + if ($bodySigner === $signer) { + unset($this->bodySigners[$k]); + + return $this; + } + } + } + + return $this; + } + + /** + * Get this message as a complete string. + * + * @return string + */ + public function toString() + { + if (empty($this->headerSigners) && empty($this->bodySigners)) { + return parent::toString(); + } + + $this->saveMessage(); + + $this->doSign(); + + $string = parent::toString(); + + $this->restoreMessage(); + + return $string; + } + + /** + * Write this message to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream $is + */ + public function toByteStream(Swift_InputByteStream $is) + { + if (empty($this->headerSigners) && empty($this->bodySigners)) { + parent::toByteStream($is); + + return; + } + + $this->saveMessage(); + + $this->doSign(); + + parent::toByteStream($is); + + $this->restoreMessage(); + } + + public function __wakeup() + { + Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message'); + } + + /** + * loops through signers and apply the signatures. + */ + protected function doSign() + { + foreach ($this->bodySigners as $signer) { + $altered = $signer->getAlteredHeaders(); + $this->saveHeaders($altered); + $signer->signMessage($this); + } + + foreach ($this->headerSigners as $signer) { + $altered = $signer->getAlteredHeaders(); + $this->saveHeaders($altered); + $signer->reset(); + + $signer->setHeaders($this->getHeaders()); + + $signer->startBody(); + $this->_bodyToByteStream($signer); + $signer->endBody(); + + $signer->addSignature($this->getHeaders()); + } + } + + /** + * save the message before any signature is applied. + */ + protected function saveMessage() + { + $this->savedMessage = array('headers' => array()); + $this->savedMessage['body'] = $this->getBody(); + $this->savedMessage['children'] = $this->getChildren(); + if (count($this->savedMessage['children']) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $this->savedMessage['children'])); + $this->setBody(''); + } + } + + /** + * save the original headers. + * + * @param array $altered + */ + protected function saveHeaders(array $altered) + { + foreach ($altered as $head) { + $lc = strtolower($head); + + if (!isset($this->savedMessage['headers'][$lc])) { + $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head); + } + } + } + + /** + * Remove or restore altered headers. + */ + protected function restoreHeaders() + { + foreach ($this->savedMessage['headers'] as $name => $savedValue) { + $headers = $this->getHeaders()->getAll($name); + + foreach ($headers as $key => $value) { + if (!isset($savedValue[$key])) { + $this->getHeaders()->remove($name, $key); + } + } + } + } + + /** + * Restore message body. + */ + protected function restoreMessage() + { + $this->setBody($this->savedMessage['body']); + $this->setChildren($this->savedMessage['children']); + + $this->restoreHeaders(); + $this->savedMessage = array(); + } + + /** + * Clone Message Signers. + * + * @see Swift_Mime_SimpleMimeEntity::__clone() + */ + public function __clone() + { + parent::__clone(); + foreach ($this->bodySigners as $key => $bodySigner) { + $this->bodySigners[$key] = clone($bodySigner); + } + + foreach ($this->headerSigners as $key => $headerSigner) { + $this->headerSigners[$key] = clone($headerSigner); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Attachment.php b/lib/SwiftMailer/classes/Swift/Mime/Attachment.php new file mode 100644 index 0000000..46a5e8d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Attachment.php @@ -0,0 +1,149 @@ +setDisposition('attachment'); + $this->setContentType('application/octet-stream'); + $this->_mimeTypes = $mimeTypes; + } + + /** + * Get the nesting level used for this attachment. + * + * Always returns {@link LEVEL_MIXED}. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_MIXED; + } + + /** + * Get the Content-Disposition of this attachment. + * + * By default attachments have a disposition of "attachment". + * + * @return string + */ + public function getDisposition() + { + return $this->_getHeaderFieldModel('Content-Disposition'); + } + + /** + * Set the Content-Disposition of this attachment. + * + * @param string $disposition + * + * @return Swift_Mime_Attachment + */ + public function setDisposition($disposition) + { + if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) { + $this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition); + } + + return $this; + } + + /** + * Get the filename of this attachment when downloaded. + * + * @return string + */ + public function getFilename() + { + return $this->_getHeaderParameter('Content-Disposition', 'filename'); + } + + /** + * Set the filename of this attachment. + * + * @param string $filename + * + * @return Swift_Mime_Attachment + */ + public function setFilename($filename) + { + $this->_setHeaderParameter('Content-Disposition', 'filename', $filename); + $this->_setHeaderParameter('Content-Type', 'name', $filename); + + return $this; + } + + /** + * Get the file size of this attachment. + * + * @return int + */ + public function getSize() + { + return $this->_getHeaderParameter('Content-Disposition', 'size'); + } + + /** + * Set the file size of this attachment. + * + * @param int $size + * + * @return Swift_Mime_Attachment + */ + public function setSize($size) + { + $this->_setHeaderParameter('Content-Disposition', 'size', $size); + + return $this; + } + + /** + * Set the file that this attachment is for. + * + * @param Swift_FileStream $file + * @param string $contentType optional + * + * @return Swift_Mime_Attachment + */ + public function setFile(Swift_FileStream $file, $contentType = null) + { + $this->setFilename(basename($file->getPath())); + $this->setBody($file, $contentType); + if (!isset($contentType)) { + $extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1)); + + if (array_key_exists($extension, $this->_mimeTypes)) { + $this->setContentType($this->_mimeTypes[$extension]); + } + } + + return $this; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/CharsetObserver.php b/lib/SwiftMailer/classes/Swift/Mime/CharsetObserver.php new file mode 100644 index 0000000..b49c3a8 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/CharsetObserver.php @@ -0,0 +1,24 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $remainder = 0; + $base64ReadBufferRemainderBytes = null; + + // To reduce memory usage, the output buffer is streamed to the input buffer like so: + // Output Stream => base64encode => wrap line length => Input Stream + // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data) + // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream. + // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the + // chunk of bytes read in the next iteration. + // When the OutputStream is empty, we must flush any remainder bytes. + while (true) { + $readBytes = $os->read(8192); + $atEOF = ($readBytes === false); + + if ($atEOF) { + $streamTheseBytes = $base64ReadBufferRemainderBytes; + } else { + $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes; + } + $base64ReadBufferRemainderBytes = null; + $bytesLength = strlen($streamTheseBytes); + + if ($bytesLength === 0) { // no data left to encode + break; + } + + // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data + // and carry over remainder 1-2 bytes to the next loop iteration + if (!$atEOF) { + $excessBytes = $bytesLength % 3; + if ($excessBytes !== 0) { + $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes); + $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes); + } + } + + $encoded = base64_encode($streamTheseBytes); + $encodedTransformed = ''; + $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset; + + while ($thisMaxLineLength < strlen($encoded)) { + $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n"; + $firstLineOffset = 0; + $encoded = substr($encoded, $thisMaxLineLength); + $thisMaxLineLength = $maxLineLength; + $remainder = 0; + } + + if (0 < $remainingLength = strlen($encoded)) { + $remainder += $remainingLength; + $encodedTransformed .= $encoded; + $encoded = null; + } + + $is->write($encodedTransformed); + + if ($atEOF) { + break; + } + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'base64'. + * + * @return string + */ + public function getName() + { + return 'base64'; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php new file mode 100644 index 0000000..710b5ac --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php @@ -0,0 +1,123 @@ +charset = $charset ? $charset : 'utf-8'; + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->charset = $charset; + } + + /** + * Encode $in to $out. + * + * @param Swift_OutputByteStream $os to read from + * @param Swift_InputByteStream $is to write to + * @param int $firstLineOffset + * @param int $maxLineLength 0 indicates the default length for this encoding + * + * @throws RuntimeException + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->charset !== 'utf-8') { + throw new RuntimeException( + sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); + } + + $string = ''; + + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + $is->write($this->encodeString($string)); + } + + /** + * Get the MIME name of this content encoding scheme. + * + * @return string + */ + public function getName() + { + return 'quoted-printable'; + } + + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset if first line needs to be shorter + * @param int $maxLineLength 0 indicates the default length for this encoding + * + * @throws RuntimeException + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->charset !== 'utf-8') { + throw new RuntimeException( + sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); + } + + return $this->_standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + * + * @param string $string + * + * @return string + */ + protected function _standardize($string) + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(?_name = $name; + $this->_canonical = $canonical; + } + + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset ignored + * @param int $maxLineLength - 0 means no wrapping will occur + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->_canonical) { + $string = $this->_canonicalize($string); + } + + return $this->_safeWordWrap($string, $maxLineLength, "\r\n"); + } + + /** + * Encode stream $in to stream $out. + * + * @param Swift_OutputByteStream $os + * @param Swift_InputByteStream $is + * @param int $firstLineOffset ignored + * @param int $maxLineLength optional, 0 means no wrapping will occur + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + $leftOver = ''; + while (false !== $bytes = $os->read(8192)) { + $toencode = $leftOver.$bytes; + if ($this->_canonical) { + $toencode = $this->_canonicalize($toencode); + } + $wrapped = $this->_safeWordWrap($toencode, $maxLineLength, "\r\n"); + $lastLinePos = strrpos($wrapped, "\r\n"); + $leftOver = substr($wrapped, $lastLinePos); + $wrapped = substr($wrapped, 0, $lastLinePos); + + $is->write($wrapped); + } + if (strlen($leftOver)) { + $is->write($leftOver); + } + } + + /** + * Get the name of this encoding scheme. + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Not used. + */ + public function charsetChanged($charset) + { + } + + /** + * A safer (but weaker) wordwrap for unicode. + * + * @param string $string + * @param int $length + * @param string $le + * + * @return string + */ + private function _safeWordwrap($string, $length = 75, $le = "\r\n") + { + if (0 >= $length) { + return $string; + } + + $originalLines = explode($le, $string); + + $lines = array(); + $lineCount = 0; + + foreach ($originalLines as $originalLine) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine); + $chunks = preg_split('/(?<=\s)/', $originalLine); + + foreach ($chunks as $chunk) { + if (0 != strlen($currentLine) + && strlen($currentLine.$chunk) > $length) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + } + $currentLine .= $chunk; + } + } + + return implode("\r\n", $lines); + } + + /** + * Canonicalize string input (fix CRLF). + * + * @param string $string + * + * @return string + */ + private function _canonicalize($string) + { + return str_replace( + array("\r\n", "\r", "\n"), + array("\n", "\n", "\r\n"), + $string + ); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php new file mode 100644 index 0000000..5cc907b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php @@ -0,0 +1,134 @@ +_dotEscape = $dotEscape; + parent::__construct($charStream, $filter); + } + + public function __sleep() + { + return array('_charStream', '_filter', '_dotEscape'); + } + + protected function getSafeMapShareId() + { + return get_class($this).($this->_dotEscape ? '.dotEscape' : ''); + } + + protected function initSafeMap() + { + parent::initSafeMap(); + if ($this->_dotEscape) { + /* Encode . as =2e for buggy remote servers */ + unset($this->_safeMap[0x2e]); + } + } + + /** + * Encode stream $in to stream $out. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + * + * @param Swift_OutputByteStream $os output stream + * @param Swift_InputByteStream $is input stream + * @param int $firstLineOffset + * @param int $maxLineLength + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $this->_charStream->flushContents(); + $this->_charStream->importByteStream($os); + + $currentLine = ''; + $prepend = ''; + $size = $lineLen = 0; + + while (false !== $bytes = $this->_nextSequence()) { + // If we're filtering the input + if (isset($this->_filter)) { + // If we can't filter because we need more bytes + while ($this->_filter->shouldBuffer($bytes)) { + // Then collect bytes into the buffer + if (false === $moreBytes = $this->_nextSequence(1)) { + break; + } + + foreach ($moreBytes as $b) { + $bytes[] = $b; + } + } + // And filter them + $bytes = $this->_filter->filter($bytes); + } + + $enc = $this->_encodeByteSequence($bytes, $size); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + ($i === false ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $is->write($prepend.$this->_standardize($currentLine)); + $currentLine = ''; + $prepend = "=\r\n"; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if ($i === false) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + if (strlen($currentLine)) { + $is->write($prepend.$this->_standardize($currentLine)); + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'quoted-printable'. + * + * @return string + */ + public function getName() + { + return 'quoted-printable'; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php new file mode 100644 index 0000000..3214e1c --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php @@ -0,0 +1,98 @@ + + */ +class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder +{ + /** + * @var Swift_Mime_ContentEncoder_QpContentEncoder + */ + private $safeEncoder; + + /** + * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder + */ + private $nativeEncoder; + + /** + * @var null|string + */ + private $charset; + + /** + * Constructor. + * + * @param Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder + * @param Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder + * @param string|null $charset + */ + public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset) + { + $this->safeEncoder = $safeEncoder; + $this->nativeEncoder = $nativeEncoder; + $this->charset = $charset; + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->safeEncoder = clone $this->safeEncoder; + $this->nativeEncoder = clone $this->nativeEncoder; + } + + /** + * {@inheritdoc} + */ + public function charsetChanged($charset) + { + $this->charset = $charset; + $this->safeEncoder->charsetChanged($charset); + } + + /** + * {@inheritdoc} + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'quoted-printable'; + } + + /** + * {@inheritdoc} + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength); + } + + /** + * @return Swift_Mime_ContentEncoder + */ + private function getEncoder() + { + return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php new file mode 100644 index 0000000..0b8526e --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php @@ -0,0 +1,64 @@ + + */ +class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder +{ + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset ignored + * @param int $maxLineLength ignored + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return $string; + } + + /** + * Encode stream $in to stream $out. + * + * @param Swift_OutputByteStream $in + * @param Swift_InputByteStream $out + * @param int $firstLineOffset ignored + * @param int $maxLineLength ignored + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + while (false !== ($bytes = $os->read(8192))) { + $is->write($bytes); + } + } + + /** + * Get the name of this encoding scheme. + * + * @return string + */ + public function getName() + { + return 'raw'; + } + + /** + * Not used. + */ + public function charsetChanged($charset) + { + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/EmbeddedFile.php b/lib/SwiftMailer/classes/Swift/Mime/EmbeddedFile.php new file mode 100644 index 0000000..6af7571 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/EmbeddedFile.php @@ -0,0 +1,45 @@ +setDisposition('inline'); + $this->setId($this->getId()); + } + + /** + * Get the nesting level of this EmbeddedFile. + * + * Returns {@see LEVEL_RELATED}. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_RELATED; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/EncodingObserver.php b/lib/SwiftMailer/classes/Swift/Mime/EncodingObserver.php new file mode 100644 index 0000000..cc44a6e --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/EncodingObserver.php @@ -0,0 +1,24 @@ +init(); + } + + public function __wakeup() + { + $this->init(); + } + + protected function init() + { + if (count(self::$_specials) > 0) { + return; + } + + self::$_specials = array( + '(', ')', '<', '>', '[', ']', + ':', ';', '@', ',', '.', '"', + ); + + /*** Refer to RFC 2822 for ABNF grammar ***/ + + // All basic building blocks + self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]'; + self::$_grammar['WSP'] = '[ \t]'; + self::$_grammar['CRLF'] = '(?:\r\n)'; + self::$_grammar['FWS'] = '(?:(?:'.self::$_grammar['WSP'].'*'. + self::$_grammar['CRLF'].')?'.self::$_grammar['WSP'].')'; + self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]'; + self::$_grammar['quoted-pair'] = '(?:\\\\'.self::$_grammar['text'].')'; + self::$_grammar['ctext'] = '(?:'.self::$_grammar['NO-WS-CTL']. + '|[\x21-\x27\x2A-\x5B\x5D-\x7E])'; + // Uses recursive PCRE (?1) -- could be a weak point?? + self::$_grammar['ccontent'] = '(?:'.self::$_grammar['ctext'].'|'. + self::$_grammar['quoted-pair'].'|(?1))'; + self::$_grammar['comment'] = '(\((?:'.self::$_grammar['FWS'].'|'. + self::$_grammar['ccontent'].')*'.self::$_grammar['FWS'].'?\))'; + self::$_grammar['CFWS'] = '(?:(?:'.self::$_grammar['FWS'].'?'. + self::$_grammar['comment'].')*(?:(?:'.self::$_grammar['FWS'].'?'. + self::$_grammar['comment'].')|'.self::$_grammar['FWS'].'))'; + self::$_grammar['qtext'] = '(?:'.self::$_grammar['NO-WS-CTL']. + '|[\x21\x23-\x5B\x5D-\x7E])'; + self::$_grammar['qcontent'] = '(?:'.self::$_grammar['qtext'].'|'. + self::$_grammar['quoted-pair'].')'; + self::$_grammar['quoted-string'] = '(?:'.self::$_grammar['CFWS'].'?"'. + '('.self::$_grammar['FWS'].'?'.self::$_grammar['qcontent'].')*'. + self::$_grammar['FWS'].'?"'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]'; + self::$_grammar['atom'] = '(?:'.self::$_grammar['CFWS'].'?'. + self::$_grammar['atext'].'+'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['dot-atom-text'] = '(?:'.self::$_grammar['atext'].'+'. + '(\.'.self::$_grammar['atext'].'+)*)'; + self::$_grammar['dot-atom'] = '(?:'.self::$_grammar['CFWS'].'?'. + self::$_grammar['dot-atom-text'].'+'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['word'] = '(?:'.self::$_grammar['atom'].'|'. + self::$_grammar['quoted-string'].')'; + self::$_grammar['phrase'] = '(?:'.self::$_grammar['word'].'+?)'; + self::$_grammar['no-fold-quote'] = '(?:"(?:'.self::$_grammar['qtext']. + '|'.self::$_grammar['quoted-pair'].')*")'; + self::$_grammar['dtext'] = '(?:'.self::$_grammar['NO-WS-CTL']. + '|[\x21-\x5A\x5E-\x7E])'; + self::$_grammar['no-fold-literal'] = '(?:\[(?:'.self::$_grammar['dtext']. + '|'.self::$_grammar['quoted-pair'].')*\])'; + + // Message IDs + self::$_grammar['id-left'] = '(?:'.self::$_grammar['dot-atom-text'].'|'. + self::$_grammar['no-fold-quote'].')'; + self::$_grammar['id-right'] = '(?:'.self::$_grammar['dot-atom-text'].'|'. + self::$_grammar['no-fold-literal'].')'; + + // Addresses, mailboxes and paths + self::$_grammar['local-part'] = '(?:'.self::$_grammar['dot-atom'].'|'. + self::$_grammar['quoted-string'].')'; + self::$_grammar['dcontent'] = '(?:'.self::$_grammar['dtext'].'|'. + self::$_grammar['quoted-pair'].')'; + self::$_grammar['domain-literal'] = '(?:'.self::$_grammar['CFWS'].'?\[('. + self::$_grammar['FWS'].'?'.self::$_grammar['dcontent'].')*?'. + self::$_grammar['FWS'].'?\]'.self::$_grammar['CFWS'].'?)'; + self::$_grammar['domain'] = '(?:'.self::$_grammar['dot-atom'].'|'. + self::$_grammar['domain-literal'].')'; + self::$_grammar['addr-spec'] = '(?:'.self::$_grammar['local-part'].'@'. + self::$_grammar['domain'].')'; + } + + /** + * Get the grammar defined for $name token. + * + * @param string $name exactly as written in the RFC + * + * @return string + */ + public function getDefinition($name) + { + if (array_key_exists($name, self::$_grammar)) { + return self::$_grammar[$name]; + } + + throw new Swift_RfcComplianceException( + "No such grammar '".$name."' defined." + ); + } + + /** + * Returns the tokens defined in RFC 2822 (and some related RFCs). + * + * @return array + */ + public function getGrammarDefinitions() + { + return self::$_grammar; + } + + /** + * Returns the current special characters used in the syntax which need to be escaped. + * + * @return array + */ + public function getSpecials() + { + return self::$_specials; + } + + /** + * Escape special characters in a string (convert to quoted-pairs). + * + * @param string $token + * @param string[] $include additional chars to escape + * @param string[] $exclude chars from escaping + * + * @return string + */ + public function escapeSpecials($token, $include = array(), $exclude = array()) + { + foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) { + $token = str_replace($char, '\\'.$char, $token); + } + + return $token; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Header.php b/lib/SwiftMailer/classes/Swift/Mime/Header.php new file mode 100644 index 0000000..a8ddd27 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Header.php @@ -0,0 +1,93 @@ +getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $firstLineOffset, $maxLineLength); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/lib/SwiftMailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php new file mode 100644 index 0000000..510dd66 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php @@ -0,0 +1,65 @@ +_safeMap[$byte] = chr($byte); + } + } + + /** + * Get the name of this encoding scheme. + * + * Returns the string 'Q'. + * + * @return string + */ + public function getName() + { + return 'Q'; + } + + /** + * Takes an unencoded string and produces a QP encoded string from it. + * + * @param string $string string to encode + * @param int $firstLineOffset optional + * @param int $maxLineLength optional, 0 indicates the default of 76 chars + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return str_replace(array(' ', '=20', "=\r\n"), array('_', '_', "\r\n"), + parent::encodeString($string, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/HeaderFactory.php b/lib/SwiftMailer/classes/Swift/Mime/HeaderFactory.php new file mode 100644 index 0000000..c65f26d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/HeaderFactory.php @@ -0,0 +1,78 @@ +setGrammar($grammar); + } + + /** + * Set the character set used in this Header. + * + * @param string $charset + */ + public function setCharset($charset) + { + $this->clearCachedValueIf($charset != $this->_charset); + $this->_charset = $charset; + if (isset($this->_encoder)) { + $this->_encoder->charsetChanged($charset); + } + } + + /** + * Get the character set used in this Header. + * + * @return string + */ + public function getCharset() + { + return $this->_charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + * This can be unspecified. + * + * @param string $lang + */ + public function setLanguage($lang) + { + $this->clearCachedValueIf($this->_lang != $lang); + $this->_lang = $lang; + } + + /** + * Get the language used in this Header. + * + * @return string + */ + public function getLanguage() + { + return $this->_lang; + } + + /** + * Set the encoder used for encoding the header. + * + * @param Swift_Mime_HeaderEncoder $encoder + */ + public function setEncoder(Swift_Mime_HeaderEncoder $encoder) + { + $this->_encoder = $encoder; + $this->setCachedValue(null); + } + + /** + * Get the encoder used for encoding this Header. + * + * @return Swift_Mime_HeaderEncoder + */ + public function getEncoder() + { + return $this->_encoder; + } + + /** + * Set the grammar used for the header. + * + * @param Swift_Mime_Grammar $grammar + */ + public function setGrammar(Swift_Mime_Grammar $grammar) + { + $this->_grammar = $grammar; + $this->setCachedValue(null); + } + + /** + * Get the grammar used for this Header. + * + * @return Swift_Mime_Grammar + */ + public function getGrammar() + { + return $this->_grammar; + } + + /** + * Get the name of this header (e.g. charset). + * + * @return string + */ + public function getFieldName() + { + return $this->_name; + } + + /** + * Set the maximum length of lines in the header (excluding EOL). + * + * @param int $lineLength + */ + public function setMaxLineLength($lineLength) + { + $this->clearCachedValueIf($this->_lineLength != $lineLength); + $this->_lineLength = $lineLength; + } + + /** + * Get the maximum permitted length of lines in this Header. + * + * @return int + */ + public function getMaxLineLength() + { + return $this->_lineLength; + } + + /** + * Get this Header rendered as a RFC 2822 compliant string. + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function toString() + { + return $this->_tokensToString($this->toTokens()); + } + + /** + * Returns a string representation of this object. + * + * @return string + * + * @see toString() + */ + public function __toString() + { + return $this->toString(); + } + + // -- Points of extension + + /** + * Set the name of this Header field. + * + * @param string $name + */ + protected function setFieldName($name) + { + $this->_name = $name; + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param Swift_Mime_Header $header + * @param string $string as displayed + * @param string $charset of the text + * @param Swift_Mime_HeaderEncoder $encoder + * @param bool $shorten the first line to make remove for header name + * + * @return string + */ + protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) + { + // Treat token as exactly what was given + $phraseStr = $string; + // If it's not valid + if (!preg_match('/^'.$this->getGrammar()->getDefinition('phrase').'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $phraseStr)) { + $phraseStr = $this->getGrammar()->escapeSpecials( + $phraseStr, array('"'), $this->getGrammar()->getSpecials() + ); + $phraseStr = '"'.$phraseStr.'"'; + } else { + // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = strlen($header->getFieldName().': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + * + * @param Swift_Mime_Header $header + * @param string $input + * @param string $usedLength optional + * + * @return string + */ + protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1) + { + $value = ''; + + $tokens = $this->getEncodableWordTokens($input); + + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = strlen($header->getFieldName().': ') + strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + + $header->setMaxLineLength(76); // Forcefully override + } else { + $value .= $token; + } + } + + return $value; + } + + /** + * Test if a token needs to be encoded or not. + * + * @param string $token + * + * @return bool + */ + protected function tokenNeedsEncoding($token) + { + return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @param string $string + * + * @return string[] + */ + protected function getEncodableWordTokens($string) + { + $tokens = array(); + + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if (strlen($encodedToken) > 0) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if (strlen($encodedToken)) { + $tokens[] = $encodedToken; + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + * + * @param string $token token to encode + * @param int $firstLineOffset optional + * + * @return string + */ + protected function getTokenAsEncodedWord($token, $firstLineOffset = 0) + { + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->_charset; + if (isset($this->_lang)) { + $charsetDecl .= '*'.$this->_lang; + } + $encodingWrapperLength = strlen( + '=?'.$charsetDecl.'?'.$this->_encoder->getName().'??=' + ); + + if ($firstLineOffset >= 75) { + //Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + $this->_encoder->encodeString( + $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset + ) + ); + + if (strtolower($this->_charset) !== 'iso-2022-jp') { + // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?'.$charsetDecl. + '?'.$this->_encoder->getName(). + '?'.$line.'?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @param string $token + * + * @return string[] + */ + protected function generateTokenLines($token) + { + return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Set a value into the cache. + * + * @param string $value + */ + protected function setCachedValue($value) + { + $this->_cachedValue = $value; + } + + /** + * Get the value in the cache. + * + * @return string + */ + protected function getCachedValue() + { + return $this->_cachedValue; + } + + /** + * Clear the cached value if $condition is met. + * + * @param bool $condition + */ + protected function clearCachedValueIf($condition) + { + if ($condition) { + $this->setCachedValue(null); + } + } + + /** + * Generate a list of all tokens in the final header. + * + * @param string $string The string to tokenize + * + * @return array An array of tokens as strings + */ + protected function toTokens($string = null) + { + if (is_null($string)) { + $string = $this->getFieldBody(); + } + + $tokens = array(); + + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + * + * @return string + */ + private function _tokensToString(array $tokens) + { + $lineCount = 0; + $headerLines = array(); + $headerLines[] = $this->_name.': '; + $currentLine = &$headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" == $token) || + ($i > 0 && strlen($currentLine.$token) > $this->_lineLength) + && 0 < strlen($currentLine)) { + $headerLines[] = ''; + $currentLine = &$headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" != $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines)."\r\n"; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/DateHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/DateHeader.php new file mode 100644 index 0000000..4fd6674 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/DateHeader.php @@ -0,0 +1,125 @@ + + * + * + * + * @param string $name of Header + * @param Swift_Mime_Grammar $grammar + */ + public function __construct($name, Swift_Mime_Grammar $grammar) + { + $this->setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_DATE; + } + + /** + * Set the model for the field body. + * + * This method takes a UNIX timestamp. + * + * @param int $model + */ + public function setFieldBodyModel($model) + { + $this->setTimestamp($model); + } + + /** + * Get the model for the field body. + * + * This method returns a UNIX timestamp. + * + * @return mixed + */ + public function getFieldBodyModel() + { + return $this->getTimestamp(); + } + + /** + * Get the UNIX timestamp of the Date in this Header. + * + * @return int + */ + public function getTimestamp() + { + return $this->_timestamp; + } + + /** + * Set the UNIX timestamp of the Date in this Header. + * + * @param int $timestamp + */ + public function setTimestamp($timestamp) + { + if (!is_null($timestamp)) { + $timestamp = (int) $timestamp; + } + $this->clearCachedValueIf($this->_timestamp != $timestamp); + $this->_timestamp = $timestamp; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + if (isset($this->_timestamp)) { + $this->setCachedValue(date('r', $this->_timestamp)); + } + } + + return $this->getCachedValue(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/IdentificationHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/IdentificationHeader.php new file mode 100644 index 0000000..b114506 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/IdentificationHeader.php @@ -0,0 +1,180 @@ +setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_ID; + } + + /** + * Set the model for the field body. + * + * This method takes a string ID, or an array of IDs. + * + * @param mixed $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setId($model); + } + + /** + * Get the model for the field body. + * + * This method returns an array of IDs + * + * @return array + */ + public function getFieldBodyModel() + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|array $id + * + * @throws Swift_RfcComplianceException + */ + public function setId($id) + { + $this->setIds(is_array($id) ? $id : array($id)); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + * + * @return string + */ + public function getId() + { + if (count($this->_ids) > 0) { + return $this->_ids[0]; + } + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws Swift_RfcComplianceException + */ + public function setIds(array $ids) + { + $actualIds = array(); + + foreach ($ids as $id) { + $this->_assertValidId($id); + $actualIds[] = $id; + } + + $this->clearCachedValueIf($this->_ids != $actualIds); + $this->_ids = $actualIds; + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds() + { + return $this->_ids; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@see toString()} for that). + * + * @see toString() + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + $angleAddrs = array(); + + foreach ($this->_ids as $id) { + $angleAddrs[] = '<'.$id.'>'; + } + + $this->setCachedValue(implode(' ', $angleAddrs)); + } + + return $this->getCachedValue(); + } + + /** + * Throws an Exception if the id passed does not comply with RFC 2822. + * + * @param string $id + * + * @throws Swift_RfcComplianceException + */ + private function _assertValidId($id) + { + if (!preg_match( + '/^'.$this->getGrammar()->getDefinition('id-left').'@'. + $this->getGrammar()->getDefinition('id-right').'$/D', + $id + )) { + throw new Swift_RfcComplianceException( + 'Invalid ID given <'.$id.'>' + ); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/MailboxHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/MailboxHeader.php new file mode 100644 index 0000000..222a57c --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/MailboxHeader.php @@ -0,0 +1,353 @@ +setFieldName($name); + $this->setEncoder($encoder); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_MAILBOX; + } + + /** + * Set the model for the field body. + * + * This method takes a string, or an array of addresses. + * + * @param mixed $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setNameAddresses($model); + } + + /** + * Get the model for the field body. + * + * This method returns an associative array like {@link getNameAddresses()} + * + * @throws Swift_RfcComplianceException + * + * @return array + */ + public function getFieldBodyModel() + { + return $this->getNameAddresses(); + } + + /** + * Set a list of mailboxes to be shown in this Header. + * + * The mailboxes can be a simple array of addresses, or an array of + * key=>value pairs where (email => personalName). + * Example: + * + * setNameAddresses(array( + * 'chris@swiftmailer.org' => 'Chris Corbyn', + * 'mark@swiftmailer.org' //No associated personal name + * )); + * ?> + * + * + * @see __construct() + * @see setAddresses() + * @see setValue() + * + * @param string|string[] $mailboxes + * + * @throws Swift_RfcComplianceException + */ + public function setNameAddresses($mailboxes) + { + $this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes); + $this->setCachedValue(null); //Clear any cached value + } + + /** + * Get the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * Example: + * + * 'Chris Corbyn', + * 'mark@swiftmailer.org' => 'Mark Corbyn') + * ); + * print_r($header->getNameAddressStrings()); + * // array ( + * // 0 => Chris Corbyn , + * // 1 => Mark Corbyn + * // ) + * ?> + * + * + * @see getNameAddresses() + * @see toString() + * + * @throws Swift_RfcComplianceException + * + * @return string[] + */ + public function getNameAddressStrings() + { + return $this->_createNameAddressStrings($this->getNameAddresses()); + } + + /** + * Get all mailboxes in this Header as key=>value pairs. + * + * The key is the address and the value is the name (or null if none set). + * Example: + * + * 'Chris Corbyn', + * 'mark@swiftmailer.org' => 'Mark Corbyn') + * ); + * print_r($header->getNameAddresses()); + * // array ( + * // chris@swiftmailer.org => Chris Corbyn, + * // mark@swiftmailer.org => Mark Corbyn + * // ) + * ?> + * + * + * @see getAddresses() + * @see getNameAddressStrings() + * + * @return string[] + */ + public function getNameAddresses() + { + return $this->_mailboxes; + } + + /** + * Makes this Header represent a list of plain email addresses with no names. + * + * Example: + * + * setAddresses( + * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld') + * ); + * ?> + * + * + * @see setNameAddresses() + * @see setValue() + * + * @param string[] $addresses + * + * @throws Swift_RfcComplianceException + */ + public function setAddresses($addresses) + { + $this->setNameAddresses(array_values((array) $addresses)); + } + + /** + * Get all email addresses in this Header. + * + * @see getNameAddresses() + * + * @return string[] + */ + public function getAddresses() + { + return array_keys($this->_mailboxes); + } + + /** + * Remove one or more addresses from this Header. + * + * @param string|string[] $addresses + */ + public function removeAddresses($addresses) + { + $this->setCachedValue(null); + foreach ((array) $addresses as $address) { + unset($this->_mailboxes[$address]); + } + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function getFieldBody() + { + // Compute the string value of the header only if needed + if (is_null($this->getCachedValue())) { + $this->setCachedValue($this->createMailboxListString($this->_mailboxes)); + } + + return $this->getCachedValue(); + } + + // -- Points of extension + + /** + * Normalizes a user-input list of mailboxes into consistent key=>value pairs. + * + * @param string[] $mailboxes + * + * @return string[] + */ + protected function normalizeMailboxes(array $mailboxes) + { + $actualMailboxes = array(); + + foreach ($mailboxes as $key => $value) { + if (is_string($key)) { + //key is email addr + $address = $key; + $name = $value; + } else { + $address = $value; + $name = null; + } + $this->_assertValidAddress($address); + $actualMailboxes[$address] = $name; + } + + return $actualMailboxes; + } + + /** + * Produces a compliant, formatted display-name based on the string given. + * + * @param string $displayName as displayed + * @param bool $shorten the first line to make remove for header name + * + * @return string + */ + protected function createDisplayNameString($displayName, $shorten = false) + { + return $this->createPhrase($this, $displayName, $this->getCharset(), $this->getEncoder(), $shorten); + } + + /** + * Creates a string form of all the mailboxes in the passed array. + * + * @param string[] $mailboxes + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + protected function createMailboxListString(array $mailboxes) + { + return implode(', ', $this->_createNameAddressStrings($mailboxes)); + } + + /** + * Redefine the encoding requirements for mailboxes. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + * + * @param string $token + * + * @return bool + */ + protected function tokenNeedsEncoding($token) + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } + + /** + * Return an array of strings conforming the the name-addr spec of RFC 2822. + * + * @param string[] $mailboxes + * + * @return string[] + */ + private function _createNameAddressStrings(array $mailboxes) + { + $strings = array(); + + foreach ($mailboxes as $email => $name) { + $mailboxStr = $email; + if (!is_null($name)) { + $nameStr = $this->createDisplayNameString($name, empty($strings)); + $mailboxStr = $nameStr.' <'.$mailboxStr.'>'; + } + $strings[] = $mailboxStr; + } + + return $strings; + } + + /** + * Throws an Exception if the address passed does not comply with RFC 2822. + * + * @param string $address + * + * @throws Swift_RfcComplianceException If invalid. + */ + private function _assertValidAddress($address) + { + if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D', + $address)) { + throw new Swift_RfcComplianceException( + 'Address in mailbox given ['.$address. + '] does not comply with RFC 2822, 3.6.2.' + ); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php new file mode 100644 index 0000000..d749550 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php @@ -0,0 +1,133 @@ + + */ +class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header +{ + /** + * The value of this Header. + * + * @var string + */ + private $_value; + + /** + * The name of this Header. + * + * @var string + */ + private $_fieldName; + + /** + * @param string $name + */ + public function __construct($name) + { + $this->_fieldName = $name; + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_TEXT; + } + + /** + * Set the model for the field body. + * + * This method takes a string for the field value. + * + * @param string $model + */ + public function setFieldBodyModel($model) + { + $this->setValue($model); + } + + /** + * Get the model for the field body. + * + * This method returns a string. + * + * @return string + */ + public function getFieldBodyModel() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + * + * @return string + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the (unencoded) value of this header. + * + * @param string $value + */ + public function setValue($value) + { + $this->_value = $value; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() + { + return $this->_value; + } + + /** + * Get this Header rendered as a RFC 2822 compliant string. + * + * @return string + */ + public function toString() + { + return $this->_fieldName.': '.$this->_value; + } + + /** + * Set the Header FieldName. + * + * @see Swift_Mime_Header::getFieldName() + */ + public function getFieldName() + { + return $this->_fieldName; + } + + /** + * Ignored. + */ + public function setCharset($charset) + { + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/ParameterizedHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/ParameterizedHeader.php new file mode 100644 index 0000000..c506dae --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/ParameterizedHeader.php @@ -0,0 +1,258 @@ +_paramEncoder = $paramEncoder; + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_PARAMETERIZED; + } + + /** + * Set the character set used in this Header. + * + * @param string $charset + */ + public function setCharset($charset) + { + parent::setCharset($charset); + if (isset($this->_paramEncoder)) { + $this->_paramEncoder->charsetChanged($charset); + } + } + + /** + * Set the value of $parameter. + * + * @param string $parameter + * @param string $value + */ + public function setParameter($parameter, $value) + { + $this->setParameters(array_merge($this->getParameters(), array($parameter => $value))); + } + + /** + * Get the value of $parameter. + * + * @param string $parameter + * + * @return string + */ + public function getParameter($parameter) + { + $params = $this->getParameters(); + + return array_key_exists($parameter, $params) ? $params[$parameter] : null; + } + + /** + * Set an associative array of parameter names mapped to values. + * + * @param string[] $parameters + */ + public function setParameters(array $parameters) + { + $this->clearCachedValueIf($this->_params != $parameters); + $this->_params = $parameters; + } + + /** + * Returns an associative array of parameter names mapped to values. + * + * @return string[] + */ + public function getParameters() + { + return $this->_params; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() //TODO: Check caching here + { + $body = parent::getFieldBody(); + foreach ($this->_params as $name => $value) { + if (!is_null($value)) { + // Add the parameter + $body .= '; '.$this->_createParameter($name, $value); + } + } + + return $body; + } + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + * + * @param string $string The string to tokenize + * + * @return array An array of tokens as strings + */ + protected function toTokens($string = null) + { + $tokens = parent::toTokens(parent::getFieldBody()); + + // Try creating any parameters + foreach ($this->_params as $name => $value) { + if (!is_null($value)) { + // Add the semi-colon separator + $tokens[count($tokens) - 1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines( + ' '.$this->_createParameter($name, $value) + )); + } + } + + return $tokens; + } + + /** + * Render a RFC 2047 compliant header parameter from the $name and $value. + * + * @param string $name + * @param string $value + * + * @return string + */ + private function _createParameter($name, $value) + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - strlen($name.'=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^'.$this->getGrammar()->getDefinition('text').'*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - strlen($name.'*N*="";') - 1; + $firstLineOffset = strlen( + $this->getCharset()."'".$this->getLanguage()."'" + ); + } + } + + // Encode if we need to + if ($encoded || strlen($value) > $maxValueLength) { + if (isset($this->_paramEncoder)) { + $value = $this->_paramEncoder->encodeString( + $origValue, $firstLineOffset, $maxValueLength, $this->getCharset() + ); + } else { + // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = isset($this->_paramEncoder) ? explode("\r\n", $value) : array($value); + + // Need to add indices + if (count($valueLines) > 1) { + $paramLines = array(); + foreach ($valueLines as $i => $line) { + $paramLines[] = $name.'*'.$i. + $this->_getEndOfParameterValue($line, true, $i == 0); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name.$this->_getEndOfParameterValue( + $valueLines[0], $encoded, true + ); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + * @param bool $encoded + * @param bool $firstLine + * + * @return string + */ + private function _getEndOfParameterValue($value, $encoded = false, $firstLine = false) + { + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + $value = '"'.$value.'"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*='.$this->getCharset()."'".$this->getLanguage(). + "'"; + } + } + + return $prepend.$value; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/PathHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/PathHeader.php new file mode 100644 index 0000000..2fffc7b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/PathHeader.php @@ -0,0 +1,143 @@ +setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_PATH; + } + + /** + * Set the model for the field body. + * This method takes a string for an address. + * + * @param string $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setAddress($model); + } + + /** + * Get the model for the field body. + * This method returns a string email address. + * + * @return mixed + */ + public function getFieldBodyModel() + { + return $this->getAddress(); + } + + /** + * Set the Address which should appear in this Header. + * + * @param string $address + * + * @throws Swift_RfcComplianceException + */ + public function setAddress($address) + { + if (is_null($address)) { + $this->_address = null; + } elseif ('' == $address) { + $this->_address = ''; + } else { + $this->_assertValidAddress($address); + $this->_address = $address; + } + $this->setCachedValue(null); + } + + /** + * Get the address which is used in this Header (if any). + * + * Null is returned if no address is set. + * + * @return string + */ + public function getAddress() + { + return $this->_address; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + if (isset($this->_address)) { + $this->setCachedValue('<'.$this->_address.'>'); + } + } + + return $this->getCachedValue(); + } + + /** + * Throws an Exception if the address passed does not comply with RFC 2822. + * + * @param string $address + * + * @throws Swift_RfcComplianceException If address is invalid + */ + private function _assertValidAddress($address) + { + if (!preg_match('/^'.$this->getGrammar()->getDefinition('addr-spec').'$/D', + $address)) { + throw new Swift_RfcComplianceException( + 'Address set in PathHeader does not comply with addr-spec of RFC 2822.' + ); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Headers/UnstructuredHeader.php b/lib/SwiftMailer/classes/Swift/Mime/Headers/UnstructuredHeader.php new file mode 100644 index 0000000..86177f1 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Headers/UnstructuredHeader.php @@ -0,0 +1,112 @@ +setFieldName($name); + $this->setEncoder($encoder); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_TEXT; + } + + /** + * Set the model for the field body. + * + * This method takes a string for the field value. + * + * @param string $model + */ + public function setFieldBodyModel($model) + { + $this->setValue($model); + } + + /** + * Get the model for the field body. + * + * This method returns a string. + * + * @return string + */ + public function getFieldBodyModel() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + * + * @return string + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the (unencoded) value of this header. + * + * @param string $value + */ + public function setValue($value) + { + $this->clearCachedValueIf($this->_value != $value); + $this->_value = $value; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + $this->setCachedValue( + $this->encodeWords($this, $this->_value) + ); + } + + return $this->getCachedValue(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/Message.php b/lib/SwiftMailer/classes/Swift/Mime/Message.php new file mode 100644 index 0000000..9b36d21 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/Message.php @@ -0,0 +1,223 @@ + 'Real Name'). + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $address + * @param string $name optional + */ + public function setSender($address, $name = null); + + /** + * Get the sender address for this message. + * + * This has a higher significance than the From address. + * + * @return string + */ + public function getSender(); + + /** + * Set the From address of this message. + * + * It is permissible for multiple From addresses to be set using an array. + * + * If multiple From addresses are used, you SHOULD set the Sender address and + * according to RFC 2822, MUST set the sender address. + * + * An array can be used if display names are to be provided: i.e. + * array('email@address.com' => 'Real Name'). + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setFrom($addresses, $name = null); + + /** + * Get the From address(es) of this message. + * + * This method always returns an associative array where the keys are the + * addresses. + * + * @return string[] + */ + public function getFrom(); + + /** + * Set the Reply-To address(es). + * + * Any replies from the receiver will be sent to this address. + * + * It is permissible for multiple reply-to addresses to be set using an array. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setReplyTo($addresses, $name = null); + + /** + * Get the Reply-To addresses for this message. + * + * This method always returns an associative array where the keys provide the + * email addresses. + * + * @return string[] + */ + public function getReplyTo(); + + /** + * Set the To address(es). + * + * Recipients set in this field will receive a copy of this message. + * + * This method has the same synopsis as {@link setFrom()} and {@link setCc()}. + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setTo($addresses, $name = null); + + /** + * Get the To addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getTo(); + + /** + * Set the Cc address(es). + * + * Recipients set in this field will receive a 'carbon-copy' of this message. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setCc($addresses, $name = null); + + /** + * Get the Cc addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getCc(); + + /** + * Set the Bcc address(es). + * + * Recipients set in this field will receive a 'blind-carbon-copy' of this + * message. + * + * In other words, they will get the message, but any other recipients of the + * message will have no such knowledge of their receipt of it. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setBcc($addresses, $name = null); + + /** + * Get the Bcc addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getBcc(); +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/MimeEntity.php b/lib/SwiftMailer/classes/Swift/Mime/MimeEntity.php new file mode 100644 index 0000000..30f460c --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/MimeEntity.php @@ -0,0 +1,117 @@ +setContentType('text/plain'); + if (!is_null($charset)) { + $this->setCharset($charset); + } + } + + /** + * Set the body of this entity, either as a string, or as an instance of + * {@link Swift_OutputByteStream}. + * + * @param mixed $body + * @param string $contentType optional + * @param string $charset optional + * + * @return Swift_Mime_MimePart + */ + public function setBody($body, $contentType = null, $charset = null) + { + if (isset($charset)) { + $this->setCharset($charset); + } + $body = $this->_convertString($body); + + parent::setBody($body, $contentType); + + return $this; + } + + /** + * Get the character set of this entity. + * + * @return string + */ + public function getCharset() + { + return $this->_getHeaderParameter('Content-Type', 'charset'); + } + + /** + * Set the character set of this entity. + * + * @param string $charset + * + * @return Swift_Mime_MimePart + */ + public function setCharset($charset) + { + $this->_setHeaderParameter('Content-Type', 'charset', $charset); + if ($charset !== $this->_userCharset) { + $this->_clearCache(); + } + $this->_userCharset = $charset; + parent::charsetChanged($charset); + + return $this; + } + + /** + * Get the format of this entity (i.e. flowed or fixed). + * + * @return string + */ + public function getFormat() + { + return $this->_getHeaderParameter('Content-Type', 'format'); + } + + /** + * Set the format of this entity (flowed or fixed). + * + * @param string $format + * + * @return Swift_Mime_MimePart + */ + public function setFormat($format) + { + $this->_setHeaderParameter('Content-Type', 'format', $format); + $this->_userFormat = $format; + + return $this; + } + + /** + * Test if delsp is being used for this entity. + * + * @return bool + */ + public function getDelSp() + { + return 'yes' == $this->_getHeaderParameter('Content-Type', 'delsp') ? true : false; + } + + /** + * Turn delsp on or off for this entity. + * + * @param bool $delsp + * + * @return Swift_Mime_MimePart + */ + public function setDelSp($delsp = true) + { + $this->_setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null); + $this->_userDelSp = $delsp; + + return $this; + } + + /** + * Get the nesting level of this entity. + * + * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED + * + * @return int + */ + public function getNestingLevel() + { + return $this->_nestingLevel; + } + + /** + * Receive notification that the charset has changed on this document, or a + * parent document. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->setCharset($charset); + } + + /** Fix the content-type and encoding of this entity */ + protected function _fixHeaders() + { + parent::_fixHeaders(); + if (count($this->getChildren())) { + $this->_setHeaderParameter('Content-Type', 'charset', null); + $this->_setHeaderParameter('Content-Type', 'format', null); + $this->_setHeaderParameter('Content-Type', 'delsp', null); + } else { + $this->setCharset($this->_userCharset); + $this->setFormat($this->_userFormat); + $this->setDelSp($this->_userDelSp); + } + } + + /** Set the nesting level of this entity */ + protected function _setNestingLevel($level) + { + $this->_nestingLevel = $level; + } + + /** Encode charset when charset is not utf-8 */ + protected function _convertString($string) + { + $charset = strtolower($this->getCharset()); + if (!in_array($charset, array('utf-8', 'iso-8859-1', 'iso-8859-15', ''))) { + // mb_convert_encoding must be the first one to check, since iconv cannot convert some words. + if (function_exists('mb_convert_encoding')) { + $string = mb_convert_encoding($string, $charset, 'utf-8'); + } elseif (function_exists('iconv')) { + $string = iconv('utf-8//TRANSLIT//IGNORE', $charset, $string); + } else { + throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your charset or install the mbstring or iconv extension).'); + } + + return $string; + } + + return $string; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/ParameterizedHeader.php b/lib/SwiftMailer/classes/Swift/Mime/ParameterizedHeader.php new file mode 100644 index 0000000..e15c6ef --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/ParameterizedHeader.php @@ -0,0 +1,34 @@ +_encoder = $encoder; + $this->_paramEncoder = $paramEncoder; + $this->_grammar = $grammar; + $this->_charset = $charset; + } + + /** + * Create a new Mailbox Header with a list of $addresses. + * + * @param string $name + * @param array|string|null $addresses + * + * @return Swift_Mime_Header + */ + public function createMailboxHeader($name, $addresses = null) + { + $header = new Swift_Mime_Headers_MailboxHeader($name, $this->_encoder, $this->_grammar); + if (isset($addresses)) { + $header->setFieldBodyModel($addresses); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Date header using $timestamp (UNIX time). + * + * @param string $name + * @param int|null $timestamp + * + * @return Swift_Mime_Header + */ + public function createDateHeader($name, $timestamp = null) + { + $header = new Swift_Mime_Headers_DateHeader($name, $this->_grammar); + if (isset($timestamp)) { + $header->setFieldBodyModel($timestamp); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new basic text header with $name and $value. + * + * @param string $name + * @param string $value + * + * @return Swift_Mime_Header + */ + public function createTextHeader($name, $value = null) + { + $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->_encoder, $this->_grammar); + if (isset($value)) { + $header->setFieldBodyModel($value); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new ParameterizedHeader with $name, $value and $params. + * + * @param string $name + * @param string $value + * @param array $params + * + * @return Swift_Mime_ParameterizedHeader + */ + public function createParameterizedHeader($name, $value = null, + $params = array()) + { + $header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->_encoder, strtolower($name) == 'content-disposition' ? $this->_paramEncoder : null, $this->_grammar); + if (isset($value)) { + $header->setFieldBodyModel($value); + } + foreach ($params as $k => $v) { + $header->setParameter($k, $v); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new ID header for Message-ID or Content-ID. + * + * @param string $name + * @param string|array $ids + * + * @return Swift_Mime_Header + */ + public function createIdHeader($name, $ids = null) + { + $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->_grammar); + if (isset($ids)) { + $header->setFieldBodyModel($ids); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Path header with an address (path) in it. + * + * @param string $name + * @param string $path + * + * @return Swift_Mime_Header + */ + public function createPathHeader($name, $path = null) + { + $header = new Swift_Mime_Headers_PathHeader($name, $this->_grammar); + if (isset($path)) { + $header->setFieldBodyModel($path); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charset = $charset; + $this->_encoder->charsetChanged($charset); + $this->_paramEncoder->charsetChanged($charset); + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_encoder = clone $this->_encoder; + $this->_paramEncoder = clone $this->_paramEncoder; + } + + /** Apply the charset to the Header */ + private function _setHeaderCharset(Swift_Mime_Header $header) + { + if (isset($this->_charset)) { + $header->setCharset($this->_charset); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/SimpleHeaderSet.php b/lib/SwiftMailer/classes/Swift/Mime/SimpleHeaderSet.php new file mode 100644 index 0000000..e2d0e87 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/SimpleHeaderSet.php @@ -0,0 +1,414 @@ +_factory = $factory; + if (isset($charset)) { + $this->setCharset($charset); + } + } + + /** + * Set the charset used by these headers. + * + * @param string $charset + */ + public function setCharset($charset) + { + $this->_charset = $charset; + $this->_factory->charsetChanged($charset); + $this->_notifyHeadersOfCharset($charset); + } + + /** + * Add a new Mailbox Header with a list of $addresses. + * + * @param string $name + * @param array|string $addresses + */ + public function addMailboxHeader($name, $addresses = null) + { + $this->_storeHeader($name, + $this->_factory->createMailboxHeader($name, $addresses)); + } + + /** + * Add a new Date header using $timestamp (UNIX time). + * + * @param string $name + * @param int $timestamp + */ + public function addDateHeader($name, $timestamp = null) + { + $this->_storeHeader($name, + $this->_factory->createDateHeader($name, $timestamp)); + } + + /** + * Add a new basic text header with $name and $value. + * + * @param string $name + * @param string $value + */ + public function addTextHeader($name, $value = null) + { + $this->_storeHeader($name, + $this->_factory->createTextHeader($name, $value)); + } + + /** + * Add a new ParameterizedHeader with $name, $value and $params. + * + * @param string $name + * @param string $value + * @param array $params + */ + public function addParameterizedHeader($name, $value = null, $params = array()) + { + $this->_storeHeader($name, $this->_factory->createParameterizedHeader($name, $value, $params)); + } + + /** + * Add a new ID header for Message-ID or Content-ID. + * + * @param string $name + * @param string|array $ids + */ + public function addIdHeader($name, $ids = null) + { + $this->_storeHeader($name, $this->_factory->createIdHeader($name, $ids)); + } + + /** + * Add a new Path header with an address (path) in it. + * + * @param string $name + * @param string $path + */ + public function addPathHeader($name, $path = null) + { + $this->_storeHeader($name, $this->_factory->createPathHeader($name, $path)); + } + + /** + * Returns true if at least one header with the given $name exists. + * + * If multiple headers match, the actual one may be specified by $index. + * + * @param string $name + * @param int $index + * + * @return bool + */ + public function has($name, $index = 0) + { + $lowerName = strtolower($name); + + if (!array_key_exists($lowerName, $this->_headers)) { + return false; + } + + if (func_num_args() < 2) { + // index was not specified, so we only need to check that there is at least one header value set + return (bool) count($this->_headers[$lowerName]); + } + + return array_key_exists($index, $this->_headers[$lowerName]); + } + + /** + * Set a header in the HeaderSet. + * + * The header may be a previously fetched header via {@link get()} or it may + * be one that has been created separately. + * + * If $index is specified, the header will be inserted into the set at this + * offset. + * + * @param Swift_Mime_Header $header + * @param int $index + */ + public function set(Swift_Mime_Header $header, $index = 0) + { + $this->_storeHeader($header->getFieldName(), $header, $index); + } + + /** + * Get the header with the given $name. + * + * If multiple headers match, the actual one may be specified by $index. + * Returns NULL if none present. + * + * @param string $name + * @param int $index + * + * @return Swift_Mime_Header + */ + public function get($name, $index = 0) + { + $name = strtolower($name); + + if (func_num_args() < 2) { + if ($this->has($name)) { + $values = array_values($this->_headers[$name]); + + return array_shift($values); + } + } else { + if ($this->has($name, $index)) { + return $this->_headers[$name][$index]; + } + } + } + + /** + * Get all headers with the given $name. + * + * @param string $name + * + * @return array + */ + public function getAll($name = null) + { + if (!isset($name)) { + $headers = array(); + foreach ($this->_headers as $collection) { + $headers = array_merge($headers, $collection); + } + + return $headers; + } + + $lowerName = strtolower($name); + if (!array_key_exists($lowerName, $this->_headers)) { + return array(); + } + + return $this->_headers[$lowerName]; + } + + /** + * Return the name of all Headers. + * + * @return array + */ + public function listAll() + { + $headers = $this->_headers; + if ($this->_canSort()) { + uksort($headers, array($this, '_sortHeaders')); + } + + return array_keys($headers); + } + + /** + * Remove the header with the given $name if it's set. + * + * If multiple headers match, the actual one may be specified by $index. + * + * @param string $name + * @param int $index + */ + public function remove($name, $index = 0) + { + $lowerName = strtolower($name); + unset($this->_headers[$lowerName][$index]); + } + + /** + * Remove all headers with the given $name. + * + * @param string $name + */ + public function removeAll($name) + { + $lowerName = strtolower($name); + unset($this->_headers[$lowerName]); + } + + /** + * Create a new instance of this HeaderSet. + * + * @return Swift_Mime_HeaderSet + */ + public function newInstance() + { + return new self($this->_factory); + } + + /** + * Define a list of Header names as an array in the correct order. + * + * These Headers will be output in the given order where present. + * + * @param array $sequence + */ + public function defineOrdering(array $sequence) + { + $this->_order = array_flip(array_map('strtolower', $sequence)); + } + + /** + * Set a list of header names which must always be displayed when set. + * + * Usually headers without a field value won't be output unless set here. + * + * @param array $names + */ + public function setAlwaysDisplayed(array $names) + { + $this->_required = array_flip(array_map('strtolower', $names)); + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->setCharset($charset); + } + + /** + * Returns a string with a representation of all headers. + * + * @return string + */ + public function toString() + { + $string = ''; + $headers = $this->_headers; + if ($this->_canSort()) { + uksort($headers, array($this, '_sortHeaders')); + } + foreach ($headers as $collection) { + foreach ($collection as $header) { + if ($this->_isDisplayed($header) || $header->getFieldBody() != '') { + $string .= $header->toString(); + } + } + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @return string + * + * @see toString() + */ + public function __toString() + { + return $this->toString(); + } + + /** Save a Header to the internal collection */ + private function _storeHeader($name, Swift_Mime_Header $header, $offset = null) + { + if (!isset($this->_headers[strtolower($name)])) { + $this->_headers[strtolower($name)] = array(); + } + if (!isset($offset)) { + $this->_headers[strtolower($name)][] = $header; + } else { + $this->_headers[strtolower($name)][$offset] = $header; + } + } + + /** Test if the headers can be sorted */ + private function _canSort() + { + return count($this->_order) > 0; + } + + /** uksort() algorithm for Header ordering */ + private function _sortHeaders($a, $b) + { + $lowerA = strtolower($a); + $lowerB = strtolower($b); + $aPos = array_key_exists($lowerA, $this->_order) ? $this->_order[$lowerA] : -1; + $bPos = array_key_exists($lowerB, $this->_order) ? $this->_order[$lowerB] : -1; + + if (-1 === $aPos && -1 === $bPos) { + // just be sure to be determinist here + return $a > $b ? -1 : 1; + } + + if ($aPos == -1) { + return 1; + } elseif ($bPos == -1) { + return -1; + } + + return $aPos < $bPos ? -1 : 1; + } + + /** Test if the given Header is always displayed */ + private function _isDisplayed(Swift_Mime_Header $header) + { + return array_key_exists(strtolower($header->getFieldName()), $this->_required); + } + + /** Notify all Headers of the new charset */ + private function _notifyHeadersOfCharset($charset) + { + foreach ($this->_headers as $headerGroup) { + foreach ($headerGroup as $header) { + $header->setCharset($charset); + } + } + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_factory = clone $this->_factory; + foreach ($this->_headers as $groupKey => $headerGroup) { + foreach ($headerGroup as $key => $header) { + $this->_headers[$groupKey][$key] = clone $header; + } + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/SimpleMessage.php b/lib/SwiftMailer/classes/Swift/Mime/SimpleMessage.php new file mode 100644 index 0000000..124644b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/SimpleMessage.php @@ -0,0 +1,649 @@ +getHeaders()->defineOrdering(array( + 'Return-Path', + 'Received', + 'DKIM-Signature', + 'DomainKey-Signature', + 'Sender', + 'Message-ID', + 'Date', + 'Subject', + 'From', + 'Reply-To', + 'To', + 'Cc', + 'Bcc', + 'MIME-Version', + 'Content-Type', + 'Content-Transfer-Encoding', + )); + $this->getHeaders()->setAlwaysDisplayed(array('Date', 'Message-ID', 'From')); + $this->getHeaders()->addTextHeader('MIME-Version', '1.0'); + $this->setDate(time()); + $this->setId($this->getId()); + $this->getHeaders()->addMailboxHeader('From'); + } + + /** + * Always returns {@link LEVEL_TOP} for a message instance. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_TOP; + } + + /** + * Set the subject of this message. + * + * @param string $subject + * + * @return Swift_Mime_SimpleMessage + */ + public function setSubject($subject) + { + if (!$this->_setHeaderFieldModel('Subject', $subject)) { + $this->getHeaders()->addTextHeader('Subject', $subject); + } + + return $this; + } + + /** + * Get the subject of this message. + * + * @return string + */ + public function getSubject() + { + return $this->_getHeaderFieldModel('Subject'); + } + + /** + * Set the date at which this message was created. + * + * @param int $date + * + * @return Swift_Mime_SimpleMessage + */ + public function setDate($date) + { + if (!$this->_setHeaderFieldModel('Date', $date)) { + $this->getHeaders()->addDateHeader('Date', $date); + } + + return $this; + } + + /** + * Get the date at which this message was created. + * + * @return int + */ + public function getDate() + { + return $this->_getHeaderFieldModel('Date'); + } + + /** + * Set the return-path (the bounce address) of this message. + * + * @param string $address + * + * @return Swift_Mime_SimpleMessage + */ + public function setReturnPath($address) + { + if (!$this->_setHeaderFieldModel('Return-Path', $address)) { + $this->getHeaders()->addPathHeader('Return-Path', $address); + } + + return $this; + } + + /** + * Get the return-path (bounce address) of this message. + * + * @return string + */ + public function getReturnPath() + { + return $this->_getHeaderFieldModel('Return-Path'); + } + + /** + * Set the sender of this message. + * + * This does not override the From field, but it has a higher significance. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setSender($address, $name = null) + { + if (!is_array($address) && isset($name)) { + $address = array($address => $name); + } + + if (!$this->_setHeaderFieldModel('Sender', (array) $address)) { + $this->getHeaders()->addMailboxHeader('Sender', (array) $address); + } + + return $this; + } + + /** + * Get the sender of this message. + * + * @return string + */ + public function getSender() + { + return $this->_getHeaderFieldModel('Sender'); + } + + /** + * Add a From: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addFrom($address, $name = null) + { + $current = $this->getFrom(); + $current[$address] = $name; + + return $this->setFrom($current); + } + + /** + * Set the from address of this message. + * + * You may pass an array of addresses if this message is from multiple people. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param string|array $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setFrom($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('From', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('From', (array) $addresses); + } + + return $this; + } + + /** + * Get the from address of this message. + * + * @return mixed + */ + public function getFrom() + { + return $this->_getHeaderFieldModel('From'); + } + + /** + * Add a Reply-To: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addReplyTo($address, $name = null) + { + $current = $this->getReplyTo(); + $current[$address] = $name; + + return $this->setReplyTo($current); + } + + /** + * Set the reply-to address of this message. + * + * You may pass an array of addresses if replies will go to multiple people. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setReplyTo($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Reply-To', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses); + } + + return $this; + } + + /** + * Get the reply-to address of this message. + * + * @return string + */ + public function getReplyTo() + { + return $this->_getHeaderFieldModel('Reply-To'); + } + + /** + * Add a To: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addTo($address, $name = null) + { + $current = $this->getTo(); + $current[$address] = $name; + + return $this->setTo($current); + } + + /** + * Set the to addresses of this message. + * + * If multiple recipients will receive the message an array should be used. + * Example: array('receiver@domain.org', 'other@domain.org' => 'A name') + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setTo($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('To', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('To', (array) $addresses); + } + + return $this; + } + + /** + * Get the To addresses of this message. + * + * @return array + */ + public function getTo() + { + return $this->_getHeaderFieldModel('To'); + } + + /** + * Add a Cc: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addCc($address, $name = null) + { + $current = $this->getCc(); + $current[$address] = $name; + + return $this->setCc($current); + } + + /** + * Set the Cc addresses of this message. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setCc($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Cc', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses); + } + + return $this; + } + + /** + * Get the Cc address of this message. + * + * @return array + */ + public function getCc() + { + return $this->_getHeaderFieldModel('Cc'); + } + + /** + * Add a Bcc: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addBcc($address, $name = null) + { + $current = $this->getBcc(); + $current[$address] = $name; + + return $this->setBcc($current); + } + + /** + * Set the Bcc addresses of this message. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setBcc($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Bcc', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses); + } + + return $this; + } + + /** + * Get the Bcc addresses of this message. + * + * @return array + */ + public function getBcc() + { + return $this->_getHeaderFieldModel('Bcc'); + } + + /** + * Set the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @param int $priority + * + * @return Swift_Mime_SimpleMessage + */ + public function setPriority($priority) + { + $priorityMap = array( + 1 => 'Highest', + 2 => 'High', + 3 => 'Normal', + 4 => 'Low', + 5 => 'Lowest', + ); + $pMapKeys = array_keys($priorityMap); + if ($priority > max($pMapKeys)) { + $priority = max($pMapKeys); + } elseif ($priority < min($pMapKeys)) { + $priority = min($pMapKeys); + } + if (!$this->_setHeaderFieldModel('X-Priority', + sprintf('%d (%s)', $priority, $priorityMap[$priority]))) { + $this->getHeaders()->addTextHeader('X-Priority', + sprintf('%d (%s)', $priority, $priorityMap[$priority])); + } + + return $this; + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + * + * @return int + */ + public function getPriority() + { + list($priority) = sscanf($this->_getHeaderFieldModel('X-Priority'), + '%[1-5]' + ); + + return isset($priority) ? $priority : 3; + } + + /** + * Ask for a delivery receipt from the recipient to be sent to $addresses. + * + * @param array $addresses + * + * @return Swift_Mime_SimpleMessage + */ + public function setReadReceiptTo($addresses) + { + if (!$this->_setHeaderFieldModel('Disposition-Notification-To', $addresses)) { + $this->getHeaders() + ->addMailboxHeader('Disposition-Notification-To', $addresses); + } + + return $this; + } + + /** + * Get the addresses to which a read-receipt will be sent. + * + * @return string + */ + public function getReadReceiptTo() + { + return $this->_getHeaderFieldModel('Disposition-Notification-To'); + } + + /** + * Attach a {@link Swift_Mime_MimeEntity} such as an Attachment or MimePart. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return Swift_Mime_SimpleMessage + */ + public function attach(Swift_Mime_MimeEntity $entity) + { + $this->setChildren(array_merge($this->getChildren(), array($entity))); + + return $this; + } + + /** + * Remove an already attached entity. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return Swift_Mime_SimpleMessage + */ + public function detach(Swift_Mime_MimeEntity $entity) + { + $newChildren = array(); + foreach ($this->getChildren() as $child) { + if ($entity !== $child) { + $newChildren[] = $child; + } + } + $this->setChildren($newChildren); + + return $this; + } + + /** + * Attach a {@link Swift_Mime_MimeEntity} and return it's CID source. + * This method should be used when embedding images or other data in a message. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return string + */ + public function embed(Swift_Mime_MimeEntity $entity) + { + $this->attach($entity); + + return 'cid:'.$entity->getId(); + } + + /** + * Get this message as a complete string. + * + * @return string + */ + public function toString() + { + if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); + $string = parent::toString(); + $this->setChildren($children); + } else { + $string = parent::toString(); + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @see toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Write this message to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream $is + */ + public function toByteStream(Swift_InputByteStream $is) + { + if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); + parent::toByteStream($is); + $this->setChildren($children); + } else { + parent::toByteStream($is); + } + } + + /** @see Swift_Mime_SimpleMimeEntity::_getIdField() */ + protected function _getIdField() + { + return 'Message-ID'; + } + + /** Turn the body of this message into a child of itself if needed */ + protected function _becomeMimePart() + { + $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(), + $this->_getCache(), $this->_getGrammar(), $this->_userCharset + ); + $part->setContentType($this->_userContentType); + $part->setBody($this->getBody()); + $part->setFormat($this->_userFormat); + $part->setDelSp($this->_userDelSp); + $part->_setNestingLevel($this->_getTopNestingLevel()); + + return $part; + } + + /** Get the highest nesting level nested inside this message */ + private function _getTopNestingLevel() + { + $highestLevel = $this->getNestingLevel(); + foreach ($this->getChildren() as $child) { + $childLevel = $child->getNestingLevel(); + if ($highestLevel < $childLevel) { + $highestLevel = $childLevel; + } + } + + return $highestLevel; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Mime/SimpleMimeEntity.php b/lib/SwiftMailer/classes/Swift/Mime/SimpleMimeEntity.php new file mode 100644 index 0000000..0694ee1 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Mime/SimpleMimeEntity.php @@ -0,0 +1,843 @@ + array(self::LEVEL_TOP, self::LEVEL_MIXED), + 'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE), + 'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED), + ); + + /** A set of filter rules to define what level an entity should be nested at */ + private $_compoundLevelFilters = array(); + + /** The nesting level of this entity */ + private $_nestingLevel = self::LEVEL_ALTERNATIVE; + + /** A KeyCache instance used during encoding and streaming */ + private $_cache; + + /** Direct descendants of this entity */ + private $_immediateChildren = array(); + + /** All descendants of this entity */ + private $_children = array(); + + /** The maximum line length of the body of this entity */ + private $_maxLineLength = 78; + + /** The order in which alternative mime types should appear */ + private $_alternativePartOrder = array( + 'text/plain' => 1, + 'text/html' => 2, + 'multipart/related' => 3, + ); + + /** The CID of this entity */ + private $_id; + + /** The key used for accessing the cache */ + private $_cacheKey; + + protected $_userContentType; + + /** + * Create a new SimpleMimeEntity with $headers, $encoder and $cache. + * + * @param Swift_Mime_HeaderSet $headers + * @param Swift_Mime_ContentEncoder $encoder + * @param Swift_KeyCache $cache + * @param Swift_Mime_Grammar $grammar + */ + public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar) + { + $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); + $this->_cache = $cache; + $this->_headers = $headers; + $this->_grammar = $grammar; + $this->setEncoder($encoder); + $this->_headers->defineOrdering(array('Content-Type', 'Content-Transfer-Encoding')); + + // This array specifies that, when the entire MIME document contains + // $compoundLevel, then for each child within $level, if its Content-Type + // is $contentType then it should be treated as if it's level is + // $neededLevel instead. I tried to write that unambiguously! :-\ + // Data Structure: + // array ( + // $compoundLevel => array( + // $level => array( + // $contentType => $neededLevel + // ) + // ) + // ) + + $this->_compoundLevelFilters = array( + (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array( + self::LEVEL_ALTERNATIVE => array( + 'text/plain' => self::LEVEL_ALTERNATIVE, + 'text/html' => self::LEVEL_RELATED, + ), + ), + ); + + $this->_id = $this->getRandomId(); + } + + /** + * Generate a new Content-ID or Message-ID for this MIME entity. + * + * @return string + */ + public function generateId() + { + $this->setId($this->getRandomId()); + + return $this->_id; + } + + /** + * Get the {@link Swift_Mime_HeaderSet} for this entity. + * + * @return Swift_Mime_HeaderSet + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Get the nesting level of this entity. + * + * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE + * + * @return int + */ + public function getNestingLevel() + { + return $this->_nestingLevel; + } + + /** + * Get the Content-type of this entity. + * + * @return string + */ + public function getContentType() + { + return $this->_getHeaderFieldModel('Content-Type'); + } + + /** + * Set the Content-type of this entity. + * + * @param string $type + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setContentType($type) + { + $this->_setContentTypeInHeaders($type); + // Keep track of the value so that if the content-type changes automatically + // due to added child entities, it can be restored if they are later removed + $this->_userContentType = $type; + + return $this; + } + + /** + * Get the CID of this entity. + * + * The CID will only be present in headers if a Content-ID header is present. + * + * @return string + */ + public function getId() + { + $tmp = (array) $this->_getHeaderFieldModel($this->_getIdField()); + + return $this->_headers->has($this->_getIdField()) ? current($tmp) : $this->_id; + } + + /** + * Set the CID of this entity. + * + * @param string $id + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setId($id) + { + if (!$this->_setHeaderFieldModel($this->_getIdField(), $id)) { + $this->_headers->addIdHeader($this->_getIdField(), $id); + } + $this->_id = $id; + + return $this; + } + + /** + * Get the description of this entity. + * + * This value comes from the Content-Description header if set. + * + * @return string + */ + public function getDescription() + { + return $this->_getHeaderFieldModel('Content-Description'); + } + + /** + * Set the description of this entity. + * + * This method sets a value in the Content-ID header. + * + * @param string $description + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setDescription($description) + { + if (!$this->_setHeaderFieldModel('Content-Description', $description)) { + $this->_headers->addTextHeader('Content-Description', $description); + } + + return $this; + } + + /** + * Get the maximum line length of the body of this entity. + * + * @return int + */ + public function getMaxLineLength() + { + return $this->_maxLineLength; + } + + /** + * Set the maximum line length of lines in this body. + * + * Though not enforced by the library, lines should not exceed 1000 chars. + * + * @param int $length + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setMaxLineLength($length) + { + $this->_maxLineLength = $length; + + return $this; + } + + /** + * Get all children added to this entity. + * + * @return Swift_Mime_MimeEntity[] + */ + public function getChildren() + { + return $this->_children; + } + + /** + * Set all children of this entity. + * + * @param Swift_Mime_MimeEntity[] $children + * @param int $compoundLevel For internal use only + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setChildren(array $children, $compoundLevel = null) + { + // TODO: Try to refactor this logic + + $compoundLevel = isset($compoundLevel) ? $compoundLevel : $this->_getCompoundLevel($children); + $immediateChildren = array(); + $grandchildren = array(); + $newContentType = $this->_userContentType; + + foreach ($children as $child) { + $level = $this->_getNeededChildLevel($child, $compoundLevel); + if (empty($immediateChildren)) { + //first iteration + $immediateChildren = array($child); + } else { + $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); + if ($nextLevel == $level) { + $immediateChildren[] = $child; + } elseif ($level < $nextLevel) { + // Re-assign immediateChildren to grandchildren + $grandchildren = array_merge($grandchildren, $immediateChildren); + // Set new children + $immediateChildren = array($child); + } else { + $grandchildren[] = $child; + } + } + } + + if ($immediateChildren) { + $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); + + // Determine which composite media type is needed to accommodate the + // immediate children + foreach ($this->_compositeRanges as $mediaType => $range) { + if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) { + $newContentType = $mediaType; + + break; + } + } + + // Put any grandchildren in a subpart + if (!empty($grandchildren)) { + $subentity = $this->_createChild(); + $subentity->_setNestingLevel($lowestLevel); + $subentity->setChildren($grandchildren, $compoundLevel); + array_unshift($immediateChildren, $subentity); + } + } + + $this->_immediateChildren = $immediateChildren; + $this->_children = $children; + $this->_setContentTypeInHeaders($newContentType); + $this->_fixHeaders(); + $this->_sortChildren(); + + return $this; + } + + /** + * Get the body of this entity as a string. + * + * @return string + */ + public function getBody() + { + return $this->_body instanceof Swift_OutputByteStream ? $this->_readStream($this->_body) : $this->_body; + } + + /** + * Set the body of this entity, either as a string, or as an instance of + * {@link Swift_OutputByteStream}. + * + * @param mixed $body + * @param string $contentType optional + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setBody($body, $contentType = null) + { + if ($body !== $this->_body) { + $this->_clearCache(); + } + + $this->_body = $body; + if (isset($contentType)) { + $this->setContentType($contentType); + } + + return $this; + } + + /** + * Get the encoder used for the body of this entity. + * + * @return Swift_Mime_ContentEncoder + */ + public function getEncoder() + { + return $this->_encoder; + } + + /** + * Set the encoder used for the body of this entity. + * + * @param Swift_Mime_ContentEncoder $encoder + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setEncoder(Swift_Mime_ContentEncoder $encoder) + { + if ($encoder !== $this->_encoder) { + $this->_clearCache(); + } + + $this->_encoder = $encoder; + $this->_setEncoding($encoder->getName()); + $this->_notifyEncoderChanged($encoder); + + return $this; + } + + /** + * Get the boundary used to separate children in this entity. + * + * @return string + */ + public function getBoundary() + { + if (!isset($this->_boundary)) { + $this->_boundary = '_=_swift_v4_'.time().'_'.md5(getmypid().mt_rand().uniqid('', true)).'_=_'; + } + + return $this->_boundary; + } + + /** + * Set the boundary used to separate children in this entity. + * + * @param string $boundary + * + * @throws Swift_RfcComplianceException + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setBoundary($boundary) + { + $this->_assertValidBoundary($boundary); + $this->_boundary = $boundary; + + return $this; + } + + /** + * Receive notification that the charset of this entity, or a parent entity + * has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_notifyCharsetChanged($charset); + } + + /** + * Receive notification that the encoder of this entity or a parent entity + * has changed. + * + * @param Swift_Mime_ContentEncoder $encoder + */ + public function encoderChanged(Swift_Mime_ContentEncoder $encoder) + { + $this->_notifyEncoderChanged($encoder); + } + + /** + * Get this entire entity as a string. + * + * @return string + */ + public function toString() + { + $string = $this->_headers->toString(); + $string .= $this->_bodyToString(); + + return $string; + } + + /** + * Get this entire entity as a string. + * + * @return string + */ + protected function _bodyToString() + { + $string = ''; + + if (isset($this->_body) && empty($this->_immediateChildren)) { + if ($this->_cache->hasKey($this->_cacheKey, 'body')) { + $body = $this->_cache->getString($this->_cacheKey, 'body'); + } else { + $body = "\r\n".$this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()); + $this->_cache->setString($this->_cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE); + } + $string .= $body; + } + + if (!empty($this->_immediateChildren)) { + foreach ($this->_immediateChildren as $child) { + $string .= "\r\n\r\n--".$this->getBoundary()."\r\n"; + $string .= $child->toString(); + } + $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n"; + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @see toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Write this entire entity to a {@see Swift_InputByteStream}. + * + * @param Swift_InputByteStream + */ + public function toByteStream(Swift_InputByteStream $is) + { + $is->write($this->_headers->toString()); + $is->commit(); + + $this->_bodyToByteStream($is); + } + + /** + * Write this entire entity to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream + */ + protected function _bodyToByteStream(Swift_InputByteStream $is) + { + if (empty($this->_immediateChildren)) { + if (isset($this->_body)) { + if ($this->_cache->hasKey($this->_cacheKey, 'body')) { + $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is); + } else { + $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body'); + if ($cacheIs) { + $is->bind($cacheIs); + } + + $is->write("\r\n"); + + if ($this->_body instanceof Swift_OutputByteStream) { + $this->_body->setReadPointer(0); + + $this->_encoder->encodeByteStream($this->_body, $is, 0, $this->getMaxLineLength()); + } else { + $is->write($this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength())); + } + + if ($cacheIs) { + $is->unbind($cacheIs); + } + } + } + } + + if (!empty($this->_immediateChildren)) { + foreach ($this->_immediateChildren as $child) { + $is->write("\r\n\r\n--".$this->getBoundary()."\r\n"); + $child->toByteStream($is); + } + $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n"); + } + } + + /** + * Get the name of the header that provides the ID of this entity. + */ + protected function _getIdField() + { + return 'Content-ID'; + } + + /** + * Get the model data (usually an array or a string) for $field. + */ + protected function _getHeaderFieldModel($field) + { + if ($this->_headers->has($field)) { + return $this->_headers->get($field)->getFieldBodyModel(); + } + } + + /** + * Set the model data for $field. + */ + protected function _setHeaderFieldModel($field, $model) + { + if ($this->_headers->has($field)) { + $this->_headers->get($field)->setFieldBodyModel($model); + + return true; + } + + return false; + } + + /** + * Get the parameter value of $parameter on $field header. + */ + protected function _getHeaderParameter($field, $parameter) + { + if ($this->_headers->has($field)) { + return $this->_headers->get($field)->getParameter($parameter); + } + } + + /** + * Set the parameter value of $parameter on $field header. + */ + protected function _setHeaderParameter($field, $parameter, $value) + { + if ($this->_headers->has($field)) { + $this->_headers->get($field)->setParameter($parameter, $value); + + return true; + } + + return false; + } + + /** + * Re-evaluate what content type and encoding should be used on this entity. + */ + protected function _fixHeaders() + { + if (count($this->_immediateChildren)) { + $this->_setHeaderParameter('Content-Type', 'boundary', + $this->getBoundary() + ); + $this->_headers->remove('Content-Transfer-Encoding'); + } else { + $this->_setHeaderParameter('Content-Type', 'boundary', null); + $this->_setEncoding($this->_encoder->getName()); + } + } + + /** + * Get the KeyCache used in this entity. + * + * @return Swift_KeyCache + */ + protected function _getCache() + { + return $this->_cache; + } + + /** + * Get the grammar used for validation. + * + * @return Swift_Mime_Grammar + */ + protected function _getGrammar() + { + return $this->_grammar; + } + + /** + * Empty the KeyCache for this entity. + */ + protected function _clearCache() + { + $this->_cache->clearKey($this->_cacheKey, 'body'); + } + + /** + * Returns a random Content-ID or Message-ID. + * + * @return string + */ + protected function getRandomId() + { + $idLeft = md5(getmypid().'.'.time().'.'.uniqid(mt_rand(), true)); + $idRight = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated'; + $id = $idLeft.'@'.$idRight; + + try { + $this->_assertValidId($id); + } catch (Swift_RfcComplianceException $e) { + $id = $idLeft.'@swift.generated'; + } + + return $id; + } + + private function _readStream(Swift_OutputByteStream $os) + { + $string = ''; + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + $os->setReadPointer(0); + + return $string; + } + + private function _setEncoding($encoding) + { + if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) { + $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding); + } + } + + private function _assertValidBoundary($boundary) + { + if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) { + throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.'); + } + } + + private function _setContentTypeInHeaders($type) + { + if (!$this->_setHeaderFieldModel('Content-Type', $type)) { + $this->_headers->addParameterizedHeader('Content-Type', $type); + } + } + + private function _setNestingLevel($level) + { + $this->_nestingLevel = $level; + } + + private function _getCompoundLevel($children) + { + $level = 0; + foreach ($children as $child) { + $level |= $child->getNestingLevel(); + } + + return $level; + } + + private function _getNeededChildLevel($child, $compoundLevel) + { + $filter = array(); + foreach ($this->_compoundLevelFilters as $bitmask => $rules) { + if (($compoundLevel & $bitmask) === $bitmask) { + $filter = $rules + $filter; + } + } + + $realLevel = $child->getNestingLevel(); + $lowercaseType = strtolower($child->getContentType()); + + if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) { + return $filter[$realLevel][$lowercaseType]; + } + + return $realLevel; + } + + private function _createChild() + { + return new self($this->_headers->newInstance(), $this->_encoder, $this->_cache, $this->_grammar); + } + + private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder) + { + foreach ($this->_immediateChildren as $child) { + $child->encoderChanged($encoder); + } + } + + private function _notifyCharsetChanged($charset) + { + $this->_encoder->charsetChanged($charset); + $this->_headers->charsetChanged($charset); + foreach ($this->_immediateChildren as $child) { + $child->charsetChanged($charset); + } + } + + private function _sortChildren() + { + $shouldSort = false; + foreach ($this->_immediateChildren as $child) { + // NOTE: This include alternative parts moved into a related part + if ($child->getNestingLevel() == self::LEVEL_ALTERNATIVE) { + $shouldSort = true; + break; + } + } + + // Sort in order of preference, if there is one + if ($shouldSort) { + usort($this->_immediateChildren, array($this, '_childSortAlgorithm')); + } + } + + private function _childSortAlgorithm($a, $b) + { + $typePrefs = array(); + $types = array(strtolower($a->getContentType()), strtolower($b->getContentType())); + + foreach ($types as $type) { + $typePrefs[] = array_key_exists($type, $this->_alternativePartOrder) ? $this->_alternativePartOrder[$type] : max($this->_alternativePartOrder) + 1; + } + + return $typePrefs[0] >= $typePrefs[1] ? 1 : -1; + } + + // -- Destructor + + /** + * Empties it's own contents from the cache. + */ + public function __destruct() + { + $this->_cache->clearAll($this->_cacheKey); + } + + /** + * Throws an Exception if the id passed does not comply with RFC 2822. + * + * @param string $id + * + * @throws Swift_RfcComplianceException + */ + private function _assertValidId($id) + { + if (!preg_match('/^'.$this->_grammar->getDefinition('id-left').'@'.$this->_grammar->getDefinition('id-right').'$/D', $id)) { + throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>'); + } + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->_headers = clone $this->_headers; + $this->_encoder = clone $this->_encoder; + $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); + $children = array(); + foreach ($this->_children as $pos => $child) { + $children[$pos] = clone $child; + } + $this->setChildren($children); + } +} diff --git a/lib/SwiftMailer/classes/Swift/MimePart.php b/lib/SwiftMailer/classes/Swift/MimePart.php new file mode 100644 index 0000000..215f8db --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/MimePart.php @@ -0,0 +1,59 @@ +createDependenciesFor('mime.part') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new MimePart. + * + * @param string $body + * @param string $contentType + * @param string $charset + * + * @return Swift_Mime_MimePart + */ + public static function newInstance($body = null, $contentType = null, $charset = null) + { + return new self($body, $contentType, $charset); + } +} diff --git a/lib/SwiftMailer/classes/Swift/NullTransport.php b/lib/SwiftMailer/classes/Swift/NullTransport.php new file mode 100644 index 0000000..b38e1cf --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/NullTransport.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + */ +class Swift_NullTransport extends Swift_Transport_NullTransport +{ + /** + * Create a new NullTransport. + */ + public function __construct() + { + call_user_func_array( + array($this, 'Swift_Transport_NullTransport::__construct'), + Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.null') + ); + } + + /** + * Create a new NullTransport instance. + * + * @return Swift_NullTransport + */ + public static function newInstance() + { + return new self(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/OutputByteStream.php b/lib/SwiftMailer/classes/Swift/OutputByteStream.php new file mode 100644 index 0000000..1f26f9b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/OutputByteStream.php @@ -0,0 +1,46 @@ +setThreshold($threshold); + $this->setSleepTime($sleep); + $this->_sleeper = $sleeper; + } + + /** + * Set the number of emails to send before restarting. + * + * @param int $threshold + */ + public function setThreshold($threshold) + { + $this->_threshold = $threshold; + } + + /** + * Get the number of emails to send before restarting. + * + * @return int + */ + public function getThreshold() + { + return $this->_threshold; + } + + /** + * Set the number of seconds to sleep for during a restart. + * + * @param int $sleep time + */ + public function setSleepTime($sleep) + { + $this->_sleep = $sleep; + } + + /** + * Get the number of seconds to sleep for during a restart. + * + * @return int + */ + public function getSleepTime() + { + return $this->_sleep; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + ++$this->_counter; + if ($this->_counter >= $this->_threshold) { + $transport = $evt->getTransport(); + $transport->stop(); + if ($this->_sleep) { + $this->sleep($this->_sleep); + } + $transport->start(); + $this->_counter = 0; + } + } + + /** + * Sleep for $seconds. + * + * @param int $seconds + */ + public function sleep($seconds) + { + if (isset($this->_sleeper)) { + $this->_sleeper->sleep($seconds); + } else { + sleep($seconds); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/lib/SwiftMailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php new file mode 100644 index 0000000..f7e18d0 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php @@ -0,0 +1,164 @@ +getMessage(); + $message->toByteStream($this); + } + + /** + * Invoked immediately following a command being sent. + * + * @param Swift_Events_CommandEvent $evt + */ + public function commandSent(Swift_Events_CommandEvent $evt) + { + $command = $evt->getCommand(); + $this->_out += strlen($command); + } + + /** + * Invoked immediately following a response coming back. + * + * @param Swift_Events_ResponseEvent $evt + */ + public function responseReceived(Swift_Events_ResponseEvent $evt) + { + $response = $evt->getResponse(); + $this->_in += strlen($response); + } + + /** + * Called when a message is sent so that the outgoing counter can be increased. + * + * @param string $bytes + */ + public function write($bytes) + { + $this->_out += strlen($bytes); + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + unset($this->_mirrors[$k]); + } + } + } + + /** + * Not used. + */ + public function flushBuffers() + { + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } + + /** + * Get the total number of bytes sent to the server. + * + * @return int + */ + public function getBytesOut() + { + return $this->_out; + } + + /** + * Get the total number of bytes received from the server. + * + * @return int + */ + public function getBytesIn() + { + return $this->_in; + } + + /** + * Reset the internal counters to zero. + */ + public function reset() + { + $this->_out = 0; + $this->_in = 0; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Decorator/Replacements.php b/lib/SwiftMailer/classes/Swift/Plugins/Decorator/Replacements.php new file mode 100644 index 0000000..9f9f08b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Decorator/Replacements.php @@ -0,0 +1,31 @@ + + * $replacements = array( + * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), + * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") + * ) + * + * + * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, + * the object should return just the array of replacements for the address + * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. + * + * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements + */ + public function __construct($replacements) + { + $this->setReplacements($replacements); + } + + /** + * Sets replacements. + * + * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements + * + * @see __construct() + */ + public function setReplacements($replacements) + { + if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) { + $this->_replacements = (array) $replacements; + } else { + $this->_replacements = $replacements; + } + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $this->_restoreMessage($message); + $to = array_keys($message->getTo()); + $address = array_shift($to); + if ($replacements = $this->getReplacementsFor($address)) { + $body = $message->getBody(); + $search = array_keys($replacements); + $replace = array_values($replacements); + $bodyReplaced = str_replace( + $search, $replace, $body + ); + if ($body != $bodyReplaced) { + $this->_originalBody = $body; + $message->setBody($bodyReplaced); + } + + foreach ($message->getHeaders()->getAll() as $header) { + $body = $header->getFieldBodyModel(); + $count = 0; + if (is_array($body)) { + $bodyReplaced = array(); + foreach ($body as $key => $value) { + $count1 = 0; + $count2 = 0; + $key = is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; + $value = is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; + $bodyReplaced[$key] = $value; + + if (!$count && ($count1 || $count2)) { + $count = 1; + } + } + } else { + $bodyReplaced = str_replace($search, $replace, $body, $count); + } + + if ($count) { + $this->_originalHeaders[$header->getFieldName()] = $body; + $header->setFieldBodyModel($bodyReplaced); + } + } + + $children = (array) $message->getChildren(); + foreach ($children as $child) { + list($type) = sscanf($child->getContentType(), '%[^/]/%s'); + if ('text' == $type) { + $body = $child->getBody(); + $bodyReplaced = str_replace( + $search, $replace, $body + ); + if ($body != $bodyReplaced) { + $child->setBody($bodyReplaced); + $this->_originalChildBodies[$child->getId()] = $body; + } + } + } + $this->_lastMessage = $message; + } + } + + /** + * Find a map of replacements for the address. + * + * If this plugin was provided with a delegate instance of + * {@link Swift_Plugins_Decorator_Replacements} then the call will be + * delegated to it. Otherwise, it will attempt to find the replacements + * from the array provided in the constructor. + * + * If no replacements can be found, an empty value (NULL) is returned. + * + * @param string $address + * + * @return array + */ + public function getReplacementsFor($address) + { + if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) { + return $this->_replacements->getReplacementsFor($address); + } + + return isset($this->_replacements[$address]) ? $this->_replacements[$address] : null; + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $this->_restoreMessage($evt->getMessage()); + } + + /** Restore a changed message back to its original state */ + private function _restoreMessage(Swift_Mime_Message $message) + { + if ($this->_lastMessage === $message) { + if (isset($this->_originalBody)) { + $message->setBody($this->_originalBody); + $this->_originalBody = null; + } + if (!empty($this->_originalHeaders)) { + foreach ($message->getHeaders()->getAll() as $header) { + if (array_key_exists($header->getFieldName(), $this->_originalHeaders)) { + $header->setFieldBodyModel($this->_originalHeaders[$header->getFieldName()]); + } + } + $this->_originalHeaders = array(); + } + if (!empty($this->_originalChildBodies)) { + $children = (array) $message->getChildren(); + foreach ($children as $child) { + $id = $child->getId(); + if (array_key_exists($id, $this->_originalChildBodies)) { + $child->setBody($this->_originalChildBodies[$id]); + } + } + $this->_originalChildBodies = array(); + } + $this->_lastMessage = null; + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/ImpersonatePlugin.php b/lib/SwiftMailer/classes/Swift/Plugins/ImpersonatePlugin.php new file mode 100644 index 0000000..7552b67 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/ImpersonatePlugin.php @@ -0,0 +1,69 @@ +_sender = $sender; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $headers = $message->getHeaders(); + + // save current recipients + $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath()); + + // replace them with the one to send to + $message->setReturnPath($this->_sender); + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + + // restore original headers + $headers = $message->getHeaders(); + + if ($headers->has('X-Swift-Return-Path')) { + $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress()); + $headers->removeAll('X-Swift-Return-Path'); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Logger.php b/lib/SwiftMailer/classes/Swift/Plugins/Logger.php new file mode 100644 index 0000000..d9bce89 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Logger.php @@ -0,0 +1,36 @@ +_logger = $logger; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + $this->_logger->add($entry); + } + + /** + * Clear the log contents. + */ + public function clear() + { + $this->_logger->clear(); + } + + /** + * Get this log as a string. + * + * @return string + */ + public function dump() + { + return $this->_logger->dump(); + } + + /** + * Invoked immediately following a command being sent. + * + * @param Swift_Events_CommandEvent $evt + */ + public function commandSent(Swift_Events_CommandEvent $evt) + { + $command = $evt->getCommand(); + $this->_logger->add(sprintf('>> %s', $command)); + } + + /** + * Invoked immediately following a response coming back. + * + * @param Swift_Events_ResponseEvent $evt + */ + public function responseReceived(Swift_Events_ResponseEvent $evt) + { + $response = $evt->getResponse(); + $this->_logger->add(sprintf('<< %s', $response)); + } + + /** + * Invoked just before a Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ Starting %s', $transportName)); + } + + /** + * Invoked immediately after the Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function transportStarted(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ %s started', $transportName)); + } + + /** + * Invoked just before a Transport is stopped. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ Stopping %s', $transportName)); + } + + /** + * Invoked immediately after the Transport is stopped. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function transportStopped(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf('++ %s stopped', $transportName)); + } + + /** + * Invoked as a TransportException is thrown in the Transport system. + * + * @param Swift_Events_TransportExceptionEvent $evt + */ + public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt) + { + $e = $evt->getException(); + $message = $e->getMessage(); + $code = $e->getCode(); + $this->_logger->add(sprintf('!! %s (code: %s)', $message, $code)); + $message .= PHP_EOL; + $message .= 'Log data:'.PHP_EOL; + $message .= $this->_logger->dump(); + $evt->cancelBubble(); + throw new Swift_TransportException($message, $code, $e->getPrevious()); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Loggers/ArrayLogger.php b/lib/SwiftMailer/classes/Swift/Plugins/Loggers/ArrayLogger.php new file mode 100644 index 0000000..865bb0a --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Loggers/ArrayLogger.php @@ -0,0 +1,72 @@ +_size = $size; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + $this->_log[] = $entry; + while (count($this->_log) > $this->_size) { + array_shift($this->_log); + } + } + + /** + * Clear the log contents. + */ + public function clear() + { + $this->_log = array(); + } + + /** + * Get this log as a string. + * + * @return string + */ + public function dump() + { + return implode(PHP_EOL, $this->_log); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Loggers/EchoLogger.php b/lib/SwiftMailer/classes/Swift/Plugins/Loggers/EchoLogger.php new file mode 100644 index 0000000..3583297 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Loggers/EchoLogger.php @@ -0,0 +1,58 @@ +_isHtml = $isHtml; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + if ($this->_isHtml) { + printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '
      ', PHP_EOL); + } else { + printf('%s%s', $entry, PHP_EOL); + } + } + + /** + * Not implemented. + */ + public function clear() + { + } + + /** + * Not implemented. + */ + public function dump() + { + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/MessageLogger.php b/lib/SwiftMailer/classes/Swift/Plugins/MessageLogger.php new file mode 100644 index 0000000..e622cb3 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/MessageLogger.php @@ -0,0 +1,74 @@ +messages = array(); + } + + /** + * Get the message list. + * + * @return array + */ + public function getMessages() + { + return $this->messages; + } + + /** + * Get the message count. + * + * @return int count + */ + public function countMessages() + { + return count($this->messages); + } + + /** + * Empty the message list. + */ + public function clear() + { + $this->messages = array(); + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $this->messages[] = clone $evt->getMessage(); + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Pop/Pop3Connection.php b/lib/SwiftMailer/classes/Swift/Plugins/Pop/Pop3Connection.php new file mode 100644 index 0000000..fb99e4c --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Pop/Pop3Connection.php @@ -0,0 +1,31 @@ +_host = $host; + $this->_port = $port; + $this->_crypto = $crypto; + } + + /** + * Create a new PopBeforeSmtpPlugin for $host and $port. + * + * @param string $host + * @param int $port + * @param string $crypto as "tls" or "ssl" + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public static function newInstance($host, $port = 110, $crypto = null) + { + return new self($host, $port, $crypto); + } + + /** + * Set a Pop3Connection to delegate to instead of connecting directly. + * + * @param Swift_Plugins_Pop_Pop3Connection $connection + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection) + { + $this->_connection = $connection; + + return $this; + } + + /** + * Bind this plugin to a specific SMTP transport instance. + * + * @param Swift_Transport + */ + public function bindSmtp(Swift_Transport $smtp) + { + $this->_transport = $smtp; + } + + /** + * Set the connection timeout in seconds (default 10). + * + * @param int $timeout + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setTimeout($timeout) + { + $this->_timeout = (int) $timeout; + + return $this; + } + + /** + * Set the username to use when connecting (if needed). + * + * @param string $username + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setUsername($username) + { + $this->_username = $username; + + return $this; + } + + /** + * Set the password to use when connecting (if needed). + * + * @param string $password + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setPassword($password) + { + $this->_password = $password; + + return $this; + } + + /** + * Connect to the POP3 host and authenticate. + * + * @throws Swift_Plugins_Pop_Pop3Exception if connection fails + */ + public function connect() + { + if (isset($this->_connection)) { + $this->_connection->connect(); + } else { + if (!isset($this->_socket)) { + if (!$socket = fsockopen( + $this->_getHostString(), $this->_port, $errno, $errstr, $this->_timeout)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to connect to POP3 host [%s]: %s', $this->_host, $errstr) + ); + } + $this->_socket = $socket; + + if (false === $greeting = fgets($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to connect to POP3 host [%s]', trim($greeting)) + ); + } + + $this->_assertOk($greeting); + + if ($this->_username) { + $this->_command(sprintf("USER %s\r\n", $this->_username)); + $this->_command(sprintf("PASS %s\r\n", $this->_password)); + } + } + } + } + + /** + * Disconnect from the POP3 host. + */ + public function disconnect() + { + if (isset($this->_connection)) { + $this->_connection->disconnect(); + } else { + $this->_command("QUIT\r\n"); + if (!fclose($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('POP3 host [%s] connection could not be stopped', $this->_host) + ); + } + $this->_socket = null; + } + } + + /** + * Invoked just before a Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) + { + if (isset($this->_transport)) { + if ($this->_transport !== $evt->getTransport()) { + return; + } + } + + $this->connect(); + $this->disconnect(); + } + + /** + * Not used. + */ + public function transportStarted(Swift_Events_TransportChangeEvent $evt) + { + } + + /** + * Not used. + */ + public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) + { + } + + /** + * Not used. + */ + public function transportStopped(Swift_Events_TransportChangeEvent $evt) + { + } + + private function _command($command) + { + if (!fwrite($this->_socket, $command)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to write command [%s] to POP3 host', trim($command)) + ); + } + + if (false === $response = fgets($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to read from POP3 host after command [%s]', trim($command)) + ); + } + + $this->_assertOk($response); + + return $response; + } + + private function _assertOk($response) + { + if (substr($response, 0, 3) != '+OK') { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('POP3 command failed [%s]', trim($response)) + ); + } + } + + private function _getHostString() + { + $host = $this->_host; + switch (strtolower($this->_crypto)) { + case 'ssl': + $host = 'ssl://'.$host; + break; + + case 'tls': + $host = 'tls://'.$host; + break; + } + + return $host; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/RedirectingPlugin.php b/lib/SwiftMailer/classes/Swift/Plugins/RedirectingPlugin.php new file mode 100644 index 0000000..c3a1f86 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/RedirectingPlugin.php @@ -0,0 +1,213 @@ +_recipient = $recipient; + $this->_whitelist = $whitelist; + } + + /** + * Set the recipient of all messages. + * + * @param mixed $recipient + */ + public function setRecipient($recipient) + { + $this->_recipient = $recipient; + } + + /** + * Get the recipient of all messages. + * + * @return mixed + */ + public function getRecipient() + { + return $this->_recipient; + } + + /** + * Set a list of regular expressions to whitelist certain recipients. + * + * @param array $whitelist + */ + public function setWhitelist(array $whitelist) + { + $this->_whitelist = $whitelist; + } + + /** + * Get the whitelist. + * + * @return array + */ + public function getWhitelist() + { + return $this->_whitelist; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $headers = $message->getHeaders(); + + // conditionally save current recipients + + if ($headers->has('to')) { + $headers->addMailboxHeader('X-Swift-To', $message->getTo()); + } + + if ($headers->has('cc')) { + $headers->addMailboxHeader('X-Swift-Cc', $message->getCc()); + } + + if ($headers->has('bcc')) { + $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc()); + } + + // Filter remaining headers against whitelist + $this->_filterHeaderSet($headers, 'To'); + $this->_filterHeaderSet($headers, 'Cc'); + $this->_filterHeaderSet($headers, 'Bcc'); + + // Add each hard coded recipient + $to = $message->getTo(); + if (null === $to) { + $to = array(); + } + + foreach ((array) $this->_recipient as $recipient) { + if (!array_key_exists($recipient, $to)) { + $message->addTo($recipient); + } + } + } + + /** + * Filter header set against a whitelist of regular expressions. + * + * @param Swift_Mime_HeaderSet $headerSet + * @param string $type + */ + private function _filterHeaderSet(Swift_Mime_HeaderSet $headerSet, $type) + { + foreach ($headerSet->getAll($type) as $headers) { + $headers->setNameAddresses($this->_filterNameAddresses($headers->getNameAddresses())); + } + } + + /** + * Filtered list of addresses => name pairs. + * + * @param array $recipients + * + * @return array + */ + private function _filterNameAddresses(array $recipients) + { + $filtered = array(); + + foreach ($recipients as $address => $name) { + if ($this->_isWhitelisted($address)) { + $filtered[$address] = $name; + } + } + + return $filtered; + } + + /** + * Matches address against whitelist of regular expressions. + * + * @param $recipient + * + * @return bool + */ + protected function _isWhitelisted($recipient) + { + if (in_array($recipient, (array) $this->_recipient)) { + return true; + } + + foreach ($this->_whitelist as $pattern) { + if (preg_match($pattern, $recipient)) { + return true; + } + } + + return false; + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $this->_restoreMessage($evt->getMessage()); + } + + private function _restoreMessage(Swift_Mime_Message $message) + { + // restore original headers + $headers = $message->getHeaders(); + + if ($headers->has('X-Swift-To')) { + $message->setTo($headers->get('X-Swift-To')->getNameAddresses()); + $headers->removeAll('X-Swift-To'); + } else { + $message->setTo(null); + } + + if ($headers->has('X-Swift-Cc')) { + $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses()); + $headers->removeAll('X-Swift-Cc'); + } + + if ($headers->has('X-Swift-Bcc')) { + $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses()); + $headers->removeAll('X-Swift-Bcc'); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Reporter.php b/lib/SwiftMailer/classes/Swift/Plugins/Reporter.php new file mode 100644 index 0000000..0f21b7d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Reporter.php @@ -0,0 +1,32 @@ +_reporter = $reporter; + } + + /** + * Not used. + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $failures = array_flip($evt->getFailedRecipients()); + foreach ((array) $message->getTo() as $address => $null) { + $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); + } + foreach ((array) $message->getCc() as $address => $null) { + $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); + } + foreach ((array) $message->getBcc() as $address => $null) { + $this->_reporter->notify($message, $address, array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Reporters/HitReporter.php b/lib/SwiftMailer/classes/Swift/Plugins/Reporters/HitReporter.php new file mode 100644 index 0000000..cad9d16 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Reporters/HitReporter.php @@ -0,0 +1,59 @@ +_failures_cache[$address])) { + $this->_failures[] = $address; + $this->_failures_cache[$address] = true; + } + } + + /** + * Get an array of addresses for which delivery failed. + * + * @return array + */ + public function getFailedRecipients() + { + return $this->_failures; + } + + /** + * Clear the buffer (empty the list). + */ + public function clear() + { + $this->_failures = $this->_failures_cache = array(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Reporters/HtmlReporter.php b/lib/SwiftMailer/classes/Swift/Plugins/Reporters/HtmlReporter.php new file mode 100644 index 0000000..c625935 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Reporters/HtmlReporter.php @@ -0,0 +1,39 @@ +'.PHP_EOL; + echo 'PASS '.$address.PHP_EOL; + echo ''.PHP_EOL; + flush(); + } else { + echo '
      '.PHP_EOL; + echo 'FAIL '.$address.PHP_EOL; + echo '
      '.PHP_EOL; + flush(); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Sleeper.php b/lib/SwiftMailer/classes/Swift/Plugins/Sleeper.php new file mode 100644 index 0000000..595c0f6 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Sleeper.php @@ -0,0 +1,24 @@ +_rate = $rate; + $this->_mode = $mode; + $this->_sleeper = $sleeper; + $this->_timer = $timer; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $time = $this->getTimestamp(); + if (!isset($this->_start)) { + $this->_start = $time; + } + $duration = $time - $this->_start; + + switch ($this->_mode) { + case self::BYTES_PER_MINUTE : + $sleep = $this->_throttleBytesPerMinute($duration); + break; + case self::MESSAGES_PER_SECOND : + $sleep = $this->_throttleMessagesPerSecond($duration); + break; + case self::MESSAGES_PER_MINUTE : + $sleep = $this->_throttleMessagesPerMinute($duration); + break; + default : + $sleep = 0; + break; + } + + if ($sleep > 0) { + $this->sleep($sleep); + } + } + + /** + * Invoked when a Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + parent::sendPerformed($evt); + ++$this->_messages; + } + + /** + * Sleep for $seconds. + * + * @param int $seconds + */ + public function sleep($seconds) + { + if (isset($this->_sleeper)) { + $this->_sleeper->sleep($seconds); + } else { + sleep($seconds); + } + } + + /** + * Get the current UNIX timestamp. + * + * @return int + */ + public function getTimestamp() + { + if (isset($this->_timer)) { + return $this->_timer->getTimestamp(); + } + + return time(); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleBytesPerMinute($timePassed) + { + $expectedDuration = $this->getBytesOut() / ($this->_rate / 60); + + return (int) ceil($expectedDuration - $timePassed); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleMessagesPerSecond($timePassed) + { + $expectedDuration = $this->_messages / ($this->_rate); + + return (int) ceil($expectedDuration - $timePassed); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleMessagesPerMinute($timePassed) + { + $expectedDuration = $this->_messages / ($this->_rate / 60); + + return (int) ceil($expectedDuration - $timePassed); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Plugins/Timer.php b/lib/SwiftMailer/classes/Swift/Plugins/Timer.php new file mode 100644 index 0000000..9c8deb3 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Plugins/Timer.php @@ -0,0 +1,24 @@ +register('properties.charset')->asValue($charset); + + return $this; + } + + /** + * Set the directory where temporary files can be saved. + * + * @param string $dir + * + * @return Swift_Preferences + */ + public function setTempDir($dir) + { + Swift_DependencyContainer::getInstance() + ->register('tempdir')->asValue($dir); + + return $this; + } + + /** + * Set the type of cache to use (i.e. "disk" or "array"). + * + * @param string $type + * + * @return Swift_Preferences + */ + public function setCacheType($type) + { + Swift_DependencyContainer::getInstance() + ->register('cache')->asAliasOf(sprintf('cache.%s', $type)); + + return $this; + } + + /** + * Set the QuotedPrintable dot escaper preference. + * + * @param bool $dotEscape + * + * @return Swift_Preferences + */ + public function setQPDotEscape($dotEscape) + { + $dotEscape = !empty($dotEscape); + Swift_DependencyContainer::getInstance() + ->register('mime.qpcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') + ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) + ->addConstructorValue($dotEscape); + + return $this; + } +} diff --git a/lib/SwiftMailer/classes/Swift/ReplacementFilterFactory.php b/lib/SwiftMailer/classes/Swift/ReplacementFilterFactory.php new file mode 100644 index 0000000..2897474 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/ReplacementFilterFactory.php @@ -0,0 +1,27 @@ +createDependenciesFor('transport.sendmail') + ); + + $this->setCommand($command); + } + + /** + * Create a new SendmailTransport instance. + * + * @param string $command + * + * @return Swift_SendmailTransport + */ + public static function newInstance($command = '/usr/sbin/sendmail -bs') + { + return new self($command); + } +} diff --git a/lib/SwiftMailer/classes/Swift/SignedMessage.php b/lib/SwiftMailer/classes/Swift/SignedMessage.php new file mode 100644 index 0000000..2e7a872 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/SignedMessage.php @@ -0,0 +1,23 @@ + + * + * @deprecated + */ +class Swift_SignedMessage extends Swift_Message +{ +} diff --git a/lib/SwiftMailer/classes/Swift/Signer.php b/lib/SwiftMailer/classes/Swift/Signer.php new file mode 100644 index 0000000..2d8176d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signer.php @@ -0,0 +1,20 @@ + + */ +interface Swift_Signer +{ + public function reset(); +} diff --git a/lib/SwiftMailer/classes/Swift/Signers/BodySigner.php b/lib/SwiftMailer/classes/Swift/Signers/BodySigner.php new file mode 100644 index 0000000..9ffcef3 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signers/BodySigner.php @@ -0,0 +1,33 @@ + + */ +interface Swift_Signers_BodySigner extends Swift_Signer +{ + /** + * Change the Swift_Signed_Message to apply the singing. + * + * @param Swift_Message $message + * + * @return Swift_Signers_BodySigner + */ + public function signMessage(Swift_Message $message); + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/lib/SwiftMailer/classes/Swift/Signers/DKIMSigner.php b/lib/SwiftMailer/classes/Swift/Signers/DKIMSigner.php new file mode 100644 index 0000000..b7a6209 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signers/DKIMSigner.php @@ -0,0 +1,698 @@ + + */ +class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey. + * + * @var string + */ + protected $_privateKey; + + /** + * DomainName. + * + * @var string + */ + protected $_domainName; + + /** + * Selector. + * + * @var string + */ + protected $_selector; + + /** + * Hash algorithm used. + * + * @var string + */ + protected $_hashAlgorithm = 'rsa-sha1'; + + /** + * Body canon method. + * + * @var string + */ + protected $_bodyCanon = 'simple'; + + /** + * Header canon method. + * + * @var string + */ + protected $_headerCanon = 'simple'; + + /** + * Headers not being signed. + * + * @var array + */ + protected $_ignoredHeaders = array('return-path' => true); + + /** + * Signer identity. + * + * @var string + */ + protected $_signerIdentity; + + /** + * BodyLength. + * + * @var int + */ + protected $_bodyLen = 0; + + /** + * Maximum signedLen. + * + * @var int + */ + protected $_maxLen = PHP_INT_MAX; + + /** + * Embbed bodyLen in signature. + * + * @var bool + */ + protected $_showLen = false; + + /** + * When the signature has been applied (true means time()), false means not embedded. + * + * @var mixed + */ + protected $_signatureTimestamp = true; + + /** + * When will the signature expires false means not embedded, if sigTimestamp is auto + * Expiration is relative, otherwhise it's absolute. + * + * @var int + */ + protected $_signatureExpiration = false; + + /** + * Must we embed signed headers? + * + * @var bool + */ + protected $_debugHeaders = false; + + // work variables + /** + * Headers used to generate hash. + * + * @var array + */ + protected $_signedHeaders = array(); + + /** + * If debugHeaders is set store debugDatas here. + * + * @var string + */ + private $_debugHeadersData = ''; + + /** + * Stores the bodyHash. + * + * @var string + */ + private $_bodyHash = ''; + + /** + * Stores the signature header. + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $_dkimHeader; + + private $_bodyHashHandler; + + private $_headerHash; + + private $_headerCanonData = ''; + + private $_bodyCanonEmptyCounter = 0; + + private $_bodyCanonIgnoreStart = 2; + + private $_bodyCanonSpace = false; + + private $_bodyCanonLastChar = null; + + private $_bodyCanonLine = ''; + + private $_bound = array(); + + /** + * Constructor. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + */ + public function __construct($privateKey, $domainName, $selector) + { + $this->_privateKey = $privateKey; + $this->_domainName = $domainName; + $this->_signerIdentity = '@'.$domainName; + $this->_selector = $selector; + } + + /** + * Instanciate DKIMSigner. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + * + * @return Swift_Signers_DKIMSigner + */ + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + /** + * Reset the Signer. + * + * @see Swift_Signer::reset() + */ + public function reset() + { + $this->_headerHash = null; + $this->_signedHeaders = array(); + $this->_bodyHash = null; + $this->_bodyHashHandler = null; + $this->_bodyCanonIgnoreStart = 2; + $this->_bodyCanonEmptyCounter = 0; + $this->_bodyCanonLastChar = null; + $this->_bodyCanonSpace = false; + } + + /** + * Writes $bytes to the end of the stream. + * + * Writing may not happen immediately if the stream chooses to buffer. If + * you want to write these bytes with immediate effect, call {@link commit()} + * after calling write(). + * + * This method returns the sequence ID of the write (i.e. 1 for first, 2 for + * second, etc etc). + * + * @param string $bytes + * + * @throws Swift_IoException + * + * @return int + */ + public function write($bytes) + { + $this->_canonicalizeBody($bytes); + foreach ($this->_bound as $is) { + $is->write($bytes); + } + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + */ + public function commit() + { + // Nothing to do + return; + } + + /** + * Attach $is to this stream. + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + $this->_bound[] = $is; + + return; + } + + /** + * Remove an already bound stream. + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + foreach ($this->_bound as $k => $stream) { + if ($stream === $is) { + unset($this->_bound[$k]); + + return; + } + } + + return; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + */ + public function flushBuffers() + { + $this->reset(); + } + + /** + * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256. + * + * @param string $hash + * + * @return Swift_Signers_DKIMSigner + */ + public function setHashAlgorithm($hash) + { + // Unable to sign with rsa-sha256 + if ($hash == 'rsa-sha1') { + $this->_hashAlgorithm = 'rsa-sha1'; + } else { + $this->_hashAlgorithm = 'rsa-sha256'; + } + + return $this; + } + + /** + * Set the body canonicalization algorithm. + * + * @param string $canon + * + * @return Swift_Signers_DKIMSigner + */ + public function setBodyCanon($canon) + { + if ($canon == 'relaxed') { + $this->_bodyCanon = 'relaxed'; + } else { + $this->_bodyCanon = 'simple'; + } + + return $this; + } + + /** + * Set the header canonicalization algorithm. + * + * @param string $canon + * + * @return Swift_Signers_DKIMSigner + */ + public function setHeaderCanon($canon) + { + if ($canon == 'relaxed') { + $this->_headerCanon = 'relaxed'; + } else { + $this->_headerCanon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity. + * + * @param string $identity + * + * @return Swift_Signers_DKIMSigner + */ + public function setSignerIdentity($identity) + { + $this->_signerIdentity = $identity; + + return $this; + } + + /** + * Set the length of the body to sign. + * + * @param mixed $len (bool or int) + * + * @return Swift_Signers_DKIMSigner + */ + public function setBodySignedLen($len) + { + if ($len === true) { + $this->_showLen = true; + $this->_maxLen = PHP_INT_MAX; + } elseif ($len === false) { + $this->_showLen = false; + $this->_maxLen = PHP_INT_MAX; + } else { + $this->_showLen = true; + $this->_maxLen = (int) $len; + } + + return $this; + } + + /** + * Set the signature timestamp. + * + * @param int $time A timestamp + * + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureTimestamp($time) + { + $this->_signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp. + * + * @param int $time A timestamp + * + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureExpiration($time) + { + $this->_signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return Swift_Signers_DKIMSigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + /** + * Start Body. + */ + public function startBody() + { + // Init + switch ($this->_hashAlgorithm) { + case 'rsa-sha256' : + $this->_bodyHashHandler = hash_init('sha256'); + break; + case 'rsa-sha1' : + $this->_bodyHashHandler = hash_init('sha1'); + break; + } + $this->_bodyCanonLine = ''; + } + + /** + * End Body. + */ + public function endBody() + { + $this->_endOfBody(); + } + + /** + * Returns the list of Headers Tampered by this plugin. + * + * @return array + */ + public function getAlteredHeaders() + { + if ($this->_debugHeaders) { + return array('DKIM-Signature', 'X-DebugHash'); + } else { + return array('DKIM-Signature'); + } + } + + /** + * Adds an ignored Header. + * + * @param string $header_name + * + * @return Swift_Signers_DKIMSigner + */ + public function ignoreHeader($header_name) + { + $this->_ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_DKIMSigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $this->_headerCanonData = ''; + // Loop through Headers + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (!isset($this->_ignoredHeaders[strtolower($hName)])) { + if ($headers->has($hName)) { + $tmp = $headers->getAll($hName); + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $this->_addHeader($header->toString()); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + + return $this; + } + + /** + * Add the signature to the given Headers. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_DKIMSigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers) + { + // Prepare the DKIM-Signature + $params = array('v' => '1', 'a' => $this->_hashAlgorithm, 'bh' => base64_encode($this->_bodyHash), 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'i' => $this->_signerIdentity, 's' => $this->_selector); + if ($this->_bodyCanon != 'simple') { + $params['c'] = $this->_headerCanon.'/'.$this->_bodyCanon; + } elseif ($this->_headerCanon != 'simple') { + $params['c'] = $this->_headerCanon; + } + if ($this->_showLen) { + $params['l'] = $this->_bodyLen; + } + if ($this->_signatureTimestamp === true) { + $params['t'] = time(); + if ($this->_signatureExpiration !== false) { + $params['x'] = $params['t'] + $this->_signatureExpiration; + } + } else { + if ($this->_signatureTimestamp !== false) { + $params['t'] = $this->_signatureTimestamp; + } + if ($this->_signatureExpiration !== false) { + $params['x'] = $this->_signatureExpiration; + } + } + if ($this->_debugHeaders) { + $params['z'] = implode('|', $this->_debugHeadersData); + } + $string = ''; + foreach ($params as $k => $v) { + $string .= $k.'='.$v.'; '; + } + $string = trim($string); + $headers->addTextHeader('DKIM-Signature', $string); + // Add the last DKIM-Signature + $tmp = $headers->getAll('DKIM-Signature'); + $this->_dkimHeader = end($tmp); + $this->_addHeader(trim($this->_dkimHeader->toString())."\r\n b=", true); + $this->_endOfHeaders(); + if ($this->_debugHeaders) { + $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash)); + } + $this->_dkimHeader->setValue($string.' b='.trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' '))); + + return $this; + } + + /* Private helpers */ + + protected function _addHeader($header, $is_sig = false) + { + switch ($this->_headerCanon) { + case 'relaxed' : + // Prepare Header and cascade + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", '', $exploded[1]); + $value = preg_replace("/[ \t][ \t]+/", ' ', $value); + $header = $name.':'.trim($value).($is_sig ? '' : "\r\n"); + case 'simple' : + // Nothing to do + } + $this->_addToHeaderHash($header); + } + + /** + * @deprecated This method is currently useless in this class but it must be + * kept for BC reasons due to its "protected" scope. This method + * might be overriden by custom client code. + */ + protected function _endOfHeaders() + { + } + + protected function _canonicalizeBody($string) + { + $len = strlen($string); + $canon = ''; + $method = ($this->_bodyCanon == 'relaxed'); + for ($i = 0; $i < $len; ++$i) { + if ($this->_bodyCanonIgnoreStart > 0) { + --$this->_bodyCanonIgnoreStart; + continue; + } + switch ($string[$i]) { + case "\r" : + $this->_bodyCanonLastChar = "\r"; + break; + case "\n" : + if ($this->_bodyCanonLastChar == "\r") { + if ($method) { + $this->_bodyCanonSpace = false; + } + if ($this->_bodyCanonLine == '') { + ++$this->_bodyCanonEmptyCounter; + } else { + $this->_bodyCanonLine = ''; + $canon .= "\r\n"; + } + } else { + // Wooops Error + // todo handle it but should never happen + } + break; + case ' ' : + case "\t" : + if ($method) { + $this->_bodyCanonSpace = true; + break; + } + default : + if ($this->_bodyCanonEmptyCounter > 0) { + $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); + $this->_bodyCanonEmptyCounter = 0; + } + if ($this->_bodyCanonSpace) { + $this->_bodyCanonLine .= ' '; + $canon .= ' '; + $this->_bodyCanonSpace = false; + } + $this->_bodyCanonLine .= $string[$i]; + $canon .= $string[$i]; + } + } + $this->_addToBodyHash($canon); + } + + protected function _endOfBody() + { + // Add trailing Line return if last line is non empty + if (strlen($this->_bodyCanonLine) > 0) { + $this->_addToBodyHash("\r\n"); + } + $this->_bodyHash = hash_final($this->_bodyHashHandler, true); + } + + private function _addToBodyHash($string) + { + $len = strlen($string); + if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) { + $string = substr($string, 0, $new_len); + $len = $new_len; + } + hash_update($this->_bodyHashHandler, $string); + $this->_bodyLen += $len; + } + + private function _addToHeaderHash($header) + { + if ($this->_debugHeaders) { + $this->_debugHeadersData[] = trim($header); + } + $this->_headerCanonData .= $header; + } + + /** + * @throws Swift_SwiftException + * + * @return string + */ + private function _getEncryptedHash() + { + $signature = ''; + switch ($this->_hashAlgorithm) { + case 'rsa-sha1': + $algorithm = OPENSSL_ALGO_SHA1; + break; + case 'rsa-sha256': + $algorithm = OPENSSL_ALGO_SHA256; + break; + } + $pkeyId = openssl_get_privatekey($this->_privateKey); + if (!$pkeyId) { + throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']'); + } + if (openssl_sign($this->_headerCanonData, $signature, $pkeyId, $algorithm)) { + return $signature; + } + throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']'); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Signers/DomainKeySigner.php b/lib/SwiftMailer/classes/Swift/Signers/DomainKeySigner.php new file mode 100644 index 0000000..43210f0 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signers/DomainKeySigner.php @@ -0,0 +1,525 @@ + + */ +class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey. + * + * @var string + */ + protected $_privateKey; + + /** + * DomainName. + * + * @var string + */ + protected $_domainName; + + /** + * Selector. + * + * @var string + */ + protected $_selector; + + /** + * Hash algorithm used. + * + * @var string + */ + protected $_hashAlgorithm = 'rsa-sha1'; + + /** + * Canonisation method. + * + * @var string + */ + protected $_canon = 'simple'; + + /** + * Headers not being signed. + * + * @var array + */ + protected $_ignoredHeaders = array(); + + /** + * Signer identity. + * + * @var string + */ + protected $_signerIdentity; + + /** + * Must we embed signed headers? + * + * @var bool + */ + protected $_debugHeaders = false; + + // work variables + /** + * Headers used to generate hash. + * + * @var array + */ + private $_signedHeaders = array(); + + /** + * Stores the signature header. + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $_domainKeyHeader; + + /** + * Hash Handler. + * + * @var resource|null + */ + private $_hashHandler; + + private $_hash; + + private $_canonData = ''; + + private $_bodyCanonEmptyCounter = 0; + + private $_bodyCanonIgnoreStart = 2; + + private $_bodyCanonSpace = false; + + private $_bodyCanonLastChar = null; + + private $_bodyCanonLine = ''; + + private $_bound = array(); + + /** + * Constructor. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + */ + public function __construct($privateKey, $domainName, $selector) + { + $this->_privateKey = $privateKey; + $this->_domainName = $domainName; + $this->_signerIdentity = '@'.$domainName; + $this->_selector = $selector; + } + + /** + * Instanciate DomainKeySigner. + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + * + * @return Swift_Signers_DomainKeySigner + */ + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + /** + * Resets internal states. + * + * @return Swift_Signers_DomainKeySigner + */ + public function reset() + { + $this->_hash = null; + $this->_hashHandler = null; + $this->_bodyCanonIgnoreStart = 2; + $this->_bodyCanonEmptyCounter = 0; + $this->_bodyCanonLastChar = null; + $this->_bodyCanonSpace = false; + + return $this; + } + + /** + * Writes $bytes to the end of the stream. + * + * Writing may not happen immediately if the stream chooses to buffer. If + * you want to write these bytes with immediate effect, call {@link commit()} + * after calling write(). + * + * This method returns the sequence ID of the write (i.e. 1 for first, 2 for + * second, etc etc). + * + * @param string $bytes + * + * @throws Swift_IoException + * + * @return int + * @return Swift_Signers_DomainKeySigner + */ + public function write($bytes) + { + $this->_canonicalizeBody($bytes); + foreach ($this->_bound as $is) { + $is->write($bytes); + } + + return $this; + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + * + * @return Swift_Signers_DomainKeySigner + */ + public function commit() + { + // Nothing to do + return $this; + } + + /** + * Attach $is to this stream. + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + * + * @return Swift_Signers_DomainKeySigner + */ + public function bind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + $this->_bound[] = $is; + + return $this; + } + + /** + * Remove an already bound stream. + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + * + * @return Swift_Signers_DomainKeySigner + */ + public function unbind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + foreach ($this->_bound as $k => $stream) { + if ($stream === $is) { + unset($this->_bound[$k]); + + return; + } + } + + return $this; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + * + * @return Swift_Signers_DomainKeySigner + */ + public function flushBuffers() + { + $this->reset(); + + return $this; + } + + /** + * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256. + * + * @param string $hash + * + * @return Swift_Signers_DomainKeySigner + */ + public function setHashAlgorithm($hash) + { + $this->_hashAlgorithm = 'rsa-sha1'; + + return $this; + } + + /** + * Set the canonicalization algorithm. + * + * @param string $canon simple | nofws defaults to simple + * + * @return Swift_Signers_DomainKeySigner + */ + public function setCanon($canon) + { + if ($canon == 'nofws') { + $this->_canon = 'nofws'; + } else { + $this->_canon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity. + * + * @param string $identity + * + * @return Swift_Signers_DomainKeySigner + */ + public function setSignerIdentity($identity) + { + $this->_signerIdentity = $identity; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return Swift_Signers_DomainKeySigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + /** + * Start Body. + */ + public function startBody() + { + } + + /** + * End Body. + */ + public function endBody() + { + $this->_endOfBody(); + } + + /** + * Returns the list of Headers Tampered by this plugin. + * + * @return array + */ + public function getAlteredHeaders() + { + if ($this->_debugHeaders) { + return array('DomainKey-Signature', 'X-DebugHash'); + } + + return array('DomainKey-Signature'); + } + + /** + * Adds an ignored Header. + * + * @param string $header_name + * + * @return Swift_Signers_DomainKeySigner + */ + public function ignoreHeader($header_name) + { + $this->_ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_DomainKeySigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $this->_startHash(); + $this->_canonData = ''; + // Loop through Headers + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (!isset($this->_ignoredHeaders[strtolower($hName)])) { + if ($headers->has($hName)) { + $tmp = $headers->getAll($hName); + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $this->_addHeader($header->toString()); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + $this->_endOfHeaders(); + + return $this; + } + + /** + * Add the signature to the given Headers. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_DomainKeySigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers) + { + // Prepare the DomainKey-Signature Header + $params = array('a' => $this->_hashAlgorithm, 'b' => chunk_split(base64_encode($this->_getEncryptedHash()), 73, ' '), 'c' => $this->_canon, 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'q' => 'dns', 's' => $this->_selector); + $string = ''; + foreach ($params as $k => $v) { + $string .= $k.'='.$v.'; '; + } + $string = trim($string); + $headers->addTextHeader('DomainKey-Signature', $string); + + return $this; + } + + /* Private helpers */ + + protected function _addHeader($header) + { + switch ($this->_canon) { + case 'nofws' : + // Prepare Header and cascade + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", '', $exploded[1]); + $value = preg_replace("/[ \t][ \t]+/", ' ', $value); + $header = $name.':'.trim($value)."\r\n"; + case 'simple' : + // Nothing to do + } + $this->_addToHash($header); + } + + protected function _endOfHeaders() + { + $this->_bodyCanonEmptyCounter = 1; + } + + protected function _canonicalizeBody($string) + { + $len = strlen($string); + $canon = ''; + $nofws = ($this->_canon == 'nofws'); + for ($i = 0; $i < $len; ++$i) { + if ($this->_bodyCanonIgnoreStart > 0) { + --$this->_bodyCanonIgnoreStart; + continue; + } + switch ($string[$i]) { + case "\r" : + $this->_bodyCanonLastChar = "\r"; + break; + case "\n" : + if ($this->_bodyCanonLastChar == "\r") { + if ($nofws) { + $this->_bodyCanonSpace = false; + } + if ($this->_bodyCanonLine == '') { + ++$this->_bodyCanonEmptyCounter; + } else { + $this->_bodyCanonLine = ''; + $canon .= "\r\n"; + } + } else { + // Wooops Error + throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r'); + } + break; + case ' ' : + case "\t" : + case "\x09": //HTAB + if ($nofws) { + $this->_bodyCanonSpace = true; + break; + } + default : + if ($this->_bodyCanonEmptyCounter > 0) { + $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); + $this->_bodyCanonEmptyCounter = 0; + } + $this->_bodyCanonLine .= $string[$i]; + $canon .= $string[$i]; + } + } + $this->_addToHash($canon); + } + + protected function _endOfBody() + { + if (strlen($this->_bodyCanonLine) > 0) { + $this->_addToHash("\r\n"); + } + $this->_hash = hash_final($this->_hashHandler, true); + } + + private function _addToHash($string) + { + $this->_canonData .= $string; + hash_update($this->_hashHandler, $string); + } + + private function _startHash() + { + // Init + switch ($this->_hashAlgorithm) { + case 'rsa-sha1' : + $this->_hashHandler = hash_init('sha1'); + break; + } + $this->_bodyCanonLine = ''; + } + + /** + * @throws Swift_SwiftException + * + * @return string + */ + private function _getEncryptedHash() + { + $signature = ''; + $pkeyId = openssl_get_privatekey($this->_privateKey); + if (!$pkeyId) { + throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']'); + } + if (openssl_sign($this->_canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) { + return $signature; + } + throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']'); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Signers/HeaderSigner.php b/lib/SwiftMailer/classes/Swift/Signers/HeaderSigner.php new file mode 100644 index 0000000..c75cb08 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signers/HeaderSigner.php @@ -0,0 +1,65 @@ + + */ +interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream +{ + /** + * Exclude an header from the signed headers. + * + * @param string $header_name + * + * @return Swift_Signers_HeaderSigner + */ + public function ignoreHeader($header_name); + + /** + * Prepare the Signer to get a new Body. + * + * @return Swift_Signers_HeaderSigner + */ + public function startBody(); + + /** + * Give the signal that the body has finished streaming. + * + * @return Swift_Signers_HeaderSigner + */ + public function endBody(); + + /** + * Give the headers already given. + * + * @param Swift_Mime_SimpleHeaderSet $headers + * + * @return Swift_Signers_HeaderSigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers); + + /** + * Add the header(s) to the headerSet. + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_HeaderSigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers); + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/lib/SwiftMailer/classes/Swift/Signers/OpenDKIMSigner.php b/lib/SwiftMailer/classes/Swift/Signers/OpenDKIMSigner.php new file mode 100644 index 0000000..3a35ad5 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signers/OpenDKIMSigner.php @@ -0,0 +1,190 @@ + + */ +class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner +{ + private $_peclLoaded = false; + + private $_dkimHandler = null; + + private $dropFirstLF = true; + + const CANON_RELAXED = 1; + const CANON_SIMPLE = 2; + const SIG_RSA_SHA1 = 3; + const SIG_RSA_SHA256 = 4; + + public function __construct($privateKey, $domainName, $selector) + { + if (!extension_loaded('opendkim')) { + throw new Swift_SwiftException('php-opendkim extension not found'); + } + + $this->_peclLoaded = true; + + parent::__construct($privateKey, $domainName, $selector); + } + + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + public function addSignature(Swift_Mime_HeaderSet $headers) + { + $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature'); + $headerVal = $this->_dkimHandler->getSignatureHeader(); + if (!$headerVal) { + throw new Swift_SwiftException('OpenDKIM Error: '.$this->_dkimHandler->getError()); + } + $header->setValue($headerVal); + $headers->set($header); + + return $this; + } + + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $bodyLen = $this->_bodyLen; + if (is_bool($bodyLen)) { + $bodyLen = -1; + } + $hash = $this->_hashAlgorithm == 'rsa-sha1' ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256; + $bodyCanon = $this->_bodyCanon == 'simple' ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; + $headerCanon = $this->_headerCanon == 'simple' ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; + $this->_dkimHandler = new OpenDKIMSign($this->_privateKey, $this->_selector, $this->_domainName, $headerCanon, $bodyCanon, $hash, $bodyLen); + // Hardcode signature Margin for now + $this->_dkimHandler->setMargin(78); + + if (!is_numeric($this->_signatureTimestamp)) { + OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time()); + } else { + if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->_signatureTimestamp)) { + throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']'); + } + } + if (isset($this->_signerIdentity)) { + $this->_dkimHandler->setSigner($this->_signerIdentity); + } + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (!isset($this->_ignoredHeaders[strtolower($hName)])) { + $tmp = $headers->getAll($hName); + if ($headers->has($hName)) { + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $htosign = $header->toString(); + $this->_dkimHandler->header($htosign); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + + return $this; + } + + public function startBody() + { + if (!$this->_peclLoaded) { + return parent::startBody(); + } + $this->dropFirstLF = true; + $this->_dkimHandler->eoh(); + + return $this; + } + + public function endBody() + { + if (!$this->_peclLoaded) { + return parent::endBody(); + } + $this->_dkimHandler->eom(); + + return $this; + } + + public function reset() + { + $this->_dkimHandler = null; + parent::reset(); + + return $this; + } + + /** + * Set the signature timestamp. + * + * @param int $time + * + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureTimestamp($time) + { + $this->_signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp. + * + * @param int $time + * + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureExpiration($time) + { + $this->_signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return Swift_Signers_DKIMSigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + // Protected + + protected function _canonicalizeBody($string) + { + if (!$this->_peclLoaded) { + return parent::_canonicalizeBody($string); + } + if (false && $this->dropFirstLF === true) { + if ($string[0] == "\r" && $string[1] == "\n") { + $string = substr($string, 2); + } + } + $this->dropFirstLF = false; + if (strlen($string)) { + $this->_dkimHandler->body($string); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Signers/SMimeSigner.php b/lib/SwiftMailer/classes/Swift/Signers/SMimeSigner.php new file mode 100644 index 0000000..b267099 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Signers/SMimeSigner.php @@ -0,0 +1,436 @@ + + */ +class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner +{ + protected $signCertificate; + protected $signPrivateKey; + protected $encryptCert; + protected $signThenEncrypt = true; + protected $signLevel; + protected $encryptLevel; + protected $signOptions; + protected $encryptOptions; + protected $encryptCipher; + protected $extraCerts = null; + + /** + * @var Swift_StreamFilters_StringReplacementFilterFactory + */ + protected $replacementFactory; + + /** + * @var Swift_Mime_HeaderFactory + */ + protected $headerFactory; + + /** + * Constructor. + * + * @param string|null $signCertificate + * @param string|null $signPrivateKey + * @param string|null $encryptCertificate + */ + public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null) + { + if (null !== $signPrivateKey) { + $this->setSignCertificate($signCertificate, $signPrivateKey); + } + + if (null !== $encryptCertificate) { + $this->setEncryptCertificate($encryptCertificate); + } + + $this->replacementFactory = Swift_DependencyContainer::getInstance() + ->lookup('transport.replacementfactory'); + + $this->signOptions = PKCS7_DETACHED; + + // Supported since php5.4 + if (defined('OPENSSL_CIPHER_AES_128_CBC')) { + $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; + } else { + $this->encryptCipher = OPENSSL_CIPHER_RC2_128; + } + } + + /** + * Returns an new Swift_Signers_SMimeSigner instance. + * + * @param string $certificate + * @param string $privateKey + * + * @return Swift_Signers_SMimeSigner + */ + public static function newInstance($certificate = null, $privateKey = null) + { + return new self($certificate, $privateKey); + } + + /** + * Set the certificate location to use for signing. + * + * @link http://www.php.net/manual/en/openssl.pkcs7.flags.php + * + * @param string $certificate + * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead + * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign() + * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate + * + * @return Swift_Signers_SMimeSigner + */ + public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null) + { + $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate)); + + if (null !== $privateKey) { + if (is_array($privateKey)) { + $this->signPrivateKey = $privateKey; + $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0])); + } else { + $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey)); + } + } + + $this->signOptions = $signOptions; + if (null !== $extraCerts) { + $this->extraCerts = str_replace('\\', '/', realpath($extraCerts)); + } + + return $this; + } + + /** + * Set the certificate location to use for encryption. + * + * @link http://www.php.net/manual/en/openssl.pkcs7.flags.php + * @link http://nl3.php.net/manual/en/openssl.ciphers.php + * + * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates. + * @param int $cipher + * + * @return Swift_Signers_SMimeSigner + */ + public function setEncryptCertificate($recipientCerts, $cipher = null) + { + if (is_array($recipientCerts)) { + $this->encryptCert = array(); + + foreach ($recipientCerts as $cert) { + $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert)); + } + } else { + $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts)); + } + + if (null !== $cipher) { + $this->encryptCipher = $cipher; + } + + return $this; + } + + /** + * @return string + */ + public function getSignCertificate() + { + return $this->signCertificate; + } + + /** + * @return string + */ + public function getSignPrivateKey() + { + return $this->signPrivateKey; + } + + /** + * Set perform signing before encryption. + * + * The default is to first sign the message and then encrypt. + * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted. + * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients. + * + * @param bool $signThenEncrypt + * + * @return Swift_Signers_SMimeSigner + */ + public function setSignThenEncrypt($signThenEncrypt = true) + { + $this->signThenEncrypt = $signThenEncrypt; + + return $this; + } + + /** + * @return bool + */ + public function isSignThenEncrypt() + { + return $this->signThenEncrypt; + } + + /** + * Resets internal states. + * + * @return Swift_Signers_SMimeSigner + */ + public function reset() + { + return $this; + } + + /** + * Change the Swift_Message to apply the signing. + * + * @param Swift_Message $message + * + * @return Swift_Signers_SMimeSigner + */ + public function signMessage(Swift_Message $message) + { + if (null === $this->signCertificate && null === $this->encryptCert) { + return $this; + } + + // Store the message using ByteStream to a file{1} + // Remove all Children + // Sign file{1}, parse the new MIME headers and set them on the primary MimeEntity + // Set the singed-body as the new body (without boundary) + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $this->toSMimeByteStream($messageStream, $message); + $message->setEncoder(Swift_DependencyContainer::getInstance()->lookup('mime.rawcontentencoder')); + + $message->setChildren(array()); + $this->streamToMime($messageStream, $message); + } + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders() + { + return array('Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition'); + } + + /** + * @param Swift_InputByteStream $inputStream + * @param Swift_Message $mimeEntity + */ + protected function toSMimeByteStream(Swift_InputByteStream $inputStream, Swift_Message $message) + { + $mimeEntity = $this->createMessage($message); + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + $mimeEntity->toByteStream($messageStream); + $messageStream->commit(); + + if (null !== $this->signCertificate && null !== $this->encryptCert) { + $temporaryStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if ($this->signThenEncrypt) { + $this->messageStreamToSignedByteStream($messageStream, $temporaryStream); + $this->messageStreamToEncryptedByteStream($temporaryStream, $inputStream); + } else { + $this->messageStreamToEncryptedByteStream($messageStream, $temporaryStream); + $this->messageStreamToSignedByteStream($temporaryStream, $inputStream); + } + } elseif ($this->signCertificate !== null) { + $this->messageStreamToSignedByteStream($messageStream, $inputStream); + } else { + $this->messageStreamToEncryptedByteStream($messageStream, $inputStream); + } + } + + /** + * @param Swift_Message $message + * + * @return Swift_Message + */ + protected function createMessage(Swift_Message $message) + { + $mimeEntity = new Swift_Message('', $message->getBody(), $message->getContentType(), $message->getCharset()); + $mimeEntity->setChildren($message->getChildren()); + + $messageHeaders = $mimeEntity->getHeaders(); + $messageHeaders->remove('Message-ID'); + $messageHeaders->remove('Date'); + $messageHeaders->remove('Subject'); + $messageHeaders->remove('MIME-Version'); + $messageHeaders->remove('To'); + $messageHeaders->remove('From'); + + return $mimeEntity; + } + + /** + * @param Swift_FileStream $outputStream + * @param Swift_InputByteStream $inputStream + * + * @throws Swift_IoException + */ + protected function messageStreamToSignedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $inputStream) + { + $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + $args = array($outputStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, array(), $this->signOptions); + if (null !== $this->extraCerts) { + $args[] = $this->extraCerts; + } + + if (!call_user_func_array('openssl_pkcs7_sign', $args)) { + throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); + } + + $this->copyFromOpenSSLOutput($signedMessageStream, $inputStream); + } + + /** + * @param Swift_FileStream $outputStream + * @param Swift_InputByteStream $is + * + * @throws Swift_IoException + */ + protected function messageStreamToEncryptedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $is) + { + $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_encrypt($outputStream->getPath(), $encryptedMessageStream->getPath(), $this->encryptCert, array(), 0, $this->encryptCipher)) { + throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); + } + + $this->copyFromOpenSSLOutput($encryptedMessageStream, $is); + } + + /** + * @param Swift_OutputByteStream $fromStream + * @param Swift_InputByteStream $toStream + */ + protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream) + { + $bufferLength = 4096; + $filteredStream = new Swift_ByteStream_TemporaryFileByteStream(); + $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); + $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $filteredStream->write($buffer); + } + + $filteredStream->flushBuffers(); + + while (false !== ($buffer = $filteredStream->read($bufferLength))) { + $toStream->write($buffer); + } + + $toStream->commit(); + } + + /** + * Merges an OutputByteStream to Swift_Message. + * + * @param Swift_OutputByteStream $fromStream + * @param Swift_Message $message + */ + protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message) + { + $bufferLength = 78; + $headerData = ''; + + $fromStream->setReadPointer(0); + + while (($buffer = $fromStream->read($bufferLength)) !== false) { + $headerData .= $buffer; + + if (false !== strpos($buffer, "\r\n\r\n")) { + break; + } + } + + $headersPosEnd = strpos($headerData, "\r\n\r\n"); + $headerData = trim($headerData); + $headerData = substr($headerData, 0, $headersPosEnd); + $headerLines = explode("\r\n", $headerData); + unset($headerData); + + $headers = array(); + $currentHeaderName = ''; + + foreach ($headerLines as $headerLine) { + // Line separated + if (ctype_space($headerLines[0]) || false === strpos($headerLine, ':')) { + $headers[$currentHeaderName] .= ' '.trim($headerLine); + continue; + } + + $header = explode(':', $headerLine, 2); + $currentHeaderName = strtolower($header[0]); + $headers[$currentHeaderName] = trim($header[1]); + } + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $messageStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); + $messageStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); + + $messageHeaders = $message->getHeaders(); + + // No need to check for 'application/pkcs7-mime', as this is always base64 + if ('multipart/signed;' === substr($headers['content-type'], 0, 17)) { + if (!preg_match('/boundary=("[^"]+"|(?:[^\s]+|$))/is', $headers['content-type'], $contentTypeData)) { + throw new Swift_SwiftException('Failed to find Boundary parameter'); + } + + $boundary = trim($contentTypeData['1'], '"'); + + // Skip the header and CRLF CRLF + $fromStream->setReadPointer($headersPosEnd + 4); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $messageStream->write($buffer); + } + + $messageStream->commit(); + + $messageHeaders->remove('Content-Transfer-Encoding'); + $message->setContentType($headers['content-type']); + $message->setBoundary($boundary); + $message->setBody($messageStream); + } else { + $fromStream->setReadPointer($headersPosEnd + 4); + + if (null === $this->headerFactory) { + $this->headerFactory = Swift_DependencyContainer::getInstance()->lookup('mime.headerfactory'); + } + + $message->setContentType($headers['content-type']); + $messageHeaders->set($this->headerFactory->createTextHeader('Content-Transfer-Encoding', $headers['content-transfer-encoding'])); + $messageHeaders->set($this->headerFactory->createTextHeader('Content-Disposition', $headers['content-disposition'])); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $messageStream->write($buffer); + } + + $messageStream->commit(); + $message->setBody($messageStream); + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/SmtpTransport.php b/lib/SwiftMailer/classes/Swift/SmtpTransport.php new file mode 100644 index 0000000..6251611 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/SmtpTransport.php @@ -0,0 +1,58 @@ +createDependenciesFor('transport.smtp') + ); + + $this->setHost($host); + $this->setPort($port); + $this->setEncryption($security); + } + + /** + * Create a new SmtpTransport instance. + * + * @param string $host + * @param int $port + * @param string $security + * + * @return Swift_SmtpTransport + */ + public static function newInstance($host = 'localhost', $port = 25, $security = null) + { + return new self($host, $port, $security); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Spool.php b/lib/SwiftMailer/classes/Swift/Spool.php new file mode 100644 index 0000000..c16ab4b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Spool.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Interface for spools. + * + * @author Fabien Potencier + */ +interface Swift_Spool +{ + /** + * Starts this Spool mechanism. + */ + public function start(); + + /** + * Stops this Spool mechanism. + */ + public function stop(); + + /** + * Tests if this Spool mechanism has started. + * + * @return bool + */ + public function isStarted(); + + /** + * Queues a message. + * + * @param Swift_Mime_Message $message The message to store + * + * @return bool Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_Message $message); + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null); +} diff --git a/lib/SwiftMailer/classes/Swift/SpoolTransport.php b/lib/SwiftMailer/classes/Swift/SpoolTransport.php new file mode 100644 index 0000000..cf9bf78 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/SpoolTransport.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in a queue. + * + * @author Fabien Potencier + */ +class Swift_SpoolTransport extends Swift_Transport_SpoolTransport +{ + /** + * Create a new SpoolTransport. + * + * @param Swift_Spool $spool + */ + public function __construct(Swift_Spool $spool) + { + $arguments = Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.spool'); + + $arguments[] = $spool; + + call_user_func_array( + array($this, 'Swift_Transport_SpoolTransport::__construct'), + $arguments + ); + } + + /** + * Create a new SpoolTransport instance. + * + * @param Swift_Spool $spool + * + * @return Swift_SpoolTransport + */ + public static function newInstance(Swift_Spool $spool) + { + return new self($spool); + } +} diff --git a/lib/SwiftMailer/classes/Swift/StreamFilter.php b/lib/SwiftMailer/classes/Swift/StreamFilter.php new file mode 100644 index 0000000..362be2e --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/StreamFilter.php @@ -0,0 +1,35 @@ +_search = $search; + $this->_index = array(); + $this->_tree = array(); + $this->_replace = array(); + $this->_repSize = array(); + + $tree = null; + $i = null; + $last_size = $size = 0; + foreach ($search as $i => $search_element) { + if ($tree !== null) { + $tree[-1] = min(count($replace) - 1, $i - 1); + $tree[-2] = $last_size; + } + $tree = &$this->_tree; + if (is_array($search_element)) { + foreach ($search_element as $k => $char) { + $this->_index[$char] = true; + if (!isset($tree[$char])) { + $tree[$char] = array(); + } + $tree = &$tree[$char]; + } + $last_size = $k + 1; + $size = max($size, $last_size); + } else { + $last_size = 1; + if (!isset($tree[$search_element])) { + $tree[$search_element] = array(); + } + $tree = &$tree[$search_element]; + $size = max($last_size, $size); + $this->_index[$search_element] = true; + } + } + if ($i !== null) { + $tree[-1] = min(count($replace) - 1, $i); + $tree[-2] = $last_size; + $this->_treeMaxLen = $size; + } + foreach ($replace as $rep) { + if (!is_array($rep)) { + $rep = array($rep); + } + $this->_replace[] = $rep; + } + for ($i = count($this->_replace) - 1; $i >= 0; --$i) { + $this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i); + $this->_repSize[$i] = count($rep); + } + } + + /** + * Returns true if based on the buffer passed more bytes should be buffered. + * + * @param array $buffer + * + * @return bool + */ + public function shouldBuffer($buffer) + { + $endOfBuffer = end($buffer); + + return isset($this->_index[$endOfBuffer]); + } + + /** + * Perform the actual replacements on $buffer and return the result. + * + * @param array $buffer + * @param int $_minReplaces + * + * @return array + */ + public function filter($buffer, $_minReplaces = -1) + { + if ($this->_treeMaxLen == 0) { + return $buffer; + } + + $newBuffer = array(); + $buf_size = count($buffer); + $last_size = 0; + for ($i = 0; $i < $buf_size; ++$i) { + $search_pos = $this->_tree; + $last_found = PHP_INT_MAX; + // We try to find if the next byte is part of a search pattern + for ($j = 0; $j <= $this->_treeMaxLen; ++$j) { + // We have a new byte for a search pattern + if (isset($buffer [$p = $i + $j]) && isset($search_pos[$buffer[$p]])) { + $search_pos = $search_pos[$buffer[$p]]; + // We have a complete pattern, save, in case we don't find a better match later + if (isset($search_pos[-1]) && $search_pos[-1] < $last_found + && $search_pos[-1] > $_minReplaces) { + $last_found = $search_pos[-1]; + $last_size = $search_pos[-2]; + } + } + // We got a complete pattern + elseif ($last_found !== PHP_INT_MAX) { + // Adding replacement datas to output buffer + $rep_size = $this->_repSize[$last_found]; + for ($j = 0; $j < $rep_size; ++$j) { + $newBuffer[] = $this->_replace[$last_found][$j]; + } + // We Move cursor forward + $i += $last_size - 1; + // Edge Case, last position in buffer + if ($i >= $buf_size) { + $newBuffer[] = $buffer[$i]; + } + + // We start the next loop + continue 2; + } else { + // this byte is not in a pattern and we haven't found another pattern + break; + } + } + // Normal byte, move it to output buffer + $newBuffer[] = $buffer[$i]; + } + + return $newBuffer; + } +} diff --git a/lib/SwiftMailer/classes/Swift/StreamFilters/StringReplacementFilter.php b/lib/SwiftMailer/classes/Swift/StreamFilters/StringReplacementFilter.php new file mode 100644 index 0000000..d0db8b9 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/StreamFilters/StringReplacementFilter.php @@ -0,0 +1,66 @@ +_search = $search; + $this->_replace = $replace; + } + + /** + * Returns true if based on the buffer passed more bytes should be buffered. + * + * @param string $buffer + * + * @return bool + */ + public function shouldBuffer($buffer) + { + $endOfBuffer = substr($buffer, -1); + foreach ((array) $this->_search as $needle) { + if (false !== strpos($needle, $endOfBuffer)) { + return true; + } + } + + return false; + } + + /** + * Perform the actual replacements on $buffer and return the result. + * + * @param string $buffer + * + * @return string + */ + public function filter($buffer) + { + return str_replace($this->_search, $this->_replace, $buffer); + } +} diff --git a/lib/SwiftMailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/lib/SwiftMailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php new file mode 100644 index 0000000..e98240b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php @@ -0,0 +1,45 @@ +_filters[$search][$replace])) { + if (!isset($this->_filters[$search])) { + $this->_filters[$search] = array(); + } + + if (!isset($this->_filters[$search][$replace])) { + $this->_filters[$search][$replace] = array(); + } + + $this->_filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace); + } + + return $this->_filters[$search][$replace]; + } +} diff --git a/lib/SwiftMailer/classes/Swift/SwiftException.php b/lib/SwiftMailer/classes/Swift/SwiftException.php new file mode 100644 index 0000000..db3d310 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/SwiftException.php @@ -0,0 +1,29 @@ +_eventDispatcher = $dispatcher; + $this->_buffer = $buf; + $this->_lookupHostname(); + } + + /** + * Set the name of the local domain which Swift will identify itself as. + * + * This should be a fully-qualified domain name and should be truly the domain + * you're using. + * + * If your server doesn't have a domain name, use the IP in square + * brackets (i.e. [127.0.0.1]). + * + * @param string $domain + * + * @return Swift_Transport_AbstractSmtpTransport + */ + public function setLocalDomain($domain) + { + $this->_domain = $domain; + + return $this; + } + + /** + * Get the name of the domain Swift will identify as. + * + * @return string + */ + public function getLocalDomain() + { + return $this->_domain; + } + + /** + * Sets the source IP. + * + * @param string $source + */ + public function setSourceIp($source) + { + $this->_sourceIp = $source; + } + + /** + * Returns the IP used to connect to the destination. + * + * @return string + */ + public function getSourceIp() + { + return $this->_sourceIp; + } + + /** + * Start the SMTP connection. + */ + public function start() + { + if (!$this->_started) { + if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted'); + if ($evt->bubbleCancelled()) { + return; + } + } + + try { + $this->_buffer->initialize($this->_getBufferParams()); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + $this->_readGreeting(); + $this->_doHeloCommand(); + + if ($evt) { + $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted'); + } + + $this->_started = true; + } + } + + /** + * Test if an SMTP connection has been established. + * + * @return bool + */ + public function isStarted() + { + return $this->_started; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $sent = 0; + $failedRecipients = (array) $failedRecipients; + + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if (!$reversePath = $this->_getReversePath($message)) { + $this->_throwException(new Swift_TransportException( + 'Cannot send message without a sender address' + ) + ); + } + + $to = (array) $message->getTo(); + $cc = (array) $message->getCc(); + $tos = array_merge($to, $cc); + $bcc = (array) $message->getBcc(); + + $message->setBcc(array()); + + try { + $sent += $this->_sendTo($message, $reversePath, $tos, $failedRecipients); + $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients); + } catch (Exception $e) { + $message->setBcc($bcc); + throw $e; + } + + $message->setBcc($bcc); + + if ($evt) { + if ($sent == count($to) + count($cc) + count($bcc)) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + } elseif ($sent > 0) { + $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE); + } else { + $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); + } + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); //Make sure a new Message ID is used + + return $sent; + } + + /** + * Stop the SMTP connection. + */ + public function stop() + { + if ($this->_started) { + if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped'); + if ($evt->bubbleCancelled()) { + return; + } + } + + try { + $this->executeCommand("QUIT\r\n", array(221)); + } catch (Swift_TransportException $e) { + } + + try { + $this->_buffer->terminate(); + + if ($evt) { + $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped'); + } + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + } + $this->_started = false; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } + + /** + * Reset the current mail transaction. + */ + public function reset() + { + $this->executeCommand("RSET\r\n", array(250)); + } + + /** + * Get the IoBuffer where read/writes are occurring. + * + * @return Swift_Transport_IoBuffer + */ + public function getBuffer() + { + return $this->_buffer; + } + + /** + * Run a command against the buffer, expecting the given response codes. + * + * If no response codes are given, the response will not be validated. + * If codes are given, an exception will be thrown on an invalid response. + * + * @param string $command + * @param int[] $codes + * @param string[] $failures An array of failures by-reference + * + * @return string + */ + public function executeCommand($command, $codes = array(), &$failures = null) + { + $failures = (array) $failures; + $seq = $this->_buffer->write($command); + $response = $this->_getFullResponse($seq); + if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) { + $this->_eventDispatcher->dispatchEvent($evt, 'commandSent'); + } + $this->_assertResponseCode($response, $codes); + + return $response; + } + + /** Read the opening SMTP greeting */ + protected function _readGreeting() + { + $this->_assertResponseCode($this->_getFullResponse(0), array(220)); + } + + /** Send the HELO welcome */ + protected function _doHeloCommand() + { + $this->executeCommand( + sprintf("HELO %s\r\n", $this->_domain), array(250) + ); + } + + /** Send the MAIL FROM command */ + protected function _doMailFromCommand($address) + { + $this->executeCommand( + sprintf("MAIL FROM:<%s>\r\n", $address), array(250) + ); + } + + /** Send the RCPT TO command */ + protected function _doRcptToCommand($address) + { + $this->executeCommand( + sprintf("RCPT TO:<%s>\r\n", $address), array(250, 251, 252) + ); + } + + /** Send the DATA command */ + protected function _doDataCommand() + { + $this->executeCommand("DATA\r\n", array(354)); + } + + /** Stream the contents of the message over the buffer */ + protected function _streamMessage(Swift_Mime_Message $message) + { + $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n..")); + try { + $message->toByteStream($this->_buffer); + $this->_buffer->flushBuffers(); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + $this->_buffer->setWriteTranslations(array()); + $this->executeCommand("\r\n.\r\n", array(250)); + } + + /** Determine the best-use reverse path for this message */ + protected function _getReversePath(Swift_Mime_Message $message) + { + $return = $message->getReturnPath(); + $sender = $message->getSender(); + $from = $message->getFrom(); + $path = null; + if (!empty($return)) { + $path = $return; + } elseif (!empty($sender)) { + // Don't use array_keys + reset($sender); // Reset Pointer to first pos + $path = key($sender); // Get key + } elseif (!empty($from)) { + reset($from); // Reset Pointer to first pos + $path = key($from); // Get key + } + + return $path; + } + + /** Throw a TransportException, first sending it to any listeners */ + protected function _throwException(Swift_TransportException $e) + { + if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { + $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); + if (!$evt->bubbleCancelled()) { + throw $e; + } + } else { + throw $e; + } + } + + /** Throws an Exception if a response code is incorrect */ + protected function _assertResponseCode($response, $wanted) + { + list($code) = sscanf($response, '%3d'); + $valid = (empty($wanted) || in_array($code, $wanted)); + + if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response, + $valid)) { + $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived'); + } + + if (!$valid) { + $this->_throwException( + new Swift_TransportException( + 'Expected response code '.implode('/', $wanted).' but got code '. + '"'.$code.'", with message "'.$response.'"', + $code) + ); + } + } + + /** Get an entire multi-line response using its sequence number */ + protected function _getFullResponse($seq) + { + $response = ''; + try { + do { + $line = $this->_buffer->readLine($seq); + $response .= $line; + } while (null !== $line && false !== $line && ' ' != $line{3}); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } catch (Swift_IoException $e) { + $this->_throwException( + new Swift_TransportException( + $e->getMessage()) + ); + } + + return $response; + } + + /** Send an email to the given recipients from the given reverse path */ + private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients) + { + $sent = 0; + $this->_doMailFromCommand($reversePath); + foreach ($recipients as $forwardPath) { + try { + $this->_doRcptToCommand($forwardPath); + ++$sent; + } catch (Swift_TransportException $e) { + $failedRecipients[] = $forwardPath; + } + } + + if ($sent != 0) { + $this->_doDataCommand(); + $this->_streamMessage($message); + } else { + $this->reset(); + } + + return $sent; + } + + /** Send a message to the given To: recipients */ + private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients) + { + if (empty($to)) { + return 0; + } + + return $this->_doMailTransaction($message, $reversePath, array_keys($to), + $failedRecipients); + } + + /** Send a message to all Bcc: recipients */ + private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients) + { + $sent = 0; + foreach ($bcc as $forwardPath => $name) { + $message->setBcc(array($forwardPath => $name)); + $sent += $this->_doMailTransaction( + $message, $reversePath, array($forwardPath), $failedRecipients + ); + } + + return $sent; + } + + /** Try to determine the hostname of the server this is run on */ + private function _lookupHostname() + { + if (!empty($_SERVER['SERVER_NAME']) && $this->_isFqdn($_SERVER['SERVER_NAME'])) { + $this->_domain = $_SERVER['SERVER_NAME']; + } elseif (!empty($_SERVER['SERVER_ADDR'])) { + // Set the address literal tag (See RFC 5321, section: 4.1.3) + if (false === strpos($_SERVER['SERVER_ADDR'], ':')) { + $prefix = ''; // IPv4 addresses are not tagged. + } else { + $prefix = 'IPv6:'; // Adding prefix in case of IPv6. + } + + $this->_domain = sprintf('[%s%s]', $prefix, $_SERVER['SERVER_ADDR']); + } + } + + /** Determine is the $hostname is a fully-qualified name */ + private function _isFqdn($hostname) + { + // We could do a really thorough check, but there's really no point + if (false !== $dotPos = strpos($hostname, '.')) { + return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1); + } + + return false; + } + + /** + * Destructor. + */ + public function __destruct() + { + $this->stop(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php new file mode 100644 index 0000000..53f721d --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php @@ -0,0 +1,81 @@ +executeCommand("AUTH CRAM-MD5\r\n", array(334)); + $challenge = base64_decode(substr($challenge, 4)); + $message = base64_encode( + $username.' '.$this->_getResponse($password, $challenge) + ); + $agent->executeCommand(sprintf("%s\r\n", $message), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + /** + * Generate a CRAM-MD5 response from a server challenge. + * + * @param string $secret + * @param string $challenge + * + * @return string + */ + private function _getResponse($secret, $challenge) + { + if (strlen($secret) > 64) { + $secret = pack('H32', md5($secret)); + } + + if (strlen($secret) < 64) { + $secret = str_pad($secret, 64, chr(0)); + } + + $k_ipad = substr($secret, 0, 64) ^ str_repeat(chr(0x36), 64); + $k_opad = substr($secret, 0, 64) ^ str_repeat(chr(0x5C), 64); + + $inner = pack('H32', md5($k_ipad.$challenge)); + $digest = md5($k_opad.$inner); + + return $digest; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php new file mode 100644 index 0000000..6ab6e33 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php @@ -0,0 +1,51 @@ +executeCommand("AUTH LOGIN\r\n", array(334)); + $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), array(334)); + $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php new file mode 100644 index 0000000..eb04acf --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php @@ -0,0 +1,720 @@ + + */ +class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator +{ + const NTLMSIG = "NTLMSSP\x00"; + const DESCONST = 'KGS!@#$%'; + + /** + * Get the name of the AUTH mechanism this Authenticator handles. + * + * @return string + */ + public function getAuthKeyword() + { + return 'NTLM'; + } + + /** + * Try to authenticate the user with $username and $password. + * + * @param Swift_Transport_SmtpAgent $agent + * @param string $username + * @param string $password + * + * @return bool + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) + { + if (!function_exists('openssl_random_pseudo_bytes') || !function_exists('openssl_encrypt')) { + throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); + } + + if (!function_exists('bcmul')) { + throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.'); + } + + try { + // execute AUTH command and filter out the code at the beginning + // AUTH NTLM xxxx + $response = base64_decode(substr(trim($this->sendMessage1($agent)), 4)); + + // extra parameters for our unit cases + $timestamp = func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000')); + $client = func_num_args() > 4 ? func_get_arg(4) : $this->getRandomBytes(8); + + // Message 3 response + $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + protected function si2bin($si, $bits = 32) + { + $bin = null; + if ($si >= -pow(2, $bits - 1) && ($si <= pow(2, $bits - 1))) { + // positive or zero + if ($si >= 0) { + $bin = base_convert($si, 10, 2); + // pad to $bits bit + $bin_length = strlen($bin); + if ($bin_length < $bits) { + $bin = str_repeat('0', $bits - $bin_length).$bin; + } + } else { + // negative + $si = -$si - pow(2, $bits); + $bin = base_convert($si, 10, 2); + $bin_length = strlen($bin); + if ($bin_length > $bits) { + $bin = str_repeat('1', $bits - $bin_length).$bin; + } + } + } + + return $bin; + } + + /** + * Send our auth message and returns the response. + * + * @param Swift_Transport_SmtpAgent $agent + * + * @return string SMTP Response + */ + protected function sendMessage1(Swift_Transport_SmtpAgent $agent) + { + $message = $this->createMessage1(); + + return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), array(334)); + } + + /** + * Fetch all details of our response (message 2). + * + * @param string $response + * + * @return array our response parsed + */ + protected function parseMessage2($response) + { + $responseHex = bin2hex($response); + $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2; + $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2; + $challenge = $this->hex2bin(substr($responseHex, 48, 16)); + $context = $this->hex2bin(substr($responseHex, 64, 16)); + $targetInfoH = $this->hex2bin(substr($responseHex, 80, 16)); + $targetName = $this->hex2bin(substr($responseHex, $offset, $length)); + $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2; + $targetInfoBlock = substr($responseHex, $offset); + list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock); + + return array( + $challenge, + $context, + $targetInfoH, + $targetName, + $domainName, + $serverName, + $DNSDomainName, + $DNSServerName, + $this->hex2bin($targetInfoBlock), + $terminatorByte, + ); + } + + /** + * Read the blob information in from message2. + * + * @param $block + * + * @return array + */ + protected function readSubBlock($block) + { + // remove terminatorByte cause it's always the same + $block = substr($block, 0, -8); + + $length = strlen($block); + $offset = 0; + $data = array(); + while ($offset < $length) { + $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256; + $offset += 8; + $data[] = $this->hex2bin(substr($block, $offset, $blockLength * 2)); + $offset += $blockLength * 2; + } + + if (count($data) == 3) { + $data[] = $data[2]; + $data[2] = ''; + } + + $data[] = $this->createByte('00'); + + return $data; + } + + /** + * Send our final message with all our data. + * + * @param string $response Message 1 response (message 2) + * @param string $username + * @param string $password + * @param string $timestamp + * @param string $client + * @param Swift_Transport_SmtpAgent $agent + * @param bool $v2 Use version2 of the protocol + * + * @return string + */ + protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true) + { + list($domain, $username) = $this->getDomainAndUsername($username); + //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter + list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response); + + if (!$v2) { + // LMv1 + $lmResponse = $this->createLMPassword($password, $challenge); + // NTLMv1 + $ntlmResponse = $this->createNTLMPassword($password, $challenge); + } else { + // LMv2 + $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client); + // NTLMv2 + $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client); + } + + $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse); + + return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), array(235)); + } + + /** + * Create our message 1. + * + * @return string + */ + protected function createMessage1() + { + return self::NTLMSIG + .$this->createByte('01') // Message 1 +.$this->createByte('0702'); // Flags + } + + /** + * Create our message 3. + * + * @param string $domain + * @param string $username + * @param string $workstation + * @param string $lmResponse + * @param string $ntlmResponse + * + * @return string + */ + protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse) + { + // Create security buffers + $domainSec = $this->createSecurityBuffer($domain, 64); + $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec)); + $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2); + $userInfo = $this->readSecurityBuffer(bin2hex($userSec)); + $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2); + $workInfo = $this->readSecurityBuffer(bin2hex($workSec)); + $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true); + $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec)); + $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true); + + return self::NTLMSIG + .$this->createByte('03') // TYPE 3 message +.$lmSec // LM response header +.$ntlmSec // NTLM response header +.$domainSec // Domain header +.$userSec // User header +.$workSec // Workstation header +.$this->createByte('000000009a', 8) // session key header (empty) +.$this->createByte('01020000') // FLAGS +.$this->convertTo16bit($domain) // domain name +.$this->convertTo16bit($username) // username +.$this->convertTo16bit($workstation) // workstation +.$lmResponse + .$ntlmResponse; + } + + /** + * @param string $timestamp Epoch timestamp in microseconds + * @param string $client Random bytes + * @param string $targetInfo + * + * @return string + */ + protected function createBlob($timestamp, $client, $targetInfo) + { + return $this->createByte('0101') + .$this->createByte('00') + .$timestamp + .$client + .$this->createByte('00') + .$targetInfo + .$this->createByte('00'); + } + + /** + * Get domain and username from our username. + * + * @example DOMAIN\username + * + * @param string $name + * + * @return array + */ + protected function getDomainAndUsername($name) + { + if (strpos($name, '\\') !== false) { + return explode('\\', $name); + } + + list($user, $domain) = explode('@', $name); + + return array($domain, $user); + } + + /** + * Create LMv1 response. + * + * @param string $password + * @param string $challenge + * + * @return string + */ + protected function createLMPassword($password, $challenge) + { + // FIRST PART + $password = $this->createByte(strtoupper($password), 14, false); + list($key1, $key2) = str_split($password, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + + $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false); + + // SECOND PART + list($key1, $key2, $key3) = str_split($constantDecrypt, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + $desKey3 = $this->createDesKey($key3); + + return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); + } + + /** + * Create NTLMv1 response. + * + * @param string $password + * @param string $challenge + * + * @return string + */ + protected function createNTLMPassword($password, $challenge) + { + // FIRST PART + $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false); + list($key1, $key2, $key3) = str_split($ntlmHash, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + $desKey3 = $this->createDesKey($key3); + + return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3); + } + + /** + * Convert a normal timestamp to a tenth of a microtime epoch time. + * + * @param string $time + * + * @return string + */ + protected function getCorrectTimestamp($time) + { + // Get our timestamp (tricky!) + bcscale(0); + + $time = number_format($time, 0, '.', ''); // save microtime to string + $time = bcadd($time, '11644473600000'); // add epoch time + $time = bcmul($time, 10000); // tenths of a microsecond. + + $binary = $this->si2bin($time, 64); // create 64 bit binary string + $timestamp = ''; + for ($i = 0; $i < 8; ++$i) { + $timestamp .= chr(bindec(substr($binary, -(($i + 1) * 8), 8))); + } + + return $timestamp; + } + + /** + * Create LMv2 response. + * + * @param string $password + * @param string $username + * @param string $domain + * @param string $challenge NTLM Challenge + * @param string $client Random string + * + * @return string + */ + protected function createLMv2Password($password, $username, $domain, $challenge, $client) + { + $lmPass = '00'; // by default 00 + // if $password > 15 than we can't use this method + if (strlen($password) <= 15) { + $ntlmHash = $this->md4Encrypt($password); + $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); + + $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client); + } + + return $this->createByte($lmPass, 24); + } + + /** + * Create NTLMv2 response. + * + * @param string $password + * @param string $username + * @param string $domain + * @param string $challenge Hex values + * @param string $targetInfo Hex values + * @param string $timestamp + * @param string $client Random bytes + * + * @return string + * + * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse + */ + protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client) + { + $ntlmHash = $this->md4Encrypt($password); + $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain)); + + // create blob + $blob = $this->createBlob($timestamp, $client, $targetInfo); + + $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob); + + return $ntlmv2Response.$blob; + } + + protected function createDesKey($key) + { + $material = array(bin2hex($key[0])); + $len = strlen($key); + for ($i = 1; $i < $len; ++$i) { + list($high, $low) = str_split(bin2hex($key[$i])); + $v = $this->castToByte(ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i)); + $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte + } + $material[] = str_pad(substr(dechex($this->castToByte(ord($key[6]) << 1)), -2), 2, '0'); + + // odd parity + foreach ($material as $k => $v) { + $b = $this->castToByte(hexdec($v)); + $needsParity = (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5) + ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2) + ^ $this->uRShift($b, 1)) & 0x01) == 0; + + list($high, $low) = str_split($v); + if ($needsParity) { + $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1); + } else { + $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe); + } + } + + return $this->hex2bin(implode('', $material)); + } + + /** HELPER FUNCTIONS */ + /** + * Create our security buffer depending on length and offset. + * + * @param string $value Value we want to put in + * @param int $offset start of value + * @param bool $is16 Do we 16bit string or not? + * + * @return string + */ + protected function createSecurityBuffer($value, $offset, $is16 = false) + { + $length = strlen(bin2hex($value)); + $length = $is16 ? $length / 2 : $length; + $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2); + + return $length.$length.$this->createByte(dechex($offset), 4); + } + + /** + * Read our security buffer to fetch length and offset of our value. + * + * @param string $value Securitybuffer in hex + * + * @return array array with length and offset + */ + protected function readSecurityBuffer($value) + { + $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2; + $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2; + + return array($length, $offset); + } + + /** + * Cast to byte java equivalent to (byte). + * + * @param int $v + * + * @return int + */ + protected function castToByte($v) + { + return (($v + 128) % 256) - 128; + } + + /** + * Java unsigned right bitwise + * $a >>> $b. + * + * @param int $a + * @param int $b + * + * @return int + */ + protected function uRShift($a, $b) + { + if ($b == 0) { + return $a; + } + + return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1)); + } + + /** + * Right padding with 0 to certain length. + * + * @param string $input + * @param int $bytes Length of bytes + * @param bool $isHex Did we provided hex value + * + * @return string + */ + protected function createByte($input, $bytes = 4, $isHex = true) + { + if ($isHex) { + $byte = $this->hex2bin(str_pad($input, $bytes * 2, '00')); + } else { + $byte = str_pad($input, $bytes, "\x00"); + } + + return $byte; + } + + /** + * Create random bytes. + * + * @param $length + * + * @return string + */ + protected function getRandomBytes($length) + { + $bytes = openssl_random_pseudo_bytes($length, $strong); + + if (false !== $bytes && true === $strong) { + return $bytes; + } + + throw new RuntimeException('OpenSSL did not produce a secure random number.'); + } + + /** ENCRYPTION ALGORITHMS */ + /** + * DES Encryption. + * + * @param string $value An 8-byte string + * @param string $key + * + * @return string + */ + protected function desEncrypt($value, $key) + { + // 1 == OPENSSL_RAW_DATA - but constant is only available as of PHP 5.4. + return substr(openssl_encrypt($value, 'DES-ECB', $key, 1), 0, 8); + } + + /** + * MD5 Encryption. + * + * @param string $key Encryption key + * @param string $msg Message to encrypt + * + * @return string + */ + protected function md5Encrypt($key, $msg) + { + $blocksize = 64; + if (strlen($key) > $blocksize) { + $key = pack('H*', md5($key)); + } + + $key = str_pad($key, $blocksize, "\0"); + $ipadk = $key ^ str_repeat("\x36", $blocksize); + $opadk = $key ^ str_repeat("\x5c", $blocksize); + + return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg)))); + } + + /** + * MD4 Encryption. + * + * @param string $input + * + * @return string + * + * @see http://php.net/manual/en/ref.hash.php + */ + protected function md4Encrypt($input) + { + $input = $this->convertTo16bit($input); + + return function_exists('hash') ? $this->hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input); + } + + /** + * Convert UTF-8 to UTF-16. + * + * @param string $input + * + * @return string + */ + protected function convertTo16bit($input) + { + return iconv('UTF-8', 'UTF-16LE', $input); + } + + /** + * Hex2bin replacement for < PHP 5.4. + * + * @param string $hex + * + * @return string Binary + */ + protected function hex2bin($hex) + { + if (function_exists('hex2bin')) { + return hex2bin($hex); + } else { + return pack('H*', $hex); + } + } + + /** + * @param string $message + */ + protected function debug($message) + { + $message = bin2hex($message); + $messageId = substr($message, 16, 8); + echo substr($message, 0, 16)." NTLMSSP Signature
      \n"; + echo $messageId." Type Indicator
      \n"; + + if ($messageId == '02000000') { + $map = array( + 'Challenge', + 'Context', + 'Target Information Security Buffer', + 'Target Name Data', + 'NetBIOS Domain Name', + 'NetBIOS Server Name', + 'DNS Domain Name', + 'DNS Server Name', + 'BLOB', + 'Target Information Terminator', + ); + + $data = $this->parseMessage2($this->hex2bin($message)); + + foreach ($map as $key => $value) { + echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."
      \n"; + } + } elseif ($messageId == '03000000') { + $i = 0; + $data[$i++] = substr($message, 24, 16); + list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 40, 16); + list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 56, 16); + list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 72, 16); + list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 88, 16); + list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 104, 16); + $data[$i++] = substr($message, 120, 8); + $data[$i++] = substr($message, $targetOffset, $targetLength); + $data[$i++] = substr($message, $userOffset, $userLength); + $data[$i++] = substr($message, $workOffset, $workLength); + $data[$i++] = substr($message, $lmOffset, $lmLength); + $data[$i] = substr($message, $ntmlOffset, $ntmlLength); + + $map = array( + 'LM Response Security Buffer', + 'NTLM Response Security Buffer', + 'Target Name Security Buffer', + 'User Name Security Buffer', + 'Workstation Name Security Buffer', + 'Session Key Security Buffer', + 'Flags', + 'Target Name Data', + 'User Name Data', + 'Workstation Name Data', + 'LM Response Data', + 'NTLM Response Data', + ); + + foreach ($map as $key => $value) { + echo $data[$key].' - '.$this->hex2bin($data[$key]).' ||| '.$value."
      \n"; + } + } + + echo '

      '; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php new file mode 100644 index 0000000..43219f9 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php @@ -0,0 +1,50 @@ +executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 0000000..ca35e7b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,70 @@ + + * $transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 587, 'tls') + * ->setAuthMode('XOAUTH2') + * ->setUsername('YOUR_EMAIL_ADDRESS') + * ->setPassword('YOUR_ACCESS_TOKEN'); + * + * + * @author xu.li + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol + */ +class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator +{ + /** + * Get the name of the AUTH mechanism this Authenticator handles. + * + * @return string + */ + public function getAuthKeyword() + { + return 'XOAUTH2'; + } + + /** + * Try to authenticate the user with $email and $token. + * + * @param Swift_Transport_SmtpAgent $agent + * @param string $email + * @param string $token + * + * @return bool + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token) + { + try { + $param = $this->constructXOAuth2Params($email, $token); + $agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + /** + * Construct the auth parameter. + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism + */ + protected function constructXOAuth2Params($email, $token) + { + return base64_encode("user=$email\1auth=Bearer $token\1\1"); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/AuthHandler.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/AuthHandler.php new file mode 100644 index 0000000..cb36133 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/AuthHandler.php @@ -0,0 +1,263 @@ +setAuthenticators($authenticators); + } + + /** + * Set the Authenticators which can process a login request. + * + * @param Swift_Transport_Esmtp_Authenticator[] $authenticators + */ + public function setAuthenticators(array $authenticators) + { + $this->_authenticators = $authenticators; + } + + /** + * Get the Authenticators which can process a login request. + * + * @return Swift_Transport_Esmtp_Authenticator[] + */ + public function getAuthenticators() + { + return $this->_authenticators; + } + + /** + * Set the username to authenticate with. + * + * @param string $username + */ + public function setUsername($username) + { + $this->_username = $username; + } + + /** + * Get the username to authenticate with. + * + * @return string + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Set the password to authenticate with. + * + * @param string $password + */ + public function setPassword($password) + { + $this->_password = $password; + } + + /** + * Get the password to authenticate with. + * + * @return string + */ + public function getPassword() + { + return $this->_password; + } + + /** + * Set the auth mode to use to authenticate. + * + * @param string $mode + */ + public function setAuthMode($mode) + { + $this->_auth_mode = $mode; + } + + /** + * Get the auth mode to use to authenticate. + * + * @return string + */ + public function getAuthMode() + { + return $this->_auth_mode; + } + + /** + * Get the name of the ESMTP extension this handles. + * + * @return bool + */ + public function getHandledKeyword() + { + return 'AUTH'; + } + + /** + * Set the parameters which the EHLO greeting indicated. + * + * @param string[] $parameters + */ + public function setKeywordParams(array $parameters) + { + $this->_esmtpParams = $parameters; + } + + /** + * Runs immediately after a EHLO has been issued. + * + * @param Swift_Transport_SmtpAgent $agent to read/write + */ + public function afterEhlo(Swift_Transport_SmtpAgent $agent) + { + if ($this->_username) { + $count = 0; + foreach ($this->_getAuthenticatorsForAgent() as $authenticator) { + if (in_array(strtolower($authenticator->getAuthKeyword()), + array_map('strtolower', $this->_esmtpParams))) { + ++$count; + if ($authenticator->authenticate($agent, $this->_username, $this->_password)) { + return; + } + } + } + throw new Swift_TransportException( + 'Failed to authenticate on SMTP server with username "'. + $this->_username.'" using '.$count.' possible authenticators' + ); + } + } + + /** + * Not used. + */ + public function getMailParams() + { + return array(); + } + + /** + * Not used. + */ + public function getRcptParams() + { + return array(); + } + + /** + * Not used. + */ + public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false) + { + } + + /** + * Returns +1, -1 or 0 according to the rules for usort(). + * + * This method is called to ensure extensions can be execute in an appropriate order. + * + * @param string $esmtpKeyword to compare with + * + * @return int + */ + public function getPriorityOver($esmtpKeyword) + { + return 0; + } + + /** + * Returns an array of method names which are exposed to the Esmtp class. + * + * @return string[] + */ + public function exposeMixinMethods() + { + return array('setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode'); + } + + /** + * Not used. + */ + public function resetState() + { + } + + /** + * Returns the authenticator list for the given agent. + * + * @param Swift_Transport_SmtpAgent $agent + * + * @return array + */ + protected function _getAuthenticatorsForAgent() + { + if (!$mode = strtolower($this->_auth_mode)) { + return $this->_authenticators; + } + + foreach ($this->_authenticators as $authenticator) { + if (strtolower($authenticator->getAuthKeyword()) == $mode) { + return array($authenticator); + } + } + + throw new Swift_TransportException('Auth mode '.$mode.' is invalid'); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Authenticator.php b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Authenticator.php new file mode 100644 index 0000000..12a9abf --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/Esmtp/Authenticator.php @@ -0,0 +1,35 @@ +. + * + * @return string[] + */ + public function getMailParams(); + + /** + * Get params which are appended to RCPT TO:<>. + * + * @return string[] + */ + public function getRcptParams(); + + /** + * Runs when a command is due to be sent. + * + * @param Swift_Transport_SmtpAgent $agent to read/write + * @param string $command to send + * @param int[] $codes expected in response + * @param string[] $failedRecipients to collect failures + * @param bool $stop to be set true by-reference if the command is now sent + */ + public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false); + + /** + * Returns +1, -1 or 0 according to the rules for usort(). + * + * This method is called to ensure extensions can be execute in an appropriate order. + * + * @param string $esmtpKeyword to compare with + * + * @return int + */ + public function getPriorityOver($esmtpKeyword); + + /** + * Returns an array of method names which are exposed to the Esmtp class. + * + * @return string[] + */ + public function exposeMixinMethods(); + + /** + * Tells this handler to clear any buffers and reset its state. + */ + public function resetState(); +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/EsmtpTransport.php b/lib/SwiftMailer/classes/Swift/Transport/EsmtpTransport.php new file mode 100644 index 0000000..a220e6f --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/EsmtpTransport.php @@ -0,0 +1,413 @@ + 'tcp', + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + 'blocking' => 1, + 'tls' => false, + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'stream_context_options' => array(), + ); + + /** + * Creates a new EsmtpTransport using the given I/O buffer. + * + * @param Swift_Transport_IoBuffer $buf + * @param Swift_Transport_EsmtpHandler[] $extensionHandlers + * @param Swift_Events_EventDispatcher $dispatcher + */ + public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher) + { + parent::__construct($buf, $dispatcher); + $this->setExtensionHandlers($extensionHandlers); + } + + /** + * Set the host to connect to. + * + * @param string $host + * + * @return Swift_Transport_EsmtpTransport + */ + public function setHost($host) + { + $this->_params['host'] = $host; + + return $this; + } + + /** + * Get the host to connect to. + * + * @return string + */ + public function getHost() + { + return $this->_params['host']; + } + + /** + * Set the port to connect to. + * + * @param int $port + * + * @return Swift_Transport_EsmtpTransport + */ + public function setPort($port) + { + $this->_params['port'] = (int) $port; + + return $this; + } + + /** + * Get the port to connect to. + * + * @return int + */ + public function getPort() + { + return $this->_params['port']; + } + + /** + * Set the connection timeout. + * + * @param int $timeout seconds + * + * @return Swift_Transport_EsmtpTransport + */ + public function setTimeout($timeout) + { + $this->_params['timeout'] = (int) $timeout; + $this->_buffer->setParam('timeout', (int) $timeout); + + return $this; + } + + /** + * Get the connection timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->_params['timeout']; + } + + /** + * Set the encryption type (tls or ssl). + * + * @param string $encryption + * + * @return Swift_Transport_EsmtpTransport + */ + public function setEncryption($encryption) + { + $encryption = strtolower($encryption); + if ('tls' == $encryption) { + $this->_params['protocol'] = 'tcp'; + $this->_params['tls'] = true; + } else { + $this->_params['protocol'] = $encryption; + $this->_params['tls'] = false; + } + + return $this; + } + + /** + * Get the encryption type. + * + * @return string + */ + public function getEncryption() + { + return $this->_params['tls'] ? 'tls' : $this->_params['protocol']; + } + + /** + * Sets the stream context options. + * + * @param array $options + * + * @return Swift_Transport_EsmtpTransport + */ + public function setStreamOptions($options) + { + $this->_params['stream_context_options'] = $options; + + return $this; + } + + /** + * Returns the stream context options. + * + * @return array + */ + public function getStreamOptions() + { + return $this->_params['stream_context_options']; + } + + /** + * Sets the source IP. + * + * @param string $source + * + * @return Swift_Transport_EsmtpTransport + */ + public function setSourceIp($source) + { + $this->_params['sourceIp'] = $source; + + return $this; + } + + /** + * Returns the IP used to connect to the destination. + * + * @return string + */ + public function getSourceIp() + { + return isset($this->_params['sourceIp']) ? $this->_params['sourceIp'] : null; + } + + /** + * Set ESMTP extension handlers. + * + * @param Swift_Transport_EsmtpHandler[] $handlers + * + * @return Swift_Transport_EsmtpTransport + */ + public function setExtensionHandlers(array $handlers) + { + $assoc = array(); + foreach ($handlers as $handler) { + $assoc[$handler->getHandledKeyword()] = $handler; + } + + @uasort($assoc, array($this, '_sortHandlers')); + $this->_handlers = $assoc; + $this->_setHandlerParams(); + + return $this; + } + + /** + * Get ESMTP extension handlers. + * + * @return Swift_Transport_EsmtpHandler[] + */ + public function getExtensionHandlers() + { + return array_values($this->_handlers); + } + + /** + * Run a command against the buffer, expecting the given response codes. + * + * If no response codes are given, the response will not be validated. + * If codes are given, an exception will be thrown on an invalid response. + * + * @param string $command + * @param int[] $codes + * @param string[] $failures An array of failures by-reference + * + * @return string + */ + public function executeCommand($command, $codes = array(), &$failures = null) + { + $failures = (array) $failures; + $stopSignal = false; + $response = null; + foreach ($this->_getActiveHandlers() as $handler) { + $response = $handler->onCommand( + $this, $command, $codes, $failures, $stopSignal + ); + if ($stopSignal) { + return $response; + } + } + + return parent::executeCommand($command, $codes, $failures); + } + + // -- Mixin invocation code + + /** Mixin handling method for ESMTP handlers */ + public function __call($method, $args) + { + foreach ($this->_handlers as $handler) { + if (in_array(strtolower($method), + array_map('strtolower', (array) $handler->exposeMixinMethods()) + )) { + $return = call_user_func_array(array($handler, $method), $args); + // Allow fluid method calls + if (is_null($return) && substr($method, 0, 3) == 'set') { + return $this; + } else { + return $return; + } + } + } + trigger_error('Call to undefined method '.$method, E_USER_ERROR); + } + + /** Get the params to initialize the buffer */ + protected function _getBufferParams() + { + return $this->_params; + } + + /** Overridden to perform EHLO instead */ + protected function _doHeloCommand() + { + try { + $response = $this->executeCommand( + sprintf("EHLO %s\r\n", $this->_domain), array(250) + ); + } catch (Swift_TransportException $e) { + return parent::_doHeloCommand(); + } + + if ($this->_params['tls']) { + try { + $this->executeCommand("STARTTLS\r\n", array(220)); + + if (!$this->_buffer->startTLS()) { + throw new Swift_TransportException('Unable to connect with TLS encryption'); + } + + try { + $response = $this->executeCommand( + sprintf("EHLO %s\r\n", $this->_domain), array(250) + ); + } catch (Swift_TransportException $e) { + return parent::_doHeloCommand(); + } + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + } + + $this->_capabilities = $this->_getCapabilities($response); + $this->_setHandlerParams(); + foreach ($this->_getActiveHandlers() as $handler) { + $handler->afterEhlo($this); + } + } + + /** Overridden to add Extension support */ + protected function _doMailFromCommand($address) + { + $handlers = $this->_getActiveHandlers(); + $params = array(); + foreach ($handlers as $handler) { + $params = array_merge($params, (array) $handler->getMailParams()); + } + $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; + $this->executeCommand( + sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), array(250) + ); + } + + /** Overridden to add Extension support */ + protected function _doRcptToCommand($address) + { + $handlers = $this->_getActiveHandlers(); + $params = array(); + foreach ($handlers as $handler) { + $params = array_merge($params, (array) $handler->getRcptParams()); + } + $paramStr = !empty($params) ? ' '.implode(' ', $params) : ''; + $this->executeCommand( + sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), array(250, 251, 252) + ); + } + + /** Determine ESMTP capabilities by function group */ + private function _getCapabilities($ehloResponse) + { + $capabilities = array(); + $ehloResponse = trim($ehloResponse); + $lines = explode("\r\n", $ehloResponse); + array_shift($lines); + foreach ($lines as $line) { + if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { + $keyword = strtoupper($matches[1]); + $paramStr = strtoupper(ltrim($matches[2], ' =')); + $params = !empty($paramStr) ? explode(' ', $paramStr) : array(); + $capabilities[$keyword] = $params; + } + } + + return $capabilities; + } + + /** Set parameters which are used by each extension handler */ + private function _setHandlerParams() + { + foreach ($this->_handlers as $keyword => $handler) { + if (array_key_exists($keyword, $this->_capabilities)) { + $handler->setKeywordParams($this->_capabilities[$keyword]); + } + } + } + + /** Get ESMTP handlers which are currently ok to use */ + private function _getActiveHandlers() + { + $handlers = array(); + foreach ($this->_handlers as $keyword => $handler) { + if (array_key_exists($keyword, $this->_capabilities)) { + $handlers[] = $handler; + } + } + + return $handlers; + } + + /** Custom sort for extension handler ordering */ + private function _sortHandlers($a, $b) + { + return $a->getPriorityOver($b->getHandledKeyword()); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/FailoverTransport.php b/lib/SwiftMailer/classes/Swift/Transport/FailoverTransport.php new file mode 100644 index 0000000..311a0f2 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/FailoverTransport.php @@ -0,0 +1,88 @@ +_transports); + $sent = 0; + $this->_lastUsedTransport = null; + + for ($i = 0; $i < $maxTransports + && $transport = $this->_getNextTransport(); ++$i) { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + + if ($sent = $transport->send($message, $failedRecipients)) { + $this->_lastUsedTransport = $transport; + + return $sent; + } + } catch (Swift_TransportException $e) { + $this->_killCurrentTransport(); + } + } + + if (count($this->_transports) == 0) { + throw new Swift_TransportException( + 'All Transports in FailoverTransport failed, or no Transports available' + ); + } + + return $sent; + } + + protected function _getNextTransport() + { + if (!isset($this->_currentTransport)) { + $this->_currentTransport = parent::_getNextTransport(); + } + + return $this->_currentTransport; + } + + protected function _killCurrentTransport() + { + $this->_currentTransport = null; + parent::_killCurrentTransport(); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/IoBuffer.php b/lib/SwiftMailer/classes/Swift/Transport/IoBuffer.php new file mode 100644 index 0000000..af97adf --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/IoBuffer.php @@ -0,0 +1,67 @@ +_transports = $transports; + $this->_deadTransports = array(); + } + + /** + * Get $transports to delegate to. + * + * @return Swift_Transport[] + */ + public function getTransports() + { + return array_merge($this->_transports, $this->_deadTransports); + } + + /** + * Get the Transport used in the last successful send operation. + * + * @return Swift_Transport + */ + public function getLastUsedTransport() + { + return $this->_lastUsedTransport; + } + + /** + * Test if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return count($this->_transports) > 0; + } + + /** + * Start this Transport mechanism. + */ + public function start() + { + $this->_transports = array_merge($this->_transports, $this->_deadTransports); + } + + /** + * Stop this Transport mechanism. + */ + public function stop() + { + foreach ($this->_transports as $transport) { + $transport->stop(); + } + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $maxTransports = count($this->_transports); + $sent = 0; + $this->_lastUsedTransport = null; + + for ($i = 0; $i < $maxTransports + && $transport = $this->_getNextTransport(); ++$i) { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + if ($sent = $transport->send($message, $failedRecipients)) { + $this->_lastUsedTransport = $transport; + break; + } + } catch (Swift_TransportException $e) { + $this->_killCurrentTransport(); + } + } + + if (count($this->_transports) == 0) { + throw new Swift_TransportException( + 'All Transports in LoadBalancedTransport failed, or no Transports available' + ); + } + + return $sent; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + foreach ($this->_transports as $transport) { + $transport->registerPlugin($plugin); + } + } + + /** + * Rotates the transport list around and returns the first instance. + * + * @return Swift_Transport + */ + protected function _getNextTransport() + { + if ($next = array_shift($this->_transports)) { + $this->_transports[] = $next; + } + + return $next; + } + + /** + * Tag the currently used (top of stack) transport as dead/useless. + */ + protected function _killCurrentTransport() + { + if ($transport = array_pop($this->_transports)) { + try { + $transport->stop(); + } catch (Exception $e) { + } + $this->_deadTransports[] = $transport; + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/MailInvoker.php b/lib/SwiftMailer/classes/Swift/Transport/MailInvoker.php new file mode 100644 index 0000000..77489ce --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/MailInvoker.php @@ -0,0 +1,32 @@ +_invoker = $invoker; + $this->_eventDispatcher = $eventDispatcher; + } + + /** + * Not used. + */ + public function isStarted() + { + return false; + } + + /** + * Not used. + */ + public function start() + { + } + + /** + * Not used. + */ + public function stop() + { + } + + /** + * Set the additional parameters used on the mail() function. + * + * This string is formatted for sprintf() where %s is the sender address. + * + * @param string $params + * + * @return Swift_Transport_MailTransport + */ + public function setExtraParams($params) + { + $this->_extraParams = $params; + + return $this; + } + + /** + * Get the additional parameters used on the mail() function. + * + * This string is formatted for sprintf() where %s is the sender address. + * + * @return string + */ + public function getExtraParams() + { + return $this->_extraParams; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + $count = ( + count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ); + + $toHeader = $message->getHeaders()->get('To'); + $subjectHeader = $message->getHeaders()->get('Subject'); + + if (0 === $count) { + $this->_throwException(new Swift_TransportException('Cannot send message without a recipient')); + } + $to = $toHeader ? $toHeader->getFieldBody() : ''; + $subject = $subjectHeader ? $subjectHeader->getFieldBody() : ''; + + $reversePath = $this->_getReversePath($message); + + // Remove headers that would otherwise be duplicated + $message->getHeaders()->remove('To'); + $message->getHeaders()->remove('Subject'); + + $messageStr = $message->toString(); + + if ($toHeader) { + $message->getHeaders()->set($toHeader); + } + $message->getHeaders()->set($subjectHeader); + + // Separate headers from body + if (false !== $endHeaders = strpos($messageStr, "\r\n\r\n")) { + $headers = substr($messageStr, 0, $endHeaders)."\r\n"; //Keep last EOL + $body = substr($messageStr, $endHeaders + 4); + } else { + $headers = $messageStr."\r\n"; + $body = ''; + } + + unset($messageStr); + + if ("\r\n" != PHP_EOL) { + // Non-windows (not using SMTP) + $headers = str_replace("\r\n", PHP_EOL, $headers); + $subject = str_replace("\r\n", PHP_EOL, $subject); + $body = str_replace("\r\n", PHP_EOL, $body); + } else { + // Windows, using SMTP + $headers = str_replace("\r\n.", "\r\n..", $headers); + $subject = str_replace("\r\n.", "\r\n..", $subject); + $body = str_replace("\r\n.", "\r\n..", $body); + } + + if ($this->_invoker->mail($to, $subject, $body, $headers, $this->_formatExtraParams($this->_extraParams, $reversePath))) { + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + } else { + $failedRecipients = array_merge( + $failedRecipients, + array_keys((array) $message->getTo()), + array_keys((array) $message->getCc()), + array_keys((array) $message->getBcc()) + ); + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); + + $count = 0; + } + + return $count; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } + + /** Throw a TransportException, first sending it to any listeners */ + protected function _throwException(Swift_TransportException $e) + { + if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { + $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); + if (!$evt->bubbleCancelled()) { + throw $e; + } + } else { + throw $e; + } + } + + /** Determine the best-use reverse path for this message */ + private function _getReversePath(Swift_Mime_Message $message) + { + $return = $message->getReturnPath(); + $sender = $message->getSender(); + $from = $message->getFrom(); + $path = null; + if (!empty($return)) { + $path = $return; + } elseif (!empty($sender)) { + $keys = array_keys($sender); + $path = array_shift($keys); + } elseif (!empty($from)) { + $keys = array_keys($from); + $path = array_shift($keys); + } + + return $path; + } + + /** + * Return php mail extra params to use for invoker->mail. + * + * @param $extraParams + * @param $reversePath + * + * @return string|null + */ + private function _formatExtraParams($extraParams, $reversePath) + { + if (false !== strpos($extraParams, '-f%s')) { + $extraParams = empty($reversePath) ? str_replace('-f%s', '', $extraParams) : sprintf($extraParams, escapeshellarg($reversePath)); + } + + return !empty($extraParams) ? $extraParams : null; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/NullTransport.php b/lib/SwiftMailer/classes/Swift/Transport/NullTransport.php new file mode 100644 index 0000000..ad20e0e --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/NullTransport.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + */ +class Swift_Transport_NullTransport implements Swift_Transport +{ + /** The event dispatcher from the plugin API */ + private $_eventDispatcher; + + /** + * Constructor. + */ + public function __construct(Swift_Events_EventDispatcher $eventDispatcher) + { + $this->_eventDispatcher = $eventDispatcher; + } + + /** + * Tests if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Sends the given message. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $count = ( + count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ); + + return $count; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/SendmailTransport.php b/lib/SwiftMailer/classes/Swift/Transport/SendmailTransport.php new file mode 100644 index 0000000..34ac4ce --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/SendmailTransport.php @@ -0,0 +1,160 @@ + 30, + 'blocking' => 1, + 'command' => '/usr/sbin/sendmail -bs', + 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS, + ); + + /** + * Create a new SendmailTransport with $buf for I/O. + * + * @param Swift_Transport_IoBuffer $buf + * @param Swift_Events_EventDispatcher $dispatcher + */ + public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher) + { + parent::__construct($buf, $dispatcher); + } + + /** + * Start the standalone SMTP session if running in -bs mode. + */ + public function start() + { + if (false !== strpos($this->getCommand(), ' -bs')) { + parent::start(); + } + } + + /** + * Set the command to invoke. + * + * If using -t mode you are strongly advised to include -oi or -i in the flags. + * For example: /usr/sbin/sendmail -oi -t + * Swift will append a -f flag if one is not present. + * + * The recommended mode is "-bs" since it is interactive and failure notifications + * are hence possible. + * + * @param string $command + * + * @return Swift_Transport_SendmailTransport + */ + public function setCommand($command) + { + $this->_params['command'] = $command; + + return $this; + } + + /** + * Get the sendmail command which will be invoked. + * + * @return string + */ + public function getCommand() + { + return $this->_params['command']; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * + * The return value is the number of recipients who were accepted for delivery. + * NOTE: If using 'sendmail -t' you will not be aware of any failures until + * they bounce (i.e. send() will always return 100% success). + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + $command = $this->getCommand(); + $buffer = $this->getBuffer(); + $count = 0; + + if (false !== strpos($command, ' -t')) { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if (false === strpos($command, ' -f')) { + $command .= ' -f'.escapeshellarg($this->_getReversePath($message)); + } + + $buffer->initialize(array_merge($this->_params, array('command' => $command))); + + if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { + $buffer->setWriteTranslations(array("\r\n" => "\n", "\n." => "\n..")); + } else { + $buffer->setWriteTranslations(array("\r\n" => "\n")); + } + + $count = count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ; + $message->toByteStream($buffer); + $buffer->flushBuffers(); + $buffer->setWriteTranslations(array()); + $buffer->terminate(); + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); + } elseif (false !== strpos($command, ' -bs')) { + $count = parent::send($message, $failedRecipients); + } else { + $this->_throwException(new Swift_TransportException( + 'Unsupported sendmail command flags ['.$command.']. '. + 'Must be one of "-bs" or "-t" but can include additional flags.' + )); + } + + return $count; + } + + /** Get the params to initialize the buffer */ + protected function _getBufferParams() + { + return $this->_params; + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/SimpleMailInvoker.php b/lib/SwiftMailer/classes/Swift/Transport/SimpleMailInvoker.php new file mode 100644 index 0000000..4cab66b --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/SimpleMailInvoker.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in a queue. + * + * @author Fabien Potencier + */ +class Swift_Transport_SpoolTransport implements Swift_Transport +{ + /** The spool instance */ + private $_spool; + + /** The event dispatcher from the plugin API */ + private $_eventDispatcher; + + /** + * Constructor. + */ + public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) + { + $this->_eventDispatcher = $eventDispatcher; + $this->_spool = $spool; + } + + /** + * Sets the spool object. + * + * @param Swift_Spool $spool + * + * @return Swift_Transport_SpoolTransport + */ + public function setSpool(Swift_Spool $spool) + { + $this->_spool = $spool; + + return $this; + } + + /** + * Get the spool object. + * + * @return Swift_Spool + */ + public function getSpool() + { + return $this->_spool; + } + + /** + * Tests if this Transport mechanism has started. + * + * @return bool + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Sends the given message. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent e-mail's + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + $success = $this->_spool->queueMessage($message); + + if ($evt) { + $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SPOOLED : Swift_Events_SendEvent::RESULT_FAILED); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + return 1; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } +} diff --git a/lib/SwiftMailer/classes/Swift/Transport/StreamBuffer.php b/lib/SwiftMailer/classes/Swift/Transport/StreamBuffer.php new file mode 100644 index 0000000..32ec97c --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/Transport/StreamBuffer.php @@ -0,0 +1,334 @@ +_replacementFactory = $replacementFactory; + } + + /** + * Perform any initialization needed, using the given $params. + * + * Parameters will vary depending upon the type of IoBuffer used. + * + * @param array $params + */ + public function initialize(array $params) + { + $this->_params = $params; + switch ($params['type']) { + case self::TYPE_PROCESS: + $this->_establishProcessConnection(); + break; + case self::TYPE_SOCKET: + default: + $this->_establishSocketConnection(); + break; + } + } + + /** + * Set an individual param on the buffer (e.g. switching to SSL). + * + * @param string $param + * @param mixed $value + */ + public function setParam($param, $value) + { + if (isset($this->_stream)) { + switch ($param) { + case 'timeout': + if ($this->_stream) { + stream_set_timeout($this->_stream, $value); + } + break; + + case 'blocking': + if ($this->_stream) { + stream_set_blocking($this->_stream, 1); + } + + } + } + $this->_params[$param] = $value; + } + + public function startTLS() + { + return stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); + } + + /** + * Perform any shutdown logic needed. + */ + public function terminate() + { + if (isset($this->_stream)) { + switch ($this->_params['type']) { + case self::TYPE_PROCESS: + fclose($this->_in); + fclose($this->_out); + proc_close($this->_stream); + break; + case self::TYPE_SOCKET: + default: + fclose($this->_stream); + break; + } + } + $this->_stream = null; + $this->_out = null; + $this->_in = null; + } + + /** + * Set an array of string replacements which should be made on data written + * to the buffer. + * + * This could replace LF with CRLF for example. + * + * @param string[] $replacements + */ + public function setWriteTranslations(array $replacements) + { + foreach ($this->_translations as $search => $replace) { + if (!isset($replacements[$search])) { + $this->removeFilter($search); + unset($this->_translations[$search]); + } + } + + foreach ($replacements as $search => $replace) { + if (!isset($this->_translations[$search])) { + $this->addFilter( + $this->_replacementFactory->createFilter($search, $replace), $search + ); + $this->_translations[$search] = true; + } + } + } + + /** + * Get a line of output (including any CRLF). + * + * The $sequence number comes from any writes and may or may not be used + * depending upon the implementation. + * + * @param int $sequence of last write to scan from + * + * @throws Swift_IoException + * + * @return string + */ + public function readLine($sequence) + { + if (isset($this->_out) && !feof($this->_out)) { + $line = fgets($this->_out); + if (strlen($line) == 0) { + $metas = stream_get_meta_data($this->_out); + if ($metas['timed_out']) { + throw new Swift_IoException( + 'Connection to '. + $this->_getReadConnectionDescription(). + ' Timed Out' + ); + } + } + + return $line; + } + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the remaining bytes are given instead. + * If no bytes are remaining at all, boolean false is returned. + * + * @param int $length + * + * @throws Swift_IoException + * + * @return string|bool + */ + public function read($length) + { + if (isset($this->_out) && !feof($this->_out)) { + $ret = fread($this->_out, $length); + if (strlen($ret) == 0) { + $metas = stream_get_meta_data($this->_out); + if ($metas['timed_out']) { + throw new Swift_IoException( + 'Connection to '. + $this->_getReadConnectionDescription(). + ' Timed Out' + ); + } + } + + return $ret; + } + } + + /** Not implemented */ + public function setReadPointer($byteOffset) + { + } + + /** Flush the stream contents */ + protected function _flush() + { + if (isset($this->_in)) { + fflush($this->_in); + } + } + + /** Write this bytes to the stream */ + protected function _commit($bytes) + { + if (isset($this->_in)) { + $bytesToWrite = strlen($bytes); + $totalBytesWritten = 0; + + while ($totalBytesWritten < $bytesToWrite) { + $bytesWritten = fwrite($this->_in, substr($bytes, $totalBytesWritten)); + if (false === $bytesWritten || 0 === $bytesWritten) { + break; + } + + $totalBytesWritten += $bytesWritten; + } + + if ($totalBytesWritten > 0) { + return ++$this->_sequence; + } + } + } + + /** + * Establishes a connection to a remote server. + */ + private function _establishSocketConnection() +{ + + $host = $this->_params['host']; + if (!empty($this->_params['protocol'])) { + $host = $this->_params['protocol'].'://'.$host; + } + + $timeout = 15; + if (!empty($this->_params['timeout'])) { + $timeout = $this->_params['timeout']; + } + + $options = array(); + if (!empty($this->_params['sourceIp'])) { + $options['socket']['bindto'] = $this->_params['sourceIp'].':0'; + } + + if (isset($this->_params['stream_context_options'])) { + $options = array_merge($options, $this->_params['stream_context_options']); + } + +$options['ssl']['verify_peer'] = FALSE; +$options['ssl']['verify_peer_name'] = FALSE; + + $streamContext = stream_context_create($options); + + $this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext); + if (false === $this->_stream) { + throw new Swift_TransportException( + 'Connection could not be established with host '.$this->_params['host']. + ' ['.$errstr.' #'.$errno.']' + ); + } + if (!empty($this->_params['blocking'])) { + stream_set_blocking($this->_stream, 1); + } else { + stream_set_blocking($this->_stream, 0); + } + stream_set_timeout($this->_stream, $timeout); + $this->_in = &$this->_stream; + $this->_out = &$this->_stream; +} + + /** + * Opens a process for input/output. + */ + private function _establishProcessConnection() + { + $command = $this->_params['command']; + $descriptorSpec = array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ); + $this->_stream = proc_open($command, $descriptorSpec, $pipes); + stream_set_blocking($pipes[2], 0); + if ($err = stream_get_contents($pipes[2])) { + throw new Swift_TransportException( + 'Process could not be started ['.$err.']' + ); + } + $this->_in = &$pipes[0]; + $this->_out = &$pipes[1]; + } + + private function _getReadConnectionDescription() + { + switch ($this->_params['type']) { + case self::TYPE_PROCESS: + return 'Process '.$this->_params['command']; + break; + + case self::TYPE_SOCKET: + default: + $host = $this->_params['host']; + if (!empty($this->_params['protocol'])) { + $host = $this->_params['protocol'].'://'.$host; + } + $host .= ':'.$this->_params['port']; + + return $host; + break; + } + } +} diff --git a/lib/SwiftMailer/classes/Swift/TransportException.php b/lib/SwiftMailer/classes/Swift/TransportException.php new file mode 100644 index 0000000..4ae2412 --- /dev/null +++ b/lib/SwiftMailer/classes/Swift/TransportException.php @@ -0,0 +1,29 @@ + + */ +class Swift_Validate +{ + /** + * Grammar Object. + * + * @var Swift_Mime_Grammar + */ + private static $grammar = null; + + /** + * Checks if an e-mail address matches the current grammars. + * + * @param string $email + * + * @return bool + */ + public static function email($email) + { + if (self::$grammar === null) { + self::$grammar = Swift_DependencyContainer::getInstance() + ->lookup('mime.grammar'); + } + + return (bool) preg_match( + '/^'.self::$grammar->getDefinition('addr-spec').'$/D', + $email + ); + } +} diff --git a/lib/SwiftMailer/dependency_maps/cache_deps.php b/lib/SwiftMailer/dependency_maps/cache_deps.php new file mode 100644 index 0000000..6023448 --- /dev/null +++ b/lib/SwiftMailer/dependency_maps/cache_deps.php @@ -0,0 +1,23 @@ +register('cache') + ->asAliasOf('cache.array') + + ->register('tempdir') + ->asValue('/tmp') + + ->register('cache.null') + ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache') + + ->register('cache.array') + ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache') + ->withDependencies(array('cache.inputstream')) + + ->register('cache.disk') + ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache') + ->withDependencies(array('cache.inputstream', 'tempdir')) + + ->register('cache.inputstream') + ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream') +; diff --git a/lib/SwiftMailer/dependency_maps/message_deps.php b/lib/SwiftMailer/dependency_maps/message_deps.php new file mode 100644 index 0000000..64d69d2 --- /dev/null +++ b/lib/SwiftMailer/dependency_maps/message_deps.php @@ -0,0 +1,9 @@ +register('message.message') + ->asNewInstanceOf('Swift_Message') + + ->register('message.mimepart') + ->asNewInstanceOf('Swift_MimePart') +; diff --git a/lib/SwiftMailer/dependency_maps/mime_deps.php b/lib/SwiftMailer/dependency_maps/mime_deps.php new file mode 100644 index 0000000..56169c9 --- /dev/null +++ b/lib/SwiftMailer/dependency_maps/mime_deps.php @@ -0,0 +1,123 @@ +register('properties.charset') + ->asValue('utf-8') + + ->register('mime.grammar') + ->asSharedInstanceOf('Swift_Mime_Grammar') + + ->register('mime.message') + ->asNewInstanceOf('Swift_Mime_SimpleMessage') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.grammar', + 'properties.charset', + )) + + ->register('mime.part') + ->asNewInstanceOf('Swift_Mime_MimePart') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.grammar', + 'properties.charset', + )) + + ->register('mime.attachment') + ->asNewInstanceOf('Swift_Mime_Attachment') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.grammar', + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.embeddedfile') + ->asNewInstanceOf('Swift_Mime_EmbeddedFile') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.grammar', + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.headerfactory') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') + ->withDependencies(array( + 'mime.qpheaderencoder', + 'mime.rfc2231encoder', + 'mime.grammar', + 'properties.charset', + )) + + ->register('mime.headerset') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet') + ->withDependencies(array('mime.headerfactory', 'properties.charset')) + + ->register('mime.qpheaderencoder') + ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder') + ->withDependencies(array('mime.charstream')) + + ->register('mime.base64headerencoder') + ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder') + ->withDependencies(array('mime.charstream')) + + ->register('mime.charstream') + ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream') + ->withDependencies(array('mime.characterreaderfactory', 'properties.charset')) + + ->register('mime.bytecanonicalizer') + ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter') + ->addConstructorValue(array(array(0x0D, 0x0A), array(0x0D), array(0x0A))) + ->addConstructorValue(array(array(0x0A), array(0x0A), array(0x0D, 0x0A))) + + ->register('mime.characterreaderfactory') + ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory') + + ->register('mime.safeqpcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') + ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) + + ->register('mime.rawcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder') + + ->register('mime.nativeqpcontentencoder') + ->withDependencies(array('properties.charset')) + ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder') + + ->register('mime.qpcontentencoderproxy') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy') + ->withDependencies(array('mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset')) + + ->register('mime.7bitcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') + ->addConstructorValue('7bit') + ->addConstructorValue(true) + + ->register('mime.8bitcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') + ->addConstructorValue('8bit') + ->addConstructorValue(true) + + ->register('mime.base64contentencoder') + ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder') + + ->register('mime.rfc2231encoder') + ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder') + ->withDependencies(array('mime.charstream')) + + // As of PHP 5.4.7, the quoted_printable_encode() function behaves correctly. + // see https://github.com/php/php-src/commit/18bb426587d62f93c54c40bf8535eb8416603629 + ->register('mime.qpcontentencoder') + ->asAliasOf(version_compare(phpversion(), '5.4.7', '>=') ? 'mime.qpcontentencoderproxy' : 'mime.safeqpcontentencoder') +; + +unset($swift_mime_types); diff --git a/lib/SwiftMailer/dependency_maps/transport_deps.php b/lib/SwiftMailer/dependency_maps/transport_deps.php new file mode 100644 index 0000000..77e432c --- /dev/null +++ b/lib/SwiftMailer/dependency_maps/transport_deps.php @@ -0,0 +1,76 @@ +register('transport.smtp') + ->asNewInstanceOf('Swift_Transport_EsmtpTransport') + ->withDependencies(array( + 'transport.buffer', + array('transport.authhandler'), + 'transport.eventdispatcher', + )) + + ->register('transport.sendmail') + ->asNewInstanceOf('Swift_Transport_SendmailTransport') + ->withDependencies(array( + 'transport.buffer', + 'transport.eventdispatcher', + )) + + ->register('transport.mail') + ->asNewInstanceOf('Swift_Transport_MailTransport') + ->withDependencies(array('transport.mailinvoker', 'transport.eventdispatcher')) + + ->register('transport.loadbalanced') + ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport') + + ->register('transport.failover') + ->asNewInstanceOf('Swift_Transport_FailoverTransport') + + ->register('transport.spool') + ->asNewInstanceOf('Swift_Transport_SpoolTransport') + ->withDependencies(array('transport.eventdispatcher')) + + ->register('transport.null') + ->asNewInstanceOf('Swift_Transport_NullTransport') + ->withDependencies(array('transport.eventdispatcher')) + + ->register('transport.mailinvoker') + ->asSharedInstanceOf('Swift_Transport_SimpleMailInvoker') + + ->register('transport.buffer') + ->asNewInstanceOf('Swift_Transport_StreamBuffer') + ->withDependencies(array('transport.replacementfactory')) + + ->register('transport.authhandler') + ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler') + ->withDependencies(array( + array( + 'transport.crammd5auth', + 'transport.loginauth', + 'transport.plainauth', + 'transport.ntlmauth', + 'transport.xoauth2auth', + ), + )) + + ->register('transport.crammd5auth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator') + + ->register('transport.loginauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator') + + ->register('transport.plainauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator') + + ->register('transport.xoauth2auth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator') + + ->register('transport.ntlmauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator') + + ->register('transport.eventdispatcher') + ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher') + + ->register('transport.replacementfactory') + ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory') +; diff --git a/lib/SwiftMailer/mime_types.php b/lib/SwiftMailer/mime_types.php new file mode 100644 index 0000000..2d7b98d --- /dev/null +++ b/lib/SwiftMailer/mime_types.php @@ -0,0 +1,1007 @@ + 'text/vnd.in3d.3dml', + '3ds' => 'image/x-3ds', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'appcache' => 'text/cache-manifest', + 'apr' => 'application/vnd.lotus-approach', + 'aps' => 'application/postscript', + 'arc' => 'application/x-freearc', + 'asc' => 'application/pgp-signature', + 'asf' => 'video/x-ms-asf', + 'asm' => 'text/x-asm', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'blb' => 'application/x-blorb', + 'blorb' => 'application/x-blorb', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'caf' => 'audio/x-caf', + 'cap' => 'application/vnd.tcpdump.pcap', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cb7' => 'application/x-cbr', + 'cba' => 'application/x-cbr', + 'cbr' => 'application/x-cbr', + 'cbt' => 'application/x-cbr', + 'cbz' => 'application/x-cbr', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfs' => 'application/x-cfs-compressed', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dart' => 'application/vnd.dart', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dbk' => 'application/docbook+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dgc' => 'application/x-dgc-compressed', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/x-apple-diskimage', + 'dmp' => 'application/vnd.tcpdump.pcap', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvb' => 'video/vnd.dvb.file', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'emf' => 'application/x-msmetafile', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'emz' => 'application/x-msmetafile', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esa' => 'application/vnd.osgi.subsystem', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'eva' => 'application/x-eva', + 'evy' => 'application/x-envoy', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'flac' => 'audio/x-flac', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gam' => 'application/x-tads', + 'gbr' => 'application/rpki-ghostbusters', + 'gca' => 'application/x-gca-compressed', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gml' => 'application/gml+xml', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gpx' => 'application/gpx+xml', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gramps' => 'application/x-gramps-xml', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxf' => 'application/gxf', + 'gxt' => 'application/vnd.geonext', + 'gz' => 'application/x-gzip', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ink' => 'application/inkml+xml', + 'inkml' => 'application/inkml+xml', + 'install' => 'application/x-install-instructions', + 'iota' => 'application/vnd.astraea-software.iota', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/x-iso9660-image', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'jsonml' => 'application/jsonml+json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'kpxx' => 'application/vnd.ds-keypoint', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/x-lzh-compressed', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'lnk' => 'application/x-ms-shortcut', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/x-lzh-compressed', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mar' => 'application/octet-stream', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'metalink' => 'application/metalink+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mft' => 'application/rpki-manifest', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mie' => 'application/x-mie', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mk3d' => 'video/x-matroska', + 'mka' => 'audio/x-matroska', + 'mks' => 'video/x-matroska', + 'mkv' => 'video/x-matroska', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mng' => 'video/x-mng', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'nfo' => 'text/x-nfo', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nitf' => 'application/vnd.nitf', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsc' => 'application/x-conference', + 'nsf' => 'application/vnd.lotus-notes', + 'ntf' => 'application/vnd.nitf', + 'nzb' => 'application/x-nzb', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'obj' => 'application/x-tgif', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'omdoc' => 'application/omdoc+xml', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'opml' => 'text/x-opml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxps' => 'application/oxps', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcap' => 'application/vnd.tcpdump.pcap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'application/x-php', + 'php3' => 'application/x-php', + 'php4' => 'application/x-php', + 'php5' => 'application/x-php', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'ris' => 'application/x-research-info-systems', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rmvb' => 'application/vnd.rn-realmedia-vbr', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roa' => 'application/rpki-roa', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 's3m' => 'audio/s3m', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sfv' => 'text/x-sfv', + 'sgi' => 'image/sgi', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sid' => 'image/x-mrsid-image', + 'sig' => 'application/pgp-signature', + 'sil' => 'audio/silk', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'smv' => 'video/x-smv', + 'smzip' => 'application/vnd.stepmania.package', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'sql' => 'application/x-sql', + 'src' => 'application/x-wais-source', + 'srt' => 'application/x-subrip', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'ssdl' => 'application/ssdl+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'text/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 't3' => 'application/x-t3vm-image', + 'taglet' => 'application/vnd.mynfc', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'tga' => 'image/x-tga', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'ulx' => 'application/x-glulx', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvvz' => 'application/vnd.dece.zip', + 'uvx' => 'application/vnd.dece.unspecified', + 'uvz' => 'application/vnd.dece.zip', + 'vcard' => 'text/vcard', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vob' => 'video/x-ms-vob', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'wdp' => 'image/vnd.ms-photo', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-msmetafile', + 'woff' => 'application/font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'model/x3d+xml', + 'x3db' => 'model/x3d+binary', + 'x3dbz' => 'model/x3d+binary', + 'x3dv' => 'model/x3d+vrml', + 'x3dvz' => 'model/x3d+vrml', + 'x3dz' => 'model/x3d+xml', + 'xaml' => 'application/xaml+xml', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlf' => 'application/x-xliff+xml', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xm' => 'audio/xm', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpl' => 'application/xproc+xml', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'xz' => 'application/x-xz', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'z1' => 'application/x-zmachine', + 'z2' => 'application/x-zmachine', + 'z3' => 'application/x-zmachine', + 'z4' => 'application/x-zmachine', + 'z5' => 'application/x-zmachine', + 'z6' => 'application/x-zmachine', + 'z7' => 'application/x-zmachine', + 'z8' => 'application/x-zmachine', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml', + '123' => 'application/vnd.lotus-1-2-3', +); diff --git a/lib/SwiftMailer/preferences.php b/lib/SwiftMailer/preferences.php new file mode 100644 index 0000000..e519501 --- /dev/null +++ b/lib/SwiftMailer/preferences.php @@ -0,0 +1,25 @@ +setCharset('utf-8'); + +// Without these lines the default caching mechanism is "array" but this uses a lot of memory. +// If possible, use a disk cache to enable attaching large attachments etc. +// You can override the default temporary directory by setting the TMPDIR environment variable. +if (@is_writable($tmpDir = sys_get_temp_dir())) { + $preferences->setTempDir($tmpDir)->setCacheType('disk'); +} + +// this should only be done when Swiftmailer won't use the native QP content encoder +// see mime_deps.php +if (version_compare(phpversion(), '5.4.7', '<')) { + $preferences->setQPDotEscape(false); +} diff --git a/lib/SwiftMailer/swift_init.php b/lib/SwiftMailer/swift_init.php new file mode 100644 index 0000000..ff71963 --- /dev/null +++ b/lib/SwiftMailer/swift_init.php @@ -0,0 +1,28 @@ + 'application/x-php', + 'php3' => 'application/x-php', + 'php4' => 'application/x-php', + 'php5' => 'application/x-php', + 'zip' => 'application/zip', + 'gif' => 'image/gif', + 'png' => 'image/png', + 'css' => 'text/css', + 'js' => 'text/javascript', + 'txt' => 'text/plain', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'avi' => 'video/avi', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bz2', + 'csv' => 'text/csv', + 'dmg' => 'application/x-apple-diskimage', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'eml' => 'message/rfc822', + 'aps' => 'application/postscript', + 'exe' => 'application/x-ms-dos-executable', + 'flv' => 'video/x-flv', + 'gz' => 'application/x-gzip', + 'hqx' => 'application/stuffit', + 'htm' => 'text/html', + 'html' => 'text/html', + 'jar' => 'application/x-java-archive', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'm3u' => 'audio/x-mpegurl', + 'm4a' => 'audio/mp4', + 'mdb' => 'application/x-msaccess', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'odg' => 'vnd.oasis.opendocument.graphics', + 'odp' => 'vnd.oasis.opendocument.presentation', + 'odt' => 'vnd.oasis.opendocument.text', + 'ods' => 'vnd.oasis.opendocument.spreadsheet', + 'ogg' => 'audio/ogg', + 'pdf' => 'application/pdf', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'ps' => 'application/postscript', + 'rar' => 'application/x-rar-compressed', + 'rtf' => 'application/rtf', + 'tar' => 'application/x-tar', + 'sit' => 'application/x-stuffit', + 'svg' => 'image/svg+xml', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'ttf' => 'application/x-font-truetype', + 'vcf' => 'text/x-vcard', + 'wav' => 'audio/wav', + 'wma' => 'audio/x-ms-wma', + 'wmv' => 'audio/x-ms-wmv', + 'xls' => 'application/excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xml' => 'application/xml', + ); + + // wrap array for generating file + foreach ($valid_mime_types_preset as $extension => $mime_type) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + + // collect extensions + $valid_extensions = array(); + + // all extensions from second match + foreach ($matches[2] as $i => $extensions) { + // explode multiple extensions from string + $extensions = explode(' ', strtolower($extensions)); + + // force array for foreach + if (!is_array($extensions)) { + $extensions = array($extensions); + } + + foreach ($extensions as $extension) { + // get mime type + $mime_type = $matches[1][$i]; + + // check if string length lower than 10 + if (strlen($extension) < 10) { + // add extension + $valid_extensions[] = $extension; + + if (!isset($valid_mime_types[$mime_type])) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + } + } + } + } + + $xml = simplexml_load_string($mime_xml); + + foreach ($xml as $node) { + // check if there is no pattern + if (!isset($node->glob['pattern'])) { + continue; + } + + // get all matching extensions from match + foreach ((array) $node->glob['pattern'] as $extension) { + // skip none glob extensions + if (strpos($extension, '.') === false) { + continue; + } + + // remove get only last part + $extension = explode('.', strtolower($extension)); + $extension = end($extension); + + // maximum length in database column + if (strlen($extension) <= 9) { + $valid_extensions[] = $extension; + } + } + + if (isset($node->glob['pattern'][0])) { + // mime type + $mime_type = strtolower((string) $node['type']); + + // get first extension + $extension = strtolower(trim($node->glob['ddpattern'][0], '*.')); + + // skip none glob extensions and check if string length between 1 and 10 + if (strpos($extension, '.') !== false || strlen($extension) < 1 || strlen($extension) > 9) { + continue; + } + + // check if string length lower than 10 + if (!isset($valid_mime_types[$mime_type])) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + } + } + + // full list of valid extensions only + $valid_mime_types = array_unique($valid_mime_types); + ksort($valid_mime_types); + + // combine mime types and extensions array + $output = "$preamble\$swift_mime_types = array(\n ".implode($valid_mime_types, ",\n ")."\n);"; + + // write mime_types.php config file + @file_put_contents('./mime_types.php', $output); +} + +generateUpToDateMimeArray(); diff --git a/lib/SwiftMailer/version.txt b/lib/SwiftMailer/version.txt new file mode 100644 index 0000000..c0e6041 --- /dev/null +++ b/lib/SwiftMailer/version.txt @@ -0,0 +1 @@ +5.4.2 + fix для php 5.5, 5.6.x \ No newline at end of file diff --git a/lib/combine/combine.php b/lib/combine/combine.php new file mode 100644 index 0000000..abe84c3 --- /dev/null +++ b/lib/combine/combine.php @@ -0,0 +1,201 @@ + diff --git a/lib/debug/debug.css b/lib/debug/debug.css new file mode 100644 index 0000000..2956370 --- /dev/null +++ b/lib/debug/debug.css @@ -0,0 +1,123 @@ +#debug_btn { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKYSURBVDjLnZPJT1NRFMb5G1wDHV5boNiqdHrvFYolCAtsGSSWKpMFKhYqlDI6oAEKaVJwCIgSphaKtLYWCgSNBgRjMNHoxsSFS3cmJmA0NMTw+R6JKKZl4eJL7sm953fOd3JPHIC4WMpcppG5SGnZc8ZjVVF6QLn975sDgfaZmvg71oRJZIRUYcuAnq/2KWroGfm3QwEn2YpLVPPvOD2oiqj9yq/mGznegl56mx6T7ZbY1M6YAM0CuZkxT0b2Wg6QW/SsApRXDsotR+d6E9Y/h9DuqoCuJq0lKoDxqU1/pITGR27mBU4h+GEcTz5OY+ClA5JbyahYzof/9TBO9B/FcWcqpA4xU3We3GJ87ntnfO5meinMvruNnqcmXA2XoDVcCc0wCYkzBaZpA7ILRJ/2O2B87jA+QT9UeDRe8svZYAG8b/txc6kc9mA+yqayYPQXwvdmBEOrA5B2p0BtFIYOWKCm5RukWwZyXIbA+0F0LpaiKaBHmVsLw4we99ccsM8a8GClF5JOMcQdou8prULrgRmQo7KI0VcE13MrGv06lE5kodhzGvdWu2GdKkTVWC4DcELcJkKyXbCb1EhAVM//M0DVUNqP2qAJd1baUDaZjTMTeXAttsPi0cM0mgvHvA0NkxYk2QRIrieOsDmEmXttH0DfVfSluSToWmpD8bgOroUOWNw6VI7koGfOBuq6EqLLTNU6ojrmP5D1HVsjmrkYezGIrlA9LjKgnrlGXJlpgbCOD0EtD0QNN8I3cZqjAlhJr4rXpB1iNLhrYffUQWoT7yUKzbxqJlHLq0jc5JYmgHMunogKYJVqF7mTrPyfgktMRTMX/CrOq1gLF3fYNrLiX+Bs8MoTwT2fQPwXgBXHGL+TaIjfinb3C7cscRMIcYL6AAAAAElFTkSuQmCC); + cursor: pointer; + position: fixed; + top: 4px; + right: 4px; + width: 16px; + height: 16px; + z-index: 99999999; +} + +#debug_bar { + background: #ffffff; + color: #000000; + display: none; + font-family: "Consolas", Verdana, Arial; + font-size: 11pt; + font-weight: normal; + line-height: normal; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 90000000; +} + +#debug_bar .debug_tabs { + display: block; + list-style: none; + margin: 0; + padding: 0; + border-bottom: 1px solid #999999; + overflow: hidden; +} + +#debug_bar .debug_tabs > li { + cursor: pointer; + font-family: Tahoma; + font-size: 10px; + font-weight: bold; + color: #000000; + display: block; + float: left; + line-height: 18px; + padding: 3px 5px; + border-right: 1px solid #999999; +} + +#debug_bar .debug_tabs > li:hover { + background: #ff8000; +} + +#debug_bar .debug_tabs > li.selected { + background: #999999; + border-bottom: 3px solid #999999; + margin-bottom: -3px; + color: #ffffff; +} + +#debug_bar .debug_tab { + font-family: "Consolas", Verdana, Arial; + font-size: 12px; + clear: both; + display: none; + padding: 15px; + overflow: scroll; + position: absolute; + left: 0; + right: 0; + top: 25px; + bottom: 0; +} + +#debug_bar pre, +#debug_bar code { + display: block; + margin: 0; + color: #000; + background: #FFF; + font-size: 12px; + border: 0; + padding: 5px 10px; + overflow-y: auto; + max-height: calc(100vh - 30px); + max-width: 100%; + overflow-x: hidden; +} + +#debug_bar pre.pre_wrap, +#debug_bar code.pre_wrap { + white-space: pre-wrap; /* Since CSS 2.1 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ + word-break: break-all; +} + +#debug_bar .debug_one_query { + padding: 2px 0px; +} + +#debug_bar .debug_one_query span { + display: inline-block; + vertical-align: middle; + width: calc(100% - 64px); +} + +#debug_bar .debug_one_query span:first-child { + width: 64px; +} + +#debug_bar .debug_one_dump { + padding:0 0 40px 0; +} + +#debug_bar .debug_one_dump .debug_varname { + display:block; + font-weight:bold; + font-size: 16px; + text-transform: uppercase; +} \ No newline at end of file diff --git a/lib/debug/debug.js b/lib/debug/debug.js new file mode 100644 index 0000000..ac5be68 --- /dev/null +++ b/lib/debug/debug.js @@ -0,0 +1,78 @@ +var Debug = { + + initialized: false, + + init: function () { + + if (this.initialized) + return; + + this.initialized = true; + + this.build(); + this.events(); + }, + + build: function () { + // + }, + + events: function () { + this.debugButton(); + this.debugTabs(); + }, + + debugButton: function () { + $('#debug_btn').on('click', function(event) { + + event.preventDefault(); + + let $bar = $('#debug_bar'); + + if ($bar.css('display') === 'none') { + $(document.body).css('overflow', 'hidden'); + $bar.show(); + } else { + $(document.body).css('overflow', 'inherit'); + $bar.hide(); + } + + Debug.debugStorage(); + }); + }, + + debugTabs: function () { + $('.debug_tabs > li').on('click', function(event) { + + event.preventDefault(); + + $('.debug_tabs > li').removeClass('selected'); + + $('.debug_tab').hide(); + + $(this).addClass('selected'); + + $('#' + this.id + '-cont').show(); + + localStorage.setItem('__debug_bar', this.id); + }); + }, + + debugStorage: function () { + + let localValue = localStorage.getItem('__debug_bar'); + + if (localValue !== '') { + + let tab = $('.debug_tabs > li#' + localValue); + + if (tab.length > 0) { + tab.click(); + } + } + } +}; + +$(document).ready(function() { + Debug.init(); +}); \ No newline at end of file diff --git a/lib/debug/debug.tpl b/lib/debug/debug.tpl new file mode 100644 index 0000000..d656788 --- /dev/null +++ b/lib/debug/debug.tpl @@ -0,0 +1,8 @@ +{foreach from=$edit item=group key=title} + {$title} + +{/foreach} \ No newline at end of file diff --git a/lib/debug/sql.php b/lib/debug/sql.php new file mode 100644 index 0000000..16b627f --- /dev/null +++ b/lib/debug/sql.php @@ -0,0 +1,1077 @@ +', '+', '-', '*', '/', '!', '^', '%', '|', '&', '#'); + + // For HTML syntax highlighting + // Styles applied to different token types + public static $quote_attributes = 'style="color: blue;"'; + public static $backtick_quote_attributes = 'style="color: purple;"'; + public static $reserved_attributes = 'style="font-weight:bold;"'; + public static $boundary_attributes = ''; + public static $number_attributes = 'style="color: green;"'; + public static $word_attributes = 'style="color: #333;"'; + public static $error_attributes = 'style="background-color: red;"'; + public static $comment_attributes = 'style="color: #aaa;"'; + public static $variable_attributes = 'style="color: orange;"'; + public static $pre_attributes = 'style="color: black; background-color: white;"'; + + // Boolean - whether or not the current environment is the CLI + // This affects the type of syntax highlighting + // If not defined, it will be determined automatically + public static $cli; + + // For CLI syntax highlighting + public static $cli_quote = "\x1b[34;1m"; + public static $cli_backtick_quote = "\x1b[35;1m"; + public static $cli_reserved = "\x1b[37m"; + public static $cli_boundary = ""; + public static $cli_number = "\x1b[32;1m"; + public static $cli_word = ""; + public static $cli_error = "\x1b[31;1;7m"; + public static $cli_comment = "\x1b[30;1m"; + public static $cli_functions = "\x1b[37m"; + public static $cli_variable = "\x1b[36;1m"; + + // The tab character to use when formatting SQL + public static $tab = ' '; + + // This flag tells us if queries need to be enclosed in
       tags
      +	public static $use_pre = true;
      +
      +	// This flag tells us if SqlFormatted has been initialized
      +	protected static $init;
      +
      +	// Regular expressions for tokenizing
      +	protected static $regex_boundaries;
      +	protected static $regex_reserved;
      +	protected static $regex_reserved_newline;
      +	protected static $regex_reserved_toplevel;
      +	protected static $regex_function;
      +
      +	// Cache variables
      +	// Only tokens shorter than this size will be cached.  Somewhere between 10 and 20 seems to work well for most cases.
      +	public static $max_cachekey_size = 15;
      +	protected static $token_cache = array();
      +	protected static $cache_hits = 0;
      +	protected static $cache_misses = 0;
      +
      +	/**
      +	 * Get stats about the token cache
      +	 * @return Array An array containing the keys 'hits', 'misses', 'entries', and 'size' in bytes
      +	 */
      +	public static function getCacheStats()
      +	{
      +		return array(
      +			'hits'=>self::$cache_hits,
      +			'misses'=>self::$cache_misses,
      +			'entries'=>count(self::$token_cache),
      +			'size'=>strlen(serialize(self::$token_cache))
      +		);
      +	}
      +
      +	/**
      +	 * Stuff that only needs to be done once.  Builds regular expressions and sorts the reserved words.
      +	 */
      +	protected static function init()
      +	{
      +		if (self::$init) return;
      +
      +		// Sort reserved word list from longest word to shortest, 3x faster than usort
      +		$reservedMap = array_combine(self::$reserved, array_map('strlen', self::$reserved));
      +		arsort($reservedMap);
      +		self::$reserved = array_keys($reservedMap);
      +
      +		// Set up regular expressions
      +		self::$regex_boundaries = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$boundaries)).')';
      +		self::$regex_reserved = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved)).')';
      +		self::$regex_reserved_toplevel = str_replace(' ','\\s+','('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved_toplevel)).')');
      +		self::$regex_reserved_newline = str_replace(' ','\\s+','('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved_newline)).')');
      +
      +		self::$regex_function = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$functions)).')';
      +
      +		self::$init = true;
      +	}
      +
      +	/**
      +	 * Return the next token and token type in a SQL string.
      +	 * Quoted strings, comments, reserved words, whitespace, and punctuation are all their own tokens.
      +	 *
      +	 * @param String $string   The SQL string
      +	 * @param array	 $previous The result of the previous getNextToken() call
      +	 *
      +	 * @return Array An associative array containing the type and value of the token.
      +	 */
      +	protected static function getNextToken($string, $previous = null)
      +	{
      +		// Whitespace
      +		if (preg_match('/^\s+/',$string,$matches)) {
      +			return array(
      +				self::TOKEN_VALUE => $matches[0],
      +				self::TOKEN_TYPE=>self::TOKEN_TYPE_WHITESPACE
      +			);
      +		}
      +
      +		// Comment
      +		if ($string[0] === '#' || (isset($string[1])&&($string[0]==='-'&&$string[1]==='-') || ($string[0]==='/'&&$string[1]==='*'))) {
      +			// Comment until end of line
      +			if ($string[0] === '-' || $string[0] === '#') {
      +				$last = strpos($string, "\n");
      +				$type = self::TOKEN_TYPE_COMMENT;
      +			} else { // Comment until closing comment tag
      +				$last = strpos($string, "*/", 2) + 2;
      +				$type = self::TOKEN_TYPE_BLOCK_COMMENT;
      +			}
      +
      +			if ($last === false) {
      +				$last = strlen($string);
      +			}
      +
      +			return array(
      +				self::TOKEN_VALUE => substr($string, 0, $last),
      +				self::TOKEN_TYPE  => $type
      +			);
      +		}
      +
      +		// Quoted String
      +		if ($string[0]==='"' || $string[0]==='\'' || $string[0]==='`' || $string[0]==='[') {
      +			$return = array(
      +				self::TOKEN_TYPE => (($string[0]==='`' || $string[0]==='[')? self::TOKEN_TYPE_BACKTICK_QUOTE : self::TOKEN_TYPE_QUOTE),
      +				self::TOKEN_VALUE => self::getQuotedString($string)
      +			);
      +
      +			return $return;
      +		}
      +
      +		// User-defined Variable
      +		if (($string[0] === '@' || $string[0] === ':') && isset($string[1])) {
      +			$ret = array(
      +				self::TOKEN_VALUE => null,
      +				self::TOKEN_TYPE => self::TOKEN_TYPE_VARIABLE
      +			);
      +
      +			// If the variable name is quoted
      +			if ($string[1]==='"' || $string[1]==='\'' || $string[1]==='`') {
      +				$ret[self::TOKEN_VALUE] = $string[0].self::getQuotedString(substr($string,1));
      +			}
      +			// Non-quoted variable name
      +			else {
      +				preg_match('/^('.$string[0].'[a-zA-Z0-9\._\$]+)/',$string,$matches);
      +				if ($matches) {
      +					$ret[self::TOKEN_VALUE] = $matches[1];
      +				}
      +			}
      +
      +			if($ret[self::TOKEN_VALUE] !== null) return $ret;
      +		}
      +
      +		// Number (decimal, binary, or hex)
      +		if (preg_match('/^([0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)($|\s|"\'`|'.self::$regex_boundaries.')/',$string,$matches)) {
      +			return array(
      +				self::TOKEN_VALUE => $matches[1],
      +				self::TOKEN_TYPE=>self::TOKEN_TYPE_NUMBER
      +			);
      +		}
      +
      +		// Boundary Character (punctuation and symbols)
      +		if (preg_match('/^('.self::$regex_boundaries.')/',$string,$matches)) {
      +			return array(
      +				self::TOKEN_VALUE => $matches[1],
      +				self::TOKEN_TYPE  => self::TOKEN_TYPE_BOUNDARY
      +			);
      +		}
      +
      +		// A reserved word cannot be preceded by a '.'
      +		// this makes it so in "mytable.from", "from" is not considered a reserved word
      +		if (!$previous || !isset($previous[self::TOKEN_VALUE]) || $previous[self::TOKEN_VALUE] !== '.') {
      +			$upper = strtoupper($string);
      +			// Top Level Reserved Word
      +			if (preg_match('/^('.self::$regex_reserved_toplevel.')($|\s|'.self::$regex_boundaries.')/', $upper,$matches)) {
      +				return array(
      +					self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED_TOPLEVEL,
      +					self::TOKEN_VALUE=>substr($string,0,strlen($matches[1]))
      +				);
      +			}
      +			// Newline Reserved Word
      +			if (preg_match('/^('.self::$regex_reserved_newline.')($|\s|'.self::$regex_boundaries.')/', $upper,$matches)) {
      +				return array(
      +					self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED_NEWLINE,
      +					self::TOKEN_VALUE=>substr($string,0,strlen($matches[1]))
      +				);
      +			}
      +			// Other Reserved Word
      +			if (preg_match('/^('.self::$regex_reserved.')($|\s|'.self::$regex_boundaries.')/', $upper,$matches)) {
      +				return array(
      +					self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED,
      +					self::TOKEN_VALUE=>substr($string,0,strlen($matches[1]))
      +				);
      +			}
      +		}
      +
      +		// A function must be suceeded by '('
      +		// this makes it so "count(" is considered a function, but "count" alone is not
      +		$upper = strtoupper($string);
      +		// function
      +		if (preg_match('/^('.self::$regex_function.'[(]|\s|[)])/', $upper,$matches)) {
      +			return array(
      +				self::TOKEN_TYPE=>self::TOKEN_TYPE_RESERVED,
      +				self::TOKEN_VALUE=>substr($string,0,strlen($matches[1])-1)
      +			);
      +		}
      +
      +		// Non reserved word
      +		preg_match('/^(.*?)($|\s|["\'`]|'.self::$regex_boundaries.')/',$string,$matches);
      +
      +		return array(
      +			self::TOKEN_VALUE => $matches[1],
      +			self::TOKEN_TYPE  => self::TOKEN_TYPE_WORD
      +		);
      +	}
      +
      +	protected static function getQuotedString($string)
      +	{
      +		$ret = null;
      +
      +		// This checks for the following patterns:
      +		// 1. backtick quoted string using `` to escape
      +		// 2. square bracket quoted string (SQL Server) using ]] to escape
      +		// 3. double quoted string using "" or \" to escape
      +		// 4. single quoted string using '' or \' to escape
      +		if ( preg_match('/^(((`[^`]*($|`))+)|((\[[^\]]*($|\]))(\][^\]]*($|\]))*)|(("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)|((\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*(\'|$))+))/s', $string, $matches)) {
      +			$ret = $matches[1];
      +		}
      +
      +		return $ret;
      +	}
      +
      +	/**
      +	 * Takes a SQL string and breaks it into tokens.
      +	 * Each token is an associative array with type and value.
      +	 *
      +	 * @param String $string The SQL string
      +	 *
      +	 * @return Array An array of tokens.
      +	 */
      +	protected static function tokenize($string)
      +	{
      +		self::init();
      +
      +		$tokens = array();
      +
      +		// Used for debugging if there is an error while tokenizing the string
      +		$original_length = strlen($string);
      +
      +		// Used to make sure the string keeps shrinking on each iteration
      +		$old_string_len = strlen($string) + 1;
      +
      +		$token = null;
      +
      +		$current_length = strlen($string);
      +
      +		// Keep processing the string until it is empty
      +		while ($current_length) {
      +			// If the string stopped shrinking, there was a problem
      +			if ($old_string_len <= $current_length) {
      +				$tokens[] = array(
      +					self::TOKEN_VALUE=>$string,
      +					self::TOKEN_TYPE=>self::TOKEN_TYPE_ERROR
      +				);
      +
      +				return $tokens;
      +			}
      +			$old_string_len =  $current_length;
      +
      +			// Determine if we can use caching
      +			if ($current_length >= self::$max_cachekey_size) {
      +				$cacheKey = substr($string,0,self::$max_cachekey_size);
      +			} else {
      +				$cacheKey = false;
      +			}
      +
      +			// See if the token is already cached
      +			if ($cacheKey && isset(self::$token_cache[$cacheKey])) {
      +				// Retrieve from cache
      +				$token = self::$token_cache[$cacheKey];
      +				$token_length = strlen($token[self::TOKEN_VALUE]);
      +				self::$cache_hits++;
      +			} else {
      +				// Get the next token and the token type
      +				$token = self::getNextToken($string, $token);
      +				$token_length = strlen($token[self::TOKEN_VALUE]);
      +				self::$cache_misses++;
      +
      +				// If the token is shorter than the max length, store it in cache
      +				if ($cacheKey && $token_length < self::$max_cachekey_size) {
      +					self::$token_cache[$cacheKey] = $token;
      +				}
      +			}
      +
      +			$tokens[] = $token;
      +
      +			// Advance the string
      +			$string = substr($string, $token_length);
      +
      +			$current_length -= $token_length;
      +		}
      +
      +		return $tokens;
      +	}
      +
      +	/**
      +	 * Format the whitespace in a SQL string to make it easier to read.
      +	 *
      +	 * @param String  $string	 The SQL string
      +	 * @param boolean $highlight If true, syntax highlighting will also be performed
      +	 *
      +	 * @return String The SQL string with HTML styles and formatting wrapped in a 
       tag
      +	 */
      +	public static function format($string, $highlight=true)
      +	{
      +		// This variable will be populated with formatted html
      +		$return = '';
      +
      +		// Use an actual tab while formatting and then switch out with self::$tab at the end
      +		$tab = "\t";
      +
      +		$indent_level = 0;
      +		$newline = false;
      +		$inline_parentheses = false;
      +		$increase_special_indent = false;
      +		$increase_block_indent = false;
      +		$indent_types = array();
      +		$added_newline = false;
      +		$inline_count = 0;
      +		$inline_indented = false;
      +		$clause_limit = false;
      +
      +		// Tokenize String
      +		$original_tokens = self::tokenize($string);
      +
      +		// Remove existing whitespace
      +		$tokens = array();
      +		foreach ($original_tokens as $i=>$token) {
      +			if ($token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
      +				$token['i'] = $i;
      +				$tokens[] = $token;
      +			}
      +		}
      +
      +		// Format token by token
      +		foreach ($tokens as $i=>$token) {
      +			// Get highlighted token if doing syntax highlighting
      +			if ($highlight) {
      +				$highlighted = self::highlightToken($token);
      +			} else { // If returning raw text
      +				$highlighted = $token[self::TOKEN_VALUE];
      +			}
      +
      +			// If we are increasing the special indent level now
      +			if ($increase_special_indent) {
      +				$indent_level++;
      +				$increase_special_indent = false;
      +				array_unshift($indent_types,'special');
      +			}
      +			// If we are increasing the block indent level now
      +			if ($increase_block_indent) {
      +				$indent_level++;
      +				$increase_block_indent = false;
      +				array_unshift($indent_types,'block');
      +			}
      +
      +			// If we need a new line before the token
      +			if ($newline) {
      +				$return .= "\n" . str_repeat($tab, $indent_level);
      +				$newline = false;
      +				$added_newline = true;
      +			} else {
      +				$added_newline = false;
      +			}
      +
      +			// Display comments directly where they appear in the source
      +			if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_COMMENT || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
      +				if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
      +					$indent = str_repeat($tab,$indent_level);
      +					$return .= "\n" . $indent;
      +					$highlighted = str_replace("\n","\n".$indent,$highlighted);
      +				}
      +
      +				$return .= $highlighted;
      +				$newline = true;
      +				continue;
      +			}
      +
      +			if ($inline_parentheses) {
      +				// End of inline parentheses
      +				if ($token[self::TOKEN_VALUE] === ')') {
      +					$return = rtrim($return,' ');
      +
      +					if ($inline_indented) {
      +						array_shift($indent_types);
      +						$indent_level --;
      +						$return .= "\n" . str_repeat($tab, $indent_level);
      +					}
      +
      +					$inline_parentheses = false;
      +
      +					$return .= $highlighted . ' ';
      +					continue;
      +				}
      +
      +				if ($token[self::TOKEN_VALUE] === ',') {
      +					if ($inline_count >= 30) {
      +						$inline_count = 0;
      +						$newline = true;
      +					}
      +				}
      +
      +				$inline_count += strlen($token[self::TOKEN_VALUE]);
      +			}
      +
      +			// Opening parentheses increase the block indent level and start a new line
      +			if ($token[self::TOKEN_VALUE] === '(') {
      +				// First check if this should be an inline parentheses block
      +				// Examples are "NOW()", "COUNT(*)", "int(10)", key(`somecolumn`), DECIMAL(7,2)
      +				// Allow up to 3 non-whitespace tokens inside inline parentheses
      +				$length = 0;
      +				for ($j=1;$j<=250;$j++) {
      +					// Reached end of string
      +					if (!isset($tokens[$i+$j])) break;
      +
      +					$next = $tokens[$i+$j];
      +
      +					// Reached closing parentheses, able to inline it
      +					if ($next[self::TOKEN_VALUE] === ')') {
      +						$inline_parentheses = true;
      +						$inline_count = 0;
      +						$inline_indented = false;
      +						break;
      +					}
      +
      +					// Reached an invalid token for inline parentheses
      +					if ($next[self::TOKEN_VALUE]===';' || $next[self::TOKEN_VALUE]==='(') {
      +						break;
      +					}
      +
      +					// Reached an invalid token type for inline parentheses
      +					if ($next[self::TOKEN_TYPE]===self::TOKEN_TYPE_RESERVED_TOPLEVEL || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_RESERVED_NEWLINE || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_COMMENT || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_BLOCK_COMMENT) {
      +						break;
      +					}
      +
      +					$length += strlen($next[self::TOKEN_VALUE]);
      +				}
      +
      +				if ($inline_parentheses && $length > 30) {
      +					$increase_block_indent = true;
      +					$inline_indented = true;
      +					$newline = true;
      +				}
      +
      +				// Take out the preceding space unless there was whitespace there in the original query
      +				if (isset($original_tokens[$token['i']-1]) && $original_tokens[$token['i']-1][self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
      +					$return = rtrim($return,' ');
      +				}
      +
      +				if (!$inline_parentheses) {
      +					$increase_block_indent = true;
      +					// Add a newline after the parentheses
      +					$newline = true;
      +				}
      +
      +			}
      +
      +			// Closing parentheses decrease the block indent level
      +			elseif ($token[self::TOKEN_VALUE] === ')') {
      +				// Remove whitespace before the closing parentheses
      +				$return = rtrim($return,' ');
      +
      +				$indent_level--;
      +
      +				// Reset indent level
      +				while ($j=array_shift($indent_types)) {
      +					if ($j==='special') {
      +						$indent_level--;
      +					} else {
      +						break;
      +					}
      +				}
      +
      +				if ($indent_level < 0) {
      +					// This is an error
      +					$indent_level = 0;
      +
      +					if ($highlight) {
      +						$return .= "\n".self::highlightError($token[self::TOKEN_VALUE]);
      +						continue;
      +					}
      +				}
      +
      +				// Add a newline before the closing parentheses (if not already added)
      +				if (!$added_newline) {
      +					$return .= "\n" . str_repeat($tab, $indent_level);
      +				}
      +			}
      +
      +			// Top level reserved words start a new line and increase the special indent level
      +			elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
      +				$increase_special_indent = true;
      +
      +				// If the last indent type was 'special', decrease the special indent for this round
      +				reset($indent_types);
      +				if (current($indent_types)==='special') {
      +					$indent_level--;
      +					array_shift($indent_types);
      +				}
      +
      +				// Add a newline after the top level reserved word
      +				$newline = true;
      +				// Add a newline before the top level reserved word (if not already added)
      +				if (!$added_newline) {
      +					$return .= "\n" . str_repeat($tab, $indent_level);
      +				}
      +				// If we already added a newline, redo the indentation since it may be different now
      +				else {
      +					$return = rtrim($return,$tab).str_repeat($tab, $indent_level);
      +				}
      +
      +				// If the token may have extra whitespace
      +				if (strpos($token[self::TOKEN_VALUE],' ')!==false || strpos($token[self::TOKEN_VALUE],"\n")!==false || strpos($token[self::TOKEN_VALUE],"\t")!==false) {
      +					$highlighted = preg_replace('/\s+/',' ',$highlighted);
      +				}
      +				//if SQL 'LIMIT' clause, start variable to reset newline
      +				if ($token[self::TOKEN_VALUE] === 'LIMIT' && !$inline_parentheses) {
      +					$clause_limit = true;
      +				}
      +			}
      +
      +			// Checks if we are out of the limit clause
      +			elseif ($clause_limit && $token[self::TOKEN_VALUE] !== "," && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_NUMBER && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
      +				$clause_limit = false;
      +			}
      +
      +			// Commas start a new line (unless within inline parentheses or SQL 'LIMIT' clause)
      +			elseif ($token[self::TOKEN_VALUE] === ',' && !$inline_parentheses) {
      +				//If the previous TOKEN_VALUE is 'LIMIT', resets new line
      +				if ($clause_limit === true) {
      +					$newline = false;
      +					$clause_limit = false;
      +				}
      +				// All other cases of commas
      +				else {
      +					$newline = true;
      +				}
      +			}
      +
      +			// Newline reserved words start a new line
      +			elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_NEWLINE) {
      +				// Add a newline before the reserved word (if not already added)
      +				if (!$added_newline) {
      +					$return .= "\n" . str_repeat($tab, $indent_level);
      +				}
      +
      +				// If the token may have extra whitespace
      +				if (strpos($token[self::TOKEN_VALUE],' ')!==false || strpos($token[self::TOKEN_VALUE],"\n")!==false || strpos($token[self::TOKEN_VALUE],"\t")!==false) {
      +					$highlighted = preg_replace('/\s+/',' ',$highlighted);
      +				}
      +			}
      +
      +			// Multiple boundary characters in a row should not have spaces between them (not including parentheses)
      +			elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BOUNDARY) {
      +				if (isset($tokens[$i-1]) && $tokens[$i-1][self::TOKEN_TYPE] === self::TOKEN_TYPE_BOUNDARY) {
      +					if (isset($original_tokens[$token['i']-1]) && $original_tokens[$token['i']-1][self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
      +						$return = rtrim($return,' ');
      +					}
      +				}
      +			}
      +
      +			// If the token shouldn't have a space before it
      +			if ($token[self::TOKEN_VALUE] === '.' || $token[self::TOKEN_VALUE] === ',' || $token[self::TOKEN_VALUE] === ';') {
      +				$return = rtrim($return, ' ');
      +			}
      +
      +			$return .= $highlighted.' ';
      +
      +			// If the token shouldn't have a space after it
      +			if ($token[self::TOKEN_VALUE] === '(' || $token[self::TOKEN_VALUE] === '.') {
      +				$return = rtrim($return,' ');
      +			}
      +
      +			// If this is the "-" of a negative number, it shouldn't have a space after it
      +			if($token[self::TOKEN_VALUE] === '-' && isset($tokens[$i+1]) && $tokens[$i+1][self::TOKEN_TYPE] === self::TOKEN_TYPE_NUMBER && isset($tokens[$i-1])) {
      +				$prev = $tokens[$i-1][self::TOKEN_TYPE];
      +				if($prev !== self::TOKEN_TYPE_QUOTE && $prev !== self::TOKEN_TYPE_BACKTICK_QUOTE && $prev !== self::TOKEN_TYPE_WORD && $prev !== self::TOKEN_TYPE_NUMBER) {
      +					$return = rtrim($return,' ');
      +				}
      +			}
      +		}
      +
      +		// If there are unmatched parentheses
      +		if ($highlight && array_search('block',$indent_types) !== false) {
      +			$return .= "\n".self::highlightError("WARNING: unclosed parentheses or section");
      +		}
      +
      +		// Replace tab characters with the configuration tab character
      +		$return = trim(str_replace("\t",self::$tab,$return));
      +
      +		if ($highlight) {
      +			$return = self::output($return);
      +		}
      +
      +		return $return;
      +	}
      +
      +	/**
      +	 * Add syntax highlighting to a SQL string
      +	 *
      +	 * @param String $string The SQL string
      +	 *
      +	 * @return String The SQL string with HTML styles applied
      +	 */
      +	public static function highlight($string)
      +	{
      +		$tokens = self::tokenize($string);
      +
      +		$return = '';
      +
      +		foreach ($tokens as $token) {
      +			$return .= self::highlightToken($token);
      +		}
      +
      +		return self::output($return);
      +	}
      +
      +	/**
      +	 * Split a SQL string into multiple queries.
      +	 * Uses ";" as a query delimiter.
      +	 *
      +	 * @param String $string The SQL string
      +	 *
      +	 * @return Array An array of individual query strings without trailing semicolons
      +	 */
      +	public static function splitQuery($string)
      +	{
      +		$queries = array();
      +		$current_query = '';
      +		$empty = true;
      +
      +		$tokens = self::tokenize($string);
      +
      +		foreach ($tokens as $token) {
      +			// If this is a query separator
      +			if ($token[self::TOKEN_VALUE] === ';') {
      +				if (!$empty) {
      +					$queries[] = $current_query.';';
      +				}
      +				$current_query = '';
      +				$empty = true;
      +				continue;
      +			}
      +
      +			// If this is a non-empty character
      +			if ($token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_COMMENT && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_BLOCK_COMMENT) {
      +				$empty = false;
      +			}
      +
      +			$current_query .= $token[self::TOKEN_VALUE];
      +		}
      +
      +		if (!$empty) {
      +			$queries[] = trim($current_query);
      +		}
      +
      +		return $queries;
      +	}
      +
      +	/**
      +	 * Remove all comments from a SQL string
      +	 *
      +	 * @param String $string The SQL string
      +	 *
      +	 * @return String The SQL string without comments
      +	 */
      +	public static function removeComments($string)
      +	{
      +		$result = '';
      +
      +		$tokens = self::tokenize($string);
      +
      +		foreach ($tokens as $token) {
      +			// Skip comment tokens
      +			if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_COMMENT || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
      +				continue;
      +			}
      +
      +			$result .= $token[self::TOKEN_VALUE];
      +		}
      +		$result = self::format( $result,false);
      +
      +		return $result;
      +	}
      +
      +	/**
      +	 * Compress a query by collapsing white space and removing comments
      +	 *
      +	 * @param String $string The SQL string
      +	 *
      +	 * @return String The SQL string without comments
      +	 */
      +	public static function compress($string)
      +	{
      +		$result = '';
      +
      +		$tokens = self::tokenize($string);
      +
      +		$whitespace = true;
      +		foreach ($tokens as $token) {
      +			// Skip comment tokens
      +			if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_COMMENT || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BLOCK_COMMENT) {
      +				continue;
      +			}
      +			// Remove extra whitespace in reserved words (e.g "OUTER	 JOIN" becomes "OUTER JOIN")
      +			elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_NEWLINE || $token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
      +				$token[self::TOKEN_VALUE] = preg_replace('/\s+/',' ',$token[self::TOKEN_VALUE]);
      +			}
      +
      +			if ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_WHITESPACE) {
      +				// If the last token was whitespace, don't add another one
      +				if ($whitespace) {
      +					continue;
      +				} else {
      +					$whitespace = true;
      +					// Convert all whitespace to a single space
      +					$token[self::TOKEN_VALUE] = ' ';
      +				}
      +			} else {
      +				$whitespace = false;
      +			}
      +
      +			$result .= $token[self::TOKEN_VALUE];
      +		}
      +
      +		return rtrim($result);
      +	}
      +
      +	/**
      +	 * Highlights a token depending on its type.
      +	 *
      +	 * @param Array $token An associative array containing type and value.
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightToken($token)
      +	{
      +		$type = $token[self::TOKEN_TYPE];
      +
      +		if (self::is_cli()) {
      +			$token = $token[self::TOKEN_VALUE];
      +		} else {
      +			if (defined('ENT_IGNORE')) {
      +			  $token = htmlentities($token[self::TOKEN_VALUE],ENT_COMPAT | ENT_IGNORE ,'UTF-8');
      +			} else {
      +			  $token = htmlentities($token[self::TOKEN_VALUE],ENT_COMPAT,'UTF-8');
      +			}
      +		}
      +
      +		if ($type===self::TOKEN_TYPE_BOUNDARY) {
      +			return self::highlightBoundary($token);
      +		} elseif ($type===self::TOKEN_TYPE_WORD) {
      +			return self::highlightWord($token);
      +		} elseif ($type===self::TOKEN_TYPE_BACKTICK_QUOTE) {
      +			return self::highlightBacktickQuote($token);
      +		} elseif ($type===self::TOKEN_TYPE_QUOTE) {
      +			return self::highlightQuote($token);
      +		} elseif ($type===self::TOKEN_TYPE_RESERVED) {
      +			return self::highlightReservedWord($token);
      +		} elseif ($type===self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
      +			return self::highlightReservedWord($token);
      +		} elseif ($type===self::TOKEN_TYPE_RESERVED_NEWLINE) {
      +			return self::highlightReservedWord($token);
      +		} elseif ($type===self::TOKEN_TYPE_NUMBER) {
      +			return self::highlightNumber($token);
      +		} elseif ($type===self::TOKEN_TYPE_VARIABLE) {
      +			return self::highlightVariable($token);
      +		} elseif ($type===self::TOKEN_TYPE_COMMENT || $type===self::TOKEN_TYPE_BLOCK_COMMENT) {
      +			return self::highlightComment($token);
      +		}
      +
      +		return $token;
      +	}
      +
      +	/**
      +	 * Highlights a quoted string
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightQuote($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_quote . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a backtick quoted string
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightBacktickQuote($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_backtick_quote . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a reserved word
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightReservedWord($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_reserved . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a boundary token
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightBoundary($value)
      +	{
      +		if ($value==='(' || $value===')') return $value;
      +
      +		if (self::is_cli()) {
      +			return self::$cli_boundary . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a number
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightNumber($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_number . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights an error
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightError($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_error . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a comment
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightComment($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_comment . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a word token
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightWord($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_word . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Highlights a variable token
      +	 *
      +	 * @param String $value The token's value
      +	 *
      +	 * @return String HTML code of the highlighted token.
      +	 */
      +	protected static function highlightVariable($value)
      +	{
      +		if (self::is_cli()) {
      +			return self::$cli_variable . $value . "\x1b[0m";
      +		} else {
      +			return '' . $value . '';
      +		}
      +	}
      +
      +	/**
      +	 * Helper function for building regular expressions for reserved words and boundary characters
      +	 *
      +	 * @param String $a The string to be quoted
      +	 *
      +	 * @return String The quoted string
      +	 */
      +	private static function quote_regex($a)
      +	{
      +		return preg_quote($a,'/');
      +	}
      +
      +	/**
      +	 * Helper function for building string output
      +	 *
      +	 * @param String $string The string to be quoted
      +	 *
      +	 * @return String The quoted string
      +	 */
      +	private static function output($string)
      +	{
      +		if (self::is_cli()) {
      +			return $string."\n";
      +		} else {
      +			$string=trim($string);
      +			if (!self::$use_pre) {
      +				return $string;
      +			}
      +
      +			return '
      ' . $string . '
      '; + } + } + + private static function is_cli() + { + if (isset(self::$cli)) return self::$cli; + else return php_sapi_name() === 'cli'; + } + +} \ No newline at end of file diff --git a/lib/flags/ad.png b/lib/flags/ad.png new file mode 100644 index 0000000..625ca84 Binary files /dev/null and b/lib/flags/ad.png differ diff --git a/lib/flags/ae.png b/lib/flags/ae.png new file mode 100644 index 0000000..ef3a1ec Binary files /dev/null and b/lib/flags/ae.png differ diff --git a/lib/flags/af.png b/lib/flags/af.png new file mode 100644 index 0000000..a4742e2 Binary files /dev/null and b/lib/flags/af.png differ diff --git a/lib/flags/ag.png b/lib/flags/ag.png new file mode 100644 index 0000000..556d550 Binary files /dev/null and b/lib/flags/ag.png differ diff --git a/lib/flags/ai.png b/lib/flags/ai.png new file mode 100644 index 0000000..74ed29d Binary files /dev/null and b/lib/flags/ai.png differ diff --git a/lib/flags/al.png b/lib/flags/al.png new file mode 100644 index 0000000..92354cb Binary files /dev/null and b/lib/flags/al.png differ diff --git a/lib/flags/am.png b/lib/flags/am.png new file mode 100644 index 0000000..344a2a8 Binary files /dev/null and b/lib/flags/am.png differ diff --git a/lib/flags/an.png b/lib/flags/an.png new file mode 100644 index 0000000..633e4b8 Binary files /dev/null and b/lib/flags/an.png differ diff --git a/lib/flags/ao.png b/lib/flags/ao.png new file mode 100644 index 0000000..bcbd1d6 Binary files /dev/null and b/lib/flags/ao.png differ diff --git a/lib/flags/ar.png b/lib/flags/ar.png new file mode 100644 index 0000000..e5ef8f1 Binary files /dev/null and b/lib/flags/ar.png differ diff --git a/lib/flags/as.png b/lib/flags/as.png new file mode 100644 index 0000000..32f30e4 Binary files /dev/null and b/lib/flags/as.png differ diff --git a/lib/flags/at.png b/lib/flags/at.png new file mode 100644 index 0000000..0f15f34 Binary files /dev/null and b/lib/flags/at.png differ diff --git a/lib/flags/au.png b/lib/flags/au.png new file mode 100644 index 0000000..a01389a Binary files /dev/null and b/lib/flags/au.png differ diff --git a/lib/flags/aw.png b/lib/flags/aw.png new file mode 100644 index 0000000..a3579c2 Binary files /dev/null and b/lib/flags/aw.png differ diff --git a/lib/flags/ax.png b/lib/flags/ax.png new file mode 100644 index 0000000..1eea80a Binary files /dev/null and b/lib/flags/ax.png differ diff --git a/lib/flags/az.png b/lib/flags/az.png new file mode 100644 index 0000000..4ee9fe5 Binary files /dev/null and b/lib/flags/az.png differ diff --git a/lib/flags/ba.png b/lib/flags/ba.png new file mode 100644 index 0000000..c774992 Binary files /dev/null and b/lib/flags/ba.png differ diff --git a/lib/flags/bb.png b/lib/flags/bb.png new file mode 100644 index 0000000..0df19c7 Binary files /dev/null and b/lib/flags/bb.png differ diff --git a/lib/flags/bd.png b/lib/flags/bd.png new file mode 100644 index 0000000..076a8bf Binary files /dev/null and b/lib/flags/bd.png differ diff --git a/lib/flags/be.png b/lib/flags/be.png new file mode 100644 index 0000000..d86ebc8 Binary files /dev/null and b/lib/flags/be.png differ diff --git a/lib/flags/bf.png b/lib/flags/bf.png new file mode 100644 index 0000000..ab5ce8f Binary files /dev/null and b/lib/flags/bf.png differ diff --git a/lib/flags/bg.png b/lib/flags/bg.png new file mode 100644 index 0000000..0469f06 Binary files /dev/null and b/lib/flags/bg.png differ diff --git a/lib/flags/bh.png b/lib/flags/bh.png new file mode 100644 index 0000000..ea8ce68 Binary files /dev/null and b/lib/flags/bh.png differ diff --git a/lib/flags/bi.png b/lib/flags/bi.png new file mode 100644 index 0000000..5cc2e30 Binary files /dev/null and b/lib/flags/bi.png differ diff --git a/lib/flags/bj.png b/lib/flags/bj.png new file mode 100644 index 0000000..1cc8b45 Binary files /dev/null and b/lib/flags/bj.png differ diff --git a/lib/flags/bm.png b/lib/flags/bm.png new file mode 100644 index 0000000..c0c7aea Binary files /dev/null and b/lib/flags/bm.png differ diff --git a/lib/flags/bn.png b/lib/flags/bn.png new file mode 100644 index 0000000..8fb0984 Binary files /dev/null and b/lib/flags/bn.png differ diff --git a/lib/flags/bo.png b/lib/flags/bo.png new file mode 100644 index 0000000..ce7ba52 Binary files /dev/null and b/lib/flags/bo.png differ diff --git a/lib/flags/br.png b/lib/flags/br.png new file mode 100644 index 0000000..9b1a553 Binary files /dev/null and b/lib/flags/br.png differ diff --git a/lib/flags/bs.png b/lib/flags/bs.png new file mode 100644 index 0000000..639fa6c Binary files /dev/null and b/lib/flags/bs.png differ diff --git a/lib/flags/bt.png b/lib/flags/bt.png new file mode 100644 index 0000000..1d512df Binary files /dev/null and b/lib/flags/bt.png differ diff --git a/lib/flags/bv.png b/lib/flags/bv.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/lib/flags/bv.png differ diff --git a/lib/flags/bw.png b/lib/flags/bw.png new file mode 100644 index 0000000..fcb1039 Binary files /dev/null and b/lib/flags/bw.png differ diff --git a/lib/flags/by.png b/lib/flags/by.png new file mode 100644 index 0000000..504774e Binary files /dev/null and b/lib/flags/by.png differ diff --git a/lib/flags/bz.png b/lib/flags/bz.png new file mode 100644 index 0000000..be63ee1 Binary files /dev/null and b/lib/flags/bz.png differ diff --git a/lib/flags/ca.png b/lib/flags/ca.png new file mode 100644 index 0000000..1f20419 Binary files /dev/null and b/lib/flags/ca.png differ diff --git a/lib/flags/catalonia.png b/lib/flags/catalonia.png new file mode 100644 index 0000000..5041e30 Binary files /dev/null and b/lib/flags/catalonia.png differ diff --git a/lib/flags/cc.png b/lib/flags/cc.png new file mode 100644 index 0000000..aed3d3b Binary files /dev/null and b/lib/flags/cc.png differ diff --git a/lib/flags/cd.png b/lib/flags/cd.png new file mode 100644 index 0000000..5e48942 Binary files /dev/null and b/lib/flags/cd.png differ diff --git a/lib/flags/cf.png b/lib/flags/cf.png new file mode 100644 index 0000000..da687bd Binary files /dev/null and b/lib/flags/cf.png differ diff --git a/lib/flags/cg.png b/lib/flags/cg.png new file mode 100644 index 0000000..a859792 Binary files /dev/null and b/lib/flags/cg.png differ diff --git a/lib/flags/ch.png b/lib/flags/ch.png new file mode 100644 index 0000000..242ec01 Binary files /dev/null and b/lib/flags/ch.png differ diff --git a/lib/flags/ci.png b/lib/flags/ci.png new file mode 100644 index 0000000..3f2c62e Binary files /dev/null and b/lib/flags/ci.png differ diff --git a/lib/flags/ck.png b/lib/flags/ck.png new file mode 100644 index 0000000..746d3d6 Binary files /dev/null and b/lib/flags/ck.png differ diff --git a/lib/flags/cl.png b/lib/flags/cl.png new file mode 100644 index 0000000..29c6d61 Binary files /dev/null and b/lib/flags/cl.png differ diff --git a/lib/flags/cm.png b/lib/flags/cm.png new file mode 100644 index 0000000..f65c5bd Binary files /dev/null and b/lib/flags/cm.png differ diff --git a/lib/flags/cn.png b/lib/flags/cn.png new file mode 100644 index 0000000..8914414 Binary files /dev/null and b/lib/flags/cn.png differ diff --git a/lib/flags/co.png b/lib/flags/co.png new file mode 100644 index 0000000..a118ff4 Binary files /dev/null and b/lib/flags/co.png differ diff --git a/lib/flags/cr.png b/lib/flags/cr.png new file mode 100644 index 0000000..c7a3731 Binary files /dev/null and b/lib/flags/cr.png differ diff --git a/lib/flags/cs.png b/lib/flags/cs.png new file mode 100644 index 0000000..8254790 Binary files /dev/null and b/lib/flags/cs.png differ diff --git a/lib/flags/cu.png b/lib/flags/cu.png new file mode 100644 index 0000000..083f1d6 Binary files /dev/null and b/lib/flags/cu.png differ diff --git a/lib/flags/cv.png b/lib/flags/cv.png new file mode 100644 index 0000000..a63f7ea Binary files /dev/null and b/lib/flags/cv.png differ diff --git a/lib/flags/cx.png b/lib/flags/cx.png new file mode 100644 index 0000000..48e31ad Binary files /dev/null and b/lib/flags/cx.png differ diff --git a/lib/flags/cy.png b/lib/flags/cy.png new file mode 100644 index 0000000..5b1ad6c Binary files /dev/null and b/lib/flags/cy.png differ diff --git a/lib/flags/cz.png b/lib/flags/cz.png new file mode 100644 index 0000000..c8403dd Binary files /dev/null and b/lib/flags/cz.png differ diff --git a/lib/flags/de.png b/lib/flags/de.png new file mode 100644 index 0000000..ac4a977 Binary files /dev/null and b/lib/flags/de.png differ diff --git a/lib/flags/dj.png b/lib/flags/dj.png new file mode 100644 index 0000000..582af36 Binary files /dev/null and b/lib/flags/dj.png differ diff --git a/lib/flags/dk.png b/lib/flags/dk.png new file mode 100644 index 0000000..e2993d3 Binary files /dev/null and b/lib/flags/dk.png differ diff --git a/lib/flags/dm.png b/lib/flags/dm.png new file mode 100644 index 0000000..5fbffcb Binary files /dev/null and b/lib/flags/dm.png differ diff --git a/lib/flags/do.png b/lib/flags/do.png new file mode 100644 index 0000000..5a04932 Binary files /dev/null and b/lib/flags/do.png differ diff --git a/lib/flags/dz.png b/lib/flags/dz.png new file mode 100644 index 0000000..335c239 Binary files /dev/null and b/lib/flags/dz.png differ diff --git a/lib/flags/ec.png b/lib/flags/ec.png new file mode 100644 index 0000000..0caa0b1 Binary files /dev/null and b/lib/flags/ec.png differ diff --git a/lib/flags/ee.png b/lib/flags/ee.png new file mode 100644 index 0000000..0c82efb Binary files /dev/null and b/lib/flags/ee.png differ diff --git a/lib/flags/eg.png b/lib/flags/eg.png new file mode 100644 index 0000000..8a3f7a1 Binary files /dev/null and b/lib/flags/eg.png differ diff --git a/lib/flags/eh.png b/lib/flags/eh.png new file mode 100644 index 0000000..90a1195 Binary files /dev/null and b/lib/flags/eh.png differ diff --git a/lib/flags/en.png b/lib/flags/en.png new file mode 100644 index 0000000..10f451f Binary files /dev/null and b/lib/flags/en.png differ diff --git a/lib/flags/england.png b/lib/flags/england.png new file mode 100644 index 0000000..3a7311d Binary files /dev/null and b/lib/flags/england.png differ diff --git a/lib/flags/er.png b/lib/flags/er.png new file mode 100644 index 0000000..13065ae Binary files /dev/null and b/lib/flags/er.png differ diff --git a/lib/flags/es.png b/lib/flags/es.png new file mode 100644 index 0000000..c2de2d7 Binary files /dev/null and b/lib/flags/es.png differ diff --git a/lib/flags/et.png b/lib/flags/et.png new file mode 100644 index 0000000..2e893fa Binary files /dev/null and b/lib/flags/et.png differ diff --git a/lib/flags/eu.png b/lib/flags/eu.png new file mode 100644 index 0000000..d6d8711 Binary files /dev/null and b/lib/flags/eu.png differ diff --git a/lib/flags/fam.png b/lib/flags/fam.png new file mode 100644 index 0000000..cf50c75 Binary files /dev/null and b/lib/flags/fam.png differ diff --git a/lib/flags/fi.png b/lib/flags/fi.png new file mode 100644 index 0000000..14ec091 Binary files /dev/null and b/lib/flags/fi.png differ diff --git a/lib/flags/fj.png b/lib/flags/fj.png new file mode 100644 index 0000000..cee9988 Binary files /dev/null and b/lib/flags/fj.png differ diff --git a/lib/flags/fk.png b/lib/flags/fk.png new file mode 100644 index 0000000..ceaeb27 Binary files /dev/null and b/lib/flags/fk.png differ diff --git a/lib/flags/fm.png b/lib/flags/fm.png new file mode 100644 index 0000000..066bb24 Binary files /dev/null and b/lib/flags/fm.png differ diff --git a/lib/flags/fo.png b/lib/flags/fo.png new file mode 100644 index 0000000..cbceb80 Binary files /dev/null and b/lib/flags/fo.png differ diff --git a/lib/flags/fr.png b/lib/flags/fr.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/flags/fr.png differ diff --git a/lib/flags/ga.png b/lib/flags/ga.png new file mode 100644 index 0000000..0e0d434 Binary files /dev/null and b/lib/flags/ga.png differ diff --git a/lib/flags/gb.png b/lib/flags/gb.png new file mode 100644 index 0000000..ff701e1 Binary files /dev/null and b/lib/flags/gb.png differ diff --git a/lib/flags/gd.png b/lib/flags/gd.png new file mode 100644 index 0000000..9ab57f5 Binary files /dev/null and b/lib/flags/gd.png differ diff --git a/lib/flags/ge.png b/lib/flags/ge.png new file mode 100644 index 0000000..728d970 Binary files /dev/null and b/lib/flags/ge.png differ diff --git a/lib/flags/gf.png b/lib/flags/gf.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/flags/gf.png differ diff --git a/lib/flags/gh.png b/lib/flags/gh.png new file mode 100644 index 0000000..4e2f896 Binary files /dev/null and b/lib/flags/gh.png differ diff --git a/lib/flags/gi.png b/lib/flags/gi.png new file mode 100644 index 0000000..e76797f Binary files /dev/null and b/lib/flags/gi.png differ diff --git a/lib/flags/gl.png b/lib/flags/gl.png new file mode 100644 index 0000000..ef12a73 Binary files /dev/null and b/lib/flags/gl.png differ diff --git a/lib/flags/gm.png b/lib/flags/gm.png new file mode 100644 index 0000000..0720b66 Binary files /dev/null and b/lib/flags/gm.png differ diff --git a/lib/flags/gn.png b/lib/flags/gn.png new file mode 100644 index 0000000..ea660b0 Binary files /dev/null and b/lib/flags/gn.png differ diff --git a/lib/flags/gp.png b/lib/flags/gp.png new file mode 100644 index 0000000..dbb086d Binary files /dev/null and b/lib/flags/gp.png differ diff --git a/lib/flags/gq.png b/lib/flags/gq.png new file mode 100644 index 0000000..ebe20a2 Binary files /dev/null and b/lib/flags/gq.png differ diff --git a/lib/flags/gr.png b/lib/flags/gr.png new file mode 100644 index 0000000..8651ade Binary files /dev/null and b/lib/flags/gr.png differ diff --git a/lib/flags/gs.png b/lib/flags/gs.png new file mode 100644 index 0000000..7ef0bf5 Binary files /dev/null and b/lib/flags/gs.png differ diff --git a/lib/flags/gt.png b/lib/flags/gt.png new file mode 100644 index 0000000..c43a70d Binary files /dev/null and b/lib/flags/gt.png differ diff --git a/lib/flags/gu.png b/lib/flags/gu.png new file mode 100644 index 0000000..92f37c0 Binary files /dev/null and b/lib/flags/gu.png differ diff --git a/lib/flags/gw.png b/lib/flags/gw.png new file mode 100644 index 0000000..b37bcf0 Binary files /dev/null and b/lib/flags/gw.png differ diff --git a/lib/flags/gy.png b/lib/flags/gy.png new file mode 100644 index 0000000..22cbe2f Binary files /dev/null and b/lib/flags/gy.png differ diff --git a/lib/flags/hk.png b/lib/flags/hk.png new file mode 100644 index 0000000..d5c380c Binary files /dev/null and b/lib/flags/hk.png differ diff --git a/lib/flags/hm.png b/lib/flags/hm.png new file mode 100644 index 0000000..a01389a Binary files /dev/null and b/lib/flags/hm.png differ diff --git a/lib/flags/hn.png b/lib/flags/hn.png new file mode 100644 index 0000000..96f8388 Binary files /dev/null and b/lib/flags/hn.png differ diff --git a/lib/flags/hr.png b/lib/flags/hr.png new file mode 100644 index 0000000..696b515 Binary files /dev/null and b/lib/flags/hr.png differ diff --git a/lib/flags/ht.png b/lib/flags/ht.png new file mode 100644 index 0000000..416052a Binary files /dev/null and b/lib/flags/ht.png differ diff --git a/lib/flags/hu.png b/lib/flags/hu.png new file mode 100644 index 0000000..7baafe4 Binary files /dev/null and b/lib/flags/hu.png differ diff --git a/lib/flags/id.png b/lib/flags/id.png new file mode 100644 index 0000000..c6bc0fa Binary files /dev/null and b/lib/flags/id.png differ diff --git a/lib/flags/ie.png b/lib/flags/ie.png new file mode 100644 index 0000000..26baa31 Binary files /dev/null and b/lib/flags/ie.png differ diff --git a/lib/flags/il.png b/lib/flags/il.png new file mode 100644 index 0000000..2ca772d Binary files /dev/null and b/lib/flags/il.png differ diff --git a/lib/flags/in.png b/lib/flags/in.png new file mode 100644 index 0000000..e4d7e81 Binary files /dev/null and b/lib/flags/in.png differ diff --git a/lib/flags/io.png b/lib/flags/io.png new file mode 100644 index 0000000..3e74b6a Binary files /dev/null and b/lib/flags/io.png differ diff --git a/lib/flags/iq.png b/lib/flags/iq.png new file mode 100644 index 0000000..878a351 Binary files /dev/null and b/lib/flags/iq.png differ diff --git a/lib/flags/ir.png b/lib/flags/ir.png new file mode 100644 index 0000000..c5fd136 Binary files /dev/null and b/lib/flags/ir.png differ diff --git a/lib/flags/is.png b/lib/flags/is.png new file mode 100644 index 0000000..b8f6d0f Binary files /dev/null and b/lib/flags/is.png differ diff --git a/lib/flags/it.png b/lib/flags/it.png new file mode 100644 index 0000000..89692f7 Binary files /dev/null and b/lib/flags/it.png differ diff --git a/lib/flags/jm.png b/lib/flags/jm.png new file mode 100644 index 0000000..7be119e Binary files /dev/null and b/lib/flags/jm.png differ diff --git a/lib/flags/jo.png b/lib/flags/jo.png new file mode 100644 index 0000000..11bd497 Binary files /dev/null and b/lib/flags/jo.png differ diff --git a/lib/flags/jp.png b/lib/flags/jp.png new file mode 100644 index 0000000..325fbad Binary files /dev/null and b/lib/flags/jp.png differ diff --git a/lib/flags/ke.png b/lib/flags/ke.png new file mode 100644 index 0000000..51879ad Binary files /dev/null and b/lib/flags/ke.png differ diff --git a/lib/flags/kg.png b/lib/flags/kg.png new file mode 100644 index 0000000..0a818f6 Binary files /dev/null and b/lib/flags/kg.png differ diff --git a/lib/flags/kh.png b/lib/flags/kh.png new file mode 100644 index 0000000..30f6bb1 Binary files /dev/null and b/lib/flags/kh.png differ diff --git a/lib/flags/ki.png b/lib/flags/ki.png new file mode 100644 index 0000000..2dcce4b Binary files /dev/null and b/lib/flags/ki.png differ diff --git a/lib/flags/km.png b/lib/flags/km.png new file mode 100644 index 0000000..812b2f5 Binary files /dev/null and b/lib/flags/km.png differ diff --git a/lib/flags/kn.png b/lib/flags/kn.png new file mode 100644 index 0000000..febd5b4 Binary files /dev/null and b/lib/flags/kn.png differ diff --git a/lib/flags/kp.png b/lib/flags/kp.png new file mode 100644 index 0000000..d3d509a Binary files /dev/null and b/lib/flags/kp.png differ diff --git a/lib/flags/kr.png b/lib/flags/kr.png new file mode 100644 index 0000000..9c0a78e Binary files /dev/null and b/lib/flags/kr.png differ diff --git a/lib/flags/kw.png b/lib/flags/kw.png new file mode 100644 index 0000000..96546da Binary files /dev/null and b/lib/flags/kw.png differ diff --git a/lib/flags/ky.png b/lib/flags/ky.png new file mode 100644 index 0000000..15c5f8e Binary files /dev/null and b/lib/flags/ky.png differ diff --git a/lib/flags/kz.png b/lib/flags/kz.png new file mode 100644 index 0000000..45a8c88 Binary files /dev/null and b/lib/flags/kz.png differ diff --git a/lib/flags/la.png b/lib/flags/la.png new file mode 100644 index 0000000..e28acd0 Binary files /dev/null and b/lib/flags/la.png differ diff --git a/lib/flags/lb.png b/lib/flags/lb.png new file mode 100644 index 0000000..d0d452b Binary files /dev/null and b/lib/flags/lb.png differ diff --git a/lib/flags/lc.png b/lib/flags/lc.png new file mode 100644 index 0000000..a47d065 Binary files /dev/null and b/lib/flags/lc.png differ diff --git a/lib/flags/li.png b/lib/flags/li.png new file mode 100644 index 0000000..6469909 Binary files /dev/null and b/lib/flags/li.png differ diff --git a/lib/flags/lk.png b/lib/flags/lk.png new file mode 100644 index 0000000..088aad6 Binary files /dev/null and b/lib/flags/lk.png differ diff --git a/lib/flags/lr.png b/lib/flags/lr.png new file mode 100644 index 0000000..89a5bc7 Binary files /dev/null and b/lib/flags/lr.png differ diff --git a/lib/flags/ls.png b/lib/flags/ls.png new file mode 100644 index 0000000..33fdef1 Binary files /dev/null and b/lib/flags/ls.png differ diff --git a/lib/flags/lt.png b/lib/flags/lt.png new file mode 100644 index 0000000..c8ef0da Binary files /dev/null and b/lib/flags/lt.png differ diff --git a/lib/flags/lu.png b/lib/flags/lu.png new file mode 100644 index 0000000..4cabba9 Binary files /dev/null and b/lib/flags/lu.png differ diff --git a/lib/flags/lv.png b/lib/flags/lv.png new file mode 100644 index 0000000..49b6998 Binary files /dev/null and b/lib/flags/lv.png differ diff --git a/lib/flags/ly.png b/lib/flags/ly.png new file mode 100644 index 0000000..b163a9f Binary files /dev/null and b/lib/flags/ly.png differ diff --git a/lib/flags/ma.png b/lib/flags/ma.png new file mode 100644 index 0000000..f386770 Binary files /dev/null and b/lib/flags/ma.png differ diff --git a/lib/flags/mc.png b/lib/flags/mc.png new file mode 100644 index 0000000..1aa830f Binary files /dev/null and b/lib/flags/mc.png differ diff --git a/lib/flags/md.png b/lib/flags/md.png new file mode 100644 index 0000000..4e92c18 Binary files /dev/null and b/lib/flags/md.png differ diff --git a/lib/flags/me.png b/lib/flags/me.png new file mode 100644 index 0000000..ac72535 Binary files /dev/null and b/lib/flags/me.png differ diff --git a/lib/flags/mg.png b/lib/flags/mg.png new file mode 100644 index 0000000..d2715b3 Binary files /dev/null and b/lib/flags/mg.png differ diff --git a/lib/flags/mh.png b/lib/flags/mh.png new file mode 100644 index 0000000..fb523a8 Binary files /dev/null and b/lib/flags/mh.png differ diff --git a/lib/flags/mk.png b/lib/flags/mk.png new file mode 100644 index 0000000..db173aa Binary files /dev/null and b/lib/flags/mk.png differ diff --git a/lib/flags/ml.png b/lib/flags/ml.png new file mode 100644 index 0000000..2cec8ba Binary files /dev/null and b/lib/flags/ml.png differ diff --git a/lib/flags/mm.png b/lib/flags/mm.png new file mode 100644 index 0000000..f464f67 Binary files /dev/null and b/lib/flags/mm.png differ diff --git a/lib/flags/mn.png b/lib/flags/mn.png new file mode 100644 index 0000000..9396355 Binary files /dev/null and b/lib/flags/mn.png differ diff --git a/lib/flags/mo.png b/lib/flags/mo.png new file mode 100644 index 0000000..deb801d Binary files /dev/null and b/lib/flags/mo.png differ diff --git a/lib/flags/mp.png b/lib/flags/mp.png new file mode 100644 index 0000000..298d588 Binary files /dev/null and b/lib/flags/mp.png differ diff --git a/lib/flags/mq.png b/lib/flags/mq.png new file mode 100644 index 0000000..010143b Binary files /dev/null and b/lib/flags/mq.png differ diff --git a/lib/flags/mr.png b/lib/flags/mr.png new file mode 100644 index 0000000..319546b Binary files /dev/null and b/lib/flags/mr.png differ diff --git a/lib/flags/ms.png b/lib/flags/ms.png new file mode 100644 index 0000000..d4cbb43 Binary files /dev/null and b/lib/flags/ms.png differ diff --git a/lib/flags/mt.png b/lib/flags/mt.png new file mode 100644 index 0000000..00af948 Binary files /dev/null and b/lib/flags/mt.png differ diff --git a/lib/flags/mu.png b/lib/flags/mu.png new file mode 100644 index 0000000..b7fdce1 Binary files /dev/null and b/lib/flags/mu.png differ diff --git a/lib/flags/mv.png b/lib/flags/mv.png new file mode 100644 index 0000000..5073d9e Binary files /dev/null and b/lib/flags/mv.png differ diff --git a/lib/flags/mw.png b/lib/flags/mw.png new file mode 100644 index 0000000..13886e9 Binary files /dev/null and b/lib/flags/mw.png differ diff --git a/lib/flags/mx.png b/lib/flags/mx.png new file mode 100644 index 0000000..5bc58ab Binary files /dev/null and b/lib/flags/mx.png differ diff --git a/lib/flags/my.png b/lib/flags/my.png new file mode 100644 index 0000000..9034cba Binary files /dev/null and b/lib/flags/my.png differ diff --git a/lib/flags/mz.png b/lib/flags/mz.png new file mode 100644 index 0000000..76405e0 Binary files /dev/null and b/lib/flags/mz.png differ diff --git a/lib/flags/na.png b/lib/flags/na.png new file mode 100644 index 0000000..63358c6 Binary files /dev/null and b/lib/flags/na.png differ diff --git a/lib/flags/nc.png b/lib/flags/nc.png new file mode 100644 index 0000000..2cad283 Binary files /dev/null and b/lib/flags/nc.png differ diff --git a/lib/flags/ne.png b/lib/flags/ne.png new file mode 100644 index 0000000..d85f424 Binary files /dev/null and b/lib/flags/ne.png differ diff --git a/lib/flags/nf.png b/lib/flags/nf.png new file mode 100644 index 0000000..f9bcdda Binary files /dev/null and b/lib/flags/nf.png differ diff --git a/lib/flags/ng.png b/lib/flags/ng.png new file mode 100644 index 0000000..3eea2e0 Binary files /dev/null and b/lib/flags/ng.png differ diff --git a/lib/flags/ni.png b/lib/flags/ni.png new file mode 100644 index 0000000..3969aaa Binary files /dev/null and b/lib/flags/ni.png differ diff --git a/lib/flags/nl.png b/lib/flags/nl.png new file mode 100644 index 0000000..fe44791 Binary files /dev/null and b/lib/flags/nl.png differ diff --git a/lib/flags/no.png b/lib/flags/no.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/lib/flags/no.png differ diff --git a/lib/flags/np.png b/lib/flags/np.png new file mode 100644 index 0000000..aeb058b Binary files /dev/null and b/lib/flags/np.png differ diff --git a/lib/flags/nr.png b/lib/flags/nr.png new file mode 100644 index 0000000..705fc33 Binary files /dev/null and b/lib/flags/nr.png differ diff --git a/lib/flags/nu.png b/lib/flags/nu.png new file mode 100644 index 0000000..c3ce4ae Binary files /dev/null and b/lib/flags/nu.png differ diff --git a/lib/flags/nz.png b/lib/flags/nz.png new file mode 100644 index 0000000..10d6306 Binary files /dev/null and b/lib/flags/nz.png differ diff --git a/lib/flags/om.png b/lib/flags/om.png new file mode 100644 index 0000000..2ffba7e Binary files /dev/null and b/lib/flags/om.png differ diff --git a/lib/flags/pa.png b/lib/flags/pa.png new file mode 100644 index 0000000..9b2ee9a Binary files /dev/null and b/lib/flags/pa.png differ diff --git a/lib/flags/pe.png b/lib/flags/pe.png new file mode 100644 index 0000000..62a0497 Binary files /dev/null and b/lib/flags/pe.png differ diff --git a/lib/flags/pf.png b/lib/flags/pf.png new file mode 100644 index 0000000..771a0f6 Binary files /dev/null and b/lib/flags/pf.png differ diff --git a/lib/flags/pg.png b/lib/flags/pg.png new file mode 100644 index 0000000..10d6233 Binary files /dev/null and b/lib/flags/pg.png differ diff --git a/lib/flags/ph.png b/lib/flags/ph.png new file mode 100644 index 0000000..b89e159 Binary files /dev/null and b/lib/flags/ph.png differ diff --git a/lib/flags/pk.png b/lib/flags/pk.png new file mode 100644 index 0000000..e9df70c Binary files /dev/null and b/lib/flags/pk.png differ diff --git a/lib/flags/pl.png b/lib/flags/pl.png new file mode 100644 index 0000000..d413d01 Binary files /dev/null and b/lib/flags/pl.png differ diff --git a/lib/flags/pm.png b/lib/flags/pm.png new file mode 100644 index 0000000..ba91d2c Binary files /dev/null and b/lib/flags/pm.png differ diff --git a/lib/flags/pn.png b/lib/flags/pn.png new file mode 100644 index 0000000..aa9344f Binary files /dev/null and b/lib/flags/pn.png differ diff --git a/lib/flags/pr.png b/lib/flags/pr.png new file mode 100644 index 0000000..82d9130 Binary files /dev/null and b/lib/flags/pr.png differ diff --git a/lib/flags/ps.png b/lib/flags/ps.png new file mode 100644 index 0000000..f5f5477 Binary files /dev/null and b/lib/flags/ps.png differ diff --git a/lib/flags/pt.png b/lib/flags/pt.png new file mode 100644 index 0000000..ece7980 Binary files /dev/null and b/lib/flags/pt.png differ diff --git a/lib/flags/pw.png b/lib/flags/pw.png new file mode 100644 index 0000000..6178b25 Binary files /dev/null and b/lib/flags/pw.png differ diff --git a/lib/flags/py.png b/lib/flags/py.png new file mode 100644 index 0000000..cb8723c Binary files /dev/null and b/lib/flags/py.png differ diff --git a/lib/flags/qa.png b/lib/flags/qa.png new file mode 100644 index 0000000..ed4c621 Binary files /dev/null and b/lib/flags/qa.png differ diff --git a/lib/flags/re.png b/lib/flags/re.png new file mode 100644 index 0000000..8332c4e Binary files /dev/null and b/lib/flags/re.png differ diff --git a/lib/flags/ro.png b/lib/flags/ro.png new file mode 100644 index 0000000..57e74a6 Binary files /dev/null and b/lib/flags/ro.png differ diff --git a/lib/flags/rs.png b/lib/flags/rs.png new file mode 100644 index 0000000..9439a5b Binary files /dev/null and b/lib/flags/rs.png differ diff --git a/lib/flags/ru.png b/lib/flags/ru.png new file mode 100644 index 0000000..47da421 Binary files /dev/null and b/lib/flags/ru.png differ diff --git a/lib/flags/rw.png b/lib/flags/rw.png new file mode 100644 index 0000000..5356491 Binary files /dev/null and b/lib/flags/rw.png differ diff --git a/lib/flags/sa.png b/lib/flags/sa.png new file mode 100644 index 0000000..b4641c7 Binary files /dev/null and b/lib/flags/sa.png differ diff --git a/lib/flags/sb.png b/lib/flags/sb.png new file mode 100644 index 0000000..a9937cc Binary files /dev/null and b/lib/flags/sb.png differ diff --git a/lib/flags/sc.png b/lib/flags/sc.png new file mode 100644 index 0000000..39ee371 Binary files /dev/null and b/lib/flags/sc.png differ diff --git a/lib/flags/scotland.png b/lib/flags/scotland.png new file mode 100644 index 0000000..a0e57b4 Binary files /dev/null and b/lib/flags/scotland.png differ diff --git a/lib/flags/sd.png b/lib/flags/sd.png new file mode 100644 index 0000000..eaab69e Binary files /dev/null and b/lib/flags/sd.png differ diff --git a/lib/flags/se.png b/lib/flags/se.png new file mode 100644 index 0000000..1994653 Binary files /dev/null and b/lib/flags/se.png differ diff --git a/lib/flags/sg.png b/lib/flags/sg.png new file mode 100644 index 0000000..dd34d61 Binary files /dev/null and b/lib/flags/sg.png differ diff --git a/lib/flags/sh.png b/lib/flags/sh.png new file mode 100644 index 0000000..4b1d2a2 Binary files /dev/null and b/lib/flags/sh.png differ diff --git a/lib/flags/si.png b/lib/flags/si.png new file mode 100644 index 0000000..bb1476f Binary files /dev/null and b/lib/flags/si.png differ diff --git a/lib/flags/sj.png b/lib/flags/sj.png new file mode 100644 index 0000000..160b6b5 Binary files /dev/null and b/lib/flags/sj.png differ diff --git a/lib/flags/sk.png b/lib/flags/sk.png new file mode 100644 index 0000000..7ccbc82 Binary files /dev/null and b/lib/flags/sk.png differ diff --git a/lib/flags/sl.png b/lib/flags/sl.png new file mode 100644 index 0000000..12d812d Binary files /dev/null and b/lib/flags/sl.png differ diff --git a/lib/flags/sm.png b/lib/flags/sm.png new file mode 100644 index 0000000..3df2fdc Binary files /dev/null and b/lib/flags/sm.png differ diff --git a/lib/flags/sn.png b/lib/flags/sn.png new file mode 100644 index 0000000..eabb71d Binary files /dev/null and b/lib/flags/sn.png differ diff --git a/lib/flags/so.png b/lib/flags/so.png new file mode 100644 index 0000000..4a1ea4b Binary files /dev/null and b/lib/flags/so.png differ diff --git a/lib/flags/sp.png b/lib/flags/sp.png new file mode 100644 index 0000000..c2de2d7 Binary files /dev/null and b/lib/flags/sp.png differ diff --git a/lib/flags/sr.png b/lib/flags/sr.png new file mode 100644 index 0000000..5eff927 Binary files /dev/null and b/lib/flags/sr.png differ diff --git a/lib/flags/st.png b/lib/flags/st.png new file mode 100644 index 0000000..2978557 Binary files /dev/null and b/lib/flags/st.png differ diff --git a/lib/flags/sv.png b/lib/flags/sv.png new file mode 100644 index 0000000..2498799 Binary files /dev/null and b/lib/flags/sv.png differ diff --git a/lib/flags/sy.png b/lib/flags/sy.png new file mode 100644 index 0000000..f5ce30d Binary files /dev/null and b/lib/flags/sy.png differ diff --git a/lib/flags/sz.png b/lib/flags/sz.png new file mode 100644 index 0000000..914ee86 Binary files /dev/null and b/lib/flags/sz.png differ diff --git a/lib/flags/tc.png b/lib/flags/tc.png new file mode 100644 index 0000000..8fc1156 Binary files /dev/null and b/lib/flags/tc.png differ diff --git a/lib/flags/td.png b/lib/flags/td.png new file mode 100644 index 0000000..667f21f Binary files /dev/null and b/lib/flags/td.png differ diff --git a/lib/flags/tf.png b/lib/flags/tf.png new file mode 100644 index 0000000..80529a4 Binary files /dev/null and b/lib/flags/tf.png differ diff --git a/lib/flags/tg.png b/lib/flags/tg.png new file mode 100644 index 0000000..3aa00ad Binary files /dev/null and b/lib/flags/tg.png differ diff --git a/lib/flags/th.png b/lib/flags/th.png new file mode 100644 index 0000000..dd8ba91 Binary files /dev/null and b/lib/flags/th.png differ diff --git a/lib/flags/tj.png b/lib/flags/tj.png new file mode 100644 index 0000000..617bf64 Binary files /dev/null and b/lib/flags/tj.png differ diff --git a/lib/flags/tk.png b/lib/flags/tk.png new file mode 100644 index 0000000..67b8c8c Binary files /dev/null and b/lib/flags/tk.png differ diff --git a/lib/flags/tl.png b/lib/flags/tl.png new file mode 100644 index 0000000..77da181 Binary files /dev/null and b/lib/flags/tl.png differ diff --git a/lib/flags/tm.png b/lib/flags/tm.png new file mode 100644 index 0000000..828020e Binary files /dev/null and b/lib/flags/tm.png differ diff --git a/lib/flags/tn.png b/lib/flags/tn.png new file mode 100644 index 0000000..183cdd3 Binary files /dev/null and b/lib/flags/tn.png differ diff --git a/lib/flags/to.png b/lib/flags/to.png new file mode 100644 index 0000000..f89b8ba Binary files /dev/null and b/lib/flags/to.png differ diff --git a/lib/flags/tr.png b/lib/flags/tr.png new file mode 100644 index 0000000..be32f77 Binary files /dev/null and b/lib/flags/tr.png differ diff --git a/lib/flags/tt.png b/lib/flags/tt.png new file mode 100644 index 0000000..2a11c1e Binary files /dev/null and b/lib/flags/tt.png differ diff --git a/lib/flags/tv.png b/lib/flags/tv.png new file mode 100644 index 0000000..28274c5 Binary files /dev/null and b/lib/flags/tv.png differ diff --git a/lib/flags/tw.png b/lib/flags/tw.png new file mode 100644 index 0000000..f31c654 Binary files /dev/null and b/lib/flags/tw.png differ diff --git a/lib/flags/tz.png b/lib/flags/tz.png new file mode 100644 index 0000000..c00ff79 Binary files /dev/null and b/lib/flags/tz.png differ diff --git a/lib/flags/ua.png b/lib/flags/ua.png new file mode 100644 index 0000000..09563a2 Binary files /dev/null and b/lib/flags/ua.png differ diff --git a/lib/flags/ug.png b/lib/flags/ug.png new file mode 100644 index 0000000..33f4aff Binary files /dev/null and b/lib/flags/ug.png differ diff --git a/lib/flags/um.png b/lib/flags/um.png new file mode 100644 index 0000000..c1dd965 Binary files /dev/null and b/lib/flags/um.png differ diff --git a/lib/flags/uy.png b/lib/flags/uy.png new file mode 100644 index 0000000..31d948a Binary files /dev/null and b/lib/flags/uy.png differ diff --git a/lib/flags/uz.png b/lib/flags/uz.png new file mode 100644 index 0000000..fef5dc1 Binary files /dev/null and b/lib/flags/uz.png differ diff --git a/lib/flags/va.png b/lib/flags/va.png new file mode 100644 index 0000000..b31eaf2 Binary files /dev/null and b/lib/flags/va.png differ diff --git a/lib/flags/vc.png b/lib/flags/vc.png new file mode 100644 index 0000000..8fa17b0 Binary files /dev/null and b/lib/flags/vc.png differ diff --git a/lib/flags/ve.png b/lib/flags/ve.png new file mode 100644 index 0000000..00c90f9 Binary files /dev/null and b/lib/flags/ve.png differ diff --git a/lib/flags/vg.png b/lib/flags/vg.png new file mode 100644 index 0000000..4156907 Binary files /dev/null and b/lib/flags/vg.png differ diff --git a/lib/flags/vi.png b/lib/flags/vi.png new file mode 100644 index 0000000..ed26915 Binary files /dev/null and b/lib/flags/vi.png differ diff --git a/lib/flags/vn.png b/lib/flags/vn.png new file mode 100644 index 0000000..ec7cd48 Binary files /dev/null and b/lib/flags/vn.png differ diff --git a/lib/flags/vu.png b/lib/flags/vu.png new file mode 100644 index 0000000..b3397bc Binary files /dev/null and b/lib/flags/vu.png differ diff --git a/lib/flags/wales.png b/lib/flags/wales.png new file mode 100644 index 0000000..e0d7cee Binary files /dev/null and b/lib/flags/wales.png differ diff --git a/lib/flags/wf.png b/lib/flags/wf.png new file mode 100644 index 0000000..9f95587 Binary files /dev/null and b/lib/flags/wf.png differ diff --git a/lib/flags/ws.png b/lib/flags/ws.png new file mode 100644 index 0000000..c169508 Binary files /dev/null and b/lib/flags/ws.png differ diff --git a/lib/flags/ye.png b/lib/flags/ye.png new file mode 100644 index 0000000..468dfad Binary files /dev/null and b/lib/flags/ye.png differ diff --git a/lib/flags/yt.png b/lib/flags/yt.png new file mode 100644 index 0000000..c298f37 Binary files /dev/null and b/lib/flags/yt.png differ diff --git a/lib/flags/za.png b/lib/flags/za.png new file mode 100644 index 0000000..57c58e2 Binary files /dev/null and b/lib/flags/za.png differ diff --git a/lib/flags/zm.png b/lib/flags/zm.png new file mode 100644 index 0000000..c25b07b Binary files /dev/null and b/lib/flags/zm.png differ diff --git a/lib/flags/zw.png b/lib/flags/zw.png new file mode 100644 index 0000000..53c9725 Binary files /dev/null and b/lib/flags/zw.png differ diff --git a/lib/kcaptcha/fonts/.htaccess b/lib/kcaptcha/fonts/.htaccess new file mode 100644 index 0000000..53b781b --- /dev/null +++ b/lib/kcaptcha/fonts/.htaccess @@ -0,0 +1,4 @@ + + Order allow,deny + Deny from all + \ No newline at end of file diff --git a/lib/kcaptcha/fonts/palatino_linotype_bold.png b/lib/kcaptcha/fonts/palatino_linotype_bold.png new file mode 100644 index 0000000..76e653a Binary files /dev/null and b/lib/kcaptcha/fonts/palatino_linotype_bold.png differ diff --git a/lib/kcaptcha/fonts/perpetua_bold.png b/lib/kcaptcha/fonts/perpetua_bold.png new file mode 100644 index 0000000..861ea50 Binary files /dev/null and b/lib/kcaptcha/fonts/perpetua_bold.png differ diff --git a/lib/kcaptcha/fonts/times_bold.png b/lib/kcaptcha/fonts/times_bold.png new file mode 100644 index 0000000..4048121 Binary files /dev/null and b/lib/kcaptcha/fonts/times_bold.png differ diff --git a/lib/kcaptcha/form_example.php b/lib/kcaptcha/form_example.php new file mode 100644 index 0000000..d38096b --- /dev/null +++ b/lib/kcaptcha/form_example.php @@ -0,0 +1,19 @@ + + +

      Enter text shown below:

      +

      +

      +

      + +0){ + if(isset($_SESSION['captcha_keystring']) && $_SESSION['captcha_keystring'] === $_POST['keystring']){ + echo "Correct"; + }else{ + echo "Wrong"; + } +} +unset($_SESSION['captcha_keystring']); +?> \ No newline at end of file diff --git a/lib/kcaptcha/index.php b/lib/kcaptcha/index.php new file mode 100644 index 0000000..00ffb0d --- /dev/null +++ b/lib/kcaptcha/index.php @@ -0,0 +1,15 @@ +getKeyString(); +} + +?> \ No newline at end of file diff --git a/lib/kcaptcha/kcaptcha.php b/lib/kcaptcha/kcaptcha.php new file mode 100644 index 0000000..1e2fa37 --- /dev/null +++ b/lib/kcaptcha/kcaptcha.php @@ -0,0 +1,240 @@ +keystring=''; + for($i=0;$i<$length;$i++){ + $this->keystring.=$allowed_symbols{mt_rand(0,strlen($allowed_symbols)-1)}; + } + if(!preg_match('/cp|cb|ck|c6|c9|rn|rm|mm|co|do|cl|db|qp|qb|dp|ww/', $this->keystring)) break; + } + + $font_file=$fonts[mt_rand(0, count($fonts)-1)]; + $font=imagecreatefrompng($font_file); + imagealphablending($font, true); + + $fontfile_width=imagesx($font); + $fontfile_height=imagesy($font)-1; + + $font_metrics=array(); + $symbol=0; + $reading_symbol=false; + + // loading font + for($i=0;$i<$fontfile_width && $symbol<$alphabet_length;$i++){ + $transparent = (imagecolorat($font, $i, 0) >> 24) == 127; + + if(!$reading_symbol && !$transparent){ + $font_metrics[$alphabet{$symbol}]=array('start'=>$i); + $reading_symbol=true; + continue; + } + + if($reading_symbol && $transparent){ + $font_metrics[$alphabet{$symbol}]['end']=$i; + $reading_symbol=false; + $symbol++; + continue; + } + } + + $img=imagecreatetruecolor($width, $height); + imagealphablending($img, true); + $white=imagecolorallocate($img, 255, 255, 255); + $black=imagecolorallocate($img, 0, 0, 0); + + imagefilledrectangle($img, 0, 0, $width-1, $height-1, $white); + + // draw text + $x=1; + $odd=mt_rand(0,1); + if($odd==0) $odd=-1; + for($i=0;$i<$length;$i++){ + $m=$font_metrics[$this->keystring{$i}]; + + $y=(($i%2)*$fluctuation_amplitude - $fluctuation_amplitude/2)*$odd + + mt_rand(-round($fluctuation_amplitude/3), round($fluctuation_amplitude/3)) + + ($height-$fontfile_height)/2; + + if($no_spaces){ + $shift=0; + if($i>0){ + $shift=10000; + for($sy=3;$sy<$fontfile_height-10;$sy+=1){ + for($sx=$m['start']-1;$sx<$m['end'];$sx+=1){ + $rgb=imagecolorat($font, $sx, $sy); + $opacity=$rgb>>24; + if($opacity<127){ + $left=$sx-$m['start']+$x; + $py=$sy+$y; + if($py>$height) break; + for($px=min($left,$width-1);$px>$left-200 && $px>=0;$px-=1){ + $color=imagecolorat($img, $px, $py) & 0xff; + if($color+$opacity<170){ // 170 - threshold + if($shift>$left-$px){ + $shift=$left-$px; + } + break; + } + } + break; + } + } + } + if($shift==10000){ + $shift=mt_rand(4,6); + } + + } + }else{ + $shift=1; + } + imagecopy($img, $font, $x-$shift, $y, $m['start'], 1, $m['end']-$m['start'], $fontfile_height); + $x+=$m['end']-$m['start']-$shift; + } + }while($x>=$width-10); // while not fit in canvas + + //noise + $white=imagecolorallocate($font, 255, 255, 255); + $black=imagecolorallocate($font, 0, 0, 0); + for($i=0;$i<(($height-30)*$x)*$white_noise_density;$i++){ + imagesetpixel($img, mt_rand(0, $x-1), mt_rand(10, $height-15), $white); + } + for($i=0;$i<(($height-30)*$x)*$black_noise_density;$i++){ + imagesetpixel($img, mt_rand(0, $x-1), mt_rand(10, $height-15), $black); + } + + + $center=$x/2; + + // credits. To remove, see configuration file + $img2=imagecreatetruecolor($width, $height+($show_credits?12:0)); + $foreground=imagecolorallocate($img2, $foreground_color[0], $foreground_color[1], $foreground_color[2]); + $background=imagecolorallocate($img2, $background_color[0], $background_color[1], $background_color[2]); + imagefilledrectangle($img2, 0, 0, $width-1, $height-1, $background); + imagefilledrectangle($img2, 0, $height, $width-1, $height+12, $foreground); + $credits=empty($credits)?$_SERVER['HTTP_HOST']:$credits; + imagestring($img2, 2, $width/2-imagefontwidth(2)*strlen($credits)/2, $height-2, $credits, $background); + + // periods + $rand1=mt_rand(750000,1200000)/10000000; + $rand2=mt_rand(750000,1200000)/10000000; + $rand3=mt_rand(750000,1200000)/10000000; + $rand4=mt_rand(750000,1200000)/10000000; + // phases + $rand5=mt_rand(0,31415926)/10000000; + $rand6=mt_rand(0,31415926)/10000000; + $rand7=mt_rand(0,31415926)/10000000; + $rand8=mt_rand(0,31415926)/10000000; + // amplitudes + $rand9=mt_rand(330,420)/110; + $rand10=mt_rand(330,450)/100; + + //wave distortion + + for($x=0;$x<$width;$x++){ + for($y=0;$y<$height;$y++){ + $sx=$x+(sin($x*$rand1+$rand5)+sin($y*$rand3+$rand6))*$rand9-$width/2+$center+1; + $sy=$y+(sin($x*$rand2+$rand7)+sin($y*$rand4+$rand8))*$rand10; + + if($sx<0 || $sy<0 || $sx>=$width-1 || $sy>=$height-1){ + continue; + }else{ + $color=imagecolorat($img, $sx, $sy) & 0xFF; + $color_x=imagecolorat($img, $sx+1, $sy) & 0xFF; + $color_y=imagecolorat($img, $sx, $sy+1) & 0xFF; + $color_xy=imagecolorat($img, $sx+1, $sy+1) & 0xFF; + } + + if($color==255 && $color_x==255 && $color_y==255 && $color_xy==255){ + continue; + }else if($color==0 && $color_x==0 && $color_y==0 && $color_xy==0){ + $newred=$foreground_color[0]; + $newgreen=$foreground_color[1]; + $newblue=$foreground_color[2]; + }else{ + $frsx=$sx-floor($sx); + $frsy=$sy-floor($sy); + $frsx1=1-$frsx; + $frsy1=1-$frsy; + + $newcolor=( + $color*$frsx1*$frsy1+ + $color_x*$frsx*$frsy1+ + $color_y*$frsx1*$frsy+ + $color_xy*$frsx*$frsy); + + if($newcolor>255) $newcolor=255; + $newcolor=$newcolor/255; + $newcolor0=1-$newcolor; + + $newred=$newcolor0*$foreground_color[0]+$newcolor*$background_color[0]; + $newgreen=$newcolor0*$foreground_color[1]+$newcolor*$background_color[1]; + $newblue=$newcolor0*$foreground_color[2]+$newcolor*$background_color[2]; + } + + imagesetpixel($img2, $x, $y, imagecolorallocate($img2, $newred, $newgreen, $newblue)); + } + } + + header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); + header('Cache-Control: no-store, no-cache, must-revalidate'); + header('Cache-Control: post-check=0, pre-check=0', FALSE); + header('Pragma: no-cache'); + if(function_exists("imagejpeg")){ + header("Content-Type: image/jpeg"); + imagejpeg($img2, null, $jpeg_quality); + }else if(function_exists("imagegif")){ + header("Content-Type: image/gif"); + imagegif($img2); + }else if(function_exists("imagepng")){ + header("Content-Type: image/x-png"); + imagepng($img2); + } + } + + // returns keystring + function getKeyString(){ + return $this->keystring; + } +} + +?> \ No newline at end of file diff --git a/lib/kcaptcha/kcaptcha_config.php b/lib/kcaptcha/kcaptcha_config.php new file mode 100644 index 0000000..e7f3935 --- /dev/null +++ b/lib/kcaptcha/kcaptcha_config.php @@ -0,0 +1,47 @@ + \ No newline at end of file diff --git a/lib/kcaptcha/util/font_preparer.php b/lib/kcaptcha/util/font_preparer.php new file mode 100644 index 0000000..1fb9344 --- /dev/null +++ b/lib/kcaptcha/util/font_preparer.php @@ -0,0 +1,42 @@ +>24; + if($opacity!=127){ + $space=false; + } + $column_opacity+=127-$opacity; + } + if(!$space){ + imageline($img,$x,0,$x,0,$column_opacity<200?$gray:$black); + } + } + imagepng($img,'../fonts/'.$file); + } + closedir($handle); +} +?> diff --git a/lib/mobile_detect/Mobile_Detect.php b/lib/mobile_detect/Mobile_Detect.php new file mode 100644 index 0000000..c65b381 --- /dev/null +++ b/lib/mobile_detect/Mobile_Detect.php @@ -0,0 +1,1473 @@ + + * @author Nick Ilyin + * Original author: Victor Stanciu + * + * @version 2.8.33 + */ +class Mobile_Detect +{ + /** + * Mobile detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_MOBILE = 'mobile'; + + /** + * Extended detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_EXTENDED = 'extended'; + + /** + * A frequently used regular expression to extract version #s. + * + * @deprecated since version 2.6.9 + */ + const VER = '([\w._\+]+)'; + + /** + * Top-level device. + */ + const MOBILE_GRADE_A = 'A'; + + /** + * Mid-level device. + */ + const MOBILE_GRADE_B = 'B'; + + /** + * Low-level device. + */ + const MOBILE_GRADE_C = 'C'; + + /** + * Stores the version number of the current release. + */ + const VERSION = '2.8.33'; + + /** + * A type for the version() method indicating a string return value. + */ + const VERSION_TYPE_STRING = 'text'; + + /** + * A type for the version() method indicating a float return value. + */ + const VERSION_TYPE_FLOAT = 'float'; + + /** + * A cache for resolved matches + * @var array + */ + protected $cache = array(); + + /** + * The User-Agent HTTP header is stored in here. + * @var string + */ + protected $userAgent = null; + + /** + * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE. + * @var array + */ + protected $httpHeaders = array(); + + /** + * CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer. + * @var array + */ + protected $cloudfrontHeaders = array(); + + /** + * The matching Regex. + * This is good for debug. + * @var string + */ + protected $matchingRegex = null; + + /** + * The matches extracted from the regex expression. + * This is good for debug. + * + * @var string + */ + protected $matchesArray = null; + + /** + * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED. + * + * @deprecated since version 2.6.9 + * + * @var string + */ + protected $detectionType = self::DETECTION_TYPE_MOBILE; + + /** + * HTTP headers that trigger the 'isMobile' detection + * to be true. + * + * @var array + */ + protected static $mobileHeaders = array( + + 'HTTP_ACCEPT' => array('matches' => array( + // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ + 'application/x-obml2d', + // BlackBerry devices. + 'application/vnd.rim.html', + 'text/vnd.wap.wml', + 'application/vnd.wap.xhtml+xml' + )), + 'HTTP_X_WAP_PROFILE' => null, + 'HTTP_X_WAP_CLIENTID' => null, + 'HTTP_WAP_CONNECTION' => null, + 'HTTP_PROFILE' => null, + // Reported by Opera on Nokia devices (eg. C3). + 'HTTP_X_OPERAMINI_PHONE_UA' => null, + 'HTTP_X_NOKIA_GATEWAY_ID' => null, + 'HTTP_X_ORANGE_ID' => null, + 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null, + 'HTTP_X_HUAWEI_USERID' => null, + // Reported by Windows Smartphones. + 'HTTP_UA_OS' => null, + // Reported by Verizon, Vodafone proxy system. + 'HTTP_X_MOBILE_GATEWAY' => null, + // Seen this on HTC Sensation. SensationXE_Beats_Z715e. + 'HTTP_X_ATT_DEVICEID' => null, + // Seen this on a HTC. + 'HTTP_UA_CPU' => array('matches' => array('ARM')), + ); + + /** + * List of mobile devices (phones). + * + * @var array + */ + protected static $phoneDevices = array( + 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes + 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+', + 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel', + 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6', + // @todo: Is 'Dell Streak' a tablet or a phone? ;) + 'Dell' => 'Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', + 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b|XT1068|XT1092|XT1052', + 'Samsung' => '\bSamsung\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F', + 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)', + 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533', + 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile', + 'NokiaLumia' => 'Lumia [0-9]{3,4}', + // http://www.micromaxinfo.com/mobiles/smartphones + // Added because the codes might conflict with Acer Tablets. + 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', + // @todo Complete the regex. + 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; + 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;) + // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH) + // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android. + 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', + // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. + 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', + // http://fr.wikomobile.com + 'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM', + 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', + // Added simvalley mobile just for fun. They have some interesting devices. + // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html + 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', + // Wolfgang - a brand that is sold by Aldi supermarkets. + // http://www.wolfgangmobile.com/ + 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q', + 'Alcatel' => 'Alcatel', + 'Nintendo' => 'Nintendo (3DS|Switch)', + // http://en.wikipedia.org/wiki/Amoi + 'Amoi' => 'Amoi', + // http://en.wikipedia.org/wiki/INQ + 'INQ' => 'INQ', + // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039 + 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser', + ); + + /** + * List of tablet devices. + * + * @var array + */ + protected static $tabletDevices = array( + // @todo: check for mobile friendly emails topic. + 'iPad' => 'iPad|iPad.*Mobile', + // Removed |^.*Android.*Nexus(?!(?:Mobile).)*$ + // @see #442 + // @todo Merge NexusTablet into GoogleTablet. + 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)', + // https://en.wikipedia.org/wiki/Pixel_C + 'GoogleTablet' => 'Android.*Pixel C', + 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone. + // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html + 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)', + // Only the Surface tablets with Windows RT are considered mobile. + // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx + 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)', + // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT + 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10', + // Watch out for PadFone, see #132. + // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/ + 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b', + 'BlackBerryTablet' => 'PlayBook|RIM Tablet', + 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410', + 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', + 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2', + // http://www.acer.ro/ac/ro/RO/content/drivers + // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer) + // http://us.acer.com/ac/en/US/content/group/tablets + // http://www.acer.de/ac/de/DE/content/models/tablets/ + // Can conflict with Micromax and Motorola phones codes. + 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30', + // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ + // http://us.toshiba.com/tablets/tablet-finder + // http://www.toshiba.co.jp/regza/tablet/ + 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO', + // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html + // http://www.lg.com/us/tablets + 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b', + 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', + // Prestigio Tablets http://www.prestigio.com/support + 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002', + // http://support.lenovo.com/en_GB/downloads/default.page?# + 'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304F|TB-X304L|TB-8703F|Tab2A7-10F|TB2-X30L', + // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets + 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7', + // http://www.yarvik.com/en/matrix/tablets/ + 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', + 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', + 'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2', + // http://www.intenso.de/kategorie_en.php?kategorie=33 + // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate + 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004', + // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/ + 'IRUTablet' => 'M702pro', + 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b', + // http://www.e-boda.ro/tablete-pc.html + 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)', + // http://www.allview.ro/produse/droseries/lista-tablete-pc/ + 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', + // http://wiki.archosfans.com/index.php?title=Main_Page + // @note Rewrite the regex format after we add more UAs. + 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', + // http://www.ainol.com/plugin.php?identifier=ainol&module=product + 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', + 'NokiaLumiaTablet' => 'Lumia 2520', + // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER + // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser + // http://www.sony.jp/support/tablet/ + 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712', + // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8 + 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b', + // db + http://www.cube-tablet.com/buy-products.html + 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT', + // http://www.cobyusa.com/?p=pcat&pcat_id=3001 + 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', + // http://www.match.net.cn/products.asp + 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10', + // http://www.msi.com/support + // @todo Research the Windows Tablets. + 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b', + // @todo http://www.kyoceramobile.com/support/drivers/ + // 'KyoceraTablet' => null, + // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/ + // 'IntextTablet' => null, + // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets) + // http://www.imp3.net/14/show.php?itemid=20454 + 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)', + // http://www.rock-chips.com/index.php?do=prod&pid=2 + 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A', + // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ + 'FlyTablet' => 'IQ310|Fly Vision', + // http://www.bqreaders.com/gb/tablets-prices-sale.html + 'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))|Maxwell.*Lite|Maxwell.*Plus', + // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 + // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) + 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09', + // Nec or Medias Tab + 'NecTablet' => '\bN-06D|\bN-08D', + // Pantech Tablets: http://www.pantechusa.com/phones/ + 'PantechTablet' => 'Pantech.*P4100', + // Broncho Tablets: http://www.broncho.cn/ (hard to find) + 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)', + // http://versusuk.com/support.html + 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b', + // http://www.zync.in/index.php/our-products/tablet-phablets + 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900', + // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ + 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA', + // https://www.nabitablet.com/ + 'NabiTablet' => 'Android.*\bNabi', + 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build', + // French Danew Tablets http://www.danew.com/produits-tablette.php + 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b', + // Texet Tablets and Readers http://www.texet.ru/tablet/ + 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE', + // Avoid detecting 'PLAYSTATION 3' as mobile. + 'PlaystationTablet' => 'Playstation.*(Portable|Vita)', + // http://www.trekstor.de/surftabs.html + 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab', + // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets + 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b', + // http://www.advandigital.com/index.php?link=content-product&jns=JP001 + // because of the short codenames we have to include whitespaces to reduce the possible conflicts. + 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ', + // http://www.danytech.com/category/tablet-pc + 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1', + // http://www.galapad.net/product.html + 'GalapadTablet' => 'Android.*\bG1\b(?!\))', + // http://www.micromaxinfo.com/tablet/funbook + 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b', + // http://www.karbonnmobiles.com/products_tablet.php + 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b', + // http://www.myallfine.com/Products.asp + 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide', + // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= + 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b', + // http://www.yonesnav.com/products/products.php + 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026', + // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 + // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html) + 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503', + // http://www.gloryunion.cn/products.asp + // http://www.allwinnertech.com/en/apply/mobile.html + // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB) + // @todo: Softwiner tablets? + // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions. + 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G + // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118 + 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10', + // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/ + // @todo: add more tests. + 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027', + // http://hclmetablet.com/India/index.php + 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync', + // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html + 'DPSTablet' => 'DPS Dream 9|DPS Dual 7', + // http://www.visture.com/index.asp + 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10', + // http://www.mijncresta.nl/tablet + 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989', + // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309 + 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b', + // Concorde tab + 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan', + // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/ + 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042', + // Modecom Tablets - http://www.modecom.eu/tablets/portal/ + 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003', + // Vonino Tablets - http://www.vonino.eu/tablets + 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b', + // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0 + 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1', + // Storex Tablets - http://storex.fr/espace_client/support.html + // @note: no need to add all the tablet codes since they are guided by the first regex. + 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', + // Generic Vodafone tablets. + 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497', + // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb + // Aka: http://www.essentielb.fr/ + 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', + // Ross & Moor - http://ross-moor.ru/ + 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711', + // i-mobile http://product.i-mobilephone.com/Mobile_Device + 'iMobileTablet' => 'i-mobile i-note', + // http://www.tolino.de/de/vergleichen/ + 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine', + // AudioSonic - a Kmart brand + // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1 + 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b', + // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/ + // @todo: add them gradually to avoid conflicts. + 'AMPETablet' => 'Android.* A78 ', + // Skk Mobile - http://skkmobile.com.ph/product_tablets.php + 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)', + // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 + 'TecnoTablet' => 'TECNO P9|TECNO DP8D', + // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 + 'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', + // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ + 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', + // http://www.intracon.eu/tablet + 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10', + // http://www.xoro.de/produkte/ + // @note: Might be the same brand with 'Simply tablets' + 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151', + // http://www1.viewsonic.com/products/computing/tablets/ + 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a', + // https://www.verizonwireless.com/tablets/verizon/ + 'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1', + // http://www.odys.de/web/internet-tablet_en.html + 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10', + // http://www.captiva-power.de/products.html#tablets-en + 'CaptivaTablet' => 'CAPTIVA PAD', + // IconBIT - http://www.iconbit.com/products/tablets/ + 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', + // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63 + 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi', + // Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price + 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+|V10 \b4G\b', + 'JaytechTablet' => 'TPC-PA762', + 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010', + // http://www.digma.ru/support/download/ + // @todo: Ebooks also (if requested) + 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b', + // http://www.evolioshop.com/ro/tablete-pc.html + // http://www.evolio.ro/support/downloads_static.html?cat=2 + // @todo: Research some more + 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b', + // @todo http://www.lavamobiles.com/tablets-data-cards + 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b', + // http://www.breezetablet.com/ + 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712', + // http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/ + 'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010', + // https://www.celkonmobiles.com/?_a=categoryphones&sid=2 + 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b', + // http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab + 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b', + 'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA', + // http://www.mi.com/en + 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b', + // http://www.nbru.cn/index.html + 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One', + // http://navroad.com/products/produkty/tablety/ + // http://navroad.com/products/produkty/tablety/ + 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI', + // http://leader-online.com/new_site/product-category/tablets/ + // http://www.leader-online.net.au/List/Tablet + 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100', + // http://www.datawind.com/ubislate/ + 'UbislateTablet' => 'UbiSlate[\s]?7C', + // http://www.pocketbook-int.com/ru/support + 'PocketBookTablet' => 'Pocketbook', + // http://www.kocaso.com/product_tablet.html + 'KocasoTablet' => '\b(TB-1207)\b', + // http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm + 'HisenseTablet' => '\b(F5281|E2371)\b', + // http://www.tesco.com/direct/hudl/ + 'Hudl' => 'Hudl HT7S3|Hudl 2', + // http://www.telstra.com.au/home-phone/thub-2/ + 'TelstraTablet' => 'T-Hub2', + 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107' + ); + + /** + * List of mobile Operating Systems. + * + * @var array + */ + protected static $operatingSystems = array( + 'AndroidOS' => 'Android', + 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', + 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', + 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', + // @reference: http://en.wikipedia.org/wiki/Windows_Mobile + 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;', + // @reference: http://en.wikipedia.org/wiki/Windows_Phone + // http://wifeng.cn/?r=blog&a=view&id=106 + // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx + // http://msdn.microsoft.com/library/ms537503.aspx + // https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx + 'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', + 'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia', + // http://en.wikipedia.org/wiki/MeeGo + // @todo: research MeeGo in UAs + 'MeeGoOS' => 'MeeGo', + // http://en.wikipedia.org/wiki/Maemo + // @todo: research Maemo in UAs + 'MaemoOS' => 'Maemo', + 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 + 'webOS' => 'webOS|hpwOS', + 'badaOS' => '\bBada\b', + 'BREWOS' => 'BREW', + ); + + /** + * List of mobile User Agents. + * + * IMPORTANT: This is a list of only mobile browsers. + * Mobile Detect 2.x supports only mobile browsers, + * it was never designed to detect all browsers. + * The change will come in 2017 in the 3.x release for PHP7. + * + * @var array + */ + protected static $browsers = array( + //'Vivaldi' => 'Vivaldi', + // @reference: https://developers.google.com/chrome/mobile/docs/user-agent + 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?', + 'Dolfin' => '\bDolfin\b', + 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+', + 'Skyfire' => 'Skyfire', + 'Edge' => 'Mobile Safari/[.0-9]* Edge', + 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ + 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS', + 'Bolt' => 'bolt', + 'TeaShark' => 'teashark', + 'Blazer' => 'Blazer', + // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 + 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari', + // http://en.wikipedia.org/wiki/Midori_(web_browser) + //'Midori' => 'midori', + //'Tizen' => 'Tizen', + 'WeChat' => '\bMicroMessenger\b', + 'UCBrowser' => 'UC.*Browser|UCWEB', + 'baiduboxapp' => 'baiduboxapp', + 'baidubrowser' => 'baidubrowser', + // https://github.com/serbanghita/Mobile-Detect/issues/7 + 'DiigoBrowser' => 'DiigoBrowser', + // http://www.puffinbrowser.com/index.php + 'Puffin' => 'Puffin', + // http://mercury-browser.com/index.html + 'Mercury' => '\bMercury\b', + // http://en.wikipedia.org/wiki/Obigo_Browser + 'ObigoBrowser' => 'Obigo', + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NF-Browser', + // @reference: http://en.wikipedia.org/wiki/Minimo + // http://en.wikipedia.org/wiki/Vision_Mobile_Browser + 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', + // @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser) + 'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon', + ); + + /** + * Utilities. + * + * @var array + */ + protected static $utilities = array( + // Experimental. When a mobile device wants to switch to 'Desktop Mode'. + // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ + // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 + // https://developers.facebook.com/docs/sharing/best-practices + 'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom', + 'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2', + 'DesktopMode' => 'WPDesktop', + 'TV' => 'SonyDTV|HbbTV', // experimental + 'WebKit' => '(webkit)[ /]([\w.]+)', + // @todo: Include JXD consoles. + 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\b', + 'Watch' => 'SM-V700', + ); + + /** + * All possible HTTP headers that represent the + * User-Agent string. + * + * @var array + */ + protected static $uaHttpHeaders = array( + // The default User-Agent string. + 'HTTP_USER_AGENT', + // Header can occur on devices using Opera Mini. + 'HTTP_X_OPERAMINI_PHONE_UA', + // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ + 'HTTP_X_DEVICE_USER_AGENT', + 'HTTP_X_ORIGINAL_USER_AGENT', + 'HTTP_X_SKYFIRE_PHONE', + 'HTTP_X_BOLT_PHONE_UA', + 'HTTP_DEVICE_STOCK_UA', + 'HTTP_X_UCBROWSER_DEVICE_UA' + ); + + /** + * The individual segments that could exist in a User-Agent string. VER refers to the regular + * expression defined in the constant self::VER. + * + * @var array + */ + protected static $properties = array( + + // Build + 'Mobile' => 'Mobile/[VER]', + 'Build' => 'Build/[VER]', + 'Version' => 'Version/[VER]', + 'VendorID' => 'VendorID/[VER]', + + // Devices + 'iPad' => 'iPad.*CPU[a-z ]+[VER]', + 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', + 'iPod' => 'iPod.*CPU[a-z ]+[VER]', + //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), + 'Kindle' => 'Kindle/[VER]', + + // Browser + 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), + 'Coast' => array('Coast/[VER]'), + 'Dolfin' => 'Dolfin/[VER]', + // @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox + 'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'), + 'Fennec' => 'Fennec/[VER]', + // http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx + 'Edge' => 'Edge/[VER]', + 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'), + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NetFront/[VER]', + 'NokiaBrowser' => 'NokiaBrowser/[VER]', + 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ), + 'Opera Mini' => 'Opera Mini/[VER]', + 'Opera Mobi' => 'Version/[VER]', + 'UCBrowser' => array( 'UCWEB[VER]', 'UC.*Browser/[VER]' ), + 'MQQBrowser' => 'MQQBrowser/[VER]', + 'MicroMessenger' => 'MicroMessenger/[VER]', + 'baiduboxapp' => 'baiduboxapp/[VER]', + 'baidubrowser' => 'baidubrowser/[VER]', + 'SamsungBrowser' => 'SamsungBrowser/[VER]', + 'Iron' => 'Iron/[VER]', + // @note: Safari 7534.48.3 is actually Version 5.1. + // @note: On BlackBerry the Version is overwriten by the OS. + 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ), + 'Skyfire' => 'Skyfire/[VER]', + 'Tizen' => 'Tizen/[VER]', + 'Webkit' => 'webkit[ /][VER]', + 'PaleMoon' => 'PaleMoon/[VER]', + + // Engine + 'Gecko' => 'Gecko/[VER]', + 'Trident' => 'Trident/[VER]', + 'Presto' => 'Presto/[VER]', + 'Goanna' => 'Goanna/[VER]', + + // OS + 'iOS' => ' \bi?OS\b [VER][ ;]{1}', + 'Android' => 'Android [VER]', + 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), + 'BREW' => 'BREW [VER]', + 'Java' => 'Java/[VER]', + // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx + // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases + 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'), + 'Windows Phone' => 'Windows Phone [VER]', + 'Windows CE' => 'Windows CE/[VER]', + // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd + 'Windows NT' => 'Windows NT [VER]', + 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'), + 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'), + ); + + /** + * Construct an instance of this class. + * + * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored. + * If left empty, will use the global _SERVER['HTTP_*'] vars instead. + * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT + * from the $headers array instead. + */ + public function __construct( + array $headers = null, + $userAgent = null + ) { + $this->setHttpHeaders($headers); + $this->setUserAgent($userAgent); + } + + /** + * Get the current script version. + * This is useful for the demo.php file, + * so people can check on what version they are testing + * for mobile devices. + * + * @return string The version number in semantic version format. + */ + public static function getScriptVersion() + { + return self::VERSION; + } + + /** + * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. + * + * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract + * the headers. The default null is left for backwards compatibility. + */ + public function setHttpHeaders($httpHeaders = null) + { + // use global _SERVER if $httpHeaders aren't defined + if (!is_array($httpHeaders) || !count($httpHeaders)) { + $httpHeaders = $_SERVER; + } + + // clear existing headers + $this->httpHeaders = array(); + + // Only save HTTP headers. In PHP land, that means only _SERVER vars that + // start with HTTP_. + foreach ($httpHeaders as $key => $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $this->httpHeaders[$key] = $value; + } + } + + // In case we're dealing with CloudFront, we need to know. + $this->setCfHeaders($httpHeaders); + } + + /** + * Retrieves the HTTP headers. + * + * @return array + */ + public function getHttpHeaders() + { + return $this->httpHeaders; + } + + /** + * Retrieves a particular header. If it doesn't exist, no exception/error is caused. + * Simply null is returned. + * + * @param string $header The name of the header to retrieve. Can be HTTP compliant such as + * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the + * all-caps, HTTP_ prefixed, underscore seperated awesomeness. + * + * @return string|null The value of the header. + */ + public function getHttpHeader($header) + { + // are we using PHP-flavored headers? + if (strpos($header, '_') === false) { + $header = str_replace('-', '_', $header); + $header = strtoupper($header); + } + + // test the alternate, too + $altHeader = 'HTTP_' . $header; + + //Test both the regular and the HTTP_ prefix + if (isset($this->httpHeaders[$header])) { + return $this->httpHeaders[$header]; + } elseif (isset($this->httpHeaders[$altHeader])) { + return $this->httpHeaders[$altHeader]; + } + + return null; + } + + public function getMobileHeaders() + { + return self::$mobileHeaders; + } + + /** + * Get all possible HTTP headers that + * can contain the User-Agent string. + * + * @return array List of HTTP headers. + */ + public function getUaHttpHeaders() + { + return self::$uaHttpHeaders; + } + + + /** + * Set CloudFront headers + * http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device + * + * @param array $cfHeaders List of HTTP headers + * + * @return boolean If there were CloudFront headers to be set + */ + public function setCfHeaders($cfHeaders = null) { + // use global _SERVER if $cfHeaders aren't defined + if (!is_array($cfHeaders) || !count($cfHeaders)) { + $cfHeaders = $_SERVER; + } + + // clear existing headers + $this->cloudfrontHeaders = array(); + + // Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that + // start with cloudfront-. + $response = false; + foreach ($cfHeaders as $key => $value) { + if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') { + $this->cloudfrontHeaders[strtoupper($key)] = $value; + $response = true; + } + } + + return $response; + } + + /** + * Retrieves the cloudfront headers. + * + * @return array + */ + public function getCfHeaders() + { + return $this->cloudfrontHeaders; + } + + /** + * @param string $userAgent + * @return string + */ + private function prepareUserAgent($userAgent) { + $userAgent = trim($userAgent); + $userAgent = substr($userAgent, 0, 500); + return $userAgent; + } + + /** + * Set the User-Agent to be used. + * + * @param string $userAgent The user agent string to set. + * + * @return string|null + */ + public function setUserAgent($userAgent = null) + { + // Invalidate cache due to #375 + $this->cache = array(); + + if (false === empty($userAgent)) { + return $this->userAgent = $this->prepareUserAgent($userAgent); + } else { + $this->userAgent = null; + foreach ($this->getUaHttpHeaders() as $altHeader) { + if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) + $this->userAgent .= $this->httpHeaders[$altHeader] . " "; + } + } + + if (!empty($this->userAgent)) { + return $this->userAgent = $this->prepareUserAgent($this->userAgent); + } + } + + if (count($this->getCfHeaders()) > 0) { + return $this->userAgent = 'Amazon CloudFront'; + } + return $this->userAgent = null; + } + + /** + * Retrieve the User-Agent. + * + * @return string|null The user agent if it's set. + */ + public function getUserAgent() + { + return $this->userAgent; + } + + /** + * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or + * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set. + * + * @deprecated since version 2.6.9 + * + * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default + * parameter is null which will default to self::DETECTION_TYPE_MOBILE. + */ + public function setDetectionType($type = null) + { + if ($type === null) { + $type = self::DETECTION_TYPE_MOBILE; + } + + if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) { + return; + } + + $this->detectionType = $type; + } + + public function getMatchingRegex() + { + return $this->matchingRegex; + } + + public function getMatchesArray() + { + return $this->matchesArray; + } + + /** + * Retrieve the list of known phone devices. + * + * @return array List of phone devices. + */ + public static function getPhoneDevices() + { + return self::$phoneDevices; + } + + /** + * Retrieve the list of known tablet devices. + * + * @return array List of tablet devices. + */ + public static function getTabletDevices() + { + return self::$tabletDevices; + } + + /** + * Alias for getBrowsers() method. + * + * @return array List of user agents. + */ + public static function getUserAgents() + { + return self::getBrowsers(); + } + + /** + * Retrieve the list of known browsers. Specifically, the user agents. + * + * @return array List of browsers / user agents. + */ + public static function getBrowsers() + { + return self::$browsers; + } + + /** + * Retrieve the list of known utilities. + * + * @return array List of utilities. + */ + public static function getUtilities() + { + return self::$utilities; + } + + /** + * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*(). + * + * @deprecated since version 2.6.9 + * + * @return array All the rules (but not extended). + */ + public static function getMobileDetectionRules() + { + static $rules; + + if (!$rules) { + $rules = array_merge( + self::$phoneDevices, + self::$tabletDevices, + self::$operatingSystems, + self::$browsers + ); + } + + return $rules; + + } + + /** + * Method gets the mobile detection rules + utilities. + * The reason this is separate is because utilities rules + * don't necessary imply mobile. This method is used inside + * the new $detect->is('stuff') method. + * + * @deprecated since version 2.6.9 + * + * @return array All the rules + extended. + */ + public function getMobileDetectionRulesExtended() + { + static $rules; + + if (!$rules) { + // Merge all rules together. + $rules = array_merge( + self::$phoneDevices, + self::$tabletDevices, + self::$operatingSystems, + self::$browsers, + self::$utilities + ); + } + + return $rules; + } + + /** + * Retrieve the current set of rules. + * + * @deprecated since version 2.6.9 + * + * @return array + */ + public function getRules() + { + if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) { + return self::getMobileDetectionRulesExtended(); + } else { + return self::getMobileDetectionRules(); + } + } + + /** + * Retrieve the list of mobile operating systems. + * + * @return array The list of mobile operating systems. + */ + public static function getOperatingSystems() + { + return self::$operatingSystems; + } + + /** + * Check the HTTP headers for signs of mobile. + * This is the fastest mobile check possible; it's used + * inside isMobile() method. + * + * @return bool + */ + public function checkHttpHeadersForMobile() + { + + foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { + if (isset($this->httpHeaders[$mobileHeader])) { + if (is_array($matchType['matches'])) { + foreach ($matchType['matches'] as $_match) { + if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) { + return true; + } + } + + return false; + } else { + return true; + } + } + } + + return false; + + } + + /** + * Magic overloading method. + * + * @method boolean is[...]() + * @param string $name + * @param array $arguments + * @return mixed + * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' + */ + public function __call($name, $arguments) + { + // make sure the name starts with 'is', otherwise + if (substr($name, 0, 2) !== 'is') { + throw new BadMethodCallException("No such method exists: $name"); + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + $key = substr($name, 2); + + return $this->matchUAAgainstKey($key); + } + + /** + * Find a detection rule that matches the current User-agent. + * + * @param null $userAgent deprecated + * @return boolean + */ + protected function matchDetectionRulesAgainstUA($userAgent = null) + { + // Begin general search. + foreach ($this->getRules() as $_regex) { + if (empty($_regex)) { + continue; + } + + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * Search for a certain key in the rules array. + * If the key is found then try to match the corresponding + * regex against the User-Agent. + * + * @param string $key + * + * @return boolean + */ + protected function matchUAAgainstKey($key) + { + // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. + $key = strtolower($key); + if (false === isset($this->cache[$key])) { + + // change the keys to lower case + $_rules = array_change_key_case($this->getRules()); + + if (false === empty($_rules[$key])) { + $this->cache[$key] = $this->match($_rules[$key]); + } + + if (false === isset($this->cache[$key])) { + $this->cache[$key] = false; + } + } + + return $this->cache[$key]; + } + + /** + * Check if the device is mobile. + * Returns true if any type of mobile device detected, including special ones + * @param null $userAgent deprecated + * @param null $httpHeaders deprecated + * @return bool + */ + public function isMobile($userAgent = null, $httpHeaders = null) + { + + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' + if ($this->getUserAgent() === 'Amazon CloudFront') { + $cfHeaders = $this->getCfHeaders(); + if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') { + return true; + } + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + if ($this->checkHttpHeadersForMobile()) { + return true; + } else { + return $this->matchDetectionRulesAgainstUA(); + } + + } + + /** + * Check if the device is a tablet. + * Return true if any type of tablet device is detected. + * + * @param string $userAgent deprecated + * @param array $httpHeaders deprecated + * @return bool + */ + public function isTablet($userAgent = null, $httpHeaders = null) + { + // Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront' + if ($this->getUserAgent() === 'Amazon CloudFront') { + $cfHeaders = $this->getCfHeaders(); + if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') { + return true; + } + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + foreach (self::$tabletDevices as $_regex) { + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * This method checks for a certain property in the + * userAgent. + * @todo: The httpHeaders part is not yet used. + * + * @param string $key + * @param string $userAgent deprecated + * @param string $httpHeaders deprecated + * @return bool|int|null + */ + public function is($key, $userAgent = null, $httpHeaders = null) + { + // Set the UA and HTTP headers only if needed (eg. batch mode). + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + $this->setDetectionType(self::DETECTION_TYPE_EXTENDED); + + return $this->matchUAAgainstKey($key); + } + + /** + * Some detection rules are relative (not standard), + * because of the diversity of devices, vendors and + * their conventions in representing the User-Agent or + * the HTTP headers. + * + * This method will be used to check custom regexes against + * the User-Agent string. + * + * @param $regex + * @param string $userAgent + * @return bool + * + * @todo: search in the HTTP headers too. + */ + public function match($regex, $userAgent = null) + { + $match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches); + // If positive match is found, store the results for debug. + if ($match) { + $this->matchingRegex = $regex; + $this->matchesArray = $matches; + } + + return $match; + } + + /** + * Get the properties array. + * + * @return array + */ + public static function getProperties() + { + return self::$properties; + } + + /** + * Prepare the version number. + * + * @todo Remove the error supression from str_replace() call. + * + * @param string $ver The string version, like "2.6.21.2152"; + * + * @return float + */ + public function prepareVersionNo($ver) + { + $ver = str_replace(array('_', ' ', '/'), '.', $ver); + $arrVer = explode('.', $ver, 2); + + if (isset($arrVer[1])) { + $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. + } + + return (float) implode('.', $arrVer); + } + + /** + * Check the version of the given property in the User-Agent. + * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) + * + * @param string $propertyName The name of the property. See self::getProperties() array + * keys for all possible properties. + * @param string $type Either self::VERSION_TYPE_STRING to get a string value or + * self::VERSION_TYPE_FLOAT indicating a float value. This parameter + * is optional and defaults to self::VERSION_TYPE_STRING. Passing an + * invalid parameter will default to the this type as well. + * + * @return string|float The version of the property we are trying to extract. + */ + public function version($propertyName, $type = self::VERSION_TYPE_STRING) + { + if (empty($propertyName)) { + return false; + } + + // set the $type to the default if we don't recognize the type + if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) { + $type = self::VERSION_TYPE_STRING; + } + + $properties = self::getProperties(); + + // Check if the property exists in the properties array. + if (true === isset($properties[$propertyName])) { + + // Prepare the pattern to be matched. + // Make sure we always deal with an array (string is converted). + $properties[$propertyName] = (array) $properties[$propertyName]; + + foreach ($properties[$propertyName] as $propertyMatchString) { + + $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); + + // Identify and extract the version. + preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match); + + if (false === empty($match[1])) { + $version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]); + + return $version; + } + + } + + } + + return false; + } + + /** + * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants. + * + * @return string One of the self::MOBILE_GRADE_* constants. + */ + public function mobileGrade() + { + $isMobile = $this->isMobile(); + + if ( + // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0) + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 || + + // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) + // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM + // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices + // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 + ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) || + + // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8) + $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 || + + // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10) + $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 || + // Blackberry Playbook (1.0-2.0) - Tested on PlayBook + $this->match('Playbook.*Tablet') || + + // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0) + ( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) || + // Palm WebOS 3.0 - Tested on HP TouchPad + $this->match('hp.*TouchPad') || + + // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices + ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) || + + // Chrome for Android - Tested on Android 4.0, 4.1 device + ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) || + + // Skyfire 4.1 - Tested on Android 2.3 device + ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || + + // Opera Mobile 11.5-12: Tested on Android 2.3 + ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) || + + // Meego 1.2 - Tested on Nokia 950 and N9 + $this->is('MeeGoOS') || + + // Tizen (pre-release) - Tested on early hardware + $this->is('Tizen') || + + // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser + // @todo: more tests here! + $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 || + + // UC Browser - Tested on Android 2.3 device + ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) || + + // Kindle 3 and Fire - Tested on the built-in WebKit browser for each + ( $this->match('Kindle Fire') || + $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) || + + // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet + $this->is('AndroidOS') && $this->is('NookTablet') || + + // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7 + $this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile || + + // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7 + $this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile || + + // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7 + $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile || + + // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 + $this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile || + + // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 + $this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile + ){ + return self::MOBILE_GRADE_A; + } + + if ( + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 || + + // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 + $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || + + //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 + ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 && + ($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) || + + // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) + $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || + + // @todo: report this (tested on Nokia N71) + $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS') + ){ + return self::MOBILE_GRADE_B; + } + + if ( + // Blackberry 4.x - Tested on the Curve 8330 + $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 || + // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) + $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 || + + // Tested on original iPhone (3.1), iPhone 3 (3.2) + $this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 || + $this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 || + $this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 || + + // Internet Explorer 7 and older - Tested on Windows XP + $this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile + ){ + return self::MOBILE_GRADE_C; + } + + // All older smartphone platforms and featurephones - Any device that doesn't support media queries + // will receive the basic, C grade experience. + return self::MOBILE_GRADE_C; + } +} diff --git a/lib/redactor/ckeditor/.htaccess b/lib/redactor/ckeditor/.htaccess new file mode 100644 index 0000000..5ecd0b6 --- /dev/null +++ b/lib/redactor/ckeditor/.htaccess @@ -0,0 +1,24 @@ +# +# Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. +# For licensing, see LICENSE.html or http://ckeditor.com/license +# + +# +# On some specific Linux installations you could face problems with Firefox. +# It could give you errors when loading the editor saying that some illegal +# characters were found (three strange chars in the beginning of the file). +# This could happen if you map the .js or .css files to PHP, for example. +# +# Those characters are the Byte Order Mask (BOM) of the Unicode encoded files. +# All FCKeditor files are Unicode encoded. +# + +AddType application/x-javascript .js +AddType text/css .css + +# +# If PHP is mapped to handle XML files, you could have some issues. The +# following will disable it. +# + +AddType text/xml .xml diff --git a/lib/redactor/ckeditor/adapters/ckeditor.php b/lib/redactor/ckeditor/adapters/ckeditor.php new file mode 100644 index 0000000..dcd1303 --- /dev/null +++ b/lib/redactor/ckeditor/adapters/ckeditor.php @@ -0,0 +1,598 @@ +editor("editor1", "

      Initial value.

      "); + * @endcode + */ +class CKEditor +{ + /** + * The version of %CKEditor. + */ + const version = '3.6.6'; + /** + * A constant string unique for each release of %CKEditor. + */ + const timestamp = 'D03G5XL'; + + /** + * URL to the %CKEditor installation directory (absolute or relative to document root). + * If not set, CKEditor will try to guess it's path. + * + * Example usage: + * @code + * $CKEditor->basePath = '/ckeditor/'; + * @endcode + */ + public $basePath; + /** + * An array that holds the global %CKEditor configuration. + * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html + * + * Example usage: + * @code + * $CKEditor->config['height'] = 400; + * // Use @@ at the beggining of a string to ouput it without surrounding quotes. + * $CKEditor->config['width'] = '@@screen.width * 0.8'; + * @endcode + */ + public $config = array(); + /** + * A boolean variable indicating whether CKEditor has been initialized. + * Set it to true only if you have already included + * <script> tag loading ckeditor.js in your website. + */ + public $initialized = false; + /** + * Boolean variable indicating whether created code should be printed out or returned by a function. + * + * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->returnOutput = true; + * $code = $CKEditor->editor("editor1", "

      Initial value.

      "); + * echo "

      Editor 1:

      "; + * echo $code; + * @endcode + */ + public $returnOutput = false; + /** + * An array with textarea attributes. + * + * When %CKEditor is created with the editor() method, a HTML <textarea> element is created, + * it will be displayed to anyone with JavaScript disabled or with incompatible browser. + */ + public $textareaAttributes = array( "rows" => 8, "cols" => 60 ); + /** + * A string indicating the creation date of %CKEditor. + * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor. + */ + public $timestamp = "D03G5XL"; + /** + * An array that holds event listeners. + */ + private $events = array(); + /** + * An array that holds global event listeners. + */ + private $globalEvents = array(); + + /** + * Main Constructor. + * + * @param $basePath (string) URL to the %CKEditor installation directory (optional). + */ + function __construct($basePath = null) + { + if (! empty($basePath)) + { + $this->basePath = $basePath; + } + } + + /** + * Creates a %CKEditor instance. + * In incompatible browsers %CKEditor will downgrade to plain HTML <textarea> element. + * + * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element). + * @param $value (string) Initial value (optional). + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example usage: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->editor("field1", "

      Initial value.

      "); + * @endcode + * + * Advanced example: + * @code + * $CKEditor = new CKEditor(); + * $config = array(); + * $config['toolbar'] = array( + * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ), + * array( 'Image', 'Link', 'Unlink', 'Anchor' ) + * ); + * $events['instanceReady'] = 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'; + * $CKEditor->editor("field1", "

      Initial value.

      ", $config, $events); + * @endcode + */ + public function editor($name, $value = "", $config = array(), $events = array()) + { + $attr = ""; + + foreach ($this->textareaAttributes as $key => $val) { + $attr.= " " . $key . '="' . str_replace('"', '"', $val) . '"'; + } + + $out = "\n"; + + if (!$this->initialized) + { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + + if (! empty($_config)) + $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");"; + else + $js .= "CKEDITOR.replace('".$name."');"; + + $out .= $this->script($js); + + if (! $this->returnOutput) + { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replaces a <textarea> with a %CKEditor instance. + * + * @param $id (string) The id or name of textarea element. + * @param $config (array) The specific configurations to apply to this editor instance (optional). + * @param $events (array) Event listeners for this editor instance (optional). + * + * Example 1: adding %CKEditor to <textarea name="article"></textarea> element: + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replace("article"); + * @endcode + */ + public function replace($id, $config = array(), $events = array()) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings($config, $events); + + $js = $this->returnGlobalEvents(); + if (!empty($_config)) { + $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");"; + } + else { + $js .= "CKEDITOR.replace('".$id."');"; + } + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Replace all <textarea> elements available in the document with editor instances. + * + * @param $className (string) If set, replace all textareas with class className in the page. + * + * Example 1: replace all <textarea> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll(); + * @endcode + * + * Example 2: replace all <textarea class="myClassName"> elements in the page. + * @code + * $CKEditor = new CKEditor(); + * $CKEditor->replaceAll( 'myClassName' ); + * @endcode + */ + public function replaceAll($className = null) + { + $out = ""; + if (!$this->initialized) { + $out .= $this->init(); + } + + $_config = $this->configSettings(); + + $js = $this->returnGlobalEvents(); + if (empty($_config)) { + if (empty($className)) { + $js .= "CKEDITOR.replaceAll();"; + } + else { + $js .= "CKEDITOR.replaceAll('".$className."');"; + } + } + else { + $classDetection = ""; + $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n"; + if (!empty($className)) { + $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n"; + $js .= " if (!classRegex.test(textarea.className))\n"; + $js .= " return false;\n"; + } + $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);"; + $js .= "} );"; + + } + + $out .= $this->script($js); + + if (!$this->returnOutput) { + print $out; + $out = ""; + } + + return $out; + } + + /** + * Adds event listener. + * Events are fired by %CKEditor in various situations. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addEventHandler('instanceReady', 'function (ev) { + * alert("Loaded: " + ev.editor.name); + * }'); + * @endcode + */ + public function addEventHandler($event, $javascriptCode) + { + if (!isset($this->events[$event])) { + $this->events[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->events[$event])) { + $this->events[$event][] = $javascriptCode; + } + } + + /** + * Clear registered event handlers. + * Note: this function will have no effect on already created editor instances. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + public function clearEventHandlers($event = null) + { + if (!empty($event)) { + $this->events[$event] = array(); + } + else { + $this->events = array(); + } + } + + /** + * Adds global event listener. + * + * @param $event (string) Event name. + * @param $javascriptCode (string) Javascript anonymous function or function name. + * + * Example usage: + * @code + * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) { + * alert("Loading dialog: " + ev.data.name); + * }'); + * @endcode + */ + public function addGlobalEventHandler($event, $javascriptCode) + { + if (!isset($this->globalEvents[$event])) { + $this->globalEvents[$event] = array(); + } + // Avoid duplicates. + if (!in_array($javascriptCode, $this->globalEvents[$event])) { + $this->globalEvents[$event][] = $javascriptCode; + } + } + + /** + * Clear registered global event handlers. + * Note: this function will have no effect if the event handler has been already printed/returned. + * + * @param $event (string) Event name, if not set all event handlers will be removed (optional). + */ + public function clearGlobalEventHandlers($event = null) + { + if (!empty($event)) { + $this->globalEvents[$event] = array(); + } + else { + $this->globalEvents = array(); + } + } + + /** + * Prints javascript code. + * + * @param string $js + */ + private function script($js) + { + $out = "\n"; + + return $out; + } + + /** + * Returns the configuration array (global and instance specific settings are merged into one array). + * + * @param $config (array) The specific configurations to apply to editor instance. + * @param $events (array) Event listeners for editor instance. + */ + private function configSettings($config = array(), $events = array()) + { + $_config = $this->config; + $_events = $this->events; + + if (is_array($config) && !empty($config)) + { + $_config = array_merge($_config, $config); + } + + if (is_array($events) && !empty($events)) + { + foreach ($events as $eventName => $code) + { + if (!isset($_events[$eventName])) + { + $_events[$eventName] = array(); + } + + if (!in_array($code, $_events[$eventName])) + { + $_events[$eventName][] = $code; + } + } + } + + if (!empty($_events)) + { + foreach($_events as $eventName => $handlers) + { + if (empty($handlers)) + { + continue; + } + else if (count($handlers) == 1) { + $_config['on'][$eventName] = '@@'.$handlers[0]; + } + else + { + $_config['on'][$eventName] = '@@function (ev){'; + + foreach ($handlers as $handler => $code) + { + $_config['on'][$eventName] .= '('.$code.')(ev);'; + } + + $_config['on'][$eventName] .= '}'; + } + } + } + + return $_config; + } + + /** + * Return global event handlers. + */ + private function returnGlobalEvents() + { + static $returnedEvents; + $out = ""; + + if (! isset($returnedEvents)) + { + $returnedEvents = array(); + } + + if (! empty($this->globalEvents)) + { + foreach ($this->globalEvents as $eventName => $handlers) + { + foreach ($handlers as $handler => $code) + { + if (!isset($returnedEvents[$eventName])) + { + $returnedEvents[$eventName] = array(); + } + // Return only new events + if (!in_array($code, $returnedEvents[$eventName])) + { + $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);"; + $returnedEvents[$eventName][] = $code; + } + } + } + } + + return $out; + } + + /** + * Initializes CKEditor (executed only once). + */ + private function init() + { + static $initComplete; + $out = ""; + + if (!empty($initComplete)) + { + return ""; + } + + if ($this->initialized) + { + $initComplete = true; + return ""; + } + + $args = ""; + + $ckeditorPath = $this->ckeditorPath(); + + if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") + { + $args = '?t=' . $this->timestamp; + } + + // Skip relative paths... + if (strpos($ckeditorPath, '..') !== 0) + { + $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';"); + } + + $out .= "\n"; + + $extraCode = ""; + if ($this->timestamp != self::timestamp) + { + $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';"; + } + + if ($extraCode) + { + $out .= $this->script($extraCode); + } + + $initComplete = $this->initialized = true; + + return $out; + } + + /** + * Return path to ckeditor.js. + */ + private function ckeditorPath() + { + if (! empty($this->basePath)) + { + return $this->basePath; + } + + /** + * The absolute pathname of the currently executing script. + * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php, + * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user. + */ + if (isset($_SERVER['SCRIPT_FILENAME'])) + { + $realPath = dirname($_SERVER['SCRIPT_FILENAME']); + } + else + { + /** + * realpath - Returns canonicalized absolute pathname + */ + $realPath = realpath( './' ) ; + } + + /** + * The filename of the currently executing script, relative to the document root. + * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar + * would be /test.php/foo.bar. + */ + $selfPath = dirname($_SERVER['PHP_SELF']); + + $file = str_replace("\\", "/", __FILE__); + + if (! $selfPath || ! $realPath || ! $file) + { + return "/newck/"; + } + + $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath)); + + $fileUrl = substr($file, strlen($documentRoot)); + + $ckeditorUrl = str_replace("adapters/ckeditor.php", "", $fileUrl); + + return $ckeditorUrl; + } + + /** + * This little function provides a basic JSON support. + * + * @param mixed $val + * @return string + */ + private function jsEncode($val) + { + if (is_null($val)) { + return 'null'; + } + if (is_bool($val)) { + return $val ? 'true' : 'false'; + } + if (is_int($val)) { + return $val; + } + if (is_float($val)) { + return str_replace(',', '.', $val); + } + if (is_array($val) || is_object($val)) { + if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) { + return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']'; + } + $temp = array(); + foreach ($val as $k => $v){ + $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v); + } + return '{' . implode(',', $temp) . '}'; + } + // String otherwise + if (strpos($val, '@@') === 0) + return substr($val, 2); + if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.') + return $val; + + return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"'; + } +} diff --git a/lib/redactor/ckeditor/adapters/jquery.js b/lib/redactor/ckeditor/adapters/jquery.js new file mode 100644 index 0000000..86cb458 --- /dev/null +++ b/lib/redactor/ckeditor/adapters/jquery.js @@ -0,0 +1,10 @@ +/* + Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +(function(a){if("undefined"==typeof a)throw Error("jQuery should be loaded before CKEditor jQuery adapter.");if("undefined"==typeof CKEDITOR)throw Error("CKEditor should be loaded before CKEditor jQuery adapter.");CKEDITOR.config.jqueryOverrideVal="undefined"==typeof CKEDITOR.config.jqueryOverrideVal?!0:CKEDITOR.config.jqueryOverrideVal;a.extend(a.fn,{ckeditorGet:function(){var a=this.eq(0).data("ckeditorInstance");if(!a)throw"CKEditor is not initialized yet, use ckeditor() with a callback.";return a}, +ckeditor:function(g,d){if(!CKEDITOR.env.isCompatible)throw Error("The environment is incompatible.");if(!a.isFunction(g)){var m=d;d=g;g=m}var k=[];d=d||{};this.each(function(){var b=a(this),c=b.data("ckeditorInstance"),f=b.data("_ckeditorInstanceLock"),h=this,l=new a.Deferred;k.push(l.promise());if(c&&!f)g&&g.apply(c,[this]),l.resolve();else if(f)c.once("instanceReady",function(){setTimeout(function(){c.element?(c.element.$==h&&g&&g.apply(c,[h]),l.resolve()):setTimeout(arguments.callee,100)},0)}, +null,null,9999);else{if(d.autoUpdateElement||"undefined"==typeof d.autoUpdateElement&&CKEDITOR.config.autoUpdateElement)d.autoUpdateElementJquery=!0;d.autoUpdateElement=!1;b.data("_ckeditorInstanceLock",!0);c=a(this).is("textarea")?CKEDITOR.replace(h,d):CKEDITOR.inline(h,d);b.data("ckeditorInstance",c);c.on("instanceReady",function(d){var e=d.editor;setTimeout(function(){if(e.element){d.removeListener();e.on("dataReady",function(){b.trigger("dataReady.ckeditor",[e])});e.on("setData",function(a){b.trigger("setData.ckeditor", +[e,a.data])});e.on("getData",function(a){b.trigger("getData.ckeditor",[e,a.data])},999);e.on("destroy",function(){b.trigger("destroy.ckeditor",[e])});e.on("save",function(){a(h.form).submit();return!1},null,null,20);if(e.config.autoUpdateElementJquery&&b.is("textarea")&&a(h.form).length){var c=function(){b.ckeditor(function(){e.updateElement()})};a(h.form).submit(c);a(h.form).bind("form-pre-serialize",c);b.bind("destroy.ckeditor",function(){a(h.form).unbind("submit",c);a(h.form).unbind("form-pre-serialize", +c)})}e.on("destroy",function(){b.removeData("ckeditorInstance")});b.removeData("_ckeditorInstanceLock");b.trigger("instanceReady.ckeditor",[e]);g&&g.apply(e,[h]);l.resolve()}else setTimeout(arguments.callee,100)},0)},null,null,9999)}});var f=new a.Deferred;this.promise=f.promise();a.when.apply(this,k).then(function(){f.resolve()});this.editor=this.eq(0).data("ckeditorInstance");return this}});CKEDITOR.config.jqueryOverrideVal&&(a.fn.val=CKEDITOR.tools.override(a.fn.val,function(g){return function(d){if(arguments.length){var m= +this,k=[],f=this.each(function(){var b=a(this),c=b.data("ckeditorInstance");if(b.is("textarea")&&c){var f=new a.Deferred;c.setData(d,function(){f.resolve()});k.push(f.promise());return!0}return g.call(b,d)});if(k.length){var b=new a.Deferred;a.when.apply(this,k).done(function(){b.resolveWith(m)});return b.promise()}return f}var f=a(this).eq(0),c=f.data("ckeditorInstance");return f.is("textarea")&&c?c.getData():g.call(f)}}))})(window.jQuery); \ No newline at end of file diff --git a/lib/redactor/ckeditor/block.js b/lib/redactor/ckeditor/block.js new file mode 100644 index 0000000..ebd91f8 --- /dev/null +++ b/lib/redactor/ckeditor/block.js @@ -0,0 +1,190 @@ +CKEDITOR.editorConfig = function( config ) { + + + CKEDITOR.dtd.$removeEmpty.span = 0; + CKEDITOR.dtd.$removeEmpty.i = 0; + CKEDITOR.dtd.$removeEmpty.div = 0; + CKEDITOR.dtd.$removeEmpty.em = 0; + CKEDITOR.dtd.$removeEmpty.b = 0; + + config.removePlugins = 'scayt'; + + config.extraPlugins = 'codemirror,placeholder,savedocs'; + + config.protectedSource.push(/<\?[\s\S]*?\?>/g); // PHP code + config.protectedSource.push(/<%[\s\S]*?%>/g); // ASP code + config.protectedSource.push(/(]+>[\s|\S]*?<\/asp:[^\>]+>)|(]+\/>)/gi); // ASP.Net code + + config.language = 'ru'; + + config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)'; + + config.toolbarCanCollapse = true; + config.disableNativeSpellChecker = false; + config.scayt_autoStartup = false; + + config.autoParagraph = false; + config.autoUpdateElement = true; + + config.enterMode = CKEDITOR.ENTER_BR; + config.shiftEnterMode = CKEDITOR.ENTER_P; + + config.toolbarStartupExpanded = true; + + config.allowedContent = true; + + config.autoGrow_minHeight = 300; + + config.toolbar_Big = [{ + name: 'document', + groups: ['mode', 'document', 'doctools'], + items: ['Source', '-', 'searchCode','autoFormat','CommentSelectedRange','UncommentSelectedRange','AutoComplete', 'Save'] + }, { + name: 'clipboard', + groups: ['clipboard', 'undo'], + items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo'] + }, { + name: 'editing', + groups: ['find', 'selection', 'spellchecker'], + items: ['Find', 'Replace', '-', 'SelectAll'] + }, { + name: 'forms', + items: ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'] + }, + '/', { + name: 'basicstyles', + groups: ['basicstyles', 'cleanup'], + items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'] + }, { + name: 'paragraph', + groups: ['list', 'indent', 'blocks', 'align', 'bidi'], + items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'] + }, { + name: 'links', + items: ['Link', 'Unlink', 'Anchor'] + }, { + name: 'insert', + items: ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe'] + }, + '/', { + name: 'styles', + items: ['Styles', 'Format', 'Font', 'FontSize'] + }, { + name: 'colors', + items: ['TextColor', 'BGColor'] + }, { + name: 'tools', + items: ['Maximize', 'ShowBlocks'] + }, { + name: 'texttransform', + items: ['TransformTextToUppercase', 'TransformTextToLowercase', 'TransformTextCapitalize', 'TransformTextSwitcher'] + }, { + name: 'about', + items: ['About'] + } + ]; + + config.codemirror = { + + // Set this to the theme you wish to use (codemirror themes) + theme: 'default', + + // Whether or not you want to show line numbers + lineNumbers: true, + + // Whether or not you want to use line wrapping + lineWrapping: true, + + // Whether or not you want to highlight matching braces + matchBrackets: true, + + // Whether or not you want to highlight matching tags + matchTags: true, + + // Whether or not you want tags to automatically close themselves + autoCloseTags: true, + + // Whether or not you want Brackets to automatically close themselves + autoCloseBrackets: true, + + // Whether or not to enable search tools, CTRL+F (Find), CTRL+SHIFT+F (Replace), CTRL+SHIFT+R (Replace All), CTRL+G (Find Next), CTRL+SHIFT+G (Find Previous) + enableSearchTools: true, + + // Whether or not you wish to enable code folding (requires 'lineNumbers' to be set to 'true') + enableCodeFolding: true, + + // Whether or not to enable code formatting + enableCodeFormatting: true, + + // Whether or not to automatically format code should be done when the editor is loaded + autoFormatOnStart: false, + + autoFormatOnModeChange: false, + + // Whether or not to automatically format code which has just been uncommented + autoFormatOnUncomment: true, + + // Whether or not to highlight the currently active line + highlightActiveLine: true, + + // Whether or not to highlight all matches of current word/selection + highlightMatches: true, + + // Define the language specific mode 'htmlmixed' for html including (css, xml, javascript), 'application/x-httpd-php' for php mode including html, or 'text/javascript' for using java script only + mode: 'application/x-httpd-php', + + // Whether or not to show the search Code button on the toolbar + showSearchButton: true, + + // Whether or not to show Trailing Spaces + showTrailingSpace: true, + + // Whether or not to show the format button on the toolbar + showFormatButton: true, + + // Whether or not to show the comment button on the toolbar + showCommentButton: true, + + // Whether or not to show the uncomment button on the toolbar + showUncommentButton: true, + + // Whether or not to show the showAutoCompleteButton button on the toolbar + showAutoCompleteButton: true + }; + + + config.filebrowserBrowseUrl = '../../../../admin/index.php?do=browser&type=link&mode=fck&target=txtUrl'; + config.filebrowserImageBrowseUrl = '../../../../admin/index.php?do=browser&type=image&mode=fck&target=txtUrl'; + config.filebrowserLinkBrowseUrl = '../../../../admin/index.php?do=docs&action=showsimple&selecturl=1&target=txtUrl&pop=1'; + + config.removeDialogTabs = 'link:upload;image:Upload'; + + config.keystrokes = + [ + [CKEDITOR.ALT + 121 /*F10*/ , 'toolbarFocus'], + [CKEDITOR.ALT + 122 /*F11*/ , 'elementsPathFocus'], + + [CKEDITOR.SHIFT + 121 /*F10*/ , 'contextMenu'], + + [CKEDITOR.CTRL + 90 /*Z*/ , 'undo'], + [CKEDITOR.CTRL + 89 /*Y*/ , 'redo'], + [CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/ , 'redo'], + + [CKEDITOR.CTRL + 76 /*L*/ , 'link'], + + [CKEDITOR.CTRL + 66 /*B*/ , 'bold'], + [CKEDITOR.CTRL + 73 /*I*/ , 'italic'], + [CKEDITOR.CTRL + 85 /*U*/ , 'underline'], + + [CKEDITOR.ALT + 109 /*-*/ , 'toolbarCollapse'] + ]; + + config.forcePasteAsPlainText = true; +}; + +CKEDITOR.on('instanceReady', function(ev) { + ev.editor.on('paste', function(evt) { + evt.data.dataValue = evt.data.dataValue.replace(/ /g,' '); + evt.data.dataValue = evt.data.dataValue.replace(/

      <\/p>/g,' '); + }, null, null, 9); +}); \ No newline at end of file diff --git a/lib/redactor/ckeditor/ckeditor.js b/lib/redactor/ckeditor/ckeditor.js new file mode 100644 index 0000000..d2584b2 --- /dev/null +++ b/lib/redactor/ckeditor/ckeditor.js @@ -0,0 +1,1135 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +(function(){if(window.CKEDITOR&&window.CKEDITOR.dom)return;window.CKEDITOR||(window.CKEDITOR=function(){var a=/(^|.*[\\\/])ckeditor\.js(?:\?.*|;.*)?$/i,d={timestamp:"H0CG",version:"4.6.2",revision:"20af917",rnd:Math.floor(900*Math.random())+100,_:{pending:[],basePathSrcPattern:a},status:"unloaded",basePath:function(){var b=window.CKEDITOR_BASEPATH||"";if(!b)for(var c=document.getElementsByTagName("script"),d=0;df.getListenerIndex(d)){f=f.listeners;g||(g=this);isNaN(h)&&(h=10);var B=this;p.fn=d;p.priority=h;for(var u=f.length-1;0<=u;u--)if(f[u].priority<=h)return f.splice(u+1,0,p),{removeListener:r};f.unshift(p)}return{removeListener:r}}, +once:function(){var a=Array.prototype.slice.call(arguments),b=a[1];a[1]=function(a){a.removeListener();return b.apply(this,arguments)};return this.on.apply(this,a)},capture:function(){CKEDITOR.event.useCapture=1;var a=this.on.apply(this,arguments);CKEDITOR.event.useCapture=0;return a},fire:function(){var a=0,b=function(){a=1},g=0,k=function(){g=1};return function(h,p,r){var f=d(this)[h];h=a;var B=g;a=g=0;if(f){var u=f.listeners;if(u.length)for(var u=u.slice(0),z,y=0;ydocument.documentMode),mobile:-1c||b.quirks);b.gecko&&(d=a.match(/rv:([\d\.]+)/))&&(d=d[1].split("."),c=1E4*d[0]+100*(d[1]||0)+1*(d[2]||0));b.air&&(c=parseFloat(a.match(/ adobeair\/(\d+)/)[1])); +b.webkit&&(c=parseFloat(a.match(/ applewebkit\/(\d+)/)[1]));b.version=c;b.isCompatible=!(b.ie&&7>c)&&!(b.gecko&&4E4>c)&&!(b.webkit&&534>c);b.hidpi=2<=window.devicePixelRatio;b.needsBrFiller=b.gecko||b.webkit||b.ie&&10c;b.cssClass="cke_browser_"+(b.ie?"ie":b.gecko?"gecko":b.webkit?"webkit":"unknown");b.quirks&&(b.cssClass+=" cke_browser_quirks");b.ie&&(b.cssClass+=" cke_browser_ie"+(b.quirks?"6 cke_browser_iequirks":b.version));b.air&&(b.cssClass+=" cke_browser_air"); +b.iOS&&(b.cssClass+=" cke_browser_ios");b.hidpi&&(b.cssClass+=" cke_hidpi");return b}()); +"unloaded"==CKEDITOR.status&&function(){CKEDITOR.event.implementOn(CKEDITOR);CKEDITOR.loadFullCore=function(){if("basic_ready"!=CKEDITOR.status)CKEDITOR.loadFullCore._load=1;else{delete CKEDITOR.loadFullCore;var a=document.createElement("script");a.type="text/javascript";a.src=CKEDITOR.basePath+"ckeditor.js";document.getElementsByTagName("head")[0].appendChild(a)}};CKEDITOR.loadFullCoreTimeout=0;CKEDITOR.add=function(a){(this._.pending||(this._.pending=[])).push(a)};(function(){CKEDITOR.domReady(function(){var a= +CKEDITOR.loadFullCore,d=CKEDITOR.loadFullCoreTimeout;a&&(CKEDITOR.status="basic_ready",a&&a._load?a():d&&setTimeout(function(){CKEDITOR.loadFullCore&&CKEDITOR.loadFullCore()},1E3*d))})})();CKEDITOR.status="basic_loaded"}();"use strict";CKEDITOR.VERBOSITY_WARN=1;CKEDITOR.VERBOSITY_ERROR=2;CKEDITOR.verbosity=CKEDITOR.VERBOSITY_WARN|CKEDITOR.VERBOSITY_ERROR;CKEDITOR.warn=function(a,d){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_WARN&&CKEDITOR.fire("log",{type:"warn",errorCode:a,additionalData:d})}; +CKEDITOR.error=function(a,d){CKEDITOR.verbosity&CKEDITOR.VERBOSITY_ERROR&&CKEDITOR.fire("log",{type:"error",errorCode:a,additionalData:d})}; +CKEDITOR.on("log",function(a){if(window.console&&window.console.log){var d=console[a.data.type]?a.data.type:"log",b=a.data.errorCode;if(a=a.data.additionalData)console[d]("[CKEDITOR] Error code: "+b+".",a);else console[d]("[CKEDITOR] Error code: "+b+".");console[d]("[CKEDITOR] For more information about this error go to http://docs.ckeditor.com/#!/guide/dev_errors-section-"+b)}},null,null,999);CKEDITOR.dom={}; +(function(){var a=[],d=CKEDITOR.env.gecko?"-moz-":CKEDITOR.env.webkit?"-webkit-":CKEDITOR.env.ie?"-ms-":"",b=/&/g,c=/>/g,e=/|\s) /g, +function(a,f){return f+"\x26nbsp;"}).replace(/ (?=<)/g,"\x26nbsp;")},getNextNumber:function(){var a=0;return function(){return++a}}(),getNextId:function(){return"cke_"+this.getNextNumber()},getUniqueId:function(){for(var a="e",f=0;8>f;f++)a+=Math.floor(65536*(1+Math.random())).toString(16).substring(1);return a},override:function(a,f){var b=f(a);b.prototype=a.prototype;return b},setTimeout:function(a,f,b,c,h){h||(h=window);b||(b=h);return h.setTimeout(function(){c?a.apply(b,[].concat(c)):a.apply(b)}, +f||0)},trim:function(){var a=/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g;return function(f){return f.replace(a,"")}}(),ltrim:function(){var a=/^[ \t\n\r]+/g;return function(f){return f.replace(a,"")}}(),rtrim:function(){var a=/[ \t\n\r]+$/g;return function(f){return f.replace(a,"")}}(),indexOf:function(a,f){if("function"==typeof f)for(var b=0,c=a.length;bb;b++)a[b]=("0"+parseInt(a[b],10).toString(16)).slice(-2); +return"#"+a.join("")})},normalizeHex:function(a){return a.replace(/#(([0-9a-f]{3}){1,2})($|;|\s+)/gi,function(a,b,c,h){a=b.toLowerCase();3==a.length&&(a=a.split(""),a=[a[0],a[0],a[1],a[1],a[2],a[2]].join(""));return"#"+a+h})},parseCssText:function(a,f,b){var c={};b&&(a=(new CKEDITOR.dom.element("span")).setAttribute("style",a).getAttribute("style")||"");a&&(a=CKEDITOR.tools.normalizeHex(CKEDITOR.tools.convertRgbToHex(a)));if(!a||";"==a)return c;a.replace(/"/g,'"').replace(/\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g, +function(a,b,h){f&&(b=b.toLowerCase(),"font-family"==b&&(h=h.replace(/\s*,\s*/g,",")),h=CKEDITOR.tools.trim(h));c[b]=h});return c},writeCssText:function(a,b){var c,h=[];for(c in a)h.push(c+":"+a[c]);b&&h.sort();return h.join("; ")},objectCompare:function(a,b,c){var h;if(!a&&!b)return!0;if(!a||!b)return!1;for(h in a)if(a[h]!=b[h])return!1;if(!c)for(h in b)if(a[h]!=b[h])return!1;return!0},objectKeys:function(a){var b=[],c;for(c in a)b.push(c);return b},convertArrayToObject:function(a,b){var c={};1== +arguments.length&&(b=!0);for(var h=0,d=a.length;hc;c++)a.push(Math.floor(256*Math.random()));for(c=0;cCKEDITOR.env.version&&(this.type==CKEDITOR.NODE_ELEMENT||this.type==CKEDITOR.NODE_DOCUMENT_FRAGMENT)&&c(e);return e},hasPrevious:function(){return!!this.$.previousSibling},hasNext:function(){return!!this.$.nextSibling},insertAfter:function(a){a.$.parentNode.insertBefore(this.$,a.$.nextSibling);return a},insertBefore:function(a){a.$.parentNode.insertBefore(this.$, +a.$);return a},insertBeforeMe:function(a){this.$.parentNode.insertBefore(a.$,this.$);return a},getAddress:function(a){for(var d=[],b=this.getDocument().$.documentElement,c=this.$;c&&c!=b;){var e=c.parentNode;e&&d.unshift(this.getIndex.call({$:c},a));c=e}return d},getDocument:function(){return new CKEDITOR.dom.document(this.$.ownerDocument||this.$.parentNode.ownerDocument)},getIndex:function(a){function d(a,c){var p=c?a.nextSibling:a.previousSibling;return p&&p.nodeType==CKEDITOR.NODE_TEXT?b(p)?d(p, +c):p:null}function b(a){return!a.nodeValue||a.nodeValue==CKEDITOR.dom.selection.FILLING_CHAR_SEQUENCE}var c=this.$,e=-1,g;if(!this.$.parentNode||a&&c.nodeType==CKEDITOR.NODE_TEXT&&b(c)&&!d(c)&&!d(c,!0))return-1;do a&&c!=this.$&&c.nodeType==CKEDITOR.NODE_TEXT&&(g||b(c))||(e++,g=c.nodeType==CKEDITOR.NODE_TEXT);while(c=c.previousSibling);return e},getNextSourceNode:function(a,d,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getFirst&&this.getFirst();var e;if(!a){if(this.type== +CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getNext()}for(;!a&&(e=(e||this).getParent());){if(b&&!1===b(e,!0))return null;a=e.getNext()}return!a||b&&!1===b(a)?null:d&&d!=a.type?a.getNextSourceNode(!1,d,b):a},getPreviousSourceNode:function(a,d,b){if(b&&!b.call){var c=b;b=function(a){return!a.equals(c)}}a=!a&&this.getLast&&this.getLast();var e;if(!a){if(this.type==CKEDITOR.NODE_ELEMENT&&b&&!1===b(this,!0))return null;a=this.getPrevious()}for(;!a&&(e=(e||this).getParent());){if(b&&!1=== +b(e,!0))return null;a=e.getPrevious()}return!a||b&&!1===b(a)?null:d&&a.type!=d?a.getPreviousSourceNode(!1,d,b):a},getPrevious:function(a){var d=this.$,b;do b=(d=d.previousSibling)&&10!=d.nodeType&&new CKEDITOR.dom.node(d);while(b&&a&&!a(b));return b},getNext:function(a){var d=this.$,b;do b=(d=d.nextSibling)&&new CKEDITOR.dom.node(d);while(b&&a&&!a(b));return b},getParent:function(a){var d=this.$.parentNode;return d&&(d.nodeType==CKEDITOR.NODE_ELEMENT||a&&d.nodeType==CKEDITOR.NODE_DOCUMENT_FRAGMENT)? +new CKEDITOR.dom.node(d):null},getParents:function(a){var d=this,b=[];do b[a?"push":"unshift"](d);while(d=d.getParent());return b},getCommonAncestor:function(a){if(a.equals(this))return this;if(a.contains&&a.contains(this))return a;var d=this.contains?this:this.getParent();do if(d.contains(a))return d;while(d=d.getParent());return null},getPosition:function(a){var d=this.$,b=a.$;if(d.compareDocumentPosition)return d.compareDocumentPosition(b);if(d==b)return CKEDITOR.POSITION_IDENTICAL;if(this.type== +CKEDITOR.NODE_ELEMENT&&a.type==CKEDITOR.NODE_ELEMENT){if(d.contains){if(d.contains(b))return CKEDITOR.POSITION_CONTAINS+CKEDITOR.POSITION_PRECEDING;if(b.contains(d))return CKEDITOR.POSITION_IS_CONTAINED+CKEDITOR.POSITION_FOLLOWING}if("sourceIndex"in d)return 0>d.sourceIndex||0>b.sourceIndex?CKEDITOR.POSITION_DISCONNECTED:d.sourceIndex=document.documentMode||!d||(a=d+":"+a);return new CKEDITOR.dom.nodeList(this.$.getElementsByTagName(a))},getHead:function(){var a=this.$.getElementsByTagName("head")[0]; +return a=a?new CKEDITOR.dom.element(a):this.getDocumentElement().append(new CKEDITOR.dom.element("head"),!0)},getBody:function(){return new CKEDITOR.dom.element(this.$.body)},getDocumentElement:function(){return new CKEDITOR.dom.element(this.$.documentElement)},getWindow:function(){return new CKEDITOR.dom.window(this.$.parentWindow||this.$.defaultView)},write:function(a){this.$.open("text/html","replace");CKEDITOR.env.ie&&(a=a.replace(/(?:^\s*]*?>)|^/i,'$\x26\n\x3cscript data-cke-temp\x3d"1"\x3e('+ +CKEDITOR.tools.fixDomain+")();\x3c/script\x3e"));this.$.write(a);this.$.close()},find:function(a){return new CKEDITOR.dom.nodeList(this.$.querySelectorAll(a))},findOne:function(a){return(a=this.$.querySelector(a))?new CKEDITOR.dom.element(a):null},_getHtml5ShivFrag:function(){var a=this.getCustomData("html5ShivFrag");a||(a=this.$.createDocumentFragment(),CKEDITOR.tools.enableHtml5Elements(a,!0),this.setCustomData("html5ShivFrag",a));return a}});CKEDITOR.dom.nodeList=function(a){this.$=a}; +CKEDITOR.dom.nodeList.prototype={count:function(){return this.$.length},getItem:function(a){return 0>a||a>=this.$.length?null:(a=this.$[a])?new CKEDITOR.dom.node(a):null}};CKEDITOR.dom.element=function(a,d){"string"==typeof a&&(a=(d?d.$:document).createElement(a));CKEDITOR.dom.domObject.call(this,a)};CKEDITOR.dom.element.get=function(a){return(a="string"==typeof a?document.getElementById(a)||document.getElementsByName(a)[0]:a)&&(a.$?a:new CKEDITOR.dom.element(a))};CKEDITOR.dom.element.prototype=new CKEDITOR.dom.node; +CKEDITOR.dom.element.createFromHtml=function(a,d){var b=new CKEDITOR.dom.element("div",d);b.setHtml(a);return b.getFirst().remove()};CKEDITOR.dom.element.setMarker=function(a,d,b,c){var e=d.getCustomData("list_marker_id")||d.setCustomData("list_marker_id",CKEDITOR.tools.getNextNumber()).getCustomData("list_marker_id"),g=d.getCustomData("list_marker_names")||d.setCustomData("list_marker_names",{}).getCustomData("list_marker_names");a[e]=d;g[b]=1;return d.setCustomData(b,c)}; +CKEDITOR.dom.element.clearAllMarkers=function(a){for(var d in a)CKEDITOR.dom.element.clearMarkers(a,a[d],1)};CKEDITOR.dom.element.clearMarkers=function(a,d,b){var c=d.getCustomData("list_marker_names"),e=d.getCustomData("list_marker_id"),g;for(g in c)d.removeCustomData(g);d.removeCustomData("list_marker_names");b&&(d.removeCustomData("list_marker_id"),delete a[e])}; +(function(){function a(a,b){return-1<(" "+a+" ").replace(g," ").indexOf(" "+b+" ")}function d(a){var b=!0;a.$.id||(a.$.id="cke_tmp_"+CKEDITOR.tools.getNextNumber(),b=!1);return function(){b||a.removeAttribute("id")}}function b(a,b){var c=CKEDITOR.tools.escapeCss(a.$.id);return"#"+c+" "+b.split(/,\s*/).join(", #"+c+" ")}function c(a){for(var b=0,c=0,f=k[a].length;cCKEDITOR.env.version?this.$.text+=a:this.append(new CKEDITOR.dom.text(a))},appendBogus:function(a){if(a||CKEDITOR.env.needsBrFiller){for(a=this.getLast();a&&a.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.rtrim(a.getText());)a=a.getPrevious();a&&a.is&&a.is("br")||(a=this.getDocument().createElement("br"),CKEDITOR.env.gecko&&a.setAttribute("type","_moz"),this.append(a))}},breakParent:function(a,b){var c=new CKEDITOR.dom.range(this.getDocument());c.setStartAfter(this);c.setEndAfter(a); +var f=c.extractContents(!1,b||!1),d;c.insertNode(this.remove());if(CKEDITOR.env.ie&&!CKEDITOR.env.edge){for(c=new CKEDITOR.dom.element("div");d=f.getFirst();)d.$.style.backgroundColor&&(d.$.style.backgroundColor=d.$.style.backgroundColor),c.append(d);c.insertAfter(this);c.remove(!0)}else f.insertAfterNode(this)},contains:document.compareDocumentPosition?function(a){return!!(this.$.compareDocumentPosition(a.$)&16)}:function(a){var b=this.$;return a.type!=CKEDITOR.NODE_ELEMENT?b.contains(a.getParent().$): +b!=a.$&&b.contains(a.$)},focus:function(){function a(){try{this.$.focus()}catch(b){}}return function(b){b?CKEDITOR.tools.setTimeout(a,100,this):a.call(this)}}(),getHtml:function(){var a=this.$.innerHTML;return CKEDITOR.env.ie?a.replace(/<\?[^>]*>/g,""):a},getOuterHtml:function(){if(this.$.outerHTML)return this.$.outerHTML.replace(/<\?[^>]*>/,"");var a=this.$.ownerDocument.createElement("div");a.appendChild(this.$.cloneNode(!0));return a.innerHTML},getClientRect:function(){var a=CKEDITOR.tools.extend({}, +this.$.getBoundingClientRect());!a.width&&(a.width=a.right-a.left);!a.height&&(a.height=a.bottom-a.top);return a},setHtml:CKEDITOR.env.ie&&9>CKEDITOR.env.version?function(a){try{var b=this.$;if(this.getParent())return b.innerHTML=a;var c=this.getDocument()._getHtml5ShivFrag();c.appendChild(b);b.innerHTML=a;c.removeChild(b);return a}catch(f){this.$.innerHTML="";b=new CKEDITOR.dom.element("body",this.getDocument());b.$.innerHTML=a;for(b=b.getChildren();b.count();)this.append(b.getItem(0));return a}}: +function(a){return this.$.innerHTML=a},setText:function(){var a=document.createElement("p");a.innerHTML="x";a=a.textContent;return function(b){this.$[a?"textContent":"innerText"]=b}}(),getAttribute:function(){var a=function(a){return this.$.getAttribute(a,2)};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(a){switch(a){case "class":a="className";break;case "http-equiv":a="httpEquiv";break;case "name":return this.$.name;case "tabindex":return a=this.$.getAttribute(a, +2),0!==a&&0===this.$.tabIndex&&(a=null),a;case "checked":return a=this.$.attributes.getNamedItem(a),(a.specified?a.nodeValue:this.$.checked)?"checked":null;case "hspace":case "value":return this.$[a];case "style":return this.$.style.cssText;case "contenteditable":case "contentEditable":return this.$.attributes.getNamedItem("contentEditable").specified?this.$.getAttribute("contentEditable"):null}return this.$.getAttribute(a,2)}:a}(),getAttributes:function(a){var b={},c=this.$.attributes,f;a=CKEDITOR.tools.isArray(a)? +a:[];for(f=0;f=document.documentMode){var b=this.$.scopeName;"HTML"!=b&&(a=b.toLowerCase()+":"+a)}this.getName=function(){return a};return this.getName()},getValue:function(){return this.$.value},getFirst:function(a){var b=this.$.firstChild;(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getNext(a));return b},getLast:function(a){var b=this.$.lastChild;(b=b&&new CKEDITOR.dom.node(b))&&a&&!a(b)&&(b=b.getPrevious(a));return b},getStyle:function(a){return this.$.style[CKEDITOR.tools.cssStyleToDomStyle(a)]}, +is:function(){var a=this.getName();if("object"==typeof arguments[0])return!!arguments[0][a];for(var b=0;bCKEDITOR.env.version&&this.is("a")){var c=this.getParent();c.type==CKEDITOR.NODE_ELEMENT&&(c=c.clone(),c.setHtml(b),b=c.getHtml(),c.setHtml(a),a=c.getHtml())}return b==a},isVisible:function(){var a=(this.$.offsetHeight||this.$.offsetWidth)&&"hidden"!=this.getComputedStyle("visibility"),b,c;a&&CKEDITOR.env.webkit&&(b=this.getWindow(),!b.equals(CKEDITOR.document.getWindow())&&(c=b.$.frameElement)&&(a=(new CKEDITOR.dom.element(c)).isVisible()));return!!a},isEmptyInlineRemoveable:function(){if(!CKEDITOR.dtd.$removeEmpty[this.getName()])return!1; +for(var a=this.getChildren(),b=0,c=a.count();bCKEDITOR.env.version?function(b){return"name"==b?!!this.$.name:a.call(this,b)}:a:function(a){return!!this.$.attributes.getNamedItem(a)}}(),hide:function(){this.setStyle("display","none")},moveChildren:function(a,b){var c=this.$;a=a.$;if(c!=a){var f;if(b)for(;f=c.lastChild;)a.insertBefore(c.removeChild(f),a.firstChild);else for(;f=c.firstChild;)a.appendChild(c.removeChild(f))}},mergeSiblings:function(){function a(b,c,f){if(c&&c.type==CKEDITOR.NODE_ELEMENT){for(var d= +[];c.data("cke-bookmark")||c.isEmptyInlineRemoveable();)if(d.push(c),c=f?c.getNext():c.getPrevious(),!c||c.type!=CKEDITOR.NODE_ELEMENT)return;if(b.isIdentical(c)){for(var h=f?b.getLast():b.getFirst();d.length;)d.shift().move(b,!f);c.moveChildren(b,!f);c.remove();h&&h.type==CKEDITOR.NODE_ELEMENT&&h.mergeSiblings()}}}return function(b){if(!1===b||CKEDITOR.dtd.$removeEmpty[this.getName()]||this.is("a"))a(this,this.getNext(),!0),a(this,this.getPrevious())}}(),show:function(){this.setStyles({display:"", +visibility:""})},setAttribute:function(){var a=function(a,b){this.$.setAttribute(a,b);return this};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(b,c){"class"==b?this.$.className=c:"style"==b?this.$.style.cssText=c:"tabindex"==b?this.$.tabIndex=c:"checked"==b?this.$.checked=c:"contenteditable"==b?a.call(this,"contentEditable",c):a.apply(this,arguments);return this}:CKEDITOR.env.ie8Compat&&CKEDITOR.env.secure?function(b,c){if("src"==b&&c.match(/^http:\/\//))try{a.apply(this, +arguments)}catch(f){}else a.apply(this,arguments);return this}:a}(),setAttributes:function(a){for(var b in a)this.setAttribute(b,a[b]);return this},setValue:function(a){this.$.value=a;return this},removeAttribute:function(){var a=function(a){this.$.removeAttribute(a)};return CKEDITOR.env.ie&&(CKEDITOR.env.ie7Compat||CKEDITOR.env.quirks)?function(a){"class"==a?a="className":"tabindex"==a?a="tabIndex":"contenteditable"==a&&(a="contentEditable");this.$.removeAttribute(a)}:a}(),removeAttributes:function(a){if(CKEDITOR.tools.isArray(a))for(var b= +0;bCKEDITOR.env.version?(a=Math.round(100*a),this.setStyle("filter",100<=a?"":"progid:DXImageTransform.Microsoft.Alpha(opacity\x3d"+a+")")):this.setStyle("opacity",a)},unselectable:function(){this.setStyles(CKEDITOR.tools.cssVendorPrefix("user-select", +"none"));if(CKEDITOR.env.ie){this.setAttribute("unselectable","on");for(var a,b=this.getElementsByTag("*"),c=0,f=b.count();cz||0z?z:d);c&&(0>e||0e?e:f,0)},setState:function(a,b,c){b=b||"cke";switch(a){case CKEDITOR.TRISTATE_ON:this.addClass(b+"_on");this.removeClass(b+ +"_off");this.removeClass(b+"_disabled");c&&this.setAttribute("aria-pressed",!0);c&&this.removeAttribute("aria-disabled");break;case CKEDITOR.TRISTATE_DISABLED:this.addClass(b+"_disabled");this.removeClass(b+"_off");this.removeClass(b+"_on");c&&this.setAttribute("aria-disabled",!0);c&&this.removeAttribute("aria-pressed");break;default:this.addClass(b+"_off"),this.removeClass(b+"_on"),this.removeClass(b+"_disabled"),c&&this.removeAttribute("aria-pressed"),c&&this.removeAttribute("aria-disabled")}}, +getFrameDocument:function(){var a=this.$;try{a.contentWindow.document}catch(b){a.src=a.src}return a&&new CKEDITOR.dom.document(a.contentWindow.document)},copyAttributes:function(a,b){var c=this.$.attributes;b=b||{};for(var f=0;f=n.getChildCount()?(n=n.getChild(A-1),D=!0):n=n.getChild(A):H=D=!0;q.type==CKEDITOR.NODE_TEXT?l?p=!0:q.split(t):0fa)for(;X;)X=m(X,K,!0);K=L}l||h()}}function b(){var a=!1,b=CKEDITOR.dom.walker.whitespaces(), +c=CKEDITOR.dom.walker.bookmark(!0),d=CKEDITOR.dom.walker.bogus();return function(e){return c(e)||b(e)?!0:d(e)&&!a?a=!0:e.type==CKEDITOR.NODE_TEXT&&(e.hasAscendant("pre")||CKEDITOR.tools.trim(e.getText()).length)||e.type==CKEDITOR.NODE_ELEMENT&&!e.is(g)?!1:!0}}function c(a){var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(1);return function(d){return c(d)||b(d)?!0:!a&&k(d)||d.type==CKEDITOR.NODE_ELEMENT&&d.is(CKEDITOR.dtd.$removeEmpty)}}function e(a){return function(){var b;return this[a? +"getPreviousNode":"getNextNode"](function(a){!b&&r(a)&&(b=a);return p(a)&&!(k(a)&&a.equals(b))})}}var g={abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,"var":1},k=CKEDITOR.dom.walker.bogus(),h=/^[\t\r\n ]*(?: |\xa0)$/,p=CKEDITOR.dom.walker.editable(),r=CKEDITOR.dom.walker.ignored(!0);CKEDITOR.dom.range.prototype={clone:function(){var a=new CKEDITOR.dom.range(this.root);a._setStartContainer(this.startContainer); +a.startOffset=this.startOffset;a._setEndContainer(this.endContainer);a.endOffset=this.endOffset;a.collapsed=this.collapsed;return a},collapse:function(a){a?(this._setEndContainer(this.startContainer),this.endOffset=this.startOffset):(this._setStartContainer(this.endContainer),this.startOffset=this.endOffset);this.collapsed=!0},cloneContents:function(a){var b=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||d(this,2,b,!1,"undefined"==typeof a?!0:a);return b},deleteContents:function(a){this.collapsed|| +d(this,0,null,a)},extractContents:function(a,b){var c=new CKEDITOR.dom.documentFragment(this.document);this.collapsed||d(this,1,c,a,"undefined"==typeof b?!0:b);return c},createBookmark:function(a){var b,c,d,e,m=this.collapsed;b=this.document.createElement("span");b.data("cke-bookmark",1);b.setStyle("display","none");b.setHtml("\x26nbsp;");a&&(d="cke_bm_"+CKEDITOR.tools.getNextNumber(),b.setAttribute("id",d+(m?"C":"S")));m||(c=b.clone(),c.setHtml("\x26nbsp;"),a&&c.setAttribute("id",d+"E"),e=this.clone(), +e.collapse(),e.insertNode(c));e=this.clone();e.collapse(!0);e.insertNode(b);c?(this.setStartAfter(b),this.setEndBefore(c)):this.moveToPosition(b,CKEDITOR.POSITION_AFTER_END);return{startNode:a?d+(m?"C":"S"):b,endNode:a?d+"E":c,serializable:a,collapsed:m}},createBookmark2:function(){function a(b){var f=b.container,d=b.offset,e;e=f;var g=d;e=e.type!=CKEDITOR.NODE_ELEMENT||0===g||g==e.getChildCount()?0:e.getChild(g-1).type==CKEDITOR.NODE_TEXT&&e.getChild(g).type==CKEDITOR.NODE_TEXT;e&&(f=f.getChild(d- +1),d=f.getLength());if(f.type==CKEDITOR.NODE_ELEMENT&&0=a.offset&&(a.offset=d.getIndex(),a.container=d.getParent()))}}var c=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_TEXT,!0);return function(c){var d=this.collapsed,e={container:this.startContainer,offset:this.startOffset},g={container:this.endContainer,offset:this.endOffset};c&&(a(e),b(e,this.root),d||(a(g),b(g,this.root)));return{start:e.container.getAddress(c),end:d?null:g.container.getAddress(c), +startOffset:e.offset,endOffset:g.offset,normalized:c,collapsed:d,is2:!0}}}(),moveToBookmark:function(a){if(a.is2){var b=this.document.getByAddress(a.start,a.normalized),c=a.startOffset,d=a.end&&this.document.getByAddress(a.end,a.normalized);a=a.endOffset;this.setStart(b,c);d?this.setEnd(d,a):this.collapse(!0)}else b=(c=a.serializable)?this.document.getById(a.startNode):a.startNode,a=c?this.document.getById(a.endNode):a.endNode,this.setStartBefore(b),b.remove(),a?(this.setEndBefore(a),a.remove()): +this.collapse(!0)},getBoundaryNodes:function(){var a=this.startContainer,b=this.endContainer,c=this.startOffset,d=this.endOffset,e;if(a.type==CKEDITOR.NODE_ELEMENT)if(e=a.getChildCount(),e>c)a=a.getChild(c);else if(1>e)a=a.getPreviousSourceNode();else{for(a=a.$;a.lastChild;)a=a.lastChild;a=new CKEDITOR.dom.node(a);a=a.getNextSourceNode()||a}if(b.type==CKEDITOR.NODE_ELEMENT)if(e=b.getChildCount(),e>d)b=b.getChild(d).getPreviousSourceNode(!0);else if(1>e)b=b.getPreviousSourceNode();else{for(b=b.$;b.lastChild;)b= +b.lastChild;b=new CKEDITOR.dom.node(b)}a.getPosition(b)&CKEDITOR.POSITION_FOLLOWING&&(a=b);return{startNode:a,endNode:b}},getCommonAncestor:function(a,b){var c=this.startContainer,d=this.endContainer,c=c.equals(d)?a&&c.type==CKEDITOR.NODE_ELEMENT&&this.startOffset==this.endOffset-1?c.getChild(this.startOffset):c:c.getCommonAncestor(d);return b&&!c.is?c.getParent():c},optimize:function(){var a=this.startContainer,b=this.startOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setStartAfter(a): +this.setStartBefore(a));a=this.endContainer;b=this.endOffset;a.type!=CKEDITOR.NODE_ELEMENT&&(b?b>=a.getLength()&&this.setEndAfter(a):this.setEndBefore(a))},optimizeBookmark:function(){var a=this.startContainer,b=this.endContainer;a.is&&a.is("span")&&a.data("cke-bookmark")&&this.setStartAt(a,CKEDITOR.POSITION_BEFORE_START);b&&b.is&&b.is("span")&&b.data("cke-bookmark")&&this.setEndAt(b,CKEDITOR.POSITION_AFTER_END)},trim:function(a,b){var c=this.startContainer,d=this.startOffset,e=this.collapsed;if((!a|| +e)&&c&&c.type==CKEDITOR.NODE_TEXT){if(d)if(d>=c.getLength())d=c.getIndex()+1,c=c.getParent();else{var m=c.split(d),d=c.getIndex()+1,c=c.getParent();this.startContainer.equals(this.endContainer)?this.setEnd(m,this.endOffset-this.startOffset):c.equals(this.endContainer)&&(this.endOffset+=1)}else d=c.getIndex(),c=c.getParent();this.setStart(c,d);if(e){this.collapse(!0);return}}c=this.endContainer;d=this.endOffset;b||e||!c||c.type!=CKEDITOR.NODE_TEXT||(d?(d>=c.getLength()||c.split(d),d=c.getIndex()+1): +d=c.getIndex(),c=c.getParent(),this.setEnd(c,d))},enlarge:function(a,b){function c(a){return a&&a.type==CKEDITOR.NODE_ELEMENT&&a.hasAttribute("contenteditable")?null:a}var d=new RegExp(/[^\s\ufeff]/);switch(a){case CKEDITOR.ENLARGE_INLINE:var e=1;case CKEDITOR.ENLARGE_ELEMENT:var m=function(a,b){var c=new CKEDITOR.dom.range(h);c.setStart(a,b);c.setEndAt(h,CKEDITOR.POSITION_BEFORE_END);var c=new CKEDITOR.dom.walker(c),f;for(c.guard=function(a){return!(a.type==CKEDITOR.NODE_ELEMENT&&a.isBlockBoundary())};f= +c.next();){if(f.type!=CKEDITOR.NODE_TEXT)return!1;C=f!=a?f.getText():f.substring(b);if(d.test(C))return!1}return!0};if(this.collapsed)break;var g=this.getCommonAncestor(),h=this.root,k,r,l,q,n,t=!1,A,C;A=this.startContainer;var D=this.startOffset;A.type==CKEDITOR.NODE_TEXT?(D&&(A=!CKEDITOR.tools.trim(A.substring(0,D)).length&&A,t=!!A),A&&((q=A.getPrevious())||(l=A.getParent()))):(D&&(q=A.getChild(D-1)||A.getLast()),q||(l=A));for(l=c(l);l||q;){if(l&&!q){!n&&l.equals(g)&&(n=!0);if(e?l.isBlockBoundary(): +!h.contains(l))break;t&&"inline"==l.getComputedStyle("display")||(t=!1,n?k=l:this.setStartBefore(l));q=l.getPrevious()}for(;q;)if(A=!1,q.type==CKEDITOR.NODE_COMMENT)q=q.getPrevious();else{if(q.type==CKEDITOR.NODE_TEXT)C=q.getText(),d.test(C)&&(q=null),A=/[\s\ufeff]$/.test(C);else if((q.$.offsetWidth>(CKEDITOR.env.webkit?1:0)||b&&q.is("br"))&&!q.data("cke-bookmark"))if(t&&CKEDITOR.dtd.$removeEmpty[q.getName()]){C=q.getText();if(d.test(C))q=null;else for(var D=q.$.getElementsByTagName("*"),M=0,H;H= +D[M++];)if(!CKEDITOR.dtd.$removeEmpty[H.nodeName.toLowerCase()]){q=null;break}q&&(A=!!C.length)}else q=null;A&&(t?n?k=l:l&&this.setStartBefore(l):t=!0);if(q){A=q.getPrevious();if(!l&&!A){l=q;q=null;break}q=A}else l=null}l&&(l=c(l.getParent()))}A=this.endContainer;D=this.endOffset;l=q=null;n=t=!1;A.type==CKEDITOR.NODE_TEXT?CKEDITOR.tools.trim(A.substring(D)).length?t=!0:(t=!A.getLength(),D==A.getLength()?(q=A.getNext())||(l=A.getParent()):m(A,D)&&(l=A.getParent())):(q=A.getChild(D))||(l=A);for(;l|| +q;){if(l&&!q){!n&&l.equals(g)&&(n=!0);if(e?l.isBlockBoundary():!h.contains(l))break;t&&"inline"==l.getComputedStyle("display")||(t=!1,n?r=l:l&&this.setEndAfter(l));q=l.getNext()}for(;q;){A=!1;if(q.type==CKEDITOR.NODE_TEXT)C=q.getText(),m(q,0)||(q=null),A=/^[\s\ufeff]/.test(C);else if(q.type==CKEDITOR.NODE_ELEMENT){if((0=e.getLength()?d.setStartAfter(e):(d.setStartBefore(e),k=0):d.setStartBefore(e));m&&m.type==CKEDITOR.NODE_TEXT&&(h?h>=m.getLength()?d.setEndAfter(m): +(d.setEndAfter(m),r=0):d.setEndBefore(m));var d=new CKEDITOR.dom.walker(d),l=CKEDITOR.dom.walker.bookmark();d.evaluator=function(b){return b.type==(a==CKEDITOR.SHRINK_ELEMENT?CKEDITOR.NODE_ELEMENT:CKEDITOR.NODE_TEXT)};var q;d.guard=function(b,d){if(l(b))return!0;if(a==CKEDITOR.SHRINK_ELEMENT&&b.type==CKEDITOR.NODE_TEXT||d&&b.equals(q)||!1===c&&b.type==CKEDITOR.NODE_ELEMENT&&b.isBlockBoundary()||b.type==CKEDITOR.NODE_ELEMENT&&b.hasAttribute("contenteditable"))return!1;d||b.type!=CKEDITOR.NODE_ELEMENT|| +(q=b);return!0};k&&(e=d[a==CKEDITOR.SHRINK_ELEMENT?"lastForward":"next"]())&&this.setStartAt(e,b?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_START);r&&(d.reset(),(d=d[a==CKEDITOR.SHRINK_ELEMENT?"lastBackward":"previous"]())&&this.setEndAt(d,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_END));return!(!k&&!r)}},insertNode:function(a){this.optimizeBookmark();this.trim(!1,!0);var b=this.startContainer,c=b.getChild(this.startOffset);c?a.insertBefore(c):b.append(a);a.getParent()&&a.getParent().equals(this.endContainer)&& +this.endOffset++;this.setStartBefore(a)},moveToPosition:function(a,b){this.setStartAt(a,b);this.collapse(!0)},moveToRange:function(a){this.setStart(a.startContainer,a.startOffset);this.setEnd(a.endContainer,a.endOffset)},selectNodeContents:function(a){this.setStart(a,0);this.setEnd(a,a.type==CKEDITOR.NODE_TEXT?a.getLength():a.getChildCount())},setStart:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex(),b=b.getParent());this._setStartContainer(b);this.startOffset= +c;this.endContainer||(this._setEndContainer(b),this.endOffset=c);a(this)},setEnd:function(b,c){b.type==CKEDITOR.NODE_ELEMENT&&CKEDITOR.dtd.$empty[b.getName()]&&(c=b.getIndex()+1,b=b.getParent());this._setEndContainer(b);this.endOffset=c;this.startContainer||(this._setStartContainer(b),this.startOffset=c);a(this)},setStartAfter:function(a){this.setStart(a.getParent(),a.getIndex()+1)},setStartBefore:function(a){this.setStart(a.getParent(),a.getIndex())},setEndAfter:function(a){this.setEnd(a.getParent(), +a.getIndex()+1)},setEndBefore:function(a){this.setEnd(a.getParent(),a.getIndex())},setStartAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setStart(b,0);break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setStart(b,b.getLength()):this.setStart(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setStartBefore(b);break;case CKEDITOR.POSITION_AFTER_END:this.setStartAfter(b)}a(this)},setEndAt:function(b,c){switch(c){case CKEDITOR.POSITION_AFTER_START:this.setEnd(b, +0);break;case CKEDITOR.POSITION_BEFORE_END:b.type==CKEDITOR.NODE_TEXT?this.setEnd(b,b.getLength()):this.setEnd(b,b.getChildCount());break;case CKEDITOR.POSITION_BEFORE_START:this.setEndBefore(b);break;case CKEDITOR.POSITION_AFTER_END:this.setEndAfter(b)}a(this)},fixBlock:function(a,b){var c=this.createBookmark(),d=this.document.createElement(b);this.collapse(a);this.enlarge(CKEDITOR.ENLARGE_BLOCK_CONTENTS);this.extractContents().appendTo(d);d.trim();this.insertNode(d);var e=d.getBogus();e&&e.remove(); +d.appendBogus();this.moveToBookmark(c);return d},splitBlock:function(a,b){var c=new CKEDITOR.dom.elementPath(this.startContainer,this.root),d=new CKEDITOR.dom.elementPath(this.endContainer,this.root),e=c.block,m=d.block,g=null;if(!c.blockLimit.equals(d.blockLimit))return null;"br"!=a&&(e||(e=this.fixBlock(!0,a),m=(new CKEDITOR.dom.elementPath(this.endContainer,this.root)).block),m||(m=this.fixBlock(!1,a)));c=e&&this.checkStartOfBlock();d=m&&this.checkEndOfBlock();this.deleteContents();e&&e.equals(m)&& +(d?(g=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(m,CKEDITOR.POSITION_AFTER_END),m=null):c?(g=new CKEDITOR.dom.elementPath(this.startContainer,this.root),this.moveToPosition(e,CKEDITOR.POSITION_BEFORE_START),e=null):(m=this.splitElement(e,b||!1),e.is("ul","ol")||e.appendBogus()));return{previousBlock:e,nextBlock:m,wasStartOfBlock:c,wasEndOfBlock:d,elementPath:g}},splitElement:function(a,b){if(!this.collapsed)return null;this.setEndAt(a,CKEDITOR.POSITION_BEFORE_END); +var c=this.extractContents(!1,b||!1),d=a.clone(!1,b||!1);c.appendTo(d);d.insertAfter(a);this.moveToPosition(a,CKEDITOR.POSITION_AFTER_END);return d},removeEmptyBlocksAtEnd:function(){function a(d){return function(a){return b(a)||c(a)||a.type==CKEDITOR.NODE_ELEMENT&&a.isEmptyInlineRemoveable()||d.is("table")&&a.is("caption")?!1:!0}}var b=CKEDITOR.dom.walker.whitespaces(),c=CKEDITOR.dom.walker.bookmark(!1);return function(b){for(var c=this.createBookmark(),d=this[b?"endPath":"startPath"](),e=d.block|| +d.blockLimit,g;e&&!e.equals(d.root)&&!e.getFirst(a(e));)g=e.getParent(),this[b?"setEndAt":"setStartAt"](e,CKEDITOR.POSITION_AFTER_END),e.remove(1),e=g;this.moveToBookmark(c)}}(),startPath:function(){return new CKEDITOR.dom.elementPath(this.startContainer,this.root)},endPath:function(){return new CKEDITOR.dom.elementPath(this.endContainer,this.root)},checkBoundaryOfElement:function(a,b){var d=b==CKEDITOR.START,e=this.clone();e.collapse(d);e[d?"setStartAt":"setEndAt"](a,d?CKEDITOR.POSITION_AFTER_START: +CKEDITOR.POSITION_BEFORE_END);e=new CKEDITOR.dom.walker(e);e.evaluator=c(d);return e[d?"checkBackward":"checkForward"]()},checkStartOfBlock:function(){var a=this.startContainer,c=this.startOffset;CKEDITOR.env.ie&&c&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.ltrim(a.substring(0,c)),h.test(a)&&this.trim(0,1));this.trim();a=new CKEDITOR.dom.elementPath(this.startContainer,this.root);c=this.clone();c.collapse(!0);c.setStartAt(a.block||a.blockLimit,CKEDITOR.POSITION_AFTER_START);a=new CKEDITOR.dom.walker(c); +a.evaluator=b();return a.checkBackward()},checkEndOfBlock:function(){var a=this.endContainer,c=this.endOffset;CKEDITOR.env.ie&&a.type==CKEDITOR.NODE_TEXT&&(a=CKEDITOR.tools.rtrim(a.substring(c)),h.test(a)&&this.trim(1,0));this.trim();a=new CKEDITOR.dom.elementPath(this.endContainer,this.root);c=this.clone();c.collapse(!1);c.setEndAt(a.block||a.blockLimit,CKEDITOR.POSITION_BEFORE_END);a=new CKEDITOR.dom.walker(c);a.evaluator=b();return a.checkForward()},getPreviousNode:function(a,b,c){var d=this.clone(); +d.collapse(1);d.setStartAt(c||this.root,CKEDITOR.POSITION_AFTER_START);c=new CKEDITOR.dom.walker(d);c.evaluator=a;c.guard=b;return c.previous()},getNextNode:function(a,b,c){var d=this.clone();d.collapse();d.setEndAt(c||this.root,CKEDITOR.POSITION_BEFORE_END);c=new CKEDITOR.dom.walker(d);c.evaluator=a;c.guard=b;return c.next()},checkReadOnly:function(){function a(b,c){for(;b;){if(b.type==CKEDITOR.NODE_ELEMENT){if("false"==b.getAttribute("contentEditable")&&!b.data("cke-editable"))return 0;if(b.is("html")|| +"true"==b.getAttribute("contentEditable")&&(b.contains(c)||b.equals(c)))break}b=b.getParent()}return 1}return function(){var b=this.startContainer,c=this.endContainer;return!(a(b,c)&&a(c,b))}}(),moveToElementEditablePosition:function(a,b){if(a.type==CKEDITOR.NODE_ELEMENT&&!a.isEditable(!1))return this.moveToPosition(a,b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START),!0;for(var c=0;a;){if(a.type==CKEDITOR.NODE_TEXT){b&&this.endContainer&&this.checkEndOfBlock()&&h.test(a.getText())?this.moveToPosition(a, +CKEDITOR.POSITION_BEFORE_START):this.moveToPosition(a,b?CKEDITOR.POSITION_AFTER_END:CKEDITOR.POSITION_BEFORE_START);c=1;break}if(a.type==CKEDITOR.NODE_ELEMENT)if(a.isEditable())this.moveToPosition(a,b?CKEDITOR.POSITION_BEFORE_END:CKEDITOR.POSITION_AFTER_START),c=1;else if(b&&a.is("br")&&this.endContainer&&this.checkEndOfBlock())this.moveToPosition(a,CKEDITOR.POSITION_BEFORE_START);else if("false"==a.getAttribute("contenteditable")&&a.is(CKEDITOR.dtd.$block))return this.setStartBefore(a),this.setEndAfter(a), +!0;var d=a,e=c,m=void 0;d.type==CKEDITOR.NODE_ELEMENT&&d.isEditable(!1)&&(m=d[b?"getLast":"getFirst"](r));e||m||(m=d[b?"getPrevious":"getNext"](r));a=m}return!!c},moveToClosestEditablePosition:function(a,b){var c,d=0,e,m,g=[CKEDITOR.POSITION_AFTER_END,CKEDITOR.POSITION_BEFORE_START];a?(c=new CKEDITOR.dom.range(this.root),c.moveToPosition(a,g[b?0:1])):c=this.clone();if(a&&!a.is(CKEDITOR.dtd.$block))d=1;else if(e=c[b?"getNextEditableNode":"getPreviousEditableNode"]())d=1,(m=e.type==CKEDITOR.NODE_ELEMENT)&& +e.is(CKEDITOR.dtd.$block)&&"false"==e.getAttribute("contenteditable")?(c.setStartAt(e,CKEDITOR.POSITION_BEFORE_START),c.setEndAt(e,CKEDITOR.POSITION_AFTER_END)):!CKEDITOR.env.needsBrFiller&&m&&e.is(CKEDITOR.dom.walker.validEmptyBlockContainers)?(c.setEnd(e,0),c.collapse()):c.moveToPosition(e,g[b?1:0]);d&&this.moveToRange(c);return!!d},moveToElementEditStart:function(a){return this.moveToElementEditablePosition(a)},moveToElementEditEnd:function(a){return this.moveToElementEditablePosition(a,!0)},getEnclosedNode:function(){var a= +this.clone();a.optimize();if(a.startContainer.type!=CKEDITOR.NODE_ELEMENT||a.endContainer.type!=CKEDITOR.NODE_ELEMENT)return null;var a=new CKEDITOR.dom.walker(a),b=CKEDITOR.dom.walker.bookmark(!1,!0),c=CKEDITOR.dom.walker.whitespaces(!0);a.evaluator=function(a){return c(a)&&b(a)};var d=a.next();a.reset();return d&&d.equals(a.previous())?d:null},getTouchedStartNode:function(){var a=this.startContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.startOffset)||a},getTouchedEndNode:function(){var a= +this.endContainer;return this.collapsed||a.type!=CKEDITOR.NODE_ELEMENT?a:a.getChild(this.endOffset-1)||a},getNextEditableNode:e(),getPreviousEditableNode:e(1),scrollIntoView:function(){var a=new CKEDITOR.dom.element.createFromHtml("\x3cspan\x3e\x26nbsp;\x3c/span\x3e",this.document),b,c,d,e=this.clone();e.optimize();(d=e.startContainer.type==CKEDITOR.NODE_TEXT)?(c=e.startContainer.getText(),b=e.startContainer.split(e.startOffset),a.insertAfter(e.startContainer)):e.insertNode(a);a.scrollIntoView(); +d&&(e.startContainer.setText(c),b.remove());a.remove()},_setStartContainer:function(a){this.startContainer=a},_setEndContainer:function(a){this.endContainer=a},_find:function(a,b){var c=this.getCommonAncestor(),d=this.getBoundaryNodes(),e=[],m,g,h,k;if(c&&c.find)for(g=c.find(a),m=0;marguments.length||(this.range=a,this.forceBrBreak=0,this.enlargeBr=1,this.enforceRealBlocks=0,this._||(this._={}))}function d(a){var b=[];a.forEach(function(a){if("true"==a.getAttribute("contenteditable"))return b.push(a),!1},CKEDITOR.NODE_ELEMENT,!0);return b}function b(a,c,e,g){a:{null==g&&(g=d(e));for(var h;h=g.shift();)if(h.getDtd().p){g={element:h,remaining:g};break a}g=null}if(!g)return 0;if((h=CKEDITOR.filter.instances[g.element.data("cke-filter")])&&!h.check(c))return b(a, +c,e,g.remaining);c=new CKEDITOR.dom.range(g.element);c.selectNodeContents(g.element);c=c.createIterator();c.enlargeBr=a.enlargeBr;c.enforceRealBlocks=a.enforceRealBlocks;c.activeFilter=c.filter=h;a._.nestedEditable={element:g.element,container:e,remaining:g.remaining,iterator:c};return 1}function c(a,b,c){if(!b)return!1;a=a.clone();a.collapse(!c);return a.checkBoundaryOfElement(b,c?CKEDITOR.START:CKEDITOR.END)}var e=/^[\r\n\t ]+$/,g=CKEDITOR.dom.walker.bookmark(!1,!0),k=CKEDITOR.dom.walker.whitespaces(!0), +h=function(a){return g(a)&&k(a)},p={dd:1,dt:1,li:1};a.prototype={getNextParagraph:function(a){var d,k,u,z,y;a=a||"p";if(this._.nestedEditable){if(d=this._.nestedEditable.iterator.getNextParagraph(a))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,d;this.activeFilter=this.filter;if(b(this,a,this._.nestedEditable.container,this._.nestedEditable.remaining))return this.activeFilter=this._.nestedEditable.iterator.activeFilter,this._.nestedEditable.iterator.getNextParagraph(a);this._.nestedEditable= +null}if(!this.range.root.getDtd()[a])return null;if(!this._.started){var m=this.range.clone();k=m.startPath();var x=m.endPath(),J=!m.collapsed&&c(m,k.block),w=!m.collapsed&&c(m,x.block,1);m.shrink(CKEDITOR.SHRINK_ELEMENT,!0);J&&m.setStartAt(k.block,CKEDITOR.POSITION_BEFORE_END);w&&m.setEndAt(x.block,CKEDITOR.POSITION_AFTER_START);k=m.endContainer.hasAscendant("pre",!0)||m.startContainer.hasAscendant("pre",!0);m.enlarge(this.forceBrBreak&&!k||!this.enlargeBr?CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:CKEDITOR.ENLARGE_BLOCK_CONTENTS); +m.collapsed||(k=new CKEDITOR.dom.walker(m.clone()),x=CKEDITOR.dom.walker.bookmark(!0,!0),k.evaluator=x,this._.nextNode=k.next(),k=new CKEDITOR.dom.walker(m.clone()),k.evaluator=x,k=k.previous(),this._.lastNode=k.getNextSourceNode(!0,null,m.root),this._.lastNode&&this._.lastNode.type==CKEDITOR.NODE_TEXT&&!CKEDITOR.tools.trim(this._.lastNode.getText())&&this._.lastNode.getParent().isBlockBoundary()&&(x=this.range.clone(),x.moveToPosition(this._.lastNode,CKEDITOR.POSITION_AFTER_END),x.checkEndOfBlock()&& +(x=new CKEDITOR.dom.elementPath(x.endContainer,x.root),this._.lastNode=(x.block||x.blockLimit).getNextSourceNode(!0))),this._.lastNode&&m.root.contains(this._.lastNode)||(this._.lastNode=this._.docEndMarker=m.document.createText(""),this._.lastNode.insertAfter(k)),m=null);this._.started=1;k=m}x=this._.nextNode;m=this._.lastNode;for(this._.nextNode=null;x;){var J=0,w=x.hasAscendant("pre"),F=x.type!=CKEDITOR.NODE_ELEMENT,l=0;if(F)x.type==CKEDITOR.NODE_TEXT&&e.test(x.getText())&&(F=0);else{var q=x.getName(); +if(CKEDITOR.dtd.$block[q]&&"false"==x.getAttribute("contenteditable")){d=x;b(this,a,d);break}else if(x.isBlockBoundary(this.forceBrBreak&&!w&&{br:1})){if("br"==q)F=1;else if(!k&&!x.getChildCount()&&"hr"!=q){d=x;u=x.equals(m);break}k&&(k.setEndAt(x,CKEDITOR.POSITION_BEFORE_START),"br"!=q&&(this._.nextNode=x));J=1}else{if(x.getFirst()){k||(k=this.range.clone(),k.setStartAt(x,CKEDITOR.POSITION_BEFORE_START));x=x.getFirst();continue}F=1}}F&&!k&&(k=this.range.clone(),k.setStartAt(x,CKEDITOR.POSITION_BEFORE_START)); +u=(!J||F)&&x.equals(m);if(k&&!J)for(;!x.getNext(h)&&!u;){q=x.getParent();if(q.isBlockBoundary(this.forceBrBreak&&!w&&{br:1})){J=1;F=0;u||q.equals(m);k.setEndAt(q,CKEDITOR.POSITION_BEFORE_END);break}x=q;F=1;u=x.equals(m);l=1}F&&k.setEndAt(x,CKEDITOR.POSITION_AFTER_END);x=this._getNextSourceNode(x,l,m);if((u=!x)||J&&k)break}if(!d){if(!k)return this._.docEndMarker&&this._.docEndMarker.remove(),this._.nextNode=null;d=new CKEDITOR.dom.elementPath(k.startContainer,k.root);x=d.blockLimit;J={div:1,th:1,td:1}; +d=d.block;!d&&x&&!this.enforceRealBlocks&&J[x.getName()]&&k.checkStartOfBlock()&&k.checkEndOfBlock()&&!x.equals(k.root)?d=x:!d||this.enforceRealBlocks&&d.is(p)?(d=this.range.document.createElement(a),k.extractContents().appendTo(d),d.trim(),k.insertNode(d),z=y=!0):"li"!=d.getName()?k.checkStartOfBlock()&&k.checkEndOfBlock()||(d=d.clone(!1),k.extractContents().appendTo(d),d.trim(),y=k.splitBlock(),z=!y.wasStartOfBlock,y=!y.wasEndOfBlock,k.insertNode(d)):u||(this._.nextNode=d.equals(m)?null:this._getNextSourceNode(k.getBoundaryNodes().endNode, +1,m))}z&&(z=d.getPrevious())&&z.type==CKEDITOR.NODE_ELEMENT&&("br"==z.getName()?z.remove():z.getLast()&&"br"==z.getLast().$.nodeName.toLowerCase()&&z.getLast().remove());y&&(z=d.getLast())&&z.type==CKEDITOR.NODE_ELEMENT&&"br"==z.getName()&&(!CKEDITOR.env.needsBrFiller||z.getPrevious(g)||z.getNext(g))&&z.remove();this._.nextNode||(this._.nextNode=u||d.equals(m)||!m?null:this._getNextSourceNode(d,1,m));return d},_getNextSourceNode:function(a,b,c){function d(a){return!(a.equals(c)||a.equals(e))}var e= +this.range.root;for(a=a.getNextSourceNode(b,null,d);!g(a);)a=a.getNextSourceNode(b,null,d);return a}};CKEDITOR.dom.range.prototype.createIterator=function(){return new a(this)}})(); +CKEDITOR.command=function(a,d){this.uiItems=[];this.exec=function(b){if(this.state==CKEDITOR.TRISTATE_DISABLED||!this.checkAllowed())return!1;this.editorFocus&&a.focus();return!1===this.fire("exec")?!0:!1!==d.exec.call(this,a,b)};this.refresh=function(a,b){if(!this.readOnly&&a.readOnly)return!0;if(this.context&&!b.isContextFor(this.context)||!this.checkAllowed(!0))return this.disable(),!0;this.startDisabled||this.enable();this.modes&&!this.modes[a.mode]&&this.disable();return!1===this.fire("refresh", +{editor:a,path:b})?!0:d.refresh&&!1!==d.refresh.apply(this,arguments)};var b;this.checkAllowed=function(c){return c||"boolean"!=typeof b?b=a.activeFilter.checkFeature(this):b};CKEDITOR.tools.extend(this,d,{modes:{wysiwyg:1},editorFocus:1,contextSensitive:!!d.context,state:CKEDITOR.TRISTATE_DISABLED});CKEDITOR.event.call(this)}; +CKEDITOR.command.prototype={enable:function(){this.state==CKEDITOR.TRISTATE_DISABLED&&this.checkAllowed()&&this.setState(this.preserveState&&"undefined"!=typeof this.previousState?this.previousState:CKEDITOR.TRISTATE_OFF)},disable:function(){this.setState(CKEDITOR.TRISTATE_DISABLED)},setState:function(a){if(this.state==a||a!=CKEDITOR.TRISTATE_DISABLED&&!this.checkAllowed())return!1;this.previousState=this.state;this.state=a;this.fire("state");return!0},toggleState:function(){this.state==CKEDITOR.TRISTATE_OFF? +this.setState(CKEDITOR.TRISTATE_ON):this.state==CKEDITOR.TRISTATE_ON&&this.setState(CKEDITOR.TRISTATE_OFF)}};CKEDITOR.event.implementOn(CKEDITOR.command.prototype);CKEDITOR.ENTER_P=1;CKEDITOR.ENTER_BR=2;CKEDITOR.ENTER_DIV=3; +CKEDITOR.config={customConfig:"config.js",autoUpdateElement:!0,language:"",defaultLanguage:"en",contentsLangDirection:"",enterMode:CKEDITOR.ENTER_P,forceEnterMode:!1,shiftEnterMode:CKEDITOR.ENTER_BR,docType:"\x3c!DOCTYPE html\x3e",bodyId:"",bodyClass:"",fullPage:!1,height:200,contentsCss:CKEDITOR.getUrl("contents.css"),extraPlugins:"",removePlugins:"",protectedSource:[],tabIndex:0,width:"",baseFloatZIndex:1E4,blockedKeystrokes:[CKEDITOR.CTRL+66,CKEDITOR.CTRL+73,CKEDITOR.CTRL+85]}; +(function(){function a(a,b,c,d,l){var e,q;a=[];for(e in b){q=b[e];q="boolean"==typeof q?{}:"function"==typeof q?{match:q}:M(q);"$"!=e.charAt(0)&&(q.elements=e);c&&(q.featureName=c.toLowerCase());var n=q;n.elements=k(n.elements,/\s+/)||null;n.propertiesOnly=n.propertiesOnly||!0===n.elements;var f=/\s*,\s*/,t=void 0;for(t in Q){n[t]=k(n[t],f)||null;var m=n,g=P[t],E=k(n[P[t]],f),v=n[t],A=[],I=!0,C=void 0;E?I=!1:E={};for(C in v)"!"==C.charAt(0)&&(C=C.slice(1),A.push(C),E[C]=!0,I=!1);for(;C=A.pop();)v[C]= +v["!"+C],delete v["!"+C];m[g]=(I?!1:E)||null}n.match=n.match||null;d.push(q);a.push(q)}b=l.elements;l=l.generic;var h;c=0;for(d=a.length;c=--h&&(g&&CKEDITOR.document.getDocumentElement().removeStyle("cursor"),f(b))},u=function(b,c){a[b]=1;var e=d[b];delete d[b];for(var f=0;f=CKEDITOR.env.version||CKEDITOR.env.ie9Compat)?f.$.onreadystatechange=function(){if("loaded"==f.$.readyState||"complete"==f.$.readyState)f.$.onreadystatechange=null,u(b,!0)}:(f.$.onload=function(){setTimeout(function(){u(b,!0)},0)},f.$.onerror=function(){u(b,!1)}));f.appendTo(CKEDITOR.document.getHead())}}};g&&CKEDITOR.document.getDocumentElement().setStyle("cursor","wait");for(var y=0;y]+)>)|(?:!--([\S|\s]*?)--\x3e)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/g}}; +(function(){var a=/([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g,d={checked:1,compact:1,declare:1,defer:1,disabled:1,ismap:1,multiple:1,nohref:1,noresize:1,noshade:1,nowrap:1,readonly:1,selected:1};CKEDITOR.htmlParser.prototype={onTagOpen:function(){},onTagClose:function(){},onText:function(){},onCDATA:function(){},onComment:function(){},parse:function(b){for(var c,e,g=0,k;c=this._.htmlPartsRegex.exec(b);){e=c.index;if(e>g)if(g=b.substring(g,e),k)k.push(g);else this.onText(g); +g=this._.htmlPartsRegex.lastIndex;if(e=c[1])if(e=e.toLowerCase(),k&&CKEDITOR.dtd.$cdata[e]&&(this.onCDATA(k.join("")),k=null),!k){this.onTagClose(e);continue}if(k)k.push(c[0]);else if(e=c[3]){if(e=e.toLowerCase(),!/="/.test(e)){var h={},p,r=c[4];c=!!c[5];if(r)for(;p=a.exec(r);){var f=p[1].toLowerCase();p=p[2]||p[3]||p[4]||"";h[f]=!p&&d[f]?f:CKEDITOR.tools.htmlDecodeAttr(p)}this.onTagOpen(e,h,c);!k&&CKEDITOR.dtd.$cdata[e]&&(k=[])}}else if(e=c[2])this.onComment(e)}if(b.length>g)this.onText(b.substring(g, +b.length))}}})(); +CKEDITOR.htmlParser.basicWriter=CKEDITOR.tools.createClass({$:function(){this._={output:[]}},proto:{openTag:function(a){this._.output.push("\x3c",a)},openTagClose:function(a,d){d?this._.output.push(" /\x3e"):this._.output.push("\x3e")},attribute:function(a,d){"string"==typeof d&&(d=CKEDITOR.tools.htmlEncodeAttr(d));this._.output.push(" ",a,'\x3d"',d,'"')},closeTag:function(a){this._.output.push("\x3c/",a,"\x3e")},text:function(a){this._.output.push(a)},comment:function(a){this._.output.push("\x3c!--",a, +"--\x3e")},write:function(a){this._.output.push(a)},reset:function(){this._.output=[];this._.indent=!1},getHtml:function(a){var d=this._.output.join("");a&&this.reset();return d}}});"use strict"; +(function(){CKEDITOR.htmlParser.node=function(){};CKEDITOR.htmlParser.node.prototype={remove:function(){var a=this.parent.children,d=CKEDITOR.tools.indexOf(a,this),b=this.previous,c=this.next;b&&(b.next=c);c&&(c.previous=b);a.splice(d,1);this.parent=null},replaceWith:function(a){var d=this.parent.children,b=CKEDITOR.tools.indexOf(d,this),c=a.previous=this.previous,e=a.next=this.next;c&&(c.next=a);e&&(e.previous=a);d[b]=a;a.parent=this.parent;this.parent=null},insertAfter:function(a){var d=a.parent.children, +b=CKEDITOR.tools.indexOf(d,a),c=a.next;d.splice(b+1,0,this);this.next=a.next;this.previous=a;a.next=this;c&&(c.previous=this);this.parent=a.parent},insertBefore:function(a){var d=a.parent.children,b=CKEDITOR.tools.indexOf(d,a);d.splice(b,0,this);this.next=a;(this.previous=a.previous)&&(a.previous.next=this);a.previous=this;this.parent=a.parent},getAscendant:function(a){var d="function"==typeof a?a:"string"==typeof a?function(b){return b.name==a}:function(b){return b.name in a},b=this.parent;for(;b&& +b.type==CKEDITOR.NODE_ELEMENT;){if(d(b))return b;b=b.parent}return null},wrapWith:function(a){this.replaceWith(a);a.add(this);return a},getIndex:function(){return CKEDITOR.tools.indexOf(this.parent.children,this)},getFilterContext:function(a){return a||{}}}})();"use strict";CKEDITOR.htmlParser.comment=function(a){this.value=a;this._={isBlockLike:!1}}; +CKEDITOR.htmlParser.comment.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_COMMENT,filter:function(a,d){var b=this.value;if(!(b=a.onComment(d,b,this)))return this.remove(),!1;if("string"!=typeof b)return this.replaceWith(b),!1;this.value=b;return!0},writeHtml:function(a,d){d&&this.filter(d);a.comment(this.value)}});"use strict"; +(function(){CKEDITOR.htmlParser.text=function(a){this.value=a;this._={isBlockLike:!1}};CKEDITOR.htmlParser.text.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,filter:function(a,d){if(!(this.value=a.onText(d,this.value,this)))return this.remove(),!1},writeHtml:function(a,d){d&&this.filter(d);a.text(this.value)}})})();"use strict"; +(function(){CKEDITOR.htmlParser.cdata=function(a){this.value=a};CKEDITOR.htmlParser.cdata.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_TEXT,filter:function(){},writeHtml:function(a){a.write(this.value)}})})();"use strict";CKEDITOR.htmlParser.fragment=function(){this.children=[];this.parent=null;this._={isBlockLike:!0,hasInlineStarted:!1}}; +(function(){function a(a){return a.attributes["data-cke-survive"]?!1:"a"==a.name&&a.attributes.href||CKEDITOR.dtd.$removeEmpty[a.name]}var d=CKEDITOR.tools.extend({table:1,ul:1,ol:1,dl:1},CKEDITOR.dtd.table,CKEDITOR.dtd.ul,CKEDITOR.dtd.ol,CKEDITOR.dtd.dl),b={ol:1,ul:1},c=CKEDITOR.tools.extend({},{html:1},CKEDITOR.dtd.html,CKEDITOR.dtd.body,CKEDITOR.dtd.head,{style:1,script:1}),e={ul:"li",ol:"li",dl:"dd",table:"tbody",tbody:"tr",thead:"tr",tfoot:"tr",tr:"td"};CKEDITOR.htmlParser.fragment.fromHtml= +function(g,k,h){function p(a){var b;if(0k;k++)if(g=d[k]){g=g.exec(a,c,this);if(!1===g)return null;if(g&&g!=c)return this.onNode(a,g);if(c.parent&&!c.name)break}return c}, +onNode:function(a,c){var d=c.type;return d==CKEDITOR.NODE_ELEMENT?this.onElement(a,c):d==CKEDITOR.NODE_TEXT?new CKEDITOR.htmlParser.text(this.onText(a,c.value)):d==CKEDITOR.NODE_COMMENT?new CKEDITOR.htmlParser.comment(this.onComment(a,c.value)):null},onAttribute:function(a,c,d,g){return(d=this.attributesRules[d])?d.exec(a,g,c,this):g}}});CKEDITOR.htmlParser.filterRulesGroup=a;a.prototype={add:function(a,c,d){this.rules.splice(this.findIndex(c),0,{value:a,priority:c,options:d})},addMany:function(a, +c,d){for(var g=[this.findIndex(c),0],k=0,h=a.length;k/g,"\x26gt;")+"\x3c/textarea\x3e");return"\x3ccke:encoded\x3e"+encodeURIComponent(a)+"\x3c/cke:encoded\x3e"})}function B(a){return a.replace(Q,function(a,b){return decodeURIComponent(b)})}function u(a){return a.replace(/\x3c!--(?!{cke_protected})[\s\S]+?--\x3e/g, +function(a){return"\x3c!--"+J+"{C}"+encodeURIComponent(a).replace(/--/g,"%2D%2D")+"--\x3e"})}function z(a){return a.replace(/\x3c!--\{cke_protected\}\{C\}([\s\S]+?)--\x3e/g,function(a,b){return decodeURIComponent(b)})}function y(a,b){var c=b._.dataStore;return a.replace(/\x3c!--\{cke_protected\}([\s\S]+?)--\x3e/g,function(a,b){return decodeURIComponent(b)}).replace(/\{cke_protected_(\d+)\}/g,function(a,b){return c&&c[b]||""})}function m(a,b){var c=[],d=b.config.protectedSource,l=b._.dataStore||(b._.dataStore= +{id:1}),e=/<\!--\{cke_temp(comment)?\}(\d*?)--\x3e/g,d=[/|$)/gi,//gi,//gi].concat(d);a=a.replace(/\x3c!--[\s\S]*?--\x3e/g,function(a){return"\x3c!--{cke_tempcomment}"+(c.push(a)-1)+"--\x3e"});for(var f=0;f]+\s*=\s*(?:[^'"\s>]+|'[^']*'|"[^"]*"))|[^\s=\/>]+))+\s*\/?>/g,function(a){return a.replace(/\x3c!--\{cke_protected\}([^>]*)--\x3e/g,function(a,b){l[l.id]=decodeURIComponent(b);return"{cke_protected_"+l.id++ +"}"})});return a=a.replace(/<(title|iframe|textarea)([^>]*)>([\s\S]*?)<\/\1>/g,function(a,c,d,l){return"\x3c"+c+d+"\x3e"+y(z(l),b)+"\x3c/"+c+"\x3e"})}CKEDITOR.htmlDataProcessor=function(b){var c, +l,e=this;this.editor=b;this.dataFilter=c=new CKEDITOR.htmlParser.filter;this.htmlFilter=l=new CKEDITOR.htmlParser.filter;this.writer=new CKEDITOR.htmlParser.basicWriter;c.addRules(q);c.addRules(n,{applyToAll:!0});c.addRules(a(b,"data"),{applyToAll:!0});l.addRules(t);l.addRules(A,{applyToAll:!0});l.addRules(a(b,"html"),{applyToAll:!0});b.on("toHtml",function(a){a=a.data;var c=a.dataValue,l,c=m(c,b),c=f(c,R),c=r(c),c=f(c,H),c=c.replace(P,"$1cke:$2"),c=c.replace(G,"\x3ccke:$1$2\x3e\x3c/cke:$1\x3e"), +c=c.replace(/(]*>)(\r\n|\n)/g,"$1$2$2"),c=c.replace(/([^a-z0-9<\-])(on\w{3,})(?!>)/gi,"$1data-cke-"+CKEDITOR.rnd+"-$2");l=a.context||b.editable().getName();var e;CKEDITOR.env.ie&&9>CKEDITOR.env.version&&"pre"==l&&(l="div",c="\x3cpre\x3e"+c+"\x3c/pre\x3e",e=1);l=b.document.createElement(l);l.setHtml("a"+c);c=l.getHtml().substr(1);c=c.replace(new RegExp("data-cke-"+CKEDITOR.rnd+"-","ig"),"");e&&(c=c.replace(/^

      |<\/pre>$/gi,""));c=c.replace(v,"$1$2");c=B(c);c=z(c);l=!1===a.fixForBody?!1:
      +d(a.enterMode,b.config.autoParagraph);c=CKEDITOR.htmlParser.fragment.fromHtml(c,a.context,l);l&&(e=c,!e.children.length&&CKEDITOR.dtd[e.name][l]&&(l=new CKEDITOR.htmlParser.element(l),e.add(l)));a.dataValue=c},null,null,5);b.on("toHtml",function(a){a.data.filter.applyTo(a.data.dataValue,!0,a.data.dontFilter,a.data.enterMode)&&b.fire("dataFiltered")},null,null,6);b.on("toHtml",function(a){a.data.dataValue.filterChildren(e.dataFilter,!0)},null,null,10);b.on("toHtml",function(a){a=a.data;var b=a.dataValue,
      +c=new CKEDITOR.htmlParser.basicWriter;b.writeChildrenHtml(c);b=c.getHtml(!0);a.dataValue=u(b)},null,null,15);b.on("toDataFormat",function(a){var c=a.data.dataValue;a.data.enterMode!=CKEDITOR.ENTER_BR&&(c=c.replace(/^
      /i,""));a.data.dataValue=CKEDITOR.htmlParser.fragment.fromHtml(c,a.data.context,d(a.data.enterMode,b.config.autoParagraph))},null,null,5);b.on("toDataFormat",function(a){a.data.dataValue.filterChildren(e.htmlFilter,!0)},null,null,10);b.on("toDataFormat",function(a){a.data.filter.applyTo(a.data.dataValue, +!1,!0)},null,null,11);b.on("toDataFormat",function(a){var c=a.data.dataValue,d=e.writer;d.reset();c.writeChildrenHtml(d);c=d.getHtml(!0);c=z(c);c=y(c,b);a.data.dataValue=c},null,null,15)};CKEDITOR.htmlDataProcessor.prototype={toHtml:function(a,b,c,d){var l=this.editor,e,f,n,q;b&&"object"==typeof b?(e=b.context,c=b.fixForBody,d=b.dontFilter,f=b.filter,n=b.enterMode,q=b.protectedWhitespaces):e=b;e||null===e||(e=l.editable().getName());return l.fire("toHtml",{dataValue:a,context:e,fixForBody:c,dontFilter:d, +filter:f||l.filter,enterMode:n||l.enterMode,protectedWhitespaces:q}).dataValue},toDataFormat:function(a,b){var c,d,l;b&&(c=b.context,d=b.filter,l=b.enterMode);c||null===c||(c=this.editor.editable().getName());return this.editor.fire("toDataFormat",{dataValue:a,filter:d||this.editor.filter,context:c,enterMode:l||this.editor.enterMode}).dataValue}};var x=/(?: |\xa0)$/,J="{cke_protected}",w=CKEDITOR.dtd,F="caption colgroup col thead tfoot tbody".split(" "),l=CKEDITOR.tools.extend({},w.$blockLimit, +w.$block),q={elements:{input:h,textarea:h}},n={attributeNames:[[/^on/,"data-cke-pa-on"],[/^data-cke-expando$/,""]]},t={elements:{embed:function(a){var b=a.parent;if(b&&"object"==b.name){var c=b.attributes.width,b=b.attributes.height;c&&(a.attributes.width=c);b&&(a.attributes.height=b)}},a:function(a){var b=a.attributes;if(!(a.children.length||b.name||b.id||a.attributes["data-cke-saved-name"]))return!1}}},A={elementNames:[[/^cke:/,""],[/^\?xml:namespace$/,""]],attributeNames:[[/^data-cke-(saved|pa)-/, +""],[/^data-cke-.*/,""],["hidefocus",""]],elements:{$:function(a){var b=a.attributes;if(b){if(b["data-cke-temp"])return!1;for(var c=["name","href","src"],d,l=0;ld? +1:-1})},param:function(a){a.children=[];a.isEmpty=!0;return a},span:function(a){"Apple-style-span"==a.attributes["class"]&&delete a.name},html:function(a){delete a.attributes.contenteditable;delete a.attributes["class"]},body:function(a){delete a.attributes.spellcheck;delete a.attributes.contenteditable},style:function(a){var b=a.children[0];b&&b.value&&(b.value=CKEDITOR.tools.trim(b.value));a.attributes.type||(a.attributes.type="text/css")},title:function(a){var b=a.children[0];!b&&k(a,b=new CKEDITOR.htmlParser.text); +b.value=a.attributes["data-cke-title"]||""},input:p,textarea:p},attributes:{"class":function(a){return CKEDITOR.tools.ltrim(a.replace(/(?:^|\s+)cke_[^\s]*/g,""))||!1}}};CKEDITOR.env.ie&&(A.attributes.style=function(a){return a.replace(/(^|;)([^\:]+)/g,function(a){return a.toLowerCase()})});var C=/<(a|area|img|input|source)\b([^>]*)>/gi,D=/([\w-:]+)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+))/gi,M=/^(href|src|name)$/i,H=/(?:])[^>]*>[\s\S]*?<\/style>)|(?:<(:?link|meta|base)[^>]*>)/gi, +R=/(])[^>]*>)([\s\S]*?)(?:<\/textarea>)/gi,Q=/([^<]*)<\/cke:encoded>/gi,P=/(<\/?)((?:object|embed|param|html|body|head|title)[^>]*>)/gi,v=/(<\/?)cke:((?:html|body|head|title)[^>]*>)/gi,G=/]*?)\/?>(?!\s*<\/cke:\1)/gi})();"use strict"; +CKEDITOR.htmlParser.element=function(a,d){this.name=a;this.attributes=d||{};this.children=[];var b=a||"",c=b.match(/^cke:(.*)/);c&&(b=c[1]);b=!!(CKEDITOR.dtd.$nonBodyContent[b]||CKEDITOR.dtd.$block[b]||CKEDITOR.dtd.$listItem[b]||CKEDITOR.dtd.$tableContent[b]||CKEDITOR.dtd.$nonEditable[b]||"br"==b);this.isEmpty=!!CKEDITOR.dtd.$empty[a];this.isUnknown=!CKEDITOR.dtd[a];this._={isBlockLike:b,hasInlineStarted:this.isEmpty||!b}}; +CKEDITOR.htmlParser.cssStyle=function(a){var d={};((a instanceof CKEDITOR.htmlParser.element?a.attributes.style:a)||"").replace(/"/g,'"').replace(/\s*([^ :;]+)\s*:\s*([^;]+)\s*(?=;|$)/g,function(a,c,e){"font-family"==c&&(e=e.replace(/["']/g,""));d[c.toLowerCase()]=e});return{rules:d,populate:function(a){var c=this.toString();c&&(a instanceof CKEDITOR.dom.element?a.setAttribute("style",c):a instanceof CKEDITOR.htmlParser.element?a.attributes.style=c:a.style=c)},toString:function(){var a=[],c; +for(c in d)d[c]&&a.push(c,":",d[c],";");return a.join("")}}}; +(function(){function a(a){return function(b){return b.type==CKEDITOR.NODE_ELEMENT&&("string"==typeof a?b.name==a:b.name in a)}}var d=function(a,b){a=a[0];b=b[0];return ab?1:0},b=CKEDITOR.htmlParser.fragment.prototype;CKEDITOR.htmlParser.element.prototype=CKEDITOR.tools.extend(new CKEDITOR.htmlParser.node,{type:CKEDITOR.NODE_ELEMENT,add:b.add,clone:function(){return new CKEDITOR.htmlParser.element(this.name,this.attributes)},filter:function(a,b){var d=this,k,h;b=d.getFilterContext(b);if(b.off)return!0; +if(!d.parent)a.onRoot(b,d);for(;;){k=d.name;if(!(h=a.onElementName(b,k)))return this.remove(),!1;d.name=h;if(!(d=a.onElement(b,d)))return this.remove(),!1;if(d!==this)return this.replaceWith(d),!1;if(d.name==k)break;if(d.type!=CKEDITOR.NODE_ELEMENT)return this.replaceWith(d),!1;if(!d.name)return this.replaceWithChildren(),!1}k=d.attributes;var p,r;for(p in k){for(h=k[p];;)if(r=a.onAttributeName(b,p))if(r!=p)delete k[p],p=r;else break;else{delete k[p];break}r&&(!1===(h=a.onAttribute(b,d,r,h))?delete k[r]: +k[r]=h)}d.isEmpty||this.filterChildren(a,!1,b);return!0},filterChildren:b.filterChildren,writeHtml:function(a,b){b&&this.filter(b);var g=this.name,k=[],h=this.attributes,p,r;a.openTag(g,h);for(p in h)k.push([p,h[p]]);a.sortAttributes&&k.sort(d);p=0;for(r=k.length;pCKEDITOR.env.version||CKEDITOR.env.quirks))this.hasFocus&&(this.focus(),b());else if(this.hasFocus)this.focus(),a();else this.once("focus",function(){a()}, +null,null,-999)},getHtmlFromRange:function(a){if(a.collapsed)return new CKEDITOR.dom.documentFragment(a.document);a={doc:this.getDocument(),range:a.clone()};w.eol.detect(a,this);w.bogus.exclude(a);w.cell.shrink(a);a.fragment=a.range.cloneContents();w.tree.rebuild(a,this);w.eol.fix(a,this);return new CKEDITOR.dom.documentFragment(a.fragment.$)},extractHtmlFromRange:function(a,b){var c=F,d={range:a,doc:a.document},e=this.getHtmlFromRange(a);if(a.collapsed)return a.optimize(),e;a.enlarge(CKEDITOR.ENLARGE_INLINE, +1);c.table.detectPurge(d);d.bookmark=a.createBookmark();delete d.range;var f=this.editor.createRange();f.moveToPosition(d.bookmark.startNode,CKEDITOR.POSITION_BEFORE_START);d.targetBookmark=f.createBookmark();c.list.detectMerge(d,this);c.table.detectRanges(d,this);c.block.detectMerge(d,this);d.tableContentsRanges?(c.table.deleteRanges(d),a.moveToBookmark(d.bookmark),d.range=a):(a.moveToBookmark(d.bookmark),d.range=a,a.extractContents(c.detectExtractMerge(d)));a.moveToBookmark(d.targetBookmark);a.optimize(); +c.fixUneditableRangePosition(a);c.list.merge(d,this);c.table.purge(d,this);c.block.merge(d,this);if(b){c=a.startPath();if(d=a.checkStartOfBlock()&&a.checkEndOfBlock()&&c.block&&!a.root.equals(c.block)){a:{var d=c.block.getElementsByTag("span"),f=0,g;if(d)for(;g=d.getItem(f++);)if(!B(g)){d=!0;break a}d=!1}d=!d}d&&(a.moveToPosition(c.block,CKEDITOR.POSITION_BEFORE_START),c.block.remove())}else c.autoParagraph(this.editor,a),u(a.startContainer)&&a.startContainer.appendBogus();a.startContainer.mergeSiblings(); +return e},setup:function(){var a=this.editor;this.attachListener(a,"beforeGetData",function(){var b=this.getData();this.is("textarea")||!1!==a.config.ignoreEmptyParagraph&&(b=b.replace(y,function(a,b){return b}));a.setData(b,null,1)},this);this.attachListener(a,"getSnapshot",function(a){a.data=this.getData(1)},this);this.attachListener(a,"afterSetData",function(){this.setData(a.getData(1))},this);this.attachListener(a,"loadSnapshot",function(a){this.setData(a.data,1)},this);this.attachListener(a, +"beforeFocus",function(){var b=a.getSelection();(b=b&&b.getNative())&&"Control"==b.type||this.focus()},this);this.attachListener(a,"insertHtml",function(a){this.insertHtml(a.data.dataValue,a.data.mode,a.data.range)},this);this.attachListener(a,"insertElement",function(a){this.insertElement(a.data)},this);this.attachListener(a,"insertText",function(a){this.insertText(a.data)},this);this.setReadOnly(a.readOnly);this.attachClass("cke_editable");a.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?this.attachClass("cke_editable_inline"): +a.elementMode!=CKEDITOR.ELEMENT_MODE_REPLACE&&a.elementMode!=CKEDITOR.ELEMENT_MODE_APPENDTO||this.attachClass("cke_editable_themed");this.attachClass("cke_contents_"+a.config.contentsLangDirection);a.keystrokeHandler.blockedKeystrokes[8]=+a.readOnly;a.keystrokeHandler.attach(this);this.on("blur",function(){this.hasFocus=!1},null,null,-1);this.on("focus",function(){this.hasFocus=!0},null,null,-1);if(CKEDITOR.env.webkit)this.on("scroll",function(){a._.previousScrollTop=a.editable().$.scrollTop},null, +null,-1);if(CKEDITOR.env.edge&&14CKEDITOR.env.version?h.$.styleSheet.cssText=k:h.setText(k)):(k=e.appendStyleText(k),k=new CKEDITOR.dom.element(k.ownerNode||k.owningElement),t.setCustomData("stylesheet", +k),k.data("cke-temp",1))}t=e.getCustomData("stylesheet_ref")||0;e.setCustomData("stylesheet_ref",t+1);this.setCustomData("cke_includeReadonly",!a.config.disableReadonlyStyling);this.attachListener(this,"click",function(a){a=a.data;var b=(new CKEDITOR.dom.elementPath(a.getTarget(),this)).contains("a");b&&2!=a.$.button&&b.isReadOnly()&&a.preventDefault()});var D={8:1,46:1};this.attachListener(a,"key",function(b){if(a.readOnly)return!0;var c=b.data.domEvent.getKey(),d;if(c in D){b=a.getSelection();var e, +n=b.getRanges()[0],q=n.startPath(),t,k,h,c=8==c;CKEDITOR.env.ie&&11>CKEDITOR.env.version&&(e=b.getSelectedElement())||(e=g(b))?(a.fire("saveSnapshot"),n.moveToPosition(e,CKEDITOR.POSITION_BEFORE_START),e.remove(),n.select(),a.fire("saveSnapshot"),d=1):n.collapsed&&((t=q.block)&&(h=t[c?"getPrevious":"getNext"](f))&&h.type==CKEDITOR.NODE_ELEMENT&&h.is("table")&&n[c?"checkStartOfBlock":"checkEndOfBlock"]()?(a.fire("saveSnapshot"),n[c?"checkEndOfBlock":"checkStartOfBlock"]()&&t.remove(),n["moveToElementEdit"+ +(c?"End":"Start")](h),n.select(),a.fire("saveSnapshot"),d=1):q.blockLimit&&q.blockLimit.is("td")&&(k=q.blockLimit.getAscendant("table"))&&n.checkBoundaryOfElement(k,c?CKEDITOR.START:CKEDITOR.END)&&(h=k[c?"getPrevious":"getNext"](f))?(a.fire("saveSnapshot"),n["moveToElementEdit"+(c?"End":"Start")](h),n.checkStartOfBlock()&&n.checkEndOfBlock()?h.remove():n.select(),a.fire("saveSnapshot"),d=1):(k=q.contains(["td","th","caption"]))&&n.checkBoundaryOfElement(k,c?CKEDITOR.START:CKEDITOR.END)&&(d=1))}return!d}); +a.blockless&&CKEDITOR.env.ie&&CKEDITOR.env.needsBrFiller&&this.attachListener(this,"keyup",function(b){b.data.getKeystroke()in D&&!this.getFirst(c)&&(this.appendBogus(),b=a.createRange(),b.moveToPosition(this,CKEDITOR.POSITION_AFTER_START),b.select())});this.attachListener(this,"dblclick",function(b){if(a.readOnly)return!1;b={element:b.data.getTarget()};a.fire("doubleclick",b)});CKEDITOR.env.ie&&this.attachListener(this,"click",b);CKEDITOR.env.ie&&!CKEDITOR.env.edge||this.attachListener(this,"mousedown", +function(b){var c=b.data.getTarget();c.is("img","hr","input","textarea","select")&&!c.isReadOnly()&&(a.getSelection().selectElement(c),c.is("input","textarea","select")&&b.data.preventDefault())});CKEDITOR.env.edge&&this.attachListener(this,"mouseup",function(b){(b=b.data.getTarget())&&b.is("img")&&a.getSelection().selectElement(b)});CKEDITOR.env.gecko&&this.attachListener(this,"mouseup",function(b){if(2==b.data.$.button&&(b=b.data.getTarget(),!b.getOuterHtml().replace(y,""))){var c=a.createRange(); +c.moveToElementEditStart(b);c.select(!0)}});CKEDITOR.env.webkit&&(this.attachListener(this,"click",function(a){a.data.getTarget().is("input","select")&&a.data.preventDefault()}),this.attachListener(this,"mouseup",function(a){a.data.getTarget().is("input","textarea")&&a.data.preventDefault()}));CKEDITOR.env.webkit&&this.attachListener(a,"key",function(b){if(a.readOnly)return!0;b=b.data.domEvent.getKey();if(b in D){var c=8==b,d=a.getSelection().getRanges()[0];b=d.startPath();if(d.collapsed)a:{var e= +b.block;if(e&&d[c?"checkStartOfBlock":"checkEndOfBlock"]()&&d.moveToClosestEditablePosition(e,!c)&&d.collapsed){if(d.startContainer.type==CKEDITOR.NODE_ELEMENT){var f=d.startContainer.getChild(d.startOffset-(c?1:0));if(f&&f.type==CKEDITOR.NODE_ELEMENT&&f.is("hr")){a.fire("saveSnapshot");f.remove();b=!0;break a}}d=d.startPath().block;if(!d||d&&d.contains(e))b=void 0;else{a.fire("saveSnapshot");var n;(n=(c?d:e).getBogus())&&n.remove();n=a.getSelection();f=n.createBookmarks();(c?e:d).moveChildren(c? +d:e,!1);b.lastElement.mergeSiblings();r(e,d,!c);n.selectBookmarks(f);b=!0}}else b=!1}else c=d,n=b.block,d=c.endPath().block,n&&d&&!n.equals(d)?(a.fire("saveSnapshot"),(e=n.getBogus())&&e.remove(),c.enlarge(CKEDITOR.ENLARGE_INLINE),c.deleteContents(),d.getParent()&&(d.moveChildren(n,!1),b.lastElement.mergeSiblings(),r(n,d,!0)),c=a.getSelection().getRanges()[0],c.collapse(1),c.optimize(),""===c.startContainer.getHtml()&&c.startContainer.appendBogus(),c.select(),b=!0):b=!1;if(!b)return;a.getSelection().scrollIntoView(); +a.fire("saveSnapshot");return!1}},this,null,100)}}},_:{detach:function(){this.editor.setData(this.editor.getData(),0,1);this.clearListeners();this.restoreAttrs();var a;if(a=this.removeCustomData("classes"))for(;a.length;)this.removeClass(a.pop());if(!this.is("textarea")){a=this.getDocument();var b=a.getHead();if(b.getCustomData("stylesheet")){var c=a.getCustomData("stylesheet_ref");--c?a.setCustomData("stylesheet_ref",c):(a.removeCustomData("stylesheet_ref"),b.removeCustomData("stylesheet").remove())}}this.editor.fire("contentDomUnload"); +delete this.editor}}});CKEDITOR.editor.prototype.editable=function(a){var b=this._.editable;if(b&&a)return 0;arguments.length&&(b=this._.editable=a?a instanceof CKEDITOR.editable?a:new CKEDITOR.editable(this,a):(b&&b.detach(),null));return b};CKEDITOR.on("instanceLoaded",function(b){var c=b.editor;c.on("insertElement",function(a){a=a.data;a.type==CKEDITOR.NODE_ELEMENT&&(a.is("input")||a.is("textarea"))&&("false"!=a.getAttribute("contentEditable")&&a.data("cke-editable",a.hasAttribute("contenteditable")? +"true":"1"),a.setAttribute("contentEditable",!1))});c.on("selectionChange",function(b){if(!c.readOnly){var d=c.getSelection();d&&!d.isLocked&&(d=c.checkDirty(),c.fire("lockSnapshot"),a(b),c.fire("unlockSnapshot"),!d&&c.resetDirty())}})});CKEDITOR.on("instanceCreated",function(a){var b=a.editor;b.on("mode",function(){var a=b.editable();if(a&&a.isInline()){var c=b.title;a.changeAttr("role","textbox");a.changeAttr("aria-label",c);c&&a.changeAttr("title",c);var d=b.fire("ariaEditorHelpLabel",{}).label; +if(d&&(c=this.ui.space(this.elementMode==CKEDITOR.ELEMENT_MODE_INLINE?"top":"contents"))){var e=CKEDITOR.tools.getNextId(),d=CKEDITOR.dom.element.createFromHtml('\x3cspan id\x3d"'+e+'" class\x3d"cke_voice_label"\x3e'+d+"\x3c/span\x3e");c.append(d);a.changeAttr("aria-describedby",e)}}})});CKEDITOR.addCss(".cke_editable{cursor:text}.cke_editable img,.cke_editable input,.cke_editable textarea{cursor:default}");f=CKEDITOR.dom.walker.whitespaces(!0);B=CKEDITOR.dom.walker.bookmark(!1,!0);u=CKEDITOR.dom.walker.empty(); +z=CKEDITOR.dom.walker.bogus();y=/(^|]*>)\s*<(p|div|address|h\d|center|pre)[^>]*>\s*(?:]*>| |\u00A0| )?\s*(:?<\/\2>)?\s*(?=$|<\/body>)/gi;m=function(){function a(b){return b.type==CKEDITOR.NODE_ELEMENT}function b(c,d){var e,f,n,t,g=[],k=d.range.startContainer;e=d.range.startPath();for(var k=p[k.getName()],h=0,C=c.getChildren(),A=C.count(),D=-1,m=-1,r=0,H=e.contains(p.$list);hCKEDITOR.env.version&&d.getChildCount()&&d.getFirst().remove())}return function(d){var e=d.startContainer,f=e.getAscendant("table",1),g=!1;c(f.getElementsByTag("td"));c(f.getElementsByTag("th"));f=d.clone();f.setStart(e,0);f=a(f).lastBackward();f||(f=d.clone(),f.setEndAt(e,CKEDITOR.POSITION_BEFORE_END),f=a(f).lastForward(),g=!0);f||(f=e);f.is("table")?(d.setStartAt(f,CKEDITOR.POSITION_BEFORE_START), +d.collapse(!0),f.remove()):(f.is({tbody:1,thead:1,tfoot:1})&&(f=b(f,"tr",g)),f.is("tr")&&(f=b(f,f.getParent().is("thead")?"th":"td",g)),(e=f.getBogus())&&e.remove(),d.moveToPosition(f,g?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END))}}();J=function(){function a(b){b=new CKEDITOR.dom.walker(b);b.guard=function(a,b){if(b)return!1;if(a.type==CKEDITOR.NODE_ELEMENT)return a.is(CKEDITOR.dtd.$list)||a.is(CKEDITOR.dtd.$listItem)};b.evaluator=function(a){return a.type==CKEDITOR.NODE_ELEMENT&& +a.is(CKEDITOR.dtd.$listItem)};return b}return function(b){var c=b.startContainer,d=!1,e;e=b.clone();e.setStart(c,0);e=a(e).lastBackward();e||(e=b.clone(),e.setEndAt(c,CKEDITOR.POSITION_BEFORE_END),e=a(e).lastForward(),d=!0);e||(e=c);e.is(CKEDITOR.dtd.$list)?(b.setStartAt(e,CKEDITOR.POSITION_BEFORE_START),b.collapse(!0),e.remove()):((c=e.getBogus())&&c.remove(),b.moveToPosition(e,d?CKEDITOR.POSITION_AFTER_START:CKEDITOR.POSITION_BEFORE_END),b.select())}}();w={eol:{detect:function(a,b){var c=a.range, +d=c.clone(),e=c.clone(),f=new CKEDITOR.dom.elementPath(c.startContainer,b),g=new CKEDITOR.dom.elementPath(c.endContainer,b);d.collapse(1);e.collapse();f.block&&d.checkBoundaryOfElement(f.block,CKEDITOR.END)&&(c.setStartAfter(f.block),a.prependEolBr=1);g.block&&e.checkBoundaryOfElement(g.block,CKEDITOR.START)&&(c.setEndBefore(g.block),a.appendEolBr=1)},fix:function(a,b){var c=b.getDocument(),d;a.appendEolBr&&(d=this.createEolBr(c),a.fragment.append(d));!a.prependEolBr||d&&!d.getPrevious()||a.fragment.append(this.createEolBr(c), +1)},createEolBr:function(a){return a.createElement("br",{attributes:{"data-cke-eol":1}})}},bogus:{exclude:function(a){var b=a.range.getBoundaryNodes(),c=b.startNode,b=b.endNode;!b||!z(b)||c&&c.equals(b)||a.range.setEndBefore(b)}},tree:{rebuild:function(a,b){var c=a.range,d=c.getCommonAncestor(),e=new CKEDITOR.dom.elementPath(d,b),f=new CKEDITOR.dom.elementPath(c.startContainer,b),c=new CKEDITOR.dom.elementPath(c.endContainer,b),g;d.type==CKEDITOR.NODE_TEXT&&(d=d.getParent());if(e.blockLimit.is({tr:1, +table:1})){var k=e.contains("table").getParent();g=function(a){return!a.equals(k)}}else if(e.block&&e.block.is(CKEDITOR.dtd.$listItem)&&(f=f.contains(CKEDITOR.dtd.$list),c=c.contains(CKEDITOR.dtd.$list),!f.equals(c))){var h=e.contains(CKEDITOR.dtd.$list).getParent();g=function(a){return!a.equals(h)}}g||(g=function(a){return!a.equals(e.block)&&!a.equals(e.blockLimit)});this.rebuildFragment(a,b,d,g)},rebuildFragment:function(a,b,c,d){for(var e;c&&!c.equals(b)&&d(c);)e=c.clone(0,1),a.fragment.appendTo(e), +a.fragment=e,c=c.getParent()}},cell:{shrink:function(a){a=a.range;var b=a.startContainer,c=a.endContainer,d=a.startOffset,e=a.endOffset;b.type==CKEDITOR.NODE_ELEMENT&&b.equals(c)&&b.is("tr")&&++d==e&&a.shrink(CKEDITOR.SHRINK_TEXT)}}};F=function(){function a(b,c){var d=b.getParent();if(d.is(CKEDITOR.dtd.$inline))b[c?"insertBefore":"insertAfter"](d)}function b(c,d,e){a(d);a(e,1);for(var f;f=e.getNext();)f.insertAfter(d),d=f;u(c)&&c.remove()}function c(a,b){var d=new CKEDITOR.dom.range(a);d.setStartAfter(b.startNode); +d.setEndBefore(b.endNode);return d}return{list:{detectMerge:function(a,b){var d=c(b,a.bookmark),e=d.startPath(),f=d.endPath(),l=e.contains(CKEDITOR.dtd.$list),g=f.contains(CKEDITOR.dtd.$list);a.mergeList=l&&g&&l.getParent().equals(g.getParent())&&!l.equals(g);a.mergeListItems=e.block&&f.block&&e.block.is(CKEDITOR.dtd.$listItem)&&f.block.is(CKEDITOR.dtd.$listItem);if(a.mergeList||a.mergeListItems)d=d.clone(),d.setStartBefore(a.bookmark.startNode),d.setEndAfter(a.bookmark.endNode),a.mergeListBookmark= +d.createBookmark()},merge:function(a,c){if(a.mergeListBookmark){var d=a.mergeListBookmark.startNode,e=a.mergeListBookmark.endNode,f=new CKEDITOR.dom.elementPath(d,c),l=new CKEDITOR.dom.elementPath(e,c);if(a.mergeList){var g=f.contains(CKEDITOR.dtd.$list),n=l.contains(CKEDITOR.dtd.$list);g.equals(n)||(n.moveChildren(g),n.remove())}a.mergeListItems&&(f=f.contains(CKEDITOR.dtd.$listItem),l=l.contains(CKEDITOR.dtd.$listItem),f.equals(l)||b(l,d,e));d.remove();e.remove()}}},block:{detectMerge:function(a, +b){if(!a.tableContentsRanges&&!a.mergeListBookmark){var c=new CKEDITOR.dom.range(b);c.setStartBefore(a.bookmark.startNode);c.setEndAfter(a.bookmark.endNode);a.mergeBlockBookmark=c.createBookmark()}},merge:function(a,c){if(a.mergeBlockBookmark&&!a.purgeTableBookmark){var d=a.mergeBlockBookmark.startNode,e=a.mergeBlockBookmark.endNode,f=new CKEDITOR.dom.elementPath(d,c),l=new CKEDITOR.dom.elementPath(e,c),f=f.block,l=l.block;f&&l&&!f.equals(l)&&b(l,d,e);d.remove();e.remove()}}},table:function(){function a(c){var e= +[],f,l=new CKEDITOR.dom.walker(c),g=c.startPath().contains(d),n=c.endPath().contains(d),k={};l.guard=function(a,l){if(a.type==CKEDITOR.NODE_ELEMENT){var h="visited_"+(l?"out":"in");if(a.getCustomData(h))return;CKEDITOR.dom.element.setMarker(k,a,h,1)}if(l&&g&&a.equals(g))f=c.clone(),f.setEndAt(g,CKEDITOR.POSITION_BEFORE_END),e.push(f);else if(!l&&n&&a.equals(n))f=c.clone(),f.setStartAt(n,CKEDITOR.POSITION_AFTER_START),e.push(f);else{if(h=!l)h=a.type==CKEDITOR.NODE_ELEMENT&&a.is(d)&&(!g||b(a,g))&&(!n|| +b(a,n));h&&(f=c.clone(),f.selectNodeContents(a),e.push(f))}};l.lastForward();CKEDITOR.dom.element.clearAllMarkers(k);return e}function b(a,c){var d=CKEDITOR.POSITION_CONTAINS+CKEDITOR.POSITION_IS_CONTAINED,e=a.getPosition(c);return e===CKEDITOR.POSITION_IDENTICAL?!1:0===(e&d)}var d={td:1,th:1,caption:1};return{detectPurge:function(a){var b=a.range,c=b.clone();c.enlarge(CKEDITOR.ENLARGE_ELEMENT);var c=new CKEDITOR.dom.walker(c),e=0;c.evaluator=function(a){a.type==CKEDITOR.NODE_ELEMENT&&a.is(d)&&++e}; +c.checkForward();if(1f&&e&&e.intersectsNode(c.$)){var g=[{node:d.anchorNode,offset:d.anchorOffset},{node:d.focusNode,offset:d.focusOffset}]; +d.anchorNode==c.$&&d.anchorOffset>f&&(g[0].offset-=f);d.focusNode==c.$&&d.focusOffset>f&&(g[1].offset-=f)}}c.setText(h(c.getText(),1));g&&(c=a.getDocument().$,d=c.getSelection(),c=c.createRange(),c.setStart(g[0].node,g[0].offset),c.collapse(!0),d.removeAllRanges(),d.addRange(c),d.extend(g[1].node,g[1].offset))}}function h(a,b){return b?a.replace(y,function(a,b){return b?" ":""}):a.replace(z,"")}function p(a,b){var c=CKEDITOR.dom.element.createFromHtml('\x3cdiv data-cke-hidden-sel\x3d"1" data-cke-temp\x3d"1" style\x3d"'+ +(CKEDITOR.env.ie&&14>CKEDITOR.env.version?"display:none":"position:fixed;top:0;left:-1000px")+'"\x3e'+(b||"\x26nbsp;")+"\x3c/div\x3e",a.document);a.fire("lockSnapshot");a.editable().append(c);var d=a.getSelection(1),e=a.createRange(),f=d.root.on("selectionchange",function(a){a.cancel()},null,null,0);e.setStartAt(c,CKEDITOR.POSITION_AFTER_START);e.setEndAt(c,CKEDITOR.POSITION_BEFORE_END);d.selectRanges([e]);f.removeListener();a.fire("unlockSnapshot");a._.hiddenSelectionContainer=c}function r(a){var b= +{37:1,39:1,8:1,46:1};return function(c){var d=c.data.getKeystroke();if(b[d]){var e=a.getSelection().getRanges(),f=e[0];1==e.length&&f.collapsed&&(d=f[38>d?"getPreviousEditableNode":"getNextEditableNode"]())&&d.type==CKEDITOR.NODE_ELEMENT&&"false"==d.getAttribute("contenteditable")&&(a.getSelection().fake(d),c.data.preventDefault(),c.cancel())}}}function f(a){for(var b=0;b=d.getLength()?h.setStartAfter(d):h.setStartBefore(d));e&&e.type==CKEDITOR.NODE_TEXT&&(g?h.setEndAfter(e):h.setEndBefore(e));d=new CKEDITOR.dom.walker(h);d.evaluator=function(d){if(d.type==CKEDITOR.NODE_ELEMENT&& +d.isReadOnly()){var e=c.clone();c.setEndBefore(d);c.collapsed&&a.splice(b--,1);d.getPosition(h.endContainer)&CKEDITOR.POSITION_CONTAINS||(e.setStartAfter(d),e.collapsed||a.splice(b+1,0,e));return!0}return!1};d.next()}}return a}var B="function"!=typeof window.getSelection,u=1,z=CKEDITOR.tools.repeat("​",7),y=new RegExp(z+"( )?","g"),m,x,J=CKEDITOR.dom.walker.invisible(1),w=function(){function a(b){return function(a){var c=a.editor.createRange();c.moveToClosestEditablePosition(a.selected,b)&&a.editor.getSelection().selectRanges([c]); +return!1}}function b(a){return function(b){var c=b.editor,d=c.createRange(),e;(e=d.moveToClosestEditablePosition(b.selected,a))||(e=d.moveToClosestEditablePosition(b.selected,!a));e&&c.getSelection().selectRanges([d]);c.fire("saveSnapshot");b.selected.remove();e||(d.moveToElementEditablePosition(c.editable()),c.getSelection().selectRanges([d]));c.fire("saveSnapshot");return!1}}var c=a(),d=a(1);return{37:c,38:c,39:d,40:d,8:b(),46:b(1)}}();CKEDITOR.on("instanceCreated",function(b){function c(){var a= +e.getSelection();a&&a.removeAllRanges()}var e=b.editor;e.on("contentDom",function(){function b(){v=new CKEDITOR.dom.selection(e.getSelection());v.lock()}function c(){l.removeListener("mouseup",c);q.removeListener("mouseup",c);var a=CKEDITOR.document.$.selection,b=a.createRange();"None"!=a.type&&b.parentElement().ownerDocument==f.$&&b.select()}var f=e.document,l=CKEDITOR.document,g=e.editable(),h=f.getBody(),q=f.getDocumentElement(),m=g.isInline(),p,v;CKEDITOR.env.gecko&&g.attachListener(g,"focus", +function(a){a.removeListener();0!==p&&(a=e.getSelection().getNative())&&a.isCollapsed&&a.anchorNode==g.$&&(a=e.createRange(),a.moveToElementEditStart(g),a.select())},null,null,-2);g.attachListener(g,CKEDITOR.env.webkit?"DOMFocusIn":"focus",function(){p&&CKEDITOR.env.webkit&&(p=e._.previousActive&&e._.previousActive.equals(f.getActive()))&&null!=e._.previousScrollTop&&e._.previousScrollTop!=g.$.scrollTop&&(g.$.scrollTop=e._.previousScrollTop);e.unlockSelection(p);p=0},null,null,-1);g.attachListener(g, +"mousedown",function(){p=0});if(CKEDITOR.env.ie||m)B?g.attachListener(g,"beforedeactivate",b,null,null,-1):g.attachListener(e,"selectionCheck",b,null,null,-1),g.attachListener(g,CKEDITOR.env.webkit?"DOMFocusOut":"blur",function(){e.lockSelection(v);p=1},null,null,-1),g.attachListener(g,"mousedown",function(){p=0});if(CKEDITOR.env.ie&&!m){var G;g.attachListener(g,"mousedown",function(a){2==a.data.$.button&&((a=e.document.getSelection())&&a.getType()!=CKEDITOR.SELECTION_NONE||(G=e.window.getScrollPosition()))}); +g.attachListener(g,"mouseup",function(a){2==a.data.$.button&&G&&(e.document.$.documentElement.scrollLeft=G.x,e.document.$.documentElement.scrollTop=G.y);G=null});if("BackCompat"!=f.$.compatMode){if(CKEDITOR.env.ie7Compat||CKEDITOR.env.ie6Compat){var E,I;q.on("mousedown",function(a){function b(a){a=a.data.$;if(E){var c=h.$.createTextRange();try{c.moveToPoint(a.clientX,a.clientY)}catch(d){}E.setEndPoint(0>I.compareEndPoints("StartToStart",c)?"EndToEnd":"StartToStart",c);E.select()}}function c(){q.removeListener("mousemove", +b);l.removeListener("mouseup",c);q.removeListener("mouseup",c);E.select()}a=a.data;if(a.getTarget().is("html")&&a.$.yCKEDITOR.env.version)q.on("mousedown",function(a){a.data.getTarget().is("html")&&(l.on("mouseup",c),q.on("mouseup",c))})}}g.attachListener(g,"selectionchange",a, +e);g.attachListener(g,"keyup",d,e);g.attachListener(g,CKEDITOR.env.webkit?"DOMFocusIn":"focus",function(){e.forceNextSelectionCheck();e.selectionChange(1)});if(m&&(CKEDITOR.env.webkit||CKEDITOR.env.gecko)){var K;g.attachListener(g,"mousedown",function(){K=1});g.attachListener(f.getDocumentElement(),"mouseup",function(){K&&d.call(e);K=0})}else g.attachListener(CKEDITOR.env.ie?g:f.getDocumentElement(),"mouseup",d,e);CKEDITOR.env.webkit&&g.attachListener(f,"keydown",function(a){switch(a.data.getKey()){case 13:case 33:case 34:case 35:case 36:case 37:case 39:case 8:case 45:case 46:k(g)}}, +null,null,-1);g.attachListener(g,"keydown",r(e),null,null,-1)});e.on("setData",function(){e.unlockSelection();CKEDITOR.env.webkit&&c()});e.on("contentDomUnload",function(){e.unlockSelection()});if(CKEDITOR.env.ie9Compat)e.on("beforeDestroy",c,null,null,9);e.on("dataReady",function(){delete e._.fakeSelection;delete e._.hiddenSelectionContainer;e.selectionChange(1)});e.on("loadSnapshot",function(){var a=CKEDITOR.dom.walker.nodeType(CKEDITOR.NODE_ELEMENT),b=e.editable().getLast(a);b&&b.hasAttribute("data-cke-hidden-sel")&& +(b.remove(),CKEDITOR.env.gecko&&(a=e.editable().getFirst(a))&&a.is("br")&&a.getAttribute("_moz_editor_bogus_node")&&a.remove())},null,null,100);e.on("key",function(a){if("wysiwyg"==e.mode){var b=e.getSelection();if(b.isFake){var c=w[a.data.keyCode];if(c)return c({editor:e,selected:b.getSelectedElement(),selection:b,keyEvent:a})}}})});if(CKEDITOR.env.webkit)CKEDITOR.on("instanceReady",function(a){var b=a.editor;b.on("selectionChange",function(){var a=b.editable(),c=a.getCustomData("cke-fillingChar"); +c&&(c.getCustomData("ready")?k(a):c.setCustomData("ready",1))},null,null,-1);b.on("beforeSetMode",function(){k(b.editable())},null,null,-1);b.on("getSnapshot",function(a){a.data&&(a.data=h(a.data))},b,null,20);b.on("toDataFormat",function(a){a.data.dataValue=h(a.data.dataValue)},null,null,0)});CKEDITOR.editor.prototype.selectionChange=function(b){(b?a:d).call(this)};CKEDITOR.editor.prototype.getSelection=function(a){return!this._.savedSelection&&!this._.fakeSelection||a?(a=this.editable())&&"wysiwyg"== +this.mode?new CKEDITOR.dom.selection(a):null:this._.savedSelection||this._.fakeSelection};CKEDITOR.editor.prototype.lockSelection=function(a){a=a||this.getSelection(1);return a.getType()!=CKEDITOR.SELECTION_NONE?(!a.isLocked&&a.lock(),this._.savedSelection=a,!0):!1};CKEDITOR.editor.prototype.unlockSelection=function(a){var b=this._.savedSelection;return b?(b.unlock(a),delete this._.savedSelection,!0):!1};CKEDITOR.editor.prototype.forceNextSelectionCheck=function(){delete this._.selectionPreviousPath}; +CKEDITOR.dom.document.prototype.getSelection=function(){return new CKEDITOR.dom.selection(this)};CKEDITOR.dom.range.prototype.select=function(){var a=this.root instanceof CKEDITOR.editable?this.root.editor.getSelection():new CKEDITOR.dom.selection(this.root);a.selectRanges([this]);return a};CKEDITOR.SELECTION_NONE=1;CKEDITOR.SELECTION_TEXT=2;CKEDITOR.SELECTION_ELEMENT=3;CKEDITOR.dom.selection=function(a){if(a instanceof CKEDITOR.dom.selection){var b=a;a=a.root}var c=a instanceof CKEDITOR.dom.element; +this.rev=b?b.rev:u++;this.document=a instanceof CKEDITOR.dom.document?a:a.getDocument();this.root=c?a:this.document.getBody();this.isLocked=0;this._={cache:{}};if(b)return CKEDITOR.tools.extend(this._.cache,b._.cache),this.isFake=b.isFake,this.isLocked=b.isLocked,this;a=this.getNative();var d,e;if(a)if(a.getRangeAt)d=(e=a.rangeCount&&a.getRangeAt(0))&&new CKEDITOR.dom.node(e.commonAncestorContainer);else{try{e=a.createRange()}catch(f){}d=e&&CKEDITOR.dom.element.get(e.item&&e.item(0)||e.parentElement())}if(!d|| +d.type!=CKEDITOR.NODE_ELEMENT&&d.type!=CKEDITOR.NODE_TEXT||!this.root.equals(d)&&!this.root.contains(d))this._.cache.type=CKEDITOR.SELECTION_NONE,this._.cache.startElement=null,this._.cache.selectedElement=null,this._.cache.selectedText="",this._.cache.ranges=new CKEDITOR.dom.rangeList;return this};var F={img:1,hr:1,li:1,table:1,tr:1,td:1,th:1,embed:1,object:1,ol:1,ul:1,a:1,input:1,form:1,select:1,textarea:1,button:1,fieldset:1,thead:1,tfoot:1};CKEDITOR.tools.extend(CKEDITOR.dom.selection,{_removeFillingCharSequenceString:h, +_createFillingCharSequenceNode:g,FILLING_CHAR_SEQUENCE:z});CKEDITOR.dom.selection.prototype={getNative:function(){return void 0!==this._.cache.nativeSel?this._.cache.nativeSel:this._.cache.nativeSel=B?this.document.$.selection:this.document.getWindow().$.getSelection()},getType:B?function(){var a=this._.cache;if(a.type)return a.type;var b=CKEDITOR.SELECTION_NONE;try{var c=this.getNative(),d=c.type;"Text"==d&&(b=CKEDITOR.SELECTION_TEXT);"Control"==d&&(b=CKEDITOR.SELECTION_ELEMENT);c.createRange().parentElement()&& +(b=CKEDITOR.SELECTION_TEXT)}catch(e){}return a.type=b}:function(){var a=this._.cache;if(a.type)return a.type;var b=CKEDITOR.SELECTION_TEXT,c=this.getNative();if(!c||!c.rangeCount)b=CKEDITOR.SELECTION_NONE;else if(1==c.rangeCount){var c=c.getRangeAt(0),d=c.startContainer;d==c.endContainer&&1==d.nodeType&&1==c.endOffset-c.startOffset&&F[d.childNodes[c.startOffset].nodeName.toLowerCase()]&&(b=CKEDITOR.SELECTION_ELEMENT)}return a.type=b},getRanges:function(){var a=B?function(){function a(b){return(new CKEDITOR.dom.node(b)).getIndex()} +var b=function(b,c){b=b.duplicate();b.collapse(c);var d=b.parentElement();if(!d.hasChildNodes())return{container:d,offset:0};for(var e=d.children,f,l,g=b.duplicate(),h=0,k=e.length-1,v=-1,n,m;h<=k;)if(v=Math.floor((h+k)/2),f=e[v],g.moveToElementText(f),n=g.compareEndPoints("StartToStart",b),0n)h=v+1;else return{container:d,offset:a(f)};if(-1==v||v==e.length-1&&0>n){g.moveToElementText(d);g.setEndPoint("StartToStart",b);g=g.text.replace(/(\r\n|\r)/g,"\n").length;e=d.childNodes;if(!g)return f= +e[e.length-1],f.nodeType!=CKEDITOR.NODE_TEXT?{container:d,offset:e.length}:{container:f,offset:f.nodeValue.length};for(d=e.length;0]*>)[ \t\r\n]*/gi,"$1");g=g.replace(/([ \t\n\r]+| )/g, +" ");g=g.replace(/]*>/gi,"\n");if(CKEDITOR.env.ie){var h=a.getDocument().createElement("div");h.append(e);e.$.outerHTML="\x3cpre\x3e"+g+"\x3c/pre\x3e";e.copyAttributes(h.getFirst());e=h.getFirst().remove()}else e.setHtml(g);b=e}else g?b=u(c?[a.getHtml()]:f(a),b):a.moveChildren(b);b.replace(a);if(d){var c=b,k;(k=c.getPrevious(R))&&k.type==CKEDITOR.NODE_ELEMENT&&k.is("pre")&&(d=B(k.getHtml(),/\n$/,"")+"\n\n"+B(c.getHtml(),/^\n/,""),CKEDITOR.env.ie?c.$.outerHTML="\x3cpre\x3e"+d+"\x3c/pre\x3e": +c.setHtml(d),k.remove())}else c&&x(b)}function f(a){var b=[];B(a.getOuterHtml(),/(\S\s*)\n(?:\s|(]+data-cke-bookmark.*?\/span>))*\n(?!$)/gi,function(a,b,c){return b+"\x3c/pre\x3e"+c+"\x3cpre\x3e"}).replace(/([\s\S]*?)<\/pre>/gi,function(a,c){b.push(c)});return b}function B(a,b,c){var d="",e="";a=a.replace(/(^]+data-cke-bookmark.*?\/span>)|(]+data-cke-bookmark.*?\/span>$)/gi,function(a,b,c){b&&(d=b);c&&(e=c);return""});return d+a.replace(b,c)+e}function u(a,b){var c; +1=c?(g=e.createText(""),g.insertAfter(this)):(a=e.createText(""),a.insertAfter(g),a.remove()));return g},substring:function(a, +d){return"number"!=typeof d?this.$.nodeValue.substr(a):this.$.nodeValue.substring(a,d)}}); +(function(){function a(a,c,d){var g=a.serializable,k=c[d?"endContainer":"startContainer"],h=d?"endOffset":"startOffset",p=g?c.document.getById(a.startNode):a.startNode;a=g?c.document.getById(a.endNode):a.endNode;k.equals(p.getPrevious())?(c.startOffset=c.startOffset-k.getLength()-a.getPrevious().getLength(),k=a.getNext()):k.equals(a.getPrevious())&&(c.startOffset-=k.getLength(),k=a.getNext());k.equals(p.getParent())&&c[h]++;k.equals(a.getParent())&&c[h]++;c[d?"endContainer":"startContainer"]=k;return c} +CKEDITOR.dom.rangeList=function(a){if(a instanceof CKEDITOR.dom.rangeList)return a;a?a instanceof CKEDITOR.dom.range&&(a=[a]):a=[];return CKEDITOR.tools.extend(a,d)};var d={createIterator:function(){var a=this,c=CKEDITOR.dom.walker.bookmark(),d=[],g;return{getNextRange:function(k){g=void 0===g?0:g+1;var h=a[g];if(h&&1b?-1:1}),e=0,g;eCKEDITOR.env.version? +a[h].$.styleSheet.cssText+=g:a[h].$.innerHTML+=g}}var g={};CKEDITOR.skin={path:a,loadPart:function(c,d){CKEDITOR.skin.name!=CKEDITOR.skinName.split(",")[0]?CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(a()+"skin.js"),function(){b(c,d)}):b(c,d)},getPath:function(a){return CKEDITOR.getUrl(d(a))},icons:{},addIcon:function(a,b,c,d){a=a.toLowerCase();this.icons[a]||(this.icons[a]={path:b,offset:c||0,bgsize:d||"16px"})},getIconStyle:function(a,b,c,d,e){var g;a&&(a=a.toLowerCase(),b&&(g=this.icons[a+"-rtl"]), +g||(g=this.icons[a]));a=c||g&&g.path||"";d=d||g&&g.offset;e=e||g&&g.bgsize||"16px";a&&(a=a.replace(/'/g,"\\'"));return a&&"background-image:url('"+CKEDITOR.getUrl(a)+"');background-position:0 "+d+"px;background-size:"+e+";"}};CKEDITOR.tools.extend(CKEDITOR.editor.prototype,{getUiColor:function(){return this.uiColor},setUiColor:function(a){var b=c(CKEDITOR.document);return(this.setUiColor=function(a){this.uiColor=a;var c=CKEDITOR.skin.chameleon,d="",g="";"function"==typeof c&&(d=c(this,"editor"),g= +c(this,"panel"));a=[[p,a]];e([b],d,a);e(h,g,a)}).call(this,a)}});var k="cke_ui_color",h=[],p=/\$color/g;CKEDITOR.on("instanceLoaded",function(a){if(!CKEDITOR.env.ie||!CKEDITOR.env.quirks){var b=a.editor;a=function(a){a=(a.data[0]||a.data).element.getElementsByTag("iframe").getItem(0).getFrameDocument();if(!a.getById("cke_ui_color")){a=c(a);h.push(a);var d=b.getUiColor();d&&e([a],CKEDITOR.skin.chameleon(b,"panel"),[[p,d]])}};b.on("panelShow",a);b.on("menuShow",a);b.config.uiColor&&b.setUiColor(b.config.uiColor)}})})(); +(function(){if(CKEDITOR.env.webkit)CKEDITOR.env.hc=!1;else{var a=CKEDITOR.dom.element.createFromHtml('\x3cdiv style\x3d"width:0;height:0;position:absolute;left:-10000px;border:1px solid;border-color:red blue"\x3e\x3c/div\x3e',CKEDITOR.document);a.appendTo(CKEDITOR.document.getHead());try{var d=a.getComputedStyle("border-top-color"),b=a.getComputedStyle("border-right-color");CKEDITOR.env.hc=!(!d||d!=b)}catch(c){CKEDITOR.env.hc=!1}a.remove()}CKEDITOR.env.hc&&(CKEDITOR.env.cssClass+=" cke_hc");CKEDITOR.document.appendStyleText(".cke{visibility:hidden;}"); +CKEDITOR.status="loaded";CKEDITOR.fireOnce("loaded");if(a=CKEDITOR._.pending)for(delete CKEDITOR._.pending,d=0;de;e++){var f=e,c;c=parseInt(a[e],16);c=("0"+(0>d?0|c*(1+d):0|c+(255-c)*d).toString(16)).slice(-2);a[f]=c}return"#"+a.join("")}}(),f={editor:new CKEDITOR.template("{id}.cke_chrome [border-color:{defaultBorder};] {id} .cke_top [ background-color:{defaultBackground};border-bottom-color:{defaultBorder};] {id} .cke_bottom [background-color:{defaultBackground};border-top-color:{defaultBorder};] {id} .cke_resizer [border-right-color:{ckeResizer}] {id} .cke_dialog_title [background-color:{defaultBackground};border-bottom-color:{defaultBorder};] {id} .cke_dialog_footer [background-color:{defaultBackground};outline-color:{defaultBorder};] {id} .cke_dialog_tab [background-color:{dialogTab};border-color:{defaultBorder};] {id} .cke_dialog_tab:hover [background-color:{lightBackground};] {id} .cke_dialog_contents [border-top-color:{defaultBorder};] {id} .cke_dialog_tab_selected, {id} .cke_dialog_tab_selected:hover [background:{dialogTabSelected};border-bottom-color:{dialogTabSelectedBorder};] {id} .cke_dialog_body [background:{dialogBody};border-color:{defaultBorder};] {id} a.cke_button_off:hover,{id} a.cke_button_off:focus,{id} a.cke_button_off:active [background-color:{darkBackground};border-color:{toolbarElementsBorder};] {id} .cke_button_on [background-color:{ckeButtonOn};border-color:{toolbarElementsBorder};] {id} .cke_toolbar_separator,{id} .cke_toolgroup a.cke_button:last-child:after,{id} .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after [background-color: {toolbarElementsBorder};border-color: {toolbarElementsBorder};] {id} a.cke_combo_button:hover,{id} a.cke_combo_button:focus,{id} .cke_combo_on a.cke_combo_button [border-color:{toolbarElementsBorder};background-color:{darkBackground};] {id} .cke_combo:after [border-color:{toolbarElementsBorder};] {id} .cke_path_item [color:{elementsPathColor};] {id} a.cke_path_item:hover,{id} a.cke_path_item:focus,{id} a.cke_path_item:active [background-color:{darkBackground};] {id}.cke_panel [border-color:{defaultBorder};] "),panel:new CKEDITOR.template(".cke_panel_grouptitle [background-color:{lightBackground};border-color:{defaultBorder};] .cke_menubutton_icon [background-color:{menubuttonIcon};] .cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active [background-color:{menubuttonHover};] .cke_menubutton:hover .cke_menubutton_icon, .cke_menubutton:focus .cke_menubutton_icon, .cke_menubutton:active .cke_menubutton_icon [background-color:{menubuttonIconHover};] .cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon [background-color:{menubuttonIcon};] .cke_menuseparator [background-color:{menubuttonIcon};] a:hover.cke_colorbox, a:active.cke_colorbox [border-color:{defaultBorder};] a:hover.cke_colorauto, a:hover.cke_colormore, a:active.cke_colorauto, a:active.cke_colormore [background-color:{ckeColorauto};border-color:{defaultBorder};] ")}; +return function(g,d){var a=b(g.uiColor,.4),a={id:"."+g.id,defaultBorder:b(a,-.2),toolbarElementsBorder:b(a,-.25),defaultBackground:a,lightBackground:b(a,.8),darkBackground:b(a,-.15),ckeButtonOn:b(a,.4),ckeResizer:b(a,-.4),ckeColorauto:b(a,.8),dialogBody:b(a,.7),dialogTab:b(a,.65),dialogTabSelected:"#FFF",dialogTabSelectedBorder:"#FFF",elementsPathColor:b(a,-.6),menubuttonHover:b(a,.1),menubuttonIcon:b(a,.5),menubuttonIconHover:b(a,.3)};return f[d].output(a).replace(/\[/g,"{").replace(/\]/g,"}")}}();CKEDITOR.plugins.add("dialogui",{onLoad:function(){var h=function(b){this._||(this._={});this._["default"]=this._.initValue=b["default"]||"";this._.required=b.required||!1;for(var a=[this._],d=1;darguments.length)){var c=h.call(this,a);c.labelId=CKEDITOR.tools.getNextId()+ +"_label";this._.children=[];var e={role:a.role||"presentation"};a.includeLabel&&(e["aria-labelledby"]=c.labelId);CKEDITOR.ui.dialog.uiElement.call(this,b,a,d,"div",null,e,function(){var e=[],g=a.required?" cke_required":"";"horizontal"!=a.labelLayout?e.push('\x3clabel class\x3d"cke_dialog_ui_labeled_label'+g+'" ',' id\x3d"'+c.labelId+'"',c.inputId?' for\x3d"'+c.inputId+'"':"",(a.labelStyle?' style\x3d"'+a.labelStyle+'"':"")+"\x3e",a.label,"\x3c/label\x3e",'\x3cdiv class\x3d"cke_dialog_ui_labeled_content"', +a.controlStyle?' style\x3d"'+a.controlStyle+'"':"",' role\x3d"presentation"\x3e',f.call(this,b,a),"\x3c/div\x3e"):(g={type:"hbox",widths:a.widths,padding:0,children:[{type:"html",html:'\x3clabel class\x3d"cke_dialog_ui_labeled_label'+g+'" id\x3d"'+c.labelId+'" for\x3d"'+c.inputId+'"'+(a.labelStyle?' style\x3d"'+a.labelStyle+'"':"")+"\x3e"+CKEDITOR.tools.htmlEncode(a.label)+"\x3c/label\x3e"},{type:"html",html:'\x3cspan class\x3d"cke_dialog_ui_labeled_content"'+(a.controlStyle?' style\x3d"'+a.controlStyle+ +'"':"")+"\x3e"+f.call(this,b,a)+"\x3c/span\x3e"}]},CKEDITOR.dialog._.uiElementBuilders.hbox.build(b,g,e));return e.join("")})}},textInput:function(b,a,d){if(!(3>arguments.length)){h.call(this,a);var f=this._.inputId=CKEDITOR.tools.getNextId()+"_textInput",c={"class":"cke_dialog_ui_input_"+a.type,id:f,type:a.type};a.validate&&(this.validate=a.validate);a.maxLength&&(c.maxlength=a.maxLength);a.size&&(c.size=a.size);a.inputStyle&&(c.style=a.inputStyle);var e=this,m=!1;b.on("load",function(){e.getInputElement().on("keydown", +function(a){13==a.data.getKeystroke()&&(m=!0)});e.getInputElement().on("keyup",function(a){13==a.data.getKeystroke()&&m&&(b.getButton("ok")&&setTimeout(function(){b.getButton("ok").click()},0),m=!1);e.bidi&&w.call(e,a)},null,null,1E3)});CKEDITOR.ui.dialog.labeledElement.call(this,b,a,d,function(){var b=['\x3cdiv class\x3d"cke_dialog_ui_input_',a.type,'" role\x3d"presentation"'];a.width&&b.push('style\x3d"width:'+a.width+'" ');b.push("\x3e\x3cinput ");c["aria-labelledby"]=this._.labelId;this._.required&& +(c["aria-required"]=this._.required);for(var e in c)b.push(e+'\x3d"'+c[e]+'" ');b.push(" /\x3e\x3c/div\x3e");return b.join("")})}},textarea:function(b,a,d){if(!(3>arguments.length)){h.call(this,a);var f=this,c=this._.inputId=CKEDITOR.tools.getNextId()+"_textarea",e={};a.validate&&(this.validate=a.validate);e.rows=a.rows||5;e.cols=a.cols||20;e["class"]="cke_dialog_ui_input_textarea "+(a["class"]||"");"undefined"!=typeof a.inputStyle&&(e.style=a.inputStyle);a.dir&&(e.dir=a.dir);if(f.bidi)b.on("load", +function(){f.getInputElement().on("keyup",w)},f);CKEDITOR.ui.dialog.labeledElement.call(this,b,a,d,function(){e["aria-labelledby"]=this._.labelId;this._.required&&(e["aria-required"]=this._.required);var a=['\x3cdiv class\x3d"cke_dialog_ui_input_textarea" role\x3d"presentation"\x3e\x3ctextarea id\x3d"',c,'" '],b;for(b in e)a.push(b+'\x3d"'+CKEDITOR.tools.htmlEncode(e[b])+'" ');a.push("\x3e",CKEDITOR.tools.htmlEncode(f._["default"]),"\x3c/textarea\x3e\x3c/div\x3e");return a.join("")})}},checkbox:function(b, +a,d){if(!(3>arguments.length)){var f=h.call(this,a,{"default":!!a["default"]});a.validate&&(this.validate=a.validate);CKEDITOR.ui.dialog.uiElement.call(this,b,a,d,"span",null,null,function(){var c=CKEDITOR.tools.extend({},a,{id:a.id?a.id+"_checkbox":CKEDITOR.tools.getNextId()+"_checkbox"},!0),e=[],d=CKEDITOR.tools.getNextId()+"_label",g={"class":"cke_dialog_ui_checkbox_input",type:"checkbox","aria-labelledby":d};t(c);a["default"]&&(g.checked="checked");"undefined"!=typeof c.inputStyle&&(c.style=c.inputStyle); +f.checkbox=new CKEDITOR.ui.dialog.uiElement(b,c,e,"input",null,g);e.push(' \x3clabel id\x3d"',d,'" for\x3d"',g.id,'"'+(a.labelStyle?' style\x3d"'+a.labelStyle+'"':"")+"\x3e",CKEDITOR.tools.htmlEncode(a.label),"\x3c/label\x3e");return e.join("")})}},radio:function(b,a,d){if(!(3>arguments.length)){h.call(this,a);this._["default"]||(this._["default"]=this._.initValue=a.items[0][1]);a.validate&&(this.validate=a.validate);var f=[],c=this;a.role="radiogroup";a.includeLabel=!0;CKEDITOR.ui.dialog.labeledElement.call(this, +b,a,d,function(){for(var e=[],d=[],g=(a.id?a.id:CKEDITOR.tools.getNextId())+"_radio",k=0;karguments.length)){var f=h.call(this,a);a.validate&&(this.validate=a.validate);f.inputId=CKEDITOR.tools.getNextId()+"_select";CKEDITOR.ui.dialog.labeledElement.call(this,b,a,d,function(){var c=CKEDITOR.tools.extend({},a,{id:a.id?a.id+"_select":CKEDITOR.tools.getNextId()+"_select"},!0),e=[],d=[],g={id:f.inputId,"class":"cke_dialog_ui_input_select","aria-labelledby":this._.labelId};e.push('\x3cdiv class\x3d"cke_dialog_ui_input_', +a.type,'" role\x3d"presentation"');a.width&&e.push('style\x3d"width:'+a.width+'" ');e.push("\x3e");void 0!==a.size&&(g.size=a.size);void 0!==a.multiple&&(g.multiple=a.multiple);t(c);for(var k=0,l;karguments.length)){void 0===a["default"]&&(a["default"]="");var f=CKEDITOR.tools.extend(h.call(this,a),{definition:a,buttons:[]});a.validate&&(this.validate=a.validate);b.on("load",function(){CKEDITOR.document.getById(f.frameId).getParent().addClass("cke_dialog_ui_input_file")});CKEDITOR.ui.dialog.labeledElement.call(this,b,a,d,function(){f.frameId=CKEDITOR.tools.getNextId()+"_fileInput";var b=['\x3ciframe frameborder\x3d"0" allowtransparency\x3d"0" class\x3d"cke_dialog_ui_input_file" role\x3d"presentation" id\x3d"', +f.frameId,'" title\x3d"',a.label,'" src\x3d"javascript:void('];b.push(CKEDITOR.env.ie?"(function(){"+encodeURIComponent("document.open();("+CKEDITOR.tools.fixDomain+")();document.close();")+"})()":"0");b.push(')"\x3e\x3c/iframe\x3e');return b.join("")})}},fileButton:function(b,a,d){var f=this;if(!(3>arguments.length)){h.call(this,a);a.validate&&(this.validate=a.validate);var c=CKEDITOR.tools.extend({},a),e=c.onClick;c.className=(c.className?c.className+" ":"")+"cke_dialog_ui_button";c.onClick=function(c){var d= +a["for"];e&&!1===e.call(this,c)||(b.getContentElement(d[0],d[1]).submit(),this.disable())};b.on("load",function(){b.getContentElement(a["for"][0],a["for"][1])._.buttons.push(f)});CKEDITOR.ui.dialog.button.call(this,b,c,d)}},html:function(){var b=/^\s*<[\w:]+\s+([^>]*)?>/,a=/^(\s*<[\w:]+(?:\s+[^>]*)?)((?:.|\r|\n)+)$/,d=/\/$/;return function(f,c,e){if(!(3>arguments.length)){var m=[],g=c.html;"\x3c"!=g.charAt(0)&&(g="\x3cspan\x3e"+g+"\x3c/span\x3e");var k=c.focus;if(k){var l=this.focus;this.focus=function(){("function"== +typeof k?k:l).call(this);this.fire("focus")};c.isFocusable&&(this.isFocusable=this.isFocusable);this.keyboardFocusable=!0}CKEDITOR.ui.dialog.uiElement.call(this,f,c,m,"span",null,null,"");m=m.join("").match(b);g=g.match(a)||["","",""];d.test(g[1])&&(g[1]=g[1].slice(0,-1),g[2]="/"+g[2]);e.push([g[1]," ",m[1]||"",g[2]].join(""))}}}(),fieldset:function(b,a,d,f,c){var e=c.label;this._={children:a};CKEDITOR.ui.dialog.uiElement.call(this,b,c,f,"fieldset",null,null,function(){var a=[];e&&a.push("\x3clegend"+ +(c.labelStyle?' style\x3d"'+c.labelStyle+'"':"")+"\x3e"+e+"\x3c/legend\x3e");for(var b=0;ba.getChildCount()?(new CKEDITOR.dom.text(b,CKEDITOR.document)).appendTo(a):a.getChild(0).$.nodeValue=b;return this},getLabel:function(){var b= +CKEDITOR.document.getById(this._.labelId);return!b||1>b.getChildCount()?"":b.getChild(0).getText()},eventProcessors:r},!0);CKEDITOR.ui.dialog.button.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.uiElement,{click:function(){return this._.disabled?!1:this.fire("click",{dialog:this._.dialog})},enable:function(){this._.disabled=!1;var b=this.getElement();b&&b.removeClass("cke_disabled")},disable:function(){this._.disabled=!0;this.getElement().addClass("cke_disabled")},isVisible:function(){return this.getElement().getFirst().isVisible()}, +isEnabled:function(){return!this._.disabled},eventProcessors:CKEDITOR.tools.extend({},CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors,{onClick:function(b,a){this.on("click",function(){a.apply(this,arguments)})}},!0),accessKeyUp:function(){this.click()},accessKeyDown:function(){this.focus()},keyboardFocusable:!0},!0);CKEDITOR.ui.dialog.textInput.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return CKEDITOR.document.getById(this._.inputId)}, +focus:function(){var b=this.selectParentTab();setTimeout(function(){var a=b.getInputElement();a&&a.$.focus()},0)},select:function(){var b=this.selectParentTab();setTimeout(function(){var a=b.getInputElement();a&&(a.$.focus(),a.$.select())},0)},accessKeyUp:function(){this.select()},setValue:function(b){if(this.bidi){var a=b&&b.charAt(0);(a="‪"==a?"ltr":"‫"==a?"rtl":null)&&(b=b.slice(1));this.setDirectionMarker(a)}b||(b="");return CKEDITOR.ui.dialog.uiElement.prototype.setValue.apply(this,arguments)}, +getValue:function(){var b=CKEDITOR.ui.dialog.uiElement.prototype.getValue.call(this);if(this.bidi&&b){var a=this.getDirectionMarker();a&&(b=("ltr"==a?"‪":"‫")+b)}return b},setDirectionMarker:function(b){var a=this.getInputElement();b?a.setAttributes({dir:b,"data-cke-dir-marker":b}):this.getDirectionMarker()&&a.removeAttributes(["dir","data-cke-dir-marker"])},getDirectionMarker:function(){return this.getInputElement().data("cke-dir-marker")},keyboardFocusable:!0},q,!0);CKEDITOR.ui.dialog.textarea.prototype= +new CKEDITOR.ui.dialog.textInput;CKEDITOR.ui.dialog.select.prototype=CKEDITOR.tools.extend(new CKEDITOR.ui.dialog.labeledElement,{getInputElement:function(){return this._.select.getElement()},add:function(b,a,d){var f=new CKEDITOR.dom.element("option",this.getDialog().getParentEditor().document),c=this.getInputElement().$;f.$.text=b;f.$.value=void 0===a||null===a?b:a;void 0===d||null===d?CKEDITOR.env.ie?c.add(f.$):c.add(f.$,null):c.add(f.$,d);return this},remove:function(b){this.getInputElement().$.remove(b); +return this},clear:function(){for(var b=this.getInputElement().$;0b-a;c--)if(this._.tabs[this._.tabIdList[c%a]][0].$.offsetHeight)return this._.tabIdList[c%a];return null}function A(){for(var a=this._.tabIdList.length,b=CKEDITOR.tools.indexOf(this._.tabIdList,this._.currentTabId),c=b+1;ck.width-c.width-g?k.width-c.width+("rtl"==f.lang.dir?0:h[1]):d.x,d.y+h[0]k.height-c.height-g?k.height-c.height+h[2]:d.y,1);b.data.preventDefault()} +function c(){CKEDITOR.document.removeListener("mousemove",b);CKEDITOR.document.removeListener("mouseup",c);if(CKEDITOR.env.ie6Compat){var a=u.getChild(0).getFrameDocument();a.removeListener("mousemove",b);a.removeListener("mouseup",c)}}var e=null,d=null,f=a.getParentEditor(),g=f.config.dialog_magnetDistance,h=CKEDITOR.skin.margins||[0,0,0,0];"undefined"==typeof g&&(g=20);a.parts.title.on("mousedown",function(g){e={x:g.data.$.screenX,y:g.data.$.screenY};CKEDITOR.document.on("mousemove",b);CKEDITOR.document.on("mouseup", +c);d=a.getPosition();if(CKEDITOR.env.ie6Compat){var f=u.getChild(0).getFrameDocument();f.on("mousemove",b);f.on("mouseup",c)}g.data.preventDefault()},a)}function Z(a){function b(b){var c="rtl"==f.lang.dir,n=k.width,q=k.height,G=n+(b.data.$.screenX-m.x)*(c?-1:1)*(a._.moved?1:2),H=q+(b.data.$.screenY-m.y)*(a._.moved?1:2),B=a._.element.getFirst(),B=c&&B.getComputedStyle("right"),C=a.getPosition();C.y+H>p.height&&(H=p.height-C.y);(c?B:C.x)+G>p.width&&(G=p.width-(c?B:C.x));if(d==CKEDITOR.DIALOG_RESIZE_WIDTH|| +d==CKEDITOR.DIALOG_RESIZE_BOTH)n=Math.max(e.minWidth||0,G-g);if(d==CKEDITOR.DIALOG_RESIZE_HEIGHT||d==CKEDITOR.DIALOG_RESIZE_BOTH)q=Math.max(e.minHeight||0,H-h);a.resize(n,q);a._.moved||a.layout();b.data.preventDefault()}function c(){CKEDITOR.document.removeListener("mouseup",c);CKEDITOR.document.removeListener("mousemove",b);q&&(q.remove(),q=null);if(CKEDITOR.env.ie6Compat){var a=u.getChild(0).getFrameDocument();a.removeListener("mouseup",c);a.removeListener("mousemove",b)}}var e=a.definition,d=e.resizable; +if(d!=CKEDITOR.DIALOG_RESIZE_NONE){var f=a.getParentEditor(),g,h,p,m,k,q,n=CKEDITOR.tools.addFunction(function(d){k=a.getSize();var e=a.parts.contents;e.$.getElementsByTagName("iframe").length&&(q=CKEDITOR.dom.element.createFromHtml('\x3cdiv class\x3d"cke_dialog_resize_cover" style\x3d"height: 100%; position: absolute; width: 100%;"\x3e\x3c/div\x3e'),e.append(q));h=k.height-a.parts.contents.getSize("height",!(CKEDITOR.env.gecko||CKEDITOR.env.ie&&CKEDITOR.env.quirks));g=k.width-a.parts.contents.getSize("width", +1);m={x:d.screenX,y:d.screenY};p=CKEDITOR.document.getWindow().getViewPaneSize();CKEDITOR.document.on("mousemove",b);CKEDITOR.document.on("mouseup",c);CKEDITOR.env.ie6Compat&&(e=u.getChild(0).getFrameDocument(),e.on("mousemove",b),e.on("mouseup",c));d.preventDefault&&d.preventDefault()});a.on("load",function(){var b="";d==CKEDITOR.DIALOG_RESIZE_WIDTH?b=" cke_resizer_horizontal":d==CKEDITOR.DIALOG_RESIZE_HEIGHT&&(b=" cke_resizer_vertical");b=CKEDITOR.dom.element.createFromHtml('\x3cdiv class\x3d"cke_resizer'+ +b+" cke_resizer_"+f.lang.dir+'" title\x3d"'+CKEDITOR.tools.htmlEncode(f.lang.common.resize)+'" onmousedown\x3d"CKEDITOR.tools.callFunction('+n+', event )"\x3e'+("ltr"==f.lang.dir?"◢":"◣")+"\x3c/div\x3e");a.parts.footer.append(b,1)});f.on("destroy",function(){CKEDITOR.tools.removeFunction(n)})}}function I(a){a.data.preventDefault(1)}function N(a){var b=CKEDITOR.document.getWindow(),c=a.config,e=CKEDITOR.skinName||a.config.skin,d=c.dialog_backgroundCoverColor||("moono-lisa"==e?"black":"white"),e=c.dialog_backgroundCoverOpacity, +f=c.baseFloatZIndex,c=CKEDITOR.tools.genKey(d,e,f),g=z[c];g?g.show():(f=['\x3cdiv tabIndex\x3d"-1" style\x3d"position: ',CKEDITOR.env.ie6Compat?"absolute":"fixed","; z-index: ",f,"; top: 0px; left: 0px; ",CKEDITOR.env.ie6Compat?"":"background-color: "+d,'" class\x3d"cke_dialog_background_cover"\x3e'],CKEDITOR.env.ie6Compat&&(d="\x3chtml\x3e\x3cbody style\x3d\\'background-color:"+d+";\\'\x3e\x3c/body\x3e\x3c/html\x3e",f.push('\x3ciframe hidefocus\x3d"true" frameborder\x3d"0" id\x3d"cke_dialog_background_iframe" src\x3d"javascript:'), +f.push("void((function(){"+encodeURIComponent("document.open();("+CKEDITOR.tools.fixDomain+")();document.write( '"+d+"' );document.close();")+"})())"),f.push('" style\x3d"position:absolute;left:0;top:0;width:100%;height: 100%;filter: progid:DXImageTransform.Microsoft.Alpha(opacity\x3d0)"\x3e\x3c/iframe\x3e')),f.push("\x3c/div\x3e"),g=CKEDITOR.dom.element.createFromHtml(f.join("")),g.setOpacity(void 0!==e?e:.5),g.on("keydown",I),g.on("keypress",I),g.on("keyup",I),g.appendTo(CKEDITOR.document.getBody()), +z[c]=g);a.focusManager.add(g);u=g;a=function(){var a=b.getViewPaneSize();g.setStyles({width:a.width+"px",height:a.height+"px"})};var h=function(){var a=b.getScrollPosition(),c=CKEDITOR.dialog._.currentTop;g.setStyles({left:a.x+"px",top:a.y+"px"});if(c){do a=c.getPosition(),c.move(a.x,a.y);while(c=c._.parentDialog)}};J=a;b.on("resize",a);a();CKEDITOR.env.mac&&CKEDITOR.env.webkit||g.focus();if(CKEDITOR.env.ie6Compat){var p=function(){h();arguments.callee.prevScrollHandler.apply(this,arguments)};b.$.setTimeout(function(){p.prevScrollHandler= +window.onscroll||function(){};window.onscroll=p},0);h()}}function O(a){u&&(a.focusManager.remove(u),a=CKEDITOR.document.getWindow(),u.hide(),a.removeListener("resize",J),CKEDITOR.env.ie6Compat&&a.$.setTimeout(function(){window.onscroll=window.onscroll&&window.onscroll.prevScrollHandler||null},0),J=null)}var v=CKEDITOR.tools.cssLength,W='\x3cdiv class\x3d"cke_reset_all {editorId} {editorDialogClass} {hidpi}" dir\x3d"{langDir}" lang\x3d"{langCode}" role\x3d"dialog" aria-labelledby\x3d"cke_dialog_title_{id}"\x3e\x3ctable class\x3d"cke_dialog '+ +CKEDITOR.env.cssClass+' cke_{langDir}" style\x3d"position:absolute" role\x3d"presentation"\x3e\x3ctr\x3e\x3ctd role\x3d"presentation"\x3e\x3cdiv class\x3d"cke_dialog_body" role\x3d"presentation"\x3e\x3cdiv id\x3d"cke_dialog_title_{id}" class\x3d"cke_dialog_title" role\x3d"presentation"\x3e\x3c/div\x3e\x3ca id\x3d"cke_dialog_close_button_{id}" class\x3d"cke_dialog_close_button" href\x3d"javascript:void(0)" title\x3d"{closeTitle}" role\x3d"button"\x3e\x3cspan class\x3d"cke_label"\x3eX\x3c/span\x3e\x3c/a\x3e\x3cdiv id\x3d"cke_dialog_tabs_{id}" class\x3d"cke_dialog_tabs" role\x3d"tablist"\x3e\x3c/div\x3e\x3ctable class\x3d"cke_dialog_contents" role\x3d"presentation"\x3e\x3ctr\x3e\x3ctd id\x3d"cke_dialog_contents_{id}" class\x3d"cke_dialog_contents_body" role\x3d"presentation"\x3e\x3c/td\x3e\x3c/tr\x3e\x3ctr\x3e\x3ctd id\x3d"cke_dialog_footer_{id}" class\x3d"cke_dialog_footer" role\x3d"presentation"\x3e\x3c/td\x3e\x3c/tr\x3e\x3c/table\x3e\x3c/div\x3e\x3c/td\x3e\x3c/tr\x3e\x3c/table\x3e\x3c/div\x3e'; +CKEDITOR.dialog=function(a,b){function c(){var a=l._.focusList;a.sort(function(a,b){return a.tabIndex!=b.tabIndex?b.tabIndex-a.tabIndex:a.focusIndex-b.focusIndex});for(var b=a.length,c=0;cb.length)){var c=l._.currentFocusIndex;l._.tabBarMode&&0>a&&(c=0);try{b[c].getInputElement().$.blur()}catch(d){}var e=c,g=1c.height|| +b.width+(0c.width?a.setStyle("position","absolute"):a.setStyle("position","fixed"));this.move(this._.moved?this._.position.x:e,this._.moved?this._.position.y:d)},foreach:function(a){for(var b in this._.contents)for(var c in this._.contents[b])a.call(this,this._.contents[b][c]);return this},reset:function(){var a=function(a){a.reset&&a.reset(1)};return function(){this.foreach(a);return this}}(),setupContent:function(){var a=arguments;this.foreach(function(b){b.setup&&b.setup.apply(b,a)})}, +commitContent:function(){var a=arguments;this.foreach(function(b){CKEDITOR.env.ie&&this._.currentFocusIndex==b.focusIndex&&b.getInputElement().$.blur();b.commit&&b.commit.apply(b,a)})},hide:function(){if(this.parts.dialog.isVisible()){this.fire("hide",{});this._.editor.fire("dialogHide",this);this.selectPage(this._.tabIdList[0]);var a=this._.element;a.setStyle("display","none");this.parts.dialog.setStyle("visibility","hidden");for(ba(this);CKEDITOR.dialog._.currentTop!=this;)CKEDITOR.dialog._.currentTop.hide(); +if(this._.parentDialog){var b=this._.parentDialog.getElement().getFirst();b.setStyle("z-index",parseInt(b.$.style.zIndex,10)+Math.floor(this._.editor.config.baseFloatZIndex/2))}else O(this._.editor);if(CKEDITOR.dialog._.currentTop=this._.parentDialog)CKEDITOR.dialog._.currentZIndex-=10;else{CKEDITOR.dialog._.currentZIndex=null;a.removeListener("keydown",Q);a.removeListener("keyup",R);var c=this._.editor;c.focus();setTimeout(function(){c.focusManager.unlock();CKEDITOR.env.iOS&&c.window.focus()},0)}delete this._.parentDialog; +this.foreach(function(a){a.resetInitValue&&a.resetInitValue()});this.setState(CKEDITOR.DIALOG_STATE_IDLE)}},addPage:function(a){if(!a.requiredContent||this._.editor.filter.check(a.requiredContent)){for(var b=[],c=a.label?' title\x3d"'+CKEDITOR.tools.htmlEncode(a.label)+'"':"",e=CKEDITOR.dialog._.uiElementBuilders.vbox.build(this,{type:"vbox",className:"cke_dialog_page_contents",children:a.elements,expand:!!a.expand,padding:a.padding,style:a.style||"width: 100%;"},b),d=this._.contents[a.id]={},f=e.getChild(), +g=0;e=f.shift();)e.notAllowed||"hbox"==e.type||"vbox"==e.type||g++,d[e.id]=e,"function"==typeof e.getChild&&f.push.apply(f,e.getChild());g||(a.hidden=!0);b=CKEDITOR.dom.element.createFromHtml(b.join(""));b.setAttribute("role","tabpanel");e=CKEDITOR.env;d="cke_"+a.id+"_"+CKEDITOR.tools.getNextNumber();c=CKEDITOR.dom.element.createFromHtml(['\x3ca class\x3d"cke_dialog_tab"',0arguments.length)){var h=(e.call?e(b):e)|| +"div",p=["\x3c",h," "],m=(d&&d.call?d(b):d)||{},k=(f&&f.call?f(b):f)||{},q=(g&&g.call?g.call(this,a,b):g)||"",n=this.domId=k.id||CKEDITOR.tools.getNextId()+"_uiElement";b.requiredContent&&!a.getParentEditor().filter.check(b.requiredContent)&&(m.display="none",this.notAllowed=!0);k.id=n;var r={};b.type&&(r["cke_dialog_ui_"+b.type]=1);b.className&&(r[b.className]=1);b.disabled&&(r.cke_disabled=1);for(var l=k["class"]&&k["class"].split?k["class"].split(" "):[],n=0;nCKEDITOR.env.version?"cke_dialog_ui_focused":"";b.on("focus",function(){a._.tabBarMode=!1;a._.hasFocus=!0;t.fire("focus");c&&this.addClass(c)});b.on("blur",function(){t.fire("blur");c&&this.removeClass(c)})}});CKEDITOR.tools.extend(this,b);this.keyboardFocusable&&(this.tabIndex= +b.tabIndex||0,this.focusIndex=a._.focusList.push(this)-1,this.on("focus",function(){a._.currentFocusIndex=t.focusIndex}))}},hbox:function(a,b,c,e,d){if(!(4>arguments.length)){this._||(this._={});var f=this._.children=b,g=d&&d.widths||null,h=d&&d.height||null,p,m={role:"presentation"};d&&d.align&&(m.align=d.align);CKEDITOR.ui.dialog.uiElement.call(this,a,d||{type:"hbox"},e,"table",{},m,function(){var a=['\x3ctbody\x3e\x3ctr class\x3d"cke_dialog_ui_hbox"\x3e'];for(p=0;parguments.length)){this._||(this._={});var f=this._.children=b,g=d&&d.width||null,h=d&&d.heights||null;CKEDITOR.ui.dialog.uiElement.call(this,a,d||{type:"vbox"},e,"div",null,{role:"presentation"},function(){var b=['\x3ctable role\x3d"presentation" cellspacing\x3d"0" border\x3d"0" '];b.push('style\x3d"');d&&d.expand&&b.push("height:100%;");b.push("width:"+v(g||"100%"),";");CKEDITOR.env.webkit&&b.push("float:none;");b.push('"');b.push('align\x3d"', +CKEDITOR.tools.htmlEncode(d&&d.align||("ltr"==a.getParentEditor().lang.dir?"left":"right")),'" ');b.push("\x3e\x3ctbody\x3e");for(var e=0;earguments.length)return this._.children.concat();a.splice||(a=[a]);return 2> +a.length?this._.children[a[0]]:this._.children[a[0]]&&this._.children[a[0]].getChild?this._.children[a[0]].getChild(a.slice(1,a.length)):null}},!0);CKEDITOR.ui.dialog.vbox.prototype=new CKEDITOR.ui.dialog.hbox;(function(){var a={build:function(a,c,e){for(var d=c.children,f,g=[],h=[],p=0;pe.length&&(a=g.document.createElement(g.config.enterMode==CKEDITOR.ENTER_P?"p":"div"),b=h.shift(),c.insertNode(a),a.append(new CKEDITOR.dom.text("",g.document)),c.moveToBookmark(b),c.selectNodeContents(a),c.collapse(!0),b=c.createBookmark(),e.push(a),h.unshift(b));d=e[0].getParent();c=[];for(b=0;b]+data-cke-bookmark[^<]*?<\/span>/ig,"");d&&q(b,c)})}function r(){if("wysiwyg"==b.mode){var a=t("paste");b.getCommand("cut").setState(t("cut")); +b.getCommand("copy").setState(t("copy"));b.getCommand("paste").setState(a);b.fire("pasteState",a)}}function t(a){if(x&&a in{paste:1,cut:1})return CKEDITOR.TRISTATE_DISABLED;if("paste"==a)return CKEDITOR.TRISTATE_OFF;a=b.getSelection();var c=a.getRanges();return a.getType()==CKEDITOR.SELECTION_NONE||1==c.length&&c[0].collapsed?CKEDITOR.TRISTATE_DISABLED:CKEDITOR.TRISTATE_OFF}var m=CKEDITOR.plugins.clipboard,p=0,v=0,x=0;(function(){b.on("key",k);b.on("contentDom",a);b.on("selectionChange",function(b){x= +b.data.selection.getRanges()[0].checkReadOnly();r()});b.contextMenu&&b.contextMenu.addListener(function(b,a){x=a.getRanges()[0].checkReadOnly();return{cut:t("cut"),copy:t("copy"),paste:t("paste")}})})();(function(){function a(c,d,g,e,h){var k=b.lang.clipboard[d];b.addCommand(d,g);b.ui.addButton&&b.ui.addButton(c,{label:k,command:d,toolbar:"clipboard,"+e});b.addMenuItems&&b.addMenuItem(d,{label:k,command:d,group:"clipboard",order:h})}a("Cut","cut",c("cut"),10,1);a("Copy","copy",c("copy"),20,4);a("Paste", +"paste",e(),30,8)})();b.getClipboardData=function(a,c){function d(a){a.removeListener();a.cancel();c(a.data)}function g(a){a.removeListener();a.cancel();f=!0;c({type:k,dataValue:a.data.dataValue,dataTransfer:a.data.dataTransfer,method:"paste"})}function e(){this.customTitle=a&&a.title}var h=!1,k="auto",f=!1;c||(c=a,a=null);b.on("paste",d,null,null,0);b.on("beforePaste",function(a){a.removeListener();h=!0;k=a.data.type},null,null,1E3);!1===w()&&(b.removeListener("paste",d),h&&b.fire("pasteDialog", +e)?(b.on("pasteDialogCommit",g),b.on("dialogHide",function(a){a.removeListener();a.data.removeListener("pasteDialogCommit",g);setTimeout(function(){f||c(null)},10)})):c(null))}}function A(b){if(CKEDITOR.env.webkit){if(!b.match(/^[^<]*$/g)&&!b.match(/^(
      <\/div>|
      [^<]*<\/div>)*$/gi))return"html"}else if(CKEDITOR.env.ie){if(!b.match(/^([^<]|)*$/gi)&&!b.match(/^(

      ([^<]|)*<\/p>|(\r\n))*$/gi))return"html"}else if(CKEDITOR.env.gecko){if(!b.match(/^([^<]|)*$/gi))return"html"}else return"html"; +return"htmlifiedtext"}function B(b,a){function c(a){return CKEDITOR.tools.repeat("\x3c/p\x3e\x3cp\x3e",~~(a/2))+(1==a%2?"\x3cbr\x3e":"")}a=a.replace(/\s+/g," ").replace(/> +/gi,"\x3cbr\x3e");a=a.replace(/<\/?[A-Z]+>/g,function(a){return a.toLowerCase()});if(a.match(/^[^<]$/))return a;CKEDITOR.env.webkit&&-1(
      |)<\/div>)(?!$|(

      (
      |)<\/div>))/g,"\x3cbr\x3e").replace(/^(
      (
      |)<\/div>){2}(?!$)/g,"\x3cdiv\x3e\x3c/div\x3e"), +a.match(/
      (
      |)<\/div>/)&&(a="\x3cp\x3e"+a.replace(/(
      (
      |)<\/div>)+/g,function(a){return c(a.split("\x3c/div\x3e\x3cdiv\x3e").length+1)})+"\x3c/p\x3e"),a=a.replace(/<\/div>
      /g,"\x3cbr\x3e"),a=a.replace(/<\/?div>/g,""));CKEDITOR.env.gecko&&b.enterMode!=CKEDITOR.ENTER_BR&&(CKEDITOR.env.gecko&&(a=a.replace(/^

      $/,"\x3cbr\x3e")),-1){2,}/g,function(a){return c(a.length/4)})+"\x3c/p\x3e"));return C(b,a)}function D(){function b(){var a= +{},b;for(b in CKEDITOR.dtd)"$"!=b.charAt(0)&&"div"!=b&&"span"!=b&&(a[b]=1);return a}var a={};return{get:function(c){return"plain-text"==c?a.plainText||(a.plainText=new CKEDITOR.filter("br")):"semantic-content"==c?((c=a.semanticContent)||(c=new CKEDITOR.filter,c.allow({$1:{elements:b(),attributes:!0,styles:!1,classes:!1}}),c=a.semanticContent=c),c):c?new CKEDITOR.filter(c):null}}}function y(b,a,c){a=CKEDITOR.htmlParser.fragment.fromHtml(a);var e=new CKEDITOR.htmlParser.basicWriter;c.applyTo(a,!0,!1, +b.activeEnterMode);a.writeHtml(e);return e.getHtml()}function C(b,a){b.enterMode==CKEDITOR.ENTER_BR?a=a.replace(/(<\/p>

      )+/g,function(a){return CKEDITOR.tools.repeat("\x3cbr\x3e",a.length/7*2)}).replace(/<\/?p>/g,""):b.enterMode==CKEDITOR.ENTER_DIV&&(a=a.replace(/<(\/)?p>/g,"\x3c$1div\x3e"));return a}function E(b){b.data.preventDefault();b.data.$.dataTransfer.dropEffect="none"}function F(b){var a=CKEDITOR.plugins.clipboard;b.on("contentDom",function(){function c(a,c,d){c.select();q(b,{dataTransfer:d, +method:"drop"},1);d.sourceEditor.fire("saveSnapshot");d.sourceEditor.editable().extractHtmlFromRange(a);d.sourceEditor.getSelection().selectRanges([a]);d.sourceEditor.fire("saveSnapshot")}function e(d,c){d.select();q(b,{dataTransfer:c,method:"drop"},1);a.resetDragDataTransfer()}function f(a,d,c){var g={$:a.data.$,target:a.data.getTarget()};d&&(g.dragRange=d);c&&(g.dropRange=c);!1===b.fire(a.name,g)&&a.data.preventDefault()}function g(a){a.type!=CKEDITOR.NODE_ELEMENT&&(a=a.getParent());return a.getChildCount()} +var d=b.editable(),h=CKEDITOR.plugins.clipboard.getDropTarget(b),n=b.ui.space("top"),w=b.ui.space("bottom");a.preventDefaultDropOnElement(n);a.preventDefaultDropOnElement(w);d.attachListener(h,"dragstart",f);d.attachListener(b,"dragstart",a.resetDragDataTransfer,a,null,1);d.attachListener(b,"dragstart",function(d){a.initDragDataTransfer(d,b)},null,null,2);d.attachListener(b,"dragstart",function(){var d=a.dragRange=b.getSelection().getRanges()[0];CKEDITOR.env.ie&&10>CKEDITOR.env.version&&(a.dragStartContainerChildCount= +d?g(d.startContainer):null,a.dragEndContainerChildCount=d?g(d.endContainer):null)},null,null,100);d.attachListener(h,"dragend",f);d.attachListener(b,"dragend",a.initDragDataTransfer,a,null,1);d.attachListener(b,"dragend",a.resetDragDataTransfer,a,null,100);d.attachListener(h,"dragover",function(a){var b=a.data.getTarget();b&&b.is&&b.is("html")?a.data.preventDefault():CKEDITOR.env.ie&&CKEDITOR.plugins.clipboard.isFileApiSupported&&a.data.$.dataTransfer.types.contains("Files")&&a.data.preventDefault()}); +d.attachListener(h,"drop",function(d){if(!d.data.$.defaultPrevented){d.data.preventDefault();var c=d.data.getTarget();if(!c.isReadOnly()||c.type==CKEDITOR.NODE_ELEMENT&&c.is("html")){var c=a.getRangeAtDropPosition(d,b),g=a.dragRange;c&&f(d,g,c)}}},null,null,9999);d.attachListener(b,"drop",a.initDragDataTransfer,a,null,1);d.attachListener(b,"drop",function(d){if(d=d.data){var g=d.dropRange,h=d.dragRange,f=d.dataTransfer;f.getTransferType(b)==CKEDITOR.DATA_TRANSFER_INTERNAL?setTimeout(function(){a.internalDrop(h, +g,f,b)},0):f.getTransferType(b)==CKEDITOR.DATA_TRANSFER_CROSS_EDITORS?c(h,g,f):e(g,f)}},null,null,9999)})}CKEDITOR.plugins.add("clipboard",{requires:"dialog",init:function(b){var a,c=D();b.config.forcePasteAsPlainText?a="plain-text":b.config.pasteFilter?a=b.config.pasteFilter:!CKEDITOR.env.webkit||"pasteFilter"in b.config||(a="semantic-content");b.pasteFilter=c.get(a);z(b);F(b);CKEDITOR.dialog.add("paste",CKEDITOR.getUrl(this.path+"dialogs/paste.js"));if(CKEDITOR.env.gecko){var e=["image/png","image/jpeg", +"image/gif"],f;b.on("paste",function(a){var d=a.data,c=d.dataTransfer;if(!d.dataValue&&"paste"==d.method&&c&&1==c.getFilesCount()&&f!=c.id&&(c=c.getFile(0),-1!=CKEDITOR.tools.indexOf(e,c.type))){var n=new FileReader;n.addEventListener("load",function(){a.data.dataValue='\x3cimg src\x3d"'+n.result+'" /\x3e';b.fire("paste",a.data)},!1);n.addEventListener("abort",function(){b.fire("paste",a.data)},!1);n.addEventListener("error",function(){b.fire("paste",a.data)},!1);n.readAsDataURL(c);f=d.dataTransfer.id; +a.stop()}},null,null,1)}b.on("paste",function(a){a.data.dataTransfer||(a.data.dataTransfer=new CKEDITOR.plugins.clipboard.dataTransfer);if(!a.data.dataValue){var d=a.data.dataTransfer,c=d.getData("text/html");if(c)a.data.dataValue=c,a.data.type="html";else if(c=d.getData("text/plain"))a.data.dataValue=b.editable().transformPlainTextToHtml(c),a.data.type="text"}},null,null,1);b.on("paste",function(a){var b=a.data.dataValue,c=CKEDITOR.dtd.$block;-1 <\/span>/gi, +" "),"html"!=a.data.type&&(b=b.replace(/]*>([^<]*)<\/span>/gi,function(a,b){return b.replace(/\t/g,"\x26nbsp;\x26nbsp; \x26nbsp;")})),-1/,"")),b=b.replace(/(<[^>]+) class="Apple-[^"]*"/gi,"$1"));if(b.match(/^<[^<]+cke_(editable|contents)/i)){var e,f,k=new CKEDITOR.dom.element("div");for(k.setHtml(b);1==k.getChildCount()&& +(e=k.getFirst())&&e.type==CKEDITOR.NODE_ELEMENT&&(e.hasClass("cke_editable")||e.hasClass("cke_contents"));)k=f=e;f&&(b=f.getHtml().replace(/
      $/i,""))}CKEDITOR.env.ie?b=b.replace(/^ (?: |\r\n)?<(\w+)/g,function(b,d){return d.toLowerCase()in c?(a.data.preSniffing="html","\x3c"+d):b}):CKEDITOR.env.webkit?b=b.replace(/<\/(\w+)>


      <\/div>$/,function(b,d){return d in c?(a.data.endsWithEOL=1,"\x3c/"+d+"\x3e"):b}):CKEDITOR.env.gecko&&(b=b.replace(/(\s)
      $/,"$1"));a.data.dataValue=b},null, +null,3);b.on("paste",function(a){a=a.data;var d=a.type,e=a.dataValue,f,p=b.config.clipboard_defaultContentType||"html",k=a.dataTransfer.getTransferType(b);f="html"==d||"html"==a.preSniffing?"html":A(e);"htmlifiedtext"==f&&(e=B(b.config,e));"text"==d&&"html"==f?e=y(b,e,c.get("plain-text")):k==CKEDITOR.DATA_TRANSFER_EXTERNAL&&b.pasteFilter&&!a.dontFilter&&(e=y(b,e,b.pasteFilter));a.startsWithEOL&&(e='\x3cbr data-cke-eol\x3d"1"\x3e'+e);a.endsWithEOL&&(e+='\x3cbr data-cke-eol\x3d"1"\x3e');"auto"==d&& +(d="html"==f||"html"==p?"html":"text");a.type=d;a.dataValue=e;delete a.preSniffing;delete a.startsWithEOL;delete a.endsWithEOL},null,null,6);b.on("paste",function(a){a=a.data;a.dataValue&&(b.insertHtml(a.dataValue,a.type,a.range),setTimeout(function(){b.fire("afterPaste")},0))},null,null,1E3);b.on("pasteDialog",function(a){setTimeout(function(){b.openDialog("paste",a.data)},0)})}});CKEDITOR.plugins.clipboard={isCustomCopyCutSupported:!CKEDITOR.env.ie&&!CKEDITOR.env.iOS,isCustomDataTypesSupported:!CKEDITOR.env.ie, +isFileApiSupported:!CKEDITOR.env.ie||9CKEDITOR.env.version||a.isInline()?a:b.document},fixSplitNodesAfterDrop:function(b,a,c,e){function f(b, +c,e){var f=b;f.type==CKEDITOR.NODE_TEXT&&(f=b.getParent());if(f.equals(c)&&e!=c.getChildCount())return b=a.startContainer.getChild(a.startOffset-1),c=a.startContainer.getChild(a.startOffset),b&&b.type==CKEDITOR.NODE_TEXT&&c&&c.type==CKEDITOR.NODE_TEXT&&(e=b.getLength(),b.setText(b.getText()+c.getText()),c.remove(),a.setStart(b,e),a.collapse(!0)),!0}var g=a.startContainer;"number"==typeof e&&"number"==typeof c&&g.type==CKEDITOR.NODE_ELEMENT&&(f(b.startContainer,g,c)||f(b.endContainer,g,e))},isDropRangeAffectedByDragRange:function(b, +a){var c=a.startContainer,e=a.endOffset;return b.endContainer.equals(c)&&b.endOffset<=e||b.startContainer.getParent().equals(c)&&b.startContainer.getIndex()CKEDITOR.env.version&&this.fixSplitNodesAfterDrop(b,a,f.dragStartContainerChildCount,f.dragEndContainerChildCount); +(h=this.isDropRangeAffectedByDragRange(b,a))||(d=b.createBookmark(!1));f=a.clone().createBookmark(!1);h&&(d=b.createBookmark(!1));b=d.startNode;a=d.endNode;h=f.startNode;a&&b.getPosition(h)&CKEDITOR.POSITION_PRECEDING&&a.getPosition(h)&CKEDITOR.POSITION_FOLLOWING&&h.insertBefore(b);b=e.createRange();b.moveToBookmark(d);g.extractHtmlFromRange(b,1);a=e.createRange();a.moveToBookmark(f);q(e,{dataTransfer:c,method:"drop",range:a},1);e.fire("unlockSnapshot")},getRangeAtDropPosition:function(b,a){var c= +b.data.$,e=c.clientX,f=c.clientY,g=a.getSelection(!0).getRanges()[0],d=a.createRange();if(b.data.testRange)return b.data.testRange;if(document.caretRangeFromPoint)c=a.document.$.caretRangeFromPoint(e,f),d.setStart(CKEDITOR.dom.node(c.startContainer),c.startOffset),d.collapse(!0);else if(c.rangeParent)d.setStart(CKEDITOR.dom.node(c.rangeParent),c.rangeOffset),d.collapse(!0);else{if(CKEDITOR.env.ie&&8n&&!h;n++){if(!h)try{c.moveToPoint(e,f-n),h=!0}catch(p){}if(!h)try{c.moveToPoint(e,f+n),h=!0}catch(k){}}if(h){var u="cke-temp-"+(new Date).getTime();c.pasteHTML('\x3cspan id\x3d"'+u+'"\x3e​\x3c/span\x3e');var r=a.document.getById(u);d.moveToPosition(r,CKEDITOR.POSITION_BEFORE_START);r.remove()}else{var t=a.document.$.elementFromPoint(e,f),m=new CKEDITOR.dom.element(t),q;if(m.equals(a.editable())||"html"==m.getName())return g&&g.startContainer&& +!g.startContainer.equals(a.editable())?g:null;q=m.getClientRect();e/i,bodyRegExp:/([\s\S]*)<\/body>/i,fragmentRegExp:/\x3c!--(?:Start|End)Fragment--\x3e/g,data:{},files:[],normalizeType:function(a){a=a.toLowerCase();return"text"==a||"text/plain"==a?"Text":"url"==a?"URL":a}};this.id=this.getData(p);this.id||(this.id="Text"==p?"":"cke-"+CKEDITOR.tools.getUniqueId());if("Text"!=p)try{this.$.setData(p,this.id)}catch(c){}a&&(this.sourceEditor= +a,this.setData("text/html",a.getSelectedHtml(1)),"Text"==p||this.getData("text/plain")||this.setData("text/plain",a.getSelection().getSelectedText()))};CKEDITOR.DATA_TRANSFER_INTERNAL=1;CKEDITOR.DATA_TRANSFER_CROSS_EDITORS=2;CKEDITOR.DATA_TRANSFER_EXTERNAL=3;CKEDITOR.plugins.clipboard.dataTransfer.prototype={getData:function(b){b=this._.normalizeType(b);var a=this._.data[b];if(void 0===a||null===a||""===a)try{a=this.$.getData(b)}catch(c){}if(void 0===a||null===a||""===a)a="";"text/html"==b?(a=a.replace(this._.metaRegExp, +""),(b=this._.bodyRegExp.exec(a))&&b.length&&(a=b[1],a=a.replace(this._.fragmentRegExp,""))):"Text"==b&&CKEDITOR.env.gecko&&this.getFilesCount()&&"file://"==a.substring(0,7)&&(a="");return a},setData:function(b,a){b=this._.normalizeType(b);this._.data[b]=a;if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported||"URL"==b||"Text"==b){"Text"==p&&"Text"==b&&(this.id=a);try{this.$.setData(b,a)}catch(c){}}},getTransferType:function(b){return this.sourceEditor?this.sourceEditor==b?CKEDITOR.DATA_TRANSFER_INTERNAL: +CKEDITOR.DATA_TRANSFER_CROSS_EDITORS:CKEDITOR.DATA_TRANSFER_EXTERNAL},cacheData:function(){function b(b){b=a._.normalizeType(b);var c=a.getData(b);c&&(a._.data[b]=c)}if(this.$){var a=this,c,e;if(CKEDITOR.plugins.clipboard.isCustomDataTypesSupported){if(this.$.types)for(c=0;cc?d+c:b.width>c?d-a.left:d-a.right+b.width): +lc?d-c:b.width>c?d-a.right+b.width:d-a.left);c=a.top;b.height-a.tope?n-e:b.height>e?n-a.bottom+b.height:n-a.top);CKEDITOR.env.ie&&(b=a=new CKEDITOR.dom.element(k.$.offsetParent),"html"==b.getName()&&(b=b.getDocument().getBody()),"rtl"==b.getComputedStyle("direction")&&(d=CKEDITOR.env.ie8Compat?d-2*k.getDocument().getDocumentElement().$.scrollLeft:d-(a.$.scrollWidth-a.$.clientWidth)));var a=k.getFirst(),f;(f=a.getCustomData("activePanel"))&&f.onHide&&f.onHide.call(this,1);a.setCustomData("activePanel", +this);k.setStyles({top:n+"px",left:d+"px"});k.setOpacity(1);g&&g()},this);m.isLoaded?a():m.onLoad=a;CKEDITOR.tools.setTimeout(function(){var a=CKEDITOR.env.webkit&&CKEDITOR.document.getWindow().getScrollPosition().y;this.focus();p.element.focus();CKEDITOR.env.webkit&&(CKEDITOR.document.getBody().$.scrollTop=a);this.allowBlur(!0);this._.editor.fire("panelShow",this)},0,this)},CKEDITOR.env.air?200:0,this);this.visible=1;this.onShow&&this.onShow.call(this)},reposition:function(){var a=this._.showBlockParams; +this.visible&&this._.showBlockParams&&(this.hide(),this.showBlock.apply(this,a))},focus:function(){if(CKEDITOR.env.webkit){var a=CKEDITOR.document.getActive();a&&!a.equals(this._.iframe)&&a.$.blur()}(this._.lastFocused||this._.iframe.getFrameDocument().getWindow()).focus()},blur:function(){var a=this._.iframe.getFrameDocument().getActive();a&&a.is("a")&&(this._.lastFocused=a)},hide:function(a){if(this.visible&&(!this.onHide||!0!==this.onHide.call(this))){this.hideChild();CKEDITOR.env.gecko&&this._.iframe.getFrameDocument().$.activeElement.blur(); +this.element.setStyle("display","none");this.visible=0;this.element.getFirst().removeCustomData("activePanel");if(a=a&&this._.returnFocus)CKEDITOR.env.webkit&&a.type&&a.getWindow().$.focus(),a.focus();delete this._.lastFocused;this._.showBlockParams=null;this._.editor.fire("panelHide",this)}},allowBlur:function(a){var b=this._.panel;void 0!==a&&(b.allowBlur=a);return b.allowBlur},showAsChild:function(a,b,c,f,h,g){if(this._.activeChild!=a||a._.panel._.offsetParentId!=c.getId())this.hideChild(),a.onHide= +CKEDITOR.tools.bind(function(){CKEDITOR.tools.setTimeout(function(){this._.focused||this.hide()},0,this)},this),this._.activeChild=a,this._.focused=!1,a.showBlock(b,c,f,h,g),this.blur(),(CKEDITOR.env.ie7Compat||CKEDITOR.env.ie6Compat)&&setTimeout(function(){a.element.getChild(0).$.style.cssText+=""},100)},hideChild:function(a){var b=this._.activeChild;b&&(delete b.onHide,delete this._.activeChild,b.hide(),a&&this.focus())}}});CKEDITOR.on("instanceDestroyed",function(){var a=CKEDITOR.tools.isEmpty(CKEDITOR.instances), +b;for(b in f){var c=f[b];a?c.destroy():c.element.hide()}a&&(f={})})})();CKEDITOR.plugins.add("colorbutton",{requires:"panelbutton,floatpanel",init:function(e){function t(a,c,f,g,l){var m=new CKEDITOR.style(k["colorButton_"+c+"Style"]),n=CKEDITOR.tools.getNextId()+"_colorBox";l=l||{};e.ui.add(a,CKEDITOR.UI_PANELBUTTON,{label:f,title:f,modes:{wysiwyg:1},editorFocus:0,toolbar:"colors,"+g,allowedContent:m,requiredContent:m,contentTransformations:l.contentTransformations,panel:{css:CKEDITOR.skin.getPath("editor"),attributes:{role:"listbox","aria-label":h.panelTitle}},onBlock:function(a, +b){b.autoSize=!0;b.element.addClass("cke_colorblock");b.element.setHtml(x(a,c,n));b.element.getDocument().getBody().setStyle("overflow","hidden");CKEDITOR.ui.fire("ready",this);var d=b.keys,f="rtl"==e.lang.dir;d[f?37:39]="next";d[40]="next";d[9]="next";d[f?39:37]="prev";d[38]="prev";d[CKEDITOR.SHIFT+9]="prev";d[32]="click"},refresh:function(){e.activeFilter.check(m)||this.setState(CKEDITOR.TRISTATE_DISABLED)},onOpen:function(){var a=e.getSelection(),a=a&&a.getStartElement(),a=e.elementPath(a),b;if(a){a= +a.block||a.blockLimit||e.document.getBody();do b=a&&a.getComputedStyle("back"==c?"background-color":"color")||"transparent";while("back"==c&&"transparent"==b&&a&&(a=a.getParent()));b&&"transparent"!=b||(b="#ffffff");!1!==k.colorButton_enableAutomatic&&this._.panel._.iframe.getFrameDocument().getById(n).setStyle("background-color",b);return b}}})}function x(a,c,f){var g=[],l=k.colorButton_colors.split(","),m=k.colorButton_colorsPerRow||6,n=e.plugins.colordialog&&!1!==k.colorButton_enableMore,p=l.length+ +(n?2:1),b=CKEDITOR.tools.addFunction(function(b,c){function d(a){this.removeListener("ok",d);this.removeListener("cancel",d);"ok"==a.name&&f(this.getContentElement("picker","selectedColor").getValue(),c)}var f=arguments.callee;if("?"==b)e.openDialog("colordialog",function(){this.on("ok",d);this.on("cancel",d)});else{e.focus();a.hide();e.fire("saveSnapshot");e.removeStyle(new CKEDITOR.style(k["colorButton_"+c+"Style"],{color:"inherit"}));if(b){var g=k["colorButton_"+c+"Style"];g.childRule="back"== +c?function(a){return u(a)}:function(a){return!(a.is("a")||a.getElementsByTag("a").count())||u(a)};e.applyStyle(new CKEDITOR.style(g,{color:b}))}e.fire("saveSnapshot")}});!1!==k.colorButton_enableAutomatic&&g.push('\x3ca class\x3d"cke_colorauto" _cke_focus\x3d1 hidefocus\x3dtrue title\x3d"',h.auto,'" onclick\x3d"CKEDITOR.tools.callFunction(',b,",null,'",c,"');return false;\" href\x3d\"javascript:void('",h.auto,'\')" role\x3d"option" aria-posinset\x3d"1" aria-setsize\x3d"',p,'"\x3e\x3ctable role\x3d"presentation" cellspacing\x3d0 cellpadding\x3d0 width\x3d"100%"\x3e\x3ctr\x3e\x3ctd colspan\x3d"'+ +m+'" align\x3d"center"\x3e\x3cspan class\x3d"cke_colorbox" id\x3d"',f,'"\x3e\x3c/span\x3e',h.auto,"\x3c/td\x3e\x3c/tr\x3e\x3c/table\x3e\x3c/a\x3e");g.push('\x3ctable role\x3d"presentation" cellspacing\x3d0 cellpadding\x3d0 width\x3d"100%"\x3e');for(f=0;fd.group?1:a.orderd.order?1:0})}var h='\x3cspan class\x3d"cke_menuitem"\x3e\x3ca id\x3d"{id}" class\x3d"cke_menubutton cke_menubutton__{name} cke_menubutton_{state} {cls}" href\x3d"{href}" title\x3d"{title}" tabindex\x3d"-1" _cke_focus\x3d1 hidefocus\x3d"true" role\x3d"{role}" aria-label\x3d"{label}" aria-describedby\x3d"{id}_description" aria-haspopup\x3d"{hasPopup}" aria-disabled\x3d"{disabled}" {ariaChecked} draggable\x3d"false"'; +CKEDITOR.env.gecko&&CKEDITOR.env.mac&&(h+=' onkeypress\x3d"return false;"');CKEDITOR.env.gecko&&(h+=' onblur\x3d"this.style.cssText \x3d this.style.cssText;" ondragstart\x3d"return false;"');var h=h+(' onmouseover\x3d"CKEDITOR.tools.callFunction({hoverFn},{index});" onmouseout\x3d"CKEDITOR.tools.callFunction({moveOutFn},{index});" '+(CKEDITOR.env.ie?'onclick\x3d"return false;" onmouseup':"onclick")+'\x3d"CKEDITOR.tools.callFunction({clickFn},{index}); return false;"\x3e'),r=CKEDITOR.addTemplate("menuItem", +h+'\x3cspan class\x3d"cke_menubutton_inner"\x3e\x3cspan class\x3d"cke_menubutton_icon"\x3e\x3cspan class\x3d"cke_button_icon cke_button__{iconName}_icon" style\x3d"{iconStyle}"\x3e\x3c/span\x3e\x3c/span\x3e\x3cspan class\x3d"cke_menubutton_label"\x3e{label}\x3c/span\x3e{shortcutHtml}{arrowHtml}\x3c/span\x3e\x3c/a\x3e\x3cspan id\x3d"{id}_description" class\x3d"cke_voice_label" aria-hidden\x3d"false"\x3e{ariaShortcut}\x3c/span\x3e\x3c/span\x3e'),t=CKEDITOR.addTemplate("menuArrow",'\x3cspan class\x3d"cke_menuarrow"\x3e\x3cspan\x3e{label}\x3c/span\x3e\x3c/span\x3e'), +n=CKEDITOR.addTemplate("menuShortcut",'\x3cspan class\x3d"cke_menubutton_label cke_menubutton_shortcut"\x3e{shortcut}\x3c/span\x3e');CKEDITOR.menu=CKEDITOR.tools.createClass({$:function(a,b){b=this._.definition=b||{};this.id=CKEDITOR.tools.getNextId();this.editor=a;this.items=[];this._.listeners=[];this._.level=b.level||1;var d=CKEDITOR.tools.extend({},b.panel,{css:[CKEDITOR.skin.getPath("editor")],level:this._.level-1,block:{}}),m=d.block.attributes=d.attributes||{};!m.role&&(m.role="menu");this._.panelDefinition= +d},_:{onShow:function(){var a=this.editor.getSelection(),b=a&&a.getStartElement(),d=this.editor.elementPath(),m=this._.listeners;this.removeAll();for(var g=0;gCKEDITOR.env.version?1===b.button:0===b.button:!1}function k(a,b,e,d){var c=new CKEDITOR.dom.walker(a);if(a=a.startContainer.getAscendant(b,!0)||a.endContainer.getAscendant(b,!0))if(e(a),d)return;for(;a=c.next();)if(a=a.getAscendant(b,!0))if(e(a),d)break}function u(a,b){var e={ul:"ol",ol:"ul"};return-1!==l(b,function(b){return b.element===a||b.element===e[a]})}function q(a){this.styles=null;this.sticky=!1;this.editor=a; +this.filter=new CKEDITOR.filter(a.config.copyFormatting_allowRules);!0===a.config.copyFormatting_allowRules&&(this.filter.disabled=!0);a.config.copyFormatting_disallowRules&&this.filter.disallow(a.config.copyFormatting_disallowRules)}var l=CKEDITOR.tools.indexOf,t=!1;CKEDITOR.plugins.add("copyformatting",{lang:"en",icons:"copyformatting",hidpi:!0,init:function(a){var b=CKEDITOR.plugins.copyformatting;b._addScreenReaderContainer();t||(CKEDITOR.document.appendStyleSheet(this.path+"styles/copyformatting.css"), +t=!0);a.addContentsCss&&a.addContentsCss(this.path+"styles/copyformatting.css");a.copyFormatting=new b.state(a);a.addCommand("copyFormatting",b.commands.copyFormatting);a.addCommand("applyFormatting",b.commands.applyFormatting);a.ui.addButton("CopyFormatting",{label:a.lang.copyformatting.label,command:"copyFormatting",toolbar:"cleanup,0"});a.on("contentDom",function(){var e=a.editable(),b=e.isInline()?e:a.document,c=a.ui.get("CopyFormatting");e.attachListener(b,"mouseup",function(b){r(b)&&a.execCommand("applyFormatting")}); +e.attachListener(CKEDITOR.document,"mouseup",function(b){var d=a.getCommand("copyFormatting");r(b)&&d.state===CKEDITOR.TRISTATE_ON&&!e.contains(b.data.getTarget())&&a.execCommand("copyFormatting")});c&&(b=CKEDITOR.document.getById(c._.id),e.attachListener(b,"dblclick",function(){a.execCommand("copyFormatting",{sticky:!0})}),e.attachListener(b,"mouseup",function(a){a.data.stopPropagation()}))});a.config.copyFormatting_keystrokeCopy&&a.setKeystroke(a.config.copyFormatting_keystrokeCopy,"copyFormatting"); +a.config.copyFormatting_keystrokePaste&&a.setKeystroke(a.config.copyFormatting_keystrokePaste,"applyFormatting");a.on("key",function(b){var d=a.getCommand("copyFormatting");b=b.data.domEvent;b.getKeystroke&&27===b.getKeystroke()&&d.state===CKEDITOR.TRISTATE_ON&&a.execCommand("copyFormatting")});a.copyFormatting.on("extractFormatting",function(e){var d=e.data.element;if(d.contains(a.editable())||d.equals(a.editable()))return e.cancel();d=b._convertElementToStyleDef(d);if(!a.copyFormatting.filter.check(new CKEDITOR.style(d), +!0,!0))return e.cancel();e.data.styleDef=d});a.copyFormatting.on("applyFormatting",function(e){if(!e.data.preventFormatStripping){var d=e.data.range,c=b._extractStylesFromRange(a,d),f=b._determineContext(d),g,h;if(a.copyFormatting._isContextAllowed(f))for(h=0;h <\/span>/g,""),a.replace(/<.*?>/g,"")):a.getText()}function d(a,c){var f=a,g=/\s/g,h="p br ol ul li td th div caption body".split(" "), +m=!1,k=!1,p,n;do{for(p=b(f,c);!p&&f.getParent();){f=f.getParent();if(-1!==l(h,f.getName())){k=m=!0;break}p=b(f,c)}if(p&&p.getName&&-1!==l(h,p.getName())){m=!0;break}f=p}while(f&&f.getStyle&&("none"==f.getStyle("display")||!f.getText()));for(f||(f=a);f.type!==CKEDITOR.NODE_TEXT;)f=!m||c||k?f.getChild(0):f.getChild(f.getChildCount()-1);for(h=e(f);null!=(k=g.exec(h))&&(n=k.index,c););if("number"!==typeof n&&!m)return d(f,c);if(m)c?n=0:(g=/([\.\b]*$)/,n=(k=g.exec(h))?k.index:h.length);else if(c&&(n+= +1,n>h.length))return d(f);return{node:f,offset:n}}var c=/\b\w+\b/ig,f,g,h,m,k;h=m=k=a.startContainer;for(f=e(h);null!=(g=c.exec(f));)if(g.index+g[0].length>=a.startOffset)return a=g.index,c=g.index+g[0].length,0===g.index&&(g=d(h,!0),m=g.node,a=g.offset),c>=f.length&&(f=d(h),k=f.node,c=f.offset),{startNode:m,startOffset:a,endNode:k,endOffset:c};return null},_filterStyles:function(a){var b=CKEDITOR.tools.isEmpty,e=[],d,c;for(c=0;cc.width&&(a.resize_minWidth=c.width);a.resize_minHeight>c.height&&(a.resize_minHeight=c.height);CKEDITOR.document.on("mousemove",f);CKEDITOR.document.on("mouseup",k);b.document&&(b.document.on("mousemove",f),b.document.on("mouseup",k));d.preventDefault&&d.preventDefault()});b.on("destroy", +function(){CKEDITOR.tools.removeFunction(q)});b.on("uiSpace",function(a){if("bottom"==a.data.space){var e="";h&&!p&&(e=" cke_resizer_horizontal");!h&&p&&(e=" cke_resizer_vertical");var c='\x3cspan id\x3d"'+r+'" class\x3d"cke_resizer'+e+" cke_resizer_"+g+'" title\x3d"'+CKEDITOR.tools.htmlEncode(b.lang.common.resize)+'" onmousedown\x3d"CKEDITOR.tools.callFunction('+q+', event)"\x3e'+("ltr"==g?"◢":"◣")+"\x3c/span\x3e";"ltr"==g&&"ltr"==e?a.data.html+=c:a.data.html=c+a.data.html}},b,null,100);b.on("maximize", +function(a){b.ui.space("resizer")[a.data==CKEDITOR.TRISTATE_ON?"hide":"show"]()})}}});(function(){function D(a){function d(){for(var b=g(),e=CKEDITOR.tools.clone(a.config.toolbarGroups)||v(a),f=0;fa.order?-1:0>b.order?1:b.orderCKEDITOR.env.version?f.createText("\r"):f.createElement("br"),a.deleteContents(),a.insertNode(b),CKEDITOR.env.needsBrFiller?(f.createText("").insertAfter(b),k&&(l||m.blockLimit).appendBogus(),b.getNext().$.nodeValue="",a.setStartAt(b.getNext(),CKEDITOR.POSITION_AFTER_START)): +a.setStartAt(b,CKEDITOR.POSITION_AFTER_END)),a.collapse(!0),a.select(),a.scrollIntoView()):u(b,d,a,h)}}};var x=CKEDITOR.plugins.enterkey,t=x.enterBr,u=x.enterBlock,w=/^h[1-6]$/})();(function(){function k(b,f){var g={},c=[],e={nbsp:" ",shy:"­",gt:"\x3e",lt:"\x3c",amp:"\x26",apos:"'",quot:'"'};b=b.replace(/\b(nbsp|shy|gt|lt|amp|apos|quot)(?:,|$)/g,function(b,a){var d=f?"\x26"+a+";":e[a];g[d]=f?e[a]:"\x26"+a+";";c.push(d);return""});if(!f&&b){b=b.split(",");var a=document.createElement("div"),d;a.innerHTML="\x26"+b.join(";\x26")+";";d=a.innerHTML;a=null;for(a=0;aa&&(a=640);420>b&&(b=420);var f=parseInt((window.screen.height-b)/2,10),g=parseInt((window.screen.width-a)/2,10);d=(d||"location\x3dno,menubar\x3dno,toolbar\x3dno,dependent\x3dyes,minimizable\x3dno,modal\x3dyes,alwaysRaised\x3dyes,resizable\x3dyes,scrollbars\x3dyes")+",width\x3d"+ +a+",height\x3d"+b+",top\x3d"+f+",left\x3d"+g;var c=window.open("",null,d,!0);if(!c)return!1;try{-1==navigator.userAgent.toLowerCase().indexOf(" chrome/")&&(c.moveTo(g,f),c.resizeTo(a,b)),c.focus(),c.location.href=e}catch(h){window.open(e,null,d,!0)}return!0}});(function(){function g(a,c){var d=[];if(c)for(var b in c)d.push(b+"\x3d"+encodeURIComponent(c[b]));else return a;return a+(-1!=a.indexOf("?")?"\x26":"?")+d.join("\x26")}function k(a){a+="";return a.charAt(0).toUpperCase()+a.substr(1)}function m(){var a=this.getDialog(),c=a.getParentEditor();c._.filebrowserSe=this;var d=c.config["filebrowser"+k(a.getName())+"WindowWidth"]||c.config.filebrowserWindowWidth||"80%",a=c.config["filebrowser"+k(a.getName())+"WindowHeight"]||c.config.filebrowserWindowHeight|| +"70%",b=this.filebrowser.params||{};b.CKEditor=c.name;b.CKEditorFuncNum=c._.filebrowserFn;b.langCode||(b.langCode=c.langCode);b=g(this.filebrowser.url,b);c.popup(b,d,a,c.config.filebrowserWindowFeatures||c.config.fileBrowserWindowFeatures)}function n(){var a=this.getDialog();a.getParentEditor()._.filebrowserSe=this;return a.getContentElement(this["for"][0],this["for"][1]).getInputElement().$.value&&a.getContentElement(this["for"][0],this["for"][1]).getAction()?!0:!1}function p(a,c,d){var b=d.params|| +{};b.CKEditor=a.name;b.CKEditorFuncNum=a._.filebrowserFn;b.langCode||(b.langCode=a.langCode);c.action=g(d.url,b);c.filebrowser=d}function l(a,c,d,b){if(b&&b.length)for(var e,g=b.length;g--;)if(e=b[g],"hbox"!=e.type&&"vbox"!=e.type&&"fieldset"!=e.type||l(a,c,d,e.children),e.filebrowser)if("string"==typeof e.filebrowser&&(e.filebrowser={action:"fileButton"==e.type?"QuickUpload":"Browse",target:e.filebrowser}),"Browse"==e.filebrowser.action){var f=e.filebrowser.url;void 0===f&&(f=a.config["filebrowser"+ +k(c)+"BrowseUrl"],void 0===f&&(f=a.config.filebrowserBrowseUrl));f&&(e.onClick=m,e.filebrowser.url=f,e.hidden=!1)}else if("QuickUpload"==e.filebrowser.action&&e["for"]&&(f=e.filebrowser.url,void 0===f&&(f=a.config["filebrowser"+k(c)+"UploadUrl"],void 0===f&&(f=a.config.filebrowserUploadUrl)),f)){var h=e.onClick;e.onClick=function(a){var b=a.sender;if(h&&!1===h.call(b,a))return!1;if(n.call(b,a)){a=b.getDialog().getContentElement(this["for"][0],this["for"][1]).getInputElement();if(b=new CKEDITOR.dom.element(a.$.form))(a= +b.$.elements.ckCsrfToken)?a=new CKEDITOR.dom.element(a):(a=new CKEDITOR.dom.element("input"),a.setAttributes({name:"ckCsrfToken",type:"hidden"}),b.append(a)),a.setAttribute("value",CKEDITOR.tools.getCsrfToken());return!0}return!1};e.filebrowser.url=f;e.hidden=!1;p(a,d.getContents(e["for"][0]).get(e["for"][1]),e.filebrowser)}}function h(a,c,d){if(-1!==d.indexOf(";")){d=d.split(";");for(var b=0;bh.height-c.bottom?e("pin"):e("bottom"),d=h.width/2,d=l.floatSpacePreferRight?"right":0n.width?"rtl"==l.contentsLangDirection? +"right":"left":d-c.left>c.right-d?"left":"right",n.width>h.width?(d="left",f=0):(f="left"==d?0h.width&&(d="left"==d?"right":"left",f=0)),b.setStyle(d,w(("pin"==m?u:p)+f+("pin"==m?0:"left"==d?v:-v)))):(m="pin",e("pin"),t(d))}}}();if(p){var k=new CKEDITOR.template('\x3cdiv id\x3d"cke_{name}" class\x3d"cke {id} cke_reset_all cke_chrome cke_editor_{name} cke_float cke_{langDir} '+CKEDITOR.env.cssClass+'" dir\x3d"{langDir}" title\x3d"'+(CKEDITOR.env.gecko? +" ":"")+'" lang\x3d"{langCode}" role\x3d"application" style\x3d"{style}"'+(a.title?' aria-labelledby\x3d"cke_{name}_arialbl"':" ")+"\x3e"+(a.title?'\x3cspan id\x3d"cke_{name}_arialbl" class\x3d"cke_voice_label"\x3e{voiceLabel}\x3c/span\x3e':" ")+'\x3cdiv class\x3d"cke_inner"\x3e\x3cdiv id\x3d"{topId}" class\x3d"cke_top" role\x3d"presentation"\x3e{content}\x3c/div\x3e\x3c/div\x3e\x3c/div\x3e'),b=CKEDITOR.document.getBody().append(CKEDITOR.dom.element.createFromHtml(k.output({content:p,id:a.id,langDir:a.lang.dir, +langCode:a.langCode,name:a.name,style:"display:none;z-index:"+(l.baseFloatZIndex-1),topId:a.ui.spaceId("top"),voiceLabel:a.title}))),u=CKEDITOR.tools.eventsBuffer(500,t),e=CKEDITOR.tools.eventsBuffer(100,t);b.unselectable();b.on("mousedown",function(a){a=a.data;a.getTarget().hasAscendant("a",1)||a.preventDefault()});a.on("focus",function(b){t(b);a.on("change",u.input);g.on("scroll",e.input);g.on("resize",e.input)});a.on("blur",function(){b.hide();a.removeListener("change",u.input);g.removeListener("scroll", +e.input);g.removeListener("resize",e.input)});a.on("destroy",function(){g.removeListener("scroll",e.input);g.removeListener("resize",e.input);b.clearCustomData();b.remove()});a.focusManager.hasFocus&&b.show();a.focusManager.add(b,1)}}var g=CKEDITOR.document.getWindow(),w=CKEDITOR.tools.cssLength;CKEDITOR.plugins.add("floatingspace",{init:function(a){a.on("loaded",function(){k(this)},null,null,20)}})})();CKEDITOR.plugins.add("listblock",{requires:"panel",onLoad:function(){var f=CKEDITOR.addTemplate("panel-list",'\x3cul role\x3d"presentation" class\x3d"cke_panel_list"\x3e{items}\x3c/ul\x3e'),g=CKEDITOR.addTemplate("panel-list-item",'\x3cli id\x3d"{id}" class\x3d"cke_panel_listItem" role\x3dpresentation\x3e\x3ca id\x3d"{id}_option" _cke_focus\x3d1 hidefocus\x3dtrue title\x3d"{title}" href\x3d"javascript:void(\'{val}\')" {onclick}\x3d"CKEDITOR.tools.callFunction({clickFn},\'{val}\'); return false;" role\x3d"option"\x3e{text}\x3c/a\x3e\x3c/li\x3e'), +h=CKEDITOR.addTemplate("panel-list-group",'\x3ch1 id\x3d"{id}" class\x3d"cke_panel_grouptitle" role\x3d"presentation" \x3e{label}\x3c/h1\x3e'),k=/\'/g;CKEDITOR.ui.panel.prototype.addListBlock=function(a,b){return this.addBlock(a,new CKEDITOR.ui.listBlock(this.getHolderElement(),b))};CKEDITOR.ui.listBlock=CKEDITOR.tools.createClass({base:CKEDITOR.ui.panel.block,$:function(a,b){b=b||{};var c=b.attributes||(b.attributes={});(this.multiSelect=!!b.multiSelect)&&(c["aria-multiselectable"]=!0);!c.role&& +(c.role="listbox");this.base.apply(this,arguments);this.element.setAttribute("role",c.role);c=this.keys;c[40]="next";c[9]="next";c[38]="prev";c[CKEDITOR.SHIFT+9]="prev";c[32]=CKEDITOR.env.ie?"mouseup":"click";CKEDITOR.env.ie&&(c[13]="mouseup");this._.pendingHtml=[];this._.pendingList=[];this._.items={};this._.groups={}},_:{close:function(){if(this._.started){var a=f.output({items:this._.pendingList.join("")});this._.pendingList=[];this._.pendingHtml.push(a);delete this._.started}},getClick:function(){this._.click|| +(this._.click=CKEDITOR.tools.addFunction(function(a){var b=this.toggle(a);if(this.onClick)this.onClick(a,b)},this));return this._.click}},proto:{add:function(a,b,c){var d=CKEDITOR.tools.getNextId();this._.started||(this._.started=1,this._.size=this._.size||0);this._.items[a]=d;var e;e=CKEDITOR.tools.htmlEncodeAttr(a).replace(k,"\\'");a={id:d,val:e,onclick:CKEDITOR.env.ie?'onclick\x3d"return false;" onmouseup':"onclick",clickFn:this._.getClick(),title:CKEDITOR.tools.htmlEncodeAttr(c||a),text:b||a}; +this._.pendingList.push(g.output(a))},startGroup:function(a){this._.close();var b=CKEDITOR.tools.getNextId();this._.groups[a]=b;this._.pendingHtml.push(h.output({id:b,label:a}))},commit:function(){this._.close();this.element.appendHtml(this._.pendingHtml.join(""));delete this._.size;this._.pendingHtml=[]},toggle:function(a){var b=this.isMarked(a);b?this.unmark(a):this.mark(a);return!b},hideGroup:function(a){var b=(a=this.element.getDocument().getById(this._.groups[a]))&&a.getNext();a&&(a.setStyle("display", +"none"),b&&"ul"==b.getName()&&b.setStyle("display","none"))},hideItem:function(a){this.element.getDocument().getById(this._.items[a]).setStyle("display","none")},showAll:function(){var a=this._.items,b=this._.groups,c=this.element.getDocument(),d;for(d in a)c.getById(a[d]).setStyle("display","");for(var e in b)a=c.getById(b[e]),d=a.getNext(),a.setStyle("display",""),d&&"ul"==d.getName()&&d.setStyle("display","")},mark:function(a){this.multiSelect||this.unmarkAll();a=this._.items[a];var b=this.element.getDocument().getById(a); +b.addClass("cke_selected");this.element.getDocument().getById(a+"_option").setAttribute("aria-selected",!0);this.onMark&&this.onMark(b)},unmark:function(a){var b=this.element.getDocument();a=this._.items[a];var c=b.getById(a);c.removeClass("cke_selected");b.getById(a+"_option").removeAttribute("aria-selected");this.onUnmark&&this.onUnmark(c)},unmarkAll:function(){var a=this._.items,b=this.element.getDocument(),c;for(c in a){var d=a[c];b.getById(d).removeClass("cke_selected");b.getById(d+"_option").removeAttribute("aria-selected")}this.onUnmark&& +this.onUnmark()},isMarked:function(a){return this.element.getDocument().getById(this._.items[a]).hasClass("cke_selected")},focus:function(a){this._.focusIndex=-1;var b=this.element.getElementsByTag("a"),c,d=-1;if(a)for(c=this.element.getDocument().getById(this._.items[a]).getFirst();a=b.getItem(++d);){if(a.equals(c)){this._.focusIndex=d;break}}else this.element.focus();c&&setTimeout(function(){c.focus()},0)}}})}});CKEDITOR.plugins.add("richcombo",{requires:"floatpanel,listblock,button",beforeInit:function(d){d.ui.addHandler(CKEDITOR.UI_RICHCOMBO,CKEDITOR.ui.richCombo.handler)}}); +(function(){var d='\x3cspan id\x3d"{id}" class\x3d"cke_combo cke_combo__{name} {cls}" role\x3d"presentation"\x3e\x3cspan id\x3d"{id}_label" class\x3d"cke_combo_label"\x3e{label}\x3c/span\x3e\x3ca class\x3d"cke_combo_button" title\x3d"{title}" tabindex\x3d"-1"'+(CKEDITOR.env.gecko&&!CKEDITOR.env.hc?"":" href\x3d\"javascript:void('{titleJs}')\"")+' hidefocus\x3d"true" role\x3d"button" aria-labelledby\x3d"{id}_label" aria-haspopup\x3d"true"';CKEDITOR.env.gecko&&CKEDITOR.env.mac&&(d+=' onkeypress\x3d"return false;"'); +CKEDITOR.env.gecko&&(d+=' onblur\x3d"this.style.cssText \x3d this.style.cssText;"');var d=d+(' onkeydown\x3d"return CKEDITOR.tools.callFunction({keydownFn},event,this);" onfocus\x3d"return CKEDITOR.tools.callFunction({focusFn},event);" '+(CKEDITOR.env.ie?'onclick\x3d"return false;" onmouseup':"onclick")+'\x3d"CKEDITOR.tools.callFunction({clickFn},this);return false;"\x3e\x3cspan id\x3d"{id}_text" class\x3d"cke_combo_text cke_combo_inlinelabel"\x3e{label}\x3c/span\x3e\x3cspan class\x3d"cke_combo_open"\x3e\x3cspan class\x3d"cke_combo_arrow"\x3e'+ +(CKEDITOR.env.hc?"\x26#9660;":CKEDITOR.env.air?"\x26nbsp;":"")+"\x3c/span\x3e\x3c/span\x3e\x3c/a\x3e\x3c/span\x3e"),k=CKEDITOR.addTemplate("combo",d);CKEDITOR.UI_RICHCOMBO="richcombo";CKEDITOR.ui.richCombo=CKEDITOR.tools.createClass({$:function(a){CKEDITOR.tools.extend(this,a,{canGroup:!1,title:a.label,modes:{wysiwyg:1},editorFocus:1});a=this.panel||{};delete this.panel;this.id=CKEDITOR.tools.getNextNumber();this.document=a.parent&&a.parent.getDocument()||CKEDITOR.document;a.className="cke_combopanel"; +a.block={multiSelect:a.multiSelect,attributes:a.attributes};a.toolbarRelated=!0;this._={panelDefinition:a,items:{}}},proto:{renderHtml:function(a){var b=[];this.render(a,b);return b.join("")},render:function(a,b){function g(){if(this.getState()!=CKEDITOR.TRISTATE_ON){var c=this.modes[a.mode]?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED;a.readOnly&&!this.readOnly&&(c=CKEDITOR.TRISTATE_DISABLED);this.setState(c);this.setValue("");c!=CKEDITOR.TRISTATE_DISABLED&&this.refresh&&this.refresh()}}var d= +CKEDITOR.env,h="cke_"+this.id,e=CKEDITOR.tools.addFunction(function(b){l&&(a.unlockSelection(1),l=0);c.execute(b)},this),f=this,c={id:h,combo:this,focus:function(){CKEDITOR.document.getById(h).getChild(1).focus()},execute:function(c){var b=f._;if(b.state!=CKEDITOR.TRISTATE_DISABLED)if(f.createPanel(a),b.on)b.panel.hide();else{f.commit();var d=f.getValue();d?b.list.mark(d):b.list.unmarkAll();b.panel.showBlock(f.id,new CKEDITOR.dom.element(c),4)}},clickFn:e};a.on("activeFilterChange",g,this);a.on("mode", +g,this);a.on("selectionChange",g,this);!this.readOnly&&a.on("readOnly",g,this);var m=CKEDITOR.tools.addFunction(function(b,d){b=new CKEDITOR.dom.event(b);var g=b.getKeystroke();if(40==g)a.once("panelShow",function(a){a.data._.panel._.currentBlock.onKeyDown(40)});switch(g){case 13:case 32:case 40:CKEDITOR.tools.callFunction(e,d);break;default:c.onkey(c,g)}b.preventDefault()}),n=CKEDITOR.tools.addFunction(function(){c.onfocus&&c.onfocus()}),l=0;c.keyDownFn=m;d={id:h,name:this.name||this.command,label:this.label, +title:this.title,cls:this.className||"",titleJs:d.gecko&&!d.hc?"":(this.title||"").replace("'",""),keydownFn:m,focusFn:n,clickFn:e};k.output(d,b);if(this.onRender)this.onRender();return c},createPanel:function(a){if(!this._.panel){var b=this._.panelDefinition,d=this._.panelDefinition.block,k=b.parent||CKEDITOR.document.getBody(),h="cke_combopanel__"+this.name,e=new CKEDITOR.ui.floatPanel(a,k,b),f=e.addListBlock(this.id,d),c=this;e.onShow=function(){this.element.addClass(h);c.setState(CKEDITOR.TRISTATE_ON); +c._.on=1;c.editorFocus&&!a.focusManager.hasFocus&&a.focus();if(c.onOpen)c.onOpen();a.once("panelShow",function(){f.focus(!f.multiSelect&&c.getValue())})};e.onHide=function(b){this.element.removeClass(h);c.setState(c.modes&&c.modes[a.mode]?CKEDITOR.TRISTATE_OFF:CKEDITOR.TRISTATE_DISABLED);c._.on=0;if(!b&&c.onClose)c.onClose()};e.onEscape=function(){e.hide(1)};f.onClick=function(a,b){c.onClick&&c.onClick.call(c,a,b);e.hide()};this._.panel=e;this._.list=f;e.getBlock(this.id).onHide=function(){c._.on= +0;c.setState(CKEDITOR.TRISTATE_OFF)};this.init&&this.init()}},setValue:function(a,b){this._.value=a;var d=this.document.getById("cke_"+this.id+"_text");d&&(a||b?d.removeClass("cke_combo_inlinelabel"):(b=this.label,d.addClass("cke_combo_inlinelabel")),d.setText("undefined"!=typeof b?b:a))},getValue:function(){return this._.value||""},unmarkAll:function(){this._.list.unmarkAll()},mark:function(a){this._.list.mark(a)},hideItem:function(a){this._.list.hideItem(a)},hideGroup:function(a){this._.list.hideGroup(a)}, +showAll:function(){this._.list.showAll()},add:function(a,b,d){this._.items[a]=d||a;this._.list.add(a,b,d)},startGroup:function(a){this._.list.startGroup(a)},commit:function(){this._.committed||(this._.list.commit(),this._.committed=1,CKEDITOR.ui.fire("ready",this));this._.committed=1},setState:function(a){if(this._.state!=a){var b=this.document.getById("cke_"+this.id);b.setState(a,"cke_combo");a==CKEDITOR.TRISTATE_DISABLED?b.setAttribute("aria-disabled",!0):b.removeAttribute("aria-disabled");this._.state= +a}},getState:function(){return this._.state},enable:function(){this._.state==CKEDITOR.TRISTATE_DISABLED&&this.setState(this._.lastState)},disable:function(){this._.state!=CKEDITOR.TRISTATE_DISABLED&&(this._.lastState=this._.state,this.setState(CKEDITOR.TRISTATE_DISABLED))}},statics:{handler:{create:function(a){return new CKEDITOR.ui.richCombo(a)}}}});CKEDITOR.ui.prototype.addRichCombo=function(a,b){this.add(a,CKEDITOR.UI_RICHCOMBO,b)}})();(function(){function n(a,c,h,e,q,n,u,w){var x=a.config,r=new CKEDITOR.style(u),g=q.split(";");q=[];for(var m={},d=0;dthis.$.offsetHeight){var d=b.createRange();d[33==c?"moveToElementEditStart":"moveToElementEditEnd"](this);d.select();a.data.preventDefault()}});CKEDITOR.env.ie&&this.attachListener(c,"blur",function(){try{c.$.selection.empty()}catch(a){}});CKEDITOR.env.iOS&&this.attachListener(c,"touchend",function(){a.focus()});d=b.document.getElementsByTag("title").getItem(0);d.data("cke-title",d.getText());CKEDITOR.env.ie&&(b.document.$.title=this._.docTitle);CKEDITOR.tools.setTimeout(function(){"unloaded"== +this.status&&(this.status="ready");b.fire("contentDom");this._.isPendingFocus&&(b.focus(),this._.isPendingFocus=!1);setTimeout(function(){b.fire("dataReady")},0)},0,this)}function n(a){function f(){var c;a.editable().attachListener(a,"selectionChange",function(){var d=a.getSelection().getSelectedElement();d&&(c&&(c.detachEvent("onresizestart",b),c=null),d.$.attachEvent("onresizestart",b),c=d.$)})}function b(a){a.returnValue=!1}if(CKEDITOR.env.gecko)try{var c=a.document.$;c.execCommand("enableObjectResizing", +!1,!a.config.disableObjectResizing);c.execCommand("enableInlineTableEditing",!1,!a.config.disableNativeTableHandles)}catch(d){}else CKEDITOR.env.ie&&11>CKEDITOR.env.version&&a.config.disableObjectResizing&&f(a)}function p(){var a=[];if(8<=CKEDITOR.document.$.documentMode){a.push("html.CSS1Compat [contenteditable\x3dfalse]{min-height:0 !important}");var f=[],b;for(b in CKEDITOR.dtd.$removeEmpty)f.push("html.CSS1Compat "+b+"[contenteditable\x3dfalse]");a.push(f.join(",")+"{display:inline-block}")}else CKEDITOR.env.gecko&& +(a.push("html{height:100% !important}"),a.push("img:-moz-broken{-moz-force-broken-image-icon:1;min-width:24px;min-height:24px}"));a.push("html{cursor:text;*cursor:auto}");a.push("img,input,textarea{cursor:default}");return a.join("\n")}var l;CKEDITOR.plugins.add("wysiwygarea",{init:function(a){a.config.fullPage&&a.addFeature({allowedContent:"html head title; style [media,type]; body (*)[id]; meta link [*]",requiredContent:"body"});a.addMode("wysiwyg",function(f){function b(b){b&&b.removeListener(); +a.editable(new l(a,d.$.contentWindow.document.body));a.setData(a.getData(1),f)}var c="document.open();"+(CKEDITOR.env.ie?"("+CKEDITOR.tools.fixDomain+")();":"")+"document.close();",c=CKEDITOR.env.air?"javascript:void(0)":CKEDITOR.env.ie&&!CKEDITOR.env.edge?"javascript:void(function(){"+encodeURIComponent(c)+"}())":"",d=CKEDITOR.dom.element.createFromHtml('\x3ciframe src\x3d"'+c+'" frameBorder\x3d"0"\x3e\x3c/iframe\x3e');d.setStyles({width:"100%",height:"100%"});d.addClass("cke_wysiwyg_frame").addClass("cke_reset"); +c=a.ui.space("contents");c.append(d);var e=CKEDITOR.env.ie&&!CKEDITOR.env.edge||CKEDITOR.env.gecko;if(e)d.on("load",b);var g=a.title,h=a.fire("ariaEditorHelpLabel",{}).label;g&&(CKEDITOR.env.ie&&h&&(g+=", "+h),d.setAttribute("title",g));if(h){var g=CKEDITOR.tools.getNextId(),k=CKEDITOR.dom.element.createFromHtml('\x3cspan id\x3d"'+g+'" class\x3d"cke_voice_label"\x3e'+h+"\x3c/span\x3e");c.append(k,1);d.setAttribute("aria-describedby",g)}a.on("beforeModeUnload",function(a){a.removeListener();k&&k.remove()}); +d.setAttributes({tabIndex:a.tabIndex,allowTransparency:"true"});!e&&b();a.fire("ariaWidget",d)})}});CKEDITOR.editor.prototype.addContentsCss=function(a){var f=this.config,b=f.contentsCss;CKEDITOR.tools.isArray(b)||(f.contentsCss=b?[b]:[]);f.contentsCss.push(a)};l=CKEDITOR.tools.createClass({$:function(){this.base.apply(this,arguments);this._.frameLoadedHandler=CKEDITOR.tools.addFunction(function(a){CKEDITOR.tools.setTimeout(m,0,this,a)},this);this._.docTitle=this.getWindow().getFrame().getAttribute("title")}, +base:CKEDITOR.editable,proto:{setData:function(a,f){var b=this.editor;if(f)this.setHtml(a),this.fixInitialSelection(),b.fire("dataReady");else{this._.isLoadingData=!0;b._.dataStore={id:1};var c=b.config,d=c.fullPage,e=c.docType,g=CKEDITOR.tools.buildStyleHtml(p()).replace(/ + [*] item [:-)] + Normal text [b]Bold text[/b] [i]italic[/i] [s]strikethrough[/s] + [hr] + + [url]http://domain.com[/url] +
      + [url=http://domain.com?a=1&b=2]Link[/url] +
      + + [img]http://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Go-home.svg/100px-Go-home.svg.png[/img] + + [quote]quoted text[/quote] + + [code]monospaced text[/code] + + [size=15]Large Text[/size] + + [color=red]Red Text[/color] + or + [color=#FF0000]Red Text[/color] + or + [color=FF0000]Red Text[/color] + + [list] [*]Entry 1 [*]Entry 2 [/list] + [list] *Entry 1 *Entry 2 [/list] + + [table] [tr] [td]table data[/td] [/tr] [/table] + +

      this is H2 tag

      +

      This is a part of one snippet

      +
      + + + [pageImage type="medium" link="url" show="99" form="home-images" xhtml="yes"] + +
      + [if_data] +
      + + %%[contactBar]%% + +
      + [/if_data] + + [if_data][contactBar][/if_data] + + [if_data]soemthing here %%[contactBar]%% and after[/if_data] + + [if_data]
      %%[contactBar]%%
      [/if_data] + + [if_data][siteTitle][else_if_data][siteTitle][/if_data] + + + + + +

      The BBCodeMixed mixed mode depends on the BBCode and HTML mixed modes. HTML + mixed mode itself depends on XML, JavaScript, and CSS modes.

      + +

      It takes the same options, as BBCode and HTML mixed modes.

      + +

      MIME types defined: text/x-bbcode.

      + + + diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/clike.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/clike.js new file mode 100644 index 0000000..cad2d51 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/clike.js @@ -0,0 +1,785 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function Context(indented, column, type, info, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.info = info; + this.align = align; + this.prev = prev; +} +function pushContext(state, col, type, info) { + var indent = state.indented; + if (state.context && state.context.type == "statement" && type != "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, info, null, state.context); +} +function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; +} + +function typeBefore(stream, state, pos) { + if (state.prevToken == "variable" || state.prevToken == "variable-3") return true; + if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true; + if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true; +} + +function isTopScope(context) { + for (;;) { + if (!context || context.type == "top") return true; + if (context.type == "}" && context.prev.info != "namespace") return false; + context = context.prev; + } +} + +CodeMirror.defineMode("clike", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, + keywords = parserConfig.keywords || {}, + types = parserConfig.types || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + defKeywords = parserConfig.defKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false, + indentSwitch = parserConfig.indentSwitch !== false, + namespaceSeparator = parserConfig.namespaceSeparator, + isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/, + numberStart = parserConfig.numberStart || /[\d\.]/, + number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i, + isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/; + + var curPunc, isDefKeyword; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (isPunctuationChar.test(ch)) { + curPunc = ch; + return null; + } + if (numberStart.test(ch)) { + stream.backUp(1) + if (stream.match(number)) return "number" + stream.next() + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {} + return "operator"; + } + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + if (namespaceSeparator) while (stream.match(namespaceSeparator)) + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + + var cur = stream.current(); + if (contains(keywords, cur)) { + if (contains(blockKeywords, cur)) curPunc = "newstatement"; + if (contains(defKeywords, cur)) isDefKeyword = true; + return "keyword"; + } + if (contains(types, cur)) return "variable-3"; + if (contains(builtin, cur)) { + if (contains(blockKeywords, cur)) curPunc = "newstatement"; + return "builtin"; + } + if (contains(atoms, cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function maybeEOL(stream, state) { + if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) + state.typeAtEndOfLine = typeBefore(stream, state, stream.pos) + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false), + indented: 0, + startOfLine: true, + prevToken: null + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) { maybeEOL(stream, state); return null; } + curPunc = isDefKeyword = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false))) + while (state.context.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && + (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || + (ctx.type == "statement" && curPunc == "newstatement"))) { + pushContext(state, stream.column(), "statement", stream.current()); + } + + if (style == "variable" && + ((state.prevToken == "def" || + (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) && + isTopScope(state.context) && stream.match(/^\s*\(/, false))))) + style = "def"; + + if (hooks.token) { + var result = hooks.token(stream, state, style); + if (result !== undefined) style = result; + } + + if (style == "def" && parserConfig.styleDefs === false) style = "variable"; + + state.startOfLine = false; + state.prevToken = isDefKeyword ? "def" : style || curPunc; + maybeEOL(stream, state); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + if (parserConfig.dontIndentStatements) + while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info)) + ctx = ctx.prev + if (hooks.indent) { + var hook = hooks.indent(state, ctx, textAfter); + if (typeof hook == "number") return hook + } + var closing = firstChar == ctx.type; + var switchBlock = ctx.prev && ctx.prev.info == "switch"; + if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { + while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev + return ctx.indented + } + if (ctx.type == "statement") + return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + if (ctx.align && (!dontAlignCalls || ctx.type != ")")) + return ctx.column + (closing ? 0 : 1); + if (ctx.type == ")" && !closing) + return ctx.indented + statementIndentUnit; + + return ctx.indented + (closing ? 0 : indentUnit) + + (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0); + }, + + electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + fold: "brace" + }; +}); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + function contains(words, word) { + if (typeof words === "function") { + return words(word); + } else { + return words.propertyIsEnumerable(word); + } + } + var cKeywords = "auto if break case register continue return default do sizeof " + + "static else struct switch extern typedef union for goto while enum const volatile"; + var cTypes = "int long char short double float unsigned signed void size_t ptrdiff_t"; + + function cppHook(stream, state) { + if (!state.startOfLine) return false + for (var ch, next = null; ch = stream.peek();) { + if (ch == "\\" && stream.match(/^.$/)) { + next = cppHook + break + } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) { + break + } + stream.next() + } + state.tokenize = next + return "meta" + } + + function pointerHook(_stream, state) { + if (state.prevToken == "variable-3") return "variable-3"; + return false; + } + + function cpp14Literal(stream) { + stream.eatWhile(/[\w\.']/); + return "number"; + } + + function cpp11StringHook(stream, state) { + stream.backUp(1); + // Raw strings. + if (stream.match(/(R|u8R|uR|UR|LR)/)) { + var match = stream.match(/"([^\s\\()]{0,16})\(/); + if (!match) { + return false; + } + state.cpp11RawStringDelim = match[1]; + state.tokenize = tokenRawString; + return tokenRawString(stream, state); + } + // Unicode strings/chars. + if (stream.match(/(u8|u|U|L)/)) { + if (stream.match(/["']/, /* eat */ false)) { + return "string"; + } + return false; + } + // Ignore this hook. + stream.next(); + return false; + } + + function cppLooksLikeConstructor(word) { + var lastTwo = /(\w+)::(\w+)$/.exec(word); + return lastTwo && lastTwo[1] == lastTwo[2]; + } + + // C#-style strings where "" escapes a quote. + function tokenAtString(stream, state) { + var next; + while ((next = stream.next()) != null) { + if (next == '"' && !stream.eat('"')) { + state.tokenize = null; + break; + } + } + return "string"; + } + + // C++11 raw string literal is "( anything )", where + // can be a string up to 16 characters long. + function tokenRawString(stream, state) { + // Escape characters that have special regex meanings. + var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&'); + var match = stream.match(new RegExp(".*?\\)" + delim + '"')); + if (match) + state.tokenize = null; + else + stream.skipToEnd(); + return "string"; + } + + function def(mimes, mode) { + if (typeof mimes == "string") mimes = [mimes]; + var words = []; + function add(obj) { + if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) + words.push(prop); + } + add(mode.keywords); + add(mode.types); + add(mode.builtin); + add(mode.atoms); + if (words.length) { + mode.helperType = mimes[0]; + CodeMirror.registerHelper("hintWords", mimes[0], words); + } + + for (var i = 0; i < mimes.length; ++i) + CodeMirror.defineMIME(mimes[i], mode); + } + + def(["text/x-csrc", "text/x-c", "text/x-chdr"], { + name: "clike", + keywords: words(cKeywords), + types: words(cTypes + " bool _Complex _Bool float_t double_t intptr_t intmax_t " + + "int8_t int16_t int32_t int64_t uintptr_t uintmax_t uint8_t uint16_t " + + "uint32_t uint64_t"), + blockKeywords: words("case do else for if switch while struct"), + defKeywords: words("struct"), + typeFirstDefinitions: true, + atoms: words("null true false"), + hooks: {"#": cppHook, "*": pointerHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def(["text/x-c++src", "text/x-c++hdr"], { + name: "clike", + keywords: words(cKeywords + " asm dynamic_cast namespace reinterpret_cast try explicit new " + + "static_cast typeid catch operator template typename class friend private " + + "this using const_cast inline public throw virtual delete mutable protected " + + "alignas alignof constexpr decltype nullptr noexcept thread_local final " + + "static_assert override"), + types: words(cTypes + " bool wchar_t"), + blockKeywords: words("catch class do else finally for if struct switch try while"), + defKeywords: words("class namespace struct enum union"), + typeFirstDefinitions: true, + atoms: words("true false null"), + dontIndentStatements: /^template$/, + hooks: { + "#": cppHook, + "*": pointerHook, + "u": cpp11StringHook, + "U": cpp11StringHook, + "L": cpp11StringHook, + "R": cpp11StringHook, + "0": cpp14Literal, + "1": cpp14Literal, + "2": cpp14Literal, + "3": cpp14Literal, + "4": cpp14Literal, + "5": cpp14Literal, + "6": cpp14Literal, + "7": cpp14Literal, + "8": cpp14Literal, + "9": cpp14Literal, + token: function(stream, state, style) { + if (style == "variable" && stream.peek() == "(" && + (state.prevToken == ";" || state.prevToken == null || + state.prevToken == "}") && + cppLooksLikeConstructor(stream.current())) + return "def"; + } + }, + namespaceSeparator: "::", + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-java", { + name: "clike", + keywords: words("abstract assert break case catch class const continue default " + + "do else enum extends final finally float for goto if implements import " + + "instanceof interface native new package private protected public " + + "return static strictfp super switch synchronized this throw throws transient " + + "try volatile while"), + types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + + "Integer Long Number Object Short String StringBuffer StringBuilder Void"), + blockKeywords: words("catch class do else finally for if switch try while"), + defKeywords: words("class interface package enum"), + typeFirstDefinitions: true, + atoms: words("true false null"), + number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + }, + modeProps: {fold: ["brace", "import"]} + }); + + def("text/x-csharp", { + name: "clike", + keywords: words("abstract as async await base break case catch checked class const continue" + + " default delegate do else enum event explicit extern finally fixed for" + + " foreach goto if implicit in interface internal is lock namespace new" + + " operator out override params private protected public readonly ref return sealed" + + " sizeof stackalloc static struct switch this throw try typeof unchecked" + + " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + + " global group into join let orderby partial remove select set value var yield"), + types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" + + " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" + + " UInt64 bool byte char decimal double short int long object" + + " sbyte float string ushort uint ulong"), + blockKeywords: words("catch class do else finally for foreach if struct switch try while"), + defKeywords: words("class interface namespace struct var"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: { + "@": function(stream, state) { + if (stream.eat('"')) { + state.tokenize = tokenAtString; + return tokenAtString(stream, state); + } + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); + + function tokenTripleString(stream, state) { + var escaped = false; + while (!stream.eol()) { + if (!escaped && stream.match('"""')) { + state.tokenize = null; + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + def("text/x-scala", { + name: "clike", + keywords: words( + + /* scala */ + "abstract case catch class def do else extends final finally for forSome if " + + "implicit import lazy match new null object override package private protected return " + + "sealed super this throw trait try type val var while with yield _ : = => <- <: " + + "<% >: # @ " + + + /* package scala */ + "assert assume require print println printf readLine readBoolean readByte readShort " + + "readChar readInt readLong readFloat readDouble " + + + ":: #:: " + ), + types: words( + "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + + "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " + + "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + + "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + + "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + + + /* package java.lang */ + "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" + ), + multiLineStrings: true, + blockKeywords: words("catch class do else finally for forSome if match switch try while"), + defKeywords: words("class def object package trait type val var"), + atoms: words("true false null"), + indentStatements: false, + indentSwitch: false, + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + }, + '"': function(stream, state) { + if (!stream.match('""')) return false; + state.tokenize = tokenTripleString; + return state.tokenize(stream, state); + }, + "'": function(stream) { + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + return "atom"; + }, + "=": function(stream, state) { + var cx = state.context + if (cx.type == "}" && cx.align && stream.eat(">")) { + state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev) + return "operator" + } else { + return false + } + } + }, + modeProps: {closeBrackets: {triples: '"'}} + }); + + function tokenKotlinString(tripleString){ + return function (stream, state) { + var escaped = false, next, end = false; + while (!stream.eol()) { + if (!tripleString && !escaped && stream.match('"') ) {end = true; break;} + if (tripleString && stream.match('"""')) {end = true; break;} + next = stream.next(); + if(!escaped && next == "$" && stream.match('{')) + stream.skipTo("}"); + escaped = !escaped && next == "\\" && !tripleString; + } + if (end || !tripleString) + state.tokenize = null; + return "string"; + } + } + + def("text/x-kotlin", { + name: "clike", + keywords: words( + /*keywords*/ + "package as typealias class interface this super val " + + "var fun for is in This throw return " + + "break continue object if else while do try when !in !is as? " + + + /*soft keywords*/ + "file import where by get set abstract enum open inner override private public internal " + + "protected catch finally out final vararg reified dynamic companion constructor init " + + "sealed field property receiver param sparam lateinit data inline noinline tailrec " + + "external annotation crossinline const operator infix" + ), + types: words( + /* package java.lang */ + "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" + ), + intendSwitch: false, + indentStatements: false, + multiLineStrings: true, + blockKeywords: words("catch class do else finally for if where try while enum"), + defKeywords: words("class val var object package interface fun"), + atoms: words("true false null this"), + hooks: { + '"': function(stream, state) { + state.tokenize = tokenKotlinString(stream.match('""')); + return state.tokenize(stream, state); + } + }, + modeProps: {closeBrackets: {triples: '"'}} + }); + + def(["x-shader/x-vertex", "x-shader/x-fragment"], { + name: "clike", + keywords: words("sampler1D sampler2D sampler3D samplerCube " + + "sampler1DShadow sampler2DShadow " + + "const attribute uniform varying " + + "break continue discard return " + + "for while do if else struct " + + "in out inout"), + types: words("float int bool void " + + "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " + + "mat2 mat3 mat4"), + blockKeywords: words("for while do if else struct"), + builtin: words("radians degrees sin cos tan asin acos atan " + + "pow exp log exp2 sqrt inversesqrt " + + "abs sign floor ceil fract mod min max clamp mix step smoothstep " + + "length distance dot cross normalize ftransform faceforward " + + "reflect refract matrixCompMult " + + "lessThan lessThanEqual greaterThan greaterThanEqual " + + "equal notEqual any all not " + + "texture1D texture1DProj texture1DLod texture1DProjLod " + + "texture2D texture2DProj texture2DLod texture2DProjLod " + + "texture3D texture3DProj texture3DLod texture3DProjLod " + + "textureCube textureCubeLod " + + "shadow1D shadow2D shadow1DProj shadow2DProj " + + "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " + + "dFdx dFdy fwidth " + + "noise1 noise2 noise3 noise4"), + atoms: words("true false " + + "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " + + "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " + + "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " + + "gl_FogCoord gl_PointCoord " + + "gl_Position gl_PointSize gl_ClipVertex " + + "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " + + "gl_TexCoord gl_FogFragCoord " + + "gl_FragCoord gl_FrontFacing " + + "gl_FragData gl_FragDepth " + + "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " + + "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " + + "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " + + "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + + "gl_ProjectionMatrixInverseTranspose " + + "gl_ModelViewProjectionMatrixInverseTranspose " + + "gl_TextureMatrixInverseTranspose " + + "gl_NormalScale gl_DepthRange gl_ClipPlane " + + "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " + + "gl_FrontLightModelProduct gl_BackLightModelProduct " + + "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " + + "gl_FogParameters " + + "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " + + "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " + + "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " + + "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " + + "gl_MaxDrawBuffers"), + indentSwitch: false, + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-nesc", { + name: "clike", + keywords: words(cKeywords + "as atomic async call command component components configuration event generic " + + "implementation includes interface module new norace nx_struct nx_union post provides " + + "signal task uses abstract extends"), + types: words(cTypes), + blockKeywords: words("case do else for if switch while struct"), + atoms: words("null true false"), + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-objectivec", { + name: "clike", + keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " + + "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"), + types: words(cTypes), + atoms: words("YES NO NULL NILL ON OFF true false"), + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$]/); + return "keyword"; + }, + "#": cppHook, + indent: function(_state, ctx, textAfter) { + if (ctx.type == "statement" && /^@\w/.test(textAfter)) return ctx.indented + } + }, + modeProps: {fold: "brace"} + }); + + def("text/x-squirrel", { + name: "clike", + keywords: words("base break clone continue const default delete enum extends function in class" + + " foreach local resume return this throw typeof yield constructor instanceof static"), + types: words(cTypes), + blockKeywords: words("case catch class else for foreach if switch try while"), + defKeywords: words("function local class"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + // Ceylon Strings need to deal with interpolation + var stringTokenizer = null; + function tokenCeylonString(type) { + return function(stream, state) { + var escaped = false, next, end = false; + while (!stream.eol()) { + if (!escaped && stream.match('"') && + (type == "single" || stream.match('""'))) { + end = true; + break; + } + if (!escaped && stream.match('``')) { + stringTokenizer = tokenCeylonString(type); + end = true; + break; + } + next = stream.next(); + escaped = type == "single" && !escaped && next == "\\"; + } + if (end) + state.tokenize = null; + return "string"; + } + } + + def("text/x-ceylon", { + name: "clike", + keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" + + " exists extends finally for function given if import in interface is let module new" + + " nonempty object of out outer package return satisfies super switch then this throw" + + " try value void while"), + types: function(word) { + // In Ceylon all identifiers that start with an uppercase are types + var first = word.charAt(0); + return (first === first.toUpperCase() && first !== first.toLowerCase()); + }, + blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"), + defKeywords: words("class dynamic function interface module object package value"), + builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" + + " native optional sealed see serializable shared suppressWarnings tagged throws variable"), + isPunctuationChar: /[\[\]{}\(\),;\:\.`]/, + isOperatorChar: /[+\-*&%=<>!?|^~:\/]/, + numberStart: /[\d#$]/, + number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i, + multiLineStrings: true, + typeFirstDefinitions: true, + atoms: words("true false null larger smaller equal empty finished"), + indentSwitch: false, + styleDefs: false, + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + }, + '"': function(stream, state) { + state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single"); + return state.tokenize(stream, state); + }, + '`': function(stream, state) { + if (!stringTokenizer || !stream.match('`')) return false; + state.tokenize = stringTokenizer; + stringTokenizer = null; + return state.tokenize(stream, state); + }, + "'": function(stream) { + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + return "atom"; + }, + token: function(_stream, state, style) { + if ((style == "variable" || style == "variable-3") && + state.prevToken == ".") { + return "variable-2"; + } + } + }, + modeProps: { + fold: ["brace", "import"], + closeBrackets: {triples: '"'} + } + }); + +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/index.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/index.html new file mode 100644 index 0000000..45c670a --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/index.html @@ -0,0 +1,360 @@ + + +CodeMirror: C-like mode + + + + + + + + + + + + +
      +

      C-like mode

      + +
      + +

      C++ example

      + +
      + +

      Objective-C example

      + +
      + +

      Java example

      + +
      + +

      Scala example

      + +
      + +

      Kotlin mode

      + +
      + +

      Ceylon mode

      + +
      + + + +

      Simple mode that tries to handle C-like languages as well as it + can. Takes two configuration parameters: keywords, an + object whose property names are the keywords in the language, + and useCPP, which determines whether C preprocessor + directives are recognized.

      + +

      MIME types defined: text/x-csrc + (C), text/x-c++src (C++), text/x-java + (Java), text/x-csharp (C#), + text/x-objectivec (Objective-C), + text/x-scala (Scala), text/x-vertex + x-shader/x-fragment (shader programs), + text/x-squirrel (Squirrel) and + text/x-ceylon (Ceylon)

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/scala.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/scala.html new file mode 100644 index 0000000..aa04cf0 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/scala.html @@ -0,0 +1,767 @@ + + +CodeMirror: Scala mode + + + + + + + + + + +
      +

      Scala mode

      +
      + +
      + + +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/test.js new file mode 100644 index 0000000..bea85b8 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/clike/test.js @@ -0,0 +1,55 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-c"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("indent", + "[variable-3 void] [def foo]([variable-3 void*] [variable a], [variable-3 int] [variable b]) {", + " [variable-3 int] [variable c] [operator =] [variable b] [operator +]", + " [number 1];", + " [keyword return] [operator *][variable a];", + "}"); + + MT("indent_switch", + "[keyword switch] ([variable x]) {", + " [keyword case] [number 10]:", + " [keyword return] [number 20];", + " [keyword default]:", + " [variable printf]([string \"foo %c\"], [variable x]);", + "}"); + + MT("def", + "[variable-3 void] [def foo]() {}", + "[keyword struct] [def bar]{}", + "[variable-3 int] [variable-3 *][def baz]() {}"); + + MT("def_new_line", + "::[variable std]::[variable SomeTerribleType][operator <][variable T][operator >]", + "[def SomeLongMethodNameThatDoesntFitIntoOneLine]([keyword const] [variable MyType][operator &] [variable param]) {}") + + MT("double_block", + "[keyword for] (;;)", + " [keyword for] (;;)", + " [variable x][operator ++];", + "[keyword return];"); + + MT("preprocessor", + "[meta #define FOO 3]", + "[variable-3 int] [variable foo];", + "[meta #define BAR\\]", + "[meta 4]", + "[variable-3 unsigned] [variable-3 int] [variable bar] [operator =] [number 8];", + "[meta #include ][comment // comment]") + + + var mode_cpp = CodeMirror.getMode({indentUnit: 2}, "text/x-c++src"); + function MTCPP(name) { test.mode(name, mode_cpp, Array.prototype.slice.call(arguments, 1)); } + + MTCPP("cpp14_literal", + "[number 10'000];", + "[number 0b10'000];", + "[number 0x10'000];", + "[string '100000'];"); +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/css.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/css.js new file mode 100644 index 0000000..985287f --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/css.js @@ -0,0 +1,825 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("css", function(config, parserConfig) { + var inline = parserConfig.inline + if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); + + var indentUnit = config.indentUnit, + tokenHooks = parserConfig.tokenHooks, + documentTypes = parserConfig.documentTypes || {}, + mediaTypes = parserConfig.mediaTypes || {}, + mediaFeatures = parserConfig.mediaFeatures || {}, + mediaValueKeywords = parserConfig.mediaValueKeywords || {}, + propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, + fontProperties = parserConfig.fontProperties || {}, + counterDescriptors = parserConfig.counterDescriptors || {}, + colorKeywords = parserConfig.colorKeywords || {}, + valueKeywords = parserConfig.valueKeywords || {}, + allowNested = parserConfig.allowNested, + supportsAtComponent = parserConfig.supportsAtComponent === true; + + var type, override; + function ret(style, tp) { type = tp; return style; } + + // Tokenizers + + function tokenBase(stream, state) { + var ch = stream.next(); + if (tokenHooks[ch]) { + var result = tokenHooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == "@") { + stream.eatWhile(/[\w\\\-]/); + return ret("def", stream.current()); + } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { + return ret(null, "compare"); + } else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "#") { + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "hash"); + } else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (ch === "-") { + if (/[\d.]/.test(stream.peek())) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (stream.match(/^-[\w\\\-]+/)) { + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ret("variable-2", "variable-definition"); + return ret("variable-2", "variable"); + } else if (stream.match(/^\w+-/)) { + return ret("meta", "meta"); + } + } else if (/[,+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { + return ret("qualifier", "qualifier"); + } else if (/[:;{}\[\]\(\)]/.test(ch)) { + return ret(null, ch); + } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) || + (ch == "d" && stream.match("omain(")) || + (ch == "r" && stream.match("egexp("))) { + stream.backUp(1); + state.tokenize = tokenParenthesized; + return ret("property", "word"); + } else if (/[\w\\\-]/.test(ch)) { + stream.eatWhile(/[\w\\\-]/); + return ret("property", "word"); + } else { + return ret(null, null); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + if (quote == ")") stream.backUp(1); + break; + } + escaped = !escaped && ch == "\\"; + } + if (ch == quote || !escaped && quote != ")") state.tokenize = null; + return ret("string", "string"); + }; + } + + function tokenParenthesized(stream, state) { + stream.next(); // Must be '(' + if (!stream.match(/\s*[\"\')]/, false)) + state.tokenize = tokenString(")"); + else + state.tokenize = null; + return ret(null, "("); + } + + // Context management + + function Context(type, indent, prev) { + this.type = type; + this.indent = indent; + this.prev = prev; + } + + function pushContext(state, stream, type, indent) { + state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context); + return type; + } + + function popContext(state) { + if (state.context.prev) + state.context = state.context.prev; + return state.context.type; + } + + function pass(type, stream, state) { + return states[state.context.type](type, stream, state); + } + function popAndPass(type, stream, state, n) { + for (var i = n || 1; i > 0; i--) + state.context = state.context.prev; + return pass(type, stream, state); + } + + // Parser + + function wordAsValue(stream) { + var word = stream.current().toLowerCase(); + if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "variable"; + } + + var states = {}; + + states.top = function(type, stream, state) { + if (type == "{") { + return pushContext(state, stream, "block"); + } else if (type == "}" && state.context.prev) { + return popContext(state); + } else if (supportsAtComponent && /@component/.test(type)) { + return pushContext(state, stream, "atComponentBlock"); + } else if (/^@(-moz-)?document$/.test(type)) { + return pushContext(state, stream, "documentTypes"); + } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) { + return pushContext(state, stream, "atBlock"); + } else if (/^@(font-face|counter-style)/.test(type)) { + state.stateArg = type; + return "restricted_atBlock_before"; + } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { + return "keyframes"; + } else if (type && type.charAt(0) == "@") { + return pushContext(state, stream, "at"); + } else if (type == "hash") { + override = "builtin"; + } else if (type == "word") { + override = "tag"; + } else if (type == "variable-definition") { + return "maybeprop"; + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } else if (type == ":") { + return "pseudo"; + } else if (allowNested && type == "(") { + return pushContext(state, stream, "parens"); + } + return state.context.type; + }; + + states.block = function(type, stream, state) { + if (type == "word") { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { + override = "property"; + return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; + } else if (allowNested) { + override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; + return "block"; + } else { + override += " error"; + return "maybeprop"; + } + } else if (type == "meta") { + return "block"; + } else if (!allowNested && (type == "hash" || type == "qualifier")) { + override = "error"; + return "block"; + } else { + return states.top(type, stream, state); + } + }; + + states.maybeprop = function(type, stream, state) { + if (type == ":") return pushContext(state, stream, "prop"); + return pass(type, stream, state); + }; + + states.prop = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); + if (type == "}" || type == "{") return popAndPass(type, stream, state); + if (type == "(") return pushContext(state, stream, "parens"); + + if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { + override += " error"; + } else if (type == "word") { + wordAsValue(stream); + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } + return "prop"; + }; + + states.propBlock = function(type, _stream, state) { + if (type == "}") return popContext(state); + if (type == "word") { override = "property"; return "maybeprop"; } + return state.context.type; + }; + + states.parens = function(type, stream, state) { + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == ")") return popContext(state); + if (type == "(") return pushContext(state, stream, "parens"); + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + if (type == "word") wordAsValue(stream); + return "parens"; + }; + + states.pseudo = function(type, stream, state) { + if (type == "word") { + override = "variable-3"; + return state.context.type; + } + return pass(type, stream, state); + }; + + states.documentTypes = function(type, stream, state) { + if (type == "word" && documentTypes.hasOwnProperty(stream.current())) { + override = "tag"; + return state.context.type; + } else { + return states.atBlock(type, stream, state); + } + }; + + states.atBlock = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "atBlock_parens"); + if (type == "}" || type == ";") return popAndPass(type, stream, state); + if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); + + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + + if (type == "word") { + var word = stream.current().toLowerCase(); + if (word == "only" || word == "not" || word == "and" || word == "or") + override = "keyword"; + else if (mediaTypes.hasOwnProperty(word)) + override = "attribute"; + else if (mediaFeatures.hasOwnProperty(word)) + override = "property"; + else if (mediaValueKeywords.hasOwnProperty(word)) + override = "keyword"; + else if (propertyKeywords.hasOwnProperty(word)) + override = "property"; + else if (nonStandardPropertyKeywords.hasOwnProperty(word)) + override = "string-2"; + else if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "error"; + } + return state.context.type; + }; + + states.atComponentBlock = function(type, stream, state) { + if (type == "}") + return popAndPass(type, stream, state); + if (type == "{") + return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false); + if (type == "word") + override = "error"; + return state.context.type; + }; + + states.atBlock_parens = function(type, stream, state) { + if (type == ")") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); + return states.atBlock(type, stream, state); + }; + + states.restricted_atBlock_before = function(type, stream, state) { + if (type == "{") + return pushContext(state, stream, "restricted_atBlock"); + if (type == "word" && state.stateArg == "@counter-style") { + override = "variable"; + return "restricted_atBlock_before"; + } + return pass(type, stream, state); + }; + + states.restricted_atBlock = function(type, stream, state) { + if (type == "}") { + state.stateArg = null; + return popContext(state); + } + if (type == "word") { + if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || + (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) + override = "error"; + else + override = "property"; + return "maybeprop"; + } + return "restricted_atBlock"; + }; + + states.keyframes = function(type, stream, state) { + if (type == "word") { override = "variable"; return "keyframes"; } + if (type == "{") return pushContext(state, stream, "top"); + return pass(type, stream, state); + }; + + states.at = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == "word") override = "tag"; + else if (type == "hash") override = "builtin"; + return "at"; + }; + + states.interpolation = function(type, stream, state) { + if (type == "}") return popContext(state); + if (type == "{" || type == ";") return popAndPass(type, stream, state); + if (type == "word") override = "variable"; + else if (type != "variable" && type != "(" && type != ")") override = "error"; + return "interpolation"; + }; + + return { + startState: function(base) { + return {tokenize: null, + state: inline ? "block" : "top", + stateArg: null, + context: new Context(inline ? "block" : "top", base || 0, null)}; + }, + + token: function(stream, state) { + if (!state.tokenize && stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style && typeof style == "object") { + type = style[1]; + style = style[0]; + } + override = style; + state.state = states[state.state](type, stream, state); + return override; + }, + + indent: function(state, textAfter) { + var cx = state.context, ch = textAfter && textAfter.charAt(0); + var indent = cx.indent; + if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; + if (cx.prev) { + if (ch == "}" && (cx.type == "block" || cx.type == "top" || + cx.type == "interpolation" || cx.type == "restricted_atBlock")) { + // Resume indentation from parent context. + cx = cx.prev; + indent = cx.indent; + } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || + ch == "{" && (cx.type == "at" || cx.type == "atBlock")) { + // Dedent relative to current context. + indent = Math.max(0, cx.indent - indentUnit); + cx = cx.prev; + } + } + return indent; + }, + + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + fold: "brace" + }; +}); + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i].toLowerCase()] = true; + } + return keys; + } + + var documentTypes_ = [ + "domain", "regexp", "url", "url-prefix" + ], documentTypes = keySet(documentTypes_); + + var mediaTypes_ = [ + "all", "aural", "braille", "handheld", "print", "projection", "screen", + "tty", "tv", "embossed" + ], mediaTypes = keySet(mediaTypes_); + + var mediaFeatures_ = [ + "width", "min-width", "max-width", "height", "min-height", "max-height", + "device-width", "min-device-width", "max-device-width", "device-height", + "min-device-height", "max-device-height", "aspect-ratio", + "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", + "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", + "max-color", "color-index", "min-color-index", "max-color-index", + "monochrome", "min-monochrome", "max-monochrome", "resolution", + "min-resolution", "max-resolution", "scan", "grid", "orientation", + "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", + "pointer", "any-pointer", "hover", "any-hover" + ], mediaFeatures = keySet(mediaFeatures_); + + var mediaValueKeywords_ = [ + "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", + "interlace", "progressive" + ], mediaValueKeywords = keySet(mediaValueKeywords_); + + var propertyKeywords_ = [ + "align-content", "align-items", "align-self", "alignment-adjust", + "alignment-baseline", "anchor-point", "animation", "animation-delay", + "animation-direction", "animation-duration", "animation-fill-mode", + "animation-iteration-count", "animation-name", "animation-play-state", + "animation-timing-function", "appearance", "azimuth", "backface-visibility", + "background", "background-attachment", "background-blend-mode", "background-clip", + "background-color", "background-image", "background-origin", "background-position", + "background-repeat", "background-size", "baseline-shift", "binding", + "bleed", "bookmark-label", "bookmark-level", "bookmark-state", + "bookmark-target", "border", "border-bottom", "border-bottom-color", + "border-bottom-left-radius", "border-bottom-right-radius", + "border-bottom-style", "border-bottom-width", "border-collapse", + "border-color", "border-image", "border-image-outset", + "border-image-repeat", "border-image-slice", "border-image-source", + "border-image-width", "border-left", "border-left-color", + "border-left-style", "border-left-width", "border-radius", "border-right", + "border-right-color", "border-right-style", "border-right-width", + "border-spacing", "border-style", "border-top", "border-top-color", + "border-top-left-radius", "border-top-right-radius", "border-top-style", + "border-top-width", "border-width", "bottom", "box-decoration-break", + "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", + "caption-side", "clear", "clip", "color", "color-profile", "column-count", + "column-fill", "column-gap", "column-rule", "column-rule-color", + "column-rule-style", "column-rule-width", "column-span", "column-width", + "columns", "content", "counter-increment", "counter-reset", "crop", "cue", + "cue-after", "cue-before", "cursor", "direction", "display", + "dominant-baseline", "drop-initial-after-adjust", + "drop-initial-after-align", "drop-initial-before-adjust", + "drop-initial-before-align", "drop-initial-size", "drop-initial-value", + "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", + "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", + "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", + "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", + "font-stretch", "font-style", "font-synthesis", "font-variant", + "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", + "font-variant-ligatures", "font-variant-numeric", "font-variant-position", + "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", + "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap", + "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", + "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns", + "grid-template-rows", "hanging-punctuation", "height", "hyphens", + "icon", "image-orientation", "image-rendering", "image-resolution", + "inline-box-align", "justify-content", "left", "letter-spacing", + "line-break", "line-height", "line-stacking", "line-stacking-ruby", + "line-stacking-shift", "line-stacking-strategy", "list-style", + "list-style-image", "list-style-position", "list-style-type", "margin", + "margin-bottom", "margin-left", "margin-right", "margin-top", + "marks", "marquee-direction", "marquee-loop", + "marquee-play-count", "marquee-speed", "marquee-style", "max-height", + "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", + "nav-left", "nav-right", "nav-up", "object-fit", "object-position", + "opacity", "order", "orphans", "outline", + "outline-color", "outline-offset", "outline-style", "outline-width", + "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", + "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", + "page", "page-break-after", "page-break-before", "page-break-inside", + "page-policy", "pause", "pause-after", "pause-before", "perspective", + "perspective-origin", "pitch", "pitch-range", "play-during", "position", + "presentation-level", "punctuation-trim", "quotes", "region-break-after", + "region-break-before", "region-break-inside", "region-fragment", + "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", + "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", + "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", + "shape-outside", "size", "speak", "speak-as", "speak-header", + "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", + "tab-size", "table-layout", "target", "target-name", "target-new", + "target-position", "text-align", "text-align-last", "text-decoration", + "text-decoration-color", "text-decoration-line", "text-decoration-skip", + "text-decoration-style", "text-emphasis", "text-emphasis-color", + "text-emphasis-position", "text-emphasis-style", "text-height", + "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", + "text-wrap", "top", "transform", "transform-origin", "transform-style", + "transition", "transition-delay", "transition-duration", + "transition-property", "transition-timing-function", "unicode-bidi", + "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", + "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", + "voice-volume", "volume", "white-space", "widows", "width", "word-break", + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", + "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", + "color-interpolation", "color-interpolation-filters", + "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", + "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", + "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "text-anchor", "writing-mode" + ], propertyKeywords = keySet(propertyKeywords_); + + var nonStandardPropertyKeywords_ = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); + + var fontProperties_ = [ + "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", + "font-stretch", "font-weight", "font-style" + ], fontProperties = keySet(fontProperties_); + + var counterDescriptors_ = [ + "additive-symbols", "fallback", "negative", "pad", "prefix", "range", + "speak-as", "suffix", "symbols", "system" + ], counterDescriptors = keySet(counterDescriptors_); + + var colorKeywords_ = [ + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", + "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", + "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", + "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", + "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", + "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", + "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", + "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", + "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", + "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", + "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "whitesmoke", "yellow", "yellowgreen" + ], colorKeywords = keySet(colorKeywords_); + + var valueKeywords_ = [ + "above", "absolute", "activeborder", "additive", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", + "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", + "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page", + "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", + "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", + "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", + "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", + "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", + "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", + "compact", "condensed", "contain", "content", + "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", + "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", + "destination-in", "destination-out", "destination-over", "devanagari", "difference", + "disc", "discard", "disclosure-closed", "disclosure-open", "document", + "dot-dash", "dot-dot-dash", + "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", + "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", + "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", + "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", + "ethiopic-halehame-gez", "ethiopic-halehame-om-et", + "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", + "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", + "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", + "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", + "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", + "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", + "help", "hidden", "hide", "higher", "highlight", "highlighttext", + "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", + "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", + "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", + "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", + "italic", "japanese-formal", "japanese-informal", "justify", "kannada", + "katakana", "katakana-iroha", "keep-all", "khmer", + "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", + "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten", + "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", + "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", + "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", + "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d", + "media-controls-background", "media-current-time-display", + "media-fullscreen-button", "media-mute-button", "media-play-button", + "media-return-to-realtime-button", "media-rewind-button", + "media-seek-back-button", "media-seek-forward-button", "media-slider", + "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", + "media-volume-slider-container", "media-volume-sliderthumb", "medium", + "menu", "menulist", "menulist-button", "menulist-text", + "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", + "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", + "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", + "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", + "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", + "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", + "progress", "push-button", "radial-gradient", "radio", "read-only", + "read-write", "read-write-plaintext-only", "rectangle", "region", + "relative", "repeat", "repeating-linear-gradient", + "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", + "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", + "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", + "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", + "scroll", "scrollbar", "se-resize", "searchfield", + "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", + "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "simp-chinese-formal", "simp-chinese-informal", "single", + "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", + "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", + "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", + "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "spell-out", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", + "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table", + "table-caption", "table-cell", "table-column", "table-column-group", + "table-footer-group", "table-header-group", "table-row", "table-row-group", + "tamil", + "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", + "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", + "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", + "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", + "trad-chinese-formal", "trad-chinese-informal", + "translate", "translate3d", "translateX", "translateY", "translateZ", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", + "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", + "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", + "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", + "xx-large", "xx-small" + ], valueKeywords = keySet(valueKeywords_); + + var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_) + .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_) + .concat(valueKeywords_); + CodeMirror.registerHelper("hintWords", "css", allWords); + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + CodeMirror.defineMIME("text/css", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css" + }); + + CodeMirror.defineMIME("text/x-scss", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + ":": function(stream) { + if (stream.match(/\s*\{/)) + return [null, "{"]; + return false; + }, + "$": function(stream) { + stream.match(/^[\w-]+/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "#": function(stream) { + if (!stream.eat("{")) return false; + return [null, "interpolation"]; + } + }, + name: "css", + helperType: "scss" + }); + + CodeMirror.defineMIME("text/x-less", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + "@": function(stream) { + if (stream.eat("{")) return [null, "interpolation"]; + if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false; + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "&": function() { + return ["atom", "atom"]; + } + }, + name: "css", + helperType: "less" + }); + + CodeMirror.defineMIME("text/x-gss", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + supportsAtComponent: true, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css", + helperType: "gss" + }); + +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/gss.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/gss.html new file mode 100644 index 0000000..232fe8c --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/gss.html @@ -0,0 +1,103 @@ + + +CodeMirror: Closure Stylesheets (GSS) mode + + + + + + + + + + + + +
      +

      Closure Stylesheets (GSS) mode

      +
      + + +

      A mode for Closure Stylesheets (GSS).

      +

      MIME type defined: text/x-gss.

      + +

      Parsing/Highlighting Tests: normal, verbose.

      + +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/gss_test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/gss_test.js new file mode 100644 index 0000000..d56e592 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/gss_test.js @@ -0,0 +1,17 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); } + + MT("atComponent", + "[def @component] {", + "[tag foo] {", + " [property color]: [keyword black];", + "}", + "}"); + +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/index.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/index.html new file mode 100644 index 0000000..2d2b9b0 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/index.html @@ -0,0 +1,75 @@ + + +CodeMirror: CSS mode + + + + + + + + + + + + +
      +

      CSS mode

      +
      + + +

      MIME types defined: text/css, text/x-scss (demo), text/x-less (demo).

      + +

      Parsing/Highlighting Tests: normal, verbose.

      + +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/less.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/less.html new file mode 100644 index 0000000..adf7427 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/less.html @@ -0,0 +1,152 @@ + + +CodeMirror: LESS mode + + + + + + + + + + +
      +

      LESS mode

      +
      + + +

      The LESS mode is a sub-mode of the CSS mode (defined in css.js).

      + +

      Parsing/Highlighting Tests: normal, verbose.

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/less_test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/less_test.js new file mode 100644 index 0000000..dd82155 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/less_test.js @@ -0,0 +1,54 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + "use strict"; + + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-less"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "less"); } + + MT("variable", + "[variable-2 @base]: [atom #f04615];", + "[qualifier .class] {", + " [property width]: [variable percentage]([number 0.5]); [comment // returns `50%`]", + " [property color]: [variable saturate]([variable-2 @base], [number 5%]);", + "}"); + + MT("amp", + "[qualifier .child], [qualifier .sibling] {", + " [qualifier .parent] [atom &] {", + " [property color]: [keyword black];", + " }", + " [atom &] + [atom &] {", + " [property color]: [keyword red];", + " }", + "}"); + + MT("mixin", + "[qualifier .mixin] ([variable dark]; [variable-2 @color]) {", + " [property color]: [atom darken]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable light]; [variable-2 @color]) {", + " [property color]: [atom lighten]([variable-2 @color], [number 10%]);", + "}", + "[qualifier .mixin] ([variable-2 @_]; [variable-2 @color]) {", + " [property display]: [atom block];", + "}", + "[variable-2 @switch]: [variable light];", + "[qualifier .class] {", + " [qualifier .mixin]([variable-2 @switch]; [atom #888]);", + "}"); + + MT("nest", + "[qualifier .one] {", + " [def @media] ([property width]: [number 400px]) {", + " [property font-size]: [number 1.2em];", + " [def @media] [attribute print] [keyword and] [property color] {", + " [property color]: [keyword blue];", + " }", + " }", + "}"); + + + MT("interpolation", ".@{[variable foo]} { [property font-weight]: [atom bold]; }"); +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/scss.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/scss.html new file mode 100644 index 0000000..f8e4d37 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/scss.html @@ -0,0 +1,157 @@ + + +CodeMirror: SCSS mode + + + + + + + + + +
      +

      SCSS mode

      +
      + + +

      The SCSS mode is a sub-mode of the CSS mode (defined in css.js).

      + +

      Parsing/Highlighting Tests: normal, verbose.

      + +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/scss_test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/scss_test.js new file mode 100644 index 0000000..785921b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/scss_test.js @@ -0,0 +1,110 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } + + MT('url_with_quotation', + "[tag foo] { [property background]:[atom url]([string test.jpg]) }"); + + MT('url_with_double_quotes', + "[tag foo] { [property background]:[atom url]([string \"test.jpg\"]) }"); + + MT('url_with_single_quotes', + "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) }"); + + MT('string', + "[def @import] [string \"compass/css3\"]"); + + MT('important_keyword', + "[tag foo] { [property background]:[atom url]([string \'test.jpg\']) [keyword !important] }"); + + MT('variable', + "[variable-2 $blue]:[atom #333]"); + + MT('variable_as_attribute', + "[tag foo] { [property color]:[variable-2 $blue] }"); + + MT('numbers', + "[tag foo] { [property padding]:[number 10px] [number 10] [number 10em] [number 8in] }"); + + MT('number_percentage', + "[tag foo] { [property width]:[number 80%] }"); + + MT('selector', + "[builtin #hello][qualifier .world]{}"); + + MT('singleline_comment', + "[comment // this is a comment]"); + + MT('multiline_comment', + "[comment /*foobar*/]"); + + MT('attribute_with_hyphen', + "[tag foo] { [property font-size]:[number 10px] }"); + + MT('string_after_attribute', + "[tag foo] { [property content]:[string \"::\"] }"); + + MT('directives', + "[def @include] [qualifier .mixin]"); + + MT('basic_structure', + "[tag p] { [property background]:[keyword red]; }"); + + MT('nested_structure', + "[tag p] { [tag a] { [property color]:[keyword red]; } }"); + + MT('mixin', + "[def @mixin] [tag table-base] {}"); + + MT('number_without_semicolon', + "[tag p] {[property width]:[number 12]}", + "[tag a] {[property color]:[keyword red];}"); + + MT('atom_in_nested_block', + "[tag p] { [tag a] { [property color]:[atom #000]; } }"); + + MT('interpolation_in_property', + "[tag foo] { #{[variable-2 $hello]}:[number 2]; }"); + + MT('interpolation_in_selector', + "[tag foo]#{[variable-2 $hello]} { [property color]:[atom #000]; }"); + + MT('interpolation_error', + "[tag foo]#{[variable foo]} { [property color]:[atom #000]; }"); + + MT("divide_operator", + "[tag foo] { [property width]:[number 4] [operator /] [number 2] }"); + + MT('nested_structure_with_id_selector', + "[tag p] { [builtin #hello] { [property color]:[keyword red]; } }"); + + MT('indent_mixin', + "[def @mixin] [tag container] (", + " [variable-2 $a]: [number 10],", + " [variable-2 $b]: [number 10])", + "{}"); + + MT('indent_nested', + "[tag foo] {", + " [tag bar] {", + " }", + "}"); + + MT('indent_parentheses', + "[tag foo] {", + " [property color]: [atom darken]([variable-2 $blue],", + " [number 9%]);", + "}"); + + MT('indent_vardef', + "[variable-2 $name]:", + " [string 'val'];", + "[tag tag] {", + " [tag inner] {", + " [property margin]: [number 3px];", + " }", + "}"); +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/test.js new file mode 100644 index 0000000..7a496fb --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/css/test.js @@ -0,0 +1,200 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "css"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Error, because "foobarhello" is neither a known type or property, but + // property was expected (after "and"), and it should be in parentheses. + MT("atMediaUnknownType", + "[def @media] [attribute screen] [keyword and] [error foobarhello] { }"); + + // Soft error, because "foobarhello" is not a known property or type. + MT("atMediaUnknownProperty", + "[def @media] [attribute screen] [keyword and] ([error foobarhello]) { }"); + + // Make sure nesting works with media queries + MT("atMediaMaxWidthNested", + "[def @media] [attribute screen] [keyword and] ([property max-width]: [number 25px]) { [tag foo] { } }"); + + MT("atMediaFeatureValueKeyword", + "[def @media] ([property orientation]: [keyword landscape]) { }"); + + MT("atMediaUnknownFeatureValueKeyword", + "[def @media] ([property orientation]: [error upsidedown]) { }"); + + MT("tagSelector", + "[tag foo] { }"); + + MT("classSelector", + "[qualifier .foo-bar_hello] { }"); + + MT("idSelector", + "[builtin #foo] { [error #foo] }"); + + MT("tagSelectorUnclosed", + "[tag foo] { [property margin]: [number 0] } [tag bar] { }"); + + MT("tagStringNoQuotes", + "[tag foo] { [property font-family]: [variable hello] [variable world]; }"); + + MT("tagStringDouble", + "[tag foo] { [property font-family]: [string \"hello world\"]; }"); + + MT("tagStringSingle", + "[tag foo] { [property font-family]: [string 'hello world']; }"); + + MT("tagColorKeyword", + "[tag foo] {", + " [property color]: [keyword black];", + " [property color]: [keyword navy];", + " [property color]: [keyword yellow];", + "}"); + + MT("tagColorHex3", + "[tag foo] { [property background]: [atom #fff]; }"); + + MT("tagColorHex4", + "[tag foo] { [property background]: [atom #ffff]; }"); + + MT("tagColorHex6", + "[tag foo] { [property background]: [atom #ffffff]; }"); + + MT("tagColorHex8", + "[tag foo] { [property background]: [atom #ffffffff]; }"); + + MT("tagColorHex5Invalid", + "[tag foo] { [property background]: [atom&error #fffff]; }"); + + MT("tagColorHexInvalid", + "[tag foo] { [property background]: [atom&error #ffg]; }"); + + MT("tagNegativeNumber", + "[tag foo] { [property margin]: [number -5px]; }"); + + MT("tagPositiveNumber", + "[tag foo] { [property padding]: [number 5px]; }"); + + MT("tagVendor", + "[tag foo] { [meta -foo-][property box-sizing]: [meta -foo-][atom border-box]; }"); + + MT("tagBogusProperty", + "[tag foo] { [property&error barhelloworld]: [number 0]; }"); + + MT("tagTwoProperties", + "[tag foo] { [property margin]: [number 0]; [property padding]: [number 0]; }"); + + MT("tagTwoPropertiesURL", + "[tag foo] { [property background]: [atom url]([string //example.com/foo.png]); [property padding]: [number 0]; }"); + + MT("indent_tagSelector", + "[tag strong], [tag em] {", + " [property background]: [atom rgba](", + " [number 255], [number 255], [number 0], [number .2]", + " );", + "}"); + + MT("indent_atMedia", + "[def @media] {", + " [tag foo] {", + " [property color]:", + " [keyword yellow];", + " }", + "}"); + + MT("indent_comma", + "[tag foo] {", + " [property font-family]: [variable verdana],", + " [atom sans-serif];", + "}"); + + MT("indent_parentheses", + "[tag foo]:[variable-3 before] {", + " [property background]: [atom url](", + "[string blahblah]", + "[string etc]", + "[string ]) [keyword !important];", + "}"); + + MT("font_face", + "[def @font-face] {", + " [property font-family]: [string 'myfont'];", + " [error nonsense]: [string 'abc'];", + " [property src]: [atom url]([string http://blah]),", + " [atom url]([string http://foo]);", + "}"); + + MT("empty_url", + "[def @import] [atom url]() [attribute screen];"); + + MT("parens", + "[qualifier .foo] {", + " [property background-image]: [variable fade]([atom #000], [number 20%]);", + " [property border-image]: [atom linear-gradient](", + " [atom to] [atom bottom],", + " [variable fade]([atom #000], [number 20%]) [number 0%],", + " [variable fade]([atom #000], [number 20%]) [number 100%]", + " );", + "}"); + + MT("css_variable", + ":[variable-3 root] {", + " [variable-2 --main-color]: [atom #06c];", + "}", + "[tag h1][builtin #foo] {", + " [property color]: [atom var]([variable-2 --main-color]);", + "}"); + + MT("supports", + "[def @supports] ([keyword not] (([property text-align-last]: [atom justify]) [keyword or] ([meta -moz-][property text-align-last]: [atom justify])) {", + " [property text-align-last]: [atom justify];", + "}"); + + MT("document", + "[def @document] [tag url]([string http://blah]),", + " [tag url-prefix]([string https://]),", + " [tag domain]([string blah.com]),", + " [tag regexp]([string \".*blah.+\"]) {", + " [builtin #id] {", + " [property background-color]: [keyword white];", + " }", + " [tag foo] {", + " [property font-family]: [variable Verdana], [atom sans-serif];", + " }", + "}"); + + MT("document_url", + "[def @document] [tag url]([string http://blah]) { [qualifier .class] { } }"); + + MT("document_urlPrefix", + "[def @document] [tag url-prefix]([string https://]) { [builtin #id] { } }"); + + MT("document_domain", + "[def @document] [tag domain]([string blah.com]) { [tag foo] { } }"); + + MT("document_regexp", + "[def @document] [tag regexp]([string \".*blah.+\"]) { [builtin #id] { } }"); + + MT("counter-style", + "[def @counter-style] [variable binary] {", + " [property system]: [atom numeric];", + " [property symbols]: [number 0] [number 1];", + " [property suffix]: [string \".\"];", + " [property range]: [atom infinite];", + " [property speak-as]: [atom numeric];", + "}"); + + MT("counter-style-additive-symbols", + "[def @counter-style] [variable simple-roman] {", + " [property system]: [atom additive];", + " [property additive-symbols]: [number 10] [variable X], [number 5] [variable V], [number 1] [variable I];", + " [property range]: [number 1] [number 49];", + "}"); + + MT("counter-style-use", + "[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }"); + + MT("counter-style-symbols", + "[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }"); +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlembedded/htmlembedded.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlembedded/htmlembedded.js new file mode 100644 index 0000000..464dc57 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlembedded/htmlembedded.js @@ -0,0 +1,28 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), + require("../../addon/mode/multiplex")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", + "../../addon/mode/multiplex"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { + return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), { + open: parserConfig.open || parserConfig.scriptStartRegex || "<%", + close: parserConfig.close || parserConfig.scriptEndRegex || "%>", + mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec) + }); + }, "htmlmixed"); + + CodeMirror.defineMIME("application/x-ejs", {name: "htmlembedded", scriptingModeSpec:"javascript"}); + CodeMirror.defineMIME("application/x-aspx", {name: "htmlembedded", scriptingModeSpec:"text/x-csharp"}); + CodeMirror.defineMIME("application/x-jsp", {name: "htmlembedded", scriptingModeSpec:"text/x-java"}); + CodeMirror.defineMIME("application/x-erb", {name: "htmlembedded", scriptingModeSpec:"ruby"}); +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlembedded/index.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlembedded/index.html new file mode 100644 index 0000000..9ed33cf --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlembedded/index.html @@ -0,0 +1,60 @@ + + +CodeMirror: Html Embedded Scripts mode + + + + + + + + + + + + + + +
      +

      Html Embedded Scripts mode

      +
      + + + +

      Mode for html embedded scripts like JSP and ASP.NET. Depends on multiplex and HtmlMixed which in turn depends on + JavaScript, CSS and XML.
      Other dependencies include those of the scripting language chosen.

      + +

      MIME types defined: application/x-aspx (ASP.NET), + application/x-ejs (Embedded Javascript), application/x-jsp (JavaServer Pages) + and application/x-erb

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlmixed/htmlmixed.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlmixed/htmlmixed.js new file mode 100644 index 0000000..eb21fcc --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlmixed/htmlmixed.js @@ -0,0 +1,152 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var defaultTags = { + script: [ + ["lang", /(javascript|babel)/i, "javascript"], + ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^$/i, "javascript"], + ["type", /./, "text/plain"], + [null, null, "javascript"] + ], + style: [ + ["lang", /^css$/i, "css"], + ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], + ["type", /./, "text/plain"], + [null, null, "css"] + ] + }; + + function maybeBackup(stream, pat, style) { + var cur = stream.current(), close = cur.search(pat); + if (close > -1) { + stream.backUp(cur.length - close); + } else if (cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur); + } + return style; + } + + var attrRegexpCache = {}; + function getAttrRegexp(attr) { + var regexp = attrRegexpCache[attr]; + if (regexp) return regexp; + return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); + } + + function getAttrValue(text, attr) { + var match = text.match(getAttrRegexp(attr)) + return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : "" + } + + function getTagRegexp(tagName, anchored) { + return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); + } + + function addTags(from, to) { + for (var tag in from) { + var dest = to[tag] || (to[tag] = []); + var source = from[tag]; + for (var i = source.length - 1; i >= 0; i--) + dest.unshift(source[i]) + } + } + + function findMatchingMode(tagInfo, tagText) { + for (var i = 0; i < tagInfo.length; i++) { + var spec = tagInfo[i]; + if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; + } + } + + CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, { + name: "xml", + htmlMode: true, + multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag + }); + + var tags = {}; + var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; + addTags(defaultTags, tags); + if (configTags) addTags(configTags, tags); + if (configScript) for (var i = configScript.length - 1; i >= 0; i--) + tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) + + function html(stream, state) { + var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName + if (tag && !/[<>\s\/]/.test(stream.current()) && + (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && + tags.hasOwnProperty(tagName)) { + state.inTag = tagName + " " + } else if (state.inTag && tag && />$/.test(stream.current())) { + var inTag = /^([\S]+) (.*)/.exec(state.inTag) + state.inTag = null + var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) + var mode = CodeMirror.getMode(config, modeSpec) + var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); + state.token = function (stream, state) { + if (stream.match(endTagA, false)) { + state.token = html; + state.localState = state.localMode = null; + return null; + } + return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); + }; + state.localMode = mode; + state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "")); + } else if (state.inTag) { + state.inTag += stream.current() + if (stream.eol()) state.inTag += " " + } + return style; + }; + + return { + startState: function () { + var state = CodeMirror.startState(htmlMode); + return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; + }, + + copyState: function (state) { + var local; + if (state.localState) { + local = CodeMirror.copyState(state.localMode, state.localState); + } + return {token: state.token, inTag: state.inTag, + localMode: state.localMode, localState: local, + htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; + }, + + token: function (stream, state) { + return state.token(stream, state); + }, + + indent: function (state, textAfter) { + if (!state.localMode || /^\s*<\//.test(textAfter)) + return htmlMode.indent(state.htmlState, textAfter); + else if (state.localMode.indent) + return state.localMode.indent(state.localState, textAfter); + else + return CodeMirror.Pass; + }, + + innerMode: function (state) { + return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; + } + }; + }, "xml", "javascript", "css"); + + CodeMirror.defineMIME("text/html", "htmlmixed"); +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlmixed/index.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlmixed/index.html new file mode 100644 index 0000000..f94df9e --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/htmlmixed/index.html @@ -0,0 +1,89 @@ + + +CodeMirror: HTML mixed mode + + + + + + + + + + + + + + +
      +

      HTML mixed mode

      +
      + + +

      The HTML mixed mode depends on the XML, JavaScript, and CSS modes.

      + +

      It takes an optional mode configuration + option, scriptTypes, which can be used to add custom + behavior for specific <script type="..."> tags. If + given, it should hold an array of {matches, mode} + objects, where matches is a string or regexp that + matches the script type, and mode is + either null, for script types that should stay in + HTML mode, or a mode + spec corresponding to the mode that should be used for the + script.

      + +

      MIME types defined: text/html + (redefined, only takes effect if you load this parser after the + XML parser).

      + +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/index.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/index.html new file mode 100644 index 0000000..592a133 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/index.html @@ -0,0 +1,114 @@ + + +CodeMirror: JavaScript mode + + + + + + + + + + + + +
      +

      JavaScript mode

      + + +
      + + + +

      + JavaScript mode supports several configuration options: +

        +
      • json which will set the mode to expect JSON + data rather than a JavaScript program.
      • +
      • jsonld which will set the mode to expect + JSON-LD linked data rather + than a JavaScript program (demo).
      • +
      • typescript which will activate additional + syntax highlighting and some other things for TypeScript code + (demo).
      • +
      • statementIndent which (given a number) will + determine the amount of indentation to use for statements + continued on a new line.
      • +
      • wordCharacters, a regexp that indicates which + characters should be considered part of an identifier. + Defaults to /[\w$]/, which does not handle + non-ASCII identifiers. Can be set to something more elaborate + to improve Unicode support.
      • +
      +

      + +

      MIME types defined: text/javascript, application/json, application/ld+json, text/typescript, application/typescript.

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/javascript.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/javascript.js new file mode 100644 index 0000000..a717745 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/javascript.js @@ -0,0 +1,784 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function expressionAllowed(stream, state, backUp) { + return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) || + (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) +} + +CodeMirror.defineMode("javascript", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}; + + var jsKeywords = { + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C, + "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this"), "class": kw("class"), "super": kw("atom"), + "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, + "await": C, "async": kw("async") + }; + + // Extend the 'normal' keywords with the TypeScript language extensions + if (isTS) { + var type = {type: "variable", style: "variable-3"}; + var tsKeywords = { + // object-like things + "interface": kw("class"), + "implements": C, + "namespace": C, + "module": kw("module"), + "enum": kw("module"), + "type": kw("type"), + + // scope modifiers + "public": kw("modifier"), + "private": kw("modifier"), + "protected": kw("modifier"), + "abstract": kw("modifier"), + + // operators + "as": operator, + + // types + "string": type, "number": type, "boolean": type, "any": type + }; + + for (var attr in tsKeywords) { + jsKeywords[attr] = tsKeywords[attr]; + } + } + + return jsKeywords; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|~^]/; + var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, next, inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == "/" && !inSet) return; + if (next == "[") inSet = true; + else if (inSet && next == "]") inSet = false; + } + escaped = !escaped && next == "\\"; + } + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { + return ret("number", "number"); + } else if (ch == "." && stream.match("..")) { + return ret("spread", "meta"); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == "=" && stream.eat(">")) { + return ret("=>", "operator"); + } else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } else if (ch == "0" && stream.eat(/o/i)) { + stream.eatWhile(/[0-7]/i); + return ret("number", "number"); + } else if (ch == "0" && stream.eat(/b/i)) { + stream.eatWhile(/[01]/i); + return ret("number", "number"); + } else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else if (expressionAllowed(stream, state, 1)) { + readRegexp(stream); + stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); + return ret("regexp", "string-2"); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } + } else if (ch == "`") { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.lastType != ".") ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ + state.tokenize = tokenBase; + return ret("jsonld-keyword", "meta"); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenQuasi(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == "\\"; + } + return ret("quasi", "string-2", stream.current()); + } + + var brackets = "([{}])"; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf("=>", stream.start); + if (arrow < 0) return; + + if (isTS) { // Try to skip TypeScript return type declarations after the arguments + var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow)) + if (m) arrow = m.index + } + + var depth = 0, sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { ++pos; break; } + if (--depth == 0) { if (ch == "(") sawSomething = true; break; } + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (wordRE.test(ch)) { + sawSomething = true; + } else if (/["'\/]/.test(ch)) { + return; + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + function inList(list) { + for (var v = list; v; v = v.next) + if (v.name == varname) return true; + return false; + } + var state = cx.state; + cx.marked = "def"; + if (state.context) { + if (inList(state.localVars)) return; + state.localVars = {name: varname, next: state.localVars}; + } else { + if (inList(state.globalVars)) return; + if (parserConfig.globalVars) + state.globalVars = {name: varname, next: state.globalVars}; + } + } + + // Combinators + + var defaultVars = {name: "this", next: {name: "arguments"}}; + function pushcontext() { + cx.state.context = {prev: cx.state.context, vars: cx.state.localVars}; + cx.state.localVars = defaultVars; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function() { + var state = cx.state, indent = state.indented; + if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; + state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(exp); + }; + return exp; + } + + function statement(type, value) { + if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == ";") return cont(); + if (type == "if") { + if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) + cx.state.cc.pop()(); + return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); + } + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), parenExpr, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + if (type == "class") return cont(pushlex("form"), className, poplex); + if (type == "export") return cont(pushlex("stat"), afterExport, poplex); + if (type == "import") return cont(pushlex("stat"), afterImport, poplex); + if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex) + if (type == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";")); + if (type == "async") return cont(statement) + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + return expressionInner(type, false); + } + function expressionNoComma(type) { + return expressionInner(type, true); + } + function parenExpr(type) { + if (type != "(") return pass() + return cont(pushlex(")"), expression, expect(")"), poplex) + } + function expressionInner(type, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); + else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == "function") return cont(functiondef, maybeop); + if (type == "class") return cont(pushlex("form"), classExpression, poplex); + if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); + if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); + if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); + if (type == "{") return contCommasep(objprop, "}", null, maybeop); + if (type == "quasi") return pass(quasi, maybeop); + if (type == "new") return cont(maybeTarget(noComma)); + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + function maybeexpressionNoComma(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expressionNoComma); + } + + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "operator") { + if (/\+\+|--/.test(value)) return cont(me); + if (value == "?") return cont(expression, expect(":"), expr); + return cont(expr); + } + if (type == "quasi") { return pass(quasi, me); } + if (type == ";") return; + if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); + } + function quasi(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expressionNoComma); + } + function maybeTarget(noComma) { + return function(type) { + if (type == ".") return cont(noComma ? targetNoComma : target); + else return pass(noComma ? expressionNoComma : expression); + }; + } + function target(_, value) { + if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } + } + function targetNoComma(_, value) { + if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperatorComma, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type, value) { + if (type == "async") { + cx.marked = "property"; + return cont(objprop); + } else if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(getterSetter); + return cont(afterprop); + } else if (type == "number" || type == "string") { + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); + } else if (type == "modifier") { + return cont(objprop) + } else if (type == "[") { + return cont(expression, expect("]"), afterprop); + } else if (type == "spread") { + return cont(expression); + } else if (type == ":") { + return pass(afterprop) + } + } + function getterSetter(type) { + if (type != "variable") return pass(afterprop); + cx.marked = "property"; + return cont(functiondef); + } + function afterprop(type) { + if (type == ":") return cont(expressionNoComma); + if (type == "(") return pass(functiondef); + } + function commasep(what, end) { + function proceed(type, value) { + if (type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(function(type, value) { + if (type == end || value == end) return pass() + return pass(what) + }, proceed); + } + if (type == end || value == end) return cont(); + return cont(expect(end)); + } + return function(type, value) { + if (type == end || value == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) + cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function maybetype(type, value) { + if (isTS) { + if (type == ":") return cont(typeexpr); + if (value == "?") return cont(maybetype); + } + } + function typeexpr(type) { + if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);} + if (type == "{") return cont(commasep(typeprop, "}")) + if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) + } + function maybeReturnType(type) { + if (type == "=>") return cont(typeexpr) + } + function typeprop(type) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property" + return cont(typeprop) + } else if (type == ":") { + return cont(typeexpr) + } + } + function typearg(type) { + if (type == "variable") return cont(typearg) + else if (type == ":") return cont(typeexpr) + } + function afterType(type, value) { + if (value == "<") return cont(commasep(typeexpr, ">"), afterType) + if (type == "[") return cont(expect("]"), afterType) + } + function vardef() { + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (type == "modifier") return cont(pattern) + if (type == "variable") { register(value); return cont(); } + if (type == "spread") return cont(pattern); + if (type == "[") return contCommasep(pattern, "]"); + if (type == "{") return contCommasep(proppattern, "}"); + } + function proppattern(type, value) { + if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == "variable") cx.marked = "property"; + if (type == "spread") return cont(pattern); + if (type == "}") return pass(); + return cont(expect(":"), pattern, maybeAssign); + } + function maybeAssign(_type, value) { + if (value == "=") return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ",") return cont(vardef); + } + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); + } + function forspec(type) { + if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); + } + function forspec1(type) { + if (type == "var") return cont(vardef, expect(";"), forspec2); + if (type == ";") return cont(forspec2); + if (type == "variable") return cont(formaybeinof); + return pass(expression, expect(";"), forspec2); + } + function formaybeinof(_type, value) { + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return cont(maybeoperatorComma, forspec2); + } + function forspec2(type, value) { + if (type == ";") return cont(forspec3); + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return pass(expression, expect(";"), forspec3); + } + function forspec3(type) { + if (type != ")") cont(expression); + } + function functiondef(type, value) { + if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} + if (type == "variable") {register(value); return cont(functiondef);} + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext); + } + function funarg(type) { + if (type == "spread") return cont(funarg); + return pass(pattern, maybetype, maybeAssign); + } + function classExpression(type, value) { + // Class expressions may have an optional name. + if (type == "variable") return className(type, value); + return classNameAfter(type, value); + } + function className(type, value) { + if (type == "variable") {register(value); return cont(classNameAfter);} + } + function classNameAfter(type, value) { + if (value == "extends" || value == "implements") return cont(isTS ? typeexpr : expression, classNameAfter); + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "variable" || cx.style == "keyword") { + if ((value == "static" || value == "get" || value == "set" || + (isTS && (value == "public" || value == "private" || value == "protected" || value == "readonly" || value == "abstract"))) && + cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false)) { + cx.marked = "keyword"; + return cont(classBody); + } + cx.marked = "property"; + return cont(isTS ? classfield : functiondef, classBody); + } + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == ";") return cont(classBody); + if (type == "}") return cont(); + } + function classfield(type, value) { + if (value == "?") return cont(classfield) + if (type == ":") return cont(typeexpr, maybeAssign) + return pass(functiondef) + } + function afterExport(_type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } + if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + return pass(statement); + } + function afterImport(type) { + if (type == "string") return cont(); + return pass(importSpec, maybeFrom); + } + function importSpec(type, value) { + if (type == "{") return contCommasep(importSpec, "}"); + if (type == "variable") register(value); + if (value == "*") cx.marked = "keyword"; + return cont(maybeAs); + } + function maybeAs(_type, value) { + if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } + } + function maybeFrom(_type, value) { + if (value == "from") { cx.marked = "keyword"; return cont(expression); } + } + function arrayLiteral(type) { + if (type == "]") return cont(); + return pass(commasep(expressionNoComma, "]")); + } + + function isContinuedStatement(state, textAfter) { + return state.lastType == "operator" || state.lastType == "," || + isOperatorChar.test(textAfter.charAt(0)) || + /[,.]/.test(textAfter.charAt(0)); + } + + // Interface + + return { + startState: function(basecolumn) { + var state = { + tokenize: tokenBase, + lastType: "sof", + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && {vars: parserConfig.localVars}, + indented: basecolumn || 0 + }; + if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + while ((lexical.type == "stat" || lexical.type == "form") && + (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && + (top == maybeoperatorComma || top == maybeoperatorNoComma) && + !/^[,\.=+\-*:?[\(]/.test(textAfter)))) + lexical = lexical.prev; + if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") + lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "form") return lexical.indented + indentUnit; + else if (type == "stat") + return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); + else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", + fold: "brace", + closeBrackets: "()[]{}''\"\"``", + + helperType: jsonMode ? "json" : "javascript", + jsonldMode: jsonldMode, + jsonMode: jsonMode, + + expressionAllowed: expressionAllowed, + skipExpression: function(state) { + var top = state.cc[state.cc.length - 1] + if (top == expression || top == expressionNoComma) state.cc.pop() + } + }; +}); + +CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); + +CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("text/ecmascript", "javascript"); +CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/x-javascript", "javascript"); +CodeMirror.defineMIME("application/ecmascript", "javascript"); +CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); +CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/json-ld.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/json-ld.html new file mode 100644 index 0000000..3a37f0b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/json-ld.html @@ -0,0 +1,72 @@ + + +CodeMirror: JSON-LD mode + + + + + + + + + + + + +
      +

      JSON-LD mode

      + + +
      + + + +

      This is a specialization of the JavaScript mode.

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/test.js new file mode 100644 index 0000000..41765e7 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/test.js @@ -0,0 +1,247 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "javascript"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("locals", + "[keyword function] [def foo]([def a], [def b]) { [keyword var] [def c] [operator =] [number 10]; [keyword return] [variable-2 a] [operator +] [variable-2 c] [operator +] [variable d]; }"); + + MT("comma-and-binop", + "[keyword function](){ [keyword var] [def x] [operator =] [number 1] [operator +] [number 2], [def y]; }"); + + MT("destructuring", + "([keyword function]([def a], [[[def b], [def c] ]]) {", + " [keyword let] {[def d], [property foo]: [def c][operator =][number 10], [def x]} [operator =] [variable foo]([variable-2 a]);", + " [[[variable-2 c], [variable y] ]] [operator =] [variable-2 c];", + "})();"); + + MT("destructure_trailing_comma", + "[keyword let] {[def a], [def b],} [operator =] [variable foo];", + "[keyword let] [def c];"); // Parser still in good state? + + MT("class_body", + "[keyword class] [def Foo] {", + " [property constructor]() {}", + " [property sayName]() {", + " [keyword return] [string-2 `foo${][variable foo][string-2 }oo`];", + " }", + "}"); + + MT("class", + "[keyword class] [def Point] [keyword extends] [variable SuperThing] {", + " [keyword get] [property prop]() { [keyword return] [number 24]; }", + " [property constructor]([def x], [def y]) {", + " [keyword super]([string 'something']);", + " [keyword this].[property x] [operator =] [variable-2 x];", + " }", + "}"); + + MT("anonymous_class_expression", + "[keyword const] [def Adder] [operator =] [keyword class] [keyword extends] [variable Arithmetic] {", + " [property add]([def a], [def b]) {}", + "};"); + + MT("named_class_expression", + "[keyword const] [def Subber] [operator =] [keyword class] [def Subtract] {", + " [property sub]([def a], [def b]) {}", + "};"); + + MT("import", + "[keyword function] [def foo]() {", + " [keyword import] [def $] [keyword from] [string 'jquery'];", + " [keyword import] { [def encrypt], [def decrypt] } [keyword from] [string 'crypto'];", + "}"); + + MT("import_trailing_comma", + "[keyword import] {[def foo], [def bar],} [keyword from] [string 'baz']") + + MT("const", + "[keyword function] [def f]() {", + " [keyword const] [[ [def a], [def b] ]] [operator =] [[ [number 1], [number 2] ]];", + "}"); + + MT("for/of", + "[keyword for]([keyword let] [def of] [keyword of] [variable something]) {}"); + + MT("generator", + "[keyword function*] [def repeat]([def n]) {", + " [keyword for]([keyword var] [def i] [operator =] [number 0]; [variable-2 i] [operator <] [variable-2 n]; [operator ++][variable-2 i])", + " [keyword yield] [variable-2 i];", + "}"); + + MT("quotedStringAddition", + "[keyword let] [def f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];"); + + MT("quotedFatArrow", + "[keyword let] [def f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];"); + + MT("fatArrow", + "[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);", + "[variable a];", // No longer in scope + "[keyword let] [def f] [operator =] ([[ [def a], [def b] ]], [def c]) [operator =>] [variable-2 a] [operator +] [variable-2 c];", + "[variable c];"); + + MT("spread", + "[keyword function] [def f]([def a], [meta ...][def b]) {", + " [variable something]([variable-2 a], [meta ...][variable-2 b]);", + "}"); + + MT("quasi", + "[variable re][string-2 `fofdlakj${][variable x] [operator +] ([variable re][string-2 `foo`]) [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); + + MT("quasi_no_function", + "[variable x] [operator =] [string-2 `fofdlakj${][variable x] [operator +] [string-2 `foo`] [operator +] [number 1][string-2 }fdsa`] [operator +] [number 2]"); + + MT("indent_statement", + "[keyword var] [def x] [operator =] [number 10]", + "[variable x] [operator +=] [variable y] [operator +]", + " [atom Infinity]", + "[keyword debugger];"); + + MT("indent_if", + "[keyword if] ([number 1])", + " [keyword break];", + "[keyword else] [keyword if] ([number 2])", + " [keyword continue];", + "[keyword else]", + " [number 10];", + "[keyword if] ([number 1]) {", + " [keyword break];", + "} [keyword else] [keyword if] ([number 2]) {", + " [keyword continue];", + "} [keyword else] {", + " [number 10];", + "}"); + + MT("indent_for", + "[keyword for] ([keyword var] [def i] [operator =] [number 0];", + " [variable i] [operator <] [number 100];", + " [variable i][operator ++])", + " [variable doSomething]([variable i]);", + "[keyword debugger];"); + + MT("indent_c_style", + "[keyword function] [def foo]()", + "{", + " [keyword debugger];", + "}"); + + MT("indent_else", + "[keyword for] (;;)", + " [keyword if] ([variable foo])", + " [keyword if] ([variable bar])", + " [number 1];", + " [keyword else]", + " [number 2];", + " [keyword else]", + " [number 3];"); + + MT("indent_funarg", + "[variable foo]([number 10000],", + " [keyword function]([def a]) {", + " [keyword debugger];", + "};"); + + MT("indent_below_if", + "[keyword for] (;;)", + " [keyword if] ([variable foo])", + " [number 1];", + "[number 2];"); + + MT("indent_semicolonless_if", + "[keyword function] [def foo]() {", + " [keyword if] ([variable x])", + " [variable foo]()", + "}") + + MT("indent_semicolonless_if_with_statement", + "[keyword function] [def foo]() {", + " [keyword if] ([variable x])", + " [variable foo]()", + " [variable bar]()", + "}") + + MT("multilinestring", + "[keyword var] [def x] [operator =] [string 'foo\\]", + "[string bar'];"); + + MT("scary_regexp", + "[string-2 /foo[[/]]bar/];"); + + MT("indent_strange_array", + "[keyword var] [def x] [operator =] [[", + " [number 1],,", + " [number 2],", + "]];", + "[number 10];"); + + MT("param_default", + "[keyword function] [def foo]([def x] [operator =] [string-2 `foo${][number 10][string-2 }bar`]) {", + " [keyword return] [variable-2 x];", + "}"); + + MT("new_target", + "[keyword function] [def F]([def target]) {", + " [keyword if] ([variable-2 target] [operator &&] [keyword new].[keyword target].[property name]) {", + " [keyword return] [keyword new]", + " .[keyword target];", + " }", + "}"); + + var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript") + function TS(name) { + test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1)) + } + + TS("extend_type", + "[keyword class] [def Foo] [keyword extends] [variable-3 Some][operator <][variable-3 Type][operator >] {}") + + TS("arrow_type", + "[keyword let] [def x]: ([variable arg]: [variable-3 Type]) [operator =>] [variable-3 ReturnType]") + + TS("typescript_class", + "[keyword class] [def Foo] {", + " [keyword public] [keyword static] [property main]() {}", + " [keyword private] [property _foo]: [variable-3 string];", + "}") + + var jsonld_mode = CodeMirror.getMode( + {indentUnit: 2}, + {name: "javascript", jsonld: true} + ); + function LD(name) { + test.mode(name, jsonld_mode, Array.prototype.slice.call(arguments, 1)); + } + + LD("json_ld_keywords", + '{', + ' [meta "@context"]: {', + ' [meta "@base"]: [string "http://example.com"],', + ' [meta "@vocab"]: [string "http://xmlns.com/foaf/0.1/"],', + ' [property "likesFlavor"]: {', + ' [meta "@container"]: [meta "@list"]', + ' [meta "@reverse"]: [string "@beFavoriteOf"]', + ' },', + ' [property "nick"]: { [meta "@container"]: [meta "@set"] },', + ' [property "nick"]: { [meta "@container"]: [meta "@index"] }', + ' },', + ' [meta "@graph"]: [[ {', + ' [meta "@id"]: [string "http://dbpedia.org/resource/John_Lennon"],', + ' [property "name"]: [string "John Lennon"],', + ' [property "modified"]: {', + ' [meta "@value"]: [string "2010-05-29T14:17:39+02:00"],', + ' [meta "@type"]: [string "http://www.w3.org/2001/XMLSchema#dateTime"]', + ' }', + ' } ]]', + '}'); + + LD("json_ld_fake", + '{', + ' [property "@fake"]: [string "@fake"],', + ' [property "@contextual"]: [string "@identifier"],', + ' [property "user@domain.com"]: [string "@graphical"],', + ' [property "@ID"]: [string "@@ID"]', + '}'); +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/typescript.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/typescript.html new file mode 100644 index 0000000..1f26d7f --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/javascript/typescript.html @@ -0,0 +1,61 @@ + + +CodeMirror: TypeScript mode + + + + + + + + + +
      +

      TypeScript mode

      + + +
      + + + +

      This is a specialization of the JavaScript mode.

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/index.html b/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/index.html new file mode 100644 index 0000000..adf6b1b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/index.html @@ -0,0 +1,64 @@ + + +CodeMirror: PHP mode + + + + + + + + + + + + + + + +
      +

      PHP mode

      +
      + + + +

      Simple HTML/PHP mode based on + the C-like mode. Depends on XML, + JavaScript, CSS, HTMLMixed, and C-like modes.

      + +

      MIME types defined: application/x-httpd-php (HTML with PHP code), text/x-php (plain, non-wrapped PHP code).

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/php.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/php.js new file mode 100644 index 0000000..57ba812 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/php.js @@ -0,0 +1,234 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../clike/clike"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // Helper for phpString + function matchSequence(list, end, escapes) { + if (list.length == 0) return phpString(end); + return function (stream, state) { + var patterns = list[0]; + for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) { + state.tokenize = matchSequence(list.slice(1), end); + return patterns[i][1]; + } + state.tokenize = phpString(end, escapes); + return "string"; + }; + } + function phpString(closing, escapes) { + return function(stream, state) { return phpString_(stream, state, closing, escapes); }; + } + function phpString_(stream, state, closing, escapes) { + // "Complex" syntax + if (escapes !== false && stream.match("${", false) || stream.match("{$", false)) { + state.tokenize = null; + return "string"; + } + + // Simple syntax + if (escapes !== false && stream.match(/^\$[a-zA-Z_][a-zA-Z0-9_]*/)) { + // After the variable name there may appear array or object operator. + if (stream.match("[", false)) { + // Match array operator + state.tokenize = matchSequence([ + [["[", null]], + [[/\d[\w\.]*/, "number"], + [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"], + [/[\w\$]+/, "variable"]], + [["]", null]] + ], closing, escapes); + } + if (stream.match(/\-\>\w/, false)) { + // Match object operator + state.tokenize = matchSequence([ + [["->", null]], + [[/[\w]+/, "variable"]] + ], closing, escapes); + } + return "variable-2"; + } + + var escaped = false; + // Normal string + while (!stream.eol() && + (escaped || escapes === false || + (!stream.match("{$", false) && + !stream.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/, false)))) { + if (!escaped && stream.match(closing)) { + state.tokenize = null; + state.tokStack.pop(); state.tokStack.pop(); + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + var phpKeywords = "abstract and array as break case catch class clone const continue declare default " + + "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " + + "for foreach function global goto if implements interface instanceof namespace " + + "new or private protected public static switch throw trait try use var while xor " + + "die echo empty exit eval include include_once isset list require require_once return " + + "print unset __halt_compiler self static parent yield insteadof finally"; + var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"; + var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists array_intersect_key array_combine array_column pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count"; + CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" ")); + CodeMirror.registerHelper("wordChars", "php", /[\w$]/); + + var phpConfig = { + name: "clike", + helperType: "php", + keywords: keywords(phpKeywords), + blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"), + defKeywords: keywords("class function interface namespace trait"), + atoms: keywords(phpAtoms), + builtin: keywords(phpBuiltin), + multiLineStrings: true, + hooks: { + "$": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "variable-2"; + }, + "<": function(stream, state) { + var before; + if (before = stream.match(/<<\s*/)) { + var quoted = stream.eat(/['"]/); + stream.eatWhile(/[\w\.]/); + var delim = stream.current().slice(before[0].length + (quoted ? 2 : 1)); + if (quoted) stream.eat(quoted); + if (delim) { + (state.tokStack || (state.tokStack = [])).push(delim, 0); + state.tokenize = phpString(delim, quoted != "'"); + return "string"; + } + } + return false; + }, + "#": function(stream) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + }, + "/": function(stream) { + if (stream.eat("/")) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + } + return false; + }, + '"': function(_stream, state) { + (state.tokStack || (state.tokStack = [])).push('"', 0); + state.tokenize = phpString('"'); + return "string"; + }, + "{": function(_stream, state) { + if (state.tokStack && state.tokStack.length) + state.tokStack[state.tokStack.length - 1]++; + return false; + }, + "}": function(_stream, state) { + if (state.tokStack && state.tokStack.length > 0 && + !--state.tokStack[state.tokStack.length - 1]) { + state.tokenize = phpString(state.tokStack[state.tokStack.length - 2]); + } + return false; + } + } + }; + + CodeMirror.defineMode("php", function(config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, "text/html"); + var phpMode = CodeMirror.getMode(config, phpConfig); + + function dispatch(stream, state) { + var isPHP = state.curMode == phpMode; + if (stream.sol() && state.pending && state.pending != '"' && state.pending != "'") state.pending = null; + if (!isPHP) { + if (stream.match(/^<\?\w*/)) { + state.curMode = phpMode; + if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, "")) + state.curState = state.php; + return "meta"; + } + if (state.pending == '"' || state.pending == "'") { + while (!stream.eol() && stream.next() != state.pending) {} + var style = "string"; + } else if (state.pending && stream.pos < state.pending.end) { + stream.pos = state.pending.end; + var style = state.pending.style; + } else { + var style = htmlMode.token(stream, state.curState); + } + if (state.pending) state.pending = null; + var cur = stream.current(), openPHP = cur.search(/<\?/), m; + if (openPHP != -1) { + if (style == "string" && (m = cur.match(/[\'\"]$/)) && !/\?>/.test(cur)) state.pending = m[0]; + else state.pending = {end: stream.pos, style: style}; + stream.backUp(cur.length - openPHP); + } + return style; + } else if (isPHP && state.php.tokenize == null && stream.match("?>")) { + state.curMode = htmlMode; + state.curState = state.html; + if (!state.php.context.prev) state.php = null; + return "meta"; + } else { + return phpMode.token(stream, state.curState); + } + } + + return { + startState: function() { + var html = CodeMirror.startState(htmlMode) + var php = parserConfig.startOpen ? CodeMirror.startState(phpMode) : null + return {html: html, + php: php, + curMode: parserConfig.startOpen ? phpMode : htmlMode, + curState: parserConfig.startOpen ? php : html, + pending: null}; + }, + + copyState: function(state) { + var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html), + php = state.php, phpNew = php && CodeMirror.copyState(phpMode, php), cur; + if (state.curMode == htmlMode) cur = htmlNew; + else cur = phpNew; + return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, + pending: state.pending}; + }, + + token: dispatch, + + indent: function(state, textAfter) { + if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) || + (state.curMode == phpMode && /^\?>/.test(textAfter))) + return htmlMode.indent(state.html, textAfter); + return state.curMode.indent(state.curState, textAfter); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + + innerMode: function(state) { return {state: state.curState, mode: state.curMode}; } + }; + }, "htmlmixed", "clike"); + + CodeMirror.defineMIME("application/x-httpd-php", "php"); + CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true}); + CodeMirror.defineMIME("text/x-php", phpConfig); +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/test.js new file mode 100644 index 0000000..e2ecefc --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/php/test.js @@ -0,0 +1,154 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "php"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT('simple_test', + '[meta ]'); + + MT('variable_interpolation_non_alphanumeric', + '[meta $/$\\$}$\\\"$:$;$?$|$[[$]]$+$=aaa"]', + '[meta ?>]'); + + MT('variable_interpolation_digits', + '[meta ]'); + + MT('variable_interpolation_simple_syntax_1', + '[meta ]'); + + MT('variable_interpolation_simple_syntax_2', + '[meta ]'); + + MT('variable_interpolation_simple_syntax_3', + '[meta [variable aaaaa][string .aaaaaa"];', + '[keyword echo] [string "aaa][variable-2 $aaaa][string ->][variable-2 $aaaaa][string .aaaaaa"];', + '[keyword echo] [string "aaa][variable-2 $aaaa]->[variable aaaaa][string [[2]].aaaaaa"];', + '[keyword echo] [string "aaa][variable-2 $aaaa]->[variable aaaaa][string ->aaaa2.aaaaaa"];', + '[meta ?>]'); + + MT('variable_interpolation_escaping', + '[meta aaa.aaa"];', + '[keyword echo] [string "aaa\\$aaaa[[2]]aaa.aaa"];', + '[keyword echo] [string "aaa\\$aaaa[[asd]]aaa.aaa"];', + '[keyword echo] [string "aaa{\\$aaaa->aaa.aaa"];', + '[keyword echo] [string "aaa{\\$aaaa[[2]]aaa.aaa"];', + '[keyword echo] [string "aaa{\\aaaaa[[asd]]aaa.aaa"];', + '[keyword echo] [string "aaa\\${aaaa->aaa.aaa"];', + '[keyword echo] [string "aaa\\${aaaa[[2]]aaa.aaa"];', + '[keyword echo] [string "aaa\\${aaaa[[asd]]aaa.aaa"];', + '[meta ?>]'); + + MT('variable_interpolation_complex_syntax_1', + '[meta aaa.aaa"];', + '[keyword echo] [string "aaa][variable-2 $]{[variable-2 $aaaa]}[string ->aaa.aaa"];', + '[keyword echo] [string "aaa][variable-2 $]{[variable-2 $aaaa][[',' [number 42]',']]}[string ->aaa.aaa"];', + '[keyword echo] [string "aaa][variable-2 $]{[variable aaaa][meta ?>]aaaaaa'); + + MT('variable_interpolation_complex_syntax_2', + '[meta } $aaaaaa.aaa"];', + '[keyword echo] [string "][variable-2 $]{[variable aaa][comment /*}?>*/][[',' [string "aaa][variable-2 $aaa][string {}][variable-2 $]{[variable aaa]}[string "]',']]}[string ->aaa.aaa"];', + '[keyword echo] [string "][variable-2 $]{[variable aaa][comment /*} } $aaa } */]}[string ->aaa.aaa"];'); + + + function build_recursive_monsters(nt, t, n){ + var monsters = [t]; + for (var i = 1; i <= n; ++i) + monsters[i] = nt.join(monsters[i - 1]); + return monsters; + } + + var m1 = build_recursive_monsters( + ['[string "][variable-2 $]{[variable aaa] [operator +] ', '}[string "]'], + '[comment /* }?>} */] [string "aaa][variable-2 $aaa][string .aaa"]', + 10 + ); + + MT('variable_interpolation_complex_syntax_3_1', + '[meta ]'); + + var m2 = build_recursive_monsters( + ['[string "a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', '}[string .a"]'], + '[comment /* }?>{{ */] [string "a?>}{{aa][variable-2 $aaa][string .a}a?>a"]', + 5 + ); + + MT('variable_interpolation_complex_syntax_3_2', + '[meta ]'); + + function build_recursive_monsters_2(mf1, mf2, nt, t, n){ + var monsters = [t]; + for (var i = 1; i <= n; ++i) + monsters[i] = nt[0] + mf1[i - 1] + nt[1] + mf2[i - 1] + nt[2] + monsters[i - 1] + nt[3]; + return monsters; + } + + var m3 = build_recursive_monsters_2( + m1, + m2, + ['[string "a][variable-2 $]{[variable aaa] [operator +] ', ' [operator +] ', ' [operator +] ', '}[string .a"]'], + '[comment /* }?>{{ */] [string "a?>}{{aa][variable-2 $aaa][string .a}a?>a"]', + 4 + ); + + MT('variable_interpolation_complex_syntax_3_3', + '[meta ]'); + + MT("variable_interpolation_heredoc", + "[meta + +CodeMirror: XML mode + + + + + + + + + +
      +

      XML mode

      +
      + +

      The XML mode supports these configuration parameters:

      +
      +
      htmlMode (boolean)
      +
      This switches the mode to parse HTML instead of XML. This + means attributes do not have to be quoted, and some elements + (such as br) do not require a closing tag.
      +
      matchClosing (boolean)
      +
      Controls whether the mode checks that close tags match the + corresponding opening tag, and highlights mismatches as errors. + Defaults to true.
      +
      alignCDATA (boolean)
      +
      Setting this to true will force the opening tag of CDATA + blocks to not be indented.
      +
      + +

      MIME types defined: application/xml, text/html.

      +
      diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/xml/test.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/xml/test.js new file mode 100644 index 0000000..f48156b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/xml/test.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); } + + MT("matching", + "[tag&bracket <][tag top][tag&bracket >]", + " text", + " [tag&bracket <][tag inner][tag&bracket />]", + "[tag&bracket ]"); + + MT("nonmatching", + "[tag&bracket <][tag top][tag&bracket >]", + " [tag&bracket <][tag inner][tag&bracket />]", + " [tag&bracket ]"); + + MT("doctype", + "[meta ]", + "[tag&bracket <][tag top][tag&bracket />]"); + + MT("cdata", + "[tag&bracket <][tag top][tag&bracket >]", + " [atom ]", + "[tag&bracket ]"); + + // HTML tests + mode = CodeMirror.getMode({indentUnit: 2}, "text/html"); + + MT("selfclose", + "[tag&bracket <][tag html][tag&bracket >]", + " [tag&bracket <][tag link] [attribute rel]=[string stylesheet] [attribute href]=[string \"/foobar\"][tag&bracket >]", + "[tag&bracket ]"); + + MT("list", + "[tag&bracket <][tag ol][tag&bracket >]", + " [tag&bracket <][tag li][tag&bracket >]one", + " [tag&bracket <][tag li][tag&bracket >]two", + "[tag&bracket ]"); + + MT("valueless", + "[tag&bracket <][tag input] [attribute type]=[string checkbox] [attribute checked][tag&bracket />]"); + + MT("pThenArticle", + "[tag&bracket <][tag p][tag&bracket >]", + " foo", + "[tag&bracket <][tag article][tag&bracket >]bar"); + +})(); diff --git a/lib/redactor/ckeditor/plugins/codemirror/js/mode/xml/xml.js b/lib/redactor/ckeditor/plugins/codemirror/js/mode/xml/xml.js new file mode 100644 index 0000000..f987a3a --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/js/mode/xml/xml.js @@ -0,0 +1,394 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +var htmlConfig = { + autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, + 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, + 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, + 'track': true, 'wbr': true, 'menuitem': true}, + implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, + 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, + 'th': true, 'tr': true}, + contextGrabbers: { + 'dd': {'dd': true, 'dt': true}, + 'dt': {'dd': true, 'dt': true}, + 'li': {'li': true}, + 'option': {'option': true, 'optgroup': true}, + 'optgroup': {'optgroup': true}, + 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, + 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, + 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, + 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, + 'rp': {'rp': true, 'rt': true}, + 'rt': {'rp': true, 'rt': true}, + 'tbody': {'tbody': true, 'tfoot': true}, + 'td': {'td': true, 'th': true}, + 'tfoot': {'tbody': true}, + 'th': {'td': true, 'th': true}, + 'thead': {'tbody': true, 'tfoot': true}, + 'tr': {'tr': true} + }, + doNotIndent: {"pre": true}, + allowUnquoted: true, + allowMissing: true, + caseFold: true +} + +var xmlConfig = { + autoSelfClosers: {}, + implicitlyClosed: {}, + contextGrabbers: {}, + doNotIndent: {}, + allowUnquoted: false, + allowMissing: false, + caseFold: false +} + +CodeMirror.defineMode("xml", function(editorConf, config_) { + var indentUnit = editorConf.indentUnit + var config = {} + var defaults = config_.htmlMode ? htmlConfig : xmlConfig + for (var prop in defaults) config[prop] = defaults[prop] + for (var prop in config_) config[prop] = config_[prop] + + // Return variables for tokenizers + var type, setStyle; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); + else return null; + } else if (stream.match("--")) { + return chain(inBlock("comment", "-->")); + } else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } else { + return null; + } + } else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } else { + type = stream.eat("/") ? "closeTag" : "openTag"; + state.tokenize = inTag; + return "tag bracket"; + } + } else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } else { + stream.eatWhile(/[^&<]/); + return null; + } + } + inText.isInText = true; + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag bracket"; + } else if (ch == "=") { + type = "equals"; + return null; + } else if (ch == "<") { + state.tokenize = inText; + state.state = baseState; + state.tagName = state.tagStart = null; + var next = state.tokenize(stream, state); + return next ? next + " tag error" : "tag error"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + state.stringStartCol = stream.column(); + return state.tokenize(stream, state); + } else { + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); + return "word"; + } + } + + function inAttribute(quote) { + var closure = function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + closure.isInAttribute = true; + return closure; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + }; + } + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + function Context(state, tagName, startOfLine) { + this.prev = state.context; + this.tagName = tagName; + this.indent = state.indented; + this.startOfLine = startOfLine; + if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) + this.noIndent = true; + } + function popContext(state) { + if (state.context) state.context = state.context.prev; + } + function maybePopContext(state, nextTagName) { + var parentTagName; + while (true) { + if (!state.context) { + return; + } + parentTagName = state.context.tagName; + if (!config.contextGrabbers.hasOwnProperty(parentTagName) || + !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(state); + } + } + + function baseState(type, stream, state) { + if (type == "openTag") { + state.tagStart = stream.column(); + return tagNameState; + } else if (type == "closeTag") { + return closeTagNameState; + } else { + return baseState; + } + } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + config.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { + setStyle = "tag"; + return closeState; + } else { + setStyle = "tag error"; + return closeStateErr; + } + } else { + setStyle = "error"; + return closeStateErr; + } + } + + function closeState(type, _stream, state) { + if (type != "endTag") { + setStyle = "error"; + return closeState; + } + popContext(state); + return baseState; + } + function closeStateErr(type, stream, state) { + setStyle = "error"; + return closeState(type, stream, state); + } + + function attrState(type, _stream, state) { + if (type == "word") { + setStyle = "attribute"; + return attrEqState; + } else if (type == "endTag" || type == "selfcloseTag") { + var tagName = state.tagName, tagStart = state.tagStart; + state.tagName = state.tagStart = null; + if (type == "selfcloseTag" || + config.autoSelfClosers.hasOwnProperty(tagName)) { + maybePopContext(state, tagName); + } else { + maybePopContext(state, tagName); + state.context = new Context(state, tagName, tagStart == state.indented); + } + return baseState; + } + setStyle = "error"; + return attrState; + } + function attrEqState(type, stream, state) { + if (type == "equals") return attrValueState; + if (!config.allowMissing) setStyle = "error"; + return attrState(type, stream, state); + } + function attrValueState(type, stream, state) { + if (type == "string") return attrContinuedState; + if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;} + setStyle = "error"; + return attrState(type, stream, state); + } + function attrContinuedState(type, stream, state) { + if (type == "string") return attrContinuedState; + return attrState(type, stream, state); + } + + return { + startState: function(baseIndent) { + var state = {tokenize: inText, + state: baseState, + indented: baseIndent || 0, + tagName: null, tagStart: null, + context: null} + if (baseIndent != null) state.baseIndent = baseIndent + return state + }, + + token: function(stream, state) { + if (!state.tagName && stream.sol()) + state.indented = stream.indentation(); + + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + setStyle = null; + state.state = state.state(type || style, stream, state); + if (setStyle) + style = setStyle == "error" ? style + " error" : setStyle; + } + return style; + }, + + indent: function(state, textAfter, fullLine) { + var context = state.context; + // Indent multi-line strings (e.g. css). + if (state.tokenize.isInAttribute) { + if (state.tagStart == state.indented) + return state.stringStartCol + 1; + else + return state.indented + indentUnit; + } + if (context && context.noIndent) return CodeMirror.Pass; + if (state.tokenize != inTag && state.tokenize != inText) + return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + // Indent the starts of attribute names. + if (state.tagName) { + if (config.multilineTagIndentPastTag !== false) + return state.tagStart + state.tagName.length + 2; + else + return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1); + } + if (config.alignCDATA && /$/, + blockCommentStart: "", + + configuration: config.htmlMode ? "html" : "xml", + helperType: config.htmlMode ? "html" : "xml", + + skipAttribute: function(state) { + if (state.state == attrValueState) + state.state = attrState + } + }; +}); + +CodeMirror.defineMIME("text/xml", "xml"); +CodeMirror.defineMIME("application/xml", "xml"); +if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) + CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); + +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/af.js b/lib/redactor/ckeditor/plugins/codemirror/lang/af.js new file mode 100644 index 0000000..eaa53d5 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/af.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'af', { + toolbar: 'Bron', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ar.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ar.js new file mode 100644 index 0000000..5fab258 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ar.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ar', { + toolbar: 'المصدر', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/bg.js b/lib/redactor/ckeditor/plugins/codemirror/lang/bg.js new file mode 100644 index 0000000..59f8c73 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/bg.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'bg', { + toolbar: 'Източник', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/bn.js b/lib/redactor/ckeditor/plugins/codemirror/lang/bn.js new file mode 100644 index 0000000..bae9090 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/bn.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'bn', { + toolbar: 'সোর্স', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/bs.js b/lib/redactor/ckeditor/plugins/codemirror/lang/bs.js new file mode 100644 index 0000000..2fa1d2b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/bs.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'bs', { + toolbar: 'HTML kôd', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ca.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ca.js new file mode 100644 index 0000000..30520f6 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ca.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ca', { + toolbar: 'Codi font', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/cs.js b/lib/redactor/ckeditor/plugins/codemirror/lang/cs.js new file mode 100644 index 0000000..7ed08f6 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/cs.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'cs', { + toolbar: 'Zdroj', + searchCode: 'Prohledat zdroj', + autoFormat: 'Formátovat výběr', + commentSelectedRange: 'Zakomentovat výběr', + uncommentSelectedRange: 'Odkomentovat výběr', + autoCompleteToggle: 'Povolit/zakázat automatické doplňování HTML tagů' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/cy.js b/lib/redactor/ckeditor/plugins/codemirror/lang/cy.js new file mode 100644 index 0000000..736103f --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/cy.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'cy', { + toolbar: 'HTML', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/da.js b/lib/redactor/ckeditor/plugins/codemirror/lang/da.js new file mode 100644 index 0000000..93b8009 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/da.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'da', { + toolbar: 'Kilde', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/de.js b/lib/redactor/ckeditor/plugins/codemirror/lang/de.js new file mode 100644 index 0000000..580eef1 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/de.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'de', { + toolbar: 'Quellcode', + searchCode: 'Quellcode durchsuchen', + autoFormat: 'Auswahl formatieren', + commentSelectedRange: 'Auswahl auskommentieren', + uncommentSelectedRange: 'Auskommentierung entfernen', + autoCompleteToggle: 'HTML Tag Autovervollständigen de-/aktivieren' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/el.js b/lib/redactor/ckeditor/plugins/codemirror/lang/el.js new file mode 100644 index 0000000..1daadb2 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/el.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'el', { + toolbar: 'HTML κώδικας', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/en-au.js b/lib/redactor/ckeditor/plugins/codemirror/lang/en-au.js new file mode 100644 index 0000000..dd7a22b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/en-au.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'en-au', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/en-ca.js b/lib/redactor/ckeditor/plugins/codemirror/lang/en-ca.js new file mode 100644 index 0000000..712d203 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/en-ca.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'en-ca', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/en-gb.js b/lib/redactor/ckeditor/plugins/codemirror/lang/en-gb.js new file mode 100644 index 0000000..fcc7c04 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/en-gb.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'en-gb', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/en.js b/lib/redactor/ckeditor/plugins/codemirror/lang/en.js new file mode 100644 index 0000000..4229820 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/en.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'en', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/eo.js b/lib/redactor/ckeditor/plugins/codemirror/lang/eo.js new file mode 100644 index 0000000..270cdb8 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/eo.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'eo', { + toolbar: 'Fonto', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/es.js b/lib/redactor/ckeditor/plugins/codemirror/lang/es.js new file mode 100644 index 0000000..9f6e769 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/es.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'es', { + toolbar: 'Fuente HTML', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/et.js b/lib/redactor/ckeditor/plugins/codemirror/lang/et.js new file mode 100644 index 0000000..666ef49 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/et.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'et', { + toolbar: 'Lähtekood', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/eu.js b/lib/redactor/ckeditor/plugins/codemirror/lang/eu.js new file mode 100644 index 0000000..4c6a701 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/eu.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'eu', { + toolbar: 'HTML Iturburua', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/fa.js b/lib/redactor/ckeditor/plugins/codemirror/lang/fa.js new file mode 100644 index 0000000..c4b7f68 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/fa.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'fa', { + toolbar: 'منبع', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/fi.js b/lib/redactor/ckeditor/plugins/codemirror/lang/fi.js new file mode 100644 index 0000000..874ce33 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/fi.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'fi', { + toolbar: 'Koodi', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/fo.js b/lib/redactor/ckeditor/plugins/codemirror/lang/fo.js new file mode 100644 index 0000000..292ce20 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/fo.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'fo', { + toolbar: 'Kelda', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/fr-ca.js b/lib/redactor/ckeditor/plugins/codemirror/lang/fr-ca.js new file mode 100644 index 0000000..7984540 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/fr-ca.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'fr-ca', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/fr.js b/lib/redactor/ckeditor/plugins/codemirror/lang/fr.js new file mode 100644 index 0000000..6eaff56 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/fr.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'fr', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/gl.js b/lib/redactor/ckeditor/plugins/codemirror/lang/gl.js new file mode 100644 index 0000000..31d1d43 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/gl.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'gl', { + toolbar: 'Código Fonte', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/gu.js b/lib/redactor/ckeditor/plugins/codemirror/lang/gu.js new file mode 100644 index 0000000..2729565 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/gu.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'gu', { + toolbar: 'મૂળ કે પ્રાથમિક દસ્તાવેજ', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/he.js b/lib/redactor/ckeditor/plugins/codemirror/lang/he.js new file mode 100644 index 0000000..ecfc545 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/he.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'he', { + toolbar: 'מקור', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/hi.js b/lib/redactor/ckeditor/plugins/codemirror/lang/hi.js new file mode 100644 index 0000000..40f673a --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/hi.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'hi', { + toolbar: 'सोर्स', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/hr.js b/lib/redactor/ckeditor/plugins/codemirror/lang/hr.js new file mode 100644 index 0000000..0c1a43e --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/hr.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'hr', { + toolbar: 'Kôd', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/hu.js b/lib/redactor/ckeditor/plugins/codemirror/lang/hu.js new file mode 100644 index 0000000..0ee5359 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/hu.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'hu', { + toolbar: 'Forráskód', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/is.js b/lib/redactor/ckeditor/plugins/codemirror/lang/is.js new file mode 100644 index 0000000..56e7144 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/is.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'is', { + toolbar: 'Kóði', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/it.js b/lib/redactor/ckeditor/plugins/codemirror/lang/it.js new file mode 100644 index 0000000..c5fc213 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/it.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'it', { + toolbar: 'Codice Sorgente', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ja.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ja.js new file mode 100644 index 0000000..3e34ccf --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ja.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ja', { + toolbar: 'ソース', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ka.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ka.js new file mode 100644 index 0000000..f17c091 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ka.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ka', { + toolbar: 'კოდები', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/km.js b/lib/redactor/ckeditor/plugins/codemirror/lang/km.js new file mode 100644 index 0000000..60049c9 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/km.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'km', { + toolbar: 'កូត', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ko.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ko.js new file mode 100644 index 0000000..13e4e26 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ko.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ko', { + toolbar: '소스', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ku.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ku.js new file mode 100644 index 0000000..d408024 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ku.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ku', { + toolbar: 'سەرچاوە', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/lt.js b/lib/redactor/ckeditor/plugins/codemirror/lang/lt.js new file mode 100644 index 0000000..de8b1ec --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/lt.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'lt', { + toolbar: 'Šaltinis', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/lv.js b/lib/redactor/ckeditor/plugins/codemirror/lang/lv.js new file mode 100644 index 0000000..749ca1b --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/lv.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'lv', { + toolbar: 'HTML kods', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/mk.js b/lib/redactor/ckeditor/plugins/codemirror/lang/mk.js new file mode 100644 index 0000000..eb1a29e --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/mk.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'mk', { + toolbar: 'Source', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/mn.js b/lib/redactor/ckeditor/plugins/codemirror/lang/mn.js new file mode 100644 index 0000000..f701217 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/mn.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'mn', { + toolbar: 'Код', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ms.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ms.js new file mode 100644 index 0000000..f61e948 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ms.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ms', { + toolbar: 'Sumber', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/nb.js b/lib/redactor/ckeditor/plugins/codemirror/lang/nb.js new file mode 100644 index 0000000..4deda75 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/nb.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'nb', { + toolbar: 'Kilde', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/nl.js b/lib/redactor/ckeditor/plugins/codemirror/lang/nl.js new file mode 100644 index 0000000..a52df7a --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/nl.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'nl', { + toolbar: 'Broncode', + searchCode: 'Zoek in broncode', + autoFormat: 'Formatteer selectie', + commentSelectedRange: 'Zet selectie in commentaar', + uncommentSelectedRange: 'Haal selectie uit commentaar', + autoCompleteToggle: 'Zet automatisch aanvullen van HTML tags aan/uit' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/no.js b/lib/redactor/ckeditor/plugins/codemirror/lang/no.js new file mode 100644 index 0000000..2e21f28 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/no.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'no', { + toolbar: 'Kilde', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/pl.js b/lib/redactor/ckeditor/plugins/codemirror/lang/pl.js new file mode 100644 index 0000000..d8b0140 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/pl.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'pl', { + toolbar: 'Źródło dokumentu', + autoFormat: 'Sformatuj zaznaczenie', + commentSelectedRange: 'Zakomentuj zaznaczenie', + uncommentSelectedRange: 'Odkomentuj zaznaczenie', + searchCode: 'Wyszukaj w źródle', + autoCompleteToggle: 'Włącza/Wyłącza automatyczne uzupełniania tagów HTML' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/pt-br.js b/lib/redactor/ckeditor/plugins/codemirror/lang/pt-br.js new file mode 100644 index 0000000..d8248a3 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/pt-br.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'pt-br', { + toolbar: 'Código-Fonte', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/pt.js b/lib/redactor/ckeditor/plugins/codemirror/lang/pt.js new file mode 100644 index 0000000..b0e074e --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/pt.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'pt', { + toolbar: 'Fonte', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ro.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ro.js new file mode 100644 index 0000000..ffd6cf3 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ro.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ro', { + toolbar: 'Sursa', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ru.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ru.js new file mode 100644 index 0000000..e7e7b1c --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ru.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ru', { + toolbar: 'Источник', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/sk.js b/lib/redactor/ckeditor/plugins/codemirror/lang/sk.js new file mode 100644 index 0000000..956d011 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/sk.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'sk', { + toolbar: 'Zdroj', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/sl.js b/lib/redactor/ckeditor/plugins/codemirror/lang/sl.js new file mode 100644 index 0000000..b43a672 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/sl.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'sl', { + toolbar: 'Izvorna koda', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/sr-latn.js b/lib/redactor/ckeditor/plugins/codemirror/lang/sr-latn.js new file mode 100644 index 0000000..6b18327 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/sr-latn.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'sr-latn', { + toolbar: 'Kôd', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/sr.js b/lib/redactor/ckeditor/plugins/codemirror/lang/sr.js new file mode 100644 index 0000000..edb3080 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/sr.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'sr', { + toolbar: 'Kôд', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/sv.js b/lib/redactor/ckeditor/plugins/codemirror/lang/sv.js new file mode 100644 index 0000000..070227e --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/sv.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'sv', { + toolbar: 'Källa', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/th.js b/lib/redactor/ckeditor/plugins/codemirror/lang/th.js new file mode 100644 index 0000000..415afe4 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/th.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'th', { + toolbar: 'ดูรหัส HTML', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/tr.js b/lib/redactor/ckeditor/plugins/codemirror/lang/tr.js new file mode 100644 index 0000000..06f708f --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/tr.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'tr', { + toolbar: 'Kaynak', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/ug.js b/lib/redactor/ckeditor/plugins/codemirror/lang/ug.js new file mode 100644 index 0000000..e6597bb --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/ug.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'ug', { + toolbar: 'مەنبە', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/uk.js b/lib/redactor/ckeditor/plugins/codemirror/lang/uk.js new file mode 100644 index 0000000..4781847 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/uk.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'uk', { + toolbar: 'Джерело', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/vi.js b/lib/redactor/ckeditor/plugins/codemirror/lang/vi.js new file mode 100644 index 0000000..1370624 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/vi.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'vi', { + toolbar: 'Mã HTML', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/zh-cn.js b/lib/redactor/ckeditor/plugins/codemirror/lang/zh-cn.js new file mode 100644 index 0000000..bbc1626 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/zh-cn.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'zh-cn', { + toolbar: '源码', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/lang/zh.js b/lib/redactor/ckeditor/plugins/codemirror/lang/zh.js new file mode 100644 index 0000000..a5e81b1 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/lang/zh.js @@ -0,0 +1,12 @@ +/* +Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +CKEDITOR.plugins.setLang( 'codemirror', 'zh', { + toolbar: '原始碼', + searchCode: 'Search Source', + autoFormat: 'Format Selection', + commentSelectedRange: 'Comment Selection', + uncommentSelectedRange: 'Uncomment Selection', + autoCompleteToggle: 'Enable/Disable HTML Tag Autocomplete' +}); diff --git a/lib/redactor/ckeditor/plugins/codemirror/plugin.js b/lib/redactor/ckeditor/plugins/codemirror/plugin.js new file mode 100644 index 0000000..447553d --- /dev/null +++ b/lib/redactor/ckeditor/plugins/codemirror/plugin.js @@ -0,0 +1,1187 @@ +/* +* The "codemirror" plugin. It's indented to enhance the +* "sourcearea" editing mode, which displays the xhtml source code with +* syntax highlight and line numbers. +* Licensed under the MIT license +* CodeMirror Plugin: http://codemirror.net/ (MIT License) +*/ + +(function() { + CKEDITOR.plugins.add('codemirror', { + icons: 'searchcode,autoformat,commentselectedrange,uncommentselectedrange,autocomplete', // %REMOVE_LINE_CORE% + lang: 'af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en-au,en-ca,en-gb,en,eo,es,et,eu,fa,fi,fo,fr-ca,fr,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt-br,pt,ro,ru,sk,sl,sr-latn,sr,sv,th,tr,ug,uk,vi,zh-cn,zh', // %REMOVE_LINE_CORE% + version: 1.15, + init: function (editor) { + var rootPath = this.path, + defaultConfig = { + extraKeys: { + 'Ctrl-S': function () { + AveDocs.documentSaveFunction(); + }, + 'Cmd-S': function () { + AveDocs.documentSaveFunction(); + }, + }, + autoCloseBrackets: true, + autoCloseTags: true, + autoFormatOnStart: false, + autoFormatOnUncomment: true, + continueComments: true, + enableCodeFolding: true, + enableCodeFormatting: true, + enableSearchTools: true, + enterMode: 'keep', + highlightMatches: true, + indentUnit: 4, + indentWithTabs: true, + lineNumbers: true, + lineWrapping: true, + mode: 'htmlmixed', + matchBrackets: true, + matchTags: true, + showAutoCompleteButton: true, + showCommentButton: true, + showFormatButton: true, + showSearchButton: true, + showTrailingSpace: true, + showUncommentButton: true, + styleActiveLine: true, + tabMode: 'shift', + theme: 'default', + useBeautify: false + }; + + // Get Config & Lang + var config = CKEDITOR.tools.extend(defaultConfig, editor.config.codemirror || {}, true), + lang = editor.lang.codemirror; + + // check for old config settings for legacy support + if (editor.config.codemirror_theme) { + config.theme = editor.config.codemirror_theme; + } + if (editor.config.codemirror_autoFormatOnStart) { + config.autoFormatOnStart = editor.config.codemirror_autoFormatOnStart; + } + + // automatically switch to bbcode mode if bbcode plugin is enabled + if (editor.plugins.bbcode && config.mode.indexOf("bbcode") <= 0) { + config.mode = "bbcode"; + } + + // Source mode isn't available in inline mode yet. + if (editor.elementMode === CKEDITOR.ELEMENT_MODE_INLINE || editor.plugins.sourcedialog) { + + // Override Source Dialog + CKEDITOR.dialog.add('sourcedialog', function (editor) { + var size = CKEDITOR.document.getWindow().getViewPaneSize(), + width = Math.min(size.width - 70, 800), + height = size.height / 1.5, + oldData; + + function loadCodeMirrorInline(editor, textarea) { + window["codemirror_" + editor.id] = CodeMirror.fromTextArea(textarea, { + mode: config.mode, + matchBrackets: config.matchBrackets, + matchTags: config.matchTags, + workDelay: 300, + workTime: 35, + readOnly: editor.readOnly, + lineNumbers: config.lineNumbers, + lineWrapping: config.lineWrapping, + autoCloseTags: config.autoCloseTags, + autoCloseBrackets: config.autoCloseBrackets, + highlightSelectionMatches: config.highlightMatches, + continueComments: config.continueComments, + indentWithTabs: config.indentWithTabs, + theme: config.theme, + showTrailingSpace: config.showTrailingSpace, + showCursorWhenSelecting: true, + styleActiveLine: config.styleActiveLine, + viewportMargin: Infinity, + extraKeys: { + "Ctrl-Q": function (codeMirror_Editor) { + if (config.enableCodeFolding) { + window["foldFunc_" + editor.id](codeMirror_Editor, codeMirror_Editor.getCursor().line); + } + }, + 'Ctrl-S': function (codeMirror_Editor) { + AveDocs.documentSaveFunction(); + }, + 'Cmd-S': function (codeMirror_Editor) { + AveDocs.documentSaveFunction(); + }, + }, + foldGutter: true, + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] + }); + + var holderHeight = height + 'px'; + var holderWidth = width + 'px'; + + // Store config so we can access it within commands etc. + window["codemirror_" + editor.id].config = config; + + if (config.autoFormatOnStart) { + if (config.useBeautify) { + var indent_size = 4, + indent_char = ' ', + brace_style = 'collapse'; //collapse, expand, end-expand + + var source = window["codemirror_" + editor.id].getValue(); + + window["codemirror_" + editor.id].setValue(html_beautify(source, indent_size, indent_char, 120, brace_style)); + } else { + window["codemirror_" + editor.id].autoFormatAll({ + line: 0, + ch: 0 + }, { + line: window["codemirror_" + editor.id].lineCount(), + ch: 0 + }); + } + } + + function getSelectedRange() { + return { + from: window["codemirror_" + editor.id].getCursor(true), + to: window["codemirror_" + editor.id].getCursor(false) + }; + } + + window["codemirror_" + editor.id].on("change", function () { + window["codemirror_" + editor.id].save(); + editor.fire('change', this); + }); + + window["codemirror_" + editor.id].setSize(holderWidth, holderHeight); + + // Enable Code Folding (Requires 'lineNumbers' to be set to 'true') + if (config.lineNumbers && config.enableCodeFolding) { + window["codemirror_" + editor.id].on("gutterClick", window["foldFunc_" + editor.id]); + } + // Run config.onLoad callback, if present. + if (typeof config.onLoad === 'function') { + config.onLoad(window["codemirror_" + editor.id], editor); + } + + // inherit blur event + window["codemirror_" + editor.id].on("blur", function () { + editor.fire('blur', this); + }); + + window["codemirror_" + editor.id].on("keypress", function (codeMirror_Editor, evt) { + if (config.enableCodeFormatting) { + var range = getSelectedRange(); + if (evt.type === "keydown" && evt.ctrlKey && evt.keyCode === 75 && !evt.shiftKey && !evt.altKey) { + window["codemirror_" + editor.id].commentRange(true, range.from, range.to); + } else if (evt.type === "keydown" && evt.ctrlKey && evt.keyCode === 75 && evt.shiftKey && !evt.altKey) { + window["codemirror_" + editor.id].commentRange(false, range.from, range.to); + if (config.autoFormatOnUncomment) { + window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); + } + } else if (evt.type === "keydown" && evt.ctrlKey && evt.keyCode === 75 && !evt.shiftKey && evt.altKey) { + window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); + }/* else if (evt.type === "keydown") { + CodeMirror.commands.newlineAndIndentContinueMarkdownList(window["codemirror_" + editor.id]); + }*/ + } + }); + } + + + return { + title: editor.lang.sourcedialog.title, + minWidth: width, + minHeight: height, + resizable : CKEDITOR.DIALOG_RESIZE_NONE, + onShow: function () { + // Set Elements + this.getContentElement('main', 'data').focus(); + this.getContentElement('main', 'AutoComplete').setValue(config.autoCloseTags, true); + + var textArea = this.getContentElement('main', 'data').getInputElement().$; + + // Load the content + this.setValueOf('main', 'data', oldData = editor.getData()); + + if (!IsStyleSheetAlreadyLoaded(rootPath + 'css/codemirror.min.css')) { + CKEDITOR.document.appendStyleSheet(rootPath + 'css/codemirror.min.css'); + } + + if (config.theme.length && config.theme != 'default' && !IsStyleSheetAlreadyLoaded(rootPath + 'theme/' + config.theme + '.css')) { + CKEDITOR.document.appendStyleSheet(rootPath + 'theme/' + config.theme + '.css'); + } + + if (typeof (CodeMirror) == 'undefined') { + + CKEDITOR.scriptLoader.load(rootPath + 'js/codemirror.js', function() { + + CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { + loadCodeMirrorInline(editor, textArea); + }); + }); + + + } else { + //loadCodeMirrorInline(editor, textArea); + if (CodeMirror.prototype['autoFormatAll']) { + loadCodeMirrorInline(editor, textArea); + } else { + // loading the add-on scripts. + CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { + loadCodeMirrorInline(editor, textArea); + }); + } + } + }, + onCancel: function (event) { + if (event.data.hide) { + window["codemirror_" + editor.id].toTextArea(); + + // Free Memory + window["codemirror_" + editor.id] = null; + + editor.fire('blur', this); + editor.fire('focus', this); + } + }, + onOk: (function () { + + function setData(newData) { + var that = this; + + editor.setData(newData, function () { + that.hide(); + + // Ensure correct selection. + var range = editor.createRange(); + range.moveToElementEditStart(editor.editable()); + range.select(); + }); + } + + return function () { + window["codemirror_" + editor.id].toTextArea(); + + // Free Memory + window["codemirror_" + editor.id] = null; + + // Remove CR from input data for reliable comparison with editor data. + var newData = this.getValueOf('main', 'data').replace(/\r/g, ''); + + // Avoid unnecessary setData. Also preserve selection + // when user changed his mind and goes back to wysiwyg editing. + if (newData === oldData) + return true; + + // Set data asynchronously to avoid errors in IE. + CKEDITOR.env.ie ? CKEDITOR.tools.setTimeout(setData, 0, this, newData) : setData.call(this, newData); + + editor.fire('blur', this); + editor.fire('focus', this); + + // Don't let the dialog close before setData is over. + return false; + }; + })(), + + contents: [{ + id: 'main', + label: editor.lang.sourcedialog.title, + elements: [ + { + type: 'hbox', + style: 'width: 80px;margin:0;', + widths: ['20px', '20px', '20px', '20px'], + children: [ + { + type: 'button', + id: 'searchCode', + label: '', + title: lang.searchCode, + 'class': 'searchCodeButton', + onClick: function() { + CodeMirror.commands.find(window["codemirror_" + editor.id]); + } + }, { + type: 'button', + id: 'autoFormat', + label: '', + title: lang.autoFormat, + 'class': 'autoFormat', + onClick: function() { + var range = { + from: window["codemirror_" + editor.id].getCursor(true), + to: window["codemirror_" + editor.id].getCursor(false) + }; + window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); + } + }, { + type: 'button', + id: 'CommentSelectedRange', + label: '', + title: lang.commentSelectedRange, + 'class': 'CommentSelectedRange', + onClick: function () { + var range = { + from: window["codemirror_" + editor.id].getCursor(true), + to: window["codemirror_" + editor.id].getCursor(false) + }; + window["codemirror_" + editor.id].commentRange(true, range.from, range.to); + } + }, { + type: 'button', + id: 'UncommentSelectedRange', + label: '', + title: lang.uncommentSelectedRange, + 'class': 'UncommentSelectedRange', + onClick: function () { + var range = { + from: window["codemirror_" + editor.id].getCursor(true), + to: window["codemirror_" + editor.id].getCursor(false) + }; + window["codemirror_" + editor.id].commentRange(false, range.from, range.to); + if (window["codemirror_" + editor.id].config.autoFormatOnUncomment) { + window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); + } + } + }] + }, { + type: 'checkbox', + id: 'AutoComplete', + label: lang.autoCompleteToggle, + title: lang.autoCompleteToggle, + onChange: function () { + window["codemirror_" + editor.id].setOption("autoCloseTags", this.getValue()); + } + }, { + type: 'textarea', + id: 'data', + dir: 'ltr', + inputStyle: 'cursor:auto;' + + 'width:' + width + 'px;' + + 'height:' + height + 'px;' + + 'tab-size:4;' + + 'text-align:left;', + 'class': 'cke_source cke_enable_context_menu' + } + ] + }] + }; + }); + + // return; + } + + /* + // Override Copy Button + if (editor.commands.copy) { + editor.commands.copy.modes = { + wysiwyg: 1, + source: 1 + }; + + // TODO + } + + // Override Paste Button + if (editor.commands.paste) { + editor.commands.paste.modes = { + wysiwyg: 1, + source: 1 + }; + // TODO + + } + + // Override Cut Button + if (editor.commands.cut) { + editor.commands.cut.modes = { + wysiwyg: 1, + source: 1 + }; + + // TODO + }*/ + + // Override Find Button + if (editor.commands.find) { + editor.commands.find.modes = { + wysiwyg: 1, + source: 1 + }; + + editor.commands.find.exec = function() { + if (editor.mode === 'wysiwyg') { + editor.openDialog('find'); + } else { + CodeMirror.commands.find(window["codemirror_" + editor.id]); + } + }; + } + + // Override Replace Button + if (editor.commands.replace) { + editor.commands.replace.modes = { + wysiwyg: 1, + source: 1 + }; + + editor.commands.replace.exec = function () { + if (editor.mode === 'wysiwyg') { + editor.openDialog('replace'); + } else { + CodeMirror.commands.replace(window["codemirror_" + editor.id]); + } + }; + } + + var sourcearea = CKEDITOR.plugins.sourcearea; + + // check if sourcearea plugin is overrriden + if (!sourcearea.commands.searchCode) { + + CKEDITOR.plugins.sourcearea.commands = { + source: { + modes: { + wysiwyg: 1, + source: 1 + }, + editorFocus: false, + readOnly: 1, + exec: function(editorInstance) { + if (editorInstance.mode === 'wysiwyg') { + editorInstance.fire('saveSnapshot'); + } + editorInstance.getCommand('source').setState(CKEDITOR.TRISTATE_DISABLED); + editorInstance.setMode(editorInstance.mode === 'source' ? 'wysiwyg' : 'source'); + }, + canUndo: false + }, + searchCode: { + modes: { + wysiwyg: 0, + source: 1 + }, + editorFocus: false, + readOnly: 1, + exec: function (editorInstance) { + CodeMirror.commands.find(window["codemirror_" + editorInstance.id]); + }, + canUndo: true + }, + autoFormat: { + modes: { + wysiwyg: 0, + source: 1 + }, + editorFocus: false, + readOnly: 1, + exec: function (editorInstance) { + var range = { + from: window["codemirror_" + editorInstance.id].getCursor(true), + to: window["codemirror_" + editorInstance.id].getCursor(false) + }; + window["codemirror_" + editorInstance.id].autoFormatRange(range.from, range.to); + }, + canUndo: true + }, + commentSelectedRange: { + modes: { + wysiwyg: 0, + source: 1 + }, + editorFocus: false, + readOnly: 1, + exec: function (editorInstance) { + var range = { + from: window["codemirror_" + editorInstance.id].getCursor(true), + to: window["codemirror_" + editorInstance.id].getCursor(false) + }; + window["codemirror_" + editorInstance.id].commentRange(true, range.from, range.to); + }, + canUndo: true + }, + uncommentSelectedRange: { + modes: { + wysiwyg: 0, + source: 1 + }, + editorFocus: false, + readOnly: 1, + exec: function (editorInstance) { + var range = { + from: window["codemirror_" + editorInstance.id].getCursor(true), + to: window["codemirror_" + editorInstance.id].getCursor(false) + }; + window["codemirror_" + editorInstance.id].commentRange(false, range.from, range.to); + if (window["codemirror_" + editorInstance.id].config.autoFormatOnUncomment) { + window["codemirror_" + editorInstance.id].autoFormatRange( + range.from, + range.to); + } + }, + canUndo: true + }, + autoCompleteToggle: { + modes: { + wysiwyg: 0, + source: 1 + }, + editorFocus: false, + readOnly: 1, + exec: function (editorInstance) { + if (this.state == CKEDITOR.TRISTATE_ON) { + window["codemirror_" + editorInstance.id].setOption("autoCloseTags", false); + } else if (this.state == CKEDITOR.TRISTATE_OFF) { + window["codemirror_" + editorInstance.id].setOption("autoCloseTags", true); + } + + this.toggleState(); + }, + canUndo: true + } + }; + } + + editor.addMode('source', function (callback) { + if (!IsStyleSheetAlreadyLoaded(rootPath + 'css/codemirror.min.css')) { + CKEDITOR.document.appendStyleSheet(rootPath + 'css/codemirror.min.css'); + } + + if (config.theme.length && config.theme != 'default' && !IsStyleSheetAlreadyLoaded(rootPath + 'theme/' + config.theme + '.css')) { + CKEDITOR.document.appendStyleSheet(rootPath + 'theme/' + config.theme + '.css'); + } + + if (typeof (CodeMirror) == 'undefined') { + + CKEDITOR.scriptLoader.load(rootPath + 'js/codemirror.js', function() { + + CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { + loadCodeMirror(editor); + callback(); + }); + }); + } else { + if (CodeMirror.prototype['autoFormatAll']) { + loadCodeMirror(editor); + callback(); + } else { + // loading the add-on scripts. + CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { + loadCodeMirror(editor); + callback(); + }); + } + } + }); + + function getCodeMirrorScripts() { + var scriptFiles = [rootPath + 'js/codemirror.addons.min.js']; + + switch (config.mode) { + case "bbcode": + { + scriptFiles.push(rootPath + 'js/codemirror.mode.bbcode.min.js'); + } + + break; + case "bbcodemixed": + { + scriptFiles.push(rootPath + 'js/codemirror.mode.bbcodemixed.min.js'); + } + + break; + case "htmlmixed": + { + scriptFiles.push(rootPath + 'js/codemirror.mode.htmlmixed.min.js'); + } + + break; + case "text/html": + { + scriptFiles.push(rootPath + 'js/codemirror.mode.htmlmixed.min.js'); + } + + break; + case "application/x-httpd-php": + { + scriptFiles.push(rootPath + 'js/codemirror.mode.php.min.js'); + } + + break; + case "text/javascript": + { + scriptFiles.push(rootPath + 'js/codemirror.mode.javascript.min.js'); + } + + break; + default: + scriptFiles.push(rootPath + 'js/codemirror.mode.htmlmixed.min.js'); + } + + if (config.useBeautify) { + scriptFiles.push(rootPath + 'js/beautify.min.js'); + } + + if (config.enableSearchTools) { + scriptFiles.push(rootPath + 'js/codemirror.addons.search.min.js'); + } + return scriptFiles; + } + + function loadCodeMirror(editor) { + var contentsSpace = editor.ui.space('contents'), + textarea = contentsSpace.getDocument().createElement('textarea'); + + textarea.setStyles( + CKEDITOR.tools.extend({ + // IE7 has overflow the + +

      +

      + +

      + + + + diff --git a/lib/redactor/ckeditor/plugins/preview/preview.html b/lib/redactor/ckeditor/plugins/preview/preview.html new file mode 100644 index 0000000..7eb8082 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/preview/preview.html @@ -0,0 +1,13 @@ + diff --git a/lib/redactor/ckeditor/plugins/savedocs/plugin.js b/lib/redactor/ckeditor/plugins/savedocs/plugin.js new file mode 100644 index 0000000..7637127 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/savedocs/plugin.js @@ -0,0 +1,22 @@ +CKEDITOR.plugins.add('savedocs', { + init: function(a) { + var cmd = a.addCommand('savedoc', { + exec: saveDocument + }) + a.ui.addButton('savedocs', { + label: 'Save', + command: 'savedoc', + icon: this.path + "images/save.png" + }) + } +}); + +function saveDocument(event) { + var theForm = event.element.$.form; + if (typeof(theForm.onsubmit) == 'function') { + AveDocs.saveDocument(); + return false; + } else { + AveDocs.saveDocument(); + } +} \ No newline at end of file diff --git a/lib/redactor/ckeditor/plugins/scayt/CHANGELOG.md b/lib/redactor/ckeditor/plugins/scayt/CHANGELOG.md new file mode 100644 index 0000000..05cf2dd --- /dev/null +++ b/lib/redactor/ckeditor/plugins/scayt/CHANGELOG.md @@ -0,0 +1,20 @@ +SCAYT plugin for CKEditor 4 Changelog +==================== +### CKEditor 4.5.6 + +New Features: +* CKEditor [language addon](http://ckeditor.com/addon/language) support +* CKEditor [placeholder addon](http://ckeditor.com/addon/placeholder) support +* Drag and Drop support +* *Experimental* GRAYT functionality http://www.webspellchecker.net/samples/scayt-ckeditor-plugin.html#25 + +Fixed issues: +* [#98](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/98) SCAYT Affects Dialog Double Click. Fixed in SCAYT Core. +* [#102](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/102) SCAYT Core performance enhancements +* [#104](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/104) SCAYT's spans leak into the clipboard and after pasting +* [#105](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/105) Javascript error fired in case of multiple instances of CKEditor in one page +* [#107](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/107) SCAYT should not check non-editable parts of content +* [#108](https://github.com/WebSpellChecker/ckeditor-plugin-scayt/issues/108) Latest SCAYT copies id of editor element to the iframe +* SCAYT stops working when CKEditor Undo plug-in not enabled +* Issue with pasting SCAYT markup in CKEditor +* [#32](https://github.com/WebSpellChecker/ckeditor-plugin-wsc/issues/32) SCAYT stops working after pressing Cancel button in WSC dialog diff --git a/lib/redactor/ckeditor/plugins/scayt/LICENSE.md b/lib/redactor/ckeditor/plugins/scayt/LICENSE.md new file mode 100644 index 0000000..610c807 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/scayt/LICENSE.md @@ -0,0 +1,28 @@ +Software License Agreement +========================== + +**CKEditor SCAYT Plugin** +Copyright © 2012, [CKSource](http://cksource.com) - Frederico Knabben. All rights reserved. + +Licensed under the terms of any of the following licenses at your choice: + +* GNU General Public License Version 2 or later (the "GPL"): + http://www.gnu.org/licenses/gpl.html + +* GNU Lesser General Public License Version 2.1 or later (the "LGPL"): + http://www.gnu.org/licenses/lgpl.html + +* Mozilla Public License Version 1.1 or later (the "MPL"): + http://www.mozilla.org/MPL/MPL-1.1.html + +You are not required to, but if you want to explicitly declare the license you have chosen to be bound to when using, reproducing, modifying and distributing this software, just include a text file titled "legal.txt" in your version of this software, indicating your license choice. + +Sources of Intellectual Property Included in this plugin +-------------------------------------------------------- + +Where not otherwise indicated, all plugin content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, the plugin will incorporate work done by developers outside of CKSource with their express permission. + +Trademarks +---------- + +CKEditor is a trademark of CKSource - Frederico Knabben. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders. diff --git a/lib/redactor/ckeditor/plugins/scayt/README.md b/lib/redactor/ckeditor/plugins/scayt/README.md new file mode 100644 index 0000000..1b3de25 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/scayt/README.md @@ -0,0 +1,25 @@ +CKEditor SCAYT Plugin +===================== + +This plugin brings Spell Check As You Type (SCAYT) into up to CKEditor 4+. + +SCAYT is a "installation-less", using the web-services of [WebSpellChecker.net](http://www.webspellchecker.net/). It's an out of the box solution. + +Installation +------------ + +1. Clone/copy this repository contents in a new "plugins/scayt" folder in your CKEditor installation. +2. Enable the "scayt" plugin in the CKEditor configuration file (config.js): + + config.extraPlugins = 'scayt'; + +That's all. SCAYT will appear on the editor toolbar and will be ready to use. + +License +------- + +Licensed under the terms of any of the following licenses at your choice: [GPL](http://www.gnu.org/licenses/gpl.html), [LGPL](http://www.gnu.org/licenses/lgpl.html) and [MPL](http://www.mozilla.org/MPL/MPL-1.1.html). + +See LICENSE.md for more information. + +Developed in cooperation with [WebSpellChecker.net](http://www.webspellchecker.net/). diff --git a/lib/redactor/ckeditor/plugins/scayt/dialogs/options.js b/lib/redactor/ckeditor/plugins/scayt/dialogs/options.js new file mode 100644 index 0000000..6f158a0 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/scayt/dialogs/options.js @@ -0,0 +1,19 @@ +CKEDITOR.dialog.add("scaytDialog",function(d){var f=d.scayt,p='\x3cp\x3e\x3cimg src\x3d"'+f.getLogo()+'" /\x3e\x3c/p\x3e\x3cp\x3e'+f.getLocal("version")+f.getVersion()+"\x3c/p\x3e\x3cp\x3e"+f.getLocal("text_copyrights")+"\x3c/p\x3e",q=CKEDITOR.document,l={isChanged:function(){return null===this.newLang||this.currentLang===this.newLang?!1:!0},currentLang:f.getLang(),newLang:null,reset:function(){this.currentLang=f.getLang();this.newLang=null},id:"lang"},p=[{id:"options",label:f.getLocal("tab_options"), +onShow:function(){},elements:[{type:"vbox",id:"scaytOptions",children:function(){var a=f.getApplicationConfig(),b=[],e={"ignore-all-caps-words":"label_allCaps","ignore-domain-names":"label_ignoreDomainNames","ignore-words-with-mixed-cases":"label_mixedCase","ignore-words-with-numbers":"label_mixedWithDigits"},h;for(h in a)a={type:"checkbox"},a.id=h,a.label=f.getLocal(e[h]),b.push(a);return b}(),onShow:function(){this.getChild();for(var a=d.scayt,b=0;bb[1]?c=1:a[1] div +{ + padding-bottom: 6px !important; +} + +.scayt-lang-list > div input +{ + margin-right: 4px; +} + +#scayt_about_ +{ + width: 190px; + margin: 30px auto 0 auto; +} + +.cke_dialog_contents_body div[name=dictionaries] .cke_dialog_ui_hbox_last > a.cke_dialog_ui_button +{ + margin-top: 0; +} diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_address.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_address.png new file mode 100644 index 0000000..5abdae1 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_address.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_blockquote.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_blockquote.png new file mode 100644 index 0000000..a8f4973 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_blockquote.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_div.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_div.png new file mode 100644 index 0000000..87b3c17 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_div.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_h1.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_h1.png new file mode 100644 index 0000000..3933325 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_h1.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_h2.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_h2.png new file mode 100644 index 0000000..c99894c Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_h2.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_h3.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_h3.png new file mode 100644 index 0000000..cb73d67 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_h3.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_h4.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_h4.png new file mode 100644 index 0000000..7af6bb4 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_h4.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_h5.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_h5.png new file mode 100644 index 0000000..ce5bec1 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_h5.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_h6.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_h6.png new file mode 100644 index 0000000..e67b982 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_h6.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_p.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_p.png new file mode 100644 index 0000000..63a5820 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_p.png differ diff --git a/lib/redactor/ckeditor/plugins/showblocks/images/block_pre.png b/lib/redactor/ckeditor/plugins/showblocks/images/block_pre.png new file mode 100644 index 0000000..955a868 Binary files /dev/null and b/lib/redactor/ckeditor/plugins/showblocks/images/block_pre.png differ diff --git a/lib/redactor/ckeditor/plugins/smiley/dialogs/smiley.js b/lib/redactor/ckeditor/plugins/smiley/dialogs/smiley.js new file mode 100644 index 0000000..841d789 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/smiley/dialogs/smiley.js @@ -0,0 +1,11 @@ +/* + Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +CKEDITOR.dialog.add("smiley",function(f){for(var e=f.config,a=f.lang.smiley,h=e.smiley_images,g=e.smiley_columns||8,k,m=function(l){var c=l.data.getTarget(),b=c.getName();if("a"==b)c=c.getChild(0);else if("img"!=b)return;var b=c.getAttribute("cke_src"),a=c.getAttribute("title"),c=f.document.createElement("img",{attributes:{src:b,"data-cke-saved-src":b,title:a,alt:a,width:c.$.width,height:c.$.height}});f.insertElement(c);k.hide();l.data.preventDefault()},q=CKEDITOR.tools.addFunction(function(a,c){a= +new CKEDITOR.dom.event(a);c=new CKEDITOR.dom.element(c);var b;b=a.getKeystroke();var d="rtl"==f.lang.dir;switch(b){case 38:if(b=c.getParent().getParent().getPrevious())b=b.getChild([c.getParent().getIndex(),0]),b.focus();a.preventDefault();break;case 40:(b=c.getParent().getParent().getNext())&&(b=b.getChild([c.getParent().getIndex(),0]))&&b.focus();a.preventDefault();break;case 32:m({data:a});a.preventDefault();break;case d?37:39:if(b=c.getParent().getNext())b=b.getChild(0),b.focus(),a.preventDefault(!0); +else if(b=c.getParent().getParent().getNext())(b=b.getChild([0,0]))&&b.focus(),a.preventDefault(!0);break;case d?39:37:if(b=c.getParent().getPrevious())b=b.getChild(0),b.focus(),a.preventDefault(!0);else if(b=c.getParent().getParent().getPrevious())b=b.getLast().getChild(0),b.focus(),a.preventDefault(!0)}}),d=CKEDITOR.tools.getNextId()+"_smiley_emtions_label",d=['\x3cdiv\x3e\x3cspan id\x3d"'+d+'" class\x3d"cke_voice_label"\x3e'+a.options+"\x3c/span\x3e",'\x3ctable role\x3d"listbox" aria-labelledby\x3d"'+ +d+'" style\x3d"width:100%;height:100%;border-collapse:separate;" cellspacing\x3d"2" cellpadding\x3d"2"',CKEDITOR.env.ie&&CKEDITOR.env.quirks?' style\x3d"position:absolute;"':"","\x3e\x3ctbody\x3e"],n=h.length,a=0;an&&(n=f)}return n}function r(a){return function(){var f=this.getValue(),f=!!(CKEDITOR.dialog.validate.integer()(f)&&0q.getSize("width")?"100%":500:0,getValue:u,validate:CKEDITOR.dialog.validate.cssLength(a.lang.common.invalidCssLength.replace("%1", +a.lang.common.width)),onChange:function(){var a=this.getDialog().getContentElement("advanced","advStyles");a&&a.updateStyle("width",this.getValue())},setup:function(a){a=a.getStyle("width");this.setValue(a)},commit:l}]},{type:"hbox",widths:["5em"],children:[{type:"text",id:"txtHeight",requiredContent:"table{height}",controlStyle:"width:5em",label:a.lang.common.height,title:a.lang.common.cssLengthTooltip,"default":"",getValue:u,validate:CKEDITOR.dialog.validate.cssLength(a.lang.common.invalidCssLength.replace("%1", +a.lang.common.height)),onChange:function(){var a=this.getDialog().getContentElement("advanced","advStyles");a&&a.updateStyle("height",this.getValue())},setup:function(a){(a=a.getStyle("height"))&&this.setValue(a)},commit:l}]},{type:"html",html:"\x26nbsp;"},{type:"text",id:"txtCellSpace",requiredContent:"table[cellspacing]",controlStyle:"width:3em",label:a.lang.table.cellSpace,"default":a.filter.check("table[cellspacing]")?1:0,validate:CKEDITOR.dialog.validate.number(a.lang.table.invalidCellSpacing), +setup:function(a){this.setValue(a.getAttribute("cellSpacing")||"")},commit:function(a,d){this.getValue()?d.setAttribute("cellSpacing",this.getValue()):d.removeAttribute("cellSpacing")}},{type:"text",id:"txtCellPad",requiredContent:"table[cellpadding]",controlStyle:"width:3em",label:a.lang.table.cellPad,"default":a.filter.check("table[cellpadding]")?1:0,validate:CKEDITOR.dialog.validate.number(a.lang.table.invalidCellPadding),setup:function(a){this.setValue(a.getAttribute("cellPadding")||"")},commit:function(a, +d){this.getValue()?d.setAttribute("cellPadding",this.getValue()):d.removeAttribute("cellPadding")}}]}]},{type:"html",align:"right",html:""},{type:"vbox",padding:0,children:[{type:"text",id:"txtCaption",requiredContent:"caption",label:a.lang.table.caption,setup:function(a){this.enable();a=a.getElementsByTag("caption");if(0 + + + + + + + +

      + diff --git a/lib/redactor/ckeditor/plugins/wsc/dialogs/tmpFrameset.html b/lib/redactor/ckeditor/plugins/wsc/dialogs/tmpFrameset.html new file mode 100644 index 0000000..d5fc6bb --- /dev/null +++ b/lib/redactor/ckeditor/plugins/wsc/dialogs/tmpFrameset.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/lib/redactor/ckeditor/plugins/wsc/dialogs/wsc.css b/lib/redactor/ckeditor/plugins/wsc/dialogs/wsc.css new file mode 100644 index 0000000..1056b45 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/wsc/dialogs/wsc.css @@ -0,0 +1,82 @@ +/* +Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +html, body +{ + background-color: transparent; + margin: 0px; + padding: 0px; +} + +body +{ + padding: 10px; +} + +body, td, input, select, textarea +{ + font-size: 11px; + font-family: 'Microsoft Sans Serif' , Arial, Helvetica, Verdana; +} + +.midtext +{ + padding:0px; + margin:10px; +} + +.midtext p +{ + padding:0px; + margin:10px; +} + +.Button +{ + border: #737357 1px solid; + color: #3b3b1f; + background-color: #c7c78f; +} + +.PopupTabArea +{ + color: #737357; + background-color: #e3e3c7; +} + +.PopupTitleBorder +{ + border-bottom: #d5d59d 1px solid; +} +.PopupTabEmptyArea +{ + padding-left: 10px; + border-bottom: #d5d59d 1px solid; +} + +.PopupTab, .PopupTabSelected +{ + border-right: #d5d59d 1px solid; + border-top: #d5d59d 1px solid; + border-left: #d5d59d 1px solid; + padding: 3px 5px 3px 5px; + color: #737357; +} + +.PopupTab +{ + margin-top: 1px; + border-bottom: #d5d59d 1px solid; + cursor: pointer; +} + +.PopupTabSelected +{ + font-weight: bold; + cursor: default; + padding-top: 4px; + border-bottom: #f1f1e3 1px solid; + background-color: #f1f1e3; +} diff --git a/lib/redactor/ckeditor/plugins/wsc/dialogs/wsc.js b/lib/redactor/ckeditor/plugins/wsc/dialogs/wsc.js new file mode 100644 index 0000000..af51da7 --- /dev/null +++ b/lib/redactor/ckeditor/plugins/wsc/dialogs/wsc.js @@ -0,0 +1,92 @@ +/* + Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved. + For licensing, see LICENSE.html or http://ckeditor.com/license +*/ +(function(){function z(a){return a&&a.domId&&a.getInputElement().$?a.getInputElement():a&&a.$?a:!1}function I(a){if(!a)throw"Languages-by-groups list are required for construct selectbox";var c=[],e="",d;for(d in a)for(var f in a[d]){var h=a[d][f];"en_US"==h?e=h:c.push(h)}c.sort();e&&c.unshift(e);return{getCurrentLangGroup:function(c){a:{for(var d in a)for(var e in a[d])if(e.toUpperCase()===c.toUpperCase()){c=d;break a}c=""}return c},setLangList:function(){var c={},d;for(d in a)for(var e in a[d])c[a[d][e]]= +e;return c}()}}var g=function(){var a=function(a,b,d){d=d||{};var f=d.expires;if("number"==typeof f&&f){var h=new Date;h.setTime(h.getTime()+1E3*f);f=d.expires=h}f&&f.toUTCString&&(d.expires=f.toUTCString());b=encodeURIComponent(b);a=a+"\x3d"+b;for(var k in d)b=d[k],a+="; "+k,!0!==b&&(a+="\x3d"+b);document.cookie=a};return{postMessage:{init:function(a){window.addEventListener?window.addEventListener("message",a,!1):window.attachEvent("onmessage",a)},send:function(a){var b=Object.prototype.toString, +d=a.fn||null,f=a.id||"",h=a.target||window,k=a.message||{id:f};a.message&&"[object Object]"==b.call(a.message)&&(a.message.id?a.message.id:a.message.id=f,k=a.message);a=window.JSON.stringify(k,d);h.postMessage(a,"*")},unbindHandler:function(a){window.removeEventListener?window.removeEventListener("message",a,!1):window.detachEvent("onmessage",a)}},hash:{create:function(){},parse:function(){}},cookie:{set:a,get:function(a){return(a=document.cookie.match(new RegExp("(?:^|; )"+a.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, +"\\$1")+"\x3d([^;]*)")))?decodeURIComponent(a[1]):void 0},remove:function(c){a(c,"",{expires:-1})}},misc:{findFocusable:function(a){var b=null;a&&(b=a.find("a[href], area[href], input, select, textarea, button, *[tabindex], *[contenteditable]"));return b},isVisible:function(a){var b;(b=0===a.offsetWidth||0==a.offsetHeight)||(b="none"===(document.defaultView&&document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(a,null).display:a.currentStyle?a.currentStyle.display:a.style.display)); +return!b},hasClass:function(a,b){return!(!a.className||!a.className.match(new RegExp("(\\s|^)"+b+"(\\s|$)")))}}}}(),a=a||{};a.TextAreaNumber=null;a.load=!0;a.cmd={SpellTab:"spell",Thesaurus:"thes",GrammTab:"grammar"};a.dialog=null;a.optionNode=null;a.selectNode=null;a.grammerSuggest=null;a.textNode={};a.iframeMain=null;a.dataTemp="";a.div_overlay=null;a.textNodeInfo={};a.selectNode={};a.selectNodeResponce={};a.langList=null;a.langSelectbox=null;a.banner="";a.show_grammar=null;a.div_overlay_no_check= +null;a.targetFromFrame={};a.onLoadOverlay=null;a.LocalizationComing={};a.OverlayPlace=null;a.sessionid="";a.LocalizationButton={ChangeTo_button:{instance:null,text:"Change to",localizationID:"ChangeTo"},ChangeAll:{instance:null,text:"Change All"},IgnoreWord:{instance:null,text:"Ignore word"},IgnoreAllWords:{instance:null,text:"Ignore all words"},Options:{instance:null,text:"Options",optionsDialog:{instance:null}},AddWord:{instance:null,text:"Add word"},FinishChecking_button:{instance:null,text:"Finish Checking", +localizationID:"FinishChecking"},FinishChecking_button_block:{instance:null,text:"Finish Checking",localizationID:"FinishChecking"}};a.LocalizationLabel={ChangeTo_label:{instance:null,text:"Change to",localizationID:"ChangeTo"},Suggestions:{instance:null,text:"Suggestions"},Categories:{instance:null,text:"Categories"},Synonyms:{instance:null,text:"Synonyms"}};var J=function(b){var c,e,d;for(d in b)c=(c=a.dialog.getContentElement(a.dialog._.currentTabId,d))?c.getElement():b[d].instance.getElement().getFirst()|| +b[d].instance.getElement(),e=b[d].localizationID||d,c.setText(a.LocalizationComing[e])},K=function(b){var c,e,d;for(d in b)c=a.dialog.getContentElement(a.dialog._.currentTabId,d),c||(c=b[d].instance),c.setLabel&&(e=b[d].localizationID||d,c.setLabel(a.LocalizationComing[e]+":"))},r,A;a.framesetHtml=function(b){return"\x3ciframe id\x3d"+a.iframeNumber+"_"+b+' frameborder\x3d"0" allowtransparency\x3d"1" style\x3d"width:100%;border: 1px solid #AEB3B9;overflow: auto;background:#fff; border-radius: 3px;"\x3e\x3c/iframe\x3e'}; +a.setIframe=function(b,c){var e;e=a.framesetHtml(c);var d=a.iframeNumber+"_"+c;b.getElement().setHtml(e);e=document.getElementById(d);e=e.contentWindow?e.contentWindow:e.contentDocument.document?e.contentDocument.document:e.contentDocument;e.document.open();e.document.write('\x3c!DOCTYPE html\x3e\x3chtml\x3e\x3chead\x3e\x3cmeta charset\x3d"UTF-8"\x3e\x3ctitle\x3eiframe\x3c/title\x3e\x3cstyle\x3ehtml,body{margin: 0;height: 100%;font: 13px/1.555 "Trebuchet MS", sans-serif;}a{color: #888;font-weight: bold;text-decoration: none;border-bottom: 1px solid #888;}.main-box {color:#252525;padding: 3px 5px;text-align: justify;}.main-box p{margin: 0 0 14px;}.main-box .cerr{color: #f00000;border-bottom-color: #f00000;}\x3c/style\x3e\x3c/head\x3e\x3cbody\x3e\x3cdiv id\x3d"content" class\x3d"main-box"\x3e\x3c/div\x3e\x3ciframe src\x3d"" frameborder\x3d"0" id\x3d"spelltext" name\x3d"spelltext" style\x3d"display:none; width: 100%" \x3e\x3c/iframe\x3e\x3ciframe src\x3d"" frameborder\x3d"0" id\x3d"loadsuggestfirst" name\x3d"loadsuggestfirst" style\x3d"display:none; width: 100%" \x3e\x3c/iframe\x3e\x3ciframe src\x3d"" frameborder\x3d"0" id\x3d"loadspellsuggestall" name\x3d"loadspellsuggestall" style\x3d"display:none; width: 100%" \x3e\x3c/iframe\x3e\x3ciframe src\x3d"" frameborder\x3d"0" id\x3d"loadOptionsForm" name\x3d"loadOptionsForm" style\x3d"display:none; width: 100%" \x3e\x3c/iframe\x3e\x3cscript\x3e(function(window) {var ManagerPostMessage \x3d function() {var _init \x3d function(handler) {if (document.addEventListener) {window.addEventListener("message", handler, false);} else {window.attachEvent("onmessage", handler);};};var _sendCmd \x3d function(o) {var str,type \x3d Object.prototype.toString,fn \x3d o.fn || null,id \x3d o.id || "",target \x3d o.target || window,message \x3d o.message || { "id": id };if (o.message \x26\x26 type.call(o.message) \x3d\x3d "[object Object]") {(o.message["id"]) ? o.message["id"] : o.message["id"] \x3d id;message \x3d o.message;};str \x3d JSON.stringify(message, fn);target.postMessage(str, "*");};return {init: _init,send: _sendCmd};};var manageMessageTmp \x3d new ManagerPostMessage;var appString \x3d (function(){var spell \x3d parent.CKEDITOR.config.wsc.DefaultParams.scriptPath;var serverUrl \x3d parent.CKEDITOR.config.wsc.DefaultParams.serviceHost;return serverUrl + spell;})();function loadScript(src, callback) {var scriptTag \x3d document.createElement("script");scriptTag.type \x3d "text/javascript";callback ? callback : callback \x3d function() {};if(scriptTag.readyState) {scriptTag.onreadystatechange \x3d function() {if (scriptTag.readyState \x3d\x3d "loaded" ||scriptTag.readyState \x3d\x3d "complete") {scriptTag.onreadystatechange \x3d null;setTimeout(function(){scriptTag.parentNode.removeChild(scriptTag)},1);callback();}};}else{scriptTag.onload \x3d function() {setTimeout(function(){scriptTag.parentNode.removeChild(scriptTag)},1);callback();};};scriptTag.src \x3d src;document.getElementsByTagName("head")[0].appendChild(scriptTag);};window.onload \x3d function(){loadScript(appString, function(){manageMessageTmp.send({"id": "iframeOnload","target": window.parent});});}})(this);\x3c/script\x3e\x3c/body\x3e\x3c/html\x3e'); +e.document.close()};a.setCurrentIframe=function(b){a.setIframe(a.dialog._.contents[b].Content,b)};a.setHeightBannerFrame=function(){var b=a.dialog.getContentElement("SpellTab","banner").getElement(),c=a.dialog.getContentElement("GrammTab","banner").getElement(),e=a.dialog.getContentElement("Thesaurus","banner").getElement();b.setStyle("height","90px");c.setStyle("height","90px");e.setStyle("height","90px")};a.setHeightFrame=function(){document.getElementById(a.iframeNumber+"_"+a.dialog._.currentTabId).style.height= +"240px"};a.sendData=function(b){var c=b._.currentTabId,e=b._.contents[c].Content,d,f;a.previousTab=c;a.setIframe(e,c);var h=function(h){c=b._.currentTabId;h=h||window.event;h.data.getTarget().is("a")&&c!==a.previousTab&&(a.previousTab=c,e=b._.contents[c].Content,d=a.iframeNumber+"_"+c,a.div_overlay.setEnable(),e.getElement().getChildCount()?E(a.targetFromFrame[d],a.cmd[c]):(a.setIframe(e,c),f=document.getElementById(d),a.targetFromFrame[d]=f.contentWindow))};b.parts.tabs.removeListener("click",h); +b.parts.tabs.on("click",h)};a.buildSelectLang=function(a){var c=new CKEDITOR.dom.element("div"),e=new CKEDITOR.dom.element("select");a="wscLang"+a;c.addClass("cke_dialog_ui_input_select");c.setAttribute("role","presentation");c.setStyles({height:"auto",position:"absolute",right:"0",top:"-1px",width:"160px","white-space":"normal"});e.setAttribute("id",a);e.addClass("cke_dialog_ui_input_select");e.setStyles({width:"160px"});c.append(e);return c};a.buildOptionLang=function(b,c){var e=document.getElementById("wscLang"+ +c),d=document.createDocumentFragment(),f,h,k=[];if(0===e.options.length){for(f in b)k.push([f,b[f]]);k.sort();for(var p=0;pm.width-D&&(e=m.width-D);if(gm.height-q&&(g=m.height-q);n.width=e+D;n.height=g+q;a._.fromResizeEvent=!1;a.resize(e,g);setTimeout(function(){a._.fromResizeEvent=!1;CKEDITOR.dialog.fire("resize",{dialog:a,width:e,height:g},b)},300)}a._.moved||(q=isNaN(c)&&isNaN(d)?0:1,isNaN(c)&&(c=(m.width-n.width)/2),0>c&&(c=0),c>m.width-n.width&&(c=m.width-n.width),isNaN(d)&&(d=(m.height-n.height)/2),0>d&&(d=0),d>m.height-n.height&&(d=m.height-n.height),a.move(c, +d,q))}function e(){b.wsc={};(function(a){var b={separator:"\x3c$\x3e",getDataType:function(a){return"undefined"===typeof a?"undefined":null===a?"null":Object.prototype.toString.call(a).slice(8,-1)},convertDataToString:function(a){return this.getDataType(a).toLowerCase()+this.separator+a},restoreDataFromString:function(a){var b=a,c;a=this.backCompatibility(a);if("string"===typeof a)switch(b=a.indexOf(this.separator),c=a.substring(0,b),b=a.substring(b+this.separator.length),c){case "boolean":b="true"=== +b;break;case "number":b=parseFloat(b);break;case "array":b=""===b?[]:b.split(",");break;case "null":b=null;break;case "undefined":b=void 0}return b},backCompatibility:function(a){var b=a,c;"string"===typeof a&&(c=a.indexOf(this.separator),0>c&&(b=parseFloat(a),isNaN(b)&&("["===a[0]&&"]"===a[a.length-1]?(a=a.replace("[",""),a=a.replace("]",""),b=""===a?[]:a.split(",")):b="true"===a||"false"===a?"true"===a:a),b=this.convertDataToString(b)));return b}},c={get:function(a){return b.restoreDataFromString(window.localStorage.getItem(a))}, +set:function(a,c){var d=b.convertDataToString(c);window.localStorage.setItem(a,d)},del:function(a){window.localStorage.removeItem(a)},clear:function(){window.localStorage.clear()}},d={expiration:31622400,get:function(a){return b.restoreDataFromString(this.getCookie(a))},set:function(a,c){var d=b.convertDataToString(c);this.setCookie(a,d,{expires:this.expiration})},del:function(a){this.deleteCookie(a)},getCookie:function(a){return(a=document.cookie.match(new RegExp("(?:^|; )"+a.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, +"\\$1")+"\x3d([^;]*)")))?decodeURIComponent(a[1]):void 0},setCookie:function(a,b,c){c=c||{};var d=c.expires;if("number"===typeof d&&d){var e=new Date;e.setTime(e.getTime()+1E3*d);d=c.expires=e}d&&d.toUTCString&&(c.expires=d.toUTCString());b=encodeURIComponent(b);a=a+"\x3d"+b;for(var h in c)b=c[h],a+="; "+h,!0!==b&&(a+="\x3d"+b);document.cookie=a},deleteCookie:function(a){this.setCookie(a,null,{expires:-1})},clear:function(){for(var a=document.cookie.split(";"),b=0;b .cke_dialog_ui_button:first-child +{ + margin-top: 4px; +} + +div[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select > label +{ + margin-left: 0; +} + +div[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select div.cke_dialog_ui_input_select +{ + width: 140px !important; +} + +div[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select select.cke_dialog_ui_input_select, +div[name=Thesaurus] div.cke_dialog_ui_input_select select.cke_dialog_ui_input_select +{ + margin-top: 1px; +} + +div[name=SpellTab] .wsc-spelltab-bottom .cke_dialog_ui_hbox_first .cke_dialog_ui_select select.cke_dialog_ui_input_select:focus, +div[name=Thesaurus] div.cke_dialog_ui_input_select select.cke_dialog_ui_input_select:focus +{ + margin-top: 0; +} + +div[name=GrammTab] .cke_dialog_ui_vbox tbody > tr:first-child .cke_dialog_ui_button, +div[name=Thesaurus] .cke_dialog_ui_vbox tbody > tr:first-child .cke_dialog_ui_button +{ + margin-top: 4px !important; +} + +div[name=Thesaurus] div.cke_dialog_ui_input_select +{ + width: 180px !important; +} diff --git a/lib/redactor/ckeditor/skins/moono-lisa/dialog.css b/lib/redactor/ckeditor/skins/moono-lisa/dialog.css new file mode 100644 index 0000000..4806c2b --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/dialog.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/dialog_ie.css b/lib/redactor/ckeditor/skins/moono-lisa/dialog_ie.css new file mode 100644 index 0000000..a5522cc --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/dialog_ie.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}.cke_rtl input.cke_dialog_ui_input_text,.cke_rtl input.cke_dialog_ui_input_password{padding-right:2px}.cke_rtl div.cke_dialog_ui_input_text,.cke_rtl div.cke_dialog_ui_input_password{padding-left:2px}.cke_rtl div.cke_dialog_ui_input_text{padding-right:1px}.cke_rtl .cke_dialog_ui_vbox_child,.cke_rtl .cke_dialog_ui_hbox_child,.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_last{padding-right:2px!important}.cke_hc .cke_dialog_title,.cke_hc .cke_dialog_footer,.cke_hc a.cke_dialog_tab,.cke_hc a.cke_dialog_ui_button,.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button_ok,.cke_hc a.cke_dialog_ui_button_ok:hover{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:0} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/dialog_ie8.css b/lib/redactor/ckeditor/skins/moono-lisa/dialog_ie8.css new file mode 100644 index 0000000..8833e5c --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/dialog_ie8.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}.cke_rtl input.cke_dialog_ui_input_text,.cke_rtl input.cke_dialog_ui_input_password{padding-right:2px}.cke_rtl div.cke_dialog_ui_input_text,.cke_rtl div.cke_dialog_ui_input_password{padding-left:2px}.cke_rtl div.cke_dialog_ui_input_text{padding-right:1px}.cke_rtl .cke_dialog_ui_vbox_child,.cke_rtl .cke_dialog_ui_hbox_child,.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_last{padding-right:2px!important}.cke_hc .cke_dialog_title,.cke_hc .cke_dialog_footer,.cke_hc a.cke_dialog_tab,.cke_hc a.cke_dialog_ui_button,.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button_ok,.cke_hc a.cke_dialog_ui_button_ok:hover{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:0}a.cke_dialog_ui_button{min-height:18px}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,textarea.cke_dialog_ui_input_textarea{min-height:18px}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,textarea.cke_dialog_ui_input_textarea:focus{padding-top:4px;padding-bottom:2px}select.cke_dialog_ui_input_select{width:100%!important}select.cke_dialog_ui_input_select:focus{margin-left:1px;width:100%!important;padding-top:2px;padding-bottom:2px} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/dialog_iequirks.css b/lib/redactor/ckeditor/skins/moono-lisa/dialog_iequirks.css new file mode 100644 index 0000000..590c5c2 --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/dialog_iequirks.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_dialog{visibility:visible}.cke_dialog_body{z-index:1;background:#fff}.cke_dialog strong{font-weight:bold}.cke_dialog_title{font-weight:bold;font-size:12px;cursor:move;position:relative;color:#484848;border-bottom:1px solid #d1d1d1;padding:12px 19px 12px 12px;background:#f8f8f8;letter-spacing:.3px}.cke_dialog_spinner{border-radius:50%;width:12px;height:12px;overflow:hidden;text-indent:-9999em;border:2px solid rgba(102,102,102,0.2);border-left-color:rgba(102,102,102,1);-webkit-animation:dialog_spinner 1s infinite linear;animation:dialog_spinner 1s infinite linear}.cke_browser_ie8 .cke_dialog_spinner,.cke_browser_ie9 .cke_dialog_spinner{background:url(images/spinner.gif) center top no-repeat;width:16px;height:16px;border:0}@-webkit-keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes dialog_spinner{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.cke_dialog_contents{background-color:#fff;overflow:auto;padding:15px 10px 5px 10px;margin-top:43px;border-top:1px solid #d1d1d1}.cke_dialog_contents_body{overflow:auto;padding:9px 10px 5px 10px;margin-top:22px}.cke_dialog_footer{text-align:right;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_rtl .cke_dialog_footer{text-align:left}.cke_hc .cke_dialog_footer{outline:0;border-top:1px solid #fff}.cke_dialog .cke_resizer{margin-top:22px}.cke_dialog .cke_resizer_rtl{margin-left:5px}.cke_dialog .cke_resizer_ltr{margin-right:5px}.cke_dialog_tabs{height:33px;display:inline-block;margin:9px 0 0;position:absolute;z-index:2;left:11px}.cke_rtl .cke_dialog_tabs{left:auto;right:11px}a.cke_dialog_tab{height:25px;padding:4px 8px;display:inline-block;cursor:pointer;line-height:26px;outline:0;color:#484848;border:1px solid #d1d1d1;border-radius:3px 3px 0 0;background:#f8f8f8;min-width:90px;text-align:center;margin-left:-1px;letter-spacing:.3px}a.cke_dialog_tab:hover{background-color:#fff}a.cke_dialog_tab:focus{border:2px solid #139ff7;border-bottom-color:#d1d1d1;padding:3px 7px;position:relative;z-index:1}a.cke_dialog_tab_selected{background:#fff;border-bottom-color:#fff;cursor:default;filter:none}a.cke_dialog_tab_selected:hover,a.cke_dialog_tab_selected:focus{border-bottom-color:#fff}.cke_hc a.cke_dialog_tab:hover,.cke_hc a.cke_dialog_tab:focus,.cke_hc a.cke_dialog_tab_selected{border:3px solid;padding:2px 6px}a.cke_dialog_tab_disabled{color:#bababa;cursor:default}.cke_single_page .cke_dialog_tabs{display:none}.cke_single_page .cke_dialog_contents{padding-top:5px;margin-top:0;border-top:0}a.cke_dialog_close_button{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:16px;width:16px;top:11px;z-index:5;opacity:.7;filter:alpha(opacity = 70)}.cke_rtl .cke_dialog_close_button{left:12px}.cke_ltr .cke_dialog_close_button{right:12px}.cke_hc a.cke_dialog_close_button{background-image:none}.cke_hidpi a.cke_dialog_close_button{background-image:url(images/hidpi/close.png);background-size:16px}a.cke_dialog_close_button:hover{opacity:1;filter:alpha(opacity = 100)}a.cke_dialog_close_button span{display:none}.cke_hc a.cke_dialog_close_button span{display:inline;cursor:pointer;font-weight:bold;position:relative;top:3px}div.cke_disabled .cke_dialog_ui_labeled_content div *{background-color:#ddd;cursor:default}.cke_dialog_ui_vbox table,.cke_dialog_ui_hbox table{margin:auto}.cke_dialog_ui_vbox_child{padding:5px 0}.cke_dialog_ui_hbox{width:100%;margin-top:12px}.cke_dialog_ui_hbox_first,.cke_dialog_ui_hbox_child,.cke_dialog_ui_hbox_last{vertical-align:top}.cke_ltr .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_ui_hbox_child{padding-right:10px}.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_child{padding-left:10px}.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_ltr .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-right:5px}.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_footer_buttons .cke_dialog_ui_hbox_child{padding-left:5px;padding-right:0}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:1px solid}textarea.cke_dialog_ui_input_textarea{overflow:auto;resize:none}input.cke_dialog_ui_input_text,input.cke_dialog_ui_input_password,textarea.cke_dialog_ui_input_textarea{background-color:#fff;border:1px solid #bcbcbc;padding:4px 6px;outline:0;width:100%;*width:95%;box-sizing:border-box;border-radius:2px;min-height:28px;margin-left:1px}input.cke_dialog_ui_input_text:hover,input.cke_dialog_ui_input_password:hover,textarea.cke_dialog_ui_input_textarea:hover{border:1px solid #aeb3b9}input.cke_dialog_ui_input_text:focus,input.cke_dialog_ui_input_password:focus,textarea.cke_dialog_ui_input_textarea:focus,select.cke_dialog_ui_input_select:focus{outline:0;border:2px solid #139ff7}input.cke_dialog_ui_input_text:focus{padding-left:5px}textarea.cke_dialog_ui_input_textarea:focus{padding:3px 5px}select.cke_dialog_ui_input_select:focus{margin:0;width:100%!important}input.cke_dialog_ui_checkbox_input,input.cke_dialog_ui_radio_input{margin-left:1px;margin-right:2px}input.cke_dialog_ui_checkbox_input:focus,input.cke_dialog_ui_checkbox_input:active,input.cke_dialog_ui_radio_input:focus,input.cke_dialog_ui_radio_input:active{border:0;outline:2px solid #139ff7}a.cke_dialog_ui_button{display:inline-block;*display:inline;*zoom:1;padding:4px 1px;margin:0;text-align:center;color:#484848;vertical-align:middle;cursor:pointer;border:1px solid #bcbcbc;border-radius:2px;background:#f8f8f8;letter-spacing:.3px;line-height:18px;box-sizing:border-box}.cke_hc a.cke_dialog_ui_button{border-width:3px}span.cke_dialog_ui_button{padding:0 10px;cursor:pointer}a.cke_dialog_ui_button:hover{background:#fff}a.cke_dialog_ui_button:focus,a.cke_dialog_ui_button:active{border:2px solid #139ff7;outline:0;padding:3px 0}.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button:focus,.cke_hc a.cke_dialog_ui_button:active{border:3px solid}.cke_dialog_footer_buttons a.cke_dialog_ui_button span{color:inherit;font-size:12px;font-weight:bold;padding:0 12px}a.cke_dialog_ui_button_ok{color:#fff;background:#09863e;border:1px solid #09863e}.cke_hc a.cke_dialog_ui_button{border:3px solid #bcbcbc}a.cke_dialog_ui_button_ok:hover{background:#53aa78;border-color:#53aa78}a.cke_dialog_ui_button_ok:focus{box-shadow:inset 0 0 0 2px #FFF}a.cke_dialog_ui_button_ok:focus,a.cke_dialog_ui_button_ok:active{border-color:#139ff7}.cke_hc a.cke_dialog_ui_button_ok:hover,.cke_hc a.cke_dialog_ui_button_ok:focus,.cke_hc a.cke_dialog_ui_button_ok:active{border-color:#484848}a.cke_dialog_ui_button_ok.cke_disabled{background:#d1d1d1;border-color:#d1d1d1;cursor:default}a.cke_dialog_ui_button_ok.cke_disabled span{cursor:default}.cke_dialog_footer_buttons{display:inline-table;margin:5px;width:auto;position:relative;vertical-align:middle}div.cke_dialog_ui_input_select{display:table}select.cke_dialog_ui_input_select{height:28px;line-height:28px;background-color:#fff;border:1px solid #bcbcbc;padding:3px 3px 3px 6px;outline:0;border-radius:2px;margin:0 1px;box-sizing:border-box;width:calc(100% - 2px)!important}.cke_dialog_ui_input_file{width:100%;height:25px}.cke_hc .cke_dialog_ui_labeled_content input:focus,.cke_hc .cke_dialog_ui_labeled_content select:focus,.cke_hc .cke_dialog_ui_labeled_content textarea:focus{outline:1px dotted}.cke_dialog_ui_labeled_label{margin-left:1px}.cke_dialog .cke_dark_background{background-color:transparent}.cke_dialog .cke_light_background{background-color:#ebebeb}.cke_dialog .cke_centered{text-align:center}.cke_dialog a.cke_btn_reset{float:right;background:url(images/refresh.png) top left no-repeat;width:16px;height:16px;border:1px none;font-size:1px}.cke_hidpi .cke_dialog a.cke_btn_reset{background-size:16px;background-image:url(images/hidpi/refresh.png)}.cke_rtl .cke_dialog a.cke_btn_reset{float:left}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked{float:left;width:16px;height:16px;background-repeat:no-repeat;border:none 1px;font-size:1px}.cke_dialog a.cke_btn_locked,.cke_dialog a.cke_btn_unlocked,.cke_dialog a.cke_btn_reset{margin:2px}.cke_dialog a.cke_btn_locked{background-image:url(images/lock.png)}.cke_dialog a.cke_btn_unlocked{background-image:url(images/lock-open.png)}.cke_rtl .cke_dialog a.cke_btn_locked,.cke_rtl .cke_dialog a.cke_btn_unlocked{float:right}.cke_hidpi .cke_dialog a.cke_btn_unlocked,.cke_hidpi .cke_dialog a.cke_btn_locked{background-size:16px}.cke_hidpi .cke_dialog a.cke_btn_locked{background-image:url(images/hidpi/lock.png)}.cke_hidpi .cke_dialog a.cke_btn_unlocked{background-image:url(images/hidpi/lock-open.png)}.cke_dialog a.cke_btn_locked .cke_icon{display:none}.cke_dialog a.cke_btn_over,.cke_dialog a.cke_btn_locked:hover,.cke_dialog a.cke_btn_locked:focus,.cke_dialog a.cke_btn_locked:active,.cke_dialog a.cke_btn_unlocked:hover,.cke_dialog a.cke_btn_unlocked:focus,.cke_dialog a.cke_btn_unlocked:active,.cke_dialog a.cke_btn_reset:hover,.cke_dialog a.cke_btn_reset:focus,.cke_dialog a.cke_btn_reset:active{cursor:pointer;outline:0;margin:0;border:2px solid #139ff7}.cke_dialog fieldset{border:1px solid #bcbcbc}.cke_dialog fieldset legend{padding:0 6px}.cke_dialog_ui_checkbox,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{display:inline-block}.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox{padding-top:5px}.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input,.cke_dialog fieldset .cke_dialog_ui_vbox .cke_dialog_ui_checkbox .cke_dialog_ui_checkbox_input+label{vertical-align:middle}.cke_dialog .ImagePreviewBox{border:1px ridge #bcbcbc;overflow:scroll;height:200px;width:300px;padding:2px;background-color:white}.cke_dialog .ImagePreviewBox table td{white-space:normal}.cke_dialog .ImagePreviewLoader{position:absolute;white-space:normal;overflow:hidden;height:160px;width:230px;margin:2px;padding:2px;opacity:.9;filter:alpha(opacity = 90);background-color:#e4e4e4}.cke_dialog .FlashPreviewBox{white-space:normal;border:1px solid #bcbcbc;overflow:auto;height:160px;width:390px;padding:2px;background-color:white}.cke_dialog .cke_pastetext{width:346px;height:170px}.cke_dialog .cke_pastetext textarea{width:340px;height:170px;resize:none}.cke_dialog iframe.cke_pasteframe{width:346px;height:130px;background-color:white;border:1px solid #aeb3b9;border-radius:3px}.cke_dialog .cke_hand{cursor:pointer}.cke_disabled{color:#a0a0a0}.cke_dialog_body .cke_label{display:none}.cke_dialog_body label{display:inline;cursor:default;letter-spacing:.3px}.cke_dialog_body label+.cke_dialog_ui_labeled_content{margin-top:2px}.cke_dialog_contents_body .cke_dialog_ui_text,.cke_dialog_contents_body .cke_dialog_ui_select,.cke_dialog_contents_body .cke_dialog_ui_hbox_last>a.cke_dialog_ui_button{margin-top:4px}a.cke_smile{overflow:hidden;display:block;text-align:center;padding:.3em 0}a.cke_smile img{vertical-align:middle}a.cke_specialchar{cursor:inherit;display:block;height:1.25em;padding:.2em .3em;text-align:center}a.cke_smile,a.cke_specialchar{border:2px solid transparent}a.cke_smile:hover,a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:hover,a.cke_specialchar:focus,a.cke_specialchar:active{background:#fff;outline:0}a.cke_smile:hover,a.cke_specialchar:hover{border-color:#888}a.cke_smile:focus,a.cke_smile:active,a.cke_specialchar:focus,a.cke_specialchar:active{border-color:#139ff7}.cke_dialog_contents a.colorChooser{display:block;margin-top:6px;margin-left:10px;width:80px}.cke_rtl .cke_dialog_contents a.colorChooser{margin-right:10px}.cke_iframe_shim{display:block;position:absolute;top:0;left:0;z-index:-1;filter:alpha(opacity = 0);width:100%;height:100%}.cke_dialog_contents_body .cke_accessibility_legend{margin:2px 7px 2px 2px}.cke_dialog_contents_body .cke_accessibility_legend:focus,.cke_dialog_contents_body .cke_accessibility_legend:active{outline:0;border:2px solid #139ff7;margin:0 5px 0 0}.cke_dialog_contents_body input[type=file]:focus,.cke_dialog_contents_body input[type=file]:active{border:2px solid #139ff7}.cke_dialog_find_fieldset{margin-top:10px!important}.cke_dialog_image_ratiolock{margin-top:52px!important}.cke_dialog_forms_select_order label.cke_dialog_ui_labeled_label{margin-left:0}.cke_dialog_forms_select_order div.cke_dialog_ui_input_select{width:100%}.cke_dialog_forms_select_order_txtsize .cke_dialog_ui_hbox_last{padding-top:4px}.cke_dialog_image_url .cke_dialog_ui_hbox_last,.cke_dialog_flash_url .cke_dialog_ui_hbox_last{vertical-align:bottom}a.cke_dialog_ui_button.cke_dialog_image_browse{margin-top:10px}.cke_dialog_contents_body .cke_tpl_list{border:#bcbcbc 1px solid;margin:1px}.cke_dialog_contents_body .cke_tpl_list:focus,.cke_dialog_contents_body .cke_tpl_list:active{outline:0;margin:0;border:2px solid #139ff7}.cke_dialog_contents_body .cke_tpl_list a:focus,.cke_dialog_contents_body .cke_tpl_list a:active{outline:0}.cke_dialog_contents_body .cke_tpl_list a:focus .cke_tpl_item,.cke_dialog_contents_body .cke_tpl_list a:active .cke_tpl_item{border:2px solid #139ff7;padding:6px}.cke_rtl input.cke_dialog_ui_input_text,.cke_rtl input.cke_dialog_ui_input_password{padding-right:2px}.cke_rtl div.cke_dialog_ui_input_text,.cke_rtl div.cke_dialog_ui_input_password{padding-left:2px}.cke_rtl div.cke_dialog_ui_input_text{padding-right:1px}.cke_rtl .cke_dialog_ui_vbox_child,.cke_rtl .cke_dialog_ui_hbox_child,.cke_rtl .cke_dialog_ui_hbox_first,.cke_rtl .cke_dialog_ui_hbox_last{padding-right:2px!important}.cke_hc .cke_dialog_title,.cke_hc .cke_dialog_footer,.cke_hc a.cke_dialog_tab,.cke_hc a.cke_dialog_ui_button,.cke_hc a.cke_dialog_ui_button:hover,.cke_hc a.cke_dialog_ui_button_ok,.cke_hc a.cke_dialog_ui_button_ok:hover{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_hc div.cke_dialog_ui_input_text,.cke_hc div.cke_dialog_ui_input_password,.cke_hc div.cke_dialog_ui_input_textarea,.cke_hc div.cke_dialog_ui_input_select,.cke_hc div.cke_dialog_ui_input_file{border:0}.cke_dialog_footer{filter:""} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/editor.css b/lib/redactor/ckeditor/skins/moono-lisa/editor.css new file mode 100644 index 0000000..9638ae8 --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/editor.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_button__about_icon {background: url(icons.png?t=20af917) no-repeat 0 -0px !important;}.cke_button__bold_icon {background: url(icons.png?t=20af917) no-repeat 0 -24px !important;}.cke_button__italic_icon {background: url(icons.png?t=20af917) no-repeat 0 -48px !important;}.cke_button__strike_icon {background: url(icons.png?t=20af917) no-repeat 0 -72px !important;}.cke_button__subscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -96px !important;}.cke_button__superscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -120px !important;}.cke_button__underline_icon {background: url(icons.png?t=20af917) no-repeat 0 -144px !important;}.cke_button__bidiltr_icon {background: url(icons.png?t=20af917) no-repeat 0 -168px !important;}.cke_button__bidirtl_icon {background: url(icons.png?t=20af917) no-repeat 0 -192px !important;}.cke_button__blockquote_icon {background: url(icons.png?t=20af917) no-repeat 0 -216px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -240px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -264px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -288px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -312px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -336px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -360px !important;}.cke_button__bgcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -384px !important;}.cke_button__textcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -408px !important;}.cke_rtl .cke_button__templates_icon, .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -432px !important;}.cke_ltr .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -456px !important;}.cke_button__copyformatting_icon {background: url(icons.png?t=20af917) no-repeat 0 -480px !important;}.cke_button__creatediv_icon {background: url(icons.png?t=20af917) no-repeat 0 -504px !important;}.cke_rtl .cke_button__find_icon, .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -528px !important;}.cke_ltr .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -552px !important;}.cke_button__replace_icon {background: url(icons.png?t=20af917) no-repeat 0 -576px !important;}.cke_button__flash_icon {background: url(icons.png?t=20af917) no-repeat 0 -600px !important;}.cke_button__button_icon {background: url(icons.png?t=20af917) no-repeat 0 -624px !important;}.cke_button__checkbox_icon {background: url(icons.png?t=20af917) no-repeat 0 -648px !important;}.cke_button__form_icon {background: url(icons.png?t=20af917) no-repeat 0 -672px !important;}.cke_button__hiddenfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -696px !important;}.cke_button__imagebutton_icon {background: url(icons.png?t=20af917) no-repeat 0 -720px !important;}.cke_button__radio_icon {background: url(icons.png?t=20af917) no-repeat 0 -744px !important;}.cke_rtl .cke_button__select_icon, .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -768px !important;}.cke_ltr .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -792px !important;}.cke_rtl .cke_button__textarea_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -816px !important;}.cke_ltr .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -840px !important;}.cke_rtl .cke_button__textfield_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -864px !important;}.cke_ltr .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -888px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=20af917) no-repeat 0 -912px !important;}.cke_button__iframe_icon {background: url(icons.png?t=20af917) no-repeat 0 -936px !important;}.cke_button__image_icon {background: url(icons.png?t=20af917) no-repeat 0 -960px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -984px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1008px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1032px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1056px !important;}.cke_button__smiley_icon {background: url(icons.png?t=20af917) no-repeat 0 -1080px !important;}.cke_button__justifyblock_icon {background: url(icons.png?t=20af917) no-repeat 0 -1104px !important;}.cke_button__justifycenter_icon {background: url(icons.png?t=20af917) no-repeat 0 -1128px !important;}.cke_button__justifyleft_icon {background: url(icons.png?t=20af917) no-repeat 0 -1152px !important;}.cke_button__justifyright_icon {background: url(icons.png?t=20af917) no-repeat 0 -1176px !important;}.cke_button__language_icon {background: url(icons.png?t=20af917) no-repeat 0 -1200px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1224px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1248px !important;}.cke_button__link_icon {background: url(icons.png?t=20af917) no-repeat 0 -1272px !important;}.cke_button__unlink_icon {background: url(icons.png?t=20af917) no-repeat 0 -1296px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1320px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1344px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1368px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1392px !important;}.cke_button__maximize_icon {background: url(icons.png?t=20af917) no-repeat 0 -1416px !important;}.cke_rtl .cke_button__newpage_icon, .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1440px !important;}.cke_ltr .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1464px !important;}.cke_rtl .cke_button__pagebreak_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1488px !important;}.cke_ltr .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1512px !important;}.cke_rtl .cke_button__pastetext_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1536px !important;}.cke_ltr .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1560px !important;}.cke_rtl .cke_button__pastefromword_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1584px !important;}.cke_ltr .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1608px !important;}.cke_rtl .cke_button__preview_icon, .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1632px !important;}.cke_ltr .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1656px !important;}.cke_button__print_icon {background: url(icons.png?t=20af917) no-repeat 0 -1680px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=20af917) no-repeat 0 -1704px !important;}.cke_button__save_icon {background: url(icons.png?t=20af917) no-repeat 0 -1728px !important;}.cke_button__selectall_icon {background: url(icons.png?t=20af917) no-repeat 0 -1752px !important;}.cke_rtl .cke_button__showblocks_icon, .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1776px !important;}.cke_ltr .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1800px !important;}.cke_rtl .cke_button__source_icon, .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1824px !important;}.cke_ltr .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1848px !important;}.cke_button__specialchar_icon {background: url(icons.png?t=20af917) no-repeat 0 -1872px !important;}.cke_button__scayt_icon {background: url(icons.png?t=20af917) no-repeat 0 -1896px !important;}.cke_button__table_icon {background: url(icons.png?t=20af917) no-repeat 0 -1920px !important;}.cke_rtl .cke_button__redo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1944px !important;}.cke_ltr .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1968px !important;}.cke_rtl .cke_button__undo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1992px !important;}.cke_ltr .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -2016px !important;}.cke_button__spellchecker_icon {background: url(icons.png?t=20af917) no-repeat 0 -2040px !important;}.cke_hidpi .cke_button__about_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidiltr_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidirtl_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_button__blockquote_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bgcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_button__textcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__templates_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__copyformatting_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_button__creatediv_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__find_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__replace_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__flash_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_hidpi .cke_button__button_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_button__checkbox_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -648px !important;background-size: 16px !important;}.cke_hidpi .cke_button__form_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -672px !important;background-size: 16px !important;}.cke_hidpi .cke_button__hiddenfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -696px !important;background-size: 16px !important;}.cke_hidpi .cke_button__imagebutton_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -720px !important;background-size: 16px !important;}.cke_hidpi .cke_button__radio_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -744px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__select_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -768px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -792px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textarea_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -816px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -840px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textfield_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -864px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -888px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -912px !important;background-size: 16px !important;}.cke_hidpi .cke_button__iframe_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -936px !important;background-size: 16px !important;}.cke_hidpi .cke_button__image_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -960px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -984px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1008px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1032px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1056px !important;background-size: 16px !important;}.cke_hidpi .cke_button__smiley_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1080px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyblock_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1104px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifycenter_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1128px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyleft_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1152px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyright_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1176px !important;background-size: 16px !important;}.cke_hidpi .cke_button__language_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1200px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1224px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1248px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1272px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1296px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1320px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1344px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1368px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1392px !important;background-size: 16px !important;}.cke_hidpi .cke_button__maximize_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1416px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__newpage_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1440px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1464px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1488px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1512px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastetext_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1536px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1560px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1584px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1608px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__preview_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1632px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1656px !important;background-size: 16px !important;}.cke_hidpi .cke_button__print_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1680px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1704px !important;background-size: 16px !important;}.cke_hidpi .cke_button__save_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1728px !important;background-size: 16px !important;}.cke_hidpi .cke_button__selectall_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1752px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__showblocks_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1776px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1800px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__source_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1824px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1848px !important;background-size: 16px !important;}.cke_hidpi .cke_button__specialchar_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1872px !important;background-size: 16px !important;}.cke_hidpi .cke_button__scayt_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1896px !important;background-size: 16px !important;}.cke_hidpi .cke_button__table_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1920px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__redo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1944px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1968px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__undo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1992px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2016px !important;background-size: 16px !important;}.cke_hidpi .cke_button__spellchecker_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2040px !important;background-size: 16px !important;} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/editor_gecko.css b/lib/redactor/ckeditor/skins/moono-lisa/editor_gecko.css new file mode 100644 index 0000000..7b02ed3 --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/editor_gecko.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}.cke_bottom{padding-bottom:3px}.cke_combo_text{margin-bottom:-1px;margin-top:1px}.cke_button__about_icon {background: url(icons.png?t=20af917) no-repeat 0 -0px !important;}.cke_button__bold_icon {background: url(icons.png?t=20af917) no-repeat 0 -24px !important;}.cke_button__italic_icon {background: url(icons.png?t=20af917) no-repeat 0 -48px !important;}.cke_button__strike_icon {background: url(icons.png?t=20af917) no-repeat 0 -72px !important;}.cke_button__subscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -96px !important;}.cke_button__superscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -120px !important;}.cke_button__underline_icon {background: url(icons.png?t=20af917) no-repeat 0 -144px !important;}.cke_button__bidiltr_icon {background: url(icons.png?t=20af917) no-repeat 0 -168px !important;}.cke_button__bidirtl_icon {background: url(icons.png?t=20af917) no-repeat 0 -192px !important;}.cke_button__blockquote_icon {background: url(icons.png?t=20af917) no-repeat 0 -216px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -240px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -264px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -288px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -312px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -336px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -360px !important;}.cke_button__bgcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -384px !important;}.cke_button__textcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -408px !important;}.cke_rtl .cke_button__templates_icon, .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -432px !important;}.cke_ltr .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -456px !important;}.cke_button__copyformatting_icon {background: url(icons.png?t=20af917) no-repeat 0 -480px !important;}.cke_button__creatediv_icon {background: url(icons.png?t=20af917) no-repeat 0 -504px !important;}.cke_rtl .cke_button__find_icon, .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -528px !important;}.cke_ltr .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -552px !important;}.cke_button__replace_icon {background: url(icons.png?t=20af917) no-repeat 0 -576px !important;}.cke_button__flash_icon {background: url(icons.png?t=20af917) no-repeat 0 -600px !important;}.cke_button__button_icon {background: url(icons.png?t=20af917) no-repeat 0 -624px !important;}.cke_button__checkbox_icon {background: url(icons.png?t=20af917) no-repeat 0 -648px !important;}.cke_button__form_icon {background: url(icons.png?t=20af917) no-repeat 0 -672px !important;}.cke_button__hiddenfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -696px !important;}.cke_button__imagebutton_icon {background: url(icons.png?t=20af917) no-repeat 0 -720px !important;}.cke_button__radio_icon {background: url(icons.png?t=20af917) no-repeat 0 -744px !important;}.cke_rtl .cke_button__select_icon, .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -768px !important;}.cke_ltr .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -792px !important;}.cke_rtl .cke_button__textarea_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -816px !important;}.cke_ltr .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -840px !important;}.cke_rtl .cke_button__textfield_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -864px !important;}.cke_ltr .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -888px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=20af917) no-repeat 0 -912px !important;}.cke_button__iframe_icon {background: url(icons.png?t=20af917) no-repeat 0 -936px !important;}.cke_button__image_icon {background: url(icons.png?t=20af917) no-repeat 0 -960px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -984px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1008px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1032px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1056px !important;}.cke_button__smiley_icon {background: url(icons.png?t=20af917) no-repeat 0 -1080px !important;}.cke_button__justifyblock_icon {background: url(icons.png?t=20af917) no-repeat 0 -1104px !important;}.cke_button__justifycenter_icon {background: url(icons.png?t=20af917) no-repeat 0 -1128px !important;}.cke_button__justifyleft_icon {background: url(icons.png?t=20af917) no-repeat 0 -1152px !important;}.cke_button__justifyright_icon {background: url(icons.png?t=20af917) no-repeat 0 -1176px !important;}.cke_button__language_icon {background: url(icons.png?t=20af917) no-repeat 0 -1200px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1224px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1248px !important;}.cke_button__link_icon {background: url(icons.png?t=20af917) no-repeat 0 -1272px !important;}.cke_button__unlink_icon {background: url(icons.png?t=20af917) no-repeat 0 -1296px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1320px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1344px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1368px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1392px !important;}.cke_button__maximize_icon {background: url(icons.png?t=20af917) no-repeat 0 -1416px !important;}.cke_rtl .cke_button__newpage_icon, .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1440px !important;}.cke_ltr .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1464px !important;}.cke_rtl .cke_button__pagebreak_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1488px !important;}.cke_ltr .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1512px !important;}.cke_rtl .cke_button__pastetext_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1536px !important;}.cke_ltr .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1560px !important;}.cke_rtl .cke_button__pastefromword_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1584px !important;}.cke_ltr .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1608px !important;}.cke_rtl .cke_button__preview_icon, .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1632px !important;}.cke_ltr .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1656px !important;}.cke_button__print_icon {background: url(icons.png?t=20af917) no-repeat 0 -1680px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=20af917) no-repeat 0 -1704px !important;}.cke_button__save_icon {background: url(icons.png?t=20af917) no-repeat 0 -1728px !important;}.cke_button__selectall_icon {background: url(icons.png?t=20af917) no-repeat 0 -1752px !important;}.cke_rtl .cke_button__showblocks_icon, .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1776px !important;}.cke_ltr .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1800px !important;}.cke_rtl .cke_button__source_icon, .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1824px !important;}.cke_ltr .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1848px !important;}.cke_button__specialchar_icon {background: url(icons.png?t=20af917) no-repeat 0 -1872px !important;}.cke_button__scayt_icon {background: url(icons.png?t=20af917) no-repeat 0 -1896px !important;}.cke_button__table_icon {background: url(icons.png?t=20af917) no-repeat 0 -1920px !important;}.cke_rtl .cke_button__redo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1944px !important;}.cke_ltr .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1968px !important;}.cke_rtl .cke_button__undo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1992px !important;}.cke_ltr .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -2016px !important;}.cke_button__spellchecker_icon {background: url(icons.png?t=20af917) no-repeat 0 -2040px !important;}.cke_hidpi .cke_button__about_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidiltr_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidirtl_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_button__blockquote_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bgcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_button__textcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__templates_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__copyformatting_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_button__creatediv_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__find_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__replace_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__flash_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_hidpi .cke_button__button_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_button__checkbox_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -648px !important;background-size: 16px !important;}.cke_hidpi .cke_button__form_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -672px !important;background-size: 16px !important;}.cke_hidpi .cke_button__hiddenfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -696px !important;background-size: 16px !important;}.cke_hidpi .cke_button__imagebutton_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -720px !important;background-size: 16px !important;}.cke_hidpi .cke_button__radio_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -744px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__select_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -768px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -792px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textarea_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -816px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -840px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textfield_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -864px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -888px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -912px !important;background-size: 16px !important;}.cke_hidpi .cke_button__iframe_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -936px !important;background-size: 16px !important;}.cke_hidpi .cke_button__image_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -960px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -984px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1008px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1032px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1056px !important;background-size: 16px !important;}.cke_hidpi .cke_button__smiley_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1080px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyblock_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1104px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifycenter_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1128px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyleft_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1152px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyright_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1176px !important;background-size: 16px !important;}.cke_hidpi .cke_button__language_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1200px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1224px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1248px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1272px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1296px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1320px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1344px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1368px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1392px !important;background-size: 16px !important;}.cke_hidpi .cke_button__maximize_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1416px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__newpage_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1440px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1464px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1488px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1512px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastetext_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1536px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1560px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1584px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1608px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__preview_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1632px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1656px !important;background-size: 16px !important;}.cke_hidpi .cke_button__print_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1680px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1704px !important;background-size: 16px !important;}.cke_hidpi .cke_button__save_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1728px !important;background-size: 16px !important;}.cke_hidpi .cke_button__selectall_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1752px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__showblocks_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1776px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1800px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__source_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1824px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1848px !important;background-size: 16px !important;}.cke_hidpi .cke_button__specialchar_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1872px !important;background-size: 16px !important;}.cke_hidpi .cke_button__scayt_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1896px !important;background-size: 16px !important;}.cke_hidpi .cke_button__table_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1920px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__redo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1944px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1968px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__undo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1992px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2016px !important;background-size: 16px !important;}.cke_hidpi .cke_button__spellchecker_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2040px !important;background-size: 16px !important;} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/editor_ie.css b/lib/redactor/ckeditor/skins/moono-lisa/editor_ie.css new file mode 100644 index 0000000..e839cfb --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/editor_ie.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_button__about_icon {background: url(icons.png?t=20af917) no-repeat 0 -0px !important;}.cke_button__bold_icon {background: url(icons.png?t=20af917) no-repeat 0 -24px !important;}.cke_button__italic_icon {background: url(icons.png?t=20af917) no-repeat 0 -48px !important;}.cke_button__strike_icon {background: url(icons.png?t=20af917) no-repeat 0 -72px !important;}.cke_button__subscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -96px !important;}.cke_button__superscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -120px !important;}.cke_button__underline_icon {background: url(icons.png?t=20af917) no-repeat 0 -144px !important;}.cke_button__bidiltr_icon {background: url(icons.png?t=20af917) no-repeat 0 -168px !important;}.cke_button__bidirtl_icon {background: url(icons.png?t=20af917) no-repeat 0 -192px !important;}.cke_button__blockquote_icon {background: url(icons.png?t=20af917) no-repeat 0 -216px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -240px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -264px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -288px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -312px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -336px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -360px !important;}.cke_button__bgcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -384px !important;}.cke_button__textcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -408px !important;}.cke_rtl .cke_button__templates_icon, .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -432px !important;}.cke_ltr .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -456px !important;}.cke_button__copyformatting_icon {background: url(icons.png?t=20af917) no-repeat 0 -480px !important;}.cke_button__creatediv_icon {background: url(icons.png?t=20af917) no-repeat 0 -504px !important;}.cke_rtl .cke_button__find_icon, .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -528px !important;}.cke_ltr .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -552px !important;}.cke_button__replace_icon {background: url(icons.png?t=20af917) no-repeat 0 -576px !important;}.cke_button__flash_icon {background: url(icons.png?t=20af917) no-repeat 0 -600px !important;}.cke_button__button_icon {background: url(icons.png?t=20af917) no-repeat 0 -624px !important;}.cke_button__checkbox_icon {background: url(icons.png?t=20af917) no-repeat 0 -648px !important;}.cke_button__form_icon {background: url(icons.png?t=20af917) no-repeat 0 -672px !important;}.cke_button__hiddenfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -696px !important;}.cke_button__imagebutton_icon {background: url(icons.png?t=20af917) no-repeat 0 -720px !important;}.cke_button__radio_icon {background: url(icons.png?t=20af917) no-repeat 0 -744px !important;}.cke_rtl .cke_button__select_icon, .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -768px !important;}.cke_ltr .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -792px !important;}.cke_rtl .cke_button__textarea_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -816px !important;}.cke_ltr .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -840px !important;}.cke_rtl .cke_button__textfield_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -864px !important;}.cke_ltr .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -888px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=20af917) no-repeat 0 -912px !important;}.cke_button__iframe_icon {background: url(icons.png?t=20af917) no-repeat 0 -936px !important;}.cke_button__image_icon {background: url(icons.png?t=20af917) no-repeat 0 -960px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -984px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1008px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1032px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1056px !important;}.cke_button__smiley_icon {background: url(icons.png?t=20af917) no-repeat 0 -1080px !important;}.cke_button__justifyblock_icon {background: url(icons.png?t=20af917) no-repeat 0 -1104px !important;}.cke_button__justifycenter_icon {background: url(icons.png?t=20af917) no-repeat 0 -1128px !important;}.cke_button__justifyleft_icon {background: url(icons.png?t=20af917) no-repeat 0 -1152px !important;}.cke_button__justifyright_icon {background: url(icons.png?t=20af917) no-repeat 0 -1176px !important;}.cke_button__language_icon {background: url(icons.png?t=20af917) no-repeat 0 -1200px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1224px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1248px !important;}.cke_button__link_icon {background: url(icons.png?t=20af917) no-repeat 0 -1272px !important;}.cke_button__unlink_icon {background: url(icons.png?t=20af917) no-repeat 0 -1296px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1320px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1344px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1368px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1392px !important;}.cke_button__maximize_icon {background: url(icons.png?t=20af917) no-repeat 0 -1416px !important;}.cke_rtl .cke_button__newpage_icon, .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1440px !important;}.cke_ltr .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1464px !important;}.cke_rtl .cke_button__pagebreak_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1488px !important;}.cke_ltr .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1512px !important;}.cke_rtl .cke_button__pastetext_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1536px !important;}.cke_ltr .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1560px !important;}.cke_rtl .cke_button__pastefromword_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1584px !important;}.cke_ltr .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1608px !important;}.cke_rtl .cke_button__preview_icon, .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1632px !important;}.cke_ltr .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1656px !important;}.cke_button__print_icon {background: url(icons.png?t=20af917) no-repeat 0 -1680px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=20af917) no-repeat 0 -1704px !important;}.cke_button__save_icon {background: url(icons.png?t=20af917) no-repeat 0 -1728px !important;}.cke_button__selectall_icon {background: url(icons.png?t=20af917) no-repeat 0 -1752px !important;}.cke_rtl .cke_button__showblocks_icon, .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1776px !important;}.cke_ltr .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1800px !important;}.cke_rtl .cke_button__source_icon, .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1824px !important;}.cke_ltr .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1848px !important;}.cke_button__specialchar_icon {background: url(icons.png?t=20af917) no-repeat 0 -1872px !important;}.cke_button__scayt_icon {background: url(icons.png?t=20af917) no-repeat 0 -1896px !important;}.cke_button__table_icon {background: url(icons.png?t=20af917) no-repeat 0 -1920px !important;}.cke_rtl .cke_button__redo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1944px !important;}.cke_ltr .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1968px !important;}.cke_rtl .cke_button__undo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1992px !important;}.cke_ltr .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -2016px !important;}.cke_button__spellchecker_icon {background: url(icons.png?t=20af917) no-repeat 0 -2040px !important;}.cke_hidpi .cke_button__about_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidiltr_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidirtl_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_button__blockquote_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bgcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_button__textcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__templates_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__copyformatting_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_button__creatediv_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__find_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__replace_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__flash_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_hidpi .cke_button__button_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_button__checkbox_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -648px !important;background-size: 16px !important;}.cke_hidpi .cke_button__form_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -672px !important;background-size: 16px !important;}.cke_hidpi .cke_button__hiddenfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -696px !important;background-size: 16px !important;}.cke_hidpi .cke_button__imagebutton_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -720px !important;background-size: 16px !important;}.cke_hidpi .cke_button__radio_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -744px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__select_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -768px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -792px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textarea_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -816px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -840px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textfield_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -864px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -888px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -912px !important;background-size: 16px !important;}.cke_hidpi .cke_button__iframe_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -936px !important;background-size: 16px !important;}.cke_hidpi .cke_button__image_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -960px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -984px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1008px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1032px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1056px !important;background-size: 16px !important;}.cke_hidpi .cke_button__smiley_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1080px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyblock_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1104px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifycenter_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1128px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyleft_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1152px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyright_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1176px !important;background-size: 16px !important;}.cke_hidpi .cke_button__language_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1200px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1224px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1248px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1272px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1296px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1320px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1344px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1368px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1392px !important;background-size: 16px !important;}.cke_hidpi .cke_button__maximize_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1416px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__newpage_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1440px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1464px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1488px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1512px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastetext_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1536px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1560px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1584px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1608px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__preview_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1632px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1656px !important;background-size: 16px !important;}.cke_hidpi .cke_button__print_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1680px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1704px !important;background-size: 16px !important;}.cke_hidpi .cke_button__save_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1728px !important;background-size: 16px !important;}.cke_hidpi .cke_button__selectall_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1752px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__showblocks_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1776px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1800px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__source_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1824px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1848px !important;background-size: 16px !important;}.cke_hidpi .cke_button__specialchar_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1872px !important;background-size: 16px !important;}.cke_hidpi .cke_button__scayt_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1896px !important;background-size: 16px !important;}.cke_hidpi .cke_button__table_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1920px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__redo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1944px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1968px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__undo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1992px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2016px !important;background-size: 16px !important;}.cke_hidpi .cke_button__spellchecker_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2040px !important;background-size: 16px !important;} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/editor_ie8.css b/lib/redactor/ckeditor/skins/moono-lisa/editor_ie8.css new file mode 100644 index 0000000..bc2e864 --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/editor_ie8.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_toolbox_collapser .cke_arrow{border-width:4px}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{border-width:3px}.cke_toolbox_collapser .cke_arrow{margin-top:0}.cke_toolbar{position:relative}.cke_rtl .cke_toolbar_end{right:auto;left:0}.cke_toolbar_end:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:1px;right:2px}.cke_rtl .cke_toolbar_end:after{right:auto;left:2px}.cke_hc .cke_toolbar_end:after{top:2px;right:5px;border-color:#000}.cke_hc.cke_rtl .cke_toolbar_end:after{right:auto;left:5px}.cke_combo+.cke_toolbar_end:after,.cke_toolbar.cke_toolbar_last .cke_toolbar_end:after{content:none;border:0}.cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:0}.cke_rtl .cke_combo+.cke_toolgroup+.cke_toolbar_end:after{right:auto;left:0}.cke_button__about_icon {background: url(icons.png?t=20af917) no-repeat 0 -0px !important;}.cke_button__bold_icon {background: url(icons.png?t=20af917) no-repeat 0 -24px !important;}.cke_button__italic_icon {background: url(icons.png?t=20af917) no-repeat 0 -48px !important;}.cke_button__strike_icon {background: url(icons.png?t=20af917) no-repeat 0 -72px !important;}.cke_button__subscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -96px !important;}.cke_button__superscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -120px !important;}.cke_button__underline_icon {background: url(icons.png?t=20af917) no-repeat 0 -144px !important;}.cke_button__bidiltr_icon {background: url(icons.png?t=20af917) no-repeat 0 -168px !important;}.cke_button__bidirtl_icon {background: url(icons.png?t=20af917) no-repeat 0 -192px !important;}.cke_button__blockquote_icon {background: url(icons.png?t=20af917) no-repeat 0 -216px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -240px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -264px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -288px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -312px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -336px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -360px !important;}.cke_button__bgcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -384px !important;}.cke_button__textcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -408px !important;}.cke_rtl .cke_button__templates_icon, .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -432px !important;}.cke_ltr .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -456px !important;}.cke_button__copyformatting_icon {background: url(icons.png?t=20af917) no-repeat 0 -480px !important;}.cke_button__creatediv_icon {background: url(icons.png?t=20af917) no-repeat 0 -504px !important;}.cke_rtl .cke_button__find_icon, .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -528px !important;}.cke_ltr .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -552px !important;}.cke_button__replace_icon {background: url(icons.png?t=20af917) no-repeat 0 -576px !important;}.cke_button__flash_icon {background: url(icons.png?t=20af917) no-repeat 0 -600px !important;}.cke_button__button_icon {background: url(icons.png?t=20af917) no-repeat 0 -624px !important;}.cke_button__checkbox_icon {background: url(icons.png?t=20af917) no-repeat 0 -648px !important;}.cke_button__form_icon {background: url(icons.png?t=20af917) no-repeat 0 -672px !important;}.cke_button__hiddenfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -696px !important;}.cke_button__imagebutton_icon {background: url(icons.png?t=20af917) no-repeat 0 -720px !important;}.cke_button__radio_icon {background: url(icons.png?t=20af917) no-repeat 0 -744px !important;}.cke_rtl .cke_button__select_icon, .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -768px !important;}.cke_ltr .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -792px !important;}.cke_rtl .cke_button__textarea_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -816px !important;}.cke_ltr .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -840px !important;}.cke_rtl .cke_button__textfield_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -864px !important;}.cke_ltr .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -888px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=20af917) no-repeat 0 -912px !important;}.cke_button__iframe_icon {background: url(icons.png?t=20af917) no-repeat 0 -936px !important;}.cke_button__image_icon {background: url(icons.png?t=20af917) no-repeat 0 -960px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -984px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1008px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1032px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1056px !important;}.cke_button__smiley_icon {background: url(icons.png?t=20af917) no-repeat 0 -1080px !important;}.cke_button__justifyblock_icon {background: url(icons.png?t=20af917) no-repeat 0 -1104px !important;}.cke_button__justifycenter_icon {background: url(icons.png?t=20af917) no-repeat 0 -1128px !important;}.cke_button__justifyleft_icon {background: url(icons.png?t=20af917) no-repeat 0 -1152px !important;}.cke_button__justifyright_icon {background: url(icons.png?t=20af917) no-repeat 0 -1176px !important;}.cke_button__language_icon {background: url(icons.png?t=20af917) no-repeat 0 -1200px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1224px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1248px !important;}.cke_button__link_icon {background: url(icons.png?t=20af917) no-repeat 0 -1272px !important;}.cke_button__unlink_icon {background: url(icons.png?t=20af917) no-repeat 0 -1296px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1320px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1344px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1368px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1392px !important;}.cke_button__maximize_icon {background: url(icons.png?t=20af917) no-repeat 0 -1416px !important;}.cke_rtl .cke_button__newpage_icon, .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1440px !important;}.cke_ltr .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1464px !important;}.cke_rtl .cke_button__pagebreak_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1488px !important;}.cke_ltr .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1512px !important;}.cke_rtl .cke_button__pastetext_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1536px !important;}.cke_ltr .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1560px !important;}.cke_rtl .cke_button__pastefromword_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1584px !important;}.cke_ltr .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1608px !important;}.cke_rtl .cke_button__preview_icon, .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1632px !important;}.cke_ltr .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1656px !important;}.cke_button__print_icon {background: url(icons.png?t=20af917) no-repeat 0 -1680px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=20af917) no-repeat 0 -1704px !important;}.cke_button__save_icon {background: url(icons.png?t=20af917) no-repeat 0 -1728px !important;}.cke_button__selectall_icon {background: url(icons.png?t=20af917) no-repeat 0 -1752px !important;}.cke_rtl .cke_button__showblocks_icon, .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1776px !important;}.cke_ltr .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1800px !important;}.cke_rtl .cke_button__source_icon, .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1824px !important;}.cke_ltr .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1848px !important;}.cke_button__specialchar_icon {background: url(icons.png?t=20af917) no-repeat 0 -1872px !important;}.cke_button__scayt_icon {background: url(icons.png?t=20af917) no-repeat 0 -1896px !important;}.cke_button__table_icon {background: url(icons.png?t=20af917) no-repeat 0 -1920px !important;}.cke_rtl .cke_button__redo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1944px !important;}.cke_ltr .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1968px !important;}.cke_rtl .cke_button__undo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1992px !important;}.cke_ltr .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -2016px !important;}.cke_button__spellchecker_icon {background: url(icons.png?t=20af917) no-repeat 0 -2040px !important;}.cke_hidpi .cke_button__about_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidiltr_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidirtl_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_button__blockquote_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bgcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_button__textcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__templates_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__copyformatting_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_button__creatediv_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__find_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__replace_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__flash_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_hidpi .cke_button__button_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_button__checkbox_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -648px !important;background-size: 16px !important;}.cke_hidpi .cke_button__form_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -672px !important;background-size: 16px !important;}.cke_hidpi .cke_button__hiddenfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -696px !important;background-size: 16px !important;}.cke_hidpi .cke_button__imagebutton_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -720px !important;background-size: 16px !important;}.cke_hidpi .cke_button__radio_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -744px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__select_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -768px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -792px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textarea_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -816px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -840px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textfield_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -864px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -888px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -912px !important;background-size: 16px !important;}.cke_hidpi .cke_button__iframe_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -936px !important;background-size: 16px !important;}.cke_hidpi .cke_button__image_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -960px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -984px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1008px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1032px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1056px !important;background-size: 16px !important;}.cke_hidpi .cke_button__smiley_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1080px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyblock_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1104px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifycenter_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1128px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyleft_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1152px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyright_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1176px !important;background-size: 16px !important;}.cke_hidpi .cke_button__language_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1200px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1224px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1248px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1272px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1296px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1320px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1344px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1368px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1392px !important;background-size: 16px !important;}.cke_hidpi .cke_button__maximize_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1416px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__newpage_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1440px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1464px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1488px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1512px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastetext_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1536px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1560px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1584px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1608px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__preview_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1632px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1656px !important;background-size: 16px !important;}.cke_hidpi .cke_button__print_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1680px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1704px !important;background-size: 16px !important;}.cke_hidpi .cke_button__save_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1728px !important;background-size: 16px !important;}.cke_hidpi .cke_button__selectall_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1752px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__showblocks_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1776px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1800px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__source_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1824px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1848px !important;background-size: 16px !important;}.cke_hidpi .cke_button__specialchar_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1872px !important;background-size: 16px !important;}.cke_hidpi .cke_button__scayt_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1896px !important;background-size: 16px !important;}.cke_hidpi .cke_button__table_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1920px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__redo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1944px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1968px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__undo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1992px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2016px !important;background-size: 16px !important;}.cke_hidpi .cke_button__spellchecker_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2040px !important;background-size: 16px !important;} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/editor_iequirks.css b/lib/redactor/ckeditor/skins/moono-lisa/editor_iequirks.css new file mode 100644 index 0000000..6f01aee --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/editor_iequirks.css @@ -0,0 +1,5 @@ +/* +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.md or http://ckeditor.com/license +*/ +.cke_reset{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none}.cke_reset_all,.cke_reset_all *,.cke_reset_all a,.cke_reset_all textarea{margin:0;padding:0;border:0;background:transparent;text-decoration:none;width:auto;height:auto;vertical-align:baseline;box-sizing:content-box;position:static;transition:none;border-collapse:collapse;font:normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;color:#000;text-align:left;white-space:nowrap;cursor:auto;float:none}.cke_reset_all .cke_rtl *{text-align:right}.cke_reset_all iframe{vertical-align:inherit}.cke_reset_all textarea{white-space:pre-wrap}.cke_reset_all textarea,.cke_reset_all input[type="text"],.cke_reset_all input[type="password"]{cursor:text}.cke_reset_all textarea[disabled],.cke_reset_all input[type="text"][disabled],.cke_reset_all input[type="password"][disabled]{cursor:default}.cke_reset_all fieldset{padding:10px;border:2px groove #e0dfe3}.cke_reset_all select{box-sizing:border-box}.cke_reset_all table{table-layout:auto}.cke_chrome{display:block;border:1px solid #d1d1d1;padding:0}.cke_inner{display:block;background:#fff;padding:0;-webkit-touch-callout:none}.cke_float{border:0}.cke_float .cke_inner{padding-bottom:0}.cke_top,.cke_contents,.cke_bottom{display:block;overflow:hidden}.cke_top{border-bottom:1px solid #d1d1d1;background:#f8f8f8;padding:6px 8px 2px;white-space:normal}.cke_float .cke_top{border:1px solid #d1d1d1}.cke_bottom{padding:6px 8px 2px;position:relative;border-top:1px solid #d1d1d1;background:#f8f8f8}.cke_browser_ios .cke_contents{overflow-y:auto;-webkit-overflow-scrolling:touch}.cke_resizer{width:0;height:0;overflow:hidden;border-width:10px 10px 0 0;border-color:transparent #bcbcbc transparent transparent;border-style:dashed solid dashed dashed;font-size:0;vertical-align:bottom;margin-top:6px;margin-bottom:2px}.cke_hc .cke_resizer{font-size:15px;width:auto;height:auto;border-width:0}.cke_resizer_ltr{cursor:se-resize;float:right;margin-right:-4px}.cke_resizer_rtl{border-width:10px 0 0 10px;border-color:transparent transparent transparent #bcbcbc;border-style:dashed dashed dashed solid;cursor:sw-resize;float:left;margin-left:-4px;right:auto}.cke_wysiwyg_div{display:block;height:100%;overflow:auto;padding:0 8px;outline-style:none;box-sizing:border-box}.cke_panel{visibility:visible;width:120px;height:100px;overflow:hidden;background-color:#fff;border:1px solid #d1d1d1}.cke_menu_panel{padding:0;margin:0}.cke_combopanel{width:150px;height:170px}.cke_panel_frame{width:100%;height:100%;font-size:12px;overflow:auto;overflow-x:hidden}.cke_panel_container{overflow-y:auto;overflow-x:hidden}.cke_panel_block:focus{outline:0}.cke_panel_list{margin:0;padding:0;list-style-type:none;white-space:nowrap}.cke_panel_listItem{margin:0;padding:0}.cke_panel_listItem a{padding:6px 7px;display:block;color:inherit!important;text-decoration:none;overflow:hidden;text-overflow:ellipsis}.cke_hc .cke_panel_listItem a{border-style:none}.cke_panel_listItem.cke_selected a,.cke_panel_listItem a:hover,.cke_panel_listItem a:focus,.cke_panel_listItem a:active{background-color:#e9e9e9}.cke_panel_listItem a:focus{outline:1px dotted #000}.cke_hc .cke_panel_listItem a:hover,.cke_hc .cke_panel_listItem a:focus,.cke_hc .cke_panel_listItem a:active{border:2px solid;padding:4px 5px}.cke_panel_listItem p,.cke_panel_listItem h1,.cke_panel_listItem h2,.cke_panel_listItem h3,.cke_panel_listItem h4,.cke_panel_listItem h5,.cke_panel_listItem h6,.cke_panel_listItem pre{margin-top:0;margin-bottom:0}.cke_panel_grouptitle{cursor:default;font-size:11px;font-weight:bold;white-space:nowrap;margin:0;padding:6px 6px 7px 6px;color:#484848;border-bottom:1px solid #d1d1d1;background:#f8f8f8}.cke_colorblock{padding:10px;font-size:11px;font-family:'Microsoft Sans Serif',Tahoma,Arial,Verdana,Sans-Serif}.cke_colorblock,.cke_colorblock a{text-decoration:none;color:#000}a.cke_colorbox{padding:2px;float:left;width:20px;height:20px}.cke_rtl a.cke_colorbox{float:right}a:hover.cke_colorbox,a:focus.cke_colorbox,a:active.cke_colorbox{outline:0;padding:0;border:2px solid #139ff7}a:hover.cke_colorbox{border-color:#bcbcbc}span.cke_colorbox{width:20px;height:20px;float:left}.cke_rtl span.cke_colorbox{float:right}a.cke_colorauto,a.cke_colormore{border:#fff 1px solid;padding:3px;display:block;cursor:pointer}a.cke_colorauto{padding:0;border:1px solid transparent;margin-bottom:6px;height:26px;line-height:26px}a.cke_colormore{margin-top:10px;height:20px;line-height:19px}a:hover.cke_colorauto,a:hover.cke_colormore,a:focus.cke_colorauto,a:focus.cke_colormore,a:active.cke_colorauto,a:active.cke_colormore{outline:0;border:#139ff7 1px solid;background-color:#f8f8f8}a:hover.cke_colorauto,a:hover.cke_colormore{border-color:#bcbcbc}.cke_colorauto span.cke_colorbox{width:18px;height:18px;border:1px solid #808080;margin-left:1px;margin-top:3px}.cke_rtl .cke_colorauto span.cke_colorbox{margin-left:0;margin-right:1px}span.cke_colorbox[style*="#ffffff"],span.cke_colorbox[style*="#FFFFFF"],span.cke_colorbox[style="background-color:#fff"],span.cke_colorbox[style="background-color:#FFF"],span.cke_colorbox[style*="rgb(255,255,255)"],span.cke_colorbox[style*="rgb(255, 255, 255)"]{border:1px solid #808080;width:18px;height:18px}.cke_toolbar{float:left}.cke_rtl .cke_toolbar{float:right}.cke_toolgroup{border:0;float:left;margin:1px 2px 6px 0;padding-right:3px}.cke_rtl .cke_toolgroup{float:right;margin:1px 0 6px 2px;padding-left:3px;padding-right:0}.cke_hc .cke_toolgroup{margin-right:5px;margin-bottom:5px}.cke_hc.cke_rtl .cke_toolgroup{margin-right:0;margin-left:5px}a.cke_button{display:inline-block;height:18px;padding:4px 6px;outline:0;cursor:default;float:left;border:0;position:relative}.cke_rtl a.cke_button{float:right}.cke_hc a.cke_button{border:1px solid black;padding:3px 5px;margin:0 3px 5px 0}.cke_hc.cke_rtl a.cke_button{margin:0 0 5px 3px}a.cke_button_on{background:#fff;border:1px #bcbcbc solid;padding:3px 5px}a.cke_button_off:hover,a.cke_button_off:focus,a.cke_button_off:active{background:#e5e5e5;border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active{background:#e5e5e5;border:3px solid #000;padding:1px 3px}a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{border:0;padding:4px 6px;background-color:transparent}a.cke_button_disabled:focus{border:1px #bcbcbc solid;padding:3px 5px}.cke_hc a.cke_button_disabled:hover,.cke_hc a.cke_button_disabled:focus,.cke_hc a.cke_button_disabled:active{border:1px solid #acacac;padding:3px 5px;margin:0 3px 5px 0}.cke_hc a.cke_button_disabled:focus{border:3px solid #000;padding:1px 3px}.cke_hc.cke_rtl a.cke_button_disabled:hover,.cke_hc.cke_rtl a.cke_button_disabled:focus,.cke_hc.cke_rtl a.cke_button_disabled:active{margin:0 0 5px 3px}a.cke_button_disabled .cke_button_icon,a.cke_button_disabled .cke_button_arrow{opacity:.3}.cke_hc a.cke_button_disabled{border-color:#acacac}.cke_hc a.cke_button_disabled .cke_button_icon,.cke_hc a.cke_button_disabled .cke_button_label{opacity:.5}.cke_toolgroup a.cke_button:last-child:after,.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:4px;top:0;right:-3px}.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-right:0;right:auto;border-left:1px solid #bcbcbc;top:0;left:-3px}.cke_hc .cke_toolgroup a.cke_button:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{border-color:#000;top:0;right:-7px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after{top:0;right:auto;left:-7px}.cke_toolgroup a.cke_button:hover:last-child:after,.cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:-4px}.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-1px;right:auto;left:-4px}.cke_hc .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:-9px}.cke_hc.cke_rtl .cke_toolgroup a.cke_button:hover:last-child:after,.cke_hc.cke_rtl .cke_toolgroup a.cke_button.cke_button_on:last-child:after{top:-2px;right:auto;left:-9px}.cke_toolbar.cke_toolbar_last .cke_toolgroup a.cke_button:last-child:after{content:none;border:0;width:0;height:0}.cke_button_icon{cursor:inherit;background-repeat:no-repeat;margin-top:1px;width:16px;height:16px;float:left;display:inline-block}.cke_rtl .cke_button_icon{float:right}.cke_hc .cke_button_icon{display:none}.cke_button_label{display:none;padding-left:3px;margin-top:1px;line-height:17px;vertical-align:middle;float:left;cursor:default;color:#484848}.cke_rtl .cke_button_label{padding-right:3px;padding-left:0;float:right}.cke_hc .cke_button_label{padding:0;display:inline-block;font-size:12px}.cke_button_arrow{display:inline-block;margin:8px 0 0 1px;width:0;height:0;cursor:default;vertical-align:top;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_rtl .cke_button_arrow{margin-right:5px;margin-left:0}.cke_hc .cke_button_arrow{font-size:10px;margin:3px 0 0 3px;width:auto;border:0}.cke_toolbar_separator{float:left;background-color:#bcbcbc;margin:4px 2px 0 2px;height:18px;width:1px}.cke_rtl .cke_toolbar_separator{float:right}.cke_hc .cke_toolbar_separator{background-color:#000;margin-left:2px;margin-right:5px;margin-bottom:9px}.cke_hc.cke_rtl .cke_toolbar_separator{margin-left:5px;margin-right:2px}.cke_toolbar_break{display:block;clear:left}.cke_rtl .cke_toolbar_break{clear:right}a.cke_toolbox_collapser{width:12px;height:11px;float:right;margin:11px 0 0;font-size:0;cursor:default;text-align:center;border:1px solid #bcbcbc}.cke_rtl .cke_toolbox_collapser{float:left}.cke_toolbox_collapser:hover{background:#e5e5e5}.cke_toolbox_collapser.cke_toolbox_collapser_min{margin:0 2px 4px}.cke_toolbox_collapser .cke_arrow{display:inline-block;height:0;width:0;font-size:0;margin-top:1px;border:3px solid transparent;border-bottom-color:#484848}.cke_toolbox_collapser.cke_toolbox_collapser_min .cke_arrow{margin-top:4px;border-bottom-color:transparent;border-top-color:#484848}.cke_hc .cke_toolbox_collapser .cke_arrow{font-size:8px;width:auto;border:0;margin-top:0}.cke_menuitem span{cursor:default}.cke_menubutton{display:block}.cke_hc .cke_menubutton{padding:2px}.cke_menubutton:hover,.cke_menubutton:focus,.cke_menubutton:active{background-color:#e9e9e9;display:block;outline:1px dotted}.cke_menubutton:hover{outline:0}.cke_hc .cke_menubutton:hover,.cke_hc .cke_menubutton:focus,.cke_hc .cke_menubutton:active{border:2px solid;padding:0}.cke_menubutton_disabled:hover,.cke_menubutton_disabled:focus,.cke_menubutton_disabled:active{background-color:transparent;outline:0}.cke_menubutton_inner{display:table-row}.cke_menubutton_icon,.cke_menubutton_label,.cke_menuarrow{display:table-cell}.cke_menubutton_icon{background-color:#f8f8f8;padding:6px 4px}.cke_hc .cke_menubutton_icon{height:16px;width:0;padding:4px 0}.cke_menubutton:hover .cke_menubutton_icon,.cke_menubutton:focus .cke_menubutton_icon,.cke_menubutton:active .cke_menubutton_icon{background-color:#e9e9e9}.cke_menubutton_disabled:hover .cke_menubutton_icon,.cke_menubutton_disabled:focus .cke_menubutton_icon,.cke_menubutton_disabled:active .cke_menubutton_icon{background-color:#f8f8f8;outline:0}.cke_menuitem .cke_menubutton_on{background-color:#e9e9e9;border:1px solid #dedede;outline:0}.cke_menubutton_on .cke_menubutton_icon{padding-right:3px;background-color:#e9e9e9}.cke_menubutton_label{padding:0 5px;background-color:transparent;width:100%;vertical-align:middle}.cke_menubutton_shortcut{color:#979797}.cke_menubutton_disabled .cke_menubutton_label{opacity:.3;filter:alpha(opacity=30)}.cke_panel_frame .cke_menubutton_label{display:none}.cke_menuseparator{background-color:#d1d1d1;height:1px}.cke_menuarrow{background:transparent url(images/arrow.png) no-repeat 0 10px;padding:0 5px}.cke_rtl .cke_menuarrow{background-position:5px -13px;background-repeat:no-repeat}.cke_hc .cke_menuarrow{background-image:none}.cke_menuarrow span{display:none}.cke_hc .cke_menuarrow span{vertical-align:middle;display:inline}.cke_combo{display:inline-block;float:left;position:relative;margin-bottom:5px}.cke_rtl .cke_combo{float:right}.cke_hc .cke_combo{margin-top:1px;margin-bottom:10px}.cke_combo:after{content:"";position:absolute;height:18px;width:0;border-right:1px solid #bcbcbc;margin-top:5px;top:0;right:0}.cke_rtl .cke_combo:after{border-right:0;border-left:1px solid #bcbcbc;right:auto;left:0}.cke_hc .cke_combo:after{border-color:#000}a.cke_combo_button{cursor:default;display:inline-block;float:left;margin:0;padding:1px}.cke_rtl a.cke_combo_button{float:right}.cke_hc a.cke_combo_button{padding:4px}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:hover,.cke_combo_off a.cke_combo_button:focus,.cke_combo_off a.cke_combo_button:active{background:#e5e5e5;border:1px solid #bcbcbc;padding:0 0 0 1px;margin-left:-1px}.cke_combo_off a.cke_combo_button:focus{outline:0}.cke_combo_on a.cke_combo_button,.cke_combo_off a.cke_combo_button:active{background:#fff}.cke_rtl .cke_combo_on a.cke_combo_button,.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:0 1px 0 0;margin-left:0;margin-right:-1px}.cke_hc .cke_combo_on a.cke_combo_button,.cke_hc .cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_combo_off a.cke_combo_button:active{border:3px solid #000;padding:1px 1px 1px 2px}.cke_hc.cke_rtl .cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_combo_off a.cke_combo_button:active{padding:1px 2px 1px 1px}.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 0 0 3px;margin-left:-3px}.cke_rtl .cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_rtl .cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0 3px 0 0;margin-left:0;margin-right:-3px}.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 1px 1px 7px;margin-left:-6px}.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc.cke_rtl .cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px 7px 1px 1px;margin-left:0;margin-right:-6px}.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:0;margin:0}.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbox .cke_toolbar:first-child>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_on a.cke_combo_button,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:hover,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:focus,.cke_hc .cke_toolbar_break+.cke_toolbar>.cke_toolbar_start+.cke_combo_off a.cke_combo_button:active{padding:1px;margin:0}.cke_toolbar .cke_combo+.cke_toolbar_end,.cke_toolbar .cke_combo+.cke_toolgroup{margin-right:0;margin-left:2px}.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:2px}.cke_hc .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:5px}.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolbar_end,.cke_hc.cke_rtl .cke_toolbar .cke_combo+.cke_toolgroup{margin-left:0;margin-right:5px}.cke_toolbar.cke_toolbar_last .cke_combo:nth-last-child(-n+2):after{content:none;border:0;width:0;height:0}.cke_combo_text{line-height:26px;padding-left:10px;text-overflow:ellipsis;overflow:hidden;float:left;cursor:default;color:#484848;width:60px}.cke_rtl .cke_combo_text{float:right;text-align:right;padding-left:0;padding-right:10px}.cke_hc .cke_combo_text{line-height:18px;font-size:12px}.cke_combo_open{cursor:default;display:inline-block;font-size:0;height:19px;line-height:17px;margin:1px 10px 1px;width:5px}.cke_hc .cke_combo_open{height:12px}.cke_combo_arrow{cursor:default;margin:11px 0 0;float:left;height:0;width:0;font-size:0;border-left:3px solid transparent;border-right:3px solid transparent;border-top:3px solid #484848}.cke_hc .cke_combo_arrow{font-size:10px;width:auto;border:0;margin-top:3px}.cke_combo_label{display:none;float:left;line-height:26px;vertical-align:top;margin-right:5px}.cke_rtl .cke_combo_label{float:right;margin-left:5px;margin-right:0}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{opacity:.3}.cke_path{float:left;margin:-2px 0 2px}a.cke_path_item,span.cke_path_empty{display:inline-block;float:left;padding:3px 4px;margin-right:2px;cursor:default;text-decoration:none;outline:0;border:0;color:#484848;font-weight:bold;font-size:11px}.cke_rtl .cke_path,.cke_rtl .cke_path_item,.cke_rtl .cke_path_empty{float:right}a.cke_path_item:hover,a.cke_path_item:focus,a.cke_path_item:active{background-color:#e5e5e5}.cke_hc a.cke_path_item:hover,.cke_hc a.cke_path_item:focus,.cke_hc a.cke_path_item:active{border:2px solid;padding:1px 2px}.cke_button__source_label,.cke_button__sourcedialog_label{display:inline}.cke_combopanel__fontsize{width:135px}textarea.cke_source{font-family:'Courier New',Monospace;font-size:small;background-color:#fff;white-space:pre-wrap;border:0;padding:0;margin:0;display:block}.cke_wysiwyg_frame,.cke_wysiwyg_div{background-color:#fff}.cke_notifications_area{pointer-events:none}.cke_notification{pointer-events:auto;position:relative;margin:10px;width:300px;color:white;text-align:center;opacity:.95;filter:alpha(opacity = 95);-webkit-animation:fadeIn .7s;animation:fadeIn .7s}.cke_notification_message a{color:#12306f}@-webkit-keyframes fadeIn{from{opacity:.4}to{opacity:.95}}@keyframes fadeIn{from{opacity:.4}to{opacity:.95}}.cke_notification_success{background:#72b572;border:1px solid #63a563}.cke_notification_warning{background:#c83939;border:1px solid #902b2b}.cke_notification_info{background:#2e9ad0;border:1px solid #0f74a8}.cke_notification_info span.cke_notification_progress{background-color:#0f74a8;display:block;padding:0;margin:0;height:100%;overflow:hidden;position:absolute;z-index:1}.cke_notification_message{position:relative;margin:4px 23px 3px;font-family:Arial,Helvetica,sans-serif;font-size:12px;line-height:18px;z-index:4;text-overflow:ellipsis;overflow:hidden}.cke_notification_close{background-image:url(images/close.png);background-repeat:no-repeat;background-position:50%;position:absolute;cursor:pointer;text-align:center;height:20px;width:20px;top:1px;right:1px;padding:0;margin:0;z-index:5;opacity:.6;filter:alpha(opacity = 60)}.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_notification_close span{display:none}.cke_notification_warning a.cke_notification_close{opacity:.8;filter:alpha(opacity = 80)}.cke_notification_warning a.cke_notification_close:hover{opacity:1;filter:alpha(opacity = 100)}.cke_chrome{visibility:inherit}.cke_voice_label{display:none}legend.cke_voice_label{display:none}a.cke_button_disabled,a.cke_button_disabled:hover,a.cke_button_disabled:focus,a.cke_button_disabled:active{filter:alpha(opacity = 30)}.cke_button_disabled .cke_button_icon{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#00ffffff,endColorstr=#00ffffff)}.cke_button_off:hover,.cke_button_off:focus,.cke_button_off:active{filter:alpha(opacity = 100)}.cke_combo_disabled .cke_combo_inlinelabel,.cke_combo_disabled .cke_combo_open{filter:alpha(opacity = 30)}.cke_toolbox_collapser{border:1px solid #a6a6a6}.cke_toolbox_collapser .cke_arrow{margin-top:1px}.cke_hc .cke_top,.cke_hc .cke_bottom,.cke_hc .cke_combo_button,.cke_hc a.cke_combo_button:hover,.cke_hc a.cke_combo_button:focus,.cke_hc .cke_toolgroup,.cke_hc .cke_button_on,.cke_hc a.cke_button_off:hover,.cke_hc a.cke_button_off:focus,.cke_hc a.cke_button_off:active,.cke_hc .cke_toolbox_collapser,.cke_hc .cke_toolbox_collapser:hover,.cke_hc .cke_panel_grouptitle{filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.cke_top,.cke_contents,.cke_bottom{width:100%}.cke_button_arrow{font-size:0}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_button,.cke_rtl .cke_button *,.cke_rtl .cke_combo,.cke_rtl .cke_combo *,.cke_rtl .cke_path_item,.cke_rtl .cke_path_item *,.cke_rtl .cke_path_empty{float:none}.cke_rtl .cke_toolgroup,.cke_rtl .cke_toolbar_separator,.cke_rtl .cke_combo_button,.cke_rtl .cke_combo_button *,.cke_rtl .cke_button,.cke_rtl .cke_button_icon{display:inline-block;vertical-align:top}.cke_rtl .cke_button_icon{float:none}.cke_resizer{width:10px}.cke_source{white-space:normal}.cke_bottom{position:static}.cke_colorbox{font-size:0}.cke_button__about_icon {background: url(icons.png?t=20af917) no-repeat 0 -0px !important;}.cke_button__bold_icon {background: url(icons.png?t=20af917) no-repeat 0 -24px !important;}.cke_button__italic_icon {background: url(icons.png?t=20af917) no-repeat 0 -48px !important;}.cke_button__strike_icon {background: url(icons.png?t=20af917) no-repeat 0 -72px !important;}.cke_button__subscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -96px !important;}.cke_button__superscript_icon {background: url(icons.png?t=20af917) no-repeat 0 -120px !important;}.cke_button__underline_icon {background: url(icons.png?t=20af917) no-repeat 0 -144px !important;}.cke_button__bidiltr_icon {background: url(icons.png?t=20af917) no-repeat 0 -168px !important;}.cke_button__bidirtl_icon {background: url(icons.png?t=20af917) no-repeat 0 -192px !important;}.cke_button__blockquote_icon {background: url(icons.png?t=20af917) no-repeat 0 -216px !important;}.cke_rtl .cke_button__copy_icon, .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -240px !important;}.cke_ltr .cke_button__copy_icon {background: url(icons.png?t=20af917) no-repeat 0 -264px !important;}.cke_rtl .cke_button__cut_icon, .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -288px !important;}.cke_ltr .cke_button__cut_icon {background: url(icons.png?t=20af917) no-repeat 0 -312px !important;}.cke_rtl .cke_button__paste_icon, .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -336px !important;}.cke_ltr .cke_button__paste_icon {background: url(icons.png?t=20af917) no-repeat 0 -360px !important;}.cke_button__bgcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -384px !important;}.cke_button__textcolor_icon {background: url(icons.png?t=20af917) no-repeat 0 -408px !important;}.cke_rtl .cke_button__templates_icon, .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -432px !important;}.cke_ltr .cke_button__templates_icon {background: url(icons.png?t=20af917) no-repeat 0 -456px !important;}.cke_button__copyformatting_icon {background: url(icons.png?t=20af917) no-repeat 0 -480px !important;}.cke_button__creatediv_icon {background: url(icons.png?t=20af917) no-repeat 0 -504px !important;}.cke_rtl .cke_button__find_icon, .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -528px !important;}.cke_ltr .cke_button__find_icon {background: url(icons.png?t=20af917) no-repeat 0 -552px !important;}.cke_button__replace_icon {background: url(icons.png?t=20af917) no-repeat 0 -576px !important;}.cke_button__flash_icon {background: url(icons.png?t=20af917) no-repeat 0 -600px !important;}.cke_button__button_icon {background: url(icons.png?t=20af917) no-repeat 0 -624px !important;}.cke_button__checkbox_icon {background: url(icons.png?t=20af917) no-repeat 0 -648px !important;}.cke_button__form_icon {background: url(icons.png?t=20af917) no-repeat 0 -672px !important;}.cke_button__hiddenfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -696px !important;}.cke_button__imagebutton_icon {background: url(icons.png?t=20af917) no-repeat 0 -720px !important;}.cke_button__radio_icon {background: url(icons.png?t=20af917) no-repeat 0 -744px !important;}.cke_rtl .cke_button__select_icon, .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -768px !important;}.cke_ltr .cke_button__select_icon {background: url(icons.png?t=20af917) no-repeat 0 -792px !important;}.cke_rtl .cke_button__textarea_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -816px !important;}.cke_ltr .cke_button__textarea_icon {background: url(icons.png?t=20af917) no-repeat 0 -840px !important;}.cke_rtl .cke_button__textfield_icon, .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -864px !important;}.cke_ltr .cke_button__textfield_icon {background: url(icons.png?t=20af917) no-repeat 0 -888px !important;}.cke_button__horizontalrule_icon {background: url(icons.png?t=20af917) no-repeat 0 -912px !important;}.cke_button__iframe_icon {background: url(icons.png?t=20af917) no-repeat 0 -936px !important;}.cke_button__image_icon {background: url(icons.png?t=20af917) no-repeat 0 -960px !important;}.cke_rtl .cke_button__indent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -984px !important;}.cke_ltr .cke_button__indent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1008px !important;}.cke_rtl .cke_button__outdent_icon, .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1032px !important;}.cke_ltr .cke_button__outdent_icon {background: url(icons.png?t=20af917) no-repeat 0 -1056px !important;}.cke_button__smiley_icon {background: url(icons.png?t=20af917) no-repeat 0 -1080px !important;}.cke_button__justifyblock_icon {background: url(icons.png?t=20af917) no-repeat 0 -1104px !important;}.cke_button__justifycenter_icon {background: url(icons.png?t=20af917) no-repeat 0 -1128px !important;}.cke_button__justifyleft_icon {background: url(icons.png?t=20af917) no-repeat 0 -1152px !important;}.cke_button__justifyright_icon {background: url(icons.png?t=20af917) no-repeat 0 -1176px !important;}.cke_button__language_icon {background: url(icons.png?t=20af917) no-repeat 0 -1200px !important;}.cke_rtl .cke_button__anchor_icon, .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1224px !important;}.cke_ltr .cke_button__anchor_icon {background: url(icons.png?t=20af917) no-repeat 0 -1248px !important;}.cke_button__link_icon {background: url(icons.png?t=20af917) no-repeat 0 -1272px !important;}.cke_button__unlink_icon {background: url(icons.png?t=20af917) no-repeat 0 -1296px !important;}.cke_rtl .cke_button__bulletedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1320px !important;}.cke_ltr .cke_button__bulletedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1344px !important;}.cke_rtl .cke_button__numberedlist_icon, .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1368px !important;}.cke_ltr .cke_button__numberedlist_icon {background: url(icons.png?t=20af917) no-repeat 0 -1392px !important;}.cke_button__maximize_icon {background: url(icons.png?t=20af917) no-repeat 0 -1416px !important;}.cke_rtl .cke_button__newpage_icon, .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1440px !important;}.cke_ltr .cke_button__newpage_icon {background: url(icons.png?t=20af917) no-repeat 0 -1464px !important;}.cke_rtl .cke_button__pagebreak_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1488px !important;}.cke_ltr .cke_button__pagebreak_icon {background: url(icons.png?t=20af917) no-repeat 0 -1512px !important;}.cke_rtl .cke_button__pastetext_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1536px !important;}.cke_ltr .cke_button__pastetext_icon {background: url(icons.png?t=20af917) no-repeat 0 -1560px !important;}.cke_rtl .cke_button__pastefromword_icon, .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1584px !important;}.cke_ltr .cke_button__pastefromword_icon {background: url(icons.png?t=20af917) no-repeat 0 -1608px !important;}.cke_rtl .cke_button__preview_icon, .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1632px !important;}.cke_ltr .cke_button__preview_icon {background: url(icons.png?t=20af917) no-repeat 0 -1656px !important;}.cke_button__print_icon {background: url(icons.png?t=20af917) no-repeat 0 -1680px !important;}.cke_button__removeformat_icon {background: url(icons.png?t=20af917) no-repeat 0 -1704px !important;}.cke_button__save_icon {background: url(icons.png?t=20af917) no-repeat 0 -1728px !important;}.cke_button__selectall_icon {background: url(icons.png?t=20af917) no-repeat 0 -1752px !important;}.cke_rtl .cke_button__showblocks_icon, .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1776px !important;}.cke_ltr .cke_button__showblocks_icon {background: url(icons.png?t=20af917) no-repeat 0 -1800px !important;}.cke_rtl .cke_button__source_icon, .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1824px !important;}.cke_ltr .cke_button__source_icon {background: url(icons.png?t=20af917) no-repeat 0 -1848px !important;}.cke_button__specialchar_icon {background: url(icons.png?t=20af917) no-repeat 0 -1872px !important;}.cke_button__scayt_icon {background: url(icons.png?t=20af917) no-repeat 0 -1896px !important;}.cke_button__table_icon {background: url(icons.png?t=20af917) no-repeat 0 -1920px !important;}.cke_rtl .cke_button__redo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1944px !important;}.cke_ltr .cke_button__redo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1968px !important;}.cke_rtl .cke_button__undo_icon, .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -1992px !important;}.cke_ltr .cke_button__undo_icon {background: url(icons.png?t=20af917) no-repeat 0 -2016px !important;}.cke_button__spellchecker_icon {background: url(icons.png?t=20af917) no-repeat 0 -2040px !important;}.cke_hidpi .cke_button__about_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -0px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bold_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -24px !important;background-size: 16px !important;}.cke_hidpi .cke_button__italic_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -48px !important;background-size: 16px !important;}.cke_hidpi .cke_button__strike_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -72px !important;background-size: 16px !important;}.cke_hidpi .cke_button__subscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -96px !important;background-size: 16px !important;}.cke_hidpi .cke_button__superscript_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -120px !important;background-size: 16px !important;}.cke_hidpi .cke_button__underline_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -144px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidiltr_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -168px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bidirtl_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -192px !important;background-size: 16px !important;}.cke_hidpi .cke_button__blockquote_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -216px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__copy_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -240px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__copy_icon,.cke_ltr.cke_hidpi .cke_button__copy_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -264px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__cut_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -288px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__cut_icon,.cke_ltr.cke_hidpi .cke_button__cut_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -312px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__paste_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -336px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__paste_icon,.cke_ltr.cke_hidpi .cke_button__paste_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -360px !important;background-size: 16px !important;}.cke_hidpi .cke_button__bgcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -384px !important;background-size: 16px !important;}.cke_hidpi .cke_button__textcolor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -408px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__templates_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -432px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__templates_icon,.cke_ltr.cke_hidpi .cke_button__templates_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -456px !important;background-size: 16px !important;}.cke_hidpi .cke_button__copyformatting_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -480px !important;background-size: 16px !important;}.cke_hidpi .cke_button__creatediv_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -504px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__find_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -528px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__find_icon,.cke_ltr.cke_hidpi .cke_button__find_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -552px !important;background-size: 16px !important;}.cke_hidpi .cke_button__replace_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -576px !important;background-size: 16px !important;}.cke_hidpi .cke_button__flash_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -600px !important;background-size: 16px !important;}.cke_hidpi .cke_button__button_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -624px !important;background-size: 16px !important;}.cke_hidpi .cke_button__checkbox_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -648px !important;background-size: 16px !important;}.cke_hidpi .cke_button__form_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -672px !important;background-size: 16px !important;}.cke_hidpi .cke_button__hiddenfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -696px !important;background-size: 16px !important;}.cke_hidpi .cke_button__imagebutton_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -720px !important;background-size: 16px !important;}.cke_hidpi .cke_button__radio_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -744px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__select_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -768px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__select_icon,.cke_ltr.cke_hidpi .cke_button__select_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -792px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textarea_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -816px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textarea_icon,.cke_ltr.cke_hidpi .cke_button__textarea_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -840px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__textfield_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -864px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__textfield_icon,.cke_ltr.cke_hidpi .cke_button__textfield_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -888px !important;background-size: 16px !important;}.cke_hidpi .cke_button__horizontalrule_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -912px !important;background-size: 16px !important;}.cke_hidpi .cke_button__iframe_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -936px !important;background-size: 16px !important;}.cke_hidpi .cke_button__image_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -960px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__indent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -984px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__indent_icon,.cke_ltr.cke_hidpi .cke_button__indent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1008px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__outdent_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1032px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__outdent_icon,.cke_ltr.cke_hidpi .cke_button__outdent_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1056px !important;background-size: 16px !important;}.cke_hidpi .cke_button__smiley_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1080px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyblock_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1104px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifycenter_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1128px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyleft_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1152px !important;background-size: 16px !important;}.cke_hidpi .cke_button__justifyright_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1176px !important;background-size: 16px !important;}.cke_hidpi .cke_button__language_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1200px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__anchor_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1224px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__anchor_icon,.cke_ltr.cke_hidpi .cke_button__anchor_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1248px !important;background-size: 16px !important;}.cke_hidpi .cke_button__link_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1272px !important;background-size: 16px !important;}.cke_hidpi .cke_button__unlink_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1296px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__bulletedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1320px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__bulletedlist_icon,.cke_ltr.cke_hidpi .cke_button__bulletedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1344px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__numberedlist_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1368px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__numberedlist_icon,.cke_ltr.cke_hidpi .cke_button__numberedlist_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1392px !important;background-size: 16px !important;}.cke_hidpi .cke_button__maximize_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1416px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__newpage_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1440px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__newpage_icon,.cke_ltr.cke_hidpi .cke_button__newpage_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1464px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pagebreak_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1488px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pagebreak_icon,.cke_ltr.cke_hidpi .cke_button__pagebreak_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1512px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastetext_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1536px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastetext_icon,.cke_ltr.cke_hidpi .cke_button__pastetext_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1560px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__pastefromword_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1584px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__pastefromword_icon,.cke_ltr.cke_hidpi .cke_button__pastefromword_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1608px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__preview_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1632px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__preview_icon,.cke_ltr.cke_hidpi .cke_button__preview_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1656px !important;background-size: 16px !important;}.cke_hidpi .cke_button__print_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1680px !important;background-size: 16px !important;}.cke_hidpi .cke_button__removeformat_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1704px !important;background-size: 16px !important;}.cke_hidpi .cke_button__save_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1728px !important;background-size: 16px !important;}.cke_hidpi .cke_button__selectall_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1752px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__showblocks_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1776px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__showblocks_icon,.cke_ltr.cke_hidpi .cke_button__showblocks_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1800px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__source_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1824px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__source_icon,.cke_ltr.cke_hidpi .cke_button__source_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1848px !important;background-size: 16px !important;}.cke_hidpi .cke_button__specialchar_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1872px !important;background-size: 16px !important;}.cke_hidpi .cke_button__scayt_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1896px !important;background-size: 16px !important;}.cke_hidpi .cke_button__table_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1920px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__redo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1944px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__redo_icon,.cke_ltr.cke_hidpi .cke_button__redo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1968px !important;background-size: 16px !important;}.cke_rtl.cke_hidpi .cke_button__undo_icon, .cke_hidpi .cke_mixed_dir_content .cke_rtl .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -1992px !important;background-size: 16px !important;}.cke_hidpi .cke_ltr .cke_button__undo_icon,.cke_ltr.cke_hidpi .cke_button__undo_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2016px !important;background-size: 16px !important;}.cke_hidpi .cke_button__spellchecker_icon {background: url(icons_hidpi.png?t=20af917) no-repeat 0 -2040px !important;background-size: 16px !important;} \ No newline at end of file diff --git a/lib/redactor/ckeditor/skins/moono-lisa/icons.png b/lib/redactor/ckeditor/skins/moono-lisa/icons.png new file mode 100644 index 0000000..958eedc Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/icons.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/icons_hidpi.png b/lib/redactor/ckeditor/skins/moono-lisa/icons_hidpi.png new file mode 100644 index 0000000..7b06991 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/icons_hidpi.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/arrow.png b/lib/redactor/ckeditor/skins/moono-lisa/images/arrow.png new file mode 100644 index 0000000..d72b5f3 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/arrow.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/close.png b/lib/redactor/ckeditor/skins/moono-lisa/images/close.png new file mode 100644 index 0000000..40caa6d Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/close.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/close.png b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/close.png new file mode 100644 index 0000000..fa00f4f Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/close.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/lock-open.png b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/lock-open.png new file mode 100644 index 0000000..c899789 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/lock-open.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/lock.png b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/lock.png new file mode 100644 index 0000000..25ad0f4 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/lock.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/refresh.png b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/refresh.png new file mode 100644 index 0000000..117a2d4 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/hidpi/refresh.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/lock-open.png b/lib/redactor/ckeditor/skins/moono-lisa/images/lock-open.png new file mode 100644 index 0000000..42df5f4 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/lock-open.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/lock.png b/lib/redactor/ckeditor/skins/moono-lisa/images/lock.png new file mode 100644 index 0000000..bde6772 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/lock.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/refresh.png b/lib/redactor/ckeditor/skins/moono-lisa/images/refresh.png new file mode 100644 index 0000000..e363764 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/refresh.png differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/images/spinner.gif b/lib/redactor/ckeditor/skins/moono-lisa/images/spinner.gif new file mode 100644 index 0000000..d898d41 Binary files /dev/null and b/lib/redactor/ckeditor/skins/moono-lisa/images/spinner.gif differ diff --git a/lib/redactor/ckeditor/skins/moono-lisa/readme.md b/lib/redactor/ckeditor/skins/moono-lisa/readme.md new file mode 100644 index 0000000..7ed4c78 --- /dev/null +++ b/lib/redactor/ckeditor/skins/moono-lisa/readme.md @@ -0,0 +1,46 @@ +"Moono-lisa" Skin +================= + +This skin has been made a **default skin** starting from CKEditor 4.6.0 and is maintained by the core developers. + +For more information about skins, please check the [CKEditor Skin SDK](http://docs.cksource.com/CKEditor_4.x/Skin_SDK) +documentation. + +Features +------------------- +"Moono-lisa" is a monochromatic skin, which offers a modern, flat and minimalistic look which blends very well in modern design. +It comes with the following features: + +- Chameleon feature with brightness. +- High-contrast compatibility. +- Graphics source provided in SVG. + +Directory Structure +------------------- + +CSS parts: +- **editor.css**: the main CSS file. It's simply loading several other files, for easier maintenance, +- **mainui.css**: the file contains styles of entire editor outline structures, +- **toolbar.css**: the file contains styles of the editor toolbar space (top), +- **richcombo.css**: the file contains styles of the rich combo ui elements on toolbar, +- **panel.css**: the file contains styles of the rich combo drop-down, it's not loaded +until the first panel open up, +- **elementspath.css**: the file contains styles of the editor elements path bar (bottom), +- **menu.css**: the file contains styles of all editor menus including context menu and button drop-down, +it's not loaded until the first menu open up, +- **dialog.css**: the CSS files for the dialog UI, it's not loaded until the first dialog open, +- **reset.css**: the file defines the basis of style resets among all editor UI spaces, +- **preset.css**: the file defines the default styles of some UI elements reflecting the skin preference, +- **editor_XYZ.css** and **dialog_XYZ.css**: browser specific CSS hacks. + +Other parts: +- **skin.js**: the only JavaScript part of the skin that registers the skin, its browser specific files and its icons and defines the Chameleon feature, +- **images/**: contains a fill general used images, +- **dev/**: contains SVG and PNG source of the skin icons. + +License +------- + +Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + +For licensing, see LICENSE.md or [http://ckeditor.com/license](http://ckeditor.com/license) diff --git a/lib/redactor/ckeditor/styles.js b/lib/redactor/ckeditor/styles.js new file mode 100644 index 0000000..e1cd4d4 --- /dev/null +++ b/lib/redactor/ckeditor/styles.js @@ -0,0 +1,137 @@ +/** + * Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or http://ckeditor.com/license + */ + +// This file contains style definitions that can be used by CKEditor plugins. +// +// The most common use for it is the "stylescombo" plugin which shows the Styles drop-down +// list containing all styles in the editor toolbar. Other plugins, like +// the "div" plugin, use a subset of the styles for their features. +// +// If you do not have plugins that depend on this file in your editor build, you can simply +// ignore it. Otherwise it is strongly recommended to customize this file to match your +// website requirements and design properly. +// +// For more information refer to: http://docs.ckeditor.com/#!/guide/dev_styles-section-style-rules + +CKEDITOR.stylesSet.add( 'default', [ + /* Block styles */ + + // These styles are already available in the "Format" drop-down list ("format" plugin), + // so they are not needed here by default. You may enable them to avoid + // placing the "Format" combo in the toolbar, maintaining the same features. + /* + { name: 'Paragraph', element: 'p' }, + { name: 'Heading 1', element: 'h1' }, + { name: 'Heading 2', element: 'h2' }, + { name: 'Heading 3', element: 'h3' }, + { name: 'Heading 4', element: 'h4' }, + { name: 'Heading 5', element: 'h5' }, + { name: 'Heading 6', element: 'h6' }, + { name: 'Preformatted Text',element: 'pre' }, + { name: 'Address', element: 'address' }, + */ + + { name: 'Italic Title', element: 'h2', styles: { 'font-style': 'italic' } }, + { name: 'Subtitle', element: 'h3', styles: { 'color': '#aaa', 'font-style': 'italic' } }, + { + name: 'Special Container', + element: 'div', + styles: { + padding: '5px 10px', + background: '#eee', + border: '1px solid #ccc' + } + }, + + /* Inline styles */ + + // These are core styles available as toolbar buttons. You may opt enabling + // some of them in the Styles drop-down list, removing them from the toolbar. + // (This requires the "stylescombo" plugin.) + /* + { name: 'Strong', element: 'strong', overrides: 'b' }, + { name: 'Emphasis', element: 'em' , overrides: 'i' }, + { name: 'Underline', element: 'u' }, + { name: 'Strikethrough', element: 'strike' }, + { name: 'Subscript', element: 'sub' }, + { name: 'Superscript', element: 'sup' }, + */ + + { name: 'Marker', element: 'span', attributes: { 'class': 'marker' } }, + + { name: 'Big', element: 'big' }, + { name: 'Small', element: 'small' }, + { name: 'Typewriter', element: 'tt' }, + + { name: 'Computer Code', element: 'code' }, + { name: 'Keyboard Phrase', element: 'kbd' }, + { name: 'Sample Text', element: 'samp' }, + { name: 'Variable', element: 'var' }, + + { name: 'Deleted Text', element: 'del' }, + { name: 'Inserted Text', element: 'ins' }, + + { name: 'Cited Work', element: 'cite' }, + { name: 'Inline Quotation', element: 'q' }, + + { name: 'Language: RTL', element: 'span', attributes: { 'dir': 'rtl' } }, + { name: 'Language: LTR', element: 'span', attributes: { 'dir': 'ltr' } }, + + /* Object styles */ + + { + name: 'Styled Image (left)', + element: 'img', + attributes: { 'class': 'left' } + }, + + { + name: 'Styled Image (right)', + element: 'img', + attributes: { 'class': 'right' } + }, + + { + name: 'Compact Table', + element: 'table', + attributes: { + cellpadding: '5', + cellspacing: '0', + border: '1', + bordercolor: '#ccc' + }, + styles: { + 'border-collapse': 'collapse' + } + }, + + { name: 'Borderless Table', element: 'table', styles: { 'border-style': 'hidden', 'background-color': '#E6E6FA' } }, + { name: 'Square Bulleted List', element: 'ul', styles: { 'list-style-type': 'square' } }, + + /* Widget styles */ + + { name: 'Clean Image', type: 'widget', widget: 'image', attributes: { 'class': 'image-clean' } }, + { name: 'Grayscale Image', type: 'widget', widget: 'image', attributes: { 'class': 'image-grayscale' } }, + + { name: 'Featured Snippet', type: 'widget', widget: 'codeSnippet', attributes: { 'class': 'code-featured' } }, + + { name: 'Featured Formula', type: 'widget', widget: 'mathjax', attributes: { 'class': 'math-featured' } }, + + { name: '240p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-240p' }, group: 'size' }, + { name: '360p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-360p' }, group: 'size' }, + { name: '480p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-480p' }, group: 'size' }, + { name: '720p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-720p' }, group: 'size' }, + { name: '1080p', type: 'widget', widget: 'embedSemantic', attributes: { 'class': 'embed-1080p' }, group: 'size' }, + + // Adding space after the style name is an intended workaround. For now, there + // is no option to create two styles with the same name for different widget types. See #16664. + { name: '240p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-240p' }, group: 'size' }, + { name: '360p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-360p' }, group: 'size' }, + { name: '480p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-480p' }, group: 'size' }, + { name: '720p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-720p' }, group: 'size' }, + { name: '1080p ', type: 'widget', widget: 'embed', attributes: { 'class': 'embed-1080p' }, group: 'size' } + +] ); + diff --git a/lib/redactor/ckeditor/sysblock.js b/lib/redactor/ckeditor/sysblock.js new file mode 100644 index 0000000..a61ac38 --- /dev/null +++ b/lib/redactor/ckeditor/sysblock.js @@ -0,0 +1,192 @@ +CKEDITOR.editorConfig = function( config ) { + + + CKEDITOR.dtd.$removeEmpty.span = 0; + CKEDITOR.dtd.$removeEmpty.i = 0; + CKEDITOR.dtd.$removeEmpty.div = 0; + CKEDITOR.dtd.$removeEmpty.em = 0; + CKEDITOR.dtd.$removeEmpty.b = 0; + + config.removePlugins = 'scayt'; + + config.extraPlugins = 'codemirror,placeholder,savedocs'; + + config.protectedSource.push(/<\?[\s\S]*?\?>/g); // PHP code + config.protectedSource.push(/<%[\s\S]*?%>/g); // ASP code + config.protectedSource.push(/(]+>[\s|\S]*?<\/asp:[^\>]+>)|(]+\/>)/gi); // ASP.Net code + + config.language = 'ru'; + + config.emailProtection = 'mt(NAME,DOMAIN,SUBJECT,BODY)'; + + config.toolbarCanCollapse = true; + config.disableNativeSpellChecker = false; + config.scayt_autoStartup = false; + + config.autoParagraph = false; + config.autoUpdateElement = true; + + config.enterMode = CKEDITOR.ENTER_BR; + config.shiftEnterMode = CKEDITOR.ENTER_P; + + config.startupMode = 'source'; + + config.toolbarStartupExpanded = true; + + config.allowedContent = true; + + config.autoGrow_minHeight = 300; + + config.toolbar_Big = [{ + name: 'document', + groups: ['mode', 'document', 'doctools'], + items: ['Source', '-', 'searchCode','autoFormat','CommentSelectedRange','UncommentSelectedRange','AutoComplete', 'Save'] + }, { + name: 'clipboard', + groups: ['clipboard', 'undo'], + items: ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo'] + }, { + name: 'editing', + groups: ['find', 'selection', 'spellchecker'], + items: ['Find', 'Replace', '-', 'SelectAll'] + }, { + name: 'forms', + items: ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'] + }, + '/', { + name: 'basicstyles', + groups: ['basicstyles', 'cleanup'], + items: ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat'] + }, { + name: 'paragraph', + groups: ['list', 'indent', 'blocks', 'align', 'bidi'], + items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl'] + }, { + name: 'links', + items: ['Link', 'Unlink', 'Anchor'] + }, { + name: 'insert', + items: ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe'] + }, + '/', { + name: 'styles', + items: ['Styles', 'Format', 'Font', 'FontSize'] + }, { + name: 'colors', + items: ['TextColor', 'BGColor'] + }, { + name: 'tools', + items: ['Maximize', 'ShowBlocks'] + }, { + name: 'texttransform', + items: ['TransformTextToUppercase', 'TransformTextToLowercase', 'TransformTextCapitalize', 'TransformTextSwitcher'] + }, { + name: 'about', + items: ['About'] + } + ]; + + config.codemirror = { + + // Set this to the theme you wish to use (codemirror themes) + theme: 'default', + + // Whether or not you want to show line numbers + lineNumbers: true, + + // Whether or not you want to use line wrapping + lineWrapping: true, + + // Whether or not you want to highlight matching braces + matchBrackets: true, + + // Whether or not you want to highlight matching tags + matchTags: true, + + // Whether or not you want tags to automatically close themselves + autoCloseTags: true, + + // Whether or not you want Brackets to automatically close themselves + autoCloseBrackets: true, + + // Whether or not to enable search tools, CTRL+F (Find), CTRL+SHIFT+F (Replace), CTRL+SHIFT+R (Replace All), CTRL+G (Find Next), CTRL+SHIFT+G (Find Previous) + enableSearchTools: true, + + // Whether or not you wish to enable code folding (requires 'lineNumbers' to be set to 'true') + enableCodeFolding: true, + + // Whether or not to enable code formatting + enableCodeFormatting: true, + + // Whether or not to automatically format code should be done when the editor is loaded + autoFormatOnStart: false, + + autoFormatOnModeChange: false, + + // Whether or not to automatically format code which has just been uncommented + autoFormatOnUncomment: true, + + // Whether or not to highlight the currently active line + highlightActiveLine: true, + + // Whether or not to highlight all matches of current word/selection + highlightMatches: true, + + // Define the language specific mode 'htmlmixed' for html including (css, xml, javascript), 'application/x-httpd-php' for php mode including html, or 'text/javascript' for using java script only + mode: 'application/x-httpd-php', + + // Whether or not to show the search Code button on the toolbar + showSearchButton: true, + + // Whether or not to show Trailing Spaces + showTrailingSpace: true, + + // Whether or not to show the format button on the toolbar + showFormatButton: true, + + // Whether or not to show the comment button on the toolbar + showCommentButton: true, + + // Whether or not to show the uncomment button on the toolbar + showUncommentButton: true, + + // Whether or not to show the showAutoCompleteButton button on the toolbar + showAutoCompleteButton: true + }; + + + config.filebrowserBrowseUrl = '../../../../admin/index.php?do=browser&type=link&mode=fck&target=txtUrl'; + config.filebrowserImageBrowseUrl = '../../../../admin/index.php?do=browser&type=image&mode=fck&target=txtUrl'; + config.filebrowserLinkBrowseUrl = '../../../../admin/index.php?do=docs&action=showsimple&selecturl=1&target=txtUrl&pop=1'; + + config.removeDialogTabs = 'link:upload;image:Upload'; + + config.keystrokes = + [ + [CKEDITOR.ALT + 121 /*F10*/ , 'toolbarFocus'], + [CKEDITOR.ALT + 122 /*F11*/ , 'elementsPathFocus'], + + [CKEDITOR.SHIFT + 121 /*F10*/ , 'contextMenu'], + + [CKEDITOR.CTRL + 90 /*Z*/ , 'undo'], + [CKEDITOR.CTRL + 89 /*Y*/ , 'redo'], + [CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/ , 'redo'], + + [CKEDITOR.CTRL + 76 /*L*/ , 'link'], + + [CKEDITOR.CTRL + 66 /*B*/ , 'bold'], + [CKEDITOR.CTRL + 73 /*I*/ , 'italic'], + [CKEDITOR.CTRL + 85 /*U*/ , 'underline'], + + [CKEDITOR.ALT + 109 /*-*/ , 'toolbarCollapse'] + ]; + + config.forcePasteAsPlainText = true; +}; + +CKEDITOR.on('instanceReady', function(ev) { + ev.editor.on('paste', function(evt) { + evt.data.dataValue = evt.data.dataValue.replace(/ /g,' '); + evt.data.dataValue = evt.data.dataValue.replace(/

      <\/p>/g,' '); + }, null, null, 9); +}); \ No newline at end of file diff --git a/lib/redactor/codemirror/addon/comment/comment.js b/lib/redactor/codemirror/addon/comment/comment.js new file mode 100644 index 0000000..8394e85 --- /dev/null +++ b/lib/redactor/codemirror/addon/comment/comment.js @@ -0,0 +1,209 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var noOptions = {}; + var nonWS = /[^\s\u00a0]/; + var Pos = CodeMirror.Pos; + + function firstNonWS(str) { + var found = str.search(nonWS); + return found == -1 ? 0 : found; + } + + CodeMirror.commands.toggleComment = function(cm) { + cm.toggleComment(); + }; + + CodeMirror.defineExtension("toggleComment", function(options) { + if (!options) options = noOptions; + var cm = this; + var minLine = Infinity, ranges = this.listSelections(), mode = null; + for (var i = ranges.length - 1; i >= 0; i--) { + var from = ranges[i].from(), to = ranges[i].to(); + if (from.line >= minLine) continue; + if (to.line >= minLine) to = Pos(minLine, 0); + minLine = from.line; + if (mode == null) { + if (cm.uncomment(from, to, options)) mode = "un"; + else { cm.lineComment(from, to, options); mode = "line"; } + } else if (mode == "un") { + cm.uncomment(from, to, options); + } else { + cm.lineComment(from, to, options); + } + } + }); + + // Rough heuristic to try and detect lines that are part of multi-line string + function probablyInsideString(cm, pos, line) { + return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line) + } + + function getMode(cm, pos) { + var mode = cm.getMode() + return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos) + } + + CodeMirror.defineExtension("lineComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = getMode(self, from); + var firstLine = self.getLine(from.line); + if (firstLine == null || probablyInsideString(self, from, firstLine)) return; + + var commentString = options.lineComment || mode.lineComment; + if (!commentString) { + if (options.blockCommentStart || mode.blockCommentStart) { + options.fullLines = true; + self.blockComment(from, to, options); + } + return; + } + + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); + var pad = options.padding == null ? " " : options.padding; + var blankLines = options.commentBlankLines || from.line == to.line; + + self.operation(function() { + if (options.indent) { + var baseString = null; + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i); + var whitespace = line.slice(0, firstNonWS(line)); + if (baseString == null || baseString.length > whitespace.length) { + baseString = whitespace; + } + } + for (var i = from.line; i < end; ++i) { + var line = self.getLine(i), cut = baseString.length; + if (!blankLines && !nonWS.test(line)) continue; + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); + } + } else { + for (var i = from.line; i < end; ++i) { + if (blankLines || nonWS.test(self.getLine(i))) + self.replaceRange(commentString + pad, Pos(i, 0)); + } + } + }); + }); + + CodeMirror.defineExtension("blockComment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = getMode(self, from); + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) { + if ((options.lineComment || mode.lineComment) && options.fullLines != false) + self.lineComment(from, to, options); + return; + } + if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return + + var end = Math.min(to.line, self.lastLine()); + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; + + var pad = options.padding == null ? " " : options.padding; + if (from.line > end) return; + + self.operation(function() { + if (options.fullLines != false) { + var lastLineHasText = nonWS.test(self.getLine(end)); + self.replaceRange(pad + endString, Pos(end)); + self.replaceRange(startString + pad, Pos(from.line, 0)); + var lead = options.blockCommentLead || mode.blockCommentLead; + if (lead != null) for (var i = from.line + 1; i <= end; ++i) + if (i != end || lastLineHasText) + self.replaceRange(lead + pad, Pos(i, 0)); + } else { + self.replaceRange(endString, to); + self.replaceRange(startString, from); + } + }); + }); + + CodeMirror.defineExtension("uncomment", function(from, to, options) { + if (!options) options = noOptions; + var self = this, mode = getMode(self, from); + var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); + + // Try finding line comments + var lineString = options.lineComment || mode.lineComment, lines = []; + var pad = options.padding == null ? " " : options.padding, didSomething; + lineComment: { + if (!lineString) break lineComment; + for (var i = start; i <= end; ++i) { + var line = self.getLine(i); + var found = line.indexOf(lineString); + if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; + if (found == -1 && nonWS.test(line)) break lineComment; + if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; + lines.push(line); + } + self.operation(function() { + for (var i = start; i <= end; ++i) { + var line = lines[i - start]; + var pos = line.indexOf(lineString), endPos = pos + lineString.length; + if (pos < 0) continue; + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; + didSomething = true; + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); + } + }); + if (didSomething) return true; + } + + // Try block comments + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) return false; + var lead = options.blockCommentLead || mode.blockCommentLead; + var startLine = self.getLine(start), open = startLine.indexOf(startString) + if (open == -1) return false + var endLine = end == start ? startLine : self.getLine(end) + var close = endLine.indexOf(endString, end == start ? open + startString.length : 0); + var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1) + if (close == -1 || + !/comment/.test(self.getTokenTypeAt(insideStart)) || + !/comment/.test(self.getTokenTypeAt(insideEnd)) || + self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1) + return false; + + // Avoid killing block comments completely outside the selection. + // Positions of the last startString before the start of the selection, and the first endString after it. + var lastStart = startLine.lastIndexOf(startString, from.ch); + var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); + if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; + // Positions of the first endString after the end of the selection, and the last startString before it. + firstEnd = endLine.indexOf(endString, to.ch); + var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); + lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; + if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; + + self.operation(function() { + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), + Pos(end, close + endString.length)); + var openEnd = open + startString.length; + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); + if (lead) for (var i = start + 1; i <= end; ++i) { + var line = self.getLine(i), found = line.indexOf(lead); + if (found == -1 || nonWS.test(line.slice(0, found))) continue; + var foundEnd = found + lead.length; + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); + } + }); + return true; + }); +}); diff --git a/lib/redactor/codemirror/addon/comment/continuecomment.js b/lib/redactor/codemirror/addon/comment/continuecomment.js new file mode 100644 index 0000000..7ca1b4a --- /dev/null +++ b/lib/redactor/codemirror/addon/comment/continuecomment.js @@ -0,0 +1,114 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var nonspace = /\S/g; + var repeat = String.prototype.repeat || function (n) { return Array(n + 1).join(this); }; + function continueComment(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), mode, inserts = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head + if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass; + var modeHere = cm.getModeAt(pos) + if (!mode) mode = modeHere; + else if (mode != modeHere) return CodeMirror.Pass; + + var insert = null, line, found; + var blockStart = mode.blockCommentStart, lineCmt = mode.lineComment; + if (blockStart && mode.blockCommentContinue) { + line = cm.getLine(pos.line); + var end = line.lastIndexOf(mode.blockCommentEnd, pos.ch - mode.blockCommentEnd.length); + // 1. if this block comment ended + // 2. if this is actually inside a line comment + if (end != -1 && end == pos.ch - mode.blockCommentEnd.length || + lineCmt && (found = line.lastIndexOf(lineCmt, pos.ch - 1)) > -1 && + /\bcomment\b/.test(cm.getTokenTypeAt({line: pos.line, ch: found + 1}))) { + // ...then don't continue it + } else if (pos.ch >= blockStart.length && + (found = line.lastIndexOf(blockStart, pos.ch - blockStart.length)) > -1 && + found > end) { + // reuse the existing leading spaces/tabs/mixed + // or build the correct indent using CM's tab/indent options + if (nonspaceAfter(0, line) >= found) { + insert = line.slice(0, found); + } else { + var tabSize = cm.options.tabSize, numTabs; + found = CodeMirror.countColumn(line, found, tabSize); + insert = !cm.options.indentWithTabs ? repeat.call(" ", found) : + repeat.call("\t", (numTabs = Math.floor(found / tabSize))) + + repeat.call(" ", found - tabSize * numTabs); + } + } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 && + found <= pos.ch && + found <= nonspaceAfter(0, line)) { + insert = line.slice(0, found); + } + if (insert != null) insert += mode.blockCommentContinue + } + if (insert == null && lineCmt && continueLineCommentEnabled(cm)) { + if (line == null) line = cm.getLine(pos.line); + found = line.indexOf(lineCmt); + // cursor at pos 0, line comment also at pos 0 => shift it down, don't continue + if (!pos.ch && !found) insert = ""; + // continue only if the line starts with an optional space + line comment + else if (found > -1 && nonspaceAfter(0, line) >= found) { + // don't continue if there's only space(s) after cursor or the end of the line + insert = nonspaceAfter(pos.ch, line) > -1; + // but always continue if the next line starts with a line comment too + if (!insert) { + var next = cm.getLine(pos.line + 1) || '', + nextFound = next.indexOf(lineCmt); + insert = nextFound > -1 && nonspaceAfter(0, next) >= nextFound || null; + } + if (insert) { + insert = line.slice(0, found) + lineCmt + + line.slice(found + lineCmt.length).match(/^\s*/)[0]; + } + } + } + if (insert == null) return CodeMirror.Pass; + inserts[i] = "\n" + insert; + } + + cm.operation(function() { + for (var i = ranges.length - 1; i >= 0; i--) + cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); + }); + } + + function nonspaceAfter(ch, str) { + nonspace.lastIndex = ch; + var m = nonspace.exec(str); + return m ? m.index : -1; + } + + function continueLineCommentEnabled(cm) { + var opt = cm.getOption("continueComments"); + if (opt && typeof opt == "object") + return opt.continueLineComment !== false; + return true; + } + + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { + if (prev && prev != CodeMirror.Init) + cm.removeKeyMap("continueComment"); + if (val) { + var key = "Enter"; + if (typeof val == "string") + key = val; + else if (typeof val == "object" && val.key) + key = val.key; + var map = {name: "continueComment"}; + map[key] = continueComment; + cm.addKeyMap(map); + } + }); +}); diff --git a/lib/redactor/codemirror/addon/dialog/dialog.css b/lib/redactor/codemirror/addon/dialog/dialog.css new file mode 100644 index 0000000..677c078 --- /dev/null +++ b/lib/redactor/codemirror/addon/dialog/dialog.css @@ -0,0 +1,32 @@ +.CodeMirror-dialog { + position: absolute; + left: 0; right: 0; + background: inherit; + z-index: 15; + padding: .1em .8em; + overflow: hidden; + color: inherit; +} + +.CodeMirror-dialog-top { + border-bottom: 1px solid #eee; + top: 0; +} + +.CodeMirror-dialog-bottom { + border-top: 1px solid #eee; + bottom: 0; +} + +.CodeMirror-dialog input { + border: none; + outline: none; + background: transparent; + width: 20em; + color: inherit; + font-family: monospace; +} + +.CodeMirror-dialog button { + font-size: 70%; +} diff --git a/lib/redactor/codemirror/addon/dialog/dialog.js b/lib/redactor/codemirror/addon/dialog/dialog.js new file mode 100644 index 0000000..23b06a8 --- /dev/null +++ b/lib/redactor/codemirror/addon/dialog/dialog.js @@ -0,0 +1,161 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Open simple dialogs on top of an editor. Relies on dialog.css. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + function dialogDiv(cm, template, bottom) { + var wrap = cm.getWrapperElement(); + var dialog; + dialog = wrap.appendChild(document.createElement("div")); + if (bottom) + dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; + else + dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; + + if (typeof template == "string") { + dialog.innerHTML = template; + } else { // Assuming it's a detached DOM element. + dialog.appendChild(template); + } + CodeMirror.addClass(wrap, 'dialog-opened'); + return dialog; + } + + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + if (!options) options = {}; + + closeNotification(this, null); + + var dialog = dialogDiv(this, template, options.bottom); + var closed = false, me = this; + function close(newVal) { + if (typeof newVal == 'string') { + inp.value = newVal; + } else { + if (closed) return; + closed = true; + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); + dialog.parentNode.removeChild(dialog); + me.focus(); + + if (options.onClose) options.onClose(dialog); + } + } + + var inp = dialog.getElementsByTagName("input")[0], button; + if (inp) { + inp.focus(); + + if (options.value) { + inp.value = options.value; + if (options.selectValueOnOpen !== false) { + inp.select(); + } + } + + if (options.onInput) + CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); + if (options.onKeyUp) + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); + + CodeMirror.on(inp, "keydown", function(e) { + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } + if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { + inp.blur(); + CodeMirror.e_stop(e); + close(); + } + if (e.keyCode == 13) callback(inp.value, e); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); + } else if (button = dialog.getElementsByTagName("button")[0]) { + CodeMirror.on(button, "click", function() { + close(); + me.focus(); + }); + + if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); + + button.focus(); + } + return close; + }); + + CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { + closeNotification(this, null); + var dialog = dialogDiv(this, template, options && options.bottom); + var buttons = dialog.getElementsByTagName("button"); + var closed = false, me = this, blurring = 1; + function close() { + if (closed) return; + closed = true; + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); + dialog.parentNode.removeChild(dialog); + me.focus(); + } + buttons[0].focus(); + for (var i = 0; i < buttons.length; ++i) { + var b = buttons[i]; + (function(callback) { + CodeMirror.on(b, "click", function(e) { + CodeMirror.e_preventDefault(e); + close(); + if (callback) callback(me); + }); + })(callbacks[i]); + CodeMirror.on(b, "blur", function() { + --blurring; + setTimeout(function() { if (blurring <= 0) close(); }, 200); + }); + CodeMirror.on(b, "focus", function() { ++blurring; }); + } + }); + + /* + * openNotification + * Opens a notification, that can be closed with an optional timer + * (default 5000ms timer) and always closes on click. + * + * If a notification is opened while another is opened, it will close the + * currently opened one and open the new one immediately. + */ + CodeMirror.defineExtension("openNotification", function(template, options) { + closeNotification(this, close); + var dialog = dialogDiv(this, template, options && options.bottom); + var closed = false, doneTimer; + var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; + + function close() { + if (closed) return; + closed = true; + clearTimeout(doneTimer); + CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); + dialog.parentNode.removeChild(dialog); + } + + CodeMirror.on(dialog, 'click', function(e) { + CodeMirror.e_preventDefault(e); + close(); + }); + + if (duration) + doneTimer = setTimeout(close, duration); + + return close; + }); +}); diff --git a/lib/redactor/codemirror/addon/display/autorefresh.js b/lib/redactor/codemirror/addon/display/autorefresh.js new file mode 100644 index 0000000..37014dc --- /dev/null +++ b/lib/redactor/codemirror/addon/display/autorefresh.js @@ -0,0 +1,47 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + + CodeMirror.defineOption("autoRefresh", false, function(cm, val) { + if (cm.state.autoRefresh) { + stopListening(cm, cm.state.autoRefresh) + cm.state.autoRefresh = null + } + if (val && cm.display.wrapper.offsetHeight == 0) + startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250}) + }) + + function startListening(cm, state) { + function check() { + if (cm.display.wrapper.offsetHeight) { + stopListening(cm, state) + if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight) + cm.refresh() + } else { + state.timeout = setTimeout(check, state.delay) + } + } + state.timeout = setTimeout(check, state.delay) + state.hurry = function() { + clearTimeout(state.timeout) + state.timeout = setTimeout(check, 50) + } + CodeMirror.on(window, "mouseup", state.hurry) + CodeMirror.on(window, "keyup", state.hurry) + } + + function stopListening(_cm, state) { + clearTimeout(state.timeout) + CodeMirror.off(window, "mouseup", state.hurry) + CodeMirror.off(window, "keyup", state.hurry) + } +}); diff --git a/lib/redactor/codemirror/addon/display/fullscreen.css b/lib/redactor/codemirror/addon/display/fullscreen.css new file mode 100644 index 0000000..437acd8 --- /dev/null +++ b/lib/redactor/codemirror/addon/display/fullscreen.css @@ -0,0 +1,6 @@ +.CodeMirror-fullscreen { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + height: auto; + z-index: 9; +} diff --git a/lib/redactor/codemirror/addon/display/fullscreen.js b/lib/redactor/codemirror/addon/display/fullscreen.js new file mode 100644 index 0000000..eda7300 --- /dev/null +++ b/lib/redactor/codemirror/addon/display/fullscreen.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { + if (old == CodeMirror.Init) old = false; + if (!old == !val) return; + if (val) setFullscreen(cm); + else setNormal(cm); + }); + + function setFullscreen(cm) { + var wrap = cm.getWrapperElement(); + cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, + width: wrap.style.width, height: wrap.style.height}; + wrap.style.width = ""; + wrap.style.height = "auto"; + wrap.className += " CodeMirror-fullscreen"; + document.documentElement.style.overflow = "hidden"; + cm.refresh(); + } + + function setNormal(cm) { + var wrap = cm.getWrapperElement(); + wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); + document.documentElement.style.overflow = ""; + var info = cm.state.fullScreenRestore; + wrap.style.width = info.width; wrap.style.height = info.height; + window.scrollTo(info.scrollLeft, info.scrollTop); + cm.refresh(); + } +}); diff --git a/lib/redactor/codemirror/addon/display/panel.js b/lib/redactor/codemirror/addon/display/panel.js new file mode 100644 index 0000000..4c9f2c0 --- /dev/null +++ b/lib/redactor/codemirror/addon/display/panel.js @@ -0,0 +1,129 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function (mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function (CodeMirror) { + CodeMirror.defineExtension("addPanel", function (node, options) { + options = options || {}; + + if (!this.state.panels) initPanels(this); + + var info = this.state.panels; + var wrapper = info.wrapper; + var cmWrapper = this.getWrapperElement(); + var replace = options.replace instanceof Panel && !options.replace.cleared; + + if (options.after instanceof Panel && !options.after.cleared) { + wrapper.insertBefore(node, options.before.node.nextSibling); + } else if (options.before instanceof Panel && !options.before.cleared) { + wrapper.insertBefore(node, options.before.node); + } else if (replace) { + wrapper.insertBefore(node, options.replace.node); + options.replace.clear(true); + } else if (options.position == "bottom") { + wrapper.appendChild(node); + } else if (options.position == "before-bottom") { + wrapper.insertBefore(node, cmWrapper.nextSibling); + } else if (options.position == "after-top") { + wrapper.insertBefore(node, cmWrapper); + } else { + wrapper.insertBefore(node, wrapper.firstChild); + } + + var height = (options && options.height) || node.offsetHeight; + + var panel = new Panel(this, node, options, height); + info.panels.push(panel); + + this.setSize(); + if (options.stable && isAtTop(this, node)) + this.scrollTo(null, this.getScrollInfo().top + height); + + return panel; + }); + + function Panel(cm, node, options, height) { + this.cm = cm; + this.node = node; + this.options = options; + this.height = height; + this.cleared = false; + } + + /* when skipRemove is true, clear() was called from addPanel(). + * Thus removePanels() should not be called (issue 5518) */ + Panel.prototype.clear = function (skipRemove) { + if (this.cleared) return; + this.cleared = true; + var info = this.cm.state.panels; + info.panels.splice(info.panels.indexOf(this), 1); + this.cm.setSize(); + if (this.options.stable && isAtTop(this.cm, this.node)) + this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) + info.wrapper.removeChild(this.node); + if (info.panels.length == 0 && !skipRemove) removePanels(this.cm); + }; + + Panel.prototype.changed = function () { + this.height = this.node.getBoundingClientRect().height; + this.cm.setSize(); + }; + + function initPanels(cm) { + var wrap = cm.getWrapperElement(); + var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; + var height = parseInt(style.height); + var info = cm.state.panels = { + setHeight: wrap.style.height, + panels: [], + wrapper: document.createElement("div") + }; + wrap.parentNode.insertBefore(info.wrapper, wrap); + var hasFocus = cm.hasFocus(); + info.wrapper.appendChild(wrap); + if (hasFocus) cm.focus(); + + cm._setSize = cm.setSize; + if (height != null) cm.setSize = function (width, newHeight) { + if (!newHeight) newHeight = info.wrapper.offsetHeight; + info.setHeight = newHeight; + if (typeof newHeight != "number") { + var px = /^(\d+\.?\d*)px$/.exec(newHeight); + if (px) { + newHeight = Number(px[1]); + } else { + info.wrapper.style.height = newHeight; + newHeight = info.wrapper.offsetHeight; + } + } + var editorheight = newHeight - info.panels + .map(function (p) { return p.node.getBoundingClientRect().height; }) + .reduce(function (a, b) { return a + b; }, 0); + cm._setSize(width, editorheight); + height = newHeight; + }; + } + + function removePanels(cm) { + var info = cm.state.panels; + cm.state.panels = null; + + var wrap = cm.getWrapperElement(); + info.wrapper.parentNode.replaceChild(wrap, info.wrapper); + wrap.style.height = info.setHeight; + cm.setSize = cm._setSize; + cm.setSize(); + } + + function isAtTop(cm, dom) { + for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) + if (sibling == cm.getWrapperElement()) return true + return false + } +}); diff --git a/lib/redactor/codemirror/addon/display/placeholder.js b/lib/redactor/codemirror/addon/display/placeholder.js new file mode 100644 index 0000000..4eabe3d --- /dev/null +++ b/lib/redactor/codemirror/addon/display/placeholder.js @@ -0,0 +1,63 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("placeholder", "", function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.on("blur", onBlur); + cm.on("change", onChange); + cm.on("swapDoc", onChange); + onChange(cm); + } else if (!val && prev) { + cm.off("blur", onBlur); + cm.off("change", onChange); + cm.off("swapDoc", onChange); + clearPlaceholder(cm); + var wrapper = cm.getWrapperElement(); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); + } + + if (val && !cm.hasFocus()) onBlur(cm); + }); + + function clearPlaceholder(cm) { + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; + } + } + function setPlaceholder(cm) { + clearPlaceholder(cm); + var elt = cm.state.placeholder = document.createElement("pre"); + elt.style.cssText = "height: 0; overflow: visible"; + elt.style.direction = cm.getOption("direction"); + elt.className = "CodeMirror-placeholder CodeMirror-line-like"; + var placeHolder = cm.getOption("placeholder") + if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) + elt.appendChild(placeHolder) + cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); + } + + function onBlur(cm) { + if (isEmpty(cm)) setPlaceholder(cm); + } + function onChange(cm) { + var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); + wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); + + if (empty) setPlaceholder(cm); + else clearPlaceholder(cm); + } + + function isEmpty(cm) { + return (cm.lineCount() === 1) && (cm.getLine(0) === ""); + } +}); diff --git a/lib/redactor/codemirror/addon/display/rulers.js b/lib/redactor/codemirror/addon/display/rulers.js new file mode 100644 index 0000000..0bb83bb --- /dev/null +++ b/lib/redactor/codemirror/addon/display/rulers.js @@ -0,0 +1,51 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("rulers", false, function(cm, val) { + if (cm.state.rulerDiv) { + cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv) + cm.state.rulerDiv = null + cm.off("refresh", drawRulers) + } + if (val && val.length) { + cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace) + cm.state.rulerDiv.className = "CodeMirror-rulers" + drawRulers(cm) + cm.on("refresh", drawRulers) + } + }); + + function drawRulers(cm) { + cm.state.rulerDiv.textContent = "" + var val = cm.getOption("rulers"); + var cw = cm.defaultCharWidth(); + var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; + cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px"; + for (var i = 0; i < val.length; i++) { + var elt = document.createElement("div"); + elt.className = "CodeMirror-ruler"; + var col, conf = val[i]; + if (typeof conf == "number") { + col = conf; + } else { + col = conf.column; + if (conf.className) elt.className += " " + conf.className; + if (conf.color) elt.style.borderColor = conf.color; + if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; + if (conf.width) elt.style.borderLeftWidth = conf.width; + } + elt.style.left = (left + col * cw) + "px"; + cm.state.rulerDiv.appendChild(elt) + } + } +}); diff --git a/lib/redactor/codemirror/addon/edit/closebrackets.js b/lib/redactor/codemirror/addon/edit/closebrackets.js new file mode 100644 index 0000000..4415c39 --- /dev/null +++ b/lib/redactor/codemirror/addon/edit/closebrackets.js @@ -0,0 +1,191 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var defaults = { + pairs: "()[]{}''\"\"", + closeBefore: ")]}'\":;>", + triples: "", + explode: "[]{}" + }; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.removeKeyMap(keyMap); + cm.state.closeBrackets = null; + } + if (val) { + ensureBound(getOption(val, "pairs")) + cm.state.closeBrackets = val; + cm.addKeyMap(keyMap); + } + }); + + function getOption(conf, name) { + if (name == "pairs" && typeof conf == "string") return conf; + if (typeof conf == "object" && conf[name] != null) return conf[name]; + return defaults[name]; + } + + var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; + function ensureBound(chars) { + for (var i = 0; i < chars.length; i++) { + var ch = chars.charAt(i), key = "'" + ch + "'" + if (!keyMap[key]) keyMap[key] = handler(ch) + } + } + ensureBound(defaults.pairs + "`") + + function handler(ch) { + return function(cm) { return handleChar(cm, ch); }; + } + + function getConfig(cm) { + var deflt = cm.state.closeBrackets; + if (!deflt || deflt.override) return deflt; + var mode = cm.getModeAt(cm.getCursor()); + return mode.closeBrackets || deflt; + } + + function handleBackspace(cm) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); + } + } + + function handleEnter(cm) { + var conf = getConfig(cm); + var explode = conf && getOption(conf, "explode"); + if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; + + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function() { + var linesep = cm.lineSeparator() || "\n"; + cm.replaceSelection(linesep + linesep, null); + cm.execCommand("goCharLeft"); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + } + + function contractSelection(sel) { + var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; + return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), + head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))}; + } + + function handleChar(cm, ch) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var pos = pairs.indexOf(ch); + if (pos == -1) return CodeMirror.Pass; + + var closeBefore = getOption(conf,"closeBefore"); + + var triples = getOption(conf, "triples"); + + var identical = pairs.charAt(pos + 1) == ch; + var ranges = cm.listSelections(); + var opening = pos % 2 == 0; + + var type; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (opening && !range.empty()) { + curType = "surround"; + } else if ((identical || !opening) && next == ch) { + if (identical && stringStartsAfter(cm, cur)) + curType = "both"; + else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) + curType = "skipThree"; + else + curType = "skip"; + } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) { + if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass; + curType = "addFour"; + } else if (identical) { + var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) + if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both"; + else return CodeMirror.Pass; + } else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) { + curType = "both"; + } else { + return CodeMirror.Pass; + } + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + var left = pos % 2 ? pairs.charAt(pos - 1) : ch; + var right = pos % 2 ? ch : pairs.charAt(pos + 1); + cm.operation(function() { + if (type == "skip") { + cm.execCommand("goCharRight"); + } else if (type == "skipThree") { + for (var i = 0; i < 3; i++) + cm.execCommand("goCharRight"); + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + sels = cm.listSelections().slice(); + for (var i = 0; i < sels.length; i++) + sels[i] = contractSelection(sels[i]); + cm.setSelections(sels); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.triggerElectric(left + right); + cm.execCommand("goCharLeft"); + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + cm.execCommand("goCharRight"); + } + }); + } + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + function stringStartsAfter(cm, pos) { + var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) + return /\bstring/.test(token.type) && token.start == pos.ch && + (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) + } +}); diff --git a/lib/redactor/codemirror/addon/edit/closetag.js b/lib/redactor/codemirror/addon/edit/closetag.js new file mode 100644 index 0000000..b8cbf95 --- /dev/null +++ b/lib/redactor/codemirror/addon/edit/closetag.js @@ -0,0 +1,184 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +/** + * Tag-closer extension for CodeMirror. + * + * This extension adds an "autoCloseTags" option that can be set to + * either true to get the default behavior, or an object to further + * configure its behavior. + * + * These are supported options: + * + * `whenClosing` (default true) + * Whether to autoclose when the '/' of a closing tag is typed. + * `whenOpening` (default true) + * Whether to autoclose the tag when the final '>' of an opening + * tag is typed. + * `dontCloseTags` (default is empty tags for HTML, none for XML) + * An array of tag names that should not be autoclosed. + * `indentTags` (default is block tags for HTML, none for XML) + * An array of tag names that should, when opened, cause a + * blank line to be added inside the tag, and the blank line and + * closing line to be indented. + * `emptyTags` (default is none) + * An array of XML tag names that should be autoclosed with '/>'. + * + * See demos/closetag.html for a usage example. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { + if (old != CodeMirror.Init && old) + cm.removeKeyMap("autoCloseTags"); + if (!val) return; + var map = {name: "autoCloseTags"}; + if (typeof val != "object" || val.whenClosing) + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; + if (typeof val != "object" || val.whenOpening) + map["'>'"] = function(cm) { return autoCloseGT(cm); }; + cm.addKeyMap(map); + }); + + var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", + "source", "track", "wbr"]; + var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", + "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; + + function autoCloseGT(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + var opt = cm.getOption("autoCloseTags"); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var pos = ranges[i].head, tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state) + var tagName = tagInfo && tagInfo.name + if (!tagName) return CodeMirror.Pass + + var html = inner.mode.configuration == "html"; + var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); + var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); + + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (!tagName || + tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || + tok.type == "tag" && tagInfo.close || + tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || + closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true)) + return CodeMirror.Pass; + + var emptyTags = typeof opt == "object" && opt.emptyTags; + if (emptyTags && indexOf(emptyTags, tagName) > -1) { + replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) }; + continue; + } + + var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; + replacements[i] = {indent: indent, + text: ">" + (indent ? "\n\n" : "") + "", + newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; + } + + var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); + for (var i = ranges.length - 1; i >= 0; i--) { + var info = replacements[i]; + cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); + var sel = cm.listSelections().slice(0); + sel[i] = {head: info.newPos, anchor: info.newPos}; + cm.setSelections(sel); + if (!dontIndentOnAutoClose && info.indent) { + cm.indentLine(info.newPos.line, null, true); + cm.indentLine(info.newPos.line + 1, null, true); + } + } + } + + function autoCloseCurrent(cm, typingSlash) { + var ranges = cm.listSelections(), replacements = []; + var head = typingSlash ? "/" : "") replacement += ">"; + replacements[i] = replacement; + } + cm.replaceSelections(replacements); + ranges = cm.listSelections(); + if (!dontIndentOnAutoClose) { + for (var i = 0; i < ranges.length; i++) + if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) + cm.indentLine(ranges[i].head.line); + } + } + + function autoCloseSlash(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + return autoCloseCurrent(cm, true); + } + + CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; + + function indexOf(collection, elt) { + if (collection.indexOf) return collection.indexOf(elt); + for (var i = 0, e = collection.length; i < e; ++i) + if (collection[i] == elt) return i; + return -1; + } + + // If xml-fold is loaded, we use its functionality to try and verify + // whether a given tag is actually unclosed. + function closingTagExists(cm, context, tagName, pos, newTag) { + if (!CodeMirror.scanForClosingTag) return false; + var end = Math.min(cm.lastLine() + 1, pos.line + 500); + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!nextClose || nextClose.tag != tagName) return false; + // If the immediate wrapping context contains onCx instances of + // the same tag, a closing tag only exists if there are at least + // that many closing tags of that type following. + var onCx = newTag ? 1 : 0 + for (var i = context.length - 1; i >= 0; i--) { + if (context[i] == tagName) ++onCx + else break + } + pos = nextClose.to; + for (var i = 1; i < onCx; i++) { + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!next || next.tag != tagName) return false; + pos = next.to; + } + return true; + } +}); diff --git a/lib/redactor/codemirror/addon/edit/continuelist.js b/lib/redactor/codemirror/addon/edit/continuelist.js new file mode 100644 index 0000000..fb5f037 --- /dev/null +++ b/lib/redactor/codemirror/addon/edit/continuelist.js @@ -0,0 +1,99 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/, + emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/, + unorderedListRE = /[*+-]\s/; + + CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { + if (cm.getOption("disableInput")) return CodeMirror.Pass; + var ranges = cm.listSelections(), replacements = []; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].head; + + // If we're not in Markdown mode, fall back to normal newlineAndIndent + var eolState = cm.getStateAfter(pos.line); + var inner = CodeMirror.innerMode(cm.getMode(), eolState); + if (inner.mode.name !== "markdown") { + cm.execCommand("newlineAndIndent"); + return; + } else { + eolState = inner.state; + } + + var inList = eolState.list !== false; + var inQuote = eolState.quote !== 0; + + var line = cm.getLine(pos.line), match = listRE.exec(line); + var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); + if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { + cm.execCommand("newlineAndIndent"); + return; + } + if (emptyListRE.test(line)) { + if (!/>\s*$/.test(line)) cm.replaceRange("", { + line: pos.line, ch: 0 + }, { + line: pos.line, ch: pos.ch + 1 + }); + replacements[i] = "\n"; + } else { + var indent = match[1], after = match[5]; + var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0); + var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " "); + replacements[i] = "\n" + indent + bullet + after; + + if (numbered) incrementRemainingMarkdownListNumbers(cm, pos); + } + } + + cm.replaceSelections(replacements); + }; + + // Auto-updating Markdown list numbers when a new item is added to the + // middle of a list + function incrementRemainingMarkdownListNumbers(cm, pos) { + var startLine = pos.line, lookAhead = 0, skipCount = 0; + var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; + + do { + lookAhead += 1; + var nextLineNumber = startLine + lookAhead; + var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); + + if (nextItem) { + var nextIndent = nextItem[1]; + var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); + var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; + + if (startIndent === nextIndent && !isNaN(nextNumber)) { + if (newNumber === nextNumber) itemNumber = nextNumber + 1; + if (newNumber > nextNumber) itemNumber = newNumber + 1; + cm.replaceRange( + nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), + { + line: nextLineNumber, ch: 0 + }, { + line: nextLineNumber, ch: nextLine.length + }); + } else { + if (startIndent.length > nextIndent.length) return; + // This doesn't run if the next line immediatley indents, as it is + // not clear of the users intention (new indented item or same level) + if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; + skipCount += 1; + } + } + } while (nextItem); + } +}); diff --git a/lib/redactor/codemirror/addon/edit/matchbrackets.js b/lib/redactor/codemirror/addon/edit/matchbrackets.js new file mode 100644 index 0000000..2a14728 --- /dev/null +++ b/lib/redactor/codemirror/addon/edit/matchbrackets.js @@ -0,0 +1,150 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && + (document.documentMode == null || document.documentMode < 8); + + var Pos = CodeMirror.Pos; + + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"}; + + function bracketRegex(config) { + return config && config.bracketRegex || /[(){}[\]]/ + } + + function findMatchingBracket(cm, where, config) { + var line = cm.getLineHandle(where.line), pos = where.ch - 1; + var afterCursor = config && config.afterCursor + if (afterCursor == null) + afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className) + var re = bracketRegex(config) + + // A cursor is defined as between two characters, but in in vim command mode + // (i.e. not insert mode), the cursor is visually represented as a + // highlighted box on top of the 2nd character. Otherwise, we allow matches + // from before or after the cursor. + var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) || + re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)]; + if (!match) return null; + var dir = match.charAt(1) == ">" ? 1 : -1; + if (config && config.strict && (dir > 0) != (pos == where.ch)) return null; + var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); + + var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config); + if (found == null) return null; + return {from: Pos(where.line, pos), to: found && found.pos, + match: found && found.ch == match.charAt(0), forward: dir > 0}; + } + + // bracketRegex is used to specify which type of bracket to scan + // should be a regexp, e.g. /[[\]]/ + // + // Note: If "where" is on an open bracket, then this bracket is ignored. + // + // Returns false when no bracket was found, null when it reached + // maxScanLines and gave up + function scanForBracket(cm, where, dir, style, config) { + var maxScanLen = (config && config.maxScanLineLength) || 10000; + var maxScanLines = (config && config.maxScanLines) || 1000; + + var stack = []; + var re = bracketRegex(config) + var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) + : Math.max(cm.firstLine() - 1, where.line - maxScanLines); + for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { + var line = cm.getLine(lineNo); + if (!line) continue; + var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; + if (line.length > maxScanLen) continue; + if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); + for (; pos != end; pos += dir) { + var ch = line.charAt(pos); + if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) { + var match = matching[ch]; + if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch); + else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; + else stack.pop(); + } + } + } + return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; + } + + function matchBrackets(cm, autoclear, config) { + // Disable brace matching in long lines, since it'll cause hugely slow updates + var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000; + var marks = [], ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config); + if (match && cm.getLine(match.from.line).length <= maxHighlightLen) { + var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; + marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); + if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) + marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); + } + } + + if (marks.length) { + // Kludge to work around the IE bug from issue #1193, where text + // input stops going to the textare whever this fires. + if (ie_lt8 && cm.state.focused) cm.focus(); + + var clear = function() { + cm.operation(function() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + }); + }; + if (autoclear) setTimeout(clear, 800); + else return clear; + } + } + + function doMatchBrackets(cm) { + cm.operation(function() { + if (cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; + } + cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); + }); + } + + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("cursorActivity", doMatchBrackets); + if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; + } + } + if (val) { + cm.state.matchBrackets = typeof val == "object" ? val : {}; + cm.on("cursorActivity", doMatchBrackets); + } + }); + + CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); + CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){ + // Backwards-compatibility kludge + if (oldConfig || typeof config == "boolean") { + if (!oldConfig) { + config = config ? {strict: true} : null + } else { + oldConfig.strict = config + config = oldConfig + } + } + return findMatchingBracket(this, pos, config) + }); + CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ + return scanForBracket(this, pos, dir, style, config); + }); +}); diff --git a/lib/redactor/codemirror/addon/edit/matchtags.js b/lib/redactor/codemirror/addon/edit/matchtags.js new file mode 100644 index 0000000..2203d93 --- /dev/null +++ b/lib/redactor/codemirror/addon/edit/matchtags.js @@ -0,0 +1,66 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../fold/xml-fold")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../fold/xml-fold"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("matchTags", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("cursorActivity", doMatchTags); + cm.off("viewportChange", maybeUpdateMatch); + clear(cm); + } + if (val) { + cm.state.matchBothTags = typeof val == "object" && val.bothTags; + cm.on("cursorActivity", doMatchTags); + cm.on("viewportChange", maybeUpdateMatch); + doMatchTags(cm); + } + }); + + function clear(cm) { + if (cm.state.tagHit) cm.state.tagHit.clear(); + if (cm.state.tagOther) cm.state.tagOther.clear(); + cm.state.tagHit = cm.state.tagOther = null; + } + + function doMatchTags(cm) { + cm.state.failedTagMatch = false; + cm.operation(function() { + clear(cm); + if (cm.somethingSelected()) return; + var cur = cm.getCursor(), range = cm.getViewport(); + range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); + var match = CodeMirror.findMatchingTag(cm, cur, range); + if (!match) return; + if (cm.state.matchBothTags) { + var hit = match.at == "open" ? match.open : match.close; + if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); + } + var other = match.at == "close" ? match.open : match.close; + if (other) + cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + else + cm.state.failedTagMatch = true; + }); + } + + function maybeUpdateMatch(cm) { + if (cm.state.failedTagMatch) doMatchTags(cm); + } + + CodeMirror.commands.toMatchingTag = function(cm) { + var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); + if (found) { + var other = found.at == "close" ? found.open : found.close; + if (other) cm.extendSelection(other.to, other.from); + } + }; +}); diff --git a/lib/redactor/codemirror/addon/edit/trailingspace.js b/lib/redactor/codemirror/addon/edit/trailingspace.js new file mode 100644 index 0000000..c39c310 --- /dev/null +++ b/lib/redactor/codemirror/addon/edit/trailingspace.js @@ -0,0 +1,27 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { + if (prev == CodeMirror.Init) prev = false; + if (prev && !val) + cm.removeOverlay("trailingspace"); + else if (!prev && val) + cm.addOverlay({ + token: function(stream) { + for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} + if (i > stream.pos) { stream.pos = i; return null; } + stream.pos = l; + return "trailingspace"; + }, + name: "trailingspace" + }); + }); +}); diff --git a/lib/redactor/codemirror/addon/fold/brace-fold.js b/lib/redactor/codemirror/addon/fold/brace-fold.js new file mode 100644 index 0000000..654d1fb --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/brace-fold.js @@ -0,0 +1,105 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "brace", function(cm, start) { + var line = start.line, lineText = cm.getLine(line); + var tokenType; + + function findOpening(openCh) { + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); + if (found == -1) { + if (pass == 1) break; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) break; + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); + if (!/^(comment|string)/.test(tokenType)) return found + 1; + at = found - 1; + } + } + + var startToken = "{", endToken = "}", startCh = findOpening("{"); + if (startCh == null) { + startToken = "[", endToken = "]"; + startCh = findOpening("["); + } + + if (startCh == null) return; + var count = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { + if (pos == nextOpen) ++count; + else if (!--count) { end = i; endCh = pos; break outer; } + } + ++pos; + } + } + if (end == null || line == end) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +CodeMirror.registerHelper("fold", "import", function(cm, start) { + function hasImport(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type != "keyword" || start.string != "import") return null; + // Now find closing semicolon, return its position + for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { + var text = cm.getLine(i), semi = text.indexOf(";"); + if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; + } + } + + var startLine = start.line, has = hasImport(startLine), prev; + if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1)) + return null; + for (var end = has.end;;) { + var next = hasImport(end.line + 1); + if (next == null) break; + end = next.end; + } + return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end}; +}); + +CodeMirror.registerHelper("fold", "include", function(cm, start) { + function hasInclude(line) { + if (line < cm.firstLine() || line > cm.lastLine()) return null; + var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); + if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); + if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; + } + + var startLine = start.line, has = hasInclude(startLine); + if (has == null || hasInclude(startLine - 1) != null) return null; + for (var end = startLine;;) { + var next = hasInclude(end + 1); + if (next == null) break; + ++end; + } + return {from: CodeMirror.Pos(startLine, has + 1), + to: cm.clipPos(CodeMirror.Pos(end))}; +}); + +}); diff --git a/lib/redactor/codemirror/addon/fold/comment-fold.js b/lib/redactor/codemirror/addon/fold/comment-fold.js new file mode 100644 index 0000000..836101d --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/comment-fold.js @@ -0,0 +1,59 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { + return mode.blockCommentStart && mode.blockCommentEnd; +}, function(cm, start) { + var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; + if (!startToken || !endToken) return; + var line = start.line, lineText = cm.getLine(line); + + var startCh; + for (var at = start.ch, pass = 0;;) { + var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); + if (found == -1) { + if (pass == 1) return; + pass = 1; + at = lineText.length; + continue; + } + if (pass == 1 && found < start.ch) return; + if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && + (found == 0 || lineText.slice(found - endToken.length, found) == endToken || + !/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { + startCh = found + startToken.length; + break; + } + at = found - 1; + } + + var depth = 1, lastLine = cm.lastLine(), end, endCh; + outer: for (var i = line; i <= lastLine; ++i) { + var text = cm.getLine(i), pos = i == line ? startCh : 0; + for (;;) { + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (pos == nextOpen) ++depth; + else if (!--depth) { end = i; endCh = pos; break outer; } + ++pos; + } + } + if (end == null || line == end && endCh == startCh) return; + return {from: CodeMirror.Pos(line, startCh), + to: CodeMirror.Pos(end, endCh)}; +}); + +}); diff --git a/lib/redactor/codemirror/addon/fold/foldcode.js b/lib/redactor/codemirror/addon/fold/foldcode.js new file mode 100644 index 0000000..887df3f --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/foldcode.js @@ -0,0 +1,157 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function doFold(cm, pos, options, force) { + if (options && options.call) { + var finder = options; + options = null; + } else { + var finder = getOption(cm, options, "rangeFinder"); + } + if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); + var minSize = getOption(cm, options, "minFoldSize"); + + function getRange(allowFolded) { + var range = finder(cm, pos); + if (!range || range.to.line - range.from.line < minSize) return null; + var marks = cm.findMarksAt(range.from); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold && force !== "fold") { + if (!allowFolded) return null; + range.cleared = true; + marks[i].clear(); + } + } + return range; + } + + var range = getRange(true); + if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { + pos = CodeMirror.Pos(pos.line - 1, 0); + range = getRange(false); + } + if (!range || range.cleared || force === "unfold") return; + + var myWidget = makeWidget(cm, options, range); + CodeMirror.on(myWidget, "mousedown", function(e) { + myRange.clear(); + CodeMirror.e_preventDefault(e); + }); + var myRange = cm.markText(range.from, range.to, { + replacedWith: myWidget, + clearOnEnter: getOption(cm, options, "clearOnEnter"), + __isFold: true + }); + myRange.on("clear", function(from, to) { + CodeMirror.signal(cm, "unfold", cm, from, to); + }); + CodeMirror.signal(cm, "fold", cm, range.from, range.to); + } + + function makeWidget(cm, options, range) { + var widget = getOption(cm, options, "widget"); + + if (typeof widget == "function") { + widget = widget(range.from, range.to); + } + + if (typeof widget == "string") { + var text = document.createTextNode(widget); + widget = document.createElement("span"); + widget.appendChild(text); + widget.className = "CodeMirror-foldmarker"; + } else if (widget) { + widget = widget.cloneNode(true) + } + return widget; + } + + // Clumsy backwards-compatible interface + CodeMirror.newFoldFunction = function(rangeFinder, widget) { + return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; + }; + + // New-style interface + CodeMirror.defineExtension("foldCode", function(pos, options, force) { + doFold(this, pos, options, force); + }); + + CodeMirror.defineExtension("isFolded", function(pos) { + var marks = this.findMarksAt(pos); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold) return true; + }); + + CodeMirror.commands.toggleFold = function(cm) { + cm.foldCode(cm.getCursor()); + }; + CodeMirror.commands.fold = function(cm) { + cm.foldCode(cm.getCursor(), null, "fold"); + }; + CodeMirror.commands.unfold = function(cm) { + cm.foldCode(cm.getCursor(), null, "unfold"); + }; + CodeMirror.commands.foldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "fold"); + }); + }; + CodeMirror.commands.unfoldAll = function(cm) { + cm.operation(function() { + for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) + cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold"); + }); + }; + + CodeMirror.registerHelper("fold", "combine", function() { + var funcs = Array.prototype.slice.call(arguments, 0); + return function(cm, start) { + for (var i = 0; i < funcs.length; ++i) { + var found = funcs[i](cm, start); + if (found) return found; + } + }; + }); + + CodeMirror.registerHelper("fold", "auto", function(cm, start) { + var helpers = cm.getHelpers(start, "fold"); + for (var i = 0; i < helpers.length; i++) { + var cur = helpers[i](cm, start); + if (cur) return cur; + } + }); + + var defaultOptions = { + rangeFinder: CodeMirror.fold.auto, + widget: "\u2194", + minFoldSize: 0, + scanUp: false, + clearOnEnter: true + }; + + CodeMirror.defineOption("foldOptions", null); + + function getOption(cm, options, name) { + if (options && options[name] !== undefined) + return options[name]; + var editorOptions = cm.options.foldOptions; + if (editorOptions && editorOptions[name] !== undefined) + return editorOptions[name]; + return defaultOptions[name]; + } + + CodeMirror.defineExtension("foldOption", function(options, name) { + return getOption(this, options, name); + }); +}); diff --git a/lib/redactor/codemirror/addon/fold/foldgutter.css b/lib/redactor/codemirror/addon/fold/foldgutter.css new file mode 100644 index 0000000..ad19ae2 --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/foldgutter.css @@ -0,0 +1,20 @@ +.CodeMirror-foldmarker { + color: blue; + text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; + font-family: arial; + line-height: .3; + cursor: pointer; +} +.CodeMirror-foldgutter { + width: .7em; +} +.CodeMirror-foldgutter-open, +.CodeMirror-foldgutter-folded { + cursor: pointer; +} +.CodeMirror-foldgutter-open:after { + content: "\25BE"; +} +.CodeMirror-foldgutter-folded:after { + content: "\25B8"; +} diff --git a/lib/redactor/codemirror/addon/fold/foldgutter.js b/lib/redactor/codemirror/addon/fold/foldgutter.js new file mode 100644 index 0000000..7d46a60 --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/foldgutter.js @@ -0,0 +1,163 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./foldcode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./foldcode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.clearGutter(cm.state.foldGutter.options.gutter); + cm.state.foldGutter = null; + cm.off("gutterClick", onGutterClick); + cm.off("changes", onChange); + cm.off("viewportChange", onViewportChange); + cm.off("fold", onFold); + cm.off("unfold", onFold); + cm.off("swapDoc", onChange); + } + if (val) { + cm.state.foldGutter = new State(parseOptions(val)); + updateInViewport(cm); + cm.on("gutterClick", onGutterClick); + cm.on("changes", onChange); + cm.on("viewportChange", onViewportChange); + cm.on("fold", onFold); + cm.on("unfold", onFold); + cm.on("swapDoc", onChange); + } + }); + + var Pos = CodeMirror.Pos; + + function State(options) { + this.options = options; + this.from = this.to = 0; + } + + function parseOptions(opts) { + if (opts === true) opts = {}; + if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; + if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; + if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; + return opts; + } + + function isFolded(cm, line) { + var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0)); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].__isFold) { + var fromPos = marks[i].find(-1); + if (fromPos && fromPos.line === line) + return marks[i]; + } + } + } + + function marker(spec) { + if (typeof spec == "string") { + var elt = document.createElement("div"); + elt.className = spec + " CodeMirror-guttermarker-subtle"; + return elt; + } else { + return spec.cloneNode(true); + } + } + + function updateFoldInfo(cm, from, to) { + var opts = cm.state.foldGutter.options, cur = from - 1; + var minSize = cm.foldOption(opts, "minFoldSize"); + var func = cm.foldOption(opts, "rangeFinder"); + // we can reuse the built-in indicator element if its className matches the new state + var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded); + var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen); + cm.eachLine(from, to, function(line) { + ++cur; + var mark = null; + var old = line.gutterMarkers; + if (old) old = old[opts.gutter]; + if (isFolded(cm, cur)) { + if (clsFolded && old && clsFolded.test(old.className)) return; + mark = marker(opts.indicatorFolded); + } else { + var pos = Pos(cur, 0); + var range = func && func(cm, pos); + if (range && range.to.line - range.from.line >= minSize) { + if (clsOpen && old && clsOpen.test(old.className)) return; + mark = marker(opts.indicatorOpen); + } + } + if (!mark && !old) return; + cm.setGutterMarker(line, opts.gutter, mark); + }); + } + + // copied from CodeMirror/src/util/dom.js + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } + + function updateInViewport(cm) { + var vp = cm.getViewport(), state = cm.state.foldGutter; + if (!state) return; + cm.operation(function() { + updateFoldInfo(cm, vp.from, vp.to); + }); + state.from = vp.from; state.to = vp.to; + } + + function onGutterClick(cm, line, gutter) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + if (gutter != opts.gutter) return; + var folded = isFolded(cm, line); + if (folded) folded.clear(); + else cm.foldCode(Pos(line, 0), opts); + } + + function onChange(cm) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + state.from = state.to = 0; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); + } + + function onViewportChange(cm) { + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { + var vp = cm.getViewport(); + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + updateInViewport(cm); + } else { + cm.operation(function() { + if (vp.from < state.from) { + updateFoldInfo(cm, vp.from, state.from); + state.from = vp.from; + } + if (vp.to > state.to) { + updateFoldInfo(cm, state.to, vp.to); + state.to = vp.to; + } + }); + } + }, opts.updateViewportTimeSpan || 400); + } + + function onFold(cm, from) { + var state = cm.state.foldGutter; + if (!state) return; + var line = from.line; + if (line >= state.from && line < state.to) + updateFoldInfo(cm, line, line + 1); + } +}); diff --git a/lib/redactor/codemirror/addon/fold/indent-fold.js b/lib/redactor/codemirror/addon/fold/indent-fold.js new file mode 100644 index 0000000..0cc1126 --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/indent-fold.js @@ -0,0 +1,48 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function lineIndent(cm, lineNo) { + var text = cm.getLine(lineNo) + var spaceTo = text.search(/\S/) + if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1)))) + return -1 + return CodeMirror.countColumn(text, null, cm.getOption("tabSize")) +} + +CodeMirror.registerHelper("fold", "indent", function(cm, start) { + var myIndent = lineIndent(cm, start.line) + if (myIndent < 0) return + var lastLineInFold = null + + // Go through lines until we find a line that definitely doesn't belong in + // the block we're folding, or to the end. + for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { + var indent = lineIndent(cm, i) + if (indent == -1) { + } else if (indent > myIndent) { + // Lines with a greater indent are considered part of the block. + lastLineInFold = i; + } else { + // If this line has non-space, non-comment content, and is + // indented less or equal to the start line, it is the start of + // another block. + break; + } + } + if (lastLineInFold) return { + from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), + to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) + }; +}); + +}); diff --git a/lib/redactor/codemirror/addon/fold/markdown-fold.js b/lib/redactor/codemirror/addon/fold/markdown-fold.js new file mode 100644 index 0000000..6a55178 --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/markdown-fold.js @@ -0,0 +1,49 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("fold", "markdown", function(cm, start) { + var maxDepth = 100; + + function isHeader(lineNo) { + var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); + return tokentype && /\bheader\b/.test(tokentype); + } + + function headerLevel(lineNo, line, nextLine) { + var match = line && line.match(/^#+/); + if (match && isHeader(lineNo)) return match[0].length; + match = nextLine && nextLine.match(/^[=\-]+\s*$/); + if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; + return maxDepth; + } + + var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); + var level = headerLevel(start.line, firstLine, nextLine); + if (level === maxDepth) return undefined; + + var lastLineNo = cm.lastLine(); + var end = start.line, nextNextLine = cm.getLine(end + 2); + while (end < lastLineNo) { + if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; + ++end; + nextLine = nextNextLine; + nextNextLine = cm.getLine(end + 2); + } + + return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(end, cm.getLine(end).length) + }; +}); + +}); diff --git a/lib/redactor/codemirror/addon/fold/xml-fold.js b/lib/redactor/codemirror/addon/fold/xml-fold.js new file mode 100644 index 0000000..13bc383 --- /dev/null +++ b/lib/redactor/codemirror/addon/fold/xml-fold.js @@ -0,0 +1,184 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } + + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; + var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); + + function Iter(cm, line, ch, range) { + this.line = line; this.ch = ch; + this.cm = cm; this.text = cm.getLine(line); + this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine(); + this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine(); + } + + function tagAt(iter, ch) { + var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); + return type && /\btag\b/.test(type); + } + + function nextLine(iter) { + if (iter.line >= iter.max) return; + iter.ch = 0; + iter.text = iter.cm.getLine(++iter.line); + return true; + } + function prevLine(iter) { + if (iter.line <= iter.min) return; + iter.text = iter.cm.getLine(--iter.line); + iter.ch = iter.text.length; + return true; + } + + function toTagEnd(iter) { + for (;;) { + var gt = iter.text.indexOf(">", iter.ch); + if (gt == -1) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + function toTagStart(iter) { + for (;;) { + var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; + if (lt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } + xmlTagStart.lastIndex = lt; + iter.ch = lt; + var match = xmlTagStart.exec(iter.text); + if (match && match.index == lt) return match; + } + } + + function toNextTag(iter) { + for (;;) { + xmlTagStart.lastIndex = iter.ch; + var found = xmlTagStart.exec(iter.text); + if (!found) { if (nextLine(iter)) continue; else return; } + if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } + iter.ch = found.index + found[0].length; + return found; + } + } + function toPrevTag(iter) { + for (;;) { + var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; + if (gt == -1) { if (prevLine(iter)) continue; else return; } + if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } + var lastSlash = iter.text.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); + iter.ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + + function findMatchingClose(iter, tag) { + var stack = []; + for (;;) { + var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); + if (!next || !(end = toTagEnd(iter))) return; + if (end == "selfClose") continue; + if (next[1]) { // closing tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == next[2])) return { + tag: next[2], + from: Pos(startLine, startCh), + to: Pos(iter.line, iter.ch) + }; + } else { // opening tag + stack.push(next[2]); + } + } + } + function findMatchingOpen(iter, tag) { + var stack = []; + for (;;) { + var prev = toPrevTag(iter); + if (!prev) return; + if (prev == "selfClose") { toTagStart(iter); continue; } + var endLine = iter.line, endCh = iter.ch; + var start = toTagStart(iter); + if (!start) return; + if (start[1]) { // closing tag + stack.push(start[2]); + } else { // opening tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { + stack.length = i; + break; + } + if (i < 0 && (!tag || tag == start[2])) return { + tag: start[2], + from: Pos(iter.line, iter.ch), + to: Pos(endLine, endCh) + }; + } + } + } + + CodeMirror.registerHelper("fold", "xml", function(cm, start) { + var iter = new Iter(cm, start.line, 0); + for (;;) { + var openTag = toNextTag(iter) + if (!openTag || iter.line != start.line) return + var end = toTagEnd(iter) + if (!end) return + if (!openTag[1] && end != "selfClose") { + var startPos = Pos(iter.line, iter.ch); + var endPos = findMatchingClose(iter, openTag[2]); + return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null + } + } + }); + CodeMirror.findMatchingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); + if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; + var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); + var start = end && toTagStart(iter); + if (!end || !start || cmp(iter, pos) > 0) return; + var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; + if (end == "selfClose") return {open: here, close: null, at: "open"}; + + if (start[1]) { // closing tag + return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; + } else { // opening tag + iter = new Iter(cm, to.line, to.ch, range); + return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; + } + }; + + CodeMirror.findEnclosingTag = function(cm, pos, range, tag) { + var iter = new Iter(cm, pos.line, pos.ch, range); + for (;;) { + var open = findMatchingOpen(iter, tag); + if (!open) break; + var forward = new Iter(cm, pos.line, pos.ch, range); + var close = findMatchingClose(forward, open.tag); + if (close) return {open: open, close: close}; + } + }; + + // Used by addon/edit/closetag.js + CodeMirror.scanForClosingTag = function(cm, pos, name, end) { + var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); + return findMatchingClose(iter, name); + }; +}); diff --git a/lib/redactor/codemirror/addon/hint/anyword-hint.js b/lib/redactor/codemirror/addon/hint/anyword-hint.js new file mode 100644 index 0000000..d27a9ec --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/anyword-hint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var WORD = /[\w$]+/, RANGE = 500; + + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var end = cur.ch, start = end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = options && options.list || [], seen = {}; + var re = new RegExp(word.source, "g"); + for (var dir = -1; dir <= 1; dir += 2) { + var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != endLine; line += dir) { + var text = editor.getLine(line), m; + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { + seen[m[0]] = true; + list.push(m[0]); + } + } + } + } + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }); +}); diff --git a/lib/redactor/codemirror/addon/hint/css-hint.js b/lib/redactor/codemirror/addon/hint/css-hint.js new file mode 100644 index 0000000..980d119 --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/css-hint.js @@ -0,0 +1,66 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var pseudoClasses = {"active":1, "after":1, "before":1, "checked":1, "default":1, + "disabled":1, "empty":1, "enabled":1, "first-child":1, "first-letter":1, + "first-line":1, "first-of-type":1, "focus":1, "hover":1, "in-range":1, + "indeterminate":1, "invalid":1, "lang":1, "last-child":1, "last-of-type":1, + "link":1, "not":1, "nth-child":1, "nth-last-child":1, "nth-last-of-type":1, + "nth-of-type":1, "only-of-type":1, "only-child":1, "optional":1, "out-of-range":1, + "placeholder":1, "read-only":1, "read-write":1, "required":1, "root":1, + "selection":1, "target":1, "valid":1, "visited":1 + }; + + CodeMirror.registerHelper("hint", "css", function(cm) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "css") return; + + if (token.type == "keyword" && "!important".indexOf(token.string) == 0) + return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end)}; + + var start = token.start, end = cur.ch, word = token.string.slice(0, end - start); + if (/[^\w$_-]/.test(word)) { + word = ""; start = end = cur.ch; + } + + var spec = CodeMirror.resolveMode("text/css"); + + var result = []; + function add(keywords) { + for (var name in keywords) + if (!word || name.lastIndexOf(word, 0) == 0) + result.push(name); + } + + var st = inner.state.state; + if (st == "pseudo" || token.type == "variable-3") { + add(pseudoClasses); + } else if (st == "block" || st == "maybeprop") { + add(spec.propertyKeywords); + } else if (st == "prop" || st == "parens" || st == "at" || st == "params") { + add(spec.valueKeywords); + add(spec.colorKeywords); + } else if (st == "media" || st == "media_parens") { + add(spec.mediaTypes); + add(spec.mediaFeatures); + } + + if (result.length) return { + list: result, + from: CodeMirror.Pos(cur.line, start), + to: CodeMirror.Pos(cur.line, end) + }; + }); +}); diff --git a/lib/redactor/codemirror/addon/hint/html-hint.js b/lib/redactor/codemirror/addon/hint/html-hint.js new file mode 100644 index 0000000..d0cca4f --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/html-hint.js @@ -0,0 +1,350 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./xml-hint")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./xml-hint"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); + var targets = ["_blank", "_self", "_top", "_parent"]; + var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; + var methods = ["get", "post", "put", "delete"]; + var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; + var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", + "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", + "orientation:landscape", "device-height: [X]", "device-width: [X]"]; + var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags + + var data = { + a: { + attrs: { + href: null, ping: null, type: null, + media: media, + target: targets, + hreflang: langs + } + }, + abbr: s, + acronym: s, + address: s, + applet: s, + area: { + attrs: { + alt: null, coords: null, href: null, target: null, ping: null, + media: media, hreflang: langs, type: null, + shape: ["default", "rect", "circle", "poly"] + } + }, + article: s, + aside: s, + audio: { + attrs: { + src: null, mediagroup: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["none", "metadata", "auto"], + autoplay: ["", "autoplay"], + loop: ["", "loop"], + controls: ["", "controls"] + } + }, + b: s, + base: { attrs: { href: null, target: targets } }, + basefont: s, + bdi: s, + bdo: s, + big: s, + blockquote: { attrs: { cite: null } }, + body: s, + br: s, + button: { + attrs: { + form: null, formaction: null, name: null, value: null, + autofocus: ["", "autofocus"], + disabled: ["", "autofocus"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + type: ["submit", "reset", "button"] + } + }, + canvas: { attrs: { width: null, height: null } }, + caption: s, + center: s, + cite: s, + code: s, + col: { attrs: { span: null } }, + colgroup: { attrs: { span: null } }, + command: { + attrs: { + type: ["command", "checkbox", "radio"], + label: null, icon: null, radiogroup: null, command: null, title: null, + disabled: ["", "disabled"], + checked: ["", "checked"] + } + }, + data: { attrs: { value: null } }, + datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, + datalist: { attrs: { data: null } }, + dd: s, + del: { attrs: { cite: null, datetime: null } }, + details: { attrs: { open: ["", "open"] } }, + dfn: s, + dir: s, + div: s, + dl: s, + dt: s, + em: s, + embed: { attrs: { src: null, type: null, width: null, height: null } }, + eventsource: { attrs: { src: null } }, + fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, + figcaption: s, + figure: s, + font: s, + footer: s, + form: { + attrs: { + action: null, name: null, + "accept-charset": charsets, + autocomplete: ["on", "off"], + enctype: encs, + method: methods, + novalidate: ["", "novalidate"], + target: targets + } + }, + frame: s, + frameset: s, + h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, + head: { + attrs: {}, + children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] + }, + header: s, + hgroup: s, + hr: s, + html: { + attrs: { manifest: null }, + children: ["head", "body"] + }, + i: s, + iframe: { + attrs: { + src: null, srcdoc: null, name: null, width: null, height: null, + sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], + seamless: ["", "seamless"] + } + }, + img: { + attrs: { + alt: null, src: null, ismap: null, usemap: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"] + } + }, + input: { + attrs: { + alt: null, dirname: null, form: null, formaction: null, + height: null, list: null, max: null, maxlength: null, min: null, + name: null, pattern: null, placeholder: null, size: null, src: null, + step: null, value: null, width: null, + accept: ["audio/*", "video/*", "image/*"], + autocomplete: ["on", "off"], + autofocus: ["", "autofocus"], + checked: ["", "checked"], + disabled: ["", "disabled"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + multiple: ["", "multiple"], + readonly: ["", "readonly"], + required: ["", "required"], + type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", + "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", + "file", "submit", "image", "reset", "button"] + } + }, + ins: { attrs: { cite: null, datetime: null } }, + kbd: s, + keygen: { + attrs: { + challenge: null, form: null, name: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + keytype: ["RSA"] + } + }, + label: { attrs: { "for": null, form: null } }, + legend: s, + li: { attrs: { value: null } }, + link: { + attrs: { + href: null, type: null, + hreflang: langs, + media: media, + sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] + } + }, + map: { attrs: { name: null } }, + mark: s, + menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, + meta: { + attrs: { + content: null, + charset: charsets, + name: ["viewport", "application-name", "author", "description", "generator", "keywords"], + "http-equiv": ["content-language", "content-type", "default-style", "refresh"] + } + }, + meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, + nav: s, + noframes: s, + noscript: s, + object: { + attrs: { + data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, + typemustmatch: ["", "typemustmatch"] + } + }, + ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, + optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, + option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, + output: { attrs: { "for": null, form: null, name: null } }, + p: s, + param: { attrs: { name: null, value: null } }, + pre: s, + progress: { attrs: { value: null, max: null } }, + q: { attrs: { cite: null } }, + rp: s, + rt: s, + ruby: s, + s: s, + samp: s, + script: { + attrs: { + type: ["text/javascript"], + src: null, + async: ["", "async"], + defer: ["", "defer"], + charset: charsets + } + }, + section: s, + select: { + attrs: { + form: null, name: null, size: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + multiple: ["", "multiple"] + } + }, + small: s, + source: { attrs: { src: null, type: null, media: null } }, + span: s, + strike: s, + strong: s, + style: { + attrs: { + type: ["text/css"], + media: media, + scoped: null + } + }, + sub: s, + summary: s, + sup: s, + table: s, + tbody: s, + td: { attrs: { colspan: null, rowspan: null, headers: null } }, + textarea: { + attrs: { + dirname: null, form: null, maxlength: null, name: null, placeholder: null, + rows: null, cols: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + readonly: ["", "readonly"], + required: ["", "required"], + wrap: ["soft", "hard"] + } + }, + tfoot: s, + th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, + thead: s, + time: { attrs: { datetime: null } }, + title: s, + tr: s, + track: { + attrs: { + src: null, label: null, "default": null, + kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], + srclang: langs + } + }, + tt: s, + u: s, + ul: s, + "var": s, + video: { + attrs: { + src: null, poster: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["auto", "metadata", "none"], + autoplay: ["", "autoplay"], + mediagroup: ["movie"], + muted: ["", "muted"], + controls: ["", "controls"] + } + }, + wbr: s + }; + + var globalAttrs = { + accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + "class": null, + contenteditable: ["true", "false"], + contextmenu: null, + dir: ["ltr", "rtl", "auto"], + draggable: ["true", "false", "auto"], + dropzone: ["copy", "move", "link", "string:", "file:"], + hidden: ["hidden"], + id: null, + inert: ["inert"], + itemid: null, + itemprop: null, + itemref: null, + itemscope: ["itemscope"], + itemtype: null, + lang: ["en", "es"], + spellcheck: ["true", "false"], + autocorrect: ["true", "false"], + autocapitalize: ["true", "false"], + style: null, + tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], + title: null, + translate: ["yes", "no"], + onclick: null, + rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] + }; + function populate(obj) { + for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) + obj.attrs[attr] = globalAttrs[attr]; + } + + populate(s); + for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) + populate(data[tag]); + + CodeMirror.htmlSchema = data; + function htmlHint(cm, options) { + var local = {schemaInfo: data}; + if (options) for (var opt in options) local[opt] = options[opt]; + return CodeMirror.hint.xml(cm, local); + } + CodeMirror.registerHelper("hint", "html", htmlHint); +}); diff --git a/lib/redactor/codemirror/addon/hint/javascript-hint.js b/lib/redactor/codemirror/addon/hint/javascript-hint.js new file mode 100644 index 0000000..182224d --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/javascript-hint.js @@ -0,0 +1,159 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + var Pos = CodeMirror.Pos; + + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, keywords, getToken, options) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur); + if (/\b(?:string|comment)\b/.test(token.type)) return; + var innerMode = CodeMirror.innerMode(editor.getMode(), token.state); + if (innerMode.mode.helperType === "json") return; + token.state = innerMode.state; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_]*$/.test(token.string)) { + token = {start: cur.ch, end: cur.ch, string: "", state: token.state, + type: token.string == "." ? "property" : null}; + } else if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + var tprop = token; + // If it is a property, find out what it is a property of. + while (tprop.type == "property") { + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (tprop.string != ".") return; + tprop = getToken(editor, Pos(cur.line, tprop.start)); + if (!context) var context = []; + context.push(tprop); + } + return {list: getCompletions(token, context, keywords, options), + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; + } + + function javascriptHint(editor, options) { + return scriptHint(editor, javascriptKeywords, + function (e, cur) {return e.getTokenAt(cur);}, + options); + }; + CodeMirror.registerHelper("hint", "javascript", javascriptHint); + + function getCoffeeScriptToken(editor, cur) { + // This getToken, it is for coffeescript, imitates the behavior of + // getTokenAt method in javascript.js, that is, returning "property" + // type and treat "." as indepenent token. + var token = editor.getTokenAt(cur); + if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { + token.end = token.start; + token.string = '.'; + token.type = "property"; + } + else if (/^\.[\w$_]*$/.test(token.string)) { + token.type = "property"; + token.start++; + token.string = token.string.replace(/\./, ''); + } + return token; + } + + function coffeescriptHint(editor, options) { + return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); + } + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); + + var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + + "toUpperCase toLowerCase split concat match replace search").split(" "); + var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + + "lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); + var funcProps = "prototype apply call bind".split(" "); + var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " + + "if in import instanceof new null return super switch this throw true try typeof var void while with yield").split(" "); + var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + + "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); + + function forAllProps(obj, callback) { + if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { + for (var name in obj) callback(name) + } else { + for (var o = obj; o; o = Object.getPrototypeOf(o)) + Object.getOwnPropertyNames(o).forEach(callback) + } + } + + function getCompletions(token, context, keywords, options) { + var found = [], start = token.string, global = options && options.globalScope || window; + function maybeAdd(str) { + if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); + } + function gatherCompletions(obj) { + if (typeof obj == "string") forEach(stringProps, maybeAdd); + else if (obj instanceof Array) forEach(arrayProps, maybeAdd); + else if (obj instanceof Function) forEach(funcProps, maybeAdd); + forAllProps(obj, maybeAdd) + } + + if (context && context.length) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + if (obj.type && obj.type.indexOf("variable") === 0) { + if (options && options.additionalContext) + base = options.additionalContext[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || global[obj.string]; + } else if (obj.type == "string") { + base = ""; + } else if (obj.type == "atom") { + base = 1; + } else if (obj.type == "function") { + if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && + (typeof global.jQuery == 'function')) + base = global.jQuery(); + else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) + base = global._(); + } + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } else { + // If not, just look in the global object and any local scope + // (reading into JS mode internals to get at the local and global variables) + for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); + for (var c = token.state.context; c; c = c.prev) + for (var v = c.vars; v; v = v.next) maybeAdd(v.name) + for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); + if (!options || options.useGlobalScope !== false) + gatherCompletions(global); + forEach(keywords, maybeAdd); + } + return found; + } +}); diff --git a/lib/redactor/codemirror/addon/hint/show-hint.css b/lib/redactor/codemirror/addon/hint/show-hint.css new file mode 100644 index 0000000..5617ccc --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/show-hint.css @@ -0,0 +1,36 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + border: 1px solid silver; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + white-space: pre; + color: black; + cursor: pointer; +} + +li.CodeMirror-hint-active { + background: #08f; + color: white; +} diff --git a/lib/redactor/codemirror/addon/hint/show-hint.js b/lib/redactor/codemirror/addon/hint/show-hint.js new file mode 100644 index 0000000..374cddf --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/show-hint.js @@ -0,0 +1,466 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function(cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = {hint: getHints}; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + CodeMirror.defineExtension("showHint", function(options) { + options = parseOptions(this, this.getCursor("start"), options); + var selections = this.listSelections() + if (selections.length > 1) return; + // By default, don't allow completion when something is selected. + // A hint function can have a `supportsSelection` property to + // indicate that it can handle selections. + if (this.somethingSelected()) { + if (!options.hint.supportsSelection) return; + // Don't try with cross-line selections + for (var i = 0; i < selections.length; i++) + if (selections[i].head.line != selections[i].anchor.line) return; + } + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + if (!completion.options.hint) return; + + CodeMirror.signal(this, "startCompletion", this); + completion.update(true); + }); + + CodeMirror.defineExtension("closeHint", function() { + if (this.state.completionActive) this.state.completionActive.close() + }) + + function Completion(cm, options) { + this.cm = cm; + this.options = options; + this.widget = null; + this.debounce = 0; + this.tick = 0; + this.startPos = this.cm.getCursor("start"); + this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; + + var self = this; + cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + } + + var requestAnimationFrame = window.requestAnimationFrame || function(fn) { + return setTimeout(fn, 1000/60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + Completion.prototype = { + close: function() { + if (!this.active()) return; + this.cm.state.completionActive = null; + this.tick = null; + this.cm.off("cursorActivity", this.activityFunc); + + if (this.widget && this.data) CodeMirror.signal(this.data, "close"); + if (this.widget) this.widget.close(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function() { + return this.cm.state.completionActive == this; + }, + + pick: function(data, i) { + var completion = data.list[i]; + if (completion.hint) completion.hint(this.cm, data, completion); + else this.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + this.close(); + }, + + cursorActivity: function() { + if (this.debounce) { + cancelAnimationFrame(this.debounce); + this.debounce = 0; + } + + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); + if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || + pos.ch < this.startPos.ch || this.cm.somethingSelected() || + (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { + this.close(); + } else { + var self = this; + this.debounce = requestAnimationFrame(function() {self.update();}); + if (this.widget) this.widget.disable(); + } + }, + + update: function(first) { + if (this.tick == null) return + var self = this, myTick = ++this.tick + fetchHints(this.options.hint, this.cm, this.options, function(data) { + if (self.tick == myTick) self.finishUpdate(data, first) + }) + }, + + finishUpdate: function(data, first) { + if (this.data) CodeMirror.signal(this.data, "update"); + + var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); + if (this.widget) this.widget.close(); + + this.data = data; + + if (data && data.list.length) { + if (picked && data.list.length == 1) { + this.pick(data, 0); + } else { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + } + } + } + }; + + function parseOptions(cm, pos, options) { + var editor = cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) + return out; + } + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function() {handle.moveFocus(-1);}, + Down: function() {handle.moveFocus(1);}, + PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, + PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, + Home: function() {handle.setFocus(0);}, + End: function() {handle.setFocus(handle.length - 1);}, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + + var mac = /Mac/.test(navigator.platform); + + if (mac) { + baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);}; + baseMap["Ctrl-N"] = function() {handle.moveFocus(1);}; + } + + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function(cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + this.picked = false; + var widget = this, cm = completion.cm; + var ownerDocument = cm.getInputField().ownerDocument; + var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow; + + var hints = this.hints = ownerDocument.createElement("ul"); + var theme = completion.cm.options.theme; + hints.className = "CodeMirror-hints " + theme; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + } + + var container = completion.options.container || ownerDocument.body; + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + var offsetLeft = 0, offsetTop = 0; + if (container !== ownerDocument.body) { + // We offset the cursor position because left and top are relative to the offsetParent's top left corner. + var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; + var offsetParent = isContainerPositioned ? container : container.offsetParent; + var offsetParentPosition = offsetParent.getBoundingClientRect(); + var bodyPosition = ownerDocument.body.getBoundingClientRect(); + offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); + offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); + } + hints.style.left = (left - offsetLeft) + "px"; + hints.style.top = (top - offsetTop) + "px"; + + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); + var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); + container.appendChild(hints); + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + var scrolls = hints.scrollHeight > hints.clientHeight + 1 + var startScroll = cm.getScrollInfo(); + + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height - offsetTop) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left - offsetLeft) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px"; + } + if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) + node.style.paddingRight = cm.display.nativeBarWidth + "px" + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function(n) { widget.changeActive(n); }, + menuSize: function() { return widget.screenAmount(); }, + length: completions.length, + close: function() { completion.close(); }, + pick: function() { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); + } + + cm.on("scroll", this.onScroll = function() { + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + }); + + CodeMirror.on(hints, "dblclick", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} + }); + + CodeMirror.on(hints, "click", function(e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function() { + setTimeout(function(){cm.focus();}, 20); + }); + this.scrollToActive() + + CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); + return true; + } + + Widget.prototype = { + close: function() { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + disable: function() { + this.completion.cm.removeKeyMap(this.keyMap); + var widget = this; + this.keyMap = {Enter: function() { widget.picked = true; }}; + this.completion.cm.addKeyMap(this.keyMap); + }, + + pick: function() { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function(i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + this.scrollToActive() + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + scrollToActive: function() { + var node = this.hints.childNodes[this.selectedHint] + if (node.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; + }, + + screenAmount: function() { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + } + }; + + function applicableHelpers(cm, helpers) { + if (!cm.somethingSelected()) return helpers + var result = [] + for (var i = 0; i < helpers.length; i++) + if (helpers[i].supportsSelection) result.push(helpers[i]) + return result + } + + function fetchHints(hint, cm, options, callback) { + if (hint.async) { + hint(cm, callback, options) + } else { + var result = hint(cm, options) + if (result && result.then) result.then(callback) + else callback(result) + } + } + + function resolveAutoHints(cm, pos) { + var helpers = cm.getHelpers(pos, "hint"), words + if (helpers.length) { + var resolved = function(cm, callback, options) { + var app = applicableHelpers(cm, helpers); + function run(i) { + if (i == app.length) return callback(null) + fetchHints(app[i], cm, options, function(result) { + if (result && result.list.length > 0) callback(result) + else run(i + 1) + }) + } + run(0) + } + resolved.async = true + resolved.supportsSelection = true + return resolved + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } + } else if (CodeMirror.hint.anyword) { + return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } + } else { + return function() {} + } + } + + CodeMirror.registerHelper("hint", "auto", { + resolve: resolveAutoHints + }); + + CodeMirror.registerHelper("hint", "fromList", function(cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur) + var term, from = CodeMirror.Pos(cur.line, token.start), to = cur + if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) { + term = token.string.substr(0, cur.ch - token.start) + } else { + term = "" + from = cur + } + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, term.length) == term) + found.push(word); + } + + if (found.length) return {list: found, from: from, to: to}; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnUnfocus: true, + completeOnSingleClick: true, + container: null, + customKeys: null, + extraKeys: null + }; + + CodeMirror.defineOption("hintOptions", null); +}); diff --git a/lib/redactor/codemirror/addon/hint/sql-hint.js b/lib/redactor/codemirror/addon/hint/sql-hint.js new file mode 100644 index 0000000..444eba8 --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/sql-hint.js @@ -0,0 +1,304 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../../mode/sql/sql"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var tables; + var defaultTable; + var keywords; + var identifierQuote; + var CONS = { + QUERY_DIV: ";", + ALIAS_KEYWORD: "AS" + }; + var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos; + + function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } + + function getKeywords(editor) { + var mode = editor.doc.modeOption; + if (mode === "sql") mode = "text/x-sql"; + return CodeMirror.resolveMode(mode).keywords; + } + + function getIdentifierQuote(editor) { + var mode = editor.doc.modeOption; + if (mode === "sql") mode = "text/x-sql"; + return CodeMirror.resolveMode(mode).identifierQuote || "`"; + } + + function getText(item) { + return typeof item == "string" ? item : item.text; + } + + function wrapTable(name, value) { + if (isArray(value)) value = {columns: value} + if (!value.text) value.text = name + return value + } + + function parseTables(input) { + var result = {} + if (isArray(input)) { + for (var i = input.length - 1; i >= 0; i--) { + var item = input[i] + result[getText(item).toUpperCase()] = wrapTable(getText(item), item) + } + } else if (input) { + for (var name in input) + result[name.toUpperCase()] = wrapTable(name, input[name]) + } + return result + } + + function getTable(name) { + return tables[name.toUpperCase()] + } + + function shallowClone(object) { + var result = {}; + for (var key in object) if (object.hasOwnProperty(key)) + result[key] = object[key]; + return result; + } + + function match(string, word) { + var len = string.length; + var sub = getText(word).substr(0, len); + return string.toUpperCase() === sub.toUpperCase(); + } + + function addMatches(result, search, wordlist, formatter) { + if (isArray(wordlist)) { + for (var i = 0; i < wordlist.length; i++) + if (match(search, wordlist[i])) result.push(formatter(wordlist[i])) + } else { + for (var word in wordlist) if (wordlist.hasOwnProperty(word)) { + var val = wordlist[word] + if (!val || val === true) + val = word + else + val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text + if (match(search, val)) result.push(formatter(val)) + } + } + } + + function cleanName(name) { + // Get rid name from identifierQuote and preceding dot(.) + if (name.charAt(0) == ".") { + name = name.substr(1); + } + // replace doublicated identifierQuotes with single identifierQuotes + // and remove single identifierQuotes + var nameParts = name.split(identifierQuote+identifierQuote); + for (var i = 0; i < nameParts.length; i++) + nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), ""); + return nameParts.join(identifierQuote); + } + + function insertIdentifierQuotes(name) { + var nameParts = getText(name).split("."); + for (var i = 0; i < nameParts.length; i++) + nameParts[i] = identifierQuote + + // doublicate identifierQuotes + nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) + + identifierQuote; + var escaped = nameParts.join("."); + if (typeof name == "string") return escaped; + name = shallowClone(name); + name.text = escaped; + return name; + } + + function nameCompletion(cur, token, result, editor) { + // Try to complete table, column names and return start position of completion + var useIdentifierQuotes = false; + var nameParts = []; + var start = token.start; + var cont = true; + while (cont) { + cont = (token.string.charAt(0) == "."); + useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote); + + start = token.start; + nameParts.unshift(cleanName(token.string)); + + token = editor.getTokenAt(Pos(cur.line, token.start)); + if (token.string == ".") { + cont = true; + token = editor.getTokenAt(Pos(cur.line, token.start)); + } + } + + // Try to complete table names + var string = nameParts.join("."); + addMatches(result, string, tables, function(w) { + return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; + }); + + // Try to complete columns from defaultTable + addMatches(result, string, defaultTable, function(w) { + return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; + }); + + // Try to complete columns + string = nameParts.pop(); + var table = nameParts.join("."); + + var alias = false; + var aliasTable = table; + // Check if table is available. If not, find table by Alias + if (!getTable(table)) { + var oldTable = table; + table = findTableByAlias(table, editor); + if (table !== oldTable) alias = true; + } + + var columns = getTable(table); + if (columns && columns.columns) + columns = columns.columns; + + if (columns) { + addMatches(result, string, columns, function(w) { + var tableInsert = table; + if (alias == true) tableInsert = aliasTable; + if (typeof w == "string") { + w = tableInsert + "." + w; + } else { + w = shallowClone(w); + w.text = tableInsert + "." + w.text; + } + return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; + }); + } + + return start; + } + + function eachWord(lineText, f) { + var words = lineText.split(/\s+/) + for (var i = 0; i < words.length; i++) + if (words[i]) f(words[i].replace(/[,;]/g, '')) + } + + function findTableByAlias(alias, editor) { + var doc = editor.doc; + var fullQuery = doc.getValue(); + var aliasUpperCase = alias.toUpperCase(); + var previousWord = ""; + var table = ""; + var separator = []; + var validRange = { + start: Pos(0, 0), + end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) + }; + + //add separator + var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); + while(indexOfSeparator != -1) { + separator.push(doc.posFromIndex(indexOfSeparator)); + indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); + } + separator.unshift(Pos(0, 0)); + separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); + + //find valid range + var prevItem = null; + var current = editor.getCursor() + for (var i = 0; i < separator.length; i++) { + if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) { + validRange = {start: prevItem, end: separator[i]}; + break; + } + prevItem = separator[i]; + } + + if (validRange.start) { + var query = doc.getRange(validRange.start, validRange.end, false); + + for (var i = 0; i < query.length; i++) { + var lineText = query[i]; + eachWord(lineText, function(word) { + var wordUpperCase = word.toUpperCase(); + if (wordUpperCase === aliasUpperCase && getTable(previousWord)) + table = previousWord; + if (wordUpperCase !== CONS.ALIAS_KEYWORD) + previousWord = word; + }); + if (table) break; + } + } + return table; + } + + CodeMirror.registerHelper("hint", "sql", function(editor, options) { + tables = parseTables(options && options.tables) + var defaultTableName = options && options.defaultTable; + var disableKeywords = options && options.disableKeywords; + defaultTable = defaultTableName && getTable(defaultTableName); + keywords = getKeywords(editor); + identifierQuote = getIdentifierQuote(editor); + + if (defaultTableName && !defaultTable) + defaultTable = findTableByAlias(defaultTableName, editor); + + defaultTable = defaultTable || []; + + if (defaultTable.columns) + defaultTable = defaultTable.columns; + + var cur = editor.getCursor(); + var result = []; + var token = editor.getTokenAt(cur), start, end, search; + if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + + if (token.string.match(/^[.`"\w@]\w*$/)) { + search = token.string; + start = token.start; + end = token.end; + } else { + start = end = cur.ch; + search = ""; + } + if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) { + start = nameCompletion(cur, token, result, editor); + } else { + var objectOrClass = function(w, className) { + if (typeof w === "object") { + w.className = className; + } else { + w = { text: w, className: className }; + } + return w; + }; + addMatches(result, search, defaultTable, function(w) { + return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table"); + }); + addMatches( + result, + search, + tables, function(w) { + return objectOrClass(w, "CodeMirror-hint-table"); + } + ); + if (!disableKeywords) + addMatches(result, search, keywords, function(w) { + return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword"); + }); + } + + return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; + }); +}); diff --git a/lib/redactor/codemirror/addon/hint/xml-hint.js b/lib/redactor/codemirror/addon/hint/xml-hint.js new file mode 100644 index 0000000..7575b37 --- /dev/null +++ b/lib/redactor/codemirror/addon/hint/xml-hint.js @@ -0,0 +1,123 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function matches(hint, typed, matchInMiddle) { + if (matchInMiddle) return hint.indexOf(typed) >= 0; + else return hint.lastIndexOf(typed, 0) == 0; + } + + function getHints(cm, options) { + var tags = options && options.schemaInfo; + var quote = (options && options.quoteChar) || '"'; + var matchInMiddle = options && options.matchInMiddle; + if (!tags) return; + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + if (token.end > cur.ch) { + token.end = cur.ch; + token.string = token.string.slice(0, cur.ch - token.start); + } + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (!inner.mode.xmlCurrentTag) return + var result = [], replaceToken = false, prefix; + var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string); + var tagName = tag && /^\w/.test(token.string), tagStart; + + if (tagName) { + var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); + var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; + if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); + } else if (tag && token.string == "<") { + tagType = "open"; + } else if (tag && token.string == ""); + } else { + // Attribute completion + var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs; + var globalAttrs = tags["!attrs"]; + if (!attrs && !globalAttrs) return; + if (!attrs) { + attrs = globalAttrs; + } else if (globalAttrs) { // Combine tag-local and global attributes + var set = {}; + for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; + for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; + attrs = set; + } + if (token.type == "string" || token.string == "=") { // A value + var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), + Pos(cur.line, token.type == "string" ? token.start : token.end)); + var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; + if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; + if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget + if (token.type == "string") { + prefix = token.string; + var n = 0; + if (/['"]/.test(token.string.charAt(0))) { + quote = token.string.charAt(0); + prefix = token.string.slice(1); + n++; + } + var len = token.string.length; + if (/['"]/.test(token.string.charAt(len - 1))) { + quote = token.string.charAt(len - 1); + prefix = token.string.substr(n, len - 2); + } + if (n) { // an opening quote + var line = cm.getLine(cur.line); + if (line.length > token.end && line.charAt(token.end) == quote) token.end++; // include a closing quote + } + replaceToken = true; + } + for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle)) + result.push(quote + atValues[i] + quote); + } else { // An attribute name + if (token.type == "attribute") { + prefix = token.string; + replaceToken = true; + } + for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || matches(attr, prefix, matchInMiddle))) + result.push(attr); + } + } + return { + list: result, + from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, + to: replaceToken ? Pos(cur.line, token.end) : cur + }; + } + + CodeMirror.registerHelper("hint", "xml", getHints); +}); diff --git a/lib/redactor/codemirror/addon/lint/coffeescript-lint.js b/lib/redactor/codemirror/addon/lint/coffeescript-lint.js new file mode 100644 index 0000000..a54c703 --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/coffeescript-lint.js @@ -0,0 +1,47 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js + +// declare global: coffeelint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "coffeescript", function(text) { + var found = []; + if (!window.coffeelint) { + if (window.console) { + window.console.error("Error: window.coffeelint not defined, CodeMirror CoffeeScript linting cannot run."); + } + return found; + } + var parseError = function(err) { + var loc = err.lineNumber; + found.push({from: CodeMirror.Pos(loc-1, 0), + to: CodeMirror.Pos(loc, 0), + severity: err.level, + message: err.message}); + }; + try { + var res = coffeelint.lint(text); + for(var i = 0; i < res.length; i++) { + parseError(res[i]); + } + } catch(e) { + found.push({from: CodeMirror.Pos(e.location.first_line, 0), + to: CodeMirror.Pos(e.location.last_line, e.location.last_column), + severity: 'error', + message: e.message}); + } + return found; +}); + +}); diff --git a/lib/redactor/codemirror/addon/lint/css-lint.js b/lib/redactor/codemirror/addon/lint/css-lint.js new file mode 100644 index 0000000..6058a73 --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/css-lint.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on csslint.js from https://github.com/stubbornella/csslint + +// declare global: CSSLint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "css", function(text, options) { + var found = []; + if (!window.CSSLint) { + if (window.console) { + window.console.error("Error: window.CSSLint not defined, CodeMirror CSS linting cannot run."); + } + return found; + } + var results = CSSLint.verify(text, options), messages = results.messages, message = null; + for ( var i = 0; i < messages.length; i++) { + message = messages[i]; + var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; +}); + +}); diff --git a/lib/redactor/codemirror/addon/lint/html-lint.js b/lib/redactor/codemirror/addon/lint/html-lint.js new file mode 100644 index 0000000..5295c33 --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/html-lint.js @@ -0,0 +1,59 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js + +// declare global: HTMLHint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("htmlhint")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "htmlhint"], mod); + else // Plain browser env + mod(CodeMirror, window.HTMLHint); +})(function(CodeMirror, HTMLHint) { + "use strict"; + + var defaultRules = { + "tagname-lowercase": true, + "attr-lowercase": true, + "attr-value-double-quotes": true, + "doctype-first": false, + "tag-pair": true, + "spec-char-escape": true, + "id-unique": true, + "src-not-empty": true, + "attr-no-duplication": true + }; + + CodeMirror.registerHelper("lint", "html", function(text, options) { + var found = []; + if (HTMLHint && !HTMLHint.verify) { + if(typeof HTMLHint.default !== 'undefined') { + HTMLHint = HTMLHint.default; + } else { + HTMLHint = HTMLHint.HTMLHint; + } + } + if (!HTMLHint) HTMLHint = window.HTMLHint; + if (!HTMLHint) { + if (window.console) { + window.console.error("Error: HTMLHint not found, not defined on window, or not available through define/require, CodeMirror HTML linting cannot run."); + } + return found; + } + var messages = HTMLHint.verify(text, options && options.rules || defaultRules); + for (var i = 0; i < messages.length; i++) { + var message = messages[i]; + var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col; + found.push({ + from: CodeMirror.Pos(startLine, startCol), + to: CodeMirror.Pos(endLine, endCol), + message: message.message, + severity : message.type + }); + } + return found; + }); +}); diff --git a/lib/redactor/codemirror/addon/lint/javascript-lint.js b/lib/redactor/codemirror/addon/lint/javascript-lint.js new file mode 100644 index 0000000..cc132d7 --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/javascript-lint.js @@ -0,0 +1,63 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: JSHINT + + function validator(text, options) { + if (!window.JSHINT) { + if (window.console) { + window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run."); + } + return []; + } + if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation + options.indent = 1; // JSHint default value is 4 + JSHINT(text, options, options.globals); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; + } + + CodeMirror.registerHelper("lint", "javascript", validator); + + function parseErrors(errors, output) { + for ( var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + if (error.line <= 0) { + if (window.console) { + window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error); + } + continue; + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + var index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + var hint = { + message: error.reason, + severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error", + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end) + }; + + output.push(hint); + } + } + } +}); diff --git a/lib/redactor/codemirror/addon/lint/json-lint.js b/lib/redactor/codemirror/addon/lint/json-lint.js new file mode 100644 index 0000000..ac1d6ec --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/json-lint.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Depends on jsonlint.js from https://github.com/zaach/jsonlint + +// declare global: jsonlint + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.registerHelper("lint", "json", function(text) { + var found = []; + if (!window.jsonlint) { + if (window.console) { + window.console.error("Error: window.jsonlint not defined, CodeMirror JSON linting cannot run."); + } + return found; + } + // for jsonlint's web dist jsonlint is exported as an object with a single property parser, of which parseError + // is a subproperty + var jsonlint = window.jsonlint.parser || window.jsonlint + jsonlint.parseError = function(str, hash) { + var loc = hash.loc; + found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), + to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), + message: str}); + }; + try { jsonlint.parse(text); } + catch(e) {} + return found; +}); + +}); diff --git a/lib/redactor/codemirror/addon/lint/lint.css b/lib/redactor/codemirror/addon/lint/lint.css new file mode 100644 index 0000000..f097cfe --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/lint.css @@ -0,0 +1,73 @@ +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: #ffd; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: black; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + white-space: pre-wrap; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { + background-position: left bottom; + background-repeat: repeat-x; +} + +.CodeMirror-lint-mark-error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.CodeMirror-lint-mark-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; + position: relative; +} + +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); +} + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} diff --git a/lib/redactor/codemirror/addon/lint/lint.js b/lib/redactor/codemirror/addon/lint/lint.js new file mode 100644 index 0000000..aa75ba0 --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/lint.js @@ -0,0 +1,252 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var GUTTER_ID = "CodeMirror-lint-markers"; + + function showTooltip(e, content) { + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; + tt.appendChild(content.cloneNode(true)); + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + CodeMirror.on(document, "mousemove", position); + position(e); + if (tt.style.opacity != null) tt.style.opacity = 1; + return tt; + } + function rm(elt) { + if (elt.parentNode) elt.parentNode.removeChild(elt); + } + function hideTooltip(tt) { + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function() { rm(tt); }, 600); + } + + function showTooltipFor(e, content, node) { + var tooltip = showTooltip(e, content); + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { hideTooltip(tooltip); tooltip = null; } + } + var poll = setInterval(function() { + if (tooltip) for (var n = node;; n = n.parentNode) { + if (n && n.nodeType == 11) n = n.host; + if (n == document.body) return; + if (!n) { hide(); break; } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); + } + + function LintState(cm, options, hasGutter) { + this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function(e) { onMouseOver(cm, e); }; + this.waitingFor = 0 + } + + function parseOptions(_cm, options) { + if (options instanceof Function) return {getAnnotations: options}; + if (!options || options === true) options = {}; + return options; + } + + function clearMarks(cm) { + var state = cm.state.lint; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked.length = 0; + } + + function makeMarker(labels, severity, multiple, tooltips) { + var marker = document.createElement("div"), inner = marker; + marker.className = "CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker-multiple"; + } + + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { + showTooltipFor(e, labels, inner); + }); + + return marker; + } + + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; + } + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); + } + return lines; + } + + function annotationTooltip(ann) { + var severity = ann.severity; + if (!severity) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message-" + severity; + if (typeof ann.messageHTML != 'undefined') { + tip.innerHTML = ann.messageHTML; + } else { + tip.appendChild(document.createTextNode(ann.message)); + } + return tip; + } + + function lintAsync(cm, getAnnotations, passOptions) { + var state = cm.state.lint + var id = ++state.waitingFor + function abort() { + id = -1 + cm.off("change", abort) + } + cm.on("change", abort) + getAnnotations(cm.getValue(), function(annotations, arg2) { + cm.off("change", abort) + if (state.waitingFor != id) return + if (arg2 && annotations instanceof CodeMirror) annotations = arg2 + cm.operation(function() {updateLinting(cm, annotations)}) + }, passOptions, cm); + } + + function startLinting(cm) { + var state = cm.state.lint, options = state.options; + /* + * Passing rules in `options` property prevents JSHint (and other linters) from complaining + * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. + */ + var passOptions = options.options || options; + var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!getAnnotations) return; + if (options.async || getAnnotations.async) { + lintAsync(cm, getAnnotations, passOptions) + } else { + var annotations = getAnnotations(cm.getValue(), passOptions, cm); + if (!annotations) return; + if (annotations.then) annotations.then(function(issues) { + cm.operation(function() {updateLinting(cm, issues)}) + }); + else cm.operation(function() {updateLinting(cm, annotations)}) + } + } + + function updateLinting(cm, annotationsNotSorted) { + clearMarks(cm); + var state = cm.state.lint, options = state.options; + + var annotations = groupByLine(annotationsNotSorted); + + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; + + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); + + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!severity) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); + + if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); + + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint-mark-" + severity, + __annotation: ann + })); + } + + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, + state.options.tooltips)); + } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); + } + + function onChange(cm) { + var state = cm.state.lint; + if (!state) return; + clearTimeout(state.timeout); + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); + } + + function popupTooltips(annotations, e) { + var target = e.target || e.srcElement; + var tooltip = document.createDocumentFragment(); + for (var i = 0; i < annotations.length; i++) { + var ann = annotations[i]; + tooltip.appendChild(annotationTooltip(ann)); + } + showTooltipFor(e, tooltip, target); + } + + function onMouseOver(cm, e) { + var target = e.target || e.srcElement; + if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; + var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; + var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); + + var annotations = []; + for (var i = 0; i < spans.length; ++i) { + var ann = spans[i].__annotation; + if (ann) annotations.push(ann); + } + if (annotations.length) popupTooltips(annotations, e); + } + + CodeMirror.defineOption("lint", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + if (cm.state.lint.options.lintOnChange !== false) + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + clearTimeout(cm.state.lint.timeout); + delete cm.state.lint; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); + if (state.options.lintOnChange !== false) + cm.on("change", onChange); + if (state.options.tooltips != false && state.options.tooltips != "gutter") + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + + startLinting(cm); + } + }); + + CodeMirror.defineExtension("performLint", function() { + if (this.state.lint) startLinting(this); + }); +}); diff --git a/lib/redactor/codemirror/addon/lint/yaml-lint.js b/lib/redactor/codemirror/addon/lint/yaml-lint.js new file mode 100644 index 0000000..b4ac5ab --- /dev/null +++ b/lib/redactor/codemirror/addon/lint/yaml-lint.js @@ -0,0 +1,41 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +// Depends on js-yaml.js from https://github.com/nodeca/js-yaml + +// declare global: jsyaml + +CodeMirror.registerHelper("lint", "yaml", function(text) { + var found = []; + if (!window.jsyaml) { + if (window.console) { + window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run."); + } + return found; + } + try { jsyaml.loadAll(text); } + catch(e) { + var loc = e.mark, + // js-yaml YAMLException doesn't always provide an accurate lineno + // e.g., when there are multiple yaml docs + // --- + // --- + // foo:bar + from = loc ? CodeMirror.Pos(loc.line, loc.column) : CodeMirror.Pos(0, 0), + to = from; + found.push({ from: from, to: to, message: e.message }); + } + return found; +}); + +}); diff --git a/lib/redactor/codemirror/addon/merge/merge.css b/lib/redactor/codemirror/addon/merge/merge.css new file mode 100644 index 0000000..dadd7f5 --- /dev/null +++ b/lib/redactor/codemirror/addon/merge/merge.css @@ -0,0 +1,119 @@ +.CodeMirror-merge { + position: relative; + border: 1px solid #ddd; + white-space: pre; +} + +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { + height: 350px; +} + +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } + +.CodeMirror-merge-pane { + display: inline-block; + white-space: normal; + vertical-align: top; +} +.CodeMirror-merge-pane-rightmost { + position: absolute; + right: 0px; + z-index: 1; +} + +.CodeMirror-merge-gap { + z-index: 2; + display: inline-block; + height: 100%; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + position: relative; + background: #f8f8f8; +} + +.CodeMirror-merge-scrolllock-wrap { + position: absolute; + bottom: 0; left: 50%; +} +.CodeMirror-merge-scrolllock { + position: relative; + left: -50%; + cursor: pointer; + color: #555; + line-height: 1; +} +.CodeMirror-merge-scrolllock:after { + content: "\21db\00a0\00a0\21da"; +} +.CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after { + content: "\21db\21da"; +} + +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { + position: absolute; + left: 0; top: 0; + right: 0; bottom: 0; + line-height: 1; +} + +.CodeMirror-merge-copy { + position: absolute; + cursor: pointer; + color: #44c; + z-index: 3; +} + +.CodeMirror-merge-copy-reverse { + position: absolute; + cursor: pointer; + color: #44c; +} + +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } + +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +.CodeMirror-merge-r-chunk { background: #ffffe0; } +.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } +.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } +.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk { background: #eef; } +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } + +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } + +.CodeMirror-merge-collapsed-widget:before { + content: "(...)"; +} +.CodeMirror-merge-collapsed-widget { + cursor: pointer; + color: #88b; + background: #eef; + border: 1px solid #ddf; + font-size: 90%; + padding: 0 3px; + border-radius: 4px; +} +.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } diff --git a/lib/redactor/codemirror/addon/merge/merge.js b/lib/redactor/codemirror/addon/merge/merge.js new file mode 100644 index 0000000..8296540 --- /dev/null +++ b/lib/redactor/codemirror/addon/merge/merge.js @@ -0,0 +1,1002 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); // Note non-packaged dependency diff_match_patch + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "diff_match_patch"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var Pos = CodeMirror.Pos; + var svgNS = "http://www.w3.org/2000/svg"; + + function DiffView(mv, type) { + this.mv = mv; + this.type = type; + this.classes = type == "left" + ? {chunk: "CodeMirror-merge-l-chunk", + start: "CodeMirror-merge-l-chunk-start", + end: "CodeMirror-merge-l-chunk-end", + insert: "CodeMirror-merge-l-inserted", + del: "CodeMirror-merge-l-deleted", + connect: "CodeMirror-merge-l-connect"} + : {chunk: "CodeMirror-merge-r-chunk", + start: "CodeMirror-merge-r-chunk-start", + end: "CodeMirror-merge-r-chunk-end", + insert: "CodeMirror-merge-r-inserted", + del: "CodeMirror-merge-r-deleted", + connect: "CodeMirror-merge-r-connect"}; + } + + DiffView.prototype = { + constructor: DiffView, + init: function(pane, orig, options) { + this.edit = this.mv.edit; + ;(this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this); + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); + if (this.mv.options.connect == "align") { + if (!this.edit.state.trackAlignable) this.edit.state.trackAlignable = new TrackAlignable(this.edit) + this.orig.state.trackAlignable = new TrackAlignable(this.orig) + } + this.lockButton.title = this.edit.phrase("Toggle locked scrolling"); + + this.orig.state.diffViews = [this]; + var classLocation = options.chunkClassLocation || "background"; + if (Object.prototype.toString.call(classLocation) != "[object Array]") classLocation = [classLocation] + this.classes.classLocation = classLocation + + this.diff = getDiff(asString(orig), asString(options.value), this.mv.options.ignoreWhitespace); + this.chunks = getChunks(this.diff); + this.diffOutOfDate = this.dealigned = false; + this.needsScrollSync = null + + this.showDifferences = options.showDifferences !== false; + }, + registerEvents: function(otherDv) { + this.forceUpdate = registerUpdate(this); + setScrollLock(this, true, false); + registerScroll(this, otherDv); + }, + setShowDifferences: function(val) { + val = val !== false; + if (val != this.showDifferences) { + this.showDifferences = val; + this.forceUpdate("full"); + } + } + }; + + function ensureDiff(dv) { + if (dv.diffOutOfDate) { + dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue(), dv.mv.options.ignoreWhitespace); + dv.chunks = getChunks(dv.diff); + dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); + } + } + + var updating = false; + function registerUpdate(dv) { + var edit = {from: 0, to: 0, marked: []}; + var orig = {from: 0, to: 0, marked: []}; + var debounceChange, updatingFast = false; + function update(mode) { + updating = true; + updatingFast = false; + if (mode == "full") { + if (dv.svg) clear(dv.svg); + if (dv.copyButtons) clear(dv.copyButtons); + clearMarks(dv.edit, edit.marked, dv.classes); + clearMarks(dv.orig, orig.marked, dv.classes); + edit.from = edit.to = orig.from = orig.to = 0; + } + ensureDiff(dv); + if (dv.showDifferences) { + updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); + updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); + } + + if (dv.mv.options.connect == "align") + alignChunks(dv); + makeConnections(dv); + if (dv.needsScrollSync != null) syncScroll(dv, dv.needsScrollSync) + + updating = false; + } + function setDealign(fast) { + if (updating) return; + dv.dealigned = true; + set(fast); + } + function set(fast) { + if (updating || updatingFast) return; + clearTimeout(debounceChange); + if (fast === true) updatingFast = true; + debounceChange = setTimeout(update, fast === true ? 20 : 250); + } + function change(_cm, change) { + if (!dv.diffOutOfDate) { + dv.diffOutOfDate = true; + edit.from = edit.to = orig.from = orig.to = 0; + } + // Update faster when a line was added/removed + setDealign(change.text.length - 1 != change.to.line - change.from.line); + } + function swapDoc() { + dv.diffOutOfDate = true; + dv.dealigned = true; + update("full"); + } + dv.edit.on("change", change); + dv.orig.on("change", change); + dv.edit.on("swapDoc", swapDoc); + dv.orig.on("swapDoc", swapDoc); + if (dv.mv.options.connect == "align") { + CodeMirror.on(dv.edit.state.trackAlignable, "realign", setDealign) + CodeMirror.on(dv.orig.state.trackAlignable, "realign", setDealign) + } + dv.edit.on("viewportChange", function() { set(false); }); + dv.orig.on("viewportChange", function() { set(false); }); + update(); + return update; + } + + function registerScroll(dv, otherDv) { + dv.edit.on("scroll", function() { + syncScroll(dv, true) && makeConnections(dv); + }); + dv.orig.on("scroll", function() { + syncScroll(dv, false) && makeConnections(dv); + if (otherDv) syncScroll(otherDv, true) && makeConnections(otherDv); + }); + } + + function syncScroll(dv, toOrig) { + // Change handler will do a refresh after a timeout when diff is out of date + if (dv.diffOutOfDate) { + if (dv.lockScroll && dv.needsScrollSync == null) dv.needsScrollSync = toOrig + return false + } + dv.needsScrollSync = null + if (!dv.lockScroll) return true; + var editor, other, now = +new Date; + if (toOrig) { editor = dv.edit; other = dv.orig; } + else { editor = dv.orig; other = dv.edit; } + // Don't take action if the position of this editor was recently set + // (to prevent feedback loops) + if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 250 > now) return false; + + var sInfo = editor.getScrollInfo(); + if (dv.mv.options.connect == "align") { + targetPos = sInfo.top; + } else { + var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen; + var mid = editor.lineAtHeight(midY, "local"); + var around = chunkBoundariesAround(dv.chunks, mid, toOrig); + var off = getOffsets(editor, toOrig ? around.edit : around.orig); + var offOther = getOffsets(other, toOrig ? around.orig : around.edit); + var ratio = (midY - off.top) / (off.bot - off.top); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + } + + other.scrollTo(sInfo.left, targetPos); + other.state.scrollSetAt = now; + other.state.scrollSetBy = dv; + return true; + } + + function getOffsets(editor, around) { + var bot = around.after; + if (bot == null) bot = editor.lastLine() + 1; + return {top: editor.heightAtLine(around.before || 0, "local"), + bot: editor.heightAtLine(bot, "local")}; + } + + function setScrollLock(dv, val, action) { + dv.lockScroll = val; + if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv); + (val ? CodeMirror.addClass : CodeMirror.rmClass)(dv.lockButton, "CodeMirror-merge-scrolllock-enabled"); + } + + // Updating the marks for editor content + + function removeClass(editor, line, classes) { + var locs = classes.classLocation + for (var i = 0; i < locs.length; i++) { + editor.removeLineClass(line, locs[i], classes.chunk); + editor.removeLineClass(line, locs[i], classes.start); + editor.removeLineClass(line, locs[i], classes.end); + } + } + + function clearMarks(editor, arr, classes) { + for (var i = 0; i < arr.length; ++i) { + var mark = arr[i]; + if (mark instanceof CodeMirror.TextMarker) + mark.clear(); + else if (mark.parent) + removeClass(editor, mark, classes); + } + arr.length = 0; + } + + // FIXME maybe add a margin around viewport to prevent too many updates + function updateMarks(editor, diff, state, type, classes) { + var vp = editor.getViewport(); + editor.operation(function() { + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + clearMarks(editor, state.marked, classes); + markChanges(editor, diff, type, state.marked, vp.from, vp.to, classes); + state.from = vp.from; state.to = vp.to; + } else { + if (vp.from < state.from) { + markChanges(editor, diff, type, state.marked, vp.from, state.from, classes); + state.from = vp.from; + } + if (vp.to > state.to) { + markChanges(editor, diff, type, state.marked, state.to, vp.to, classes); + state.to = vp.to; + } + } + }); + } + + function addClass(editor, lineNr, classes, main, start, end) { + var locs = classes.classLocation, line = editor.getLineHandle(lineNr); + for (var i = 0; i < locs.length; i++) { + if (main) editor.addLineClass(line, locs[i], classes.chunk); + if (start) editor.addLineClass(line, locs[i], classes.start); + if (end) editor.addLineClass(line, locs[i], classes.end); + } + return line; + } + + function markChanges(editor, diff, type, marks, from, to, classes) { + var pos = Pos(0, 0); + var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); + var cls = type == DIFF_DELETE ? classes.del : classes.insert; + function markChunk(start, end) { + var bfrom = Math.max(from, start), bto = Math.min(to, end); + for (var i = bfrom; i < bto; ++i) + marks.push(addClass(editor, i, classes, true, i == start, i == end - 1)); + // When the chunk is empty, make sure a horizontal line shows up + if (start == end && bfrom == end && bto == end) { + if (bfrom) + marks.push(addClass(editor, bfrom - 1, classes, false, false, true)); + else + marks.push(addClass(editor, bfrom, classes, false, true, false)); + } + } + + var chunkStart = 0, pending = false; + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0], str = part[1]; + if (tp == DIFF_EQUAL) { + var cleanFrom = pos.line + (startOfLineClean(diff, i) ? 0 : 1); + moveOver(pos, str); + var cleanTo = pos.line + (endOfLineClean(diff, i) ? 1 : 0); + if (cleanTo > cleanFrom) { + if (pending) { markChunk(chunkStart, cleanFrom); pending = false } + chunkStart = cleanTo; + } + } else { + pending = true + if (tp == type) { + var end = moveOver(pos, str, true); + var a = posMax(top, pos), b = posMin(bot, end); + if (!posEq(a, b)) + marks.push(editor.markText(a, b, {className: cls})); + pos = end; + } + } + } + if (pending) markChunk(chunkStart, pos.line + 1); + } + + // Updating the gap between editor and original + + function makeConnections(dv) { + if (!dv.showDifferences) return; + + if (dv.svg) { + clear(dv.svg); + var w = dv.gap.offsetWidth; + attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight); + } + if (dv.copyButtons) clear(dv.copyButtons); + + var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); + var outerTop = dv.mv.wrap.getBoundingClientRect().top + var sTopEdit = outerTop - dv.edit.getScrollerElement().getBoundingClientRect().top + dv.edit.getScrollInfo().top + var sTopOrig = outerTop - dv.orig.getScrollerElement().getBoundingClientRect().top + dv.orig.getScrollInfo().top; + for (var i = 0; i < dv.chunks.length; i++) { + var ch = dv.chunks[i]; + if (ch.editFrom <= vpEdit.to && ch.editTo >= vpEdit.from && + ch.origFrom <= vpOrig.to && ch.origTo >= vpOrig.from) + drawConnectorsForChunk(dv, ch, sTopOrig, sTopEdit, w); + } + } + + function getMatchingOrigLine(editLine, chunks) { + var editStart = 0, origStart = 0; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + if (chunk.editTo > editLine && chunk.editFrom <= editLine) return null; + if (chunk.editFrom > editLine) break; + editStart = chunk.editTo; + origStart = chunk.origTo; + } + return origStart + (editLine - editStart); + } + + // Combines information about chunks and widgets/markers to return + // an array of lines, in a single editor, that probably need to be + // aligned with their counterparts in the editor next to it. + function alignableFor(cm, chunks, isOrig) { + var tracker = cm.state.trackAlignable + var start = cm.firstLine(), trackI = 0 + var result = [] + for (var i = 0;; i++) { + var chunk = chunks[i] + var chunkStart = !chunk ? 1e9 : isOrig ? chunk.origFrom : chunk.editFrom + for (; trackI < tracker.alignable.length; trackI += 2) { + var n = tracker.alignable[trackI] + 1 + if (n <= start) continue + if (n <= chunkStart) result.push(n) + else break + } + if (!chunk) break + result.push(start = isOrig ? chunk.origTo : chunk.editTo) + } + return result + } + + // Given information about alignable lines in two editors, fill in + // the result (an array of three-element arrays) to reflect the + // lines that need to be aligned with each other. + function mergeAlignable(result, origAlignable, chunks, setIndex) { + var rI = 0, origI = 0, chunkI = 0, diff = 0 + outer: for (;; rI++) { + var nextR = result[rI], nextO = origAlignable[origI] + if (!nextR && nextO == null) break + + var rLine = nextR ? nextR[0] : 1e9, oLine = nextO == null ? 1e9 : nextO + while (chunkI < chunks.length) { + var chunk = chunks[chunkI] + if (chunk.origFrom <= oLine && chunk.origTo > oLine) { + origI++ + rI-- + continue outer; + } + if (chunk.editTo > rLine) { + if (chunk.editFrom <= rLine) continue outer; + break + } + diff += (chunk.origTo - chunk.origFrom) - (chunk.editTo - chunk.editFrom) + chunkI++ + } + if (rLine == oLine - diff) { + nextR[setIndex] = oLine + origI++ + } else if (rLine < oLine - diff) { + nextR[setIndex] = rLine + diff + } else { + var record = [oLine - diff, null, null] + record[setIndex] = oLine + result.splice(rI, 0, record) + origI++ + } + } + } + + function findAlignedLines(dv, other) { + var alignable = alignableFor(dv.edit, dv.chunks, false), result = [] + if (other) for (var i = 0, j = 0; i < other.chunks.length; i++) { + var n = other.chunks[i].editTo + while (j < alignable.length && alignable[j] < n) j++ + if (j == alignable.length || alignable[j] != n) alignable.splice(j++, 0, n) + } + for (var i = 0; i < alignable.length; i++) + result.push([alignable[i], null, null]) + + mergeAlignable(result, alignableFor(dv.orig, dv.chunks, true), dv.chunks, 1) + if (other) + mergeAlignable(result, alignableFor(other.orig, other.chunks, true), other.chunks, 2) + + return result + } + + function alignChunks(dv, force) { + if (!dv.dealigned && !force) return; + if (!dv.orig.curOp) return dv.orig.operation(function() { + alignChunks(dv, force); + }); + + dv.dealigned = false; + var other = dv.mv.left == dv ? dv.mv.right : dv.mv.left; + if (other) { + ensureDiff(other); + other.dealigned = false; + } + var linesToAlign = findAlignedLines(dv, other); + + // Clear old aligners + var aligners = dv.mv.aligners; + for (var i = 0; i < aligners.length; i++) + aligners[i].clear(); + aligners.length = 0; + + var cm = [dv.edit, dv.orig], scroll = []; + if (other) cm.push(other.orig); + for (var i = 0; i < cm.length; i++) + scroll.push(cm[i].getScrollInfo().top); + + for (var ln = 0; ln < linesToAlign.length; ln++) + alignLines(cm, linesToAlign[ln], aligners); + + for (var i = 0; i < cm.length; i++) + cm[i].scrollTo(null, scroll[i]); + } + + function alignLines(cm, lines, aligners) { + var maxOffset = 0, offset = []; + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var off = cm[i].heightAtLine(lines[i], "local"); + offset[i] = off; + maxOffset = Math.max(maxOffset, off); + } + for (var i = 0; i < cm.length; i++) if (lines[i] != null) { + var diff = maxOffset - offset[i]; + if (diff > 1) + aligners.push(padAbove(cm[i], lines[i], diff)); + } + } + + function padAbove(cm, line, size) { + var above = true; + if (line > cm.lastLine()) { + line--; + above = false; + } + var elt = document.createElement("div"); + elt.className = "CodeMirror-merge-spacer"; + elt.style.height = size + "px"; elt.style.minWidth = "1px"; + return cm.addLineWidget(line, elt, {height: size, above: above, mergeSpacer: true, handleMouseEvents: true}); + } + + function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { + var flip = dv.type == "left"; + var top = dv.orig.heightAtLine(chunk.origFrom, "local", true) - sTopOrig; + if (dv.svg) { + var topLpx = top; + var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local", true) - sTopEdit; + if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } + var botLpx = dv.orig.heightAtLine(chunk.origTo, "local", true) - sTopOrig; + var botRpx = dv.edit.heightAtLine(chunk.editTo, "local", true) - sTopEdit; + if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } + var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; + var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; + attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")), + "d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z", + "class", dv.classes.connect); + } + if (dv.copyButtons) { + var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy")); + var editOriginals = dv.mv.options.allowEditingOriginals; + copy.title = dv.edit.phrase(editOriginals ? "Push to left" : "Revert chunk"); + copy.chunk = chunk; + copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; + + if (editOriginals) { + var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy-reverse")); + copyReverse.title = "Push to right"; + copyReverse.chunk = {editFrom: chunk.origFrom, editTo: chunk.origTo, + origFrom: chunk.editFrom, origTo: chunk.editTo}; + copyReverse.style.top = topReverse + "px"; + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; + } + } + } + + function copyChunk(dv, to, from, chunk) { + if (dv.diffOutOfDate) return; + var origStart = chunk.origTo > from.lastLine() ? Pos(chunk.origFrom - 1) : Pos(chunk.origFrom, 0) + var origEnd = Pos(chunk.origTo, 0) + var editStart = chunk.editTo > to.lastLine() ? Pos(chunk.editFrom - 1) : Pos(chunk.editFrom, 0) + var editEnd = Pos(chunk.editTo, 0) + var handler = dv.mv.options.revertChunk + if (handler) + handler(dv.mv, from, origStart, origEnd, to, editStart, editEnd) + else + to.replaceRange(from.getRange(origStart, origEnd), editStart, editEnd) + } + + // Merge view, containing 0, 1, or 2 diff views. + + var MergeView = CodeMirror.MergeView = function(node, options) { + if (!(this instanceof MergeView)) return new MergeView(node, options); + + this.options = options; + var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight; + + var hasLeft = origLeft != null, hasRight = origRight != null; + var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0); + var wrap = [], left = this.left = null, right = this.right = null; + var self = this; + + if (hasLeft) { + left = this.left = new DiffView(this, "left"); + var leftPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-left"); + wrap.push(leftPane); + wrap.push(buildGap(left)); + } + + var editPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-editor"); + wrap.push(editPane); + + if (hasRight) { + right = this.right = new DiffView(this, "right"); + wrap.push(buildGap(right)); + var rightPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-right"); + wrap.push(rightPane); + } + + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; + + wrap.push(elt("div", null, null, "height: 0; clear: both;")); + + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); + this.edit = CodeMirror(editPane, copyObj(options)); + + if (left) left.init(leftPane, origLeft, options); + if (right) right.init(rightPane, origRight, options); + if (options.collapseIdentical) + this.editor().operation(function() { + collapseIdenticalStretches(self, options.collapseIdentical); + }); + if (options.connect == "align") { + this.aligners = []; + alignChunks(this.left || this.right, true); + } + if (left) left.registerEvents(right) + if (right) right.registerEvents(left) + + + var onResize = function() { + if (left) makeConnections(left); + if (right) makeConnections(right); + }; + CodeMirror.on(window, "resize", onResize); + var resizeInterval = setInterval(function() { + for (var p = wrapElt.parentNode; p && p != document.body; p = p.parentNode) {} + if (!p) { clearInterval(resizeInterval); CodeMirror.off(window, "resize", onResize); } + }, 5000); + }; + + function buildGap(dv) { + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); + CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); + var gapElts = [lockWrap]; + if (dv.mv.options.revertButtons !== false) { + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); + CodeMirror.on(dv.copyButtons, "click", function(e) { + var node = e.target || e.srcElement; + if (!node.chunk) return; + if (node.className == "CodeMirror-merge-copy-reverse") { + copyChunk(dv, dv.orig, dv.edit, node.chunk); + return; + } + copyChunk(dv, dv.edit, dv.orig, node.chunk); + }); + gapElts.unshift(dv.copyButtons); + } + if (dv.mv.options.connect != "align") { + var svg = document.createElementNS && document.createElementNS(svgNS, "svg"); + if (svg && !svg.createSVGRect) svg = null; + dv.svg = svg; + if (svg) gapElts.push(svg); + } + + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); + } + + MergeView.prototype = { + constructor: MergeView, + editor: function() { return this.edit; }, + rightOriginal: function() { return this.right && this.right.orig; }, + leftOriginal: function() { return this.left && this.left.orig; }, + setShowDifferences: function(val) { + if (this.right) this.right.setShowDifferences(val); + if (this.left) this.left.setShowDifferences(val); + }, + rightChunks: function() { + if (this.right) { ensureDiff(this.right); return this.right.chunks; } + }, + leftChunks: function() { + if (this.left) { ensureDiff(this.left); return this.left.chunks; } + } + }; + + function asString(obj) { + if (typeof obj == "string") return obj; + else return obj.getValue(); + } + + // Operations on diffs + var dmp; + function getDiff(a, b, ignoreWhitespace) { + if (!dmp) dmp = new diff_match_patch(); + + var diff = dmp.diff_main(a, b); + // The library sometimes leaves in empty parts, which confuse the algorithm + for (var i = 0; i < diff.length; ++i) { + var part = diff[i]; + if (ignoreWhitespace ? !/[^ \t]/.test(part[1]) : !part[1]) { + diff.splice(i--, 1); + } else if (i && diff[i - 1][0] == part[0]) { + diff.splice(i--, 1); + diff[i][1] += part[1]; + } + } + return diff; + } + + function getChunks(diff) { + var chunks = []; + if (!diff.length) return chunks; + var startEdit = 0, startOrig = 0; + var edit = Pos(0, 0), orig = Pos(0, 0); + for (var i = 0; i < diff.length; ++i) { + var part = diff[i], tp = part[0]; + if (tp == DIFF_EQUAL) { + var startOff = !startOfLineClean(diff, i) || edit.line < startEdit || orig.line < startOrig ? 1 : 0; + var cleanFromEdit = edit.line + startOff, cleanFromOrig = orig.line + startOff; + moveOver(edit, part[1], null, orig); + var endOff = endOfLineClean(diff, i) ? 1 : 0; + var cleanToEdit = edit.line + endOff, cleanToOrig = orig.line + endOff; + if (cleanToEdit > cleanFromEdit) { + if (i) chunks.push({origFrom: startOrig, origTo: cleanFromOrig, + editFrom: startEdit, editTo: cleanFromEdit}); + startEdit = cleanToEdit; startOrig = cleanToOrig; + } + } else { + moveOver(tp == DIFF_INSERT ? edit : orig, part[1]); + } + } + if (startEdit <= edit.line || startOrig <= orig.line) + chunks.push({origFrom: startOrig, origTo: orig.line + 1, + editFrom: startEdit, editTo: edit.line + 1}); + return chunks; + } + + function endOfLineClean(diff, i) { + if (i == diff.length - 1) return true; + var next = diff[i + 1][1]; + if ((next.length == 1 && i < diff.length - 2) || next.charCodeAt(0) != 10) return false; + if (i == diff.length - 2) return true; + next = diff[i + 2][1]; + return (next.length > 1 || i == diff.length - 3) && next.charCodeAt(0) == 10; + } + + function startOfLineClean(diff, i) { + if (i == 0) return true; + var last = diff[i - 1][1]; + if (last.charCodeAt(last.length - 1) != 10) return false; + if (i == 1) return true; + last = diff[i - 2][1]; + return last.charCodeAt(last.length - 1) == 10; + } + + function chunkBoundariesAround(chunks, n, nInEdit) { + var beforeE, afterE, beforeO, afterO; + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var fromLocal = nInEdit ? chunk.editFrom : chunk.origFrom; + var toLocal = nInEdit ? chunk.editTo : chunk.origTo; + if (afterE == null) { + if (fromLocal > n) { afterE = chunk.editFrom; afterO = chunk.origFrom; } + else if (toLocal > n) { afterE = chunk.editTo; afterO = chunk.origTo; } + } + if (toLocal <= n) { beforeE = chunk.editTo; beforeO = chunk.origTo; } + else if (fromLocal <= n) { beforeE = chunk.editFrom; beforeO = chunk.origFrom; } + } + return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}}; + } + + function collapseSingle(cm, from, to) { + cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + var widget = document.createElement("span"); + widget.className = "CodeMirror-merge-collapsed-widget"; + widget.title = cm.phrase("Identical text collapsed. Click to expand."); + var mark = cm.markText(Pos(from, 0), Pos(to - 1), { + inclusiveLeft: true, + inclusiveRight: true, + replacedWith: widget, + clearOnEnter: true + }); + function clear() { + mark.clear(); + cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); + } + if (mark.explicitlyCleared) clear(); + CodeMirror.on(widget, "click", clear); + mark.on("clear", clear); + CodeMirror.on(widget, "click", clear); + return {mark: mark, clear: clear}; + } + + function collapseStretch(size, editors) { + var marks = []; + function clear() { + for (var i = 0; i < marks.length; i++) marks[i].clear(); + } + for (var i = 0; i < editors.length; i++) { + var editor = editors[i]; + var mark = collapseSingle(editor.cm, editor.line, editor.line + size); + marks.push(mark); + mark.mark.on("clear", clear); + } + return marks[0].mark; + } + + function unclearNearChunks(dv, margin, off, clear) { + for (var i = 0; i < dv.chunks.length; i++) { + var chunk = dv.chunks[i]; + for (var l = chunk.editFrom - margin; l < chunk.editTo + margin; l++) { + var pos = l + off; + if (pos >= 0 && pos < clear.length) clear[pos] = false; + } + } + } + + function collapseIdenticalStretches(mv, margin) { + if (typeof margin != "number") margin = 2; + var clear = [], edit = mv.editor(), off = edit.firstLine(); + for (var l = off, e = edit.lastLine(); l <= e; l++) clear.push(true); + if (mv.left) unclearNearChunks(mv.left, margin, off, clear); + if (mv.right) unclearNearChunks(mv.right, margin, off, clear); + + for (var i = 0; i < clear.length; i++) { + if (clear[i]) { + var line = i + off; + for (var size = 1; i < clear.length - 1 && clear[i + 1]; i++, size++) {} + if (size > margin) { + var editors = [{line: line, cm: edit}]; + if (mv.left) editors.push({line: getMatchingOrigLine(line, mv.left.chunks), cm: mv.left.orig}); + if (mv.right) editors.push({line: getMatchingOrigLine(line, mv.right.chunks), cm: mv.right.orig}); + var mark = collapseStretch(size, editors); + if (mv.options.onCollapse) mv.options.onCollapse(mv, line, size, mark); + } + } + } + } + + // General utilities + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + function clear(node) { + for (var count = node.childNodes.length; count > 0; --count) + node.removeChild(node.firstChild); + } + + function attrs(elt) { + for (var i = 1; i < arguments.length; i += 2) + elt.setAttribute(arguments[i], arguments[i+1]); + } + + function copyObj(obj, target) { + if (!target) target = {}; + for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + return target; + } + + function moveOver(pos, str, copy, other) { + var out = copy ? Pos(pos.line, pos.ch) : pos, at = 0; + for (;;) { + var nl = str.indexOf("\n", at); + if (nl == -1) break; + ++out.line; + if (other) ++other.line; + at = nl + 1; + } + out.ch = (at ? 0 : out.ch) + (str.length - at); + if (other) other.ch = (at ? 0 : other.ch) + (str.length - at); + return out; + } + + // Tracks collapsed markers and line widgets, in order to be able to + // accurately align the content of two editors. + + var F_WIDGET = 1, F_WIDGET_BELOW = 2, F_MARKER = 4 + + function TrackAlignable(cm) { + this.cm = cm + this.alignable = [] + this.height = cm.doc.height + var self = this + cm.on("markerAdded", function(_, marker) { + if (!marker.collapsed) return + var found = marker.find(1) + if (found != null) self.set(found.line, F_MARKER) + }) + cm.on("markerCleared", function(_, marker, _min, max) { + if (max != null && marker.collapsed) + self.check(max, F_MARKER, self.hasMarker) + }) + cm.on("markerChanged", this.signal.bind(this)) + cm.on("lineWidgetAdded", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.set(lineNo - 1, F_WIDGET_BELOW) + else self.set(lineNo, F_WIDGET) + }) + cm.on("lineWidgetCleared", function(_, widget, lineNo) { + if (widget.mergeSpacer) return + if (widget.above) self.check(lineNo - 1, F_WIDGET_BELOW, self.hasWidgetBelow) + else self.check(lineNo, F_WIDGET, self.hasWidget) + }) + cm.on("lineWidgetChanged", this.signal.bind(this)) + cm.on("change", function(_, change) { + var start = change.from.line, nBefore = change.to.line - change.from.line + var nAfter = change.text.length - 1, end = start + nAfter + if (nBefore || nAfter) self.map(start, nBefore, nAfter) + self.check(end, F_MARKER, self.hasMarker) + if (nBefore || nAfter) self.check(change.from.line, F_MARKER, self.hasMarker) + }) + cm.on("viewportChange", function() { + if (self.cm.doc.height != self.height) self.signal() + }) + } + + TrackAlignable.prototype = { + signal: function() { + CodeMirror.signal(this, "realign") + this.height = this.cm.doc.height + }, + + set: function(n, flags) { + var pos = -1 + for (; pos < this.alignable.length; pos += 2) { + var diff = this.alignable[pos] - n + if (diff == 0) { + if ((this.alignable[pos + 1] & flags) == flags) return + this.alignable[pos + 1] |= flags + this.signal() + return + } + if (diff > 0) break + } + this.signal() + this.alignable.splice(pos, 0, n, flags) + }, + + find: function(n) { + for (var i = 0; i < this.alignable.length; i += 2) + if (this.alignable[i] == n) return i + return -1 + }, + + check: function(n, flag, pred) { + var found = this.find(n) + if (found == -1 || !(this.alignable[found + 1] & flag)) return + if (!pred.call(this, n)) { + this.signal() + var flags = this.alignable[found + 1] & ~flag + if (flags) this.alignable[found + 1] = flags + else this.alignable.splice(found, 2) + } + }, + + hasMarker: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.markedSpans) for (var i = 0; i < handle.markedSpans.length; i++) + if (handle.markedSpans[i].marker.collapsed && handle.markedSpans[i].to != null) + return true + return false + }, + + hasWidget: function(n) { + var handle = this.cm.getLineHandle(n) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (!handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + hasWidgetBelow: function(n) { + if (n == this.cm.lastLine()) return false + var handle = this.cm.getLineHandle(n + 1) + if (handle.widgets) for (var i = 0; i < handle.widgets.length; i++) + if (handle.widgets[i].above && !handle.widgets[i].mergeSpacer) return true + return false + }, + + map: function(from, nBefore, nAfter) { + var diff = nAfter - nBefore, to = from + nBefore, widgetFrom = -1, widgetTo = -1 + for (var i = 0; i < this.alignable.length; i += 2) { + var n = this.alignable[i] + if (n == from && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetFrom = i + if (n == to && (this.alignable[i + 1] & F_WIDGET_BELOW)) widgetTo = i + if (n <= from) continue + else if (n < to) this.alignable.splice(i--, 2) + else this.alignable[i] += diff + } + if (widgetFrom > -1) { + var flags = this.alignable[widgetFrom + 1] + if (flags == F_WIDGET_BELOW) this.alignable.splice(widgetFrom, 2) + else this.alignable[widgetFrom + 1] = flags & ~F_WIDGET_BELOW + } + if (widgetTo > -1 && nAfter) + this.set(from + nAfter, F_WIDGET_BELOW) + } + } + + function posMin(a, b) { return (a.line - b.line || a.ch - b.ch) < 0 ? a : b; } + function posMax(a, b) { return (a.line - b.line || a.ch - b.ch) > 0 ? a : b; } + function posEq(a, b) { return a.line == b.line && a.ch == b.ch; } + + function findPrevDiff(chunks, start, isOrig) { + for (var i = chunks.length - 1; i >= 0; i--) { + var chunk = chunks[i]; + var to = (isOrig ? chunk.origTo : chunk.editTo) - 1; + if (to < start) return to; + } + } + + function findNextDiff(chunks, start, isOrig) { + for (var i = 0; i < chunks.length; i++) { + var chunk = chunks[i]; + var from = (isOrig ? chunk.origFrom : chunk.editFrom); + if (from > start) return from; + } + } + + function goNearbyDiff(cm, dir) { + var found = null, views = cm.state.diffViews, line = cm.getCursor().line; + if (views) for (var i = 0; i < views.length; i++) { + var dv = views[i], isOrig = cm == dv.orig; + ensureDiff(dv); + var pos = dir < 0 ? findPrevDiff(dv.chunks, line, isOrig) : findNextDiff(dv.chunks, line, isOrig); + if (pos != null && (found == null || (dir < 0 ? pos > found : pos < found))) + found = pos; + } + if (found != null) + cm.setCursor(found, 0); + else + return CodeMirror.Pass; + } + + CodeMirror.commands.goNextDiff = function(cm) { + return goNearbyDiff(cm, 1); + }; + CodeMirror.commands.goPrevDiff = function(cm) { + return goNearbyDiff(cm, -1); + }; +}); diff --git a/lib/redactor/codemirror/addon/mode/loadmode.js b/lib/redactor/codemirror/addon/mode/loadmode.js new file mode 100644 index 0000000..4ce716a --- /dev/null +++ b/lib/redactor/codemirror/addon/mode/loadmode.js @@ -0,0 +1,64 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), "cjs"); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); }); + else // Plain browser env + mod(CodeMirror, "plain"); +})(function(CodeMirror, env) { + if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; + + var loading = {}; + function splitCallback(cont, n) { + var countDown = n; + return function() { if (--countDown == 0) cont(); }; + } + function ensureDeps(mode, cont) { + var deps = CodeMirror.modes[mode].dependencies; + if (!deps) return cont(); + var missing = []; + for (var i = 0; i < deps.length; ++i) { + if (!CodeMirror.modes.hasOwnProperty(deps[i])) + missing.push(deps[i]); + } + if (!missing.length) return cont(); + var split = splitCallback(cont, missing.length); + for (var i = 0; i < missing.length; ++i) + CodeMirror.requireMode(missing[i], split); + } + + CodeMirror.requireMode = function(mode, cont) { + if (typeof mode != "string") mode = mode.name; + if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont); + if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); + + var file = CodeMirror.modeURL.replace(/%N/g, mode); + if (env == "plain") { + var script = document.createElement("script"); + script.src = file; + var others = document.getElementsByTagName("script")[0]; + var list = loading[mode] = [cont]; + CodeMirror.on(script, "load", function() { + ensureDeps(mode, function() { + for (var i = 0; i < list.length; ++i) list[i](); + }); + }); + others.parentNode.insertBefore(script, others); + } else if (env == "cjs") { + require(file); + cont(); + } else if (env == "amd") { + requirejs([file], cont); + } + }; + + CodeMirror.autoLoadMode = function(instance, mode) { + if (!CodeMirror.modes.hasOwnProperty(mode)) + CodeMirror.requireMode(mode, function() { + instance.setOption("mode", instance.getOption("mode")); + }); + }; +}); diff --git a/lib/redactor/codemirror/addon/mode/multiplex.js b/lib/redactor/codemirror/addon/mode/multiplex.js new file mode 100644 index 0000000..93fd9a5 --- /dev/null +++ b/lib/redactor/codemirror/addon/mode/multiplex.js @@ -0,0 +1,131 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.multiplexingMode = function(outer /*, others */) { + // Others should be {open, close, mode [, delimStyle] [, innerStyle]} objects + var others = Array.prototype.slice.call(arguments, 1); + + function indexOf(string, pattern, from, returnEnd) { + if (typeof pattern == "string") { + var found = string.indexOf(pattern, from); + return returnEnd && found > -1 ? found + pattern.length : found; + } + var m = pattern.exec(from ? string.slice(from) : string); + return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1; + } + + return { + startState: function() { + return { + outer: CodeMirror.startState(outer), + innerActive: null, + inner: null + }; + }, + + copyState: function(state) { + return { + outer: CodeMirror.copyState(outer, state.outer), + innerActive: state.innerActive, + inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner) + }; + }, + + token: function(stream, state) { + if (!state.innerActive) { + var cutOff = Infinity, oldContent = stream.string; + for (var i = 0; i < others.length; ++i) { + var other = others[i]; + var found = indexOf(oldContent, other.open, stream.pos); + if (found == stream.pos) { + if (!other.parseDelimiters) stream.match(other.open); + state.innerActive = other; + + // Get the outer indent, making sure to handle CodeMirror.Pass + var outerIndent = 0; + if (outer.indent) { + var possibleOuterIndent = outer.indent(state.outer, "", ""); + if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent; + } + + state.inner = CodeMirror.startState(other.mode, outerIndent); + return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open"); + } else if (found != -1 && found < cutOff) { + cutOff = found; + } + } + if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); + var outerToken = outer.token(stream, state.outer); + if (cutOff != Infinity) stream.string = oldContent; + return outerToken; + } else { + var curInner = state.innerActive, oldContent = stream.string; + if (!curInner.close && stream.sol()) { + state.innerActive = state.inner = null; + return this.token(stream, state); + } + var found = curInner.close ? indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1; + if (found == stream.pos && !curInner.parseDelimiters) { + stream.match(curInner.close); + state.innerActive = state.inner = null; + return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close"); + } + if (found > -1) stream.string = oldContent.slice(0, found); + var innerToken = curInner.mode.token(stream, state.inner); + if (found > -1) stream.string = oldContent; + + if (found == stream.pos && curInner.parseDelimiters) + state.innerActive = state.inner = null; + + if (curInner.innerStyle) { + if (innerToken) innerToken = innerToken + " " + curInner.innerStyle; + else innerToken = curInner.innerStyle; + } + + return innerToken; + } + }, + + indent: function(state, textAfter, line) { + var mode = state.innerActive ? state.innerActive.mode : outer; + if (!mode.indent) return CodeMirror.Pass; + return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line); + }, + + blankLine: function(state) { + var mode = state.innerActive ? state.innerActive.mode : outer; + if (mode.blankLine) { + mode.blankLine(state.innerActive ? state.inner : state.outer); + } + if (!state.innerActive) { + for (var i = 0; i < others.length; ++i) { + var other = others[i]; + if (other.open === "\n") { + state.innerActive = other; + state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0); + } + } + } else if (state.innerActive.close === "\n") { + state.innerActive = state.inner = null; + } + }, + + electricChars: outer.electricChars, + + innerMode: function(state) { + return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; + } + }; +}; + +}); diff --git a/lib/redactor/codemirror/addon/mode/multiplex_test.js b/lib/redactor/codemirror/addon/mode/multiplex_test.js new file mode 100644 index 0000000..c51cad4 --- /dev/null +++ b/lib/redactor/codemirror/addon/mode/multiplex_test.js @@ -0,0 +1,33 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function() { + CodeMirror.defineMode("markdown_with_stex", function(){ + var inner = CodeMirror.getMode({}, "stex"); + var outer = CodeMirror.getMode({}, "markdown"); + + var innerOptions = { + open: '$', + close: '$', + mode: inner, + delimStyle: 'delim', + innerStyle: 'inner' + }; + + return CodeMirror.multiplexingMode(outer, innerOptions); + }); + + var mode = CodeMirror.getMode({}, "markdown_with_stex"); + + function MT(name) { + test.mode( + name, + mode, + Array.prototype.slice.call(arguments, 1), + 'multiplexing'); + } + + MT( + "stexInsideMarkdown", + "[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]"); +})(); diff --git a/lib/redactor/codemirror/addon/mode/overlay.js b/lib/redactor/codemirror/addon/mode/overlay.js new file mode 100644 index 0000000..016e3c2 --- /dev/null +++ b/lib/redactor/codemirror/addon/mode/overlay.js @@ -0,0 +1,90 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Utility function that allows modes to be combined. The mode given +// as the base argument takes care of most of the normal mode +// functionality, but a second (typically simple) mode is used, which +// can override the style of text. Both modes get to parse all of the +// text, but when both assign a non-null style to a piece of code, the +// overlay wins, unless the combine argument was true and not overridden, +// or state.overlay.combineTokens was true, in which case the styles are +// combined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.overlayMode = function(base, overlay, combine) { + return { + startState: function() { + return { + base: CodeMirror.startState(base), + overlay: CodeMirror.startState(overlay), + basePos: 0, baseCur: null, + overlayPos: 0, overlayCur: null, + streamSeen: null + }; + }, + copyState: function(state) { + return { + base: CodeMirror.copyState(base, state.base), + overlay: CodeMirror.copyState(overlay, state.overlay), + basePos: state.basePos, baseCur: null, + overlayPos: state.overlayPos, overlayCur: null + }; + }, + + token: function(stream, state) { + if (stream != state.streamSeen || + Math.min(state.basePos, state.overlayPos) < stream.start) { + state.streamSeen = stream; + state.basePos = state.overlayPos = stream.start; + } + + if (stream.start == state.basePos) { + state.baseCur = base.token(stream, state.base); + state.basePos = stream.pos; + } + if (stream.start == state.overlayPos) { + stream.pos = stream.start; + state.overlayCur = overlay.token(stream, state.overlay); + state.overlayPos = stream.pos; + } + stream.pos = Math.min(state.basePos, state.overlayPos); + + // state.overlay.combineTokens always takes precedence over combine, + // unless set to null + if (state.overlayCur == null) return state.baseCur; + else if (state.baseCur != null && + state.overlay.combineTokens || + combine && state.overlay.combineTokens == null) + return state.baseCur + " " + state.overlayCur; + else return state.overlayCur; + }, + + indent: base.indent && function(state, textAfter, line) { + return base.indent(state.base, textAfter, line); + }, + electricChars: base.electricChars, + + innerMode: function(state) { return {state: state.base, mode: base}; }, + + blankLine: function(state) { + var baseToken, overlayToken; + if (base.blankLine) baseToken = base.blankLine(state.base); + if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay); + + return overlayToken == null ? + baseToken : + (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken); + } + }; +}; + +}); diff --git a/lib/redactor/codemirror/addon/mode/simple.js b/lib/redactor/codemirror/addon/mode/simple.js new file mode 100644 index 0000000..655f991 --- /dev/null +++ b/lib/redactor/codemirror/addon/mode/simple.js @@ -0,0 +1,216 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineSimpleMode = function(name, states) { + CodeMirror.defineMode(name, function(config) { + return CodeMirror.simpleMode(config, states); + }); + }; + + CodeMirror.simpleMode = function(config, states) { + ensureState(states, "start"); + var states_ = {}, meta = states.meta || {}, hasIndentation = false; + for (var state in states) if (state != meta && states.hasOwnProperty(state)) { + var list = states_[state] = [], orig = states[state]; + for (var i = 0; i < orig.length; i++) { + var data = orig[i]; + list.push(new Rule(data, states)); + if (data.indent || data.dedent) hasIndentation = true; + } + } + var mode = { + startState: function() { + return {state: "start", pending: null, + local: null, localState: null, + indent: hasIndentation ? [] : null}; + }, + copyState: function(state) { + var s = {state: state.state, pending: state.pending, + local: state.local, localState: null, + indent: state.indent && state.indent.slice(0)}; + if (state.localState) + s.localState = CodeMirror.copyState(state.local.mode, state.localState); + if (state.stack) + s.stack = state.stack.slice(0); + for (var pers = state.persistentStates; pers; pers = pers.next) + s.persistentStates = {mode: pers.mode, + spec: pers.spec, + state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state), + next: s.persistentStates}; + return s; + }, + token: tokenFunction(states_, config), + innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; }, + indent: indentFunction(states_, meta) + }; + if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop)) + mode[prop] = meta[prop]; + return mode; + }; + + function ensureState(states, name) { + if (!states.hasOwnProperty(name)) + throw new Error("Undefined state " + name + " in simple mode"); + } + + function toRegex(val, caret) { + if (!val) return /(?:)/; + var flags = ""; + if (val instanceof RegExp) { + if (val.ignoreCase) flags = "i"; + val = val.source; + } else { + val = String(val); + } + return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags); + } + + function asToken(val) { + if (!val) return null; + if (val.apply) return val + if (typeof val == "string") return val.replace(/\./g, " "); + var result = []; + for (var i = 0; i < val.length; i++) + result.push(val[i] && val[i].replace(/\./g, " ")); + return result; + } + + function Rule(data, states) { + if (data.next || data.push) ensureState(states, data.next || data.push); + this.regex = toRegex(data.regex); + this.token = asToken(data.token); + this.data = data; + } + + function tokenFunction(states, config) { + return function(stream, state) { + if (state.pending) { + var pend = state.pending.shift(); + if (state.pending.length == 0) state.pending = null; + stream.pos += pend.text.length; + return pend.token; + } + + if (state.local) { + if (state.local.end && stream.match(state.local.end)) { + var tok = state.local.endToken || null; + state.local = state.localState = null; + return tok; + } else { + var tok = state.local.mode.token(stream, state.localState), m; + if (state.local.endScan && (m = state.local.endScan.exec(stream.current()))) + stream.pos = stream.start + m.index; + return tok; + } + } + + var curState = states[state.state]; + for (var i = 0; i < curState.length; i++) { + var rule = curState[i]; + var matches = (!rule.data.sol || stream.sol()) && stream.match(rule.regex); + if (matches) { + if (rule.data.next) { + state.state = rule.data.next; + } else if (rule.data.push) { + (state.stack || (state.stack = [])).push(state.state); + state.state = rule.data.push; + } else if (rule.data.pop && state.stack && state.stack.length) { + state.state = state.stack.pop(); + } + + if (rule.data.mode) + enterLocalMode(config, state, rule.data.mode, rule.token); + if (rule.data.indent) + state.indent.push(stream.indentation() + config.indentUnit); + if (rule.data.dedent) + state.indent.pop(); + var token = rule.token + if (token && token.apply) token = token(matches) + if (matches.length > 2 && rule.token && typeof rule.token != "string") { + state.pending = []; + for (var j = 2; j < matches.length; j++) + if (matches[j]) + state.pending.push({text: matches[j], token: rule.token[j - 1]}); + stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0)); + return token[0]; + } else if (token && token.join) { + return token[0]; + } else { + return token; + } + } + } + stream.next(); + return null; + }; + } + + function cmp(a, b) { + if (a === b) return true; + if (!a || typeof a != "object" || !b || typeof b != "object") return false; + var props = 0; + for (var prop in a) if (a.hasOwnProperty(prop)) { + if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false; + props++; + } + for (var prop in b) if (b.hasOwnProperty(prop)) props--; + return props == 0; + } + + function enterLocalMode(config, state, spec, token) { + var pers; + if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next) + if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p; + var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec); + var lState = pers ? pers.state : CodeMirror.startState(mode); + if (spec.persistent && !pers) + state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates}; + + state.localState = lState; + state.local = {mode: mode, + end: spec.end && toRegex(spec.end), + endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false), + endToken: token && token.join ? token[token.length - 1] : token}; + } + + function indexOf(val, arr) { + for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true; + } + + function indentFunction(states, meta) { + return function(state, textAfter, line) { + if (state.local && state.local.mode.indent) + return state.local.mode.indent(state.localState, textAfter, line); + if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1) + return CodeMirror.Pass; + + var pos = state.indent.length - 1, rules = states[state.state]; + scan: for (;;) { + for (var i = 0; i < rules.length; i++) { + var rule = rules[i]; + if (rule.data.dedent && rule.data.dedentIfLineStart !== false) { + var m = rule.regex.exec(textAfter); + if (m && m[0]) { + pos--; + if (rule.next || rule.push) rules = states[rule.next || rule.push]; + textAfter = textAfter.slice(m[0].length); + continue scan; + } + } + } + break; + } + return pos < 0 ? 0 : state.indent[pos]; + }; + } +}); diff --git a/lib/redactor/codemirror/addon/runmode/colorize.js b/lib/redactor/codemirror/addon/runmode/colorize.js new file mode 100644 index 0000000..3be5411 --- /dev/null +++ b/lib/redactor/codemirror/addon/runmode/colorize.js @@ -0,0 +1,40 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./runmode")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./runmode"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; + + function textContent(node, out) { + if (node.nodeType == 3) return out.push(node.nodeValue); + for (var ch = node.firstChild; ch; ch = ch.nextSibling) { + textContent(ch, out); + if (isBlock.test(node.nodeType)) out.push("\n"); + } + } + + CodeMirror.colorize = function(collection, defaultMode) { + if (!collection) collection = document.body.getElementsByTagName("pre"); + + for (var i = 0; i < collection.length; ++i) { + var node = collection[i]; + var mode = node.getAttribute("data-lang") || defaultMode; + if (!mode) continue; + + var text = []; + textContent(node, text); + node.innerHTML = ""; + CodeMirror.runMode(text.join(""), mode, node); + + node.className += " cm-s-default"; + } + }; +}); diff --git a/lib/redactor/codemirror/addon/runmode/runmode-standalone.js b/lib/redactor/codemirror/addon/runmode/runmode-standalone.js new file mode 100644 index 0000000..745eaf8 --- /dev/null +++ b/lib/redactor/codemirror/addon/runmode/runmode-standalone.js @@ -0,0 +1,158 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +window.CodeMirror = {}; + +(function() { +"use strict"; + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this.lineStart = 0; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start - this.lineStart;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + }, + lookAhead: function() { return null } +}; +CodeMirror.StringStream = StringStream; + +CodeMirror.startState = function (mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; +CodeMirror.defineMode = function (name, mode) { + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; +}; +CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; +CodeMirror.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; +CodeMirror.getMode = function (options, spec) { + spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, spec); +}; +CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; +CodeMirror.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +CodeMirror.defineMIME("text/plain", "null"); + +CodeMirror.runMode = function (string, modespec, callback, options) { + var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || 4; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function (text, style) { + if (text == "\n") { + node.appendChild(document.createElement("br")); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0; ;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; +})(); diff --git a/lib/redactor/codemirror/addon/runmode/runmode.js b/lib/redactor/codemirror/addon/runmode/runmode.js new file mode 100644 index 0000000..eb4cadf --- /dev/null +++ b/lib/redactor/codemirror/addon/runmode/runmode.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.runMode = function(string, modespec, callback, options) { + var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + + if (callback.appendChild) { + var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function(text, style) { + if (text == "\n") { + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0;;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +}); diff --git a/lib/redactor/codemirror/addon/runmode/runmode.node.js b/lib/redactor/codemirror/addon/runmode/runmode.node.js new file mode 100644 index 0000000..53b6994 --- /dev/null +++ b/lib/redactor/codemirror/addon/runmode/runmode.node.js @@ -0,0 +1,197 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +/* Just enough of CodeMirror to run runMode under node.js */ + +function splitLines(string){return string.split(/\r\n?|\n/);}; + +// Counts the column offset in a string, taking tabs into account. +// Used mostly to find indentation. +var countColumn = exports.countColumn = function(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } +}; + +function StringStream(string, tabSize, context) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + this.context = context +}; + +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == this.lineStart;}, + peek: function() {return this.string.charAt(this.pos) || undefined;}, + next: function() { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function(match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) {++this.pos; return ch;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start; + }, + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function() {this.pos = this.string.length;}, + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function() { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);}, + hideFirstChars: function(n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + }, + lookAhead: function(n) { + var line = this.context.line + n + return line >= this.context.lines.length ? null : this.context.lines[line] + } +}; +exports.StringStream = StringStream; + +exports.startState = function(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = exports.modes = {}, mimeModes = exports.mimeModes = {}; +exports.defineMode = function(name, mode) { + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; +}; +exports.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; + +exports.defineMode("null", function() { + return {token: function(stream) {stream.skipToEnd();}}; +}); +exports.defineMIME("text/plain", "null"); + +exports.resolveMode = function(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + spec = mimeModes[spec.name]; + } + if (typeof spec == "string") return {name: spec}; + else return spec || {name: "null"}; +}; + +function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; +} + +// This can be used to attach properties to mode objects from +// outside the actual mode definition. +var modeExtensions = exports.modeExtensions = {}; +exports.extendMode = function(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); +}; + +exports.getMode = function(options, spec) { + var spec = exports.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return exports.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; +}; + +exports.innerMode = function(mode, state) { + var info; + while (mode.innerMode) { + info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; +} + +exports.registerHelper = exports.registerGlobalHelper = Math.min; + +exports.runMode = function(string, modespec, callback, options) { + var mode = exports.getMode({indentUnit: 2}, modespec); + var lines = splitLines(string), state = (options && options.state) || exports.startState(mode); + var context = {lines: lines, line: 0} + for (var i = 0, e = lines.length; i < e; ++i, ++context.line) { + if (i) callback("\n"); + var stream = new exports.StringStream(lines[i], 4, context); + if (!stream.string && mode.blankLine) mode.blankLine(state); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start, state); + stream.start = stream.pos; + } + } +}; + +require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; +require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")]; diff --git a/lib/redactor/codemirror/addon/scroll/annotatescrollbar.js b/lib/redactor/codemirror/addon/scroll/annotatescrollbar.js new file mode 100644 index 0000000..9fe61ec --- /dev/null +++ b/lib/redactor/codemirror/addon/scroll/annotatescrollbar.js @@ -0,0 +1,122 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("annotateScrollbar", function(options) { + if (typeof options == "string") options = {className: options}; + return new Annotation(this, options); + }); + + CodeMirror.defineOption("scrollButtonHeight", 0); + + function Annotation(cm, options) { + this.cm = cm; + this.options = options; + this.buttonHeight = options.scrollButtonHeight || cm.getOption("scrollButtonHeight"); + this.annotations = []; + this.doRedraw = this.doUpdate = null; + this.div = cm.getWrapperElement().appendChild(document.createElement("div")); + this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none"; + this.computeScale(); + + function scheduleRedraw(delay) { + clearTimeout(self.doRedraw); + self.doRedraw = setTimeout(function() { self.redraw(); }, delay); + } + + var self = this; + cm.on("refresh", this.resizeHandler = function() { + clearTimeout(self.doUpdate); + self.doUpdate = setTimeout(function() { + if (self.computeScale()) scheduleRedraw(20); + }, 100); + }); + cm.on("markerAdded", this.resizeHandler); + cm.on("markerCleared", this.resizeHandler); + if (options.listenForChanges !== false) + cm.on("changes", this.changeHandler = function() { + scheduleRedraw(250); + }); + } + + Annotation.prototype.computeScale = function() { + var cm = this.cm; + var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight - this.buttonHeight * 2) / + cm.getScrollerElement().scrollHeight + if (hScale != this.hScale) { + this.hScale = hScale; + return true; + } + }; + + Annotation.prototype.update = function(annotations) { + this.annotations = annotations; + this.redraw(); + }; + + Annotation.prototype.redraw = function(compute) { + if (compute !== false) this.computeScale(); + var cm = this.cm, hScale = this.hScale; + + var frag = document.createDocumentFragment(), anns = this.annotations; + + var wrapping = cm.getOption("lineWrapping"); + var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; + var curLine = null, curLineObj = null; + function getY(pos, top) { + if (curLine != pos.line) { + curLine = pos.line; + curLineObj = cm.getLineHandle(curLine); + } + if ((curLineObj.widgets && curLineObj.widgets.length) || + (wrapping && curLineObj.height > singleLineH)) + return cm.charCoords(pos, "local")[top ? "top" : "bottom"]; + var topY = cm.heightAtLine(curLineObj, "local"); + return topY + (top ? 0 : curLineObj.height); + } + + var lastLine = cm.lastLine() + if (cm.display.barWidth) for (var i = 0, nextTop; i < anns.length; i++) { + var ann = anns[i]; + if (ann.to.line > lastLine) continue; + var top = nextTop || getY(ann.from, true) * hScale; + var bottom = getY(ann.to, false) * hScale; + while (i < anns.length - 1) { + if (anns[i + 1].to.line > lastLine) break; + nextTop = getY(anns[i + 1].from, true) * hScale; + if (nextTop > bottom + .9) break; + ann = anns[++i]; + bottom = getY(ann.to, false) * hScale; + } + if (bottom == top) continue; + var height = Math.max(bottom - top, 3); + + var elt = frag.appendChild(document.createElement("div")); + elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " + + (top + this.buttonHeight) + "px; height: " + height + "px"; + elt.className = this.options.className; + if (ann.id) { + elt.setAttribute("annotation-id", ann.id); + } + } + this.div.textContent = ""; + this.div.appendChild(frag); + }; + + Annotation.prototype.clear = function() { + this.cm.off("refresh", this.resizeHandler); + this.cm.off("markerAdded", this.resizeHandler); + this.cm.off("markerCleared", this.resizeHandler); + if (this.changeHandler) this.cm.off("changes", this.changeHandler); + this.div.parentNode.removeChild(this.div); + }; +}); diff --git a/lib/redactor/codemirror/addon/scroll/scrollpastend.js b/lib/redactor/codemirror/addon/scroll/scrollpastend.js new file mode 100644 index 0000000..2ed9d95 --- /dev/null +++ b/lib/redactor/codemirror/addon/scroll/scrollpastend.js @@ -0,0 +1,48 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("scrollPastEnd", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.off("change", onChange); + cm.off("refresh", updateBottomMargin); + cm.display.lineSpace.parentNode.style.paddingBottom = ""; + cm.state.scrollPastEndPadding = null; + } + if (val) { + cm.on("change", onChange); + cm.on("refresh", updateBottomMargin); + updateBottomMargin(cm); + } + }); + + function onChange(cm, change) { + if (CodeMirror.changeEnd(change).line == cm.lastLine()) + updateBottomMargin(cm); + } + + function updateBottomMargin(cm) { + var padding = ""; + if (cm.lineCount() > 1) { + var totalH = cm.display.scroller.clientHeight - 30, + lastLineH = cm.getLineHandle(cm.lastLine()).height; + padding = (totalH - lastLineH) + "px"; + } + if (cm.state.scrollPastEndPadding != padding) { + cm.state.scrollPastEndPadding = padding; + cm.display.lineSpace.parentNode.style.paddingBottom = padding; + cm.off("refresh", updateBottomMargin); + cm.setSize(); + cm.on("refresh", updateBottomMargin); + } + } +}); diff --git a/lib/redactor/codemirror/addon/scroll/simplescrollbars.css b/lib/redactor/codemirror/addon/scroll/simplescrollbars.css new file mode 100644 index 0000000..5eea7aa --- /dev/null +++ b/lib/redactor/codemirror/addon/scroll/simplescrollbars.css @@ -0,0 +1,66 @@ +.CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div { + position: absolute; + background: #ccc; + -moz-box-sizing: border-box; + box-sizing: border-box; + border: 1px solid #bbb; + border-radius: 2px; +} + +.CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical { + position: absolute; + z-index: 6; + background: #eee; +} + +.CodeMirror-simplescroll-horizontal { + bottom: 0; left: 0; + height: 8px; +} +.CodeMirror-simplescroll-horizontal div { + bottom: 0; + height: 100%; +} + +.CodeMirror-simplescroll-vertical { + right: 0; top: 0; + width: 8px; +} +.CodeMirror-simplescroll-vertical div { + right: 0; + width: 100%; +} + + +.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler { + display: none; +} + +.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div { + position: absolute; + background: #bcd; + border-radius: 3px; +} + +.CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical { + position: absolute; + z-index: 6; +} + +.CodeMirror-overlayscroll-horizontal { + bottom: 0; left: 0; + height: 6px; +} +.CodeMirror-overlayscroll-horizontal div { + bottom: 0; + height: 100%; +} + +.CodeMirror-overlayscroll-vertical { + right: 0; top: 0; + width: 6px; +} +.CodeMirror-overlayscroll-vertical div { + right: 0; + width: 100%; +} diff --git a/lib/redactor/codemirror/addon/scroll/simplescrollbars.js b/lib/redactor/codemirror/addon/scroll/simplescrollbars.js new file mode 100644 index 0000000..750a2bd --- /dev/null +++ b/lib/redactor/codemirror/addon/scroll/simplescrollbars.js @@ -0,0 +1,152 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function Bar(cls, orientation, scroll) { + this.orientation = orientation; + this.scroll = scroll; + this.screen = this.total = this.size = 1; + this.pos = 0; + + this.node = document.createElement("div"); + this.node.className = cls + "-" + orientation; + this.inner = this.node.appendChild(document.createElement("div")); + + var self = this; + CodeMirror.on(this.inner, "mousedown", function(e) { + if (e.which != 1) return; + CodeMirror.e_preventDefault(e); + var axis = self.orientation == "horizontal" ? "pageX" : "pageY"; + var start = e[axis], startpos = self.pos; + function done() { + CodeMirror.off(document, "mousemove", move); + CodeMirror.off(document, "mouseup", done); + } + function move(e) { + if (e.which != 1) return done(); + self.moveTo(startpos + (e[axis] - start) * (self.total / self.size)); + } + CodeMirror.on(document, "mousemove", move); + CodeMirror.on(document, "mouseup", done); + }); + + CodeMirror.on(this.node, "click", function(e) { + CodeMirror.e_preventDefault(e); + var innerBox = self.inner.getBoundingClientRect(), where; + if (self.orientation == "horizontal") + where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0; + else + where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0; + self.moveTo(self.pos + where * self.screen); + }); + + function onWheel(e) { + var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"]; + var oldPos = self.pos; + self.moveTo(self.pos + moved); + if (self.pos != oldPos) CodeMirror.e_preventDefault(e); + } + CodeMirror.on(this.node, "mousewheel", onWheel); + CodeMirror.on(this.node, "DOMMouseScroll", onWheel); + } + + Bar.prototype.setPos = function(pos, force) { + if (pos < 0) pos = 0; + if (pos > this.total - this.screen) pos = this.total - this.screen; + if (!force && pos == this.pos) return false; + this.pos = pos; + this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = + (pos * (this.size / this.total)) + "px"; + return true + }; + + Bar.prototype.moveTo = function(pos) { + if (this.setPos(pos)) this.scroll(pos, this.orientation); + } + + var minButtonSize = 10; + + Bar.prototype.update = function(scrollSize, clientSize, barSize) { + var sizeChanged = this.screen != clientSize || this.total != scrollSize || this.size != barSize + if (sizeChanged) { + this.screen = clientSize; + this.total = scrollSize; + this.size = barSize; + } + + var buttonSize = this.screen * (this.size / this.total); + if (buttonSize < minButtonSize) { + this.size -= minButtonSize - buttonSize; + buttonSize = minButtonSize; + } + this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = + buttonSize + "px"; + this.setPos(this.pos, sizeChanged); + }; + + function SimpleScrollbars(cls, place, scroll) { + this.addClass = cls; + this.horiz = new Bar(cls, "horizontal", scroll); + place(this.horiz.node); + this.vert = new Bar(cls, "vertical", scroll); + place(this.vert.node); + this.width = null; + } + + SimpleScrollbars.prototype.update = function(measure) { + if (this.width == null) { + var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle; + if (style) this.width = parseInt(style.height); + } + var width = this.width || 0; + + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + this.vert.node.style.display = needsV ? "block" : "none"; + this.horiz.node.style.display = needsH ? "block" : "none"; + + if (needsV) { + this.vert.update(measure.scrollHeight, measure.clientHeight, + measure.viewHeight - (needsH ? width : 0)); + this.vert.node.style.bottom = needsH ? width + "px" : "0"; + } + if (needsH) { + this.horiz.update(measure.scrollWidth, measure.clientWidth, + measure.viewWidth - (needsV ? width : 0) - measure.barLeft); + this.horiz.node.style.right = needsV ? width + "px" : "0"; + this.horiz.node.style.left = measure.barLeft + "px"; + } + + return {right: needsV ? width : 0, bottom: needsH ? width : 0}; + }; + + SimpleScrollbars.prototype.setScrollTop = function(pos) { + this.vert.setPos(pos); + }; + + SimpleScrollbars.prototype.setScrollLeft = function(pos) { + this.horiz.setPos(pos); + }; + + SimpleScrollbars.prototype.clear = function() { + var parent = this.horiz.node.parentNode; + parent.removeChild(this.horiz.node); + parent.removeChild(this.vert.node); + }; + + CodeMirror.scrollbarModel.simple = function(place, scroll) { + return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll); + }; + CodeMirror.scrollbarModel.overlay = function(place, scroll) { + return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll); + }; +}); diff --git a/lib/redactor/codemirror/addon/search/jump-to-line.js b/lib/redactor/codemirror/addon/search/jump-to-line.js new file mode 100644 index 0000000..1f3526d --- /dev/null +++ b/lib/redactor/codemirror/addon/search/jump-to-line.js @@ -0,0 +1,50 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Defines jumpToLine command. Uses dialog.js if present. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + else f(prompt(shortText, deflt)); + } + + function getJumpDialog(cm) { + return cm.phrase("Jump to line:") + ' ' + cm.phrase("(Use line:column or scroll% syntax)") + ''; + } + + function interpretLine(cm, string) { + var num = Number(string) + if (/^[-+]/.test(string)) return cm.getCursor().line + num + else return num - 1 + } + + CodeMirror.commands.jumpToLine = function(cm) { + var cur = cm.getCursor(); + dialog(cm, getJumpDialog(cm), cm.phrase("Jump to line:"), (cur.line + 1) + ":" + cur.ch, function(posStr) { + if (!posStr) return; + + var match; + if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), Number(match[2])) + } else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) { + var line = Math.round(cm.lineCount() * Number(match[1]) / 100); + if (/^[-+]/.test(match[1])) line = cur.line + line + 1; + cm.setCursor(line - 1, cur.ch); + } else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) { + cm.setCursor(interpretLine(cm, match[1]), cur.ch); + } + }); + }; + + CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine"; +}); diff --git a/lib/redactor/codemirror/addon/search/match-highlighter.js b/lib/redactor/codemirror/addon/search/match-highlighter.js new file mode 100644 index 0000000..b344ac7 --- /dev/null +++ b/lib/redactor/codemirror/addon/search/match-highlighter.js @@ -0,0 +1,165 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Highlighting text that matches the selection +// +// Defines an option highlightSelectionMatches, which, when enabled, +// will style strings that match the selection throughout the +// document. +// +// The option can be set to true to simply enable it, or to a +// {minChars, style, wordsOnly, showToken, delay} object to explicitly +// configure it. minChars is the minimum amount of characters that should be +// selected for the behavior to occur, and style is the token style to +// apply to the matches. This will be prefixed by "cm-" to create an +// actual CSS class name. If wordsOnly is enabled, the matches will be +// highlighted only if the selected text is a word. showToken, when enabled, +// will cause the current token to be highlighted when nothing is selected. +// delay is used to specify how much time to wait, in milliseconds, before +// highlighting the matches. If annotateScrollbar is enabled, the occurences +// will be highlighted on the scrollbar via the matchesonscrollbar addon. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./matchesonscrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./matchesonscrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var defaults = { + style: "matchhighlight", + minChars: 2, + delay: 100, + wordsOnly: false, + annotateScrollbar: false, + showToken: false, + trim: true + } + + function State(options) { + this.options = {} + for (var name in defaults) + this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name] + this.overlay = this.timeout = null; + this.matchesonscroll = null; + this.active = false; + } + + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + removeOverlay(cm); + clearTimeout(cm.state.matchHighlighter.timeout); + cm.state.matchHighlighter = null; + cm.off("cursorActivity", cursorActivity); + cm.off("focus", onFocus) + } + if (val) { + var state = cm.state.matchHighlighter = new State(val); + if (cm.hasFocus()) { + state.active = true + highlightMatches(cm) + } else { + cm.on("focus", onFocus) + } + cm.on("cursorActivity", cursorActivity); + } + }); + + function cursorActivity(cm) { + var state = cm.state.matchHighlighter; + if (state.active || cm.hasFocus()) scheduleHighlight(cm, state) + } + + function onFocus(cm) { + var state = cm.state.matchHighlighter + if (!state.active) { + state.active = true + scheduleHighlight(cm, state) + } + } + + function scheduleHighlight(cm, state) { + clearTimeout(state.timeout); + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay); + } + + function addOverlay(cm, query, hasBoundary, style) { + var state = cm.state.matchHighlighter; + cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style)); + if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) { + var searchFor = hasBoundary ? new RegExp("\\b" + query.replace(/[\\\[.+*?(){|^$]/g, "\\$&") + "\\b") : query; + state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false, + {className: "CodeMirror-selection-highlight-scrollbar"}); + } + } + + function removeOverlay(cm) { + var state = cm.state.matchHighlighter; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; + if (state.matchesonscroll) { + state.matchesonscroll.clear(); + state.matchesonscroll = null; + } + } + } + + function highlightMatches(cm) { + cm.operation(function() { + var state = cm.state.matchHighlighter; + removeOverlay(cm); + if (!cm.somethingSelected() && state.options.showToken) { + var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken; + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; + while (start && re.test(line.charAt(start - 1))) --start; + while (end < line.length && re.test(line.charAt(end))) ++end; + if (start < end) + addOverlay(cm, line.slice(start, end), re, state.options.style); + return; + } + var from = cm.getCursor("from"), to = cm.getCursor("to"); + if (from.line != to.line) return; + if (state.options.wordsOnly && !isWord(cm, from, to)) return; + var selection = cm.getRange(from, to) + if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "") + if (selection.length >= state.options.minChars) + addOverlay(cm, selection, false, state.options.style); + }); + } + + function isWord(cm, from, to) { + var str = cm.getRange(from, to); + if (str.match(/^\w+$/) !== null) { + if (from.ch > 0) { + var pos = {line: from.line, ch: from.ch - 1}; + var chr = cm.getRange(pos, from); + if (chr.match(/\W/) === null) return false; + } + if (to.ch < cm.getLine(from.line).length) { + var pos = {line: to.line, ch: to.ch + 1}; + var chr = cm.getRange(to, pos); + if (chr.match(/\W/) === null) return false; + } + return true; + } else return false; + } + + function boundariesAround(stream, re) { + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); + } + + function makeOverlay(query, hasBoundary, style) { + return {token: function(stream) { + if (stream.match(query) && + (!hasBoundary || boundariesAround(stream, hasBoundary))) + return style; + stream.next(); + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); + }}; + } +}); diff --git a/lib/redactor/codemirror/addon/search/matchesonscrollbar.css b/lib/redactor/codemirror/addon/search/matchesonscrollbar.css new file mode 100644 index 0000000..77932cc --- /dev/null +++ b/lib/redactor/codemirror/addon/search/matchesonscrollbar.css @@ -0,0 +1,8 @@ +.CodeMirror-search-match { + background: gold; + border-top: 1px solid orange; + border-bottom: 1px solid orange; + -moz-box-sizing: border-box; + box-sizing: border-box; + opacity: .5; +} diff --git a/lib/redactor/codemirror/addon/search/matchesonscrollbar.js b/lib/redactor/codemirror/addon/search/matchesonscrollbar.js new file mode 100644 index 0000000..8a4a827 --- /dev/null +++ b/lib/redactor/codemirror/addon/search/matchesonscrollbar.js @@ -0,0 +1,97 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { + if (typeof options == "string") options = {className: options}; + if (!options) options = {}; + return new SearchAnnotation(this, query, caseFold, options); + }); + + function SearchAnnotation(cm, query, caseFold, options) { + this.cm = cm; + this.options = options; + var annotateOptions = {listenForChanges: false}; + for (var prop in options) annotateOptions[prop] = options[prop]; + if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; + this.annotation = cm.annotateScrollbar(annotateOptions); + this.query = query; + this.caseFold = caseFold; + this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; + this.matches = []; + this.update = null; + + this.findMatches(); + this.annotation.update(this.matches); + + var self = this; + cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); }); + } + + var MAX_MATCHES = 1000; + + SearchAnnotation.prototype.findMatches = function() { + if (!this.gap) return; + for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + if (match.from.line >= this.gap.to) break; + if (match.to.line >= this.gap.from) this.matches.splice(i--, 1); + } + var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), {caseFold: this.caseFold, multiline: this.options.multiline}); + var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES; + while (cursor.findNext()) { + var match = {from: cursor.from(), to: cursor.to()}; + if (match.from.line >= this.gap.to) break; + this.matches.splice(i++, 0, match); + if (this.matches.length > maxMatches) break; + } + this.gap = null; + }; + + function offsetLine(line, changeStart, sizeChange) { + if (line <= changeStart) return line; + return Math.max(changeStart, line + sizeChange); + } + + SearchAnnotation.prototype.onChange = function(change) { + var startLine = change.from.line; + var endLine = CodeMirror.changeEnd(change).line; + var sizeChange = endLine - change.to.line; + if (this.gap) { + this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line); + this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line); + } else { + this.gap = {from: change.from.line, to: endLine + 1}; + } + + if (sizeChange) for (var i = 0; i < this.matches.length; i++) { + var match = this.matches[i]; + var newFrom = offsetLine(match.from.line, startLine, sizeChange); + if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch); + var newTo = offsetLine(match.to.line, startLine, sizeChange); + if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch); + } + clearTimeout(this.update); + var self = this; + this.update = setTimeout(function() { self.updateAfterChange(); }, 250); + }; + + SearchAnnotation.prototype.updateAfterChange = function() { + this.findMatches(); + this.annotation.update(this.matches); + }; + + SearchAnnotation.prototype.clear = function() { + this.cm.off("change", this.changeHandler); + this.annotation.clear(); + }; +}); diff --git a/lib/redactor/codemirror/addon/search/search.js b/lib/redactor/codemirror/addon/search/search.js new file mode 100644 index 0000000..cecdd52 --- /dev/null +++ b/lib/redactor/codemirror/addon/search/search.js @@ -0,0 +1,260 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Define search commands. Depends on dialog.js or another +// implementation of the openDialog method. + +// Replace works a little oddly -- it will do the replace on the next +// Ctrl-G (or whatever is bound to findNext) press. You prevent a +// replace by making sure the match is no longer selected when hitting +// Ctrl-G. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function searchOverlay(query, caseInsensitive) { + if (typeof query == "string") + query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); + else if (!query.global) + query = new RegExp(query.source, query.ignoreCase ? "gi" : "g"); + + return {token: function(stream) { + query.lastIndex = stream.pos; + var match = query.exec(stream.string); + if (match && match.index == stream.pos) { + stream.pos += match[0].length || 1; + return "searching"; + } else if (match) { + stream.pos = match.index; + } else { + stream.skipToEnd(); + } + }}; + } + + function SearchState() { + this.posFrom = this.posTo = this.lastQuery = this.query = null; + this.overlay = null; + } + + function getSearchState(cm) { + return cm.state.search || (cm.state.search = new SearchState()); + } + + function queryCaseInsensitive(query) { + return typeof query == "string" && query == query.toLowerCase(); + } + + function getSearchCursor(cm, query, pos) { + // Heuristic: if the query string is all lowercase, do a case insensitive search. + return cm.getSearchCursor(query, pos, {caseFold: queryCaseInsensitive(query), multiline: true}); + } + + function persistentDialog(cm, text, deflt, onEnter, onKeyDown) { + cm.openDialog(text, onEnter, { + value: deflt, + selectValueOnOpen: true, + closeOnEnter: false, + onClose: function() { clearSearch(cm); }, + onKeyDown: onKeyDown + }); + } + + function dialog(cm, text, shortText, deflt, f) { + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + else f(prompt(shortText, deflt)); + } + + function confirmDialog(cm, text, shortText, fs) { + if (cm.openConfirm) cm.openConfirm(text, fs); + else if (confirm(shortText)) fs[0](); + } + + function parseString(string) { + return string.replace(/\\([nrt\\])/g, function(match, ch) { + if (ch == "n") return "\n" + if (ch == "r") return "\r" + if (ch == "t") return "\t" + if (ch == "\\") return "\\" + return match + }) + } + + function parseQuery(query) { + var isRE = query.match(/^\/(.*)\/([a-z]*)$/); + if (isRE) { + try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } + catch(e) {} // Not a regular expression after all, do a string search + } else { + query = parseString(query) + } + if (typeof query == "string" ? query == "" : query.test("")) + query = /x^/; + return query; + } + + function startSearch(cm, state, query) { + state.queryText = query; + state.query = parseQuery(query); + cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query)); + state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query)); + cm.addOverlay(state.overlay); + if (cm.showMatchesOnScrollbar) { + if (state.annotate) { state.annotate.clear(); state.annotate = null; } + state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query)); + } + } + + function doSearch(cm, rev, persistent, immediate) { + var state = getSearchState(cm); + if (state.query) return findNext(cm, rev); + var q = cm.getSelection() || state.lastQuery; + if (q instanceof RegExp && q.source == "x^") q = null + if (persistent && cm.openDialog) { + var hiding = null + var searchNext = function(query, event) { + CodeMirror.e_stop(event); + if (!query) return; + if (query != state.queryText) { + startSearch(cm, state, query); + state.posFrom = state.posTo = cm.getCursor(); + } + if (hiding) hiding.style.opacity = 1 + findNext(cm, event.shiftKey, function(_, to) { + var dialog + if (to.line < 3 && document.querySelector && + (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && + dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) + (hiding = dialog).style.opacity = .4 + }) + }; + persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) { + var keyName = CodeMirror.keyName(event) + var extra = cm.getOption('extraKeys'), cmd = (extra && extra[keyName]) || CodeMirror.keyMap[cm.getOption("keyMap")][keyName] + if (cmd == "findNext" || cmd == "findPrev" || + cmd == "findPersistentNext" || cmd == "findPersistentPrev") { + CodeMirror.e_stop(event); + startSearch(cm, getSearchState(cm), query); + cm.execCommand(cmd); + } else if (cmd == "find" || cmd == "findPersistent") { + CodeMirror.e_stop(event); + searchNext(query, event); + } + }); + if (immediate && q) { + startSearch(cm, state, q); + findNext(cm, rev); + } + } else { + dialog(cm, getQueryDialog(cm), "Search for:", q, function(query) { + if (query && !state.query) cm.operation(function() { + startSearch(cm, state, query); + state.posFrom = state.posTo = cm.getCursor(); + findNext(cm, rev); + }); + }); + } + } + + function findNext(cm, rev, callback) {cm.operation(function() { + var state = getSearchState(cm); + var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); + if (!cursor.find(rev)) { + cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); + if (!cursor.find(rev)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); + state.posFrom = cursor.from(); state.posTo = cursor.to(); + if (callback) callback(cursor.from(), cursor.to()) + });} + + function clearSearch(cm) {cm.operation(function() { + var state = getSearchState(cm); + state.lastQuery = state.query; + if (!state.query) return; + state.query = state.queryText = null; + cm.removeOverlay(state.overlay); + if (state.annotate) { state.annotate.clear(); state.annotate = null; } + });} + + + function getQueryDialog(cm) { + return '' + cm.phrase("Search:") + ' ' + cm.phrase("(Use /re/ syntax for regexp search)") + ''; + } + function getReplaceQueryDialog(cm) { + return ' ' + cm.phrase("(Use /re/ syntax for regexp search)") + ''; + } + function getReplacementQueryDialog(cm) { + return '' + cm.phrase("With:") + ' '; + } + function getDoReplaceConfirm(cm) { + return '' + cm.phrase("Replace?") + ' '; + } + + function replaceAll(cm, query, text) { + cm.operation(function() { + for (var cursor = getSearchCursor(cm, query); cursor.findNext();) { + if (typeof query != "string") { + var match = cm.getRange(cursor.from(), cursor.to()).match(query); + cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + } else cursor.replace(text); + } + }); + } + + function replace(cm, all) { + if (cm.getOption("readOnly")) return; + var query = cm.getSelection() || getSearchState(cm).lastQuery; + var dialogText = '' + (all ? cm.phrase("Replace all:") : cm.phrase("Replace:")) + ''; + dialog(cm, dialogText + getReplaceQueryDialog(cm), dialogText, query, function(query) { + if (!query) return; + query = parseQuery(query); + dialog(cm, getReplacementQueryDialog(cm), cm.phrase("Replace with:"), "", function(text) { + text = parseString(text) + if (all) { + replaceAll(cm, query, text) + } else { + clearSearch(cm); + var cursor = getSearchCursor(cm, query, cm.getCursor("from")); + var advance = function() { + var start = cursor.from(), match; + if (!(match = cursor.findNext())) { + cursor = getSearchCursor(cm, query); + if (!(match = cursor.findNext()) || + (start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return; + } + cm.setSelection(cursor.from(), cursor.to()); + cm.scrollIntoView({from: cursor.from(), to: cursor.to()}); + confirmDialog(cm, getDoReplaceConfirm(cm), cm.phrase("Replace?"), + [function() {doReplace(match);}, advance, + function() {replaceAll(cm, query, text)}]); + }; + var doReplace = function(match) { + cursor.replace(typeof query == "string" ? text : + text.replace(/\$(\d)/g, function(_, i) {return match[i];})); + advance(); + }; + advance(); + } + }); + }); + } + + CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);}; + CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);}; + CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);}; + CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);}; + CodeMirror.commands.findNext = doSearch; + CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);}; + CodeMirror.commands.clearSearch = clearSearch; + CodeMirror.commands.replace = replace; + CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);}; +}); diff --git a/lib/redactor/codemirror/addon/search/searchcursor.js b/lib/redactor/codemirror/addon/search/searchcursor.js new file mode 100644 index 0000000..816bf77 --- /dev/null +++ b/lib/redactor/codemirror/addon/search/searchcursor.js @@ -0,0 +1,296 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")) + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + "use strict" + var Pos = CodeMirror.Pos + + function regexpFlags(regexp) { + var flags = regexp.flags + return flags != null ? flags : (regexp.ignoreCase ? "i" : "") + + (regexp.global ? "g" : "") + + (regexp.multiline ? "m" : "") + } + + function ensureFlags(regexp, flags) { + var current = regexpFlags(regexp), target = current + for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1) + target += flags.charAt(i) + return current == target ? regexp : new RegExp(regexp.source, target) + } + + function maybeMultiline(regexp) { + return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source) + } + + function searchRegexpForward(doc, regexp, start) { + regexp = ensureFlags(regexp, "g") + for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { + regexp.lastIndex = ch + var string = doc.getLine(line), match = regexp.exec(string) + if (match) + return {from: Pos(line, match.index), + to: Pos(line, match.index + match[0].length), + match: match} + } + } + + function searchRegexpForwardMultiline(doc, regexp, start) { + if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) + + regexp = ensureFlags(regexp, "gm") + var string, chunk = 1 + for (var line = start.line, last = doc.lastLine(); line <= last;) { + // This grows the search buffer in exponentially-sized chunks + // between matches, so that nearby matches are fast and don't + // require concatenating the whole document (in case we're + // searching for something that has tons of matches), but at the + // same time, the amount of retries is limited. + for (var i = 0; i < chunk; i++) { + if (line > last) break + var curLine = doc.getLine(line++) + string = string == null ? curLine : string + "\n" + curLine + } + chunk = chunk * 2 + regexp.lastIndex = start.ch + var match = regexp.exec(string) + if (match) { + var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") + var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length + return {from: Pos(startLine, startCh), + to: Pos(startLine + inside.length - 1, + inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), + match: match} + } + } + } + + function lastMatchIn(string, regexp, endMargin) { + var match, from = 0 + while (from <= string.length) { + regexp.lastIndex = from + var newMatch = regexp.exec(string) + if (!newMatch) break + var end = newMatch.index + newMatch[0].length + if (end > string.length - endMargin) break + if (!match || end > match.index + match[0].length) + match = newMatch + from = newMatch.index + 1 + } + return match + } + + function searchRegexpBackward(doc, regexp, start) { + regexp = ensureFlags(regexp, "g") + for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { + var string = doc.getLine(line) + var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch) + if (match) + return {from: Pos(line, match.index), + to: Pos(line, match.index + match[0].length), + match: match} + } + } + + function searchRegexpBackwardMultiline(doc, regexp, start) { + if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start) + regexp = ensureFlags(regexp, "gm") + var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch + for (var line = start.line, first = doc.firstLine(); line >= first;) { + for (var i = 0; i < chunkSize && line >= first; i++) { + var curLine = doc.getLine(line--) + string = string == null ? curLine : curLine + "\n" + string + } + chunkSize *= 2 + + var match = lastMatchIn(string, regexp, endMargin) + if (match) { + var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") + var startLine = line + before.length, startCh = before[before.length - 1].length + return {from: Pos(startLine, startCh), + to: Pos(startLine + inside.length - 1, + inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), + match: match} + } + } + } + + var doFold, noFold + if (String.prototype.normalize) { + doFold = function(str) { return str.normalize("NFD").toLowerCase() } + noFold = function(str) { return str.normalize("NFD") } + } else { + doFold = function(str) { return str.toLowerCase() } + noFold = function(str) { return str } + } + + // Maps a position in a case-folded line back to a position in the original line + // (compensating for codepoints increasing in number during folding) + function adjustPos(orig, folded, pos, foldFunc) { + if (orig.length == folded.length) return pos + for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) { + if (min == max) return min + var mid = (min + max) >> 1 + var len = foldFunc(orig.slice(0, mid)).length + if (len == pos) return mid + else if (len > pos) max = mid + else min = mid + 1 + } + } + + function searchStringForward(doc, query, start, caseFold) { + // Empty string would match anything and never progress, so we + // define it to match nothing instead. + if (!query.length) return null + var fold = caseFold ? doFold : noFold + var lines = fold(query).split(/\r|\n\r?/) + + search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) { + var orig = doc.getLine(line).slice(ch), string = fold(orig) + if (lines.length == 1) { + var found = string.indexOf(lines[0]) + if (found == -1) continue search + var start = adjustPos(orig, string, found, fold) + ch + return {from: Pos(line, adjustPos(orig, string, found, fold) + ch), + to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)} + } else { + var cutFrom = string.length - lines[0].length + if (string.slice(cutFrom) != lines[0]) continue search + for (var i = 1; i < lines.length - 1; i++) + if (fold(doc.getLine(line + i)) != lines[i]) continue search + var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1] + if (endString.slice(0, lastLine.length) != lastLine) continue search + return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch), + to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))} + } + } + } + + function searchStringBackward(doc, query, start, caseFold) { + if (!query.length) return null + var fold = caseFold ? doFold : noFold + var lines = fold(query).split(/\r|\n\r?/) + + search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) { + var orig = doc.getLine(line) + if (ch > -1) orig = orig.slice(0, ch) + var string = fold(orig) + if (lines.length == 1) { + var found = string.lastIndexOf(lines[0]) + if (found == -1) continue search + return {from: Pos(line, adjustPos(orig, string, found, fold)), + to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))} + } else { + var lastLine = lines[lines.length - 1] + if (string.slice(0, lastLine.length) != lastLine) continue search + for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++) + if (fold(doc.getLine(start + i)) != lines[i]) continue search + var top = doc.getLine(line + 1 - lines.length), topString = fold(top) + if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search + return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)), + to: Pos(line, adjustPos(orig, string, lastLine.length, fold))} + } + } + } + + function SearchCursor(doc, query, pos, options) { + this.atOccurrence = false + this.doc = doc + pos = pos ? doc.clipPos(pos) : Pos(0, 0) + this.pos = {from: pos, to: pos} + + var caseFold + if (typeof options == "object") { + caseFold = options.caseFold + } else { // Backwards compat for when caseFold was the 4th argument + caseFold = options + options = null + } + + if (typeof query == "string") { + if (caseFold == null) caseFold = false + this.matches = function(reverse, pos) { + return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) + } + } else { + query = ensureFlags(query, "gm") + if (!options || options.multiline !== false) + this.matches = function(reverse, pos) { + return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) + } + else + this.matches = function(reverse, pos) { + return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos) + } + } + } + + SearchCursor.prototype = { + findNext: function() {return this.find(false)}, + findPrevious: function() {return this.find(true)}, + + find: function(reverse) { + var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) + + // Implements weird auto-growing behavior on null-matches for + // backwards-compatiblity with the vim code (unfortunately) + while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { + if (reverse) { + if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) + else if (result.from.line == this.doc.firstLine()) result = null + else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1))) + } else { + if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1) + else if (result.to.line == this.doc.lastLine()) result = null + else result = this.matches(reverse, Pos(result.to.line + 1, 0)) + } + } + + if (result) { + this.pos = result + this.atOccurrence = true + return this.pos.match || true + } else { + var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0) + this.pos = {from: end, to: end} + return this.atOccurrence = false + } + }, + + from: function() {if (this.atOccurrence) return this.pos.from}, + to: function() {if (this.atOccurrence) return this.pos.to}, + + replace: function(newText, origin) { + if (!this.atOccurrence) return + var lines = CodeMirror.splitLines(newText) + this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin) + this.pos.to = Pos(this.pos.from.line + lines.length - 1, + lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)) + } + } + + CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this.doc, query, pos, caseFold) + }) + CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this, query, pos, caseFold) + }) + + CodeMirror.defineExtension("selectMatches", function(query, caseFold) { + var ranges = [] + var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold) + while (cur.findNext()) { + if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break + ranges.push({anchor: cur.from(), head: cur.to()}) + } + if (ranges.length) + this.setSelections(ranges, 0) + }) +}); diff --git a/lib/redactor/codemirror/addon/selection/active-line.js b/lib/redactor/codemirror/addon/selection/active-line.js new file mode 100644 index 0000000..c7b14ce --- /dev/null +++ b/lib/redactor/codemirror/addon/selection/active-line.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + var WRAP_CLASS = "CodeMirror-activeline"; + var BACK_CLASS = "CodeMirror-activeline-background"; + var GUTT_CLASS = "CodeMirror-activeline-gutter"; + + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { + var prev = old == CodeMirror.Init ? false : old; + if (val == prev) return + if (prev) { + cm.off("beforeSelectionChange", selectionChange); + clearActiveLines(cm); + delete cm.state.activeLines; + } + if (val) { + cm.state.activeLines = []; + updateActiveLines(cm, cm.listSelections()); + cm.on("beforeSelectionChange", selectionChange); + } + }); + + function clearActiveLines(cm) { + for (var i = 0; i < cm.state.activeLines.length; i++) { + cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS); + cm.removeLineClass(cm.state.activeLines[i], "gutter", GUTT_CLASS); + } + } + + function sameArray(a, b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) + if (a[i] != b[i]) return false; + return true; + } + + function updateActiveLines(cm, ranges) { + var active = []; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + var option = cm.getOption("styleActiveLine"); + if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) + continue + var line = cm.getLineHandleVisualStart(range.head.line); + if (active[active.length - 1] != line) active.push(line); + } + if (sameArray(cm.state.activeLines, active)) return; + cm.operation(function() { + clearActiveLines(cm); + for (var i = 0; i < active.length; i++) { + cm.addLineClass(active[i], "wrap", WRAP_CLASS); + cm.addLineClass(active[i], "background", BACK_CLASS); + cm.addLineClass(active[i], "gutter", GUTT_CLASS); + } + cm.state.activeLines = active; + }); + } + + function selectionChange(cm, sel) { + updateActiveLines(cm, sel.ranges); + } +}); diff --git a/lib/redactor/codemirror/addon/selection/mark-selection.js b/lib/redactor/codemirror/addon/selection/mark-selection.js new file mode 100644 index 0000000..adfaa62 --- /dev/null +++ b/lib/redactor/codemirror/addon/selection/mark-selection.js @@ -0,0 +1,119 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Because sometimes you need to mark the selected *text*. +// +// Adds an option 'styleSelectedText' which, when enabled, gives +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); + } else if (!val && prev) { + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; + } + }); + + function onCursorActivity(cm) { + if (cm.state.markedSelection) + cm.operation(function() { update(cm); }); + } + + function onChange(cm) { + if (cm.state.markedSelection && cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + var cmp = CodeMirror.cmpPos; + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; + } + } + + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; + } + + function reset(cm) { + clear(cm); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) + coverRange(cm, ranges[i].from(), ranges[i].to()); + } + + function update(cm) { + if (!cm.somethingSelected()) return clear(cm); + if (cm.listSelections().length > 1) return reset(cm); + + var from = cm.getCursor("start"), to = cm.getCursor("end"); + + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); + + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); + } else { + coverRange(cm, from, coverStart.from, 0); + } + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); + } else { + coverRange(cm, coverEnd.to, to); + } + } + } +}); diff --git a/lib/redactor/codemirror/addon/selection/selection-pointer.js b/lib/redactor/codemirror/addon/selection/selection-pointer.js new file mode 100644 index 0000000..f0bd61a --- /dev/null +++ b/lib/redactor/codemirror/addon/selection/selection-pointer.js @@ -0,0 +1,98 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineOption("selectionPointer", false, function(cm, val) { + var data = cm.state.selectionPointer; + if (data) { + CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.off(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.off(window, "scroll", data.windowScroll); + cm.off("cursorActivity", reset); + cm.off("scroll", reset); + cm.state.selectionPointer = null; + cm.display.lineDiv.style.cursor = ""; + } + if (val) { + data = cm.state.selectionPointer = { + value: typeof val == "string" ? val : "default", + mousemove: function(event) { mousemove(cm, event); }, + mouseout: function(event) { mouseout(cm, event); }, + windowScroll: function() { reset(cm); }, + rects: null, + mouseX: null, mouseY: null, + willUpdate: false + }; + CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove); + CodeMirror.on(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.on(window, "scroll", data.windowScroll); + cm.on("cursorActivity", reset); + cm.on("scroll", reset); + } + }); + + function mousemove(cm, event) { + var data = cm.state.selectionPointer; + if (event.buttons == null ? event.which : event.buttons) { + data.mouseX = data.mouseY = null; + } else { + data.mouseX = event.clientX; + data.mouseY = event.clientY; + } + scheduleUpdate(cm); + } + + function mouseout(cm, event) { + if (!cm.getWrapperElement().contains(event.relatedTarget)) { + var data = cm.state.selectionPointer; + data.mouseX = data.mouseY = null; + scheduleUpdate(cm); + } + } + + function reset(cm) { + cm.state.selectionPointer.rects = null; + scheduleUpdate(cm); + } + + function scheduleUpdate(cm) { + if (!cm.state.selectionPointer.willUpdate) { + cm.state.selectionPointer.willUpdate = true; + setTimeout(function() { + update(cm); + cm.state.selectionPointer.willUpdate = false; + }, 50); + } + } + + function update(cm) { + var data = cm.state.selectionPointer; + if (!data) return; + if (data.rects == null && data.mouseX != null) { + data.rects = []; + if (cm.somethingSelected()) { + for (var sel = cm.display.selectionDiv.firstChild; sel; sel = sel.nextSibling) + data.rects.push(sel.getBoundingClientRect()); + } + } + var inside = false; + if (data.mouseX != null) for (var i = 0; i < data.rects.length; i++) { + var rect = data.rects[i]; + if (rect.left <= data.mouseX && rect.right >= data.mouseX && + rect.top <= data.mouseY && rect.bottom >= data.mouseY) + inside = true; + } + var cursor = inside ? data.value : ""; + if (cm.display.lineDiv.style.cursor != cursor) + cm.display.lineDiv.style.cursor = cursor; + } +}); diff --git a/lib/redactor/codemirror/addon/tern/tern.css b/lib/redactor/codemirror/addon/tern/tern.css new file mode 100644 index 0000000..c4b8a2f --- /dev/null +++ b/lib/redactor/codemirror/addon/tern/tern.css @@ -0,0 +1,87 @@ +.CodeMirror-Tern-completion { + padding-left: 22px; + position: relative; + line-height: 1.5; +} +.CodeMirror-Tern-completion:before { + position: absolute; + left: 2px; + bottom: 2px; + border-radius: 50%; + font-size: 12px; + font-weight: bold; + height: 15px; + width: 15px; + line-height: 16px; + text-align: center; + color: white; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.CodeMirror-Tern-completion-unknown:before { + content: "?"; + background: #4bb; +} +.CodeMirror-Tern-completion-object:before { + content: "O"; + background: #77c; +} +.CodeMirror-Tern-completion-fn:before { + content: "F"; + background: #7c7; +} +.CodeMirror-Tern-completion-array:before { + content: "A"; + background: #c66; +} +.CodeMirror-Tern-completion-number:before { + content: "1"; + background: #999; +} +.CodeMirror-Tern-completion-string:before { + content: "S"; + background: #999; +} +.CodeMirror-Tern-completion-bool:before { + content: "B"; + background: #999; +} + +.CodeMirror-Tern-completion-guess { + color: #999; +} + +.CodeMirror-Tern-tooltip { + border: 1px solid silver; + border-radius: 3px; + color: #444; + padding: 2px 5px; + font-size: 90%; + font-family: monospace; + background-color: white; + white-space: pre-wrap; + + max-width: 40em; + position: absolute; + z-index: 10; + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + + transition: opacity 1s; + -moz-transition: opacity 1s; + -webkit-transition: opacity 1s; + -o-transition: opacity 1s; + -ms-transition: opacity 1s; +} + +.CodeMirror-Tern-hint-doc { + max-width: 25em; + margin-top: -3px; +} + +.CodeMirror-Tern-fname { color: black; } +.CodeMirror-Tern-farg { color: #70a; } +.CodeMirror-Tern-farg-current { text-decoration: underline; } +.CodeMirror-Tern-type { color: #07c; } +.CodeMirror-Tern-fhint-guess { opacity: .7; } diff --git a/lib/redactor/codemirror/addon/tern/tern.js b/lib/redactor/codemirror/addon/tern/tern.js new file mode 100644 index 0000000..253309d --- /dev/null +++ b/lib/redactor/codemirror/addon/tern/tern.js @@ -0,0 +1,718 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// Glue code between CodeMirror and Tern. +// +// Create a CodeMirror.TernServer to wrap an actual Tern server, +// register open documents (CodeMirror.Doc instances) with it, and +// call its methods to activate the assisting functions that Tern +// provides. +// +// Options supported (all optional): +// * defs: An array of JSON definition data structures. +// * plugins: An object mapping plugin names to configuration +// options. +// * getFile: A function(name, c) that can be used to access files in +// the project that haven't been loaded yet. Simply do c(null) to +// indicate that a file is not available. +// * fileFilter: A function(value, docName, doc) that will be applied +// to documents before passing them on to Tern. +// * switchToDoc: A function(name, doc) that should, when providing a +// multi-file view, switch the view or focus to the named file. +// * showError: A function(editor, message) that can be used to +// override the way errors are displayed. +// * completionTip: Customize the content in tooltips for completions. +// Is passed a single argument—the completion's data as returned by +// Tern—and may return a string, DOM node, or null to indicate that +// no tip should be shown. By default the docstring is shown. +// * typeTip: Like completionTip, but for the tooltips shown for type +// queries. +// * responseFilter: A function(doc, query, request, error, data) that +// will be applied to the Tern responses before treating them +// +// +// It is possible to run the Tern server in a web worker by specifying +// these additional options: +// * useWorker: Set to true to enable web worker mode. You'll probably +// want to feature detect the actual value you use here, for example +// !!window.Worker. +// * workerScript: The main script of the worker. Point this to +// wherever you are hosting worker.js from this directory. +// * workerDeps: An array of paths pointing (relative to workerScript) +// to the Acorn and Tern libraries and any Tern plugins you want to +// load. Or, if you minified those into a single script and included +// them in the workerScript, simply leave this undefined. + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + // declare global: tern + + CodeMirror.TernServer = function(options) { + var self = this; + this.options = options || {}; + var plugins = this.options.plugins || (this.options.plugins = {}); + if (!plugins.doc_comment) plugins.doc_comment = true; + this.docs = Object.create(null); + if (this.options.useWorker) { + this.server = new WorkerServer(this); + } else { + this.server = new tern.Server({ + getFile: function(name, c) { return getFile(self, name, c); }, + async: true, + defs: this.options.defs || [], + plugins: plugins + }); + } + this.trackChange = function(doc, change) { trackChange(self, doc, change); }; + + this.cachedArgHints = null; + this.activeArgHints = null; + this.jumpStack = []; + + this.getHint = function(cm, c) { return hint(self, cm, c); }; + this.getHint.async = true; + }; + + CodeMirror.TernServer.prototype = { + addDoc: function(name, doc) { + var data = {doc: doc, name: name, changed: null}; + this.server.addFile(name, docValue(this, data)); + CodeMirror.on(doc, "change", this.trackChange); + return this.docs[name] = data; + }, + + delDoc: function(id) { + var found = resolveDoc(this, id); + if (!found) return; + CodeMirror.off(found.doc, "change", this.trackChange); + delete this.docs[found.name]; + this.server.delFile(found.name); + }, + + hideDoc: function(id) { + closeArgHints(this); + var found = resolveDoc(this, id); + if (found && found.changed) sendDoc(this, found); + }, + + complete: function(cm) { + cm.showHint({hint: this.getHint}); + }, + + showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); }, + + showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); }, + + updateArgHints: function(cm) { updateArgHints(this, cm); }, + + jumpToDef: function(cm) { jumpToDef(this, cm); }, + + jumpBack: function(cm) { jumpBack(this, cm); }, + + rename: function(cm) { rename(this, cm); }, + + selectName: function(cm) { selectName(this, cm); }, + + request: function (cm, query, c, pos) { + var self = this; + var doc = findDoc(this, cm.getDoc()); + var request = buildRequest(this, doc, query, pos); + var extraOptions = request.query && this.options.queryOptions && this.options.queryOptions[request.query.type] + if (extraOptions) for (var prop in extraOptions) request.query[prop] = extraOptions[prop]; + + this.server.request(request, function (error, data) { + if (!error && self.options.responseFilter) + data = self.options.responseFilter(doc, query, request, error, data); + c(error, data); + }); + }, + + destroy: function () { + closeArgHints(this) + if (this.worker) { + this.worker.terminate(); + this.worker = null; + } + } + }; + + var Pos = CodeMirror.Pos; + var cls = "CodeMirror-Tern-"; + var bigDoc = 250; + + function getFile(ts, name, c) { + var buf = ts.docs[name]; + if (buf) + c(docValue(ts, buf)); + else if (ts.options.getFile) + ts.options.getFile(name, c); + else + c(null); + } + + function findDoc(ts, doc, name) { + for (var n in ts.docs) { + var cur = ts.docs[n]; + if (cur.doc == doc) return cur; + } + if (!name) for (var i = 0;; ++i) { + n = "[doc" + (i || "") + "]"; + if (!ts.docs[n]) { name = n; break; } + } + return ts.addDoc(name, doc); + } + + function resolveDoc(ts, id) { + if (typeof id == "string") return ts.docs[id]; + if (id instanceof CodeMirror) id = id.getDoc(); + if (id instanceof CodeMirror.Doc) return findDoc(ts, id); + } + + function trackChange(ts, doc, change) { + var data = findDoc(ts, doc); + + var argHints = ts.cachedArgHints; + if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0) + ts.cachedArgHints = null; + + var changed = data.changed; + if (changed == null) + data.changed = changed = {from: change.from.line, to: change.from.line}; + var end = change.from.line + (change.text.length - 1); + if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end); + if (end >= changed.to) changed.to = end + 1; + if (changed.from > change.from.line) changed.from = change.from.line; + + if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() { + if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data); + }, 200); + } + + function sendDoc(ts, doc) { + ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) { + if (error) window.console.error(error); + else doc.changed = null; + }); + } + + // Completion + + function hint(ts, cm, c) { + ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) { + if (error) return showError(ts, cm, error); + var completions = [], after = ""; + var from = data.start, to = data.end; + if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" && + cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]") + after = "\"]"; + + for (var i = 0; i < data.completions.length; ++i) { + var completion = data.completions[i], className = typeToIcon(completion.type); + if (data.guess) className += " " + cls + "guess"; + completions.push({text: completion.name + after, + displayText: completion.displayName || completion.name, + className: className, + data: completion}); + } + + var obj = {from: from, to: to, list: completions}; + var tooltip = null; + CodeMirror.on(obj, "close", function() { remove(tooltip); }); + CodeMirror.on(obj, "update", function() { remove(tooltip); }); + CodeMirror.on(obj, "select", function(cur, node) { + remove(tooltip); + var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; + if (content) { + tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, + node.getBoundingClientRect().top + window.pageYOffset, content); + tooltip.className += " " + cls + "hint-doc"; + } + }); + c(obj); + }); + } + + function typeToIcon(type) { + var suffix; + if (type == "?") suffix = "unknown"; + else if (type == "number" || type == "string" || type == "bool") suffix = type; + else if (/^fn\(/.test(type)) suffix = "fn"; + else if (/^\[/.test(type)) suffix = "array"; + else suffix = "object"; + return cls + "completion " + cls + "completion-" + suffix; + } + + // Type queries + + function showContextInfo(ts, cm, pos, queryName, c) { + ts.request(cm, queryName, function(error, data) { + if (error) return showError(ts, cm, error); + if (ts.options.typeTip) { + var tip = ts.options.typeTip(data); + } else { + var tip = elt("span", null, elt("strong", null, data.type || "not found")); + if (data.doc) + tip.appendChild(document.createTextNode(" — " + data.doc)); + if (data.url) { + tip.appendChild(document.createTextNode(" ")); + var child = tip.appendChild(elt("a", null, "[docs]")); + child.href = data.url; + child.target = "_blank"; + } + } + tempTooltip(cm, tip, ts); + if (c) c(); + }, pos); + } + + // Maintaining argument hints + + function updateArgHints(ts, cm) { + closeArgHints(ts); + + if (cm.somethingSelected()) return; + var state = cm.getTokenAt(cm.getCursor()).state; + var inner = CodeMirror.innerMode(cm.getMode(), state); + if (inner.mode.name != "javascript") return; + var lex = inner.state.lexical; + if (lex.info != "call") return; + + var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize"); + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { + var str = cm.getLine(line), extra = 0; + for (var pos = 0;;) { + var tab = str.indexOf("\t", pos); + if (tab == -1) break; + extra += tabSize - (tab + extra) % tabSize - 1; + pos = tab + 1; + } + ch = lex.column - extra; + if (str.charAt(ch) == "(") {found = true; break;} + } + if (!found) return; + + var start = Pos(line, ch); + var cache = ts.cachedArgHints; + if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) + return showArgHints(ts, cm, argPos); + + ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { + if (error || !data.type || !(/^fn\(/).test(data.type)) return; + ts.cachedArgHints = { + start: start, + type: parseFnType(data.type), + name: data.exprName || data.name || "fn", + guess: data.guess, + doc: cm.getDoc() + }; + showArgHints(ts, cm, argPos); + }); + } + + function showArgHints(ts, cm, pos) { + closeArgHints(ts); + + var cache = ts.cachedArgHints, tp = cache.type; + var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, + elt("span", cls + "fname", cache.name), "("); + for (var i = 0; i < tp.args.length; ++i) { + if (i) tip.appendChild(document.createTextNode(", ")); + var arg = tp.args[i]; + tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?")); + if (arg.type != "?") { + tip.appendChild(document.createTextNode(":\u00a0")); + tip.appendChild(elt("span", cls + "type", arg.type)); + } + } + tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")")); + if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype)); + var place = cm.cursorCoords(null, "page"); + var tooltip = ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip) + setTimeout(function() { + tooltip.clear = onEditorActivity(cm, function() { + if (ts.activeArgHints == tooltip) closeArgHints(ts) }) + }, 20) + } + + function parseFnType(text) { + var args = [], pos = 3; + + function skipMatching(upto) { + var depth = 0, start = pos; + for (;;) { + var next = text.charAt(pos); + if (upto.test(next) && !depth) return text.slice(start, pos); + if (/[{\[\(]/.test(next)) ++depth; + else if (/[}\]\)]/.test(next)) --depth; + ++pos; + } + } + + // Parse arguments + if (text.charAt(pos) != ")") for (;;) { + var name = text.slice(pos).match(/^([^, \(\[\{]+): /); + if (name) { + pos += name[0].length; + name = name[1]; + } + args.push({name: name, type: skipMatching(/[\),]/)}); + if (text.charAt(pos) == ")") break; + pos += 2; + } + + var rettype = text.slice(pos).match(/^\) -> (.*)$/); + + return {args: args, rettype: rettype && rettype[1]}; + } + + // Moving to the definition of something + + function jumpToDef(ts, cm) { + function inner(varName) { + var req = {type: "definition", variable: varName || null}; + var doc = findDoc(ts, cm.getDoc()); + ts.server.request(buildRequest(ts, doc, req), function(error, data) { + if (error) return showError(ts, cm, error); + if (!data.file && data.url) { window.open(data.url); return; } + + if (data.file) { + var localDoc = ts.docs[data.file], found; + if (localDoc && (found = findContext(localDoc.doc, data))) { + ts.jumpStack.push({file: doc.name, + start: cm.getCursor("from"), + end: cm.getCursor("to")}); + moveTo(ts, doc, localDoc, found.start, found.end); + return; + } + } + showError(ts, cm, "Could not find a definition."); + }); + } + + if (!atInterestingExpression(cm)) + dialog(cm, "Jump to variable", function(name) { if (name) inner(name); }); + else + inner(); + } + + function jumpBack(ts, cm) { + var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file]; + if (!doc) return; + moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end); + } + + function moveTo(ts, curDoc, doc, start, end) { + doc.doc.setSelection(start, end); + if (curDoc != doc && ts.options.switchToDoc) { + closeArgHints(ts); + ts.options.switchToDoc(doc.name, doc.doc); + } + } + + // The {line,ch} representation of positions makes this rather awkward. + function findContext(doc, data) { + var before = data.context.slice(0, data.contextOffset).split("\n"); + var startLine = data.start.line - (before.length - 1); + var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length); + + var text = doc.getLine(startLine).slice(start.ch); + for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur) + text += "\n" + doc.getLine(cur); + if (text.slice(0, data.context.length) == data.context) return data; + + var cursor = doc.getSearchCursor(data.context, 0, false); + var nearest, nearestDist = Infinity; + while (cursor.findNext()) { + var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000; + if (!dist) dist = Math.abs(from.ch - start.ch); + if (dist < nearestDist) { nearest = from; nearestDist = dist; } + } + if (!nearest) return null; + + if (before.length == 1) + nearest.ch += before[0].length; + else + nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length); + if (data.start.line == data.end.line) + var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch)); + else + var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch); + return {start: nearest, end: end}; + } + + function atInterestingExpression(cm) { + var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos); + if (tok.start < pos.ch && tok.type == "comment") return false; + return /[\w)\]]/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1)); + } + + // Variable renaming + + function rename(ts, cm) { + var token = cm.getTokenAt(cm.getCursor()); + if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); + dialog(cm, "New name for " + token.string, function(newName) { + ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { + if (error) return showError(ts, cm, error); + applyChanges(ts, data.changes); + }); + }); + } + + function selectName(ts, cm) { + var name = findDoc(ts, cm.doc).name; + ts.request(cm, {type: "refs"}, function(error, data) { + if (error) return showError(ts, cm, error); + var ranges = [], cur = 0; + var curPos = cm.getCursor(); + for (var i = 0; i < data.refs.length; i++) { + var ref = data.refs[i]; + if (ref.file == name) { + ranges.push({anchor: ref.start, head: ref.end}); + if (cmpPos(curPos, ref.start) >= 0 && cmpPos(curPos, ref.end) <= 0) + cur = ranges.length - 1; + } + } + cm.setSelections(ranges, cur); + }); + } + + var nextChangeOrig = 0; + function applyChanges(ts, changes) { + var perFile = Object.create(null); + for (var i = 0; i < changes.length; ++i) { + var ch = changes[i]; + (perFile[ch.file] || (perFile[ch.file] = [])).push(ch); + } + for (var file in perFile) { + var known = ts.docs[file], chs = perFile[file];; + if (!known) continue; + chs.sort(function(a, b) { return cmpPos(b.start, a.start); }); + var origin = "*rename" + (++nextChangeOrig); + for (var i = 0; i < chs.length; ++i) { + var ch = chs[i]; + known.doc.replaceRange(ch.text, ch.start, ch.end, origin); + } + } + } + + // Generic request-building helper + + function buildRequest(ts, doc, query, pos) { + var files = [], offsetLines = 0, allowFragments = !query.fullDocs; + if (!allowFragments) delete query.fullDocs; + if (typeof query == "string") query = {type: query}; + query.lineCharPositions = true; + if (query.end == null) { + query.end = pos || doc.doc.getCursor("end"); + if (doc.doc.somethingSelected()) + query.start = doc.doc.getCursor("start"); + } + var startPos = query.start || query.end; + + if (doc.changed) { + if (doc.doc.lineCount() > bigDoc && allowFragments !== false && + doc.changed.to - doc.changed.from < 100 && + doc.changed.from <= startPos.line && doc.changed.to > query.end.line) { + files.push(getFragmentAround(doc, startPos, query.end)); + query.file = "#0"; + var offsetLines = files[0].offsetLines; + if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch); + query.end = Pos(query.end.line - offsetLines, query.end.ch); + } else { + files.push({type: "full", + name: doc.name, + text: docValue(ts, doc)}); + query.file = doc.name; + doc.changed = null; + } + } else { + query.file = doc.name; + } + for (var name in ts.docs) { + var cur = ts.docs[name]; + if (cur.changed && cur != doc) { + files.push({type: "full", name: cur.name, text: docValue(ts, cur)}); + cur.changed = null; + } + } + + return {query: query, files: files}; + } + + function getFragmentAround(data, start, end) { + var doc = data.doc; + var minIndent = null, minLine = null, endLine, tabSize = 4; + for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) { + var line = doc.getLine(p), fn = line.search(/\bfunction\b/); + if (fn < 0) continue; + var indent = CodeMirror.countColumn(line, null, tabSize); + if (minIndent != null && minIndent <= indent) continue; + minIndent = indent; + minLine = p; + } + if (minLine == null) minLine = min; + var max = Math.min(doc.lastLine(), end.line + 20); + if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize)) + endLine = max; + else for (endLine = end.line + 1; endLine < max; ++endLine) { + var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize); + if (indent <= minIndent) break; + } + var from = Pos(minLine, 0); + + return {type: "part", + name: data.name, + offsetLines: from.line, + text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))}; + } + + // Generic utilities + + var cmpPos = CodeMirror.cmpPos; + + function elt(tagname, cls /*, ... elts*/) { + var e = document.createElement(tagname); + if (cls) e.className = cls; + for (var i = 2; i < arguments.length; ++i) { + var elt = arguments[i]; + if (typeof elt == "string") elt = document.createTextNode(elt); + e.appendChild(elt); + } + return e; + } + + function dialog(cm, text, f) { + if (cm.openDialog) + cm.openDialog(text + ": ", f); + else + f(prompt(text, "")); + } + + // Tooltips + + function tempTooltip(cm, content, ts) { + if (cm.state.ternTooltip) remove(cm.state.ternTooltip); + var where = cm.cursorCoords(); + var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content); + function maybeClear() { + old = true; + if (!mouseOnTip) clear(); + } + function clear() { + cm.state.ternTooltip = null; + if (tip.parentNode) fadeOut(tip) + clearActivity() + } + var mouseOnTip = false, old = false; + CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); + CodeMirror.on(tip, "mouseout", function(e) { + var related = e.relatedTarget || e.toElement + if (!related || !CodeMirror.contains(tip, related)) { + if (old) clear(); + else mouseOnTip = false; + } + }); + setTimeout(maybeClear, ts.options.hintDelay ? ts.options.hintDelay : 1700); + var clearActivity = onEditorActivity(cm, clear) + } + + function onEditorActivity(cm, f) { + cm.on("cursorActivity", f) + cm.on("blur", f) + cm.on("scroll", f) + cm.on("setDoc", f) + return function() { + cm.off("cursorActivity", f) + cm.off("blur", f) + cm.off("scroll", f) + cm.off("setDoc", f) + } + } + + function makeTooltip(x, y, content) { + var node = elt("div", cls + "tooltip", content); + node.style.left = x + "px"; + node.style.top = y + "px"; + document.body.appendChild(node); + return node; + } + + function remove(node) { + var p = node && node.parentNode; + if (p) p.removeChild(node); + } + + function fadeOut(tooltip) { + tooltip.style.opacity = "0"; + setTimeout(function() { remove(tooltip); }, 1100); + } + + function showError(ts, cm, msg) { + if (ts.options.showError) + ts.options.showError(cm, msg); + else + tempTooltip(cm, String(msg), ts); + } + + function closeArgHints(ts) { + if (ts.activeArgHints) { + if (ts.activeArgHints.clear) ts.activeArgHints.clear() + remove(ts.activeArgHints) + ts.activeArgHints = null + } + } + + function docValue(ts, doc) { + var val = doc.doc.getValue(); + if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc); + return val; + } + + // Worker wrapper + + function WorkerServer(ts) { + var worker = ts.worker = new Worker(ts.options.workerScript); + worker.postMessage({type: "init", + defs: ts.options.defs, + plugins: ts.options.plugins, + scripts: ts.options.workerDeps}); + var msgId = 0, pending = {}; + + function send(data, c) { + if (c) { + data.id = ++msgId; + pending[msgId] = c; + } + worker.postMessage(data); + } + worker.onmessage = function(e) { + var data = e.data; + if (data.type == "getFile") { + getFile(ts, data.name, function(err, text) { + send({type: "getFile", err: String(err), text: text, id: data.id}); + }); + } else if (data.type == "debug") { + window.console.log(data.message); + } else if (data.id && pending[data.id]) { + pending[data.id](data.err, data.body); + delete pending[data.id]; + } + }; + worker.onerror = function(e) { + for (var id in pending) pending[id](e); + pending = {}; + }; + + this.addFile = function(name, text) { send({type: "add", name: name, text: text}); }; + this.delFile = function(name) { send({type: "del", name: name}); }; + this.request = function(body, c) { send({type: "req", body: body}, c); }; + } +}); diff --git a/lib/redactor/codemirror/addon/tern/worker.js b/lib/redactor/codemirror/addon/tern/worker.js new file mode 100644 index 0000000..e134ad4 --- /dev/null +++ b/lib/redactor/codemirror/addon/tern/worker.js @@ -0,0 +1,44 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// declare global: tern, server + +var server; + +this.onmessage = function(e) { + var data = e.data; + switch (data.type) { + case "init": return startServer(data.defs, data.plugins, data.scripts); + case "add": return server.addFile(data.name, data.text); + case "del": return server.delFile(data.name); + case "req": return server.request(data.body, function(err, reqData) { + postMessage({id: data.id, body: reqData, err: err && String(err)}); + }); + case "getFile": + var c = pending[data.id]; + delete pending[data.id]; + return c(data.err, data.text); + default: throw new Error("Unknown message type: " + data.type); + } +}; + +var nextId = 0, pending = {}; +function getFile(file, c) { + postMessage({type: "getFile", name: file, id: ++nextId}); + pending[nextId] = c; +} + +function startServer(defs, plugins, scripts) { + if (scripts) importScripts.apply(null, scripts); + + server = new tern.Server({ + getFile: getFile, + async: true, + defs: defs, + plugins: plugins + }); +} + +this.console = { + log: function(v) { postMessage({type: "debug", message: v}); } +}; diff --git a/lib/redactor/codemirror/addon/wrap/hardwrap.js b/lib/redactor/codemirror/addon/wrap/hardwrap.js new file mode 100644 index 0000000..29cc15f --- /dev/null +++ b/lib/redactor/codemirror/addon/wrap/hardwrap.js @@ -0,0 +1,145 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var Pos = CodeMirror.Pos; + + function findParagraph(cm, pos, options) { + var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart"); + for (var start = pos.line, first = cm.firstLine(); start > first; --start) { + var line = cm.getLine(start); + if (startRE && startRE.test(line)) break; + if (!/\S/.test(line)) { ++start; break; } + } + var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd"); + for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) { + var line = cm.getLine(end); + if (endRE && endRE.test(line)) { ++end; break; } + if (!/\S/.test(line)) break; + } + return {from: start, to: end}; + } + + function findBreakPoint(text, column, wrapOn, killTrailingSpace) { + var at = column + while (at < text.length && text.charAt(at) == " ") at++ + for (; at > 0; --at) + if (wrapOn.test(text.slice(at - 1, at + 1))) break; + for (var first = true;; first = false) { + var endOfText = at; + if (killTrailingSpace) + while (text.charAt(endOfText - 1) == " ") --endOfText; + if (endOfText == 0 && first) at = column; + else return {from: endOfText, to: at}; + } + } + + function wrapRange(cm, from, to, options) { + from = cm.clipPos(from); to = cm.clipPos(to); + var column = options.column || 80; + var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/; + var killTrailing = options.killTrailingSpace !== false; + var changes = [], curLine = "", curNo = from.line; + var lines = cm.getRange(from, to, false); + if (!lines.length) return null; + var leadingSpace = lines[0].match(/^[ \t]*/)[0]; + if (leadingSpace.length >= column) column = leadingSpace.length + 1 + + for (var i = 0; i < lines.length; ++i) { + var text = lines[i], oldLen = curLine.length, spaceInserted = 0; + if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) { + curLine += " "; + spaceInserted = 1; + } + var spaceTrimmed = ""; + if (i) { + spaceTrimmed = text.match(/^\s*/)[0]; + text = text.slice(spaceTrimmed.length); + } + curLine += text; + if (i) { + var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed && + findBreakPoint(curLine, column, wrapOn, killTrailing); + // If this isn't broken, or is broken at a different point, remove old break + if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) { + changes.push({text: [spaceInserted ? " " : ""], + from: Pos(curNo, oldLen), + to: Pos(curNo + 1, spaceTrimmed.length)}); + } else { + curLine = leadingSpace + text; + ++curNo; + } + } + while (curLine.length > column) { + var bp = findBreakPoint(curLine, column, wrapOn, killTrailing); + changes.push({text: ["", leadingSpace], + from: Pos(curNo, bp.from), + to: Pos(curNo, bp.to)}); + curLine = leadingSpace + curLine.slice(bp.to); + ++curNo; + } + } + if (changes.length) cm.operation(function() { + for (var i = 0; i < changes.length; ++i) { + var change = changes[i]; + if (change.text || CodeMirror.cmpPos(change.from, change.to)) + cm.replaceRange(change.text, change.from, change.to); + } + }); + return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null; + } + + CodeMirror.defineExtension("wrapParagraph", function(pos, options) { + options = options || {}; + if (!pos) pos = this.getCursor(); + var para = findParagraph(this, pos, options); + return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options); + }); + + CodeMirror.commands.wrapLines = function(cm) { + cm.operation(function() { + var ranges = cm.listSelections(), at = cm.lastLine() + 1; + for (var i = ranges.length - 1; i >= 0; i--) { + var range = ranges[i], span; + if (range.empty()) { + var para = findParagraph(cm, range.head, {}); + span = {from: Pos(para.from, 0), to: Pos(para.to - 1)}; + } else { + span = {from: range.from(), to: range.to()}; + } + if (span.to.line >= at) continue; + at = span.from.line; + wrapRange(cm, span.from, span.to, {}); + } + }); + }; + + CodeMirror.defineExtension("wrapRange", function(from, to, options) { + return wrapRange(this, from, to, options || {}); + }); + + CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) { + options = options || {}; + var cm = this, paras = []; + for (var line = from.line; line <= to.line;) { + var para = findParagraph(cm, Pos(line, 0), options); + paras.push(para); + line = para.to; + } + var madeChange = false; + if (paras.length) cm.operation(function() { + for (var i = paras.length - 1; i >= 0; --i) + madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options); + }); + return madeChange; + }); +}); diff --git a/lib/redactor/codemirror/codemirror_connect.tpl b/lib/redactor/codemirror/codemirror_connect.tpl new file mode 100644 index 0000000..958fdc7 --- /dev/null +++ b/lib/redactor/codemirror/codemirror_connect.tpl @@ -0,0 +1,30 @@ +{assign var=codemirror value="load" scope="global"} + + + + + + +{if $smarty.const.CODEMIRROR_THEME != '' && $smarty.const.CODEMIRROR_THEME != 'default'} + +{/if} + + + + + + + + + + + + + + + + + + + + diff --git a/lib/redactor/codemirror/codemirror_editor.tpl b/lib/redactor/codemirror/codemirror_editor.tpl new file mode 100644 index 0000000..2e3189f --- /dev/null +++ b/lib/redactor/codemirror/codemirror_editor.tpl @@ -0,0 +1,83 @@ + diff --git a/lib/redactor/codemirror/config.js b/lib/redactor/codemirror/config.js new file mode 100644 index 0000000..6b0407e --- /dev/null +++ b/lib/redactor/codemirror/config.js @@ -0,0 +1,31 @@ +$(function () { + + var config = { + height: "400px", + parserfile: ["parsexml.js", "parsecss.js", "tokenizejavascript.js", "parsejavascript.js", + "../contrib/php/js/tokenizephp.js", "../contrib/php/js/parsephp.js", + "../contrib/php/js/parsephphtmlmixed.js"], + stylesheet: ["codemirror/css/xmlcolors.css", "codemirror/css/jscolors.css", "codemirror/css/csscolors.css", "codemirror/contrib/php/css/phpcolors.css"], + path: "codemirror/js/", + lineNumbers: true, + lineWrapping: true, + matchBrackets: true, + onCursorActivity: function() { + editor.setLineClass(hlLine, null); + hlLine = editor.setLineClass(editor.getCursor().line, "activeline"); + } + }; + var arrays = $(".coder_in textarea"); + + $.each(arrays, function() { + editor($(this).attr('id')); + }); + + function editor(id) + { + CodeMirror.fromTextArea(id, config); + } + + var hlLine = editor.setLineClass(0, "activeline"); + +}); \ No newline at end of file diff --git a/lib/redactor/codemirror/config_css.js b/lib/redactor/codemirror/config_css.js new file mode 100644 index 0000000..e01b959 --- /dev/null +++ b/lib/redactor/codemirror/config_css.js @@ -0,0 +1,28 @@ +$(function () { + + var config = { + height: "400px", + stylesheet: ["codemirror/lib/codemirror.css", "codemirror/doc/docs.css", "codemirror/mode/css/csscolors.css"], + path: "codemirror/lib/", + lineNumbers: true, + lineWrapping: true, + matchBrackets: true, + onCursorActivity: function() { + editor.setLineClass(hlLine, null); + hlLine = editor.setLineClass(editor.getCursor().line, "activeline"); + } + }; + var arrays = $(".code_text textarea"); + + $.each(arrays, function() { + editor($(this).attr('id')); + }); + + function editor(id) + { + CodeMirror.fromTextArea(id, config); + } + + var hlLine = editor.setLineClass(0, "activeline"); + +}); \ No newline at end of file diff --git a/lib/redactor/codemirror/functions.js b/lib/redactor/codemirror/functions.js new file mode 100644 index 0000000..887e647 --- /dev/null +++ b/lib/redactor/codemirror/functions.js @@ -0,0 +1,5 @@ + +CodeMirror.commands.autocomplete = function (cm) { + CodeMirror.showHint(cm, CodeMirror.htmlHint); +} + \ No newline at end of file diff --git a/lib/redactor/codemirror/index.php b/lib/redactor/codemirror/index.php new file mode 100644 index 0000000..ed2dcab --- /dev/null +++ b/lib/redactor/codemirror/index.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/lib/redactor/codemirror/lib/codemirror.css b/lib/redactor/codemirror/lib/codemirror.css new file mode 100644 index 0000000..98d9fe8 --- /dev/null +++ b/lib/redactor/codemirror/lib/codemirror.css @@ -0,0 +1,350 @@ +/* BASICS */ + +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + direction: ltr; + font-size: 15px !important; +} + +/* PADDING */ + +.CodeMirror-lines { + padding: 4px 0; /* Vertical padding around content */ +} +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { + padding: 0 4px; /* Horizontal padding of content */ +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; /* The little square between H and V scrollbars */ +} + +/* GUTTER */ + +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} +.CodeMirror-linenumbers {} +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +.CodeMirror-guttermarker { color: black; } +.CodeMirror-guttermarker-subtle { color: #999; } + +/* CURSOR */ + +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} +/* Shown when moving in bi-directional text */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0 !important; + background: #7e7; +} +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} +.cm-fat-cursor-mark { + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} +@-moz-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@-webkit-keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} +@keyframes blink { + 0% {} + 50% { background-color: transparent; } + 100% {} +} + +/* Can style cursor different in overwrite (non-insert) mode */ +.CodeMirror-overwrite .CodeMirror-cursor {} + +.cm-tab { display: inline-block; text-decoration: inherit; } + +.CodeMirror-rulers { + position: absolute; + left: 0; right: 0; top: -50px; bottom: 0; + overflow: hidden; +} +.CodeMirror-ruler { + border-left: 1px solid #ccc; + top: 0; bottom: 0; + position: absolute; +} + +/* DEFAULT THEME */ + +.cm-s-default .cm-header {color: blue;} +.cm-s-default .cm-quote {color: #090;} +.cm-negative {color: #d44;} +.cm-positive {color: #292;} +.cm-header, .cm-strong {font-weight: bold;} +.cm-em {font-style: italic;} +.cm-link {text-decoration: underline;} +.cm-strikethrough {text-decoration: line-through;} + +.cm-s-default .cm-keyword {color: #708;} +.cm-s-default .cm-atom {color: #219;} +.cm-s-default .cm-number {color: #164;} +.cm-s-default .cm-def {color: #00f;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} +.cm-s-default .cm-variable-2 {color: #05a;} +.cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} +.cm-s-default .cm-comment {color: #a50;} +.cm-s-default .cm-string {color: #a11;} +.cm-s-default .cm-string-2 {color: #f50;} +.cm-s-default .cm-meta {color: #555;} +.cm-s-default .cm-qualifier {color: #555;} +.cm-s-default .cm-builtin {color: #30a;} +.cm-s-default .cm-bracket {color: #997;} +.cm-s-default .cm-tag {color: #170;} +.cm-s-default .cm-attribute {color: #00c;} +.cm-s-default .cm-hr {color: #999;} +.cm-s-default .cm-link {color: #00c;} + +.cm-s-default .cm-error {color: #f00;} +.cm-invalidchar {color: #f00;} + +.CodeMirror-composing { border-bottom: 2px solid; } + +/* Default styles for common addons */ + +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} +.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } +.CodeMirror-activeline-background {background: #e8f2ff;} + +/* STOP */ + +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ + +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +.CodeMirror-scroll { + overflow: scroll !important; /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; /* Prevent dragging from highlighting the element */ + position: relative; +} +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} +.CodeMirror-vscrollbar { + right: 0; top: 0; + overflow-x: hidden; + overflow-y: scroll; +} +.CodeMirror-hscrollbar { + bottom: 0; left: 0; + overflow-y: hidden; + overflow-x: scroll; +} +.CodeMirror-scrollbar-filler { + right: 0; bottom: 0; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; +} + +.CodeMirror-gutters { + position: absolute; left: 0; top: 0; + min-height: 100%; + z-index: 3; +} +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; +} +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} +.CodeMirror-gutter-background { + position: absolute; + top: 0; bottom: 0; + z-index: 4; +} +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} +.CodeMirror-gutter-wrapper ::selection { background-color: transparent } +.CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } + +.CodeMirror-lines { + cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ +} +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { + /* Reset some styles that the rest of the page might have set */ + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; +} +.CodeMirror-wrap pre.CodeMirror-line, +.CodeMirror-wrap pre.CodeMirror-line-like { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +.CodeMirror-linebackground { + position: absolute; + left: 0; right: 0; top: 0; bottom: 0; + z-index: 0; +} + +.CodeMirror-linewidget { + position: relative; + z-index: 2; + padding: 0.1px; /* Force widget margins to stay inside of the container */ +} + +.CodeMirror-widget {} + +.CodeMirror-rtl pre { direction: rtl; } + +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +.CodeMirror-cursor { + position: absolute; + pointer-events: none; +} +.CodeMirror-measure pre { position: static; } + +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} +div.CodeMirror-dragcursors { + visibility: visible; +} + +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +.CodeMirror-selected { background: #d9d9d9; } +.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } +.CodeMirror-crosshair { cursor: crosshair; } +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } + +.cm-searching { + background-color: #ffa; + background-color: rgba(255, 255, 0, .4); +} + +/* Used to force a border model for a node */ +.cm-force-border { padding-right: .1px; } + +@media print { + /* Hide the cursor when printing */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +.cm-tab-wrap-hack:after { content: ''; } + +/* Help users use markselection to safely style text background */ +span.CodeMirror-selectedtext { background: none; } diff --git a/lib/redactor/codemirror/lib/codemirror.js b/lib/redactor/codemirror/lib/codemirror.js new file mode 100644 index 0000000..72267f6 --- /dev/null +++ b/lib/redactor/codemirror/lib/codemirror.js @@ -0,0 +1,9806 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// This is CodeMirror (https://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.CodeMirror = factory()); +}(this, (function () { 'use strict'; + + // Kludges for bugs and behavior differences that can't be feature + // detected are enabled based on userAgent etc sniffing. + var userAgent = navigator.userAgent; + var platform = navigator.platform; + + var gecko = /gecko\/\d/i.test(userAgent); + var ie_upto10 = /MSIE \d/.test(userAgent); + var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); + var edge = /Edge\/(\d+)/.exec(userAgent); + var ie = ie_upto10 || ie_11up || edge; + var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]); + var webkit = !edge && /WebKit\//.test(userAgent); + var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); + var chrome = !edge && /Chrome\//.test(userAgent); + var presto = /Opera\//.test(userAgent); + var safari = /Apple Computer/.test(navigator.vendor); + var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); + var phantom = /PhantomJS/.test(userAgent); + + var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); + var android = /Android/.test(userAgent); + // This is woefully incomplete. Suggestions for alternative methods welcome. + var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); + var mac = ios || /Mac/.test(platform); + var chromeOS = /\bCrOS\b/.test(userAgent); + var windows = /win/i.test(platform); + + var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); + if (presto_version) { presto_version = Number(presto_version[1]); } + if (presto_version && presto_version >= 15) { presto = false; webkit = true; } + // Some browsers use the wrong event properties to signal cmd/ctrl on OS X + var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); + var captureRightClick = gecko || (ie && ie_version >= 9); + + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } + + var rmClass = function(node, cls) { + var current = node.className; + var match = classTest(cls).exec(current); + if (match) { + var after = current.slice(match.index + match[0].length); + node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + } + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + { e.removeChild(e.firstChild); } + return e + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e) + } + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) { e.className = className; } + if (style) { e.style.cssText = style; } + if (typeof content == "string") { e.appendChild(document.createTextNode(content)); } + else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } } + return e + } + // wrapper for elt, which removes the elt from the accessibility tree + function eltP(tag, content, className, style) { + var e = elt(tag, content, className, style); + e.setAttribute("role", "presentation"); + return e + } + + var range; + if (document.createRange) { range = function(node, start, end, endNode) { + var r = document.createRange(); + r.setEnd(endNode || node, end); + r.setStart(node, start); + return r + }; } + else { range = function(node, start, end) { + var r = document.body.createTextRange(); + try { r.moveToElementText(node.parentNode); } + catch(e) { return r } + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r + }; } + + function contains(parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + { child = child.parentNode; } + if (parent.contains) + { return parent.contains(child) } + do { + if (child.nodeType == 11) { child = child.host; } + if (child == parent) { return true } + } while (child = child.parentNode) + } + + function activeElt() { + // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. + // IE < 10 will throw when accessed while the page is loading or in an iframe. + // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. + var activeElement; + try { + activeElement = document.activeElement; + } catch(e) { + activeElement = document.body || null; + } + while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement) + { activeElement = activeElement.shadowRoot.activeElement; } + return activeElement + } + + function addClass(node, cls) { + var current = node.className; + if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; } + } + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } } + return b + } + + var selectInput = function(node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; } + else if (ie) // Suppress mysterious IE10 errors + { selectInput = function(node) { try { node.select(); } catch(_e) {} }; } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function(){return f.apply(null, args)} + } + + function copyObj(obj, target, overwrite) { + if (!target) { target = {}; } + for (var prop in obj) + { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + { target[prop] = obj[prop]; } } + return target + } + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + function countColumn(string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) { end = string.length; } + } + for (var i = startIndex || 0, n = startValue || 0;;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + { return n + (end - i) } + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + } + + var Delayed = function() { + this.id = null; + this.f = null; + this.time = 0; + this.handler = bind(this.onTimeout, this); + }; + Delayed.prototype.onTimeout = function (self) { + self.id = 0; + if (self.time <= +new Date) { + self.f(); + } else { + setTimeout(self.handler, self.time - +new Date); + } + }; + Delayed.prototype.set = function (ms, f) { + this.f = f; + var time = +new Date + ms; + if (!this.id || time < this.time) { + clearTimeout(this.id); + this.id = setTimeout(this.handler, ms); + this.time = time; + } + }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + { if (array[i] == elt) { return i } } + return -1 + } + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerGap = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = {toString: function(){return "CodeMirror.Pass"}}; + + // Reused option objects for setSelection & friends + var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + function findColumn(string, goal, tabSize) { + for (var pos = 0, col = 0;;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) { nextTab = string.length; } + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + { return pos + Math.min(skipped, goal - col) } + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) { return pos } + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + { spaceStrs.push(lst(spaceStrs) + " "); } + return spaceStrs[n] + } + + function lst(arr) { return arr[arr.length-1] } + + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); } + return out + } + + function insertSorted(array, value, score) { + var pos = 0, priority = score(value); + while (pos < array.length && score(array[pos]) <= priority) { pos++; } + array.splice(pos, 0, value); + } + + function nothing() {} + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + nothing.prototype = base; + inst = new nothing(); + } + if (props) { copyObj(props, inst); } + return inst + } + + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + function isWordCharBasic(ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) + } + function isWordChar(ch, helper) { + if (!helper) { return isWordCharBasic(ch) } + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true } + return helper.test(ch) + } + + function isEmpty(obj) { + for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } } + return true + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } + + // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range. + function skipExtendingChars(str, pos, dir) { + while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; } + return pos + } + + // Returns the value from the range [`from`; `to`] that satisfies + // `pred` and is closest to `from`. Assumes that at least `to` + // satisfies `pred`. Supports `from` being greater than `to`. + function findFirst(pred, from, to) { + // At any point we are certain `to` satisfies `pred`, don't know + // whether `from` does. + var dir = from > to ? -1 : 1; + for (;;) { + if (from == to) { return from } + var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF); + if (mid == from) { return pred(mid) ? from : to } + if (pred(mid)) { to = mid; } + else { from = mid + dir; } + } + } + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) { return f(from, to, "ltr", 0) } + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i); + found = true; + } + } + if (!found) { f(from, to, "ltr"); } + } + + var bidiOther = null; + function getBidiPartAt(order, ch, sticky) { + var found; + bidiOther = null; + for (var i = 0; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < ch && cur.to > ch) { return i } + if (cur.to == ch) { + if (cur.from != cur.to && sticky == "before") { found = i; } + else { bidiOther = i; } + } + if (cur.from == ch) { + if (cur.from != cur.to && sticky != "before") { found = i; } + else { bidiOther = i; } + } + } + return found != null ? found : bidiOther + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function() { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6f9 + var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111"; + function charType(code) { + if (code <= 0xf7) { return lowTypes.charAt(code) } + else if (0x590 <= code && code <= 0x5f4) { return "R" } + else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) } + else if (0x6ee <= code && code <= 0x8ac) { return "r" } + else if (0x2000 <= code && code <= 0x200b) { return "w" } + else if (code == 0x200c) { return "b" } + else { return "L" } + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function(str, direction) { + var outerType = direction == "ltr" ? "L" : "R"; + + if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false } + var len = str.length, types = []; + for (var i = 0; i < len; ++i) + { types.push(charType(str.charCodeAt(i))); } + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) { + var type = types[i$1]; + if (type == "m") { types[i$1] = prev; } + else { prev = type; } + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) { + var type$1 = types[i$2]; + if (type$1 == "1" && cur == "r") { types[i$2] = "n"; } + else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) { + var type$2 = types[i$3]; + if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; } + else if (type$2 == "," && prev$1 == types[i$3+1] && + (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; } + prev$1 = type$2; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i$4 = 0; i$4 < len; ++i$4) { + var type$3 = types[i$4]; + if (type$3 == ",") { types[i$4] = "N"; } + else if (type$3 == "%") { + var end = (void 0); + for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {} + var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i$4; j < end; ++j) { types[j] = replace; } + i$4 = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) { + var type$4 = types[i$5]; + if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; } + else if (isStrong.test(type$4)) { cur$1 = type$4; } + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i$6 = 0; i$6 < len; ++i$6) { + if (isNeutral.test(types[i$6])) { + var end$1 = (void 0); + for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {} + var before = (i$6 ? types[i$6-1] : outerType) == "L"; + var after = (end$1 < len ? types[end$1] : outerType) == "L"; + var replace$1 = before == after ? (before ? "L" : "R") : outerType; + for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; } + i$6 = end$1 - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i$7 = 0; i$7 < len;) { + if (countsAsLeft.test(types[i$7])) { + var start = i$7; + for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {} + order.push(new BidiSpan(0, start, i$7)); + } else { + var pos = i$7, at = order.length; + for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {} + for (var j$2 = pos; j$2 < i$7;) { + if (countsAsNum.test(types[j$2])) { + if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); } + var nstart = j$2; + for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {} + order.splice(at, 0, new BidiSpan(2, nstart, j$2)); + pos = j$2; + } else { ++j$2; } + } + if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); } + } + } + if (direction == "ltr") { + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + } + + return direction == "rtl" ? order.reverse() : order + } + })(); + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line, direction) { + var order = line.order; + if (order == null) { order = line.order = bidiOrdering(line.text, direction); } + return order + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var noHandlers = []; + + var on = function(emitter, type, f) { + if (emitter.addEventListener) { + emitter.addEventListener(type, f, false); + } else if (emitter.attachEvent) { + emitter.attachEvent("on" + type, f); + } else { + var map$$1 = emitter._handlers || (emitter._handlers = {}); + map$$1[type] = (map$$1[type] || noHandlers).concat(f); + } + }; + + function getHandlers(emitter, type) { + return emitter._handlers && emitter._handlers[type] || noHandlers + } + + function off(emitter, type, f) { + if (emitter.removeEventListener) { + emitter.removeEventListener(type, f, false); + } else if (emitter.detachEvent) { + emitter.detachEvent("on" + type, f); + } else { + var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type]; + if (arr) { + var index = indexOf(arr, f); + if (index > -1) + { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); } + } + } + } + + function signal(emitter, type /*, values...*/) { + var handlers = getHandlers(emitter, type); + if (!handlers.length) { return } + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); } + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; } + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) { return } + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1) + { set.push(arr[i]); } } + } + + function hasHandler(emitter, type) { + return getHandlers(emitter, type).length > 0 + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + function e_preventDefault(e) { + if (e.preventDefault) { e.preventDefault(); } + else { e.returnValue = false; } + } + function e_stopPropagation(e) { + if (e.stopPropagation) { e.stopPropagation(); } + else { e.cancelBubble = true; } + } + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false + } + function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);} + + function e_target(e) {return e.target || e.srcElement} + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) { b = 1; } + else if (e.button & 2) { b = 3; } + else if (e.button & 4) { b = 2; } + } + if (mac && e.ctrlKey && b == 1) { b = 3; } + return b + } + + // Detect drag-and-drop + var dragAndDrop = function() { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) { return false } + var div = elt('div'); + return "draggable" in div || "dragDrop" in div + }(); + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); } + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + node.setAttribute("cm-text", ""); + return node + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) { return badBidiRects } + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + var r1 = range(txt, 1, 2).getBoundingClientRect(); + removeChildren(measure); + if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780) + return badBidiRects = (r1.right - r0.right < 3) + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) { nl = string.length; } + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result + } : function (string) { return string.split(/\r\n?|\n/); }; + + var hasSelection = window.getSelection ? function (te) { + try { return te.selectionStart != te.selectionEnd } + catch(e) { return false } + } : function (te) { + var range$$1; + try {range$$1 = te.ownerDocument.selection.createRange();} + catch(e) {} + if (!range$$1 || range$$1.parentElement() != te) { return false } + return range$$1.compareEndPoints("StartToEnd", range$$1) != 0 + }; + + var hasCopyEvent = (function () { + var e = elt("div"); + if ("oncopy" in e) { return true } + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function" + })(); + + var badZoomedRects = null; + function hasBadZoomedRects(measure) { + if (badZoomedRects != null) { return badZoomedRects } + var node = removeChildrenAndAdd(measure, elt("span", "x")); + var normal = node.getBoundingClientRect(); + var fromRange = range(node, 0, 1).getBoundingClientRect(); + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 + } + + // Known modes, by name and by MIME + var modes = {}, mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + function defineMode(name, mode) { + if (arguments.length > 2) + { mode.dependencies = Array.prototype.slice.call(arguments, 2); } + modes[name] = mode; + } + + function defineMIME(mime, spec) { + mimeModes[mime] = spec; + } + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + function resolveMode(spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") { found = {name: found}; } + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return resolveMode("application/xml") + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { + return resolveMode("application/json") + } + if (typeof spec == "string") { return {name: spec} } + else { return spec || {name: "null"} } + } + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + function getMode(options, spec) { + spec = resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) { return getMode(options, "text/plain") } + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) { continue } + if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; } + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) { modeObj.helperType = spec.helperType; } + if (spec.modeProps) { for (var prop$1 in spec.modeProps) + { modeObj[prop$1] = spec.modeProps[prop$1]; } } + + return modeObj + } + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = {}; + function extendMode(mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + } + + function copyState(mode, state) { + if (state === true) { return state } + if (mode.copyState) { return mode.copyState(state) } + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) { val = val.concat([]); } + nstate[n] = val; + } + return nstate + } + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + function innerMode(mode, state) { + var info; + while (mode.innerMode) { + info = mode.innerMode(state); + if (!info || info.mode == mode) { break } + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state} + } + + function startState(mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true + } + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = function(string, tabSize, lineOracle) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + this.lineOracle = lineOracle; + }; + + StringStream.prototype.eol = function () {return this.pos >= this.string.length}; + StringStream.prototype.sol = function () {return this.pos == this.lineStart}; + StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; + StringStream.prototype.next = function () { + if (this.pos < this.string.length) + { return this.string.charAt(this.pos++) } + }; + StringStream.prototype.eat = function (match) { + var ch = this.string.charAt(this.pos); + var ok; + if (typeof match == "string") { ok = ch == match; } + else { ok = ch && (match.test ? match.test(ch) : match(ch)); } + if (ok) {++this.pos; return ch} + }; + StringStream.prototype.eatWhile = function (match) { + var start = this.pos; + while (this.eat(match)){} + return this.pos > start + }; + StringStream.prototype.eatSpace = function () { + var this$1 = this; + + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; } + return this.pos > start + }; + StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; + StringStream.prototype.skipTo = function (ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) {this.pos = found; return true} + }; + StringStream.prototype.backUp = function (n) {this.pos -= n;}; + StringStream.prototype.column = function () { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) + }; + StringStream.prototype.indentation = function () { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) + }; + StringStream.prototype.match = function (pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) { this.pos += pattern.length; } + return true + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) { return null } + if (match && consume !== false) { this.pos += match[0].length; } + return match + } + }; + StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; + StringStream.prototype.hideFirstChars = function (n, inner) { + this.lineStart += n; + try { return inner() } + finally { this.lineStart -= n; } + }; + StringStream.prototype.lookAhead = function (n) { + var oracle = this.lineOracle; + return oracle && oracle.lookAhead(n) + }; + StringStream.prototype.baseToken = function () { + var oracle = this.lineOracle; + return oracle && oracle.baseToken(this.pos) + }; + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") } + var chunk = doc; + while (!chunk.lines) { + for (var i = 0;; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break } + n -= sz; + } + } + return chunk.lines[n] + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function (line) { + var text = line.text; + if (n == end.line) { text = text.slice(0, end.ch); } + if (n == start.line) { text = text.slice(start.ch); } + out.push(text); + ++n; + }); + return out + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value + return out + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } } + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) { return null } + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0;; ++i) { + if (chunk.children[i] == cur) { break } + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) { + var child = chunk.children[i$1], ch = child.height; + if (h < ch) { chunk = child; continue outer } + h -= ch; + n += child.chunkSize(); + } + return n + } while (!chunk.lines) + var i = 0; + for (; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) { break } + h -= lh; + } + return n + i + } + + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size} + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)) + } + + // A Pos instance represents a position within the text. + function Pos(line, ch, sticky) { + if ( sticky === void 0 ) sticky = null; + + if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) } + this.line = line; + this.ch = ch; + this.sticky = sticky; + } + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + function cmp(a, b) { return a.line - b.line || a.ch - b.ch } + + function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 } + + function copyPos(x) {return Pos(x.line, x.ch)} + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} + function clipPos(doc, pos) { + if (pos.line < doc.first) { return Pos(doc.first, 0) } + var last = doc.first + doc.size - 1; + if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) } + return clipToLen(pos, getLine(doc, pos.line).text.length) + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) { return Pos(pos.line, linelen) } + else if (ch < 0) { return Pos(pos.line, 0) } + else { return pos } + } + function clipPosArray(doc, array) { + var out = []; + for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); } + return out + } + + var SavedContext = function(state, lookAhead) { + this.state = state; + this.lookAhead = lookAhead; + }; + + var Context = function(doc, state, line, lookAhead) { + this.state = state; + this.doc = doc; + this.line = line; + this.maxLookAhead = lookAhead || 0; + this.baseTokens = null; + this.baseTokenPos = 1; + }; + + Context.prototype.lookAhead = function (n) { + var line = this.doc.getLine(this.line + n); + if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; } + return line + }; + + Context.prototype.baseToken = function (n) { + var this$1 = this; + + if (!this.baseTokens) { return null } + while (this.baseTokens[this.baseTokenPos] <= n) + { this$1.baseTokenPos += 2; } + var type = this.baseTokens[this.baseTokenPos + 1]; + return {type: type && type.replace(/( |^)overlay .*/, ""), + size: this.baseTokens[this.baseTokenPos] - n} + }; + + Context.prototype.nextLine = function () { + this.line++; + if (this.maxLookAhead > 0) { this.maxLookAhead--; } + }; + + Context.fromSaved = function (doc, saved, line) { + if (saved instanceof SavedContext) + { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) } + else + { return new Context(doc, copyState(doc.mode, saved), line) } + }; + + Context.prototype.save = function (copy) { + var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state; + return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state + }; + + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, context, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); }, + lineClasses, forceToEnd); + var state = context.state; + + // Run overlays, adjust style array. + var loop = function ( o ) { + context.baseTokens = st; + var overlay = cm.state.overlays[o], i = 1, at = 0; + context.state = true; + runMode(cm, line.text, overlay.mode, context, function (end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + { st.splice(i, 1, end, st[i+1], i_end); } + i += 2; + at = Math.min(end, i_end); + } + if (!style) { return } + if (overlay.opaque) { + st.splice(start, i - start, end, "overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start+1]; + st[start+1] = (cur ? cur + " " : "") + "overlay " + style; + } + } + }, lineClasses); + context.state = state; + context.baseTokens = null; + context.baseTokenPos = 1; + }; + + for (var o = 0; o < cm.state.overlays.length; ++o) loop( o ); + + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} + } + + function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var context = getContextBefore(cm, lineNo(line)); + var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state); + var result = highlightLine(cm, line, context); + if (resetState) { context.state = resetState; } + line.stateAfter = context.save(!resetState); + line.styles = result.styles; + if (result.classes) { line.styleClasses = result.classes; } + else if (line.styleClasses) { line.styleClasses = null; } + if (updateFrontier === cm.doc.highlightFrontier) + { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); } + } + return line.styles + } + + function getContextBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) { return new Context(doc, true, n) } + var start = findStartLine(cm, n, precise); + var saved = start > doc.first && getLine(doc, start - 1).stateAfter; + var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start); + + doc.iter(start, n, function (line) { + processLine(cm, line.text, context); + var pos = context.line; + line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null; + context.nextLine(); + }); + if (precise) { doc.modeFrontier = context.line; } + return context + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, context, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize, context); + stream.start = stream.pos = startAt || 0; + if (text == "") { callBlankLine(mode, context.state); } + while (!stream.eol()) { + readToken(mode, stream, context.state); + stream.start = stream.pos; + } + } + + function callBlankLine(mode, state) { + if (mode.blankLine) { return mode.blankLine(state) } + if (!mode.innerMode) { return } + var inner = innerMode(mode, state); + if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) } + } + + function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) { inner[0] = innerMode(mode, state).mode; } + var style = mode.token(stream, state); + if (stream.pos > stream.start) { return style } + } + throw new Error("Mode " + mode.name + " failed to advance stream.") + } + + var Token = function(stream, type, state) { + this.start = stream.start; this.end = stream.pos; + this.string = stream.current(); + this.type = type || null; + this.state = state; + }; + + // Utility for getTokenAt and getLineTokens + function takeToken(cm, pos, precise, asArray) { + var doc = cm.doc, mode = doc.mode, style; + pos = clipPos(doc, pos); + var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise); + var stream = new StringStream(line.text, cm.options.tabSize, context), tokens; + if (asArray) { tokens = []; } + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos; + style = readToken(mode, stream, context.state); + if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); } + } + return asArray ? tokens : new Token(stream, style, context.state) + } + + function extractLineClasses(type, output) { + if (type) { for (;;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) { break } + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + { output[prop] = lineClass[2]; } + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + { output[prop] += " " + lineClass[2]; } + } } + return type + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; } + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize, context), style; + var inner = cm.options.addModeClass && [null]; + if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); } + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) { processLine(cm, text, context, stream.pos); } + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses); + } + if (inner) { + var mName = inner[0].name; + if (mName) { style = "m-" + (style ? mName + " " + style : mName); } + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 5000); + f(curStart, curStyle); + } + curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 + // characters, and returns inaccurate measurements in nodes + // starting around 5000 chars. + var pos = Math.min(stream.pos, curStart + 5000); + f(pos, curStyle); + curStart = pos; + } + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) { return doc.first } + var line = getLine(doc, search - 1), after = line.stateAfter; + if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier)) + { return search } + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline + } + + function retreatFrontier(doc, n) { + doc.modeFrontier = Math.min(doc.modeFrontier, n); + if (doc.highlightFrontier < n - 10) { return } + var start = doc.first; + for (var line = n - 1; line > start; line--) { + var saved = getLine(doc, line).stateAfter; + // change is on 3 + // state on line 1 looked ahead 2 -- so saw 3 + // test 1 + 2 < 3 should cover this + if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) { + start = line + 1; + break + } + } + doc.highlightFrontier = Math.min(doc.highlightFrontier, start); + } + + // Optimize some code when these features are not used. + var sawReadOnlySpans = false, sawCollapsedSpans = false; + + function seeReadOnlySpans() { + sawReadOnlySpans = true; + } + + function seeCollapsedSpans() { + sawCollapsedSpans = true; + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) { for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) { return span } + } } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + var r; + for (var i = 0; i < spans.length; ++i) + { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } } + return r + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + var nw; + if (old) { for (var i = 0; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } } + return nw + } + function markedSpansAfter(old, endCh, isInsert) { + var nw; + if (old) { for (var i = 0; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } } + return nw + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + if (change.full) { return null } + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) { return null } + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) { span.to = startCh; } + else if (sameLine) { span.to = found.to == null ? null : found.to + offset; } + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i$1 = 0; i$1 < last.length; ++i$1) { + var span$1 = last[i$1]; + if (span$1.to != null) { span$1.to += offset; } + if (span$1.from == null) { + var found$1 = getMarkedSpanFor(first, span$1.marker); + if (!found$1) { + span$1.from = offset; + if (sameLine) { (first || (first = [])).push(span$1); } + } + } else { + span$1.from += offset; + if (sameLine) { (first || (first = [])).push(span$1); } + } + } + } + // Make sure we didn't create any zero-length spans + if (first) { first = clearEmptySpans(first); } + if (last && last != first) { last = clearEmptySpans(last); } + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + { for (var i$2 = 0; i$2 < first.length; ++i$2) + { if (first[i$2].to == null) + { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } } + for (var i$3 = 0; i$3 < gap; ++i$3) + { newMarkers.push(gapMarkers); } + newMarkers.push(last); + } + return newMarkers + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + { spans.splice(i--, 1); } + } + if (!spans.length) { return null } + return spans + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function (line) { + if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + { (markers || (markers = [])).push(mark); } + } } + }); + if (!markers) { return null } + var parts = [{from: from, to: to}]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue } + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + { newParts.push({from: p.from, to: m.from}); } + if (dto > 0 || !mk.inclusiveRight && !dto) + { newParts.push({from: m.to, to: p.to}); } + parts.splice.apply(parts, newParts); + j += newParts.length - 3; + } + } + return parts + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) { return } + for (var i = 0; i < spans.length; ++i) + { spans[i].marker.detachLine(line); } + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) { return } + for (var i = 0; i < spans.length; ++i) + { spans[i].marker.attachLine(line); } + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) { return lenDiff } + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) { return -fromCmp } + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) { return toCmp } + return b.id - a.id + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + { found = sp.marker; } + } } + return found + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } + + function collapsedSpanAround(line, ch) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; } + } } + return found + } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) { + var line = getLine(doc, lineNo$$1); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) { for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) { continue } + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue } + if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || + fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) + { return true } + } } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + { line = merged.find(-1, true).line; } + return line + } + + function visualLineEnd(line) { + var merged; + while (merged = collapsedSpanAtEnd(line)) + { line = merged.find(1, true).line; } + return line + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line + ;(lines || (lines = [])).push(line); + } + return lines + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) { return lineN } + return lineNo(vis) + } + + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) { return lineN } + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) { return lineN } + while (merged = collapsedSpanAtEnd(line)) + { line = merged.find(1, true).line; } + return lineNo(line) + 1 + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) { continue } + if (sp.from == null) { return true } + if (sp.marker.widgetNode) { continue } + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + { return true } + } } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) + } + if (span.marker.inclusiveRight && span.to == line.text.length) + { return true } + for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) { return true } + } + } + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) { break } + else { h += line.height; } + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i$1 = 0; i$1 < p.children.length; ++i$1) { + var cur = p.children[i$1]; + if (cur == chunk) { break } + else { h += cur.height; } + } + } + return h + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) { return 0 } + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found$1 = merged.find(0, true); + len -= cur.text.length - found$1.from.ch; + cur = found$1.to.line; + len += cur.text.length - found$1.to.ch; + } + return len + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function (line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = function(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + + Line.prototype.lineNo = function () { return lineNo(this) }; + eventMixin(Line); + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) { line.stateAfter = null; } + if (line.styles) { line.styles = null; } + if (line.order != null) { line.order = null; } + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) { updateLineHeight(line, estHeight); } + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) { return null } + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")) + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content, + col: 0, pos: 0, cm: cm, + trailingSpace: false, + splitSpaces: cm.getOption("lineWrapping")}; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0); + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction))) + { builder.addToken = buildTokenBadBidi(builder.addToken, order); } + builder.map = []; + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); } + if (line.styleClasses.textClass) + { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); } + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); } + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) + ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + // See issue #2901 + if (webkit) { + var last = builder.content.lastChild; + if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) + { builder.content.className = "cm-tab-wrap-hack"; } + } + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); } + + return builder + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); + return token + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, css, attributes) { + if (!text) { return } + var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text; + var special = builder.cm.state.specialChars, mustWrap = false; + var content; + if (!special.test(text)) { + builder.col += text.length; + content = document.createTextNode(displayText); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) { mustWrap = true; } + builder.pos += text.length; + } else { + content = document.createDocumentFragment(); + var pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); + if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); } + else { content.appendChild(txt); } + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) { break } + pos += skipped + 1; + var txt$1 = (void 0); + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt$1.setAttribute("role", "presentation"); + txt$1.setAttribute("cm-text", "\t"); + builder.col += tabWidth; + } else if (m[0] == "\r" || m[0] == "\n") { + txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); + txt$1.setAttribute("cm-text", m[0]); + builder.col += 1; + } else { + txt$1 = builder.cm.options.specialCharPlaceholder(m[0]); + txt$1.setAttribute("cm-text", m[0]); + if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); } + else { content.appendChild(txt$1); } + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt$1); + builder.pos++; + } + } + builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32; + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || ""; + if (startStyle) { fullStyle += startStyle; } + if (endStyle) { fullStyle += endStyle; } + var token = elt("span", [content], fullStyle, css); + if (attributes) { + for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class") + { token.setAttribute(attr, attributes[attr]); } } + } + return builder.content.appendChild(token) + } + builder.content.appendChild(content); + } + + // Change some spaces to NBSP to prevent the browser from collapsing + // trailing spaces at the end of a line when rendering text (issue #1362). + function splitSpaces(text, trailingBefore) { + if (text.length > 1 && !/ /.test(text)) { return text } + var spaceBefore = trailingBefore, result = ""; + for (var i = 0; i < text.length; i++) { + var ch = text.charAt(i); + if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) + { ch = "\u00a0"; } + result += ch; + spaceBefore = ch == " "; + } + return result + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function (builder, text, style, startStyle, endStyle, css, attributes) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (;;) { + // Find the part that overlaps with the start of this text + var part = (void 0); + for (var i = 0; i < order.length; i++) { + part = order[i]; + if (part.to > start && part.from <= start) { break } + } + if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) } + inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + } + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); } + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + { widget = builder.content.appendChild(document.createElement("span")); } + widget.setAttribute("cm-marker", marker.id); + } + if (widget) { + builder.cm.display.input.setUneditable(widget); + builder.content.appendChild(widget); + } + builder.pos += size; + builder.trailingSpace = false; + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i$1 = 1; i$1 < styles.length; i$1+=2) + { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); } + return + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes; + for (;;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = css = ""; + attributes = null; + collapsed = null; nextChange = Infinity; + var foundBookmarks = [], endStyles = (void 0); + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { + foundBookmarks.push(m); + } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { + if (sp.to != null && sp.to != pos && nextChange > sp.to) { + nextChange = sp.to; + spanEndStyle = ""; + } + if (m.className) { spanStyle += " " + m.className; } + if (m.css) { css = (css ? css + ";" : "") + m.css; } + if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; } + if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); } + // support for the old title property + // https://github.com/codemirror/CodeMirror/pull/5673 + if (m.title) { (attributes || (attributes = {})).title = m.title; } + if (m.attributes) { + for (var attr in m.attributes) + { (attributes || (attributes = {}))[attr] = m.attributes[attr]; } + } + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + { collapsed = sp; } + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + } + if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2) + { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } } + + if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2) + { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } } + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) { return } + if (collapsed.to == pos) { collapsed = false; } + } + } + if (pos >= len) { break } + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes); + } + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break} + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array + } + + var operationGroup = null; + + function pushOperation(op) { + if (operationGroup) { + operationGroup.ops.push(op); + } else { + op.ownsGroup = operationGroup = { + ops: [op], + delayedCallbacks: [] + }; + } + } + + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + { callbacks[i].call(null); } + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + { while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } } + } + } while (i < callbacks.length) + } + + function finishOperation(op, endCb) { + var group = op.ownsGroup; + if (!group) { return } + + try { fireCallbacksForOps(group); } + finally { + operationGroup = null; + endCb(group); + } + } + + var orphanDelayedCallbacks = null; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + function signalLater(emitter, type /*, values...*/) { + var arr = getHandlers(emitter, type); + if (!arr.length) { return } + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); + } + var loop = function ( i ) { + list.push(function () { return arr[i].apply(null, args); }); + }; + + for (var i = 0; i < arr.length; ++i) + loop( i ); + } + + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) { delayed[i](); } + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") { updateLineText(cm, lineView); } + else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); } + else if (type == "class") { updateLineClasses(cm, lineView); } + else if (type == "widget") { updateLineWidgets(cm, lineView, dims); } + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); } + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; } + } + return lineView.node + } + + function updateLineBackground(cm, lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) { cls += " CodeMirror-linebackground"; } + if (lineView.background) { + if (cls) { lineView.background.className = cls; } + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + cm.display.input.setUneditable(lineView.background); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built + } + return buildLineContent(cm, lineView) + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) { lineView.node = built.pre; } + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(cm, lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(cm, lineView) { + updateLineBackground(cm, lineView); + if (lineView.line.wrapClass) + { ensureLineWrapped(lineView).className = lineView.line.wrapClass; } + else if (lineView.node != lineView.text) + { lineView.node.className = ""; } + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + if (lineView.gutterBackground) { + lineView.node.removeChild(lineView.gutterBackground); + lineView.gutterBackground = null; + } + if (lineView.line.gutterClass) { + var wrap = ensureLineWrapped(lineView); + lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, + ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px")); + cm.display.input.setUneditable(lineView.gutterBackground); + wrap.insertBefore(lineView.gutterBackground, lineView.text); + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap$1 = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")); + cm.display.input.setUneditable(gutterWrap); + wrap$1.insertBefore(gutterWrap, lineView.text); + if (lineView.line.gutterClass) + { gutterWrap.className += " " + lineView.line.gutterClass; } + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + { lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); } + if (markers) { for (var k = 0; k < cm.display.gutterSpecs.length; ++k) { + var id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id]; + if (found) + { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", + ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); } + } } + } + } + + function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) { lineView.alignable = null; } + var isWidget = classTest("CodeMirror-linewidget"); + for (var node = lineView.node.firstChild, next = (void 0); node; node = next) { + next = node.nextSibling; + if (isWidget.test(node.className)) { lineView.node.removeChild(node); } + } + insertLineWidgets(cm, lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) { lineView.bgClass = built.bgClass; } + if (built.textClass) { lineView.textClass = built.textClass; } + + updateLineClasses(cm, lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(cm, lineView, dims); + return lineView.node + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) + { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } } + } + + function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) { return } + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget" + (widget.className ? " " + widget.className : "")); + if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); } + positionLineWidget(widget, node, lineView, dims); + cm.display.input.setUneditable(node); + if (allowAbove && widget.above) + { wrap.insertBefore(node, lineView.gutter || lineView.text); } + else + { wrap.appendChild(node); } + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; } + } + } + + function widgetHeight(widget) { + if (widget.height != null) { return widget.height } + var cm = widget.doc.cm; + if (!cm) { return 0 } + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; } + if (widget.noHScroll) + { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; } + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.parentNode.offsetHeight + } + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + { return true } + } + } + + // POSITION MEASUREMENT + + function paddingTop(display) {return display.lineSpace.offsetTop} + function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} + function paddingH(display) { + if (display.cachedPaddingH) { return display.cachedPaddingH } + var e = removeChildrenAndAdd(display.measure, elt("pre", "x", "CodeMirror-line-like")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; + if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; } + return data + } + + function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth } + function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth + } + function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && displayWidth(cm); + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + { heights.push((cur.bottom + next.top) / 2 - rect.top); } + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + { return {map: lineView.measure.map, cache: lineView.measure.cache} } + for (var i = 0; i < lineView.rest.length; i++) + { if (lineView.rest[i] == line) + { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } } + for (var i$1 = 0; i$1 < lineView.rest.length; i$1++) + { if (lineNo(lineView.rest[i$1]) > lineN) + { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } } + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias) + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + { return cm.display.view[findViewIndex(cm, lineN)] } + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + { return ext } + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) { + view = null; + } else if (view && view.changes) { + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + cm.curOp.forceUpdate = true; + } + if (!view) + { view = updateExternalMeasurement(cm, line); } + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + } + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) { ch = -1; } + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + { prepared.rect = prepared.view.text.getBoundingClientRect(); } + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) { prepared.cache[key] = found; } + } + return {left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom} + } + + var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; + + function nodeAndOffsetInLineMap(map$$1, ch, bias) { + var node, start, end, collapse, mStart, mEnd; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map$$1.length; i += 3) { + mStart = map$$1[i]; + mEnd = map$$1[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) { collapse = "right"; } + } + if (start != null) { + node = map$$1[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + { collapse = bias; } + if (bias == "left" && start == 0) + { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) { + node = map$$1[(i -= 3) + 2]; + collapse = "left"; + } } + if (bias == "right" && start == mEnd - mStart) + { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) { + node = map$$1[(i += 3) + 2]; + collapse = "right"; + } } + break + } + } + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd} + } + + function getUsefulRect(rects, bias) { + var rect = nullRect; + if (bias == "left") { for (var i = 0; i < rects.length; i++) { + if ((rect = rects[i]).left != rect.right) { break } + } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) { + if ((rect = rects[i$1]).left != rect.right) { break } + } } + return rect + } + + function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); + var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; } + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; } + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) + { rect = node.parentNode.getBoundingClientRect(); } + else + { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); } + if (rect.left || rect.right || start == 0) { break } + end = start; + start = start - 1; + collapse = "right"; + } + if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); } + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) { collapse = bias = "right"; } + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + { rect = rects[bias == "right" ? rects.length - 1 : 0]; } + else + { rect = node.getBoundingClientRect(); } + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; } + else + { rect = nullRect; } + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + var i = 0; + for (; i < heights.length - 1; i++) + { if (mid < heights[i]) { break } } + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot}; + if (!rect.left && !rect.right) { result.bogus = true; } + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + + return result + } + + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + { return rect } + var scaleX = screen.logicalXDPI / screen.deviceXDPI; + var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY} + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++) + { lineView.measure.caches[i] = {}; } } + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + { clearLineMeasurementCacheFor(cm.display.view[i]); } + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; } + cm.display.lineNumChars = null; + } + + function pageScrollX() { + // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206 + // which causes page_Offset and bounding client rects to use + // different reference viewports and invalidate our calculations. + if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) } + return window.pageXOffset || (document.documentElement || document.body).scrollLeft + } + function pageScrollY() { + if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) } + return window.pageYOffset || (document.documentElement || document.body).scrollTop + } + + function widgetTopHeight(lineObj) { + var height = 0; + if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) + { height += widgetHeight(lineObj.widgets[i]); } } } + return height + } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"./null (editor), "window", + // or "page". + function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) { + if (!includeWidgets) { + var height = widgetTopHeight(lineObj); + rect.top += height; rect.bottom += height; + } + if (context == "line") { return rect } + if (!context) { context = "local"; } + var yOff = heightAtLine(lineObj); + if (context == "local") { yOff += paddingTop(cm.display); } + else { yOff -= cm.display.viewOffset; } + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"./null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") { return coords } + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) { lineObj = getLine(cm.doc, pos.line); } + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context) + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + // A cursor Pos(line, char, "before") is on the same visual line as `char - 1` + // and after `char - 1` in writing order of `char - 1` + // A cursor Pos(line, char, "after") is on the same visual line as `char` + // and before `char` in writing order of `char` + // Examples (upper-case letters are RTL, lower-case are LTR): + // Pos(0, 1, ...) + // before after + // ab a|b a|b + // aB a|B aB| + // Ab |Ab A|b + // AB B|A B|A + // Every position after the last character on a line is considered to stick + // to the last character on the line. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); } + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) { m.left = m.right; } else { m.right = m.left; } + return intoCoordSystem(cm, lineObj, m, context) + } + var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky; + if (ch >= lineObj.text.length) { + ch = lineObj.text.length; + sticky = "before"; + } else if (ch <= 0) { + ch = 0; + sticky = "after"; + } + if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") } + + function getBidi(ch, partPos, invert) { + var part = order[partPos], right = part.level == 1; + return get(invert ? ch - 1 : ch, right != invert) + } + var partPos = getBidiPartAt(order, ch, sticky); + var other = bidiOther; + var val = getBidi(ch, partPos, sticky == "before"); + if (other != null) { val.other = getBidi(ch, other, sticky != "before"); } + return val + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0; + pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; } + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return {left: left, right: left, top: top, bottom: top + lineObj.height} + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, sticky, outside, xRel) { + var pos = Pos(line, ch, sticky); + pos.xRel = xRel; + if (outside) { pos.outside = outside; } + return pos + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) { return PosWithInfo(doc.first, 0, null, -1, -1) } + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, 1, 1) } + if (x < 0) { x = 0; } + + var lineObj = getLine(doc, lineN); + for (;;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 || found.outside > 0 ? 1 : 0)); + if (!collapsed) { return found } + var rangeEnd = collapsed.find(1); + if (rangeEnd.line == lineN) { return rangeEnd } + lineObj = getLine(doc, lineN = rangeEnd.line); + } + } + + function wrappedLineExtent(cm, lineObj, preparedMeasure, y) { + y -= widgetTopHeight(lineObj); + var end = lineObj.text.length; + var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0); + end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end); + return {begin: begin, end: end} + } + + function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) { + if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); } + var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top; + return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop) + } + + // Returns true if the given side of a box is after the given + // coordinates, in top-to-bottom, left-to-right order. + function boxIsAfter(box, x, y, left) { + return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x + } + + function coordsCharInner(cm, lineObj, lineNo$$1, x, y) { + // Move y into line-local coordinate space + y -= heightAtLine(lineObj); + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + // When directly calling `measureCharPrepared`, we have to adjust + // for the widgets at this line. + var widgetHeight$$1 = widgetTopHeight(lineObj); + var begin = 0, end = lineObj.text.length, ltr = true; + + var order = getOrder(lineObj, cm.doc.direction); + // If the line isn't plain left-to-right text, first figure out + // which bidi section the coordinates fall into. + if (order) { + var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart) + (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y); + ltr = part.level != 1; + // The awkward -1 offsets are needed because findFirst (called + // on these below) will treat its first bound as inclusive, + // second as exclusive, but we want to actually address the + // characters in the part's range + begin = ltr ? part.from : part.to - 1; + end = ltr ? part.to : part.from - 1; + } + + // A binary search to find the first character whose bounding box + // starts after the coordinates. If we run across any whose box wrap + // the coordinates, store that. + var chAround = null, boxAround = null; + var ch = findFirst(function (ch) { + var box = measureCharPrepared(cm, preparedMeasure, ch); + box.top += widgetHeight$$1; box.bottom += widgetHeight$$1; + if (!boxIsAfter(box, x, y, false)) { return false } + if (box.top <= y && box.left <= x) { + chAround = ch; + boxAround = box; + } + return true + }, begin, end); + + var baseX, sticky, outside = false; + // If a box around the coordinates was found, use that + if (boxAround) { + // Distinguish coordinates nearer to the left or right side of the box + var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr; + ch = chAround + (atStart ? 0 : 1); + sticky = atStart ? "after" : "before"; + baseX = atLeft ? boxAround.left : boxAround.right; + } else { + // (Adjust for extended bound, if necessary.) + if (!ltr && (ch == end || ch == begin)) { ch++; } + // To determine which side to associate with, get the box to the + // left of the character and compare it's vertical position to the + // coordinates + sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" : + (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ? + "after" : "before"; + // Now get accurate coordinates for this place, in order to get a + // base X position + var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure); + baseX = coords.left; + outside = y < coords.top ? -1 : y >= coords.bottom ? 1 : 0; + } + + ch = skipExtendingChars(lineObj.text, ch, 1); + return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX) + } + + function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) { + // Bidi parts are sorted left-to-right, and in a non-line-wrapping + // situation, we can take this ordering to correspond to the visual + // ordering. This finds the first part whose end is after the given + // coordinates. + var index = findFirst(function (i) { + var part = order[i], ltr = part.level != 1; + return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"), + "line", lineObj, preparedMeasure), x, y, true) + }, 0, order.length - 1); + var part = order[index]; + // If this isn't the first part, the part's start is also after + // the coordinates, and the coordinates aren't on the same line as + // that start, move one part back. + if (index > 0) { + var ltr = part.level != 1; + var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"), + "line", lineObj, preparedMeasure); + if (boxIsAfter(start, x, y, true) && start.top > y) + { part = order[index - 1]; } + } + return part + } + + function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) { + // In a wrapped line, rtl text on wrapping boundaries can do things + // that don't correspond to the ordering in our `order` array at + // all, so a binary search doesn't work, and we want to return a + // part that only spans one line so that the binary search in + // coordsCharInner is safe. As such, we first find the extent of the + // wrapped line, and then do a flat search in which we discard any + // spans that aren't on the line. + var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y); + var begin = ref.begin; + var end = ref.end; + if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; } + var part = null, closestDist = null; + for (var i = 0; i < order.length; i++) { + var p = order[i]; + if (p.from >= end || p.to <= begin) { continue } + var ltr = p.level != 1; + var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right; + // Weigh against spans ending before this, so that they are only + // picked if nothing ends after + var dist = endX < x ? x - endX + 1e9 : endX - x; + if (!part || closestDist > dist) { + part = p; + closestDist = dist; + } + } + if (!part) { part = order[order.length - 1]; } + // Clip the part to the wrapped line. + if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; } + if (part.to > end) { part = {from: part.from, to: end, level: part.level}; } + return part + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) { return display.cachedTextHeight } + if (measureText == null) { + measureText = elt("pre", null, "CodeMirror-line-like"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) { display.cachedTextHeight = height; } + removeChildren(display.measure); + return height || 1 + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) { return display.cachedCharWidth } + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor], "CodeMirror-line-like"); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) { display.cachedCharWidth = width; } + return width || 10 + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + var gutterLeft = d.gutters.clientLeft; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + var id = cm.display.gutterSpecs[i].className; + left[id] = n.offsetLeft + n.clientLeft + gutterLeft; + width[id] = n.clientWidth; + } + return {fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth} + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function (line) { + if (lineIsHidden(cm.doc, line)) { return 0 } + + var widgetsHeight = 0; + if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; } + } } + + if (wrapping) + { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th } + else + { return widgetsHeight + th } + } + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function (line) { + var estHeight = est(line); + if (estHeight != line.height) { updateLineHeight(line, estHeight); } + }); + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null } + + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel > 0 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) { return null } + n -= cm.display.viewFrom; + if (n < 0) { return null } + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) { return i } + } + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) { from = cm.doc.first; } + if (to == null) { to = cm.doc.first + cm.doc.size; } + if (!lendiff) { lendiff = 0; } + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + { display.updateLineNumbers = from; } + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + { resetView(cm); } + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut$1 = viewCuttingPoint(cm, from, from, -1); + if (cut$1) { + display.view = display.view.slice(0, cut$1.index); + display.viewTo = cut$1.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + { ext.lineN += lendiff; } + else if (from < ext.lineN + ext.size) + { display.externalMeasured = null; } + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + { display.externalMeasured = null; } + + if (line < display.viewFrom || line >= display.viewTo) { return } + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) { return } + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) { arr.push(type); } + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + { return {index: index, lineN: newN} } + var n = cm.display.viewFrom; + for (var i = 0; i < index; i++) + { n += view[i].size; } + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) { return null } + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) { return null } + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return {index: index, lineN: newN} + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); } + else if (display.viewFrom < from) + { display.view = display.view.slice(findViewIndex(cm, from)); } + display.viewFrom = from; + if (display.viewTo < to) + { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); } + else if (display.viewTo > to) + { display.view = display.view.slice(0, findViewIndex(cm, to)); } + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; } + } + return dirty + } + + function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()); + } + + function prepareSelection(cm, primary) { + if ( primary === void 0 ) primary = true; + + var doc = cm.doc, result = {}; + var curFragment = result.cursors = document.createDocumentFragment(); + var selFragment = result.selection = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (!primary && i == doc.sel.primIndex) { continue } + var range$$1 = doc.sel.ranges[i]; + if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue } + var collapsed = range$$1.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + { drawSelectionCursor(cm, range$$1.head, curFragment); } + if (!collapsed) + { drawSelectionRange(cm, range$$1, selFragment); } + } + return result + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, head, output) { + var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + cursor.style.left = pos.left + "px"; + cursor.style.top = pos.top + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left + "px"; + otherCursor.style.top = pos.other.top + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + } + } + + function cmpCoords(a, b) { return a.top - b.top || a.left - b.left } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range$$1, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left; + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + var docLTR = doc.direction == "ltr"; + + function add(left, top, width, bottom) { + if (top < 0) { top = 0; } + top = Math.round(top); + bottom = Math.round(bottom); + fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px"))); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias) + } + + function wrapX(pos, dir, side) { + var extent = wrappedLineExtentChar(cm, lineObj, null, pos); + var prop = (dir == "ltr") == (side == "after") ? "left" : "right"; + var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1); + return coords(ch, prop)[prop] + } + + var order = getOrder(lineObj, doc.direction); + iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) { + var ltr = dir == "ltr"; + var fromPos = coords(from, ltr ? "left" : "right"); + var toPos = coords(to - 1, ltr ? "right" : "left"); + + var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen; + var first = i == 0, last = !order || i == order.length - 1; + if (toPos.top - fromPos.top <= 3) { // Single line + var openLeft = (docLTR ? openStart : openEnd) && first; + var openRight = (docLTR ? openEnd : openStart) && last; + var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left; + var right = openRight ? rightSide : (ltr ? toPos : fromPos).right; + add(left, fromPos.top, right - left, fromPos.bottom); + } else { // Multiple lines + var topLeft, topRight, botLeft, botRight; + if (ltr) { + topLeft = docLTR && openStart && first ? leftSide : fromPos.left; + topRight = docLTR ? rightSide : wrapX(from, dir, "before"); + botLeft = docLTR ? leftSide : wrapX(to, dir, "after"); + botRight = docLTR && openEnd && last ? rightSide : toPos.right; + } else { + topLeft = !docLTR ? leftSide : wrapX(from, dir, "before"); + topRight = !docLTR && openStart && first ? rightSide : fromPos.right; + botLeft = !docLTR && openEnd && last ? leftSide : toPos.left; + botRight = !docLTR ? rightSide : wrapX(to, dir, "after"); + } + add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom); + if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); } + add(botLeft, toPos.top, botRight - botLeft, toPos.bottom); + } + + if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; } + if (cmpCoords(toPos, start) < 0) { start = toPos; } + if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; } + if (cmpCoords(toPos, end) < 0) { end = toPos; } + }); + return {start: start, end: end} + } + + var sFrom = range$$1.from(), sTo = range$$1.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + { add(leftSide, leftEnd.bottom, null, rightStart.top); } + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) { return } + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, + cm.options.cursorBlinkRate); } + else if (cm.options.cursorBlinkRate < 0) + { display.cursorDiv.style.visibility = "hidden"; } + } + + function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + } + + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function () { if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } }, 100); + } + + function onFocus(cm, e) { + if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; } + + if (cm.options.readOnly == "nocursor") { return } + if (!cm.state.focused) { + signal(cm, "focus", cm, e); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset(); + if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730 + } + cm.display.input.receivedFocus(); + } + restartBlink(cm); + } + function onBlur(cm, e) { + if (cm.state.delayingBlurEvent) { return } + + if (cm.state.focused) { + signal(cm, "blur", cm, e); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150); + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], wrapping = cm.options.lineWrapping; + var height = (void 0), width = 0; + if (cur.hidden) { continue } + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + // Check that lines don't extend past the right of the current + // editor width + if (!wrapping && cur.text.firstChild) + { width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; } + } + var diff = cur.line.height - height; + if (diff > .005 || diff < -.005) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) { for (var j = 0; j < cur.rest.length; j++) + { updateWidgetHeight(cur.rest[j]); } } + } + if (width > cm.display.sizerWidth) { + var chWidth = Math.ceil(width / charWidth(cm.display)); + if (chWidth > cm.display.maxLineLength) { + cm.display.maxLineLength = chWidth; + cm.display.maxLine = cur.line; + cm.display.maxLineChanged = true; + } + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) { + var w = line.widgets[i], parent = w.node.parentNode; + if (parent) { w.height = parent.offsetHeight; } + } } + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewport may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + if (ensureFrom < from) { + from = ensureFrom; + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); + to = ensureTo; + } + } + return {from: from, to: Math.max(to, from + 1)} + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, rect) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) { return } + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (rect.top + box.top < 0) { doScroll = true; } + else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; } + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;")); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) { margin = 0; } + var rect; + if (!cm.options.lineWrapping && pos == end) { + // Set pos and end to the cursor positions around the character pos sticks to + // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch + // If pos == Pos(_, 0, "before"), pos and end are unchanged + pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos; + end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos; + } + for (var limit = 0; limit < 5; limit++) { + var changed = false; + var coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + rect = {left: Math.min(coords.left, endCoords.left), + top: Math.min(coords.top, endCoords.top) - margin, + right: Math.max(coords.left, endCoords.left), + bottom: Math.max(coords.bottom, endCoords.bottom) + margin}; + var scrollPos = calculateScrollPos(cm, rect); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + updateScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; } + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; } + } + if (!changed) { break } + } + return rect + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, rect) { + var scrollPos = calculateScrollPos(cm, rect); + if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); } + if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); } + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, rect) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (rect.top < 0) { rect.top = 0; } + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = displayHeight(cm), result = {}; + if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; } + var docBottom = cm.doc.height + paddingVert(display); + var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin; + if (rect.top < screentop) { + result.scrollTop = atTop ? 0 : rect.top; + } else if (rect.bottom > screentop + screen) { + var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen); + if (newTop != screentop) { result.scrollTop = newTop; } + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var tooWide = rect.right - rect.left > screenw; + if (tooWide) { rect.right = rect.left + screenw; } + if (rect.left < 10) + { result.scrollLeft = 0; } + else if (rect.left < screenleft) + { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); } + else if (rect.right > screenw + screenleft - 3) + { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; } + return result + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollTop(cm, top) { + if (top == null) { return } + resolveScrollToPos(cm); + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(); + cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin}; + } + + function scrollToCoords(cm, x, y) { + if (x != null || y != null) { resolveScrollToPos(cm); } + if (x != null) { cm.curOp.scrollLeft = x; } + if (y != null) { cm.curOp.scrollTop = y; } + } + + function scrollToRange(cm, range$$1) { + resolveScrollToPos(cm); + cm.curOp.scrollToPos = range$$1; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range$$1 = cm.curOp.scrollToPos; + if (range$$1) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to); + scrollToCoordsRange(cm, from, to, range$$1.margin); + } + } + + function scrollToCoordsRange(cm, from, to, margin) { + var sPos = calculateScrollPos(cm, { + left: Math.min(from.left, to.left), + top: Math.min(from.top, to.top) - margin, + right: Math.max(from.right, to.right), + bottom: Math.max(from.bottom, to.bottom) + margin + }); + scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop); + } + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function updateScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) { return } + if (!gecko) { updateDisplaySimple(cm, {top: val}); } + setScrollTop(cm, val, true); + if (gecko) { updateDisplaySimple(cm); } + startWorker(cm, 100); + } + + function setScrollTop(cm, val, forceScroll) { + val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val); + if (cm.display.scroller.scrollTop == val && !forceScroll) { return } + cm.doc.scrollTop = val; + cm.display.scrollbars.setScrollTop(val); + if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; } + } + + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller, forceScroll) { + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return } + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; } + cm.display.scrollbars.setScrollLeft(val); + } + + // SCROLLBARS + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth; + var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + } + } + + var NativeScrollbars = function(place, scroll, cm) { + this.cm = cm; + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + vert.tabIndex = horiz.tabIndex = -1; + place(vert); place(horiz); + + on(vert, "scroll", function () { + if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); } + }); + on(horiz, "scroll", function () { + if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); } + }); + + this.checkedZeroWidth = false; + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; } + }; + + NativeScrollbars.prototype.update = function (measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + var sWidth = measure.nativeBarWidth; + + if (needsV) { + this.vert.style.display = "block"; + this.vert.style.bottom = needsH ? sWidth + "px" : "0"; + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + } else { + this.vert.style.display = ""; + this.vert.firstChild.style.height = "0"; + } + + if (needsH) { + this.horiz.style.display = "block"; + this.horiz.style.right = needsV ? sWidth + "px" : "0"; + this.horiz.style.left = measure.barLeft + "px"; + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.firstChild.style.width = + Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + } else { + this.horiz.style.display = ""; + this.horiz.firstChild.style.width = "0"; + } + + if (!this.checkedZeroWidth && measure.clientHeight > 0) { + if (sWidth == 0) { this.zeroWidthHack(); } + this.checkedZeroWidth = true; + } + + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} + }; + + NativeScrollbars.prototype.setScrollLeft = function (pos) { + if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; } + if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); } + }; + + NativeScrollbars.prototype.setScrollTop = function (pos) { + if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; } + if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); } + }; + + NativeScrollbars.prototype.zeroWidthHack = function () { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + this.horiz.style.height = this.vert.style.width = w; + this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; + this.disableHoriz = new Delayed; + this.disableVert = new Delayed; + }; + + NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) { + bar.style.pointerEvents = "auto"; + function maybeDisable() { + // To find out whether the scrollbar is still visible, we + // check whether the element under the pixel in the bottom + // right corner of the scrollbar box is the scrollbar box + // itself (when the bar is still visible) or its filler child + // (when the bar is hidden). If it is still visible, we keep + // it enabled, if it's hidden, we disable pointer events. + var box = bar.getBoundingClientRect(); + var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2) + : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1); + if (elt$$1 != bar) { bar.style.pointerEvents = "none"; } + else { delay.set(1000, maybeDisable); } + } + delay.set(1000, maybeDisable); + }; + + NativeScrollbars.prototype.clear = function () { + var parent = this.horiz.parentNode; + parent.removeChild(this.horiz); + parent.removeChild(this.vert); + }; + + var NullScrollbars = function () {}; + + NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} }; + NullScrollbars.prototype.setScrollLeft = function () {}; + NullScrollbars.prototype.setScrollTop = function () {}; + NullScrollbars.prototype.clear = function () {}; + + function updateScrollbars(cm, measure) { + if (!measure) { measure = measureForScrollbars(cm); } + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; + updateScrollbarsInner(cm, measure); + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + { updateHeightsInViewport(cm); } + updateScrollbarsInner(cm, measureForScrollbars(cm)); + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + } + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbarsInner(cm, measure) { + var d = cm.display; + var sizes = d.scrollbars.update(measure); + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"; + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = sizes.bottom + "px"; + d.scrollbarFiller.style.width = sizes.right + "px"; + } else { d.scrollbarFiller.style.display = ""; } + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sizes.bottom + "px"; + d.gutterFiller.style.width = measure.gutterWidth + "px"; + } else { d.gutterFiller.style.display = ""; } + } + + var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; + + function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear(); + if (cm.display.scrollbars.addClass) + { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); } + } + + cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function () { + if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); } + }); + node.setAttribute("cm-not-content", "true"); + }, function (pos, axis) { + if (axis == "horizontal") { setScrollLeft(cm, pos); } + else { updateScrollTop(cm, pos); } + }, cm); + if (cm.display.scrollbars.addClass) + { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); } + } + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: 0, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + }; + pushOperation(cm.curOp); + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp; + if (op) { finishOperation(op, function (group) { + for (var i = 0; i < group.ops.length; i++) + { group.ops[i].cm.curOp = null; } + endOperations(group); + }); } + } + + // The DOM updates done when an operation finishes are batched so + // that the minimum number of relayouts are required. + function endOperations(group) { + var ops = group.ops; + for (var i = 0; i < ops.length; i++) // Read DOM + { endOperation_R1(ops[i]); } + for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe) + { endOperation_W1(ops[i$1]); } + for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM + { endOperation_R2(ops[i$2]); } + for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe) + { endOperation_W2(ops[i$3]); } + for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM + { endOperation_finish(ops[i$4]); } + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; + maybeClipScrollbars(cm); + if (op.updateMaxLine) { findMaxLine(cm); } + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping; + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + } + + function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) { updateHeightsInViewport(cm); } + + op.barMeasure = measureForScrollbars(cm); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; + cm.display.sizerWidth = op.adjustWidthTo; + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + } + + if (op.updatedDisplay || op.selectionChanged) + { op.preparedSelection = display.input.prepareSelection(); } + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + if (op.maxScrollLeft < cm.doc.scrollLeft) + { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); } + cm.display.maxLineChanged = false; + } + + var takeFocus = op.focus && op.focus == activeElt(); + if (op.preparedSelection) + { cm.display.input.showSelection(op.preparedSelection, takeFocus); } + if (op.updatedDisplay || op.startHeight != cm.doc.height) + { updateScrollbars(cm, op.barMeasure); } + if (op.updatedDisplay) + { setDocumentHeight(cm, op.barMeasure); } + + if (op.selectionChanged) { restartBlink(cm); } + + if (cm.state.focused && op.updateInput) + { cm.display.input.reset(op.typing); } + if (takeFocus) { ensureFocus(op.cm); } + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; + + if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); } + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + { display.wheelStartX = display.wheelStartY = null; } + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); } + + if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); + maybeScrollWindow(cm, rect); + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) { for (var i = 0; i < hidden.length; ++i) + { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } } + if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1) + { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } } + + if (display.wrapper.offsetHeight) + { doc.scrollTop = cm.display.scroller.scrollTop; } + + // Fire change events, and delayed event handlers + if (op.changeObjs) + { signal(cm, "changes", cm, op.changeObjs); } + if (op.update) + { op.update.finish(); } + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) { return f() } + startOperation(cm); + try { return f() } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function() { + if (cm.curOp) { return f.apply(cm, arguments) } + startOperation(cm); + try { return f.apply(cm, arguments) } + finally { endOperation(cm); } + } + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function() { + if (this.curOp) { return f.apply(this, arguments) } + startOperation(this); + try { return f.apply(this, arguments) } + finally { endOperation(this); } + } + } + function docMethodOp(f) { + return function() { + var cm = this.cm; + if (!cm || cm.curOp) { return f.apply(this, arguments) } + startOperation(cm); + try { return f.apply(this, arguments) } + finally { endOperation(cm); } + } + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.highlightFrontier < cm.display.viewTo) + { cm.state.highlight.set(time, bind(highlightWorker, cm)); } + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.highlightFrontier >= cm.display.viewTo) { return } + var end = +new Date + cm.options.workTime; + var context = getContextBefore(cm, doc.highlightFrontier); + var changedLines = []; + + doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { + if (context.line >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles; + var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null; + var highlighted = highlightLine(cm, line, context, true); + if (resetState) { context.state = resetState; } + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) { line.styleClasses = newCls; } + else if (oldCls) { line.styleClasses = null; } + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; } + if (ischange) { changedLines.push(context.line); } + line.stateAfter = context.save(); + context.nextLine(); + } else { + if (line.text.length <= cm.options.maxHighlightLength) + { processLine(cm, line.text, context); } + line.stateAfter = context.line % 5 == 0 ? context.save() : null; + context.nextLine(); + } + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true + } + }); + doc.highlightFrontier = context.line; + doc.modeFrontier = Math.max(doc.modeFrontier, context.line); + if (changedLines.length) { runInOp(cm, function () { + for (var i = 0; i < changedLines.length; i++) + { regLineChange(cm, changedLines[i], "text"); } + }); } + } + + // DISPLAY DRAWING + + var DisplayUpdate = function(cm, viewport, force) { + var display = cm.display; + + this.viewport = viewport; + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport); + this.editorIsHidden = !display.wrapper.offsetWidth; + this.wrapperHeight = display.wrapper.clientHeight; + this.wrapperWidth = display.wrapper.clientWidth; + this.oldDisplayWidth = displayWidth(cm); + this.force = force; + this.dims = getDimensions(cm); + this.events = []; + }; + + DisplayUpdate.prototype.signal = function (emitter, type) { + if (hasHandler(emitter, type)) + { this.events.push(arguments); } + }; + DisplayUpdate.prototype.finish = function () { + var this$1 = this; + + for (var i = 0; i < this.events.length; i++) + { signal.apply(null, this$1.events[i]); } + }; + + function maybeClipScrollbars(cm) { + var display = cm.display; + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; + display.heightForcer.style.height = scrollGap(cm) + "px"; + display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; + display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; + display.scrollbarsClipped = true; + } + } + + function selectionSnapshot(cm) { + if (cm.hasFocus()) { return null } + var active = activeElt(); + if (!active || !contains(cm.display.lineDiv, active)) { return null } + var result = {activeElt: active}; + if (window.getSelection) { + var sel = window.getSelection(); + if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) { + result.anchorNode = sel.anchorNode; + result.anchorOffset = sel.anchorOffset; + result.focusNode = sel.focusNode; + result.focusOffset = sel.focusOffset; + } + } + return result + } + + function restoreSelection(snapshot) { + if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return } + snapshot.activeElt.focus(); + if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { + var sel = window.getSelection(), range$$1 = document.createRange(); + range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset); + range$$1.collapse(false); + sel.removeAllRanges(); + sel.addRange(range$$1); + sel.extend(snapshot.focusNode, snapshot.focusOffset); + } + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc; + + if (update.editorIsHidden) { + resetView(cm); + return false + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + { return false } + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm); + update.dims = getDimensions(cm); + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, update.visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); } + if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); } + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + { return false } + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var selSnapshot = selectionSnapshot(cm); + if (toUpdate > 4) { display.lineDiv.style.display = "none"; } + patchDisplay(cm, display.updateLineNumbers, update.dims); + if (toUpdate > 4) { display.lineDiv.style.display = ""; } + display.renderedView = display.view; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + restoreSelection(selSnapshot); + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + display.gutters.style.height = display.sizer.style.minHeight = 0; + + if (different) { + display.lastWrapHeight = update.wrapperHeight; + display.lastWrapWidth = update.wrapperWidth; + startWorker(cm, 400); + } + + display.updateLineNumbers = null; + + return true + } + + function postUpdateDisplay(cm, update) { + var viewport = update.viewport; + + for (var first = true;; first = false) { + if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; } + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + { break } + } + if (!updateDisplayIfNeeded(cm, update)) { break } + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + updateScrollbars(cm, barMeasure); + setDocumentHeight(cm, barMeasure); + update.force = false; + } + + update.signal(cm, "update", cm); + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + } + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm); + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + updateScrollbars(cm, barMeasure); + setDocumentHeight(cm, barMeasure); + update.finish(); + } + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + { node.style.display = "none"; } + else + { node.parentNode.removeChild(node); } + return next + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) { cur = rm(cur); } + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; } + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) { cur = rm(cur); } + } + + function updateGutterSpace(display) { + var width = display.gutters.offsetWidth; + display.sizer.style.marginLeft = width + "px"; + } + + function setDocumentHeight(cm, measure) { + cm.display.sizer.style.minHeight = measure.docHeight + "px"; + cm.display.heightForcer.style.top = measure.docHeight + "px"; + cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px"; + } + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return } + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) { if (!view[i].hidden) { + if (cm.options.fixedGutter) { + if (view[i].gutter) + { view[i].gutter.style.left = left; } + if (view[i].gutterBackground) + { view[i].gutterBackground.style.left = left; } + } + var align = view[i].alignable; + if (align) { for (var j = 0; j < align.length; j++) + { align[j].style.left = left; } } + } } + if (cm.options.fixedGutter) + { display.gutters.style.left = (comp + gutterW) + "px"; } + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) { return false } + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; + display.lineNumWidth = display.lineNumInnerWidth + padding; + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm.display); + return true + } + return false + } + + function getGutters(gutters, lineNumbers) { + var result = [], sawLineNumbers = false; + for (var i = 0; i < gutters.length; i++) { + var name = gutters[i], style = null; + if (typeof name != "string") { style = name.style; name = name.className; } + if (name == "CodeMirror-linenumbers") { + if (!lineNumbers) { continue } + else { sawLineNumbers = true; } + } + result.push({className: name, style: style}); + } + if (lineNumbers && !sawLineNumbers) { result.push({className: "CodeMirror-linenumbers", style: null}); } + return result + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function renderGutters(display) { + var gutters = display.gutters, specs = display.gutterSpecs; + removeChildren(gutters); + display.lineGutter = null; + for (var i = 0; i < specs.length; ++i) { + var ref = specs[i]; + var className = ref.className; + var style = ref.style; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + className)); + if (style) { gElt.style.cssText = style; } + if (className == "CodeMirror-linenumbers") { + display.lineGutter = gElt; + gElt.style.width = (display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = specs.length ? "" : "none"; + updateGutterSpace(display); + } + + function updateGutters(cm) { + renderGutters(cm.display); + regChange(cm); + alignHorizontally(cm); + } + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc, input, options) { + var d = this; + this.input = input; + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.scrollbarFiller.setAttribute("cm-not-content", "true"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + d.gutterFiller.setAttribute("cm-not-content", "true"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = eltP("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + var lines = eltP("div", [d.lineSpace], "CodeMirror-lines"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [lines], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + d.sizerWidth = null; + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; } + + if (place) { + if (place.appendChild) { place.appendChild(d.wrapper); } + else { place(d.wrapper); } + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + d.reportedViewFrom = d.reportedViewTo = doc.first; + // Information about the rendered lines. + d.view = []; + d.renderedView = null; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastWrapHeight = d.lastWrapWidth = 0; + d.updateLineNumbers = null; + + d.nativeBarWidth = d.barHeight = d.barWidth = 0; + d.scrollbarsClipped = false; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + + d.activeTouch = null; + + d.gutterSpecs = getGutters(options.gutters, options.lineNumbers); + renderGutters(d); + + input.init(d); + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) { wheelPixelsPerUnit = -.53; } + else if (gecko) { wheelPixelsPerUnit = 15; } + else if (chrome) { wheelPixelsPerUnit = -.7; } + else if (safari) { wheelPixelsPerUnit = -1/3; } + + function wheelEventDelta(e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; } + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; } + else if (dy == null) { dy = e.wheelDelta; } + return {x: dx, y: dy} + } + function wheelEventPixels(e) { + var delta = wheelEventDelta(e); + delta.x *= wheelPixelsPerUnit; + delta.y *= wheelPixelsPerUnit; + return delta + } + + function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + var canScrollX = scroll.scrollWidth > scroll.clientWidth; + var canScrollY = scroll.scrollHeight > scroll.clientHeight; + if (!(dx && canScrollX || dy && canScrollY)) { return } + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy && canScrollY) + { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); } + setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit)); + // Only prevent default scrolling if vertical scrolling is + // actually possible. Otherwise, it causes vertical scroll + // jitter on OSX trackpads when deltaX is small and deltaY + // is large (issue #3579) + if (!dy || (dy && canScrollY)) + { e_preventDefault(e); } + display.wheelStartX = null; // Abort measurement, if in progress + return + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) { top = Math.max(0, top + pixels - 50); } + else { bot = Math.min(cm.doc.height, bot + pixels + 50); } + updateDisplaySimple(cm, {top: top, bottom: bot}); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function () { + if (display.wheelStartX == null) { return } + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) { return } + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + var Selection = function(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + }; + + Selection.prototype.primary = function () { return this.ranges[this.primIndex] }; + + Selection.prototype.equals = function (other) { + var this$1 = this; + + if (other == this) { return true } + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false } + for (var i = 0; i < this.ranges.length; i++) { + var here = this$1.ranges[i], there = other.ranges[i]; + if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false } + } + return true + }; + + Selection.prototype.deepCopy = function () { + var this$1 = this; + + var out = []; + for (var i = 0; i < this.ranges.length; i++) + { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); } + return new Selection(out, this.primIndex) + }; + + Selection.prototype.somethingSelected = function () { + var this$1 = this; + + for (var i = 0; i < this.ranges.length; i++) + { if (!this$1.ranges[i].empty()) { return true } } + return false + }; + + Selection.prototype.contains = function (pos, end) { + var this$1 = this; + + if (!end) { end = pos; } + for (var i = 0; i < this.ranges.length; i++) { + var range = this$1.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + { return i } + } + return -1 + }; + + var Range = function(anchor, head) { + this.anchor = anchor; this.head = head; + }; + + Range.prototype.from = function () { return minPos(this.anchor, this.head) }; + Range.prototype.to = function () { return maxPos(this.anchor, this.head) }; + Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(cm, ranges, primIndex) { + var mayTouch = cm && cm.options.selectionsMayTouch; + var prim = ranges[primIndex]; + ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + var diff = cmp(prev.to(), cur.from()); + if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) { --primIndex; } + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex) + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0) + } + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + function changeEnd(change) { + if (!change.text) { return change.to } + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) + } + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) { return pos } + if (cmp(pos, change.to) <= 0) { return changeEnd(change) } + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; } + return Pos(line, ch) + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(doc.cm, out, doc.sel.primIndex) + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + { return Pos(nw.line, pos.ch - old.ch + nw.ch) } + else + { return Pos(nw.line + (pos.line - old.line), pos.ch) } + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex) + } + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function (line) { + if (line.stateAfter) { line.stateAfter = null; } + if (line.styles) { line.styles = null; } + }); + cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) { regChange(cm); } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore) + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight$$1) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight$$1); + signalLater(line, "change", line, change); + } + function linesFor(start, end) { + var result = []; + for (var i = start; i < end; ++i) + { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); } + return result + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)); + doc.remove(text.length, doc.size - text.length); + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1); + update(lastLine, lastLine.text, lastSpans); + if (nlines) { doc.remove(from.line, nlines); } + if (added.length) { doc.insert(from.line, added); } + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + var added$1 = linesFor(1, text.length - 1); + added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added$1); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + var added$2 = linesFor(1, text.length - 1); + if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); } + doc.insert(from.line + 1, added$2); + } + + signalLater(doc, "change", doc, change); + } + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) { continue } + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) { continue } + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) { throw new Error("This document is already in use.") } + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + setDirectionClass(cm); + if (!cm.options.lineWrapping) { findMaxLine(cm); } + cm.options.mode = doc.modeOption; + regChange(cm); + } + + function setDirectionClass(cm) { + (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl"); + } + + function directionChanged(cm) { + runInOp(cm, function () { + setDirectionClass(cm); + regChange(cm); + }); + } + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = this.lastSelOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true); + return histChange + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) { array.pop(); } + else { break } + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done) + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done) + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done) + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, or are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + var last; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + { pushSelectionToHistory(doc.sel, hist.done); } + cur = {changes: [historyChangeFromChange(doc, change)], + generation: hist.generation}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) { hist.done.shift(); } + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = hist.lastSelOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) { signal(doc, "historyAdded"); } + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500) + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + { hist.done[hist.done.length - 1] = sel; } + else + { pushSelectionToHistory(sel, hist.done); } + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastSelOp = opId; + if (options && options.clearRedo !== false) + { clearSelectionEvents(hist.undone); } + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + { dest.push(sel); } + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { + if (line.markedSpans) + { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; } + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) { return null } + var out; + for (var i = 0; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } } + else if (out) { out.push(spans[i]); } + } + return !out ? spans : out.length ? out : null + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) { return null } + var nw = []; + for (var i = 0; i < change.text.length; ++i) + { nw.push(removeClearedSpans(found[i])); } + return nw + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) { return stretched } + if (!stretched) { return old } + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + { if (oldCur[k].marker == span.marker) { continue spans } } + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + var copy = []; + for (var i = 0; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue + } + var changes = event.changes, newChanges = []; + copy.push({changes: newChanges}); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m = (void 0); + newChanges.push({from: change.from, to: change.to, text: change.text}); + if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } } } + } + } + return copy + } + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(range, head, other, extend) { + if (extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head) + } else { + return new Range(other || head, head) + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options, extend) { + if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); } + setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + var out = []; + var extend = doc.cm && (doc.cm.display.shift || doc.extend); + for (var i = 0; i < doc.sel.ranges.length; i++) + { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); } + var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel, options) { + var obj = { + ranges: sel.ranges, + update: function(ranges) { + var this$1 = this; + + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); } + }, + origin: options && options.origin + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); } + if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) } + else { return sel } + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + { sel = filterSelectionChange(doc, sel, options); } + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + { ensureCursorVisible(doc.cm); } + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) { return } + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = 1; + doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false)); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) { out = sel.ranges.slice(0, i); } + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel + } + + function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { + var line = getLine(doc, pos.line); + if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + + // Determine if we should prevent the cursor being placed to the left/right of an atomic marker + // Historically this was determined using the inclusiveLeft/Right option, but the new way to control it + // is with selectLeft/Right + var preventCursorLeft = ("selectLeft" in m) ? !m.selectLeft : m.inclusiveLeft; + var preventCursorRight = ("selectRight" in m) ? !m.selectRight : m.inclusiveRight; + + if ((sp.from == null || (preventCursorLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && + (sp.to == null || (preventCursorRight ? sp.to >= pos.ch : sp.to > pos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) { break } + else {--i; continue} + } + } + if (!m.atomic) { continue } + + if (oldPos) { + var near = m.find(dir < 0 ? 1 : -1), diff = (void 0); + if (dir < 0 ? preventCursorRight : preventCursorLeft) + { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); } + if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) + { return skipAtomicInner(doc, near, pos, dir, mayClear) } + } + + var far = m.find(dir < 0 ? -1 : 1); + if (dir < 0 ? preventCursorLeft : preventCursorRight) + { far = movePos(doc, far, dir, far.line == pos.line ? line : null); } + return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null + } + } } + return pos + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, oldPos, bias, mayClear) { + var dir = bias || 1; + var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || + skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); + if (!found) { + doc.cantEdit = true; + return Pos(doc.first, 0) + } + return found + } + + function movePos(doc, pos, dir, line) { + if (dir < 0 && pos.ch == 0) { + if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) } + else { return null } + } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { + if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) } + else { return null } + } else { + return new Pos(pos.line, pos.ch + dir) + } + } + + function selectAll(cm) { + cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll); + } + + // UPDATING + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function () { return obj.canceled = true; } + }; + if (update) { obj.update = function (from, to, text, origin) { + if (from) { obj.from = clipPos(doc, from); } + if (to) { obj.to = clipPos(doc, to); } + if (text) { obj.text = text; } + if (origin !== undefined) { obj.origin = origin; } + }; } + signal(doc, "beforeChange", doc, obj); + if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); } + + if (obj.canceled) { + if (doc.cm) { doc.cm.curOp.updateInput = 2; } + return null + } + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) } + if (doc.cm.state.suppressEdits) { return } + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) { return } + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); } + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return } + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + var suppress = doc.cm && doc.cm.state.suppressEdits; + if (suppress && !allowSelectionOnly) { return } + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + var i = 0; + for (; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + { break } + } + if (i == source.length) { return } + hist.lastOrigin = hist.lastSelOrigin = null; + + for (;;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, {clearRedo: false}); + return + } + selAfter = event; + } else if (suppress) { + source.push(event); + return + } else { break } + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({changes: antiChanges, generation: hist.generation}); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + var loop = function ( i ) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return {} + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); } + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + }; + + for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) { + var returned = loop( i$1 ); + + if ( returned ) return returned.v; + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) { return } + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range( + Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch) + ); }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + { regLineChange(doc.cm, l, "gutter"); } + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) } + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return + } + if (change.from.line > doc.lastLine()) { return } + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin}; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) { selAfter = computeSelAfterChange(doc, change); } + if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); } + else { updateDoc(doc, change, spans); } + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + + if (doc.cantEdit && skipAtomic(doc, Pos(doc.firstLine(), 0))) + { doc.cantEdit = false; } + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function (line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + { signalCursorActivity(cm); } + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function (line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; } + } + + retreatFrontier(doc, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (change.full) + { regChange(cm); } + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + { regLineChange(cm, from.line, "text"); } + else + { regChange(cm, from.line, to.line + 1, lendiff); } + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) { signalLater(cm, "change", cm, obj); } + if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); } + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + var assign; + + if (!to) { to = from; } + if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); } + if (typeof code == "string") { code = doc.splitLines(code); } + makeChange(doc, {from: from, to: to, text: code, origin: origin}); + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue + } + for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) { + var cur = sub.changes[j$1]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); } + else { no = lineNo(handle); } + if (no == null) { return null } + if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); } + return line + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + var this$1 = this; + + this.lines = lines; + this.parent = null; + var height = 0; + for (var i = 0; i < lines.length; ++i) { + lines[i].parent = this$1; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function() { return this.lines.length }, + + // Remove the n lines at offset 'at'. + removeInner: function(at, n) { + var this$1 = this; + + for (var i = at, e = at + n; i < e; ++i) { + var line = this$1.lines[i]; + this$1.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + + // Helper used to collapse a small branch into a single leaf. + collapse: function(lines) { + lines.push.apply(lines, this.lines); + }, + + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function(at, lines, height) { + var this$1 = this; + + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; } + }, + + // Used to iterate over a part of the tree. + iterN: function(at, n, op) { + var this$1 = this; + + for (var e = at + n; at < e; ++at) + { if (op(this$1.lines[at])) { return true } } + } + }; + + function BranchChunk(children) { + var this$1 = this; + + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this$1; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function() { return this.size }, + + removeInner: function(at, n) { + var this$1 = this; + + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this$1.height -= oldHeight - child.height; + if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) { break } + at = 0; + } else { at -= sz; } + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + + collapse: function(lines) { + var this$1 = this; + + for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); } + }, + + insertInner: function(at, lines, height) { + var this$1 = this; + + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. + // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. + var remaining = child.lines.length % 25 + 25; + for (var pos = remaining; pos < child.lines.length;) { + var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); + child.height -= leaf.height; + this$1.children.splice(++i, 0, leaf); + leaf.parent = this$1; + } + child.lines = child.lines.slice(0, remaining); + this$1.maybeSpill(); + } + break + } + at -= sz; + } + }, + + // When a node has grown, check whether it should be split. + maybeSpill: function() { + if (this.children.length <= 10) { return } + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10) + me.parent.maybeSpill(); + }, + + iterN: function(at, n, op) { + var this$1 = this; + + for (var i = 0; i < this.children.length; ++i) { + var child = this$1.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) { return true } + if ((n -= used) == 0) { break } + at = 0; + } else { at -= sz; } + } + } + }; + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = function(doc, node, options) { + var this$1 = this; + + if (options) { for (var opt in options) { if (options.hasOwnProperty(opt)) + { this$1[opt] = options[opt]; } } } + this.doc = doc; + this.node = node; + }; + + LineWidget.prototype.clear = function () { + var this$1 = this; + + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) { return } + for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } } + if (!ws.length) { line.widgets = null; } + var height = widgetHeight(this); + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) { + runInOp(cm, function () { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + }); + signalLater(cm, "lineWidgetCleared", cm, this, no); + } + }; + + LineWidget.prototype.changed = function () { + var this$1 = this; + + var oldH = this.height, cm = this.doc.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) { return } + if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); } + if (cm) { + runInOp(cm, function () { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line)); + }); + } + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + { addToScrollTop(cm, diff); } + } + + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) { cm.display.alignWidgets = true; } + changeLine(doc, handle, "widget", function (line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) { widgets.push(widget); } + else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); } + widget.line = line; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) { addToScrollTop(cm, widget.height); } + cm.curOp.forceUpdate = true; + } + return true + }); + if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); } + return widget + } + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + var TextMarker = function(doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + this.id = ++nextMarkerId; + }; + + // Clear the marker. + TextMarker.prototype.clear = function () { + var this$1 = this; + + if (this.explicitlyCleared) { return } + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) { startOperation(cm); } + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) { signalLater(this, "clear", found.from, found.to); } + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this$1.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this$1); + if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); } + else if (cm) { + if (span.to != null) { max = lineNo(line); } + if (span.from != null) { min = lineNo(line); } + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm) + { updateLineHeight(line, textHeight(cm.display)); } + } + if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) { + var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } } + + if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); } + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) { reCheckSelection(cm.doc); } + } + if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); } + if (withOp) { endOperation(cm); } + if (this.parent) { this.parent.clear(); } + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function (side, lineObj) { + var this$1 = this; + + if (side == null && this.type == "bookmark") { side = 1; } + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this$1.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this$1); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) { return from } + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) { return to } + } + } + return from && {from: from, to: to} + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function () { + var this$1 = this; + + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) { return } + runInOp(cm, function () { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + { updateLineHeight(line, line.height + dHeight); } + } + signalLater(cm, "markerChanged", cm, this$1); + }); + }; + + TextMarker.prototype.attachLine = function (line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); } + } + this.lines.push(line); + }; + + TextMarker.prototype.detachLine = function (line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp + ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + eventMixin(TextMarker); + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) { return markTextShared(doc, from, to, options, type) } + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) } + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) { copyObj(options, marker, false); } + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + { return marker } + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); } + if (options.insertLeft) { marker.widgetNode.insertLeft = true; } + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + { throw new Error("Inserting collapsed marker partially overlapping an existing one") } + seeCollapsedSpans(); + } + + if (marker.addToHistory) + { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); } + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function (line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + { updateMaxLine = true; } + if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); } + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) { + if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); } + }); } + + if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); } + + if (marker.readOnly) { + seeReadOnlySpans(); + if (doc.history.done.length || doc.history.undone.length) + { doc.clearHistory(); } + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) { cm.curOp.updateMaxLine = true; } + if (marker.collapsed) + { regChange(cm, from.line, to.line + 1); } + else if (marker.className || marker.startStyle || marker.endStyle || marker.css || + marker.attributes || marker.title) + { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } } + if (marker.atomic) { reCheckSelection(cm.doc); } + signalLater(cm, "markerAdded", cm, marker); + } + return marker + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = function(markers, primary) { + var this$1 = this; + + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + { markers[i].parent = this$1; } + }; + + SharedTextMarker.prototype.clear = function () { + var this$1 = this; + + if (this.explicitlyCleared) { return } + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + { this$1.markers[i].clear(); } + signalLater(this, "clear"); + }; + + SharedTextMarker.prototype.find = function (side, lineObj) { + return this.primary.find(side, lineObj) + }; + eventMixin(SharedTextMarker); + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function (doc) { + if (widget) { options.widgetNode = widget.cloneNode(true); } + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + { if (doc.linked[i].isParent) { return } } + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary) + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; }) + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + var loop = function ( i ) { + var marker = markers[i], linked = [marker.primary.doc]; + linkedDocs(marker.primary.doc, function (d) { return linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + }; + + for (var i = 0; i < markers.length; i++) loop( i ); + } + + var nextDocId = 0; + var Doc = function(text, mode, firstLine, lineSep, direction) { + if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) } + if (firstLine == null) { firstLine = 0; } + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.modeFrontier = this.highlightFrontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + this.lineSep = lineSep; + this.direction = (direction == "rtl") ? "rtl" : "ltr"; + this.extend = false; + + if (typeof text == "string") { text = this.splitLines(text); } + updateDoc(this, {from: start, to: start, text: text}); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function(from, to, op) { + if (op) { this.iterN(from - this.first, to - from, op); } + else { this.iterN(this.first, this.first + this.size, from); } + }, + + // Non-public interface for adding and removing lines. + insert: function(at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) { height += lines[i].height; } + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) { return lines } + return lines.join(lineSep || this.lineSeparator()) + }, + setValue: docMethodOp(function(code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), + text: this.splitLines(code), origin: "setValue", full: true}, true); + if (this.cm) { scrollToCoords(this.cm, 0, 0); } + setSelection(this, simpleSelection(top), sel_dontScroll); + }), + replaceRange: function(code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) { return lines } + return lines.join(lineSep || this.lineSeparator()) + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, + + getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }}, + getLineNumber: function(line) {return lineNo(line)}, + + getLineHandleVisualStart: function(line) { + if (typeof line == "number") { line = getLine(this, line); } + return visualLine(line) + }, + + lineCount: function() {return this.size}, + firstLine: function() {return this.first}, + lastLine: function() {return this.first + this.size - 1}, + + clipPos: function(pos) {return clipPos(this, pos)}, + + getCursor: function(start) { + var range$$1 = this.sel.primary(), pos; + if (start == null || start == "head") { pos = range$$1.head; } + else if (start == "anchor") { pos = range$$1.anchor; } + else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); } + else { pos = range$$1.from(); } + return pos + }, + listSelections: function() { return this.sel.ranges }, + somethingSelected: function() {return this.sel.somethingSelected()}, + + setCursor: docMethodOp(function(line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function(anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function(head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function(heads, options) { + extendSelections(this, clipPosArray(this, heads), options); + }), + extendSelectionsBy: docMethodOp(function(f, options) { + var heads = map(this.sel.ranges, f); + extendSelections(this, clipPosArray(this, heads), options); + }), + setSelections: docMethodOp(function(ranges, primary, options) { + var this$1 = this; + + if (!ranges.length) { return } + var out = []; + for (var i = 0; i < ranges.length; i++) + { out[i] = new Range(clipPos(this$1, ranges[i].anchor), + clipPos(this$1, ranges[i].head)); } + if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); } + setSelection(this, normalizeSelection(this.cm, out, primary), options); + }), + addSelection: docMethodOp(function(anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options); + }), + + getSelection: function(lineSep) { + var this$1 = this; + + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) { return lines } + else { return lines.join(lineSep || this.lineSeparator()) } + }, + getSelections: function(lineSep) { + var this$1 = this; + + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this$1, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); } + parts[i] = sel; + } + return parts + }, + replaceSelection: function(code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + { dup[i] = code; } + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function(code, collapse, origin) { + var this$1 = this; + + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range$$1 = sel.ranges[i]; + changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin}; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i$1 = changes.length - 1; i$1 >= 0; i$1--) + { makeChange(this$1, changes[i$1]); } + if (newSel) { setSelectionReplaceHistory(this, newSel); } + else if (this.cm) { ensureCursorVisible(this.cm); } + }), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + + setExtending: function(val) {this.extend = val;}, + getExtending: function() {return this.extend}, + + historySize: function() { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } } + for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } } + return {undo: done, redo: undone} + }, + clearHistory: function() { + var this$1 = this; + + this.history = new History(this.history.maxGeneration); + linkedDocs(this, function (doc) { return doc.history = this$1.history; }, true); + }, + + markClean: function() { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function(forceSplit) { + if (forceSplit) + { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; } + return this.history.generation + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration) + }, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)} + }, + setHistory: function(histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + setGutterMarker: docMethodOp(function(line, gutterID, value) { + return changeLine(this, line, "gutter", function (line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) { line.gutterMarkers = null; } + return true + }) + }), + + clearGutter: docMethodOp(function(gutterID) { + var this$1 = this; + + this.iter(function (line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + changeLine(this$1, line, "gutter", function () { + line.gutterMarkers[gutterID] = null; + if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; } + return true + }); + } + }); + }), + + lineInfo: function(line) { + var n; + if (typeof line == "number") { + if (!isLine(this, line)) { return null } + n = line; + line = getLine(this, line); + if (!line) { return null } + } else { + n = lineNo(line); + if (n == null) { return null } + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets} + }, + + addLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + if (!line[prop]) { line[prop] = cls; } + else if (classTest(cls).test(line[prop])) { return false } + else { line[prop] += " " + cls; } + return true + }) + }), + removeLineClass: docMethodOp(function(handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) { return false } + else if (cls == null) { line[prop] = null; } + else { + var found = cur.match(classTest(cls)); + if (!found) { return false } + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true + }) + }), + + addLineWidget: docMethodOp(function(handle, node, options) { + return addLineWidget(this, handle, node, options) + }), + removeLineWidget: function(widget) { widget.clear(); }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") + }, + setBookmark: function(pos, options) { + var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents}; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark") + }, + findMarksAt: function(pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) { for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + { markers.push(span.marker.parent || span.marker); } + } } + return markers + }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo$$1 = from.line; + this.iter(from.line, to.line + 1, function (line) { + var spans = line.markedSpans; + if (spans) { for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to || + span.from == null && lineNo$$1 != from.line || + span.from != null && lineNo$$1 == to.line && span.from >= to.ch) && + (!filter || filter(span.marker))) + { found.push(span.marker.parent || span.marker); } + } } + ++lineNo$$1; + }); + return found + }, + getAllMarks: function() { + var markers = []; + this.iter(function (line) { + var sps = line.markedSpans; + if (sps) { for (var i = 0; i < sps.length; ++i) + { if (sps[i].from != null) { markers.push(sps[i].marker); } } } + }); + return markers + }, + + posFromIndex: function(off) { + var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length; + this.iter(function (line) { + var sz = line.text.length + sepSize; + if (sz > off) { ch = off; return true } + off -= sz; + ++lineNo$$1; + }); + return clipPos(this, Pos(lineNo$$1, ch)) + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) { return 0 } + var sepSize = this.lineSeparator().length; + this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value + index += line.text.length + sepSize; + }); + return index + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), + this.modeOption, this.first, this.lineSep, this.direction); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc + }, + + linkedDoc: function(options) { + if (!options) { options = {}; } + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) { from = options.from; } + if (options.to != null && options.to < to) { to = options.to; } + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction); + if (options.sharedHist) { copy.history = this.history + ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy + }, + unlinkDoc: function(other) { + var this$1 = this; + + if (other instanceof CodeMirror) { other = other.doc; } + if (this.linked) { for (var i = 0; i < this.linked.length; ++i) { + var link = this$1.linked[i]; + if (link.doc != other) { continue } + this$1.linked.splice(i, 1); + other.unlinkDoc(this$1); + detachSharedMarkers(findSharedMarkers(this$1)); + break + } } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getMode: function() {return this.mode}, + getEditor: function() {return this.cm}, + + splitLines: function(str) { + if (this.lineSep) { return str.split(this.lineSep) } + return splitLinesAuto(str) + }, + lineSeparator: function() { return this.lineSep || "\n" }, + + setDirection: docMethodOp(function (dir) { + if (dir != "rtl") { dir = "ltr"; } + if (dir == this.direction) { return } + this.direction = dir; + this.iter(function (line) { return line.order = null; }); + if (this.cm) { directionChanged(this.cm); } + }) + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + clearDragCursor(cm); + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + { return } + e_preventDefault(e); + if (ie) { lastDrop = +new Date; } + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || cm.isReadOnly()) { return } + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var markAsReadAndPasteIfAllFilesAreRead = function () { + if (++read == n) { + operation(cm, function () { + pos = clipPos(cm.doc, pos); + var change = {from: pos, to: pos, + text: cm.doc.splitLines( + text.filter(function (t) { return t != null; }).join(cm.doc.lineSeparator())), + origin: "paste"}; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + })(); + } + }; + var readTextFromFile = function (file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) { + markAsReadAndPasteIfAllFilesAreRead(); + return + } + var reader = new FileReader; + reader.onerror = function () { return markAsReadAndPasteIfAllFilesAreRead(); }; + reader.onload = function () { + var content = reader.result; + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { + markAsReadAndPasteIfAllFilesAreRead(); + return + } + text[i] = content; + markAsReadAndPasteIfAllFilesAreRead(); + }; + reader.readAsText(file); + }; + for (var i = 0; i < files.length; i++) { readTextFromFile(files[i], i); } + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(function () { return cm.display.input.focus(); }, 20); + return + } + try { + var text$1 = e.dataTransfer.getData("Text"); + if (text$1) { + var selected; + if (cm.state.draggingText && !cm.state.draggingText.copy) + { selected = cm.listSelections(); } + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1) + { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } } + cm.replaceSelection(text$1, "around", "paste"); + cm.display.input.focus(); + } + } + catch(e){} + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return } + + e.dataTransfer.setData("Text", cm.getSelection()); + e.dataTransfer.effectAllowed = "copyMove"; + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) { img.parentNode.removeChild(img); } + } + } + + function onDragOver(cm, e) { + var pos = posFromMouse(cm, e); + if (!pos) { return } + var frag = document.createDocumentFragment(); + drawSelectionCursor(cm, pos, frag); + if (!cm.display.dragCursor) { + cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); + cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); + } + removeChildrenAndAdd(cm.display.dragCursor, frag); + } + + function clearDragCursor(cm) { + if (cm.display.dragCursor) { + cm.display.lineSpace.removeChild(cm.display.dragCursor); + cm.display.dragCursor = null; + } + } + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.getElementsByClassName) { return } + var byClass = document.getElementsByClassName("CodeMirror"), editors = []; + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) { editors.push(cm); } + } + if (editors.length) { editors[0].operation(function () { + for (var i = 0; i < editors.length; i++) { f(editors[i]); } + }); } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) { return } + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function () { + if (resizeTimer == null) { resizeTimer = setTimeout(function () { + resizeTimer = null; + forEachCodeMirror(onResize); + }, 100); } + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function () { return forEachCodeMirror(onBlur); }); + } + // Called when the window resizes + function onResize(cm) { + var d = cm.display; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.scrollbarsClipped = false; + cm.setSize(); + } + + var keyNames = { + 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", + 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 145: "ScrollLock", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" + }; + + // Number keys + for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); } + // Alphabetic keys + for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); } + // Function keys + for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; } + + var keyMap = {}; + + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + "fallthrough": "basic" + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", + "Ctrl-O": "openLine" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + "fallthrough": ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/); + name = parts[parts.length - 1]; + var alt, ctrl, shift, cmd; + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; } + else if (/^a(lt)?$/i.test(mod)) { alt = true; } + else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; } + else if (/^s(hift)?$/i.test(mod)) { shift = true; } + else { throw new Error("Unrecognized modifier name: " + mod) } + } + if (alt) { name = "Alt-" + name; } + if (ctrl) { name = "Ctrl-" + name; } + if (cmd) { name = "Cmd-" + name; } + if (shift) { name = "Shift-" + name; } + return name + } + + // This is a kludge to keep keymaps mostly working as raw objects + // (backwards compatibility) while at the same time support features + // like normalization and multi-stroke key bindings. It compiles a + // new normalized keymap, and then updates the old object to reflect + // this. + function normalizeKeyMap(keymap) { + var copy = {}; + for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname]; + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue } + if (value == "...") { delete keymap[keyname]; continue } + + var keys = map(keyname.split(" "), normalizeKeyName); + for (var i = 0; i < keys.length; i++) { + var val = (void 0), name = (void 0); + if (i == keys.length - 1) { + name = keys.join(" "); + val = value; + } else { + name = keys.slice(0, i + 1).join(" "); + val = "..."; + } + var prev = copy[name]; + if (!prev) { copy[name] = val; } + else if (prev != val) { throw new Error("Inconsistent bindings for " + name) } + } + delete keymap[keyname]; + } } + for (var prop in copy) { keymap[prop] = copy[prop]; } + return keymap + } + + function lookupKey(key, map$$1, handle, context) { + map$$1 = getKeyMap(map$$1); + var found = map$$1.call ? map$$1.call(key, context) : map$$1[key]; + if (found === false) { return "nothing" } + if (found === "...") { return "multi" } + if (found != null && handle(found)) { return "handled" } + + if (map$$1.fallthrough) { + if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]") + { return lookupKey(key, map$$1.fallthrough, handle, context) } + for (var i = 0; i < map$$1.fallthrough.length; i++) { + var result = lookupKey(key, map$$1.fallthrough[i], handle, context); + if (result) { return result } + } + } + } + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + function isModifierKey(value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" + } + + function addModifierNames(name, event, noShift) { + var base = name; + if (event.altKey && base != "Alt") { name = "Alt-" + name; } + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; } + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; } + if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; } + return name + } + + // Look up the name of a key as indicated by an event object. + function keyName(event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) { return false } + var name = keyNames[event.keyCode]; + if (name == null || event.altGraphKey) { return false } + // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause, + // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+) + if (event.keyCode == 3 && event.code) { name = event.code; } + return addModifierNames(name, event, noShift) + } + + function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function () { + for (var i = kill.length - 1; i >= 0; i--) + { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); } + ensureCursorVisible(cm); + }); + } + + function moveCharLogically(line, ch, dir) { + var target = skipExtendingChars(line.text, ch + dir, dir); + return target < 0 || target > line.text.length ? null : target + } + + function moveLogically(line, start, dir) { + var ch = moveCharLogically(line, start.ch, dir); + return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before") + } + + function endOfLine(visually, cm, lineObj, lineNo, dir) { + if (visually) { + if (cm.getOption("direction") == "rtl") { dir = -dir; } + var order = getOrder(lineObj, cm.doc.direction); + if (order) { + var part = dir < 0 ? lst(order) : order[0]; + var moveInStorageOrder = (dir < 0) == (part.level == 1); + var sticky = moveInStorageOrder ? "after" : "before"; + var ch; + // With a wrapped rtl chunk (possibly spanning multiple bidi parts), + // it could be that the last bidi part is not on the last visual line, + // since visual lines contain content order-consecutive chunks. + // Thus, in rtl, we are looking for the first (content-order) character + // in the rtl chunk that is on the last line (that is, the same line + // as the last (content-order) character). + if (part.level > 0 || cm.doc.direction == "rtl") { + var prep = prepareMeasureForLine(cm, lineObj); + ch = dir < 0 ? lineObj.text.length - 1 : 0; + var targetTop = measureCharPrepared(cm, prep, ch).top; + ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch); + if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); } + } else { ch = dir < 0 ? part.to : part.from; } + return new Pos(lineNo, ch, sticky) + } + } + return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after") + } + + function moveVisually(cm, line, start, dir) { + var bidi = getOrder(line, cm.doc.direction); + if (!bidi) { return moveLogically(line, start, dir) } + if (start.ch >= line.text.length) { + start.ch = line.text.length; + start.sticky = "before"; + } else if (start.ch <= 0) { + start.ch = 0; + start.sticky = "after"; + } + var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos]; + if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) { + // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines, + // nothing interesting happens. + return moveLogically(line, start, dir) + } + + var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); }; + var prep; + var getWrappedLineExtent = function (ch) { + if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} } + prep = prep || prepareMeasureForLine(cm, line); + return wrappedLineExtentChar(cm, line, prep, ch) + }; + var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch); + + if (cm.doc.direction == "rtl" || part.level == 1) { + var moveInStorageOrder = (part.level == 1) == (dir < 0); + var ch = mv(start, moveInStorageOrder ? 1 : -1); + if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) { + // Case 2: We move within an rtl part or in an rtl editor on the same visual line + var sticky = moveInStorageOrder ? "before" : "after"; + return new Pos(start.line, ch, sticky) + } + } + + // Case 3: Could not move within this bidi part in this visual line, so leave + // the current bidi part + + var searchInVisualLine = function (partPos, dir, wrappedLineExtent) { + var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder + ? new Pos(start.line, mv(ch, 1), "before") + : new Pos(start.line, ch, "after"); }; + + for (; partPos >= 0 && partPos < bidi.length; partPos += dir) { + var part = bidi[partPos]; + var moveInStorageOrder = (dir > 0) == (part.level != 1); + var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1); + if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) } + ch = moveInStorageOrder ? part.from : mv(part.to, -1); + if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) } + } + }; + + // Case 3a: Look for other bidi parts on the same visual line + var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent); + if (res) { return res } + + // Case 3b: Look for other bidi parts on the next visual line + var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1); + if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) { + res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh)); + if (res) { return res } + } + + // Case 4: Nowhere to move + return null + } + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = { + selectAll: selectAll, + singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, + killLine: function (cm) { return deleteNearSelection(cm, function (range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + { return {from: range.head, to: Pos(range.head.line + 1, 0)} } + else + { return {from: range.head, to: Pos(range.head.line, len)} } + } else { + return {from: range.from(), to: range.to()} + } + }); }, + deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({ + from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) + }); }); }, + delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({ + from: Pos(range.from().line, 0), to: range.from() + }); }); }, + delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + var leftPos = cm.coordsChar({left: 0, top: top}, "div"); + return {from: leftPos, to: range.from()} + }); }, + delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); + return {from: range.from(), to: rightPos } + }); }, + undo: function (cm) { return cm.undo(); }, + redo: function (cm) { return cm.redo(); }, + undoSelection: function (cm) { return cm.undoSelection(); }, + redoSelection: function (cm) { return cm.redoSelection(); }, + goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); }, + goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); }, + goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, + {origin: "+move", bias: 1} + ); }, + goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); }, + {origin: "+move", bias: 1} + ); }, + goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, + {origin: "+move", bias: -1} + ); }, + goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.cursorCoords(range.head, "div").top + 5; + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + }, sel_move); }, + goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.cursorCoords(range.head, "div").top + 5; + return cm.coordsChar({left: 0, top: top}, "div") + }, sel_move); }, + goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) { + var top = cm.cursorCoords(range.head, "div").top + 5; + var pos = cm.coordsChar({left: 0, top: top}, "div"); + if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) } + return pos + }, sel_move); }, + goLineUp: function (cm) { return cm.moveV(-1, "line"); }, + goLineDown: function (cm) { return cm.moveV(1, "line"); }, + goPageUp: function (cm) { return cm.moveV(-1, "page"); }, + goPageDown: function (cm) { return cm.moveV(1, "page"); }, + goCharLeft: function (cm) { return cm.moveH(-1, "char"); }, + goCharRight: function (cm) { return cm.moveH(1, "char"); }, + goColumnLeft: function (cm) { return cm.moveH(-1, "column"); }, + goColumnRight: function (cm) { return cm.moveH(1, "column"); }, + goWordLeft: function (cm) { return cm.moveH(-1, "word"); }, + goGroupRight: function (cm) { return cm.moveH(1, "group"); }, + goGroupLeft: function (cm) { return cm.moveH(-1, "group"); }, + goWordRight: function (cm) { return cm.moveH(1, "word"); }, + delCharBefore: function (cm) { return cm.deleteH(-1, "char"); }, + delCharAfter: function (cm) { return cm.deleteH(1, "char"); }, + delWordBefore: function (cm) { return cm.deleteH(-1, "word"); }, + delWordAfter: function (cm) { return cm.deleteH(1, "word"); }, + delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); }, + delGroupAfter: function (cm) { return cm.deleteH(1, "group"); }, + indentAuto: function (cm) { return cm.indentSelection("smart"); }, + indentMore: function (cm) { return cm.indentSelection("add"); }, + indentLess: function (cm) { return cm.indentSelection("subtract"); }, + insertTab: function (cm) { return cm.replaceSelection("\t"); }, + insertSoftTab: function (cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(spaceStr(tabSize - col % tabSize)); + } + cm.replaceSelections(spaces); + }, + defaultTab: function (cm) { + if (cm.somethingSelected()) { cm.indentSelection("add"); } + else { cm.execCommand("insertTab"); } + }, + // Swap the two chars left and right of each selection's head. + // Move cursor behind the two swapped characters afterwards. + // + // Doesn't consider line feeds a character. + // Doesn't scan more than one line above to find a character. + // Doesn't do anything on an empty line. + // Doesn't do anything with non-empty selections. + transposeChars: function (cm) { return runInOp(cm, function () { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) { continue } + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); } + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) { + cur = new Pos(cur.line, 1); + cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), cur, "+transpose"); + } + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); }, + newlineAndIndent: function (cm) { return runInOp(cm, function () { + var sels = cm.listSelections(); + for (var i = sels.length - 1; i >= 0; i--) + { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); } + sels = cm.listSelections(); + for (var i$1 = 0; i$1 < sels.length; i$1++) + { cm.indentLine(sels[i$1].from().line, null, true); } + ensureCursorVisible(cm); + }); }, + openLine: function (cm) { return cm.replaceSelection("\n", "start"); }, + toggleOverwrite: function (cm) { return cm.toggleOverwrite(); } + }; + + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) { lineN = lineNo(visual); } + return endOfLine(true, cm, visual, lineN, 1) + } + function lineEnd(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLineEnd(line); + if (visual != line) { lineN = lineNo(visual); } + return endOfLine(true, cm, line, lineN, -1) + } + function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line); + var line = getLine(cm.doc, start.line); + var order = getOrder(line, cm.doc.direction); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; + return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky) + } + return start + } + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) { return false } + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled(); + var prevShift = cm.display.shift, done = false; + try { + if (cm.isReadOnly()) { cm.state.suppressEdits = true; } + if (dropShift) { cm.display.shift = false; } + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done + } + + function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); + if (result) { return result } + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm) + } + + // Note that, despite the name, this function is also used to check + // for bound mouse clicks. + + var stopSeq = new Delayed; + + function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq; + if (seq) { + if (isModifierKey(name)) { return "handled" } + if (/\'$/.test(name)) + { cm.state.keySeq = null; } + else + { stopSeq.set(50, function () { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null; + cm.display.input.reset(); + } + }); } + if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true } + } + return dispatchKeyInner(cm, name, e, handle) + } + + function dispatchKeyInner(cm, name, e, handle) { + var result = lookupKeyForEditor(cm, name, handle); + + if (result == "multi") + { cm.state.keySeq = name; } + if (result == "handled") + { signalLater(cm, "keyHandled", cm, name, e); } + + if (result == "handled" || result == "multi") { + e_preventDefault(e); + restartBlink(cm); + } + + return !!result + } + + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + var name = keyName(e, true); + if (!name) { return false } + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) + || dispatchKey(cm, name, e, function (b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + { return doHandleBinding(cm, b) } + }) + } else { + return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }) + } + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); }) + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + cm.curOp.focus = activeElt(); + if (signalDOMEvent(cm, e)) { return } + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; } + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + { cm.replaceSelection("", null, "cut"); } + } + if (gecko && !mac && !handled && code == 46 && e.shiftKey && !e.ctrlKey && document.execCommand) + { document.execCommand("cut"); } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + { showCrossHair(cm); } + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (e.keyCode == 16) { this.doc.sel.shift = false; } + signalDOMEvent(this, e); + } + + function onKeyPress(e) { + var cm = this; + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return } + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return } + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + // Some browsers fire keypress events for backspace + if (ch == "\x08") { return } + if (handleCharBinding(cm, e, ch)) { return } + cm.display.input.onKeyPress(e); + } + + var DOUBLECLICK_DELAY = 400; + + var PastClick = function(time, pos, button) { + this.time = time; + this.pos = pos; + this.button = button; + }; + + PastClick.prototype.compare = function (time, pos, button) { + return this.time + DOUBLECLICK_DELAY > time && + cmp(pos, this.pos) == 0 && button == this.button + }; + + var lastClick, lastDoubleClick; + function clickRepeat(pos, button) { + var now = +new Date; + if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) { + lastClick = lastDoubleClick = null; + return "triple" + } else if (lastClick && lastClick.compare(now, pos, button)) { + lastDoubleClick = new PastClick(now, pos, button); + lastClick = null; + return "double" + } else { + lastClick = new PastClick(now, pos, button); + lastDoubleClick = null; + return "single" + } + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + var cm = this, display = cm.display; + if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return } + display.input.ensurePolled(); + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function () { return display.scroller.draggable = true; }, 100); + } + return + } + if (clickInGutter(cm, e)) { return } + var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single"; + window.focus(); + + // #3261: make sure, that we're not starting a second selection + if (button == 1 && cm.state.selectingText) + { cm.state.selectingText(e); } + + if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return } + + if (button == 1) { + if (pos) { leftButtonDown(cm, pos, repeat, e); } + else if (e_target(e) == display.scroller) { e_preventDefault(e); } + } else if (button == 2) { + if (pos) { extendSelection(cm.doc, pos); } + setTimeout(function () { return display.input.focus(); }, 20); + } else if (button == 3) { + if (captureRightClick) { cm.display.input.onContextMenu(e); } + else { delayBlurEvent(cm); } + } + } + + function handleMappedButton(cm, button, pos, repeat, event) { + var name = "Click"; + if (repeat == "double") { name = "Double" + name; } + else if (repeat == "triple") { name = "Triple" + name; } + name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name; + + return dispatchKey(cm, addModifierNames(name, event), event, function (bound) { + if (typeof bound == "string") { bound = commands[bound]; } + if (!bound) { return false } + var done = false; + try { + if (cm.isReadOnly()) { cm.state.suppressEdits = true; } + done = bound(cm, pos) != Pass; + } finally { + cm.state.suppressEdits = false; + } + return done + }) + } + + function configureMouse(cm, repeat, event) { + var option = cm.getOption("configureMouse"); + var value = option ? option(cm, repeat, event) : {}; + if (value.unit == null) { + var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey; + value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line"; + } + if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; } + if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; } + if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); } + return value + } + + function leftButtonDown(cm, pos, repeat, event) { + if (ie) { setTimeout(bind(ensureFocus, cm), 0); } + else { cm.curOp.focus = activeElt(); } + + var behavior = configureMouse(cm, repeat, event); + + var sel = cm.doc.sel, contained; + if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && + repeat == "single" && (contained = sel.contains(pos)) > -1 && + (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) && + (cmp(contained.to(), pos) > 0 || pos.xRel < 0)) + { leftButtonStartDrag(cm, event, pos, behavior); } + else + { leftButtonSelect(cm, event, pos, behavior); } + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, event, pos, behavior) { + var display = cm.display, moved = false; + var dragEnd = operation(cm, function (e) { + if (webkit) { display.scroller.draggable = false; } + cm.state.draggingText = false; + off(display.wrapper.ownerDocument, "mouseup", dragEnd); + off(display.wrapper.ownerDocument, "mousemove", mouseMove); + off(display.scroller, "dragstart", dragStart); + off(display.scroller, "drop", dragEnd); + if (!moved) { + e_preventDefault(e); + if (!behavior.addNew) + { extendSelection(cm.doc, pos, null, null, behavior.extend); } + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + { setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); } + else + { display.input.focus(); } + } + }); + var mouseMove = function(e2) { + moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10; + }; + var dragStart = function () { return moved = true; }; + // Let the drag handler handle this. + if (webkit) { display.scroller.draggable = true; } + cm.state.draggingText = dragEnd; + dragEnd.copy = !behavior.moveOnDrag; + // IE's approach to draggable + if (display.scroller.dragDrop) { display.scroller.dragDrop(); } + on(display.wrapper.ownerDocument, "mouseup", dragEnd); + on(display.wrapper.ownerDocument, "mousemove", mouseMove); + on(display.scroller, "dragstart", dragStart); + on(display.scroller, "drop", dragEnd); + + delayBlurEvent(cm); + setTimeout(function () { return display.input.focus(); }, 20); + } + + function rangeForUnit(cm, pos, unit) { + if (unit == "char") { return new Range(pos, pos) } + if (unit == "word") { return cm.findWordAt(pos) } + if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) } + var result = unit(cm, pos); + return new Range(result.from, result.to) + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, event, start, behavior) { + var display = cm.display, doc = cm.doc; + e_preventDefault(event); + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + if (behavior.addNew && !behavior.extend) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + { ourRange = ranges[ourIndex]; } + else + { ourRange = new Range(start, start); } + } else { + ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; + } + + if (behavior.unit == "rectangle") { + if (!behavior.addNew) { ourRange = new Range(start, start); } + start = posFromMouse(cm, event, true, true); + ourIndex = -1; + } else { + var range$$1 = rangeForUnit(cm, start, behavior.unit); + if (behavior.extend) + { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); } + else + { ourRange = range$$1; } + } + + if (!behavior.addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex == -1) { + ourIndex = ranges.length; + setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex), + {scroll: false, origin: "*mouse"}); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) { + setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), + {scroll: false, origin: "*mouse"}); + startSel = doc.sel; + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) { return } + lastPos = pos; + + if (behavior.unit == "rectangle") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); } + else if (text.length > leftPos) + { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); } + } + if (!ranges.length) { ranges.push(new Range(start, start)); } + setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + {origin: "*mouse", scroll: false}); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var range$$1 = rangeForUnit(cm, pos, behavior.unit); + var anchor = oldRange.anchor, head; + if (cmp(range$$1.anchor, anchor) > 0) { + head = range$$1.head; + anchor = minPos(oldRange.from(), range$$1.anchor); + } else { + head = range$$1.anchor; + anchor = maxPos(oldRange.to(), range$$1.head); + } + var ranges$1 = startSel.ranges.slice(0); + ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head)); + setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle"); + if (!cur) { return } + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt(); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); } + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) { setTimeout(operation(cm, function () { + if (counter != curCount) { return } + display.scroller.scrollTop += outside; + extend(e); + }), 50); } + } + } + + function done(e) { + cm.state.selectingText = false; + counter = Infinity; + // If e is null or undefined we interpret this as someone trying + // to explicitly cancel the selection rather than the user + // letting go of the mouse button. + if (e) { + e_preventDefault(e); + display.input.focus(); + } + off(display.wrapper.ownerDocument, "mousemove", move); + off(display.wrapper.ownerDocument, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function (e) { + if (e.buttons === 0 || !e_button(e)) { done(e); } + else { extend(e); } + }); + var up = operation(cm, done); + cm.state.selectingText = up; + on(display.wrapper.ownerDocument, "mousemove", move); + on(display.wrapper.ownerDocument, "mouseup", up); + } + + // Used when mouse-selecting to adjust the anchor to the proper side + // of a bidi jump depending on the visual position of the head. + function bidiSimplify(cm, range$$1) { + var anchor = range$$1.anchor; + var head = range$$1.head; + var anchorLine = getLine(cm.doc, anchor.line); + if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 } + var order = getOrder(anchorLine); + if (!order) { return range$$1 } + var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index]; + if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 } + var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1); + if (boundary == 0 || boundary == order.length) { return range$$1 } + + // Compute the relative visual position of the head compared to the + // anchor (<0 is to the left, >0 to the right) + var leftSide; + if (head.line != anchor.line) { + leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0; + } else { + var headIndex = getBidiPartAt(order, head.ch, head.sticky); + var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1); + if (headIndex == boundary - 1 || headIndex == boundary) + { leftSide = dir < 0; } + else + { leftSide = dir > 0; } + } + + var usePart = order[boundary + (leftSide ? -1 : 0)]; + var from = leftSide == (usePart.level == 1); + var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before"; + return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head) + } + + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent) { + var mX, mY; + if (e.touches) { + mX = e.touches[0].clientX; + mY = e.touches[0].clientY; + } else { + try { mX = e.clientX; mY = e.clientY; } + catch(e) { return false } + } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false } + if (prevent) { e_preventDefault(e); } + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) } + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.display.gutterSpecs.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.display.gutterSpecs[i]; + signal(cm, type, cm, line, gutter.className, e); + return e_defaultPrevented(e) + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true) + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return } + if (signalDOMEvent(cm, e, "contextmenu")) { return } + if (!captureRightClick) { cm.display.input.onContextMenu(e); } + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) { return false } + return gutterEvent(cm, e, "gutterContextMenu", false) + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + var Init = {toString: function(){return "CodeMirror.Init"}}; + + var defaults = {}; + var optionHandlers = {}; + + function defineOptions(CodeMirror) { + var optionHandlers = CodeMirror.optionHandlers; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) { optionHandlers[name] = + notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; } + } + + CodeMirror.defineOption = option; + + // Passed to option handlers when there is no old value. + CodeMirror.Init = Init; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function (cm, val) { return cm.setValue(val); }, true); + option("mode", null, function (cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function (cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + + option("lineSeparator", null, function (cm, val) { + cm.doc.lineSep = val; + if (!val) { return } + var newBreaks = [], lineNo = cm.doc.first; + cm.doc.iter(function (line) { + for (var pos = 0;;) { + var found = line.text.indexOf(val, pos); + if (found == -1) { break } + pos = found + val.length; + newBreaks.push(Pos(lineNo, found)); + } + lineNo++; + }); + for (var i = newBreaks.length - 1; i >= 0; i--) + { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); } + }); + option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, function (cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != Init) { cm.refresh(); } + }); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true); + option("electricChars", true); + option("inputStyle", mobile ? "contenteditable" : "textarea", function () { + throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME + }, true); + option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true); + option("autocorrect", false, function (cm, val) { return cm.getInputField().autocorrect = val; }, true); + option("autocapitalize", false, function (cm, val) { return cm.getInputField().autocapitalize = val; }, true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function (cm) { + themeChanged(cm); + updateGutters(cm); + }, true); + option("keyMap", "default", function (cm, val, old) { + var next = getKeyMap(val); + var prev = old != Init && getKeyMap(old); + if (prev && prev.detach) { prev.detach(cm, next); } + if (next.attach) { next.attach(cm, prev || null); } + }); + option("extraKeys", null); + option("configureMouse", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function (cm, val) { + cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers); + updateGutters(cm); + }, true); + option("fixedGutter", true, function (cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true); + option("scrollbarStyle", "native", function (cm) { + initScrollbars(cm); + updateScrollbars(cm); + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); + }, true); + option("lineNumbers", false, function (cm, val) { + cm.display.gutterSpecs = getGutters(cm.options.gutters, val); + updateGutters(cm); + }, true); + option("firstLineNumber", 1, updateGutters, true); + option("lineNumberFormatter", function (integer) { return integer; }, updateGutters, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); + option("pasteLinesPerSelection", true); + option("selectionsMayTouch", false); + + option("readOnly", false, function (cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + } + cm.display.input.readOnlyChanged(val); + }); + option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true); + option("dragDrop", true, dragDropChanged); + option("allowDropFileTypes", null); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; }); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function (cm, val) { + if (!val) { cm.display.input.resetPosition(); } + }); + + option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; }); + option("autofocus", null); + option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true); + option("phrases", null); + } + + function dragDropChanged(cm, value, old) { + var wasOn = old && old != Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.enter); + toggle(cm.display.scroller, "dragover", funcs.over); + toggle(cm.display.scroller, "dragleave", funcs.leave); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + cm.display.sizerWidth = null; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function () { return updateScrollbars(cm); }, 100); + } + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + var this$1 = this; + + if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) } + + this.options = options = options ? copyObj(options) : {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + + var doc = options.value; + if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); } + else if (options.mode) { doc.modeOption = options.mode; } + this.doc = doc; + + var input = new CodeMirror.inputStyles[options.inputStyle](this); + var display = this.display = new Display(place, doc, input, options); + display.wrapper.CodeMirror = this; + themeChanged(this); + if (options.lineWrapping) + { this.display.wrapper.className += " CodeMirror-wrap"; } + initScrollbars(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: -1, cutIncoming: -1, // help recognize paste/cut edits in input.poll + selectingText: false, + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + }; + + if (options.autofocus && !mobile) { display.input.focus(); } + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); } + + registerEventHandlers(this); + ensureGlobalHandlers(); + + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); + + if ((options.autofocus && !mobile) || this.hasFocus()) + { setTimeout(bind(onFocus, this), 20); } + else + { onBlur(this); } + + for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt)) + { optionHandlers[opt](this$1, options[opt], Init); } } + maybeUpdateLineNumberWidth(this); + if (options.finishInit) { options.finishInit(this); } + for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); } + endOperation(this); + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + { display.lineDiv.style.textRendering = "auto"; } + } + + // The default configuration options. + CodeMirror.defaults = defaults; + // Functions to run when options are changed. + CodeMirror.optionHandlers = optionHandlers; + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + { on(d.scroller, "dblclick", operation(cm, function (e) { + if (signalDOMEvent(cm, e)) { return } + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return } + e_preventDefault(e); + var word = cm.findWordAt(pos); + extendSelection(cm.doc, word.anchor, word.head); + })); } + else + { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); } + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); + on(d.input.getField(), "contextmenu", function (e) { + if (!d.scroller.contains(e.target)) { onContextMenu(cm, e); } + }); + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = {end: 0}; + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000); + prevTouch = d.activeTouch; + prevTouch.end = +new Date; + } + } + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) { return false } + var touch = e.touches[0]; + return touch.radiusX <= 1 && touch.radiusY <= 1 + } + function farAway(touch, other) { + if (other.left == null) { return true } + var dx = other.left - touch.left, dy = other.top - touch.top; + return dx * dx + dy * dy > 20 * 20 + } + on(d.scroller, "touchstart", function (e) { + if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) { + d.input.ensurePolled(); + clearTimeout(touchFinished); + var now = +new Date; + d.activeTouch = {start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null}; + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX; + d.activeTouch.top = e.touches[0].pageY; + } + } + }); + on(d.scroller, "touchmove", function () { + if (d.activeTouch) { d.activeTouch.moved = true; } + }); + on(d.scroller, "touchend", function (e) { + var touch = d.activeTouch; + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range; + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + { range = new Range(pos, pos); } + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + { range = cm.findWordAt(pos); } + else // Triple tap + { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); } + cm.setSelection(range.anchor, range.head); + cm.focus(); + e_preventDefault(e); + } + finishTouch(); + }); + on(d.scroller, "touchcancel", finishTouch); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function () { + if (d.scroller.clientHeight) { + updateScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); }); + on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); }); + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + d.dragFunctions = { + enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }}, + over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }}, + start: function (e) { return onDragStart(cm, e); }, + drop: operation(cm, onDrop), + leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }} + }; + + var inp = d.input.getField(); + on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); }); + on(inp, "keydown", operation(cm, onKeyDown)); + on(inp, "keypress", operation(cm, onKeyPress)); + on(inp, "focus", function (e) { return onFocus(cm, e); }); + on(inp, "blur", function (e) { return onBlur(cm, e); }); + } + + var initHooks = []; + CodeMirror.defineInitHook = function (f) { return initHooks.push(f); }; + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) { how = "add"; } + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) { how = "prev"; } + else { state = getContextBefore(cm, n).state; } + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) { line.stateAfter = null; } + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass || indentation > 150) { + if (!aggressive) { return } + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); } + else { indentation = 0; } + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} } + if (pos < indentation) { indentString += spaceStr(indentation - pos); } + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + line.stateAfter = null; + return true + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) { + var range = doc.sel.ranges[i$1]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos$1 = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i$1, new Range(pos$1, pos$1)); + break + } + } + } + } + + // This will be set to a {lineWise: bool, text: [string]} object, so + // that, when pasting, we know what kind of selections the copied + // text was made out of. + var lastCopied = null; + + function setLastCopied(newLastCopied) { + lastCopied = newLastCopied; + } + + function applyTextInput(cm, inserted, deleted, sel, origin) { + var doc = cm.doc; + cm.display.shift = false; + if (!sel) { sel = doc.sel; } + + var recent = +new Date - 200; + var paste = origin == "paste" || cm.state.pasteIncoming > recent; + var textLines = splitLinesAuto(inserted), multiPaste = null; + // When pasting N lines into N selections, insert one line per selection + if (paste && sel.ranges.length > 1) { + if (lastCopied && lastCopied.text.join("\n") == inserted) { + if (sel.ranges.length % lastCopied.text.length == 0) { + multiPaste = []; + for (var i = 0; i < lastCopied.text.length; i++) + { multiPaste.push(doc.splitLines(lastCopied.text[i])); } + } + } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) { + multiPaste = map(textLines, function (l) { return [l]; }); + } + } + + var updateInput = cm.curOp.updateInput; + // Normal behavior is to insert the new text into every selection + for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) { + var range$$1 = sel.ranges[i$1]; + var from = range$$1.from(), to = range$$1.to(); + if (range$$1.empty()) { + if (deleted && deleted > 0) // Handle deletion + { from = Pos(from.line, from.ch - deleted); } + else if (cm.state.overwrite && !paste) // Handle overwrite + { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } + else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + { from = to = Pos(from.line, 0); } + } + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines, + origin: origin || (paste ? "paste" : cm.state.cutIncoming > recent ? "cut" : "+input")}; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + } + if (inserted && !paste) + { triggerElectric(cm, inserted); } + + ensureCursorVisible(cm); + if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; } + cm.curOp.typing = true; + cm.state.pasteIncoming = cm.state.cutIncoming = -1; + } + + function handlePaste(e, cm) { + var pasted = e.clipboardData && e.clipboardData.getData("Text"); + if (pasted) { + e.preventDefault(); + if (!cm.isReadOnly() && !cm.options.disableInput) + { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); } + return true + } + } + + function triggerElectric(cm, inserted) { + // When an 'electric' character is inserted, immediately trigger a reindent + if (!cm.options.electricChars || !cm.options.smartIndent) { return } + var sel = cm.doc.sel; + + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range$$1 = sel.ranges[i]; + if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue } + var mode = cm.getModeAt(range$$1.head); + var indented = false; + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indented = indentLine(cm, range$$1.head.line, "smart"); + break + } } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch))) + { indented = indentLine(cm, range$$1.head.line, "smart"); } + } + if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); } + } + } + + function copyableRanges(cm) { + var text = [], ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; + ranges.push(lineRange); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); + } + return {text: text, ranges: ranges} + } + + function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) { + field.setAttribute("autocorrect", autocorrect ? "" : "off"); + field.setAttribute("autocapitalize", autocapitalize ? "" : "off"); + field.setAttribute("spellcheck", !!spellcheck); + } + + function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"); + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) { te.style.width = "1000px"; } + else { te.setAttribute("wrap", "off"); } + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) { te.style.border = "1px solid black"; } + disableBrowserMagic(te); + return div + } + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + function addEditorMethods(CodeMirror) { + var optionHandlers = CodeMirror.optionHandlers; + + var helpers = CodeMirror.helpers = {}; + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function(){window.focus(); this.display.input.focus();}, + + setOption: function(option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") { return } + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + { operation(this, optionHandlers[option])(this, value, old); } + signal(this, "optionChange", this, option); + }, + + getOption: function(option) {return this.options[option]}, + getDoc: function() {return this.doc}, + + addKeyMap: function(map$$1, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1)); + }, + removeKeyMap: function(map$$1) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + { if (maps[i] == map$$1 || maps[i].name == map$$1) { + maps.splice(i, 1); + return true + } } + }, + + addOverlay: methodOp(function(spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) { throw new Error("Overlays may not be stateful.") } + insertSorted(this.state.overlays, + {mode: mode, modeSpec: spec, opaque: options && options.opaque, + priority: (options && options.priority) || 0}, + function (overlay) { return overlay.priority; }); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function(spec) { + var this$1 = this; + + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this$1.state.modeGen++; + regChange(this$1); + return + } + } + }), + + indentLine: methodOp(function(n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; } + else { dir = dir ? "add" : "subtract"; } + } + if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); } + }), + indentSelection: methodOp(function(how) { + var this$1 = this; + + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range$$1 = ranges[i]; + if (!range$$1.empty()) { + var from = range$$1.from(), to = range$$1.to(); + var start = Math.max(end, from.line); + end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + { indentLine(this$1, j, how); } + var newRanges = this$1.doc.sel.ranges; + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } + } else if (range$$1.head.line > end) { + indentLine(this$1, range$$1.head.line, how, true); + end = range$$1.head.line; + if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); } + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function(pos, precise) { + return takeToken(this, pos, precise) + }, + + getLineTokens: function(line, precise) { + return takeToken(this, Pos(line), precise, true) + }, + + getTokenTypeAt: function(pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) { type = styles[2]; } + else { for (;;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; } + else if (styles[mid * 2 + 1] < ch) { before = mid + 1; } + else { type = styles[mid * 2 + 2]; break } + } } + var cut = type ? type.indexOf("overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) + }, + + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) { return mode } + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode + }, + + getHelper: function(pos, type) { + return this.getHelpers(pos, type)[0] + }, + + getHelpers: function(pos, type) { + var this$1 = this; + + var found = []; + if (!helpers.hasOwnProperty(type)) { return found } + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) { found.push(help[mode[type]]); } + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) { found.push(val); } + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i$1 = 0; i$1 < help._global.length; i$1++) { + var cur = help._global[i$1]; + if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1) + { found.push(cur.val); } + } + return found + }, + + getStateAfter: function(line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); + return getContextBefore(this, line + 1, precise).state + }, + + cursorCoords: function(start, mode) { + var pos, range$$1 = this.doc.sel.primary(); + if (start == null) { pos = range$$1.head; } + else if (typeof start == "object") { pos = clipPos(this.doc, start); } + else { pos = start ? range$$1.from() : range$$1.to(); } + return cursorCoords(this, pos, mode || "page") + }, + + charCoords: function(pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page") + }, + + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top) + }, + + lineAtHeight: function(height, mode) { + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset) + }, + heightAtLine: function(line, mode, includeWidgets) { + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) { line = this.doc.first; } + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top + + (end ? this.doc.height - heightAtLine(lineObj) : 0) + }, + + defaultTextHeight: function() { return textHeight(this.display) }, + defaultCharWidth: function() { return charWidth(this.display) }, + + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, + + addWidget: function(pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + node.setAttribute("cm-ignore-events", "true"); + this.display.input.setUneditable(node); + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + { top = pos.top - node.offsetHeight; } + else if (pos.bottom + node.offsetHeight <= vspace) + { top = pos.bottom; } + if (left + node.offsetWidth > hspace) + { left = hspace - node.offsetWidth; } + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") { left = 0; } + else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; } + node.style.left = left + "px"; + } + if (scroll) + { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); } + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + triggerOnMouseDown: methodOp(onMouseDown), + + execCommand: function(cmd) { + if (commands.hasOwnProperty(cmd)) + { return commands[cmd].call(null, this) } + }, + + triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), + + findPosH: function(from, amount, unit, visually) { + var this$1 = this; + + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + var cur = clipPos(this.doc, from); + for (var i = 0; i < amount; ++i) { + cur = findPosH(this$1.doc, cur, dir, unit, visually); + if (cur.hitSide) { break } + } + return cur + }, + + moveH: methodOp(function(dir, unit) { + var this$1 = this; + + this.extendSelectionsBy(function (range$$1) { + if (this$1.display.shift || this$1.doc.extend || range$$1.empty()) + { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) } + else + { return dir < 0 ? range$$1.from() : range$$1.to() } + }, sel_move); + }), + + deleteH: methodOp(function(dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + { doc.replaceSelection("", null, "+delete"); } + else + { deleteNearSelection(this, function (range$$1) { + var other = findPosH(doc, range$$1.head, dir, unit, false); + return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other} + }); } + }), + + findPosV: function(from, amount, unit, goalColumn) { + var this$1 = this; + + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + var cur = clipPos(this.doc, from); + for (var i = 0; i < amount; ++i) { + var coords = cursorCoords(this$1, cur, "div"); + if (x == null) { x = coords.left; } + else { coords.left = x; } + cur = findPosV(this$1, coords, dir, unit); + if (cur.hitSide) { break } + } + return cur + }, + + moveV: methodOp(function(dir, unit) { + var this$1 = this; + + var doc = this.doc, goals = []; + var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function (range$$1) { + if (collapse) + { return dir < 0 ? range$$1.from() : range$$1.to() } + var headPos = cursorCoords(this$1, range$$1.head, "div"); + if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; } + goals.push(headPos.left); + var pos = findPosV(this$1, headPos, dir, unit); + if (unit == "page" && range$$1 == doc.sel.primary()) + { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); } + return pos + }, sel_move); + if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++) + { doc.sel.ranges[i].goalColumn = goals[i]; } } + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function(pos) { + var doc = this.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = this.getHelper(pos, "wordChars"); + if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; } + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function (ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } + : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); }; + while (start > 0 && check(line.charAt(start - 1))) { --start; } + while (end < line.length && check(line.charAt(end))) { ++end; } + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)) + }, + + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) { return } + if (this.state.overwrite = !this.state.overwrite) + { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); } + else + { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); } + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function() { return this.display.input.getField() == activeElt() }, + isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, + + scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }), + getScrollInfo: function() { + var scroller = this.display.scroller; + return {left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this)} + }, + + scrollIntoView: methodOp(function(range$$1, margin) { + if (range$$1 == null) { + range$$1 = {from: this.doc.sel.primary().head, to: null}; + if (margin == null) { margin = this.options.cursorScrollMargin; } + } else if (typeof range$$1 == "number") { + range$$1 = {from: Pos(range$$1, 0), to: null}; + } else if (range$$1.from == null) { + range$$1 = {from: range$$1, to: null}; + } + if (!range$$1.to) { range$$1.to = range$$1.from; } + range$$1.margin = margin || 0; + + if (range$$1.from.line != null) { + scrollToRange(this, range$$1); + } else { + scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin); + } + }), + + setSize: methodOp(function(width, height) { + var this$1 = this; + + var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; }; + if (width != null) { this.display.wrapper.style.width = interpret(width); } + if (height != null) { this.display.wrapper.style.height = interpret(height); } + if (this.options.lineWrapping) { clearLineMeasurementCache(this); } + var lineNo$$1 = this.display.viewFrom; + this.doc.iter(lineNo$$1, this.display.viewTo, function (line) { + if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) + { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } } + ++lineNo$$1; + }); + this.curOp.forceUpdate = true; + signal(this, "refresh", this); + }), + + operation: function(f){return runInOp(this, f)}, + startOperation: function(){return startOperation(this)}, + endOperation: function(){return endOperation(this)}, + + refresh: methodOp(function() { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this.display); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + { estimateLineHeights(this); } + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function(doc) { + var old = this.doc; + old.cm = null; + // Cancel the current text selection if any (#5821) + if (this.state.selectingText) { this.state.selectingText(); } + attachDoc(this, doc); + clearCaches(this); + this.display.input.reset(); + scrollToCoords(this, doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; + signalLater(this, "swapDoc", this, old); + return old + }), + + phrase: function(phraseText) { + var phrases = this.options.phrases; + return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText + }, + + getInputField: function(){return this.display.input.getField()}, + getWrapperElement: function(){return this.display.wrapper}, + getScrollerElement: function(){return this.display.scroller}, + getGutterElement: function(){return this.display.gutters} + }; + eventMixin(CodeMirror); + + CodeMirror.registerHelper = function(type, name, value) { + if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; } + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({pred: predicate, val: value}); + }; + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var oldPos = pos; + var origDir = dir; + var lineObj = getLine(doc, pos.line); + var lineDir = visually && doc.cm && doc.cm.getOption("direction") == "rtl" ? -dir : dir; + function findNextLine() { + var l = pos.line + lineDir; + if (l < doc.first || l >= doc.first + doc.size) { return false } + pos = new Pos(l, pos.ch, pos.sticky); + return lineObj = getLine(doc, l) + } + function moveOnce(boundToLine) { + var next; + if (visually) { + next = moveVisually(doc.cm, lineObj, pos, dir); + } else { + next = moveLogically(lineObj, pos, dir); + } + if (next == null) { + if (!boundToLine && findNextLine()) + { pos = endOfLine(visually, doc.cm, lineObj, pos.line, lineDir); } + else + { return false } + } else { + pos = next; + } + return true + } + + if (unit == "char") { + moveOnce(); + } else if (unit == "column") { + moveOnce(true); + } else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) { break } + var cur = lineObj.text.charAt(pos.ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) { type = "s"; } + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";} + break + } + + if (type) { sawType = type; } + if (dir > 0 && !moveOnce(!first)) { break } + } + } + var result = skipAtomic(doc, pos, oldPos, origDir, true); + if (equalCursorPos(oldPos, result)) { result.hitSide = true; } + return result + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3); + y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount; + + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + var target; + for (;;) { + target = coordsChar(cm, x, y); + if (!target.outside) { break } + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } + y += dir * 5; + } + return target + } + + // CONTENTEDITABLE INPUT STYLE + + var ContentEditableInput = function(cm) { + this.cm = cm; + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; + this.polling = new Delayed(); + this.composing = null; + this.gracePeriod = false; + this.readDOMTimeout = null; + }; + + ContentEditableInput.prototype.init = function (display) { + var this$1 = this; + + var input = this, cm = input.cm; + var div = input.div = display.lineDiv; + disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize); + + on(div, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + // IE doesn't fire input events, so we schedule a read for the pasted content in this way + if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); } + }); + + on(div, "compositionstart", function (e) { + this$1.composing = {data: e.data, done: false}; + }); + on(div, "compositionupdate", function (e) { + if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; } + }); + on(div, "compositionend", function (e) { + if (this$1.composing) { + if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); } + this$1.composing.done = true; + } + }); + + on(div, "touchstart", function () { return input.forceCompositionEnd(); }); + + on(div, "input", function () { + if (!this$1.composing) { this$1.readFromDOMSoon(); } + }); + + function onCopyCut(e) { + if (signalDOMEvent(cm, e)) { return } + if (cm.somethingSelected()) { + setLastCopied({lineWise: false, text: cm.getSelections()}); + if (e.type == "cut") { cm.replaceSelection("", null, "cut"); } + } else if (!cm.options.lineWiseCopyCut) { + return + } else { + var ranges = copyableRanges(cm); + setLastCopied({lineWise: true, text: ranges.text}); + if (e.type == "cut") { + cm.operation(function () { + cm.setSelections(ranges.ranges, 0, sel_dontScroll); + cm.replaceSelection("", null, "cut"); + }); + } + } + if (e.clipboardData) { + e.clipboardData.clearData(); + var content = lastCopied.text.join("\n"); + // iOS exposes the clipboard API, but seems to discard content inserted into it + e.clipboardData.setData("Text", content); + if (e.clipboardData.getData("Text") == content) { + e.preventDefault(); + return + } + } + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild; + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); + te.value = lastCopied.text.join("\n"); + var hadFocus = document.activeElement; + selectInput(te); + setTimeout(function () { + cm.display.lineSpace.removeChild(kludge); + hadFocus.focus(); + if (hadFocus == div) { input.showPrimarySelection(); } + }, 50); + } + on(div, "copy", onCopyCut); + on(div, "cut", onCopyCut); + }; + + ContentEditableInput.prototype.prepareSelection = function () { + var result = prepareSelection(this.cm, false); + result.focus = this.cm.state.focused; + return result + }; + + ContentEditableInput.prototype.showSelection = function (info, takeFocus) { + if (!info || !this.cm.display.view.length) { return } + if (info.focus || takeFocus) { this.showPrimarySelection(); } + this.showMultipleSelections(info); + }; + + ContentEditableInput.prototype.getSelection = function () { + return this.cm.display.wrapper.ownerDocument.getSelection() + }; + + ContentEditableInput.prototype.showPrimarySelection = function () { + var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary(); + var from = prim.from(), to = prim.to(); + + if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) { + sel.removeAllRanges(); + return + } + + var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset); + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), from) == 0 && + cmp(maxPos(curAnchor, curFocus), to) == 0) + { return } + + var view = cm.display.view; + var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) || + {node: view[0].measure.map[2], offset: 0}; + var end = to.line < cm.display.viewTo && posToDOM(cm, to); + if (!end) { + var measure = view[view.length - 1].measure; + var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]}; + } + + if (!start || !end) { + sel.removeAllRanges(); + return + } + + var old = sel.rangeCount && sel.getRangeAt(0), rng; + try { rng = range(start.node, start.offset, end.offset, end.node); } + catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + if (!gecko && cm.state.focused) { + sel.collapse(start.node, start.offset); + if (!rng.collapsed) { + sel.removeAllRanges(); + sel.addRange(rng); + } + } else { + sel.removeAllRanges(); + sel.addRange(rng); + } + if (old && sel.anchorNode == null) { sel.addRange(old); } + else if (gecko) { this.startGracePeriod(); } + } + this.rememberSelection(); + }; + + ContentEditableInput.prototype.startGracePeriod = function () { + var this$1 = this; + + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function () { + this$1.gracePeriod = false; + if (this$1.selectionChanged()) + { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); } + }, 20); + }; + + ContentEditableInput.prototype.showMultipleSelections = function (info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + }; + + ContentEditableInput.prototype.rememberSelection = function () { + var sel = this.getSelection(); + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + }; + + ContentEditableInput.prototype.selectionInEditor = function () { + var sel = this.getSelection(); + if (!sel.rangeCount) { return false } + var node = sel.getRangeAt(0).commonAncestorContainer; + return contains(this.div, node) + }; + + ContentEditableInput.prototype.focus = function () { + if (this.cm.options.readOnly != "nocursor") { + if (!this.selectionInEditor()) + { this.showSelection(this.prepareSelection(), true); } + this.div.focus(); + } + }; + ContentEditableInput.prototype.blur = function () { this.div.blur(); }; + ContentEditableInput.prototype.getField = function () { return this.div }; + + ContentEditableInput.prototype.supportsTouch = function () { return true }; + + ContentEditableInput.prototype.receivedFocus = function () { + var input = this; + if (this.selectionInEditor()) + { this.pollSelection(); } + else + { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); } + + function poll() { + if (input.cm.state.focused) { + input.pollSelection(); + input.polling.set(input.cm.options.pollInterval, poll); + } + } + this.polling.set(this.cm.options.pollInterval, poll); + }; + + ContentEditableInput.prototype.selectionChanged = function () { + var sel = this.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset + }; + + ContentEditableInput.prototype.pollSelection = function () { + if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return } + var sel = this.getSelection(), cm = this.cm; + // On Android Chrome (version 56, at least), backspacing into an + // uneditable block element will put the cursor in that element, + // and then, because it's not editable, hide the virtual keyboard. + // Because Android doesn't allow us to actually detect backspace + // presses in a sane way, this code checks for when that happens + // and simulates a backspace press in this case. + if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) { + this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs}); + this.blur(); + this.focus(); + return + } + if (this.composing) { return } + this.rememberSelection(); + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var head = domToPos(cm, sel.focusNode, sel.focusOffset); + if (anchor && head) { runInOp(cm, function () { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); + if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; } + }); } + }; + + ContentEditableInput.prototype.pollContent = function () { + if (this.readDOMTimeout != null) { + clearTimeout(this.readDOMTimeout); + this.readDOMTimeout = null; + } + + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); + var from = sel.from(), to = sel.to(); + if (from.ch == 0 && from.line > cm.firstLine()) + { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); } + if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine()) + { to = Pos(to.line + 1, 0); } + if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false } + + var fromIndex, fromLine, fromNode; + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + fromLine = lineNo(display.view[0].line); + fromNode = display.view[0].node; + } else { + fromLine = lineNo(display.view[fromIndex].line); + fromNode = display.view[fromIndex - 1].node.nextSibling; + } + var toIndex = findViewIndex(cm, to.line); + var toLine, toNode; + if (toIndex == display.view.length - 1) { + toLine = display.viewTo - 1; + toNode = display.lineDiv.lastChild; + } else { + toLine = lineNo(display.view[toIndex + 1].line) - 1; + toNode = display.view[toIndex + 1].node.previousSibling; + } + + if (!fromNode) { return false } + var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } + else { break } + } + + var cutFront = 0, cutEnd = 0; + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + { ++cutFront; } + var newBot = lst(newText), oldBot = lst(oldText); + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)); + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + { ++cutEnd; } + // Try to move start of change to start of selection if ambiguous + if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) { + while (cutFront && cutFront > from.ch && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) { + cutFront--; + cutEnd++; + } + } + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, ""); + newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, ""); + + var chFrom = Pos(fromLine, cutFront); + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input"); + return true + } + }; + + ContentEditableInput.prototype.ensurePolled = function () { + this.forceCompositionEnd(); + }; + ContentEditableInput.prototype.reset = function () { + this.forceCompositionEnd(); + }; + ContentEditableInput.prototype.forceCompositionEnd = function () { + if (!this.composing) { return } + clearTimeout(this.readDOMTimeout); + this.composing = null; + this.updateFromDOM(); + this.div.blur(); + this.div.focus(); + }; + ContentEditableInput.prototype.readFromDOMSoon = function () { + var this$1 = this; + + if (this.readDOMTimeout != null) { return } + this.readDOMTimeout = setTimeout(function () { + this$1.readDOMTimeout = null; + if (this$1.composing) { + if (this$1.composing.done) { this$1.composing = null; } + else { return } + } + this$1.updateFromDOM(); + }, 80); + }; + + ContentEditableInput.prototype.updateFromDOM = function () { + var this$1 = this; + + if (this.cm.isReadOnly() || !this.pollContent()) + { runInOp(this.cm, function () { return regChange(this$1.cm); }); } + }; + + ContentEditableInput.prototype.setUneditable = function (node) { + node.contentEditable = "false"; + }; + + ContentEditableInput.prototype.onKeyPress = function (e) { + if (e.charCode == 0 || this.composing) { return } + e.preventDefault(); + if (!this.cm.isReadOnly()) + { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); } + }; + + ContentEditableInput.prototype.readOnlyChanged = function (val) { + this.div.contentEditable = String(val != "nocursor"); + }; + + ContentEditableInput.prototype.onContextMenu = function () {}; + ContentEditableInput.prototype.resetPosition = function () {}; + + ContentEditableInput.prototype.needsContentAttribute = true; + + function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line); + if (!view || view.hidden) { return null } + var line = getLine(cm.doc, pos.line); + var info = mapFromLineView(view, line, pos.line); + + var order = getOrder(line, cm.doc.direction), side = "left"; + if (order) { + var partPos = getBidiPartAt(order, pos.ch); + side = partPos % 2 ? "right" : "left"; + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); + result.offset = result.collapse == "right" ? result.end : result.start; + return result + } + + function isInGutter(node) { + for (var scan = node; scan; scan = scan.parentNode) + { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } } + return false + } + + function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos } + + function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false; + function recognizeMarker(id) { return function (marker) { return marker.id == id; } } + function close() { + if (closing) { + text += lineSep; + if (extraLinebreak) { text += lineSep; } + closing = extraLinebreak = false; + } + } + function addText(str) { + if (str) { + close(); + text += str; + } + } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text"); + if (cmText) { + addText(cmText); + return + } + var markerID = node.getAttribute("cm-marker"), range$$1; + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + if (found.length && (range$$1 = found[0].find(0))) + { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); } + return + } + if (node.getAttribute("contenteditable") == "false") { return } + var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName); + if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return } + + if (isBlock) { close(); } + for (var i = 0; i < node.childNodes.length; i++) + { walk(node.childNodes[i]); } + + if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; } + if (isBlock) { closing = true; } + } else if (node.nodeType == 3) { + addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " ")); + } + } + for (;;) { + walk(from); + if (from == to) { break } + from = from.nextSibling; + extraLinebreak = false; + } + return text + } + + function domToPos(cm, node, offset) { + var lineNode; + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset]; + if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) } + node = null; offset = 0; + } else { + for (lineNode = node;; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) { return null } + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break } + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i]; + if (lineView.node == lineNode) + { return locateNodeInLineView(lineView, node, offset) } + } + } + + function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false; + if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) } + if (node == wrapper) { + bad = true; + node = wrapper.childNodes[offset]; + offset = 0; + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line; + return badPos(Pos(lineNo(line), line.text.length), bad) + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node; + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild; + if (offset) { offset = textNode.nodeValue.length; } + } + while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; } + var measure = lineView.measure, maps = measure.maps; + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map$$1 = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map$$1.length; j += 3) { + var curNode = map$$1[j + 2]; + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); + var ch = map$$1[j] + offset; + if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; } + return Pos(line, ch) + } + } + } + } + var found = find(textNode, topNode, offset); + if (found) { return badPos(found, bad) } + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0); + if (found) + { return badPos(Pos(found.line, found.ch - dist), bad) } + else + { dist += after.textContent.length; } + } + for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1); + if (found) + { return badPos(Pos(found.line, found.ch + dist$1), bad) } + else + { dist$1 += before.textContent.length; } + } + } + + // TEXTAREA INPUT STYLE + + var TextareaInput = function(cm) { + this.cm = cm; + // See input.poll and input.reset + this.prevInput = ""; + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false; + // Self-resetting timeout for the poller + this.polling = new Delayed(); + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false; + this.composing = null; + }; + + TextareaInput.prototype.init = function (display) { + var this$1 = this; + + var input = this, cm = this.cm; + this.createField(display); + var te = this.textarea; + + display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild); + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) { te.style.width = "0px"; } + + on(te, "input", function () { + if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; } + input.poll(); + }); + + on(te, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return } + + cm.state.pasteIncoming = +new Date; + input.fastPoll(); + }); + + function prepareCopyCut(e) { + if (signalDOMEvent(cm, e)) { return } + if (cm.somethingSelected()) { + setLastCopied({lineWise: false, text: cm.getSelections()}); + } else if (!cm.options.lineWiseCopyCut) { + return + } else { + var ranges = copyableRanges(cm); + setLastCopied({lineWise: true, text: ranges.text}); + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll); + } else { + input.prevInput = ""; + te.value = ranges.text.join("\n"); + selectInput(te); + } + } + if (e.type == "cut") { cm.state.cutIncoming = +new Date; } + } + on(te, "cut", prepareCopyCut); + on(te, "copy", prepareCopyCut); + + on(display.scroller, "paste", function (e) { + if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return } + if (!te.dispatchEvent) { + cm.state.pasteIncoming = +new Date; + input.focus(); + return + } + + // Pass the `paste` event to the textarea so it's handled by its event listener. + var event = new Event("paste"); + event.clipboardData = e.clipboardData; + te.dispatchEvent(event); + }); + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function (e) { + if (!eventInWidget(display, e)) { e_preventDefault(e); } + }); + + on(te, "compositionstart", function () { + var start = cm.getCursor("from"); + if (input.composing) { input.composing.range.clear(); } + input.composing = { + start: start, + range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) + }; + }); + on(te, "compositionend", function () { + if (input.composing) { + input.poll(); + input.composing.range.clear(); + input.composing = null; + } + }); + }; + + TextareaInput.prototype.createField = function (_display) { + // Wraps and hides input textarea + this.wrapper = hiddenTextarea(); + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + this.textarea = this.wrapper.firstChild; + }; + + TextareaInput.prototype.prepareSelection = function () { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc; + var result = prepareSelection(cm); + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + } + + return result + }; + + TextareaInput.prototype.showSelection = function (drawn) { + var cm = this.cm, display = cm.display; + removeChildrenAndAdd(display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px"; + this.wrapper.style.left = drawn.teLeft + "px"; + } + }; + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + TextareaInput.prototype.reset = function (typing) { + if (this.contextMenuPending || this.composing) { return } + var cm = this.cm; + if (cm.somethingSelected()) { + this.prevInput = ""; + var content = cm.getSelection(); + this.textarea.value = content; + if (cm.state.focused) { selectInput(this.textarea); } + if (ie && ie_version >= 9) { this.hasSelection = content; } + } else if (!typing) { + this.prevInput = this.textarea.value = ""; + if (ie && ie_version >= 9) { this.hasSelection = null; } + } + }; + + TextareaInput.prototype.getField = function () { return this.textarea }; + + TextareaInput.prototype.supportsTouch = function () { return false }; + + TextareaInput.prototype.focus = function () { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus(); } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } + }; + + TextareaInput.prototype.blur = function () { this.textarea.blur(); }; + + TextareaInput.prototype.resetPosition = function () { + this.wrapper.style.top = this.wrapper.style.left = 0; + }; + + TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); }; + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + TextareaInput.prototype.slowPoll = function () { + var this$1 = this; + + if (this.pollingFast) { return } + this.polling.set(this.cm.options.pollInterval, function () { + this$1.poll(); + if (this$1.cm.state.focused) { this$1.slowPoll(); } + }); + }; + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + TextareaInput.prototype.fastPoll = function () { + var missed = false, input = this; + input.pollingFast = true; + function p() { + var changed = input.poll(); + if (!changed && !missed) {missed = true; input.polling.set(60, p);} + else {input.pollingFast = false; input.slowPoll();} + } + input.polling.set(20, p); + }; + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + TextareaInput.prototype.poll = function () { + var this$1 = this; + + var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (this.contextMenuPending || !cm.state.focused || + (hasSelection(input) && !prevInput && !this.composing) || + cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) + { return false } + + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) { return false } + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset(); + return false + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) { prevInput = "\u200b"; } + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; } + + runInOp(cm, function () { + applyTextInput(cm, text.slice(same), prevInput.length - same, + null, this$1.composing ? "*compose" : null); + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; } + else { this$1.prevInput = text; } + + if (this$1.composing) { + this$1.composing.range.clear(); + this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"), + {className: "CodeMirror-composing"}); + } + }); + return true + }; + + TextareaInput.prototype.ensurePolled = function () { + if (this.pollingFast && this.poll()) { this.pollingFast = false; } + }; + + TextareaInput.prototype.onKeyPress = function () { + if (ie && ie_version >= 9) { this.hasSelection = null; } + this.fastPoll(); + }; + + TextareaInput.prototype.onContextMenu = function (e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea; + if (input.contextMenuPending) { input.contextMenuPending(); } + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) { return } // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); } + + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; + var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect(); + input.wrapper.style.cssText = "position: static"; + te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + var oldScrollY; + if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712) + display.input.focus(); + if (webkit) { window.scrollTo(null, oldScrollY); } + display.input.reset(); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) { te.value = input.prevInput = " "; } + input.contextMenuPending = rehide; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; + input.prevInput = selected ? "" : "\u200b"; + te.selectionStart = 1; te.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + if (input.contextMenuPending != rehide) { return } + input.contextMenuPending = false; + input.wrapper.style.cssText = oldWrapperCSS; + te.style.cssText = oldCSS; + if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); } + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); } + var i = 0, poll = function () { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") { + operation(cm, selectAll)(cm); + } else if (i++ < 10) { + display.detectingSelectAll = setTimeout(poll, 500); + } else { + display.selForContextMenu = null; + display.input.reset(); + } + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) { prepareSelectAllHack(); } + if (captureRightClick) { + e_stop(e); + var mouseup = function () { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + }; + + TextareaInput.prototype.readOnlyChanged = function (val) { + if (!val) { this.reset(); } + this.textarea.disabled = val == "nocursor"; + }; + + TextareaInput.prototype.setUneditable = function () {}; + + TextareaInput.prototype.needsContentAttribute = false; + + function fromTextArea(textarea, options) { + options = options ? copyObj(options) : {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabIndex) + { options.tabindex = textarea.tabIndex; } + if (!options.placeholder && textarea.placeholder) + { options.placeholder = textarea.placeholder; } + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() {textarea.value = cm.getValue();} + + var realSubmit; + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form; + realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function () { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } + } + + options.finishInit = function (cm) { + cm.save = save; + cm.getTextArea = function () { return textarea; }; + cm.toTextArea = function () { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (!options.leaveSubmitMethodAlone && typeof textarea.form.submit == "function") + { textarea.form.submit = realSubmit; } + } + }; + }; + + textarea.style.display = "none"; + var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); }, + options); + return cm + } + + function addLegacyProps(CodeMirror) { + CodeMirror.off = off; + CodeMirror.on = on; + CodeMirror.wheelEventPixels = wheelEventPixels; + CodeMirror.Doc = Doc; + CodeMirror.splitLines = splitLinesAuto; + CodeMirror.countColumn = countColumn; + CodeMirror.findColumn = findColumn; + CodeMirror.isWordChar = isWordCharBasic; + CodeMirror.Pass = Pass; + CodeMirror.signal = signal; + CodeMirror.Line = Line; + CodeMirror.changeEnd = changeEnd; + CodeMirror.scrollbarModel = scrollbarModel; + CodeMirror.Pos = Pos; + CodeMirror.cmpPos = cmp; + CodeMirror.modes = modes; + CodeMirror.mimeModes = mimeModes; + CodeMirror.resolveMode = resolveMode; + CodeMirror.getMode = getMode; + CodeMirror.modeExtensions = modeExtensions; + CodeMirror.extendMode = extendMode; + CodeMirror.copyState = copyState; + CodeMirror.startState = startState; + CodeMirror.innerMode = innerMode; + CodeMirror.commands = commands; + CodeMirror.keyMap = keyMap; + CodeMirror.keyName = keyName; + CodeMirror.isModifierKey = isModifierKey; + CodeMirror.lookupKey = lookupKey; + CodeMirror.normalizeKeyMap = normalizeKeyMap; + CodeMirror.StringStream = StringStream; + CodeMirror.SharedTextMarker = SharedTextMarker; + CodeMirror.TextMarker = TextMarker; + CodeMirror.LineWidget = LineWidget; + CodeMirror.e_preventDefault = e_preventDefault; + CodeMirror.e_stopPropagation = e_stopPropagation; + CodeMirror.e_stop = e_stop; + CodeMirror.addClass = addClass; + CodeMirror.contains = contains; + CodeMirror.rmClass = rmClass; + CodeMirror.keyNames = keyNames; + } + + // EDITOR CONSTRUCTOR + + defineOptions(CodeMirror); + + addEditorMethods(CodeMirror); + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); + for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + { CodeMirror.prototype[prop] = (function(method) { + return function() {return method.apply(this.doc, arguments)} + })(Doc.prototype[prop]); } } + + eventMixin(Doc); + CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function(name/*, mode, …*/) { + if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name; } + defineMode.apply(this, arguments); + }; + + CodeMirror.defineMIME = defineMIME; + + // Minimal default mode. + CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }); + CodeMirror.defineMIME("text/plain", "null"); + + // EXTENSIONS + + CodeMirror.defineExtension = function (name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function (name, func) { + Doc.prototype[name] = func; + }; + + CodeMirror.fromTextArea = fromTextArea; + + addLegacyProps(CodeMirror); + + CodeMirror.version = "5.51.0"; + + return CodeMirror; + +}))); diff --git a/lib/redactor/codemirror/mode/clike/clike.js b/lib/redactor/codemirror/mode/clike/clike.js new file mode 100644 index 0000000..37da2ec --- /dev/null +++ b/lib/redactor/codemirror/mode/clike/clike.js @@ -0,0 +1,935 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function Context(indented, column, type, info, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.info = info; + this.align = align; + this.prev = prev; +} +function pushContext(state, col, type, info) { + var indent = state.indented; + if (state.context && state.context.type == "statement" && type != "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, info, null, state.context); +} +function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; +} + +function typeBefore(stream, state, pos) { + if (state.prevToken == "variable" || state.prevToken == "type") return true; + if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true; + if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true; +} + +function isTopScope(context) { + for (;;) { + if (!context || context.type == "top") return true; + if (context.type == "}" && context.prev.info != "namespace") return false; + context = context.prev; + } +} + +CodeMirror.defineMode("clike", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, + keywords = parserConfig.keywords || {}, + types = parserConfig.types || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + defKeywords = parserConfig.defKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings, + indentStatements = parserConfig.indentStatements !== false, + indentSwitch = parserConfig.indentSwitch !== false, + namespaceSeparator = parserConfig.namespaceSeparator, + isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/, + numberStart = parserConfig.numberStart || /[\d\.]/, + number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i, + isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/, + isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/, + // An optional function that takes a {string} token and returns true if it + // should be treated as a builtin. + isReservedIdentifier = parserConfig.isReservedIdentifier || false; + + var curPunc, isDefKeyword; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (isPunctuationChar.test(ch)) { + curPunc = ch; + return null; + } + if (numberStart.test(ch)) { + stream.backUp(1) + if (stream.match(number)) return "number" + stream.next() + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {} + return "operator"; + } + stream.eatWhile(isIdentifierChar); + if (namespaceSeparator) while (stream.match(namespaceSeparator)) + stream.eatWhile(isIdentifierChar); + + var cur = stream.current(); + if (contains(keywords, cur)) { + if (contains(blockKeywords, cur)) curPunc = "newstatement"; + if (contains(defKeywords, cur)) isDefKeyword = true; + return "keyword"; + } + if (contains(types, cur)) return "type"; + if (contains(builtin, cur) + || (isReservedIdentifier && isReservedIdentifier(cur))) { + if (contains(blockKeywords, cur)) curPunc = "newstatement"; + return "builtin"; + } + if (contains(atoms, cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function maybeEOL(stream, state) { + if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) + state.typeAtEndOfLine = typeBefore(stream, state, stream.pos) + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false), + indented: 0, + startOfLine: true, + prevToken: null + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) { maybeEOL(stream, state); return null; } + curPunc = isDefKeyword = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false))) + while (state.context.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (indentStatements && + (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || + (ctx.type == "statement" && curPunc == "newstatement"))) { + pushContext(state, stream.column(), "statement", stream.current()); + } + + if (style == "variable" && + ((state.prevToken == "def" || + (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) && + isTopScope(state.context) && stream.match(/^\s*\(/, false))))) + style = "def"; + + if (hooks.token) { + var result = hooks.token(stream, state, style); + if (result !== undefined) style = result; + } + + if (style == "def" && parserConfig.styleDefs === false) style = "variable"; + + state.startOfLine = false; + state.prevToken = isDefKeyword ? "def" : style || curPunc; + maybeEOL(stream, state); + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + var closing = firstChar == ctx.type; + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + if (parserConfig.dontIndentStatements) + while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info)) + ctx = ctx.prev + if (hooks.indent) { + var hook = hooks.indent(state, ctx, textAfter, indentUnit); + if (typeof hook == "number") return hook + } + var switchBlock = ctx.prev && ctx.prev.info == "switch"; + if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { + while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev + return ctx.indented + } + if (ctx.type == "statement") + return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + if (ctx.align && (!dontAlignCalls || ctx.type != ")")) + return ctx.column + (closing ? 0 : 1); + if (ctx.type == ")" && !closing) + return ctx.indented + statementIndentUnit; + + return ctx.indented + (closing ? 0 : indentUnit) + + (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0); + }, + + electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", + lineComment: "//", + fold: "brace" + }; +}); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + function contains(words, word) { + if (typeof words === "function") { + return words(word); + } else { + return words.propertyIsEnumerable(word); + } + } + var cKeywords = "auto if break case register continue return default do sizeof " + + "static else struct switch extern typedef union for goto while enum const " + + "volatile inline restrict asm fortran"; + + // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20. + var cppKeywords = "alignas alignof and and_eq audit axiom bitand bitor catch " + + "class compl concept constexpr const_cast decltype delete dynamic_cast " + + "explicit export final friend import module mutable namespace new noexcept " + + "not not_eq operator or or_eq override private protected public " + + "reinterpret_cast requires static_assert static_cast template this " + + "thread_local throw try typeid typename using virtual xor xor_eq"; + + var objCKeywords = "bycopy byref in inout oneway out self super atomic nonatomic retain copy " + + "readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " + + "@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " + + "@public @package @private @protected @required @optional @try @catch @finally @import " + + "@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available"; + + var objCBuiltins = "FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION " + + " NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER " + + "NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION " + + "NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT" + + // Do not use this. Use the cTypes function below. This is global just to avoid + // excessive calls when cTypes is being called multiple times during a parse. + var basicCTypes = words("int long char short double float unsigned signed " + + "void bool"); + + // Do not use this. Use the objCTypes function below. This is global just to avoid + // excessive calls when objCTypes is being called multiple times during a parse. + var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL"); + + // Returns true if identifier is a "C" type. + // C type is defined as those that are reserved by the compiler (basicTypes), + // and those that end in _t (Reserved by POSIX for types) + // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html + function cTypes(identifier) { + return contains(basicCTypes, identifier) || /.+_t$/.test(identifier); + } + + // Returns true if identifier is a "Objective C" type. + function objCTypes(identifier) { + return cTypes(identifier) || contains(basicObjCTypes, identifier); + } + + var cBlockKeywords = "case do else for if switch while struct enum union"; + var cDefKeywords = "struct enum union"; + + function cppHook(stream, state) { + if (!state.startOfLine) return false + for (var ch, next = null; ch = stream.peek();) { + if (ch == "\\" && stream.match(/^.$/)) { + next = cppHook + break + } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) { + break + } + stream.next() + } + state.tokenize = next + return "meta" + } + + function pointerHook(_stream, state) { + if (state.prevToken == "type") return "type"; + return false; + } + + // For C and C++ (and ObjC): identifiers starting with __ + // or _ followed by a capital letter are reserved for the compiler. + function cIsReservedIdentifier(token) { + if (!token || token.length < 2) return false; + if (token[0] != '_') return false; + return (token[1] == '_') || (token[1] !== token[1].toLowerCase()); + } + + function cpp14Literal(stream) { + stream.eatWhile(/[\w\.']/); + return "number"; + } + + function cpp11StringHook(stream, state) { + stream.backUp(1); + // Raw strings. + if (stream.match(/(R|u8R|uR|UR|LR)/)) { + var match = stream.match(/"([^\s\\()]{0,16})\(/); + if (!match) { + return false; + } + state.cpp11RawStringDelim = match[1]; + state.tokenize = tokenRawString; + return tokenRawString(stream, state); + } + // Unicode strings/chars. + if (stream.match(/(u8|u|U|L)/)) { + if (stream.match(/["']/, /* eat */ false)) { + return "string"; + } + return false; + } + // Ignore this hook. + stream.next(); + return false; + } + + function cppLooksLikeConstructor(word) { + var lastTwo = /(\w+)::~?(\w+)$/.exec(word); + return lastTwo && lastTwo[1] == lastTwo[2]; + } + + // C#-style strings where "" escapes a quote. + function tokenAtString(stream, state) { + var next; + while ((next = stream.next()) != null) { + if (next == '"' && !stream.eat('"')) { + state.tokenize = null; + break; + } + } + return "string"; + } + + // C++11 raw string literal is "( anything )", where + // can be a string up to 16 characters long. + function tokenRawString(stream, state) { + // Escape characters that have special regex meanings. + var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&'); + var match = stream.match(new RegExp(".*?\\)" + delim + '"')); + if (match) + state.tokenize = null; + else + stream.skipToEnd(); + return "string"; + } + + function def(mimes, mode) { + if (typeof mimes == "string") mimes = [mimes]; + var words = []; + function add(obj) { + if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) + words.push(prop); + } + add(mode.keywords); + add(mode.types); + add(mode.builtin); + add(mode.atoms); + if (words.length) { + mode.helperType = mimes[0]; + CodeMirror.registerHelper("hintWords", mimes[0], words); + } + + for (var i = 0; i < mimes.length; ++i) + CodeMirror.defineMIME(mimes[i], mode); + } + + def(["text/x-csrc", "text/x-c", "text/x-chdr"], { + name: "clike", + keywords: words(cKeywords), + types: cTypes, + blockKeywords: words(cBlockKeywords), + defKeywords: words(cDefKeywords), + typeFirstDefinitions: true, + atoms: words("NULL true false"), + isReservedIdentifier: cIsReservedIdentifier, + hooks: { + "#": cppHook, + "*": pointerHook, + }, + modeProps: {fold: ["brace", "include"]} + }); + + def(["text/x-c++src", "text/x-c++hdr"], { + name: "clike", + keywords: words(cKeywords + " " + cppKeywords), + types: cTypes, + blockKeywords: words(cBlockKeywords + " class try catch"), + defKeywords: words(cDefKeywords + " class namespace"), + typeFirstDefinitions: true, + atoms: words("true false NULL nullptr"), + dontIndentStatements: /^template$/, + isIdentifierChar: /[\w\$_~\xa1-\uffff]/, + isReservedIdentifier: cIsReservedIdentifier, + hooks: { + "#": cppHook, + "*": pointerHook, + "u": cpp11StringHook, + "U": cpp11StringHook, + "L": cpp11StringHook, + "R": cpp11StringHook, + "0": cpp14Literal, + "1": cpp14Literal, + "2": cpp14Literal, + "3": cpp14Literal, + "4": cpp14Literal, + "5": cpp14Literal, + "6": cpp14Literal, + "7": cpp14Literal, + "8": cpp14Literal, + "9": cpp14Literal, + token: function(stream, state, style) { + if (style == "variable" && stream.peek() == "(" && + (state.prevToken == ";" || state.prevToken == null || + state.prevToken == "}") && + cppLooksLikeConstructor(stream.current())) + return "def"; + } + }, + namespaceSeparator: "::", + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-java", { + name: "clike", + keywords: words("abstract assert break case catch class const continue default " + + "do else enum extends final finally for goto if implements import " + + "instanceof interface native new package private protected public " + + "return static strictfp super switch synchronized this throw throws transient " + + "try volatile while @interface"), + types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + + "Integer Long Number Object Short String StringBuffer StringBuilder Void"), + blockKeywords: words("catch class do else finally for if switch try while"), + defKeywords: words("class interface enum @interface"), + typeFirstDefinitions: true, + atoms: words("true false null"), + number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, + hooks: { + "@": function(stream) { + // Don't match the @interface keyword. + if (stream.match('interface', false)) return false; + + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + }, + modeProps: {fold: ["brace", "import"]} + }); + + def("text/x-csharp", { + name: "clike", + keywords: words("abstract as async await base break case catch checked class const continue" + + " default delegate do else enum event explicit extern finally fixed for" + + " foreach goto if implicit in interface internal is lock namespace new" + + " operator out override params private protected public readonly ref return sealed" + + " sizeof stackalloc static struct switch this throw try typeof unchecked" + + " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + + " global group into join let orderby partial remove select set value var yield"), + types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" + + " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" + + " UInt64 bool byte char decimal double short int long object" + + " sbyte float string ushort uint ulong"), + blockKeywords: words("catch class do else finally for foreach if struct switch try while"), + defKeywords: words("class interface namespace struct var"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: { + "@": function(stream, state) { + if (stream.eat('"')) { + state.tokenize = tokenAtString; + return tokenAtString(stream, state); + } + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); + + function tokenTripleString(stream, state) { + var escaped = false; + while (!stream.eol()) { + if (!escaped && stream.match('"""')) { + state.tokenize = null; + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + function tokenNestedComment(depth) { + return function (stream, state) { + var ch + while (ch = stream.next()) { + if (ch == "*" && stream.eat("/")) { + if (depth == 1) { + state.tokenize = null + break + } else { + state.tokenize = tokenNestedComment(depth - 1) + return state.tokenize(stream, state) + } + } else if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenNestedComment(depth + 1) + return state.tokenize(stream, state) + } + } + return "comment" + } + } + + def("text/x-scala", { + name: "clike", + keywords: words( + /* scala */ + "abstract case catch class def do else extends final finally for forSome if " + + "implicit import lazy match new null object override package private protected return " + + "sealed super this throw trait try type val var while with yield _ " + + + /* package scala */ + "assert assume require print println printf readLine readBoolean readByte readShort " + + "readChar readInt readLong readFloat readDouble" + ), + types: words( + "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + + "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " + + "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + + "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + + "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + + + /* package java.lang */ + "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" + ), + multiLineStrings: true, + blockKeywords: words("catch class enum do else finally for forSome if match switch try while"), + defKeywords: words("class enum def object package trait type val var"), + atoms: words("true false null"), + indentStatements: false, + indentSwitch: false, + isOperatorChar: /[+\-*&%=<>!?|\/#:@]/, + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + }, + '"': function(stream, state) { + if (!stream.match('""')) return false; + state.tokenize = tokenTripleString; + return state.tokenize(stream, state); + }, + "'": function(stream) { + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + return "atom"; + }, + "=": function(stream, state) { + var cx = state.context + if (cx.type == "}" && cx.align && stream.eat(">")) { + state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev) + return "operator" + } else { + return false + } + }, + + "/": function(stream, state) { + if (!stream.eat("*")) return false + state.tokenize = tokenNestedComment(1) + return state.tokenize(stream, state) + } + }, + modeProps: {closeBrackets: {pairs: '()[]{}""', triples: '"'}} + }); + + function tokenKotlinString(tripleString){ + return function (stream, state) { + var escaped = false, next, end = false; + while (!stream.eol()) { + if (!tripleString && !escaped && stream.match('"') ) {end = true; break;} + if (tripleString && stream.match('"""')) {end = true; break;} + next = stream.next(); + if(!escaped && next == "$" && stream.match('{')) + stream.skipTo("}"); + escaped = !escaped && next == "\\" && !tripleString; + } + if (end || !tripleString) + state.tokenize = null; + return "string"; + } + } + + def("text/x-kotlin", { + name: "clike", + keywords: words( + /*keywords*/ + "package as typealias class interface this super val operator " + + "var fun for is in This throw return annotation " + + "break continue object if else while do try when !in !is as? " + + + /*soft keywords*/ + "file import where by get set abstract enum open inner override private public internal " + + "protected catch finally out final vararg reified dynamic companion constructor init " + + "sealed field property receiver param sparam lateinit data inline noinline tailrec " + + "external annotation crossinline const operator infix suspend actual expect setparam" + ), + types: words( + /* package java.lang */ + "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " + + "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " + + "LazyThreadSafetyMode LongArray Nothing ShortArray Unit" + ), + intendSwitch: false, + indentStatements: false, + multiLineStrings: true, + number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, + blockKeywords: words("catch class do else finally for if where try while enum"), + defKeywords: words("class val var object interface fun"), + atoms: words("true false null this"), + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + }, + '*': function(_stream, state) { + return state.prevToken == '.' ? 'variable' : 'operator'; + }, + '"': function(stream, state) { + state.tokenize = tokenKotlinString(stream.match('""')); + return state.tokenize(stream, state); + }, + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenNestedComment(1); + return state.tokenize(stream, state) + }, + indent: function(state, ctx, textAfter, indentUnit) { + var firstChar = textAfter && textAfter.charAt(0); + if ((state.prevToken == "}" || state.prevToken == ")") && textAfter == "") + return state.indented; + if ((state.prevToken == "operator" && textAfter != "}" && state.context.type != "}") || + state.prevToken == "variable" && firstChar == "." || + (state.prevToken == "}" || state.prevToken == ")") && firstChar == ".") + return indentUnit * 2 + ctx.indented; + if (ctx.align && ctx.type == "}") + return ctx.indented + (state.context.type == (textAfter || "").charAt(0) ? 0 : indentUnit); + } + }, + modeProps: {closeBrackets: {triples: '"'}} + }); + + def(["x-shader/x-vertex", "x-shader/x-fragment"], { + name: "clike", + keywords: words("sampler1D sampler2D sampler3D samplerCube " + + "sampler1DShadow sampler2DShadow " + + "const attribute uniform varying " + + "break continue discard return " + + "for while do if else struct " + + "in out inout"), + types: words("float int bool void " + + "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " + + "mat2 mat3 mat4"), + blockKeywords: words("for while do if else struct"), + builtin: words("radians degrees sin cos tan asin acos atan " + + "pow exp log exp2 sqrt inversesqrt " + + "abs sign floor ceil fract mod min max clamp mix step smoothstep " + + "length distance dot cross normalize ftransform faceforward " + + "reflect refract matrixCompMult " + + "lessThan lessThanEqual greaterThan greaterThanEqual " + + "equal notEqual any all not " + + "texture1D texture1DProj texture1DLod texture1DProjLod " + + "texture2D texture2DProj texture2DLod texture2DProjLod " + + "texture3D texture3DProj texture3DLod texture3DProjLod " + + "textureCube textureCubeLod " + + "shadow1D shadow2D shadow1DProj shadow2DProj " + + "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " + + "dFdx dFdy fwidth " + + "noise1 noise2 noise3 noise4"), + atoms: words("true false " + + "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " + + "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " + + "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " + + "gl_FogCoord gl_PointCoord " + + "gl_Position gl_PointSize gl_ClipVertex " + + "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " + + "gl_TexCoord gl_FogFragCoord " + + "gl_FragCoord gl_FrontFacing " + + "gl_FragData gl_FragDepth " + + "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " + + "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " + + "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " + + "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + + "gl_ProjectionMatrixInverseTranspose " + + "gl_ModelViewProjectionMatrixInverseTranspose " + + "gl_TextureMatrixInverseTranspose " + + "gl_NormalScale gl_DepthRange gl_ClipPlane " + + "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " + + "gl_FrontLightModelProduct gl_BackLightModelProduct " + + "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " + + "gl_FogParameters " + + "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " + + "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " + + "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " + + "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " + + "gl_MaxDrawBuffers"), + indentSwitch: false, + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-nesc", { + name: "clike", + keywords: words(cKeywords + " as atomic async call command component components configuration event generic " + + "implementation includes interface module new norace nx_struct nx_union post provides " + + "signal task uses abstract extends"), + types: cTypes, + blockKeywords: words(cBlockKeywords), + atoms: words("null true false"), + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-objectivec", { + name: "clike", + keywords: words(cKeywords + " " + objCKeywords), + types: objCTypes, + builtin: words(objCBuiltins), + blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized"), + defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class"), + dontIndentStatements: /^@.*$/, + typeFirstDefinitions: true, + atoms: words("YES NO NULL Nil nil true false nullptr"), + isReservedIdentifier: cIsReservedIdentifier, + hooks: { + "#": cppHook, + "*": pointerHook, + }, + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-objectivec++", { + name: "clike", + keywords: words(cKeywords + " " + objCKeywords + " " + cppKeywords), + types: objCTypes, + builtin: words(objCBuiltins), + blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch"), + defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class class namespace"), + dontIndentStatements: /^@.*$|^template$/, + typeFirstDefinitions: true, + atoms: words("YES NO NULL Nil nil true false nullptr"), + isReservedIdentifier: cIsReservedIdentifier, + hooks: { + "#": cppHook, + "*": pointerHook, + "u": cpp11StringHook, + "U": cpp11StringHook, + "L": cpp11StringHook, + "R": cpp11StringHook, + "0": cpp14Literal, + "1": cpp14Literal, + "2": cpp14Literal, + "3": cpp14Literal, + "4": cpp14Literal, + "5": cpp14Literal, + "6": cpp14Literal, + "7": cpp14Literal, + "8": cpp14Literal, + "9": cpp14Literal, + token: function(stream, state, style) { + if (style == "variable" && stream.peek() == "(" && + (state.prevToken == ";" || state.prevToken == null || + state.prevToken == "}") && + cppLooksLikeConstructor(stream.current())) + return "def"; + } + }, + namespaceSeparator: "::", + modeProps: {fold: ["brace", "include"]} + }); + + def("text/x-squirrel", { + name: "clike", + keywords: words("base break clone continue const default delete enum extends function in class" + + " foreach local resume return this throw typeof yield constructor instanceof static"), + types: cTypes, + blockKeywords: words("case catch class else for foreach if switch try while"), + defKeywords: words("function local class"), + typeFirstDefinitions: true, + atoms: words("true false null"), + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + + // Ceylon Strings need to deal with interpolation + var stringTokenizer = null; + function tokenCeylonString(type) { + return function(stream, state) { + var escaped = false, next, end = false; + while (!stream.eol()) { + if (!escaped && stream.match('"') && + (type == "single" || stream.match('""'))) { + end = true; + break; + } + if (!escaped && stream.match('``')) { + stringTokenizer = tokenCeylonString(type); + end = true; + break; + } + next = stream.next(); + escaped = type == "single" && !escaped && next == "\\"; + } + if (end) + state.tokenize = null; + return "string"; + } + } + + def("text/x-ceylon", { + name: "clike", + keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" + + " exists extends finally for function given if import in interface is let module new" + + " nonempty object of out outer package return satisfies super switch then this throw" + + " try value void while"), + types: function(word) { + // In Ceylon all identifiers that start with an uppercase are types + var first = word.charAt(0); + return (first === first.toUpperCase() && first !== first.toLowerCase()); + }, + blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"), + defKeywords: words("class dynamic function interface module object package value"), + builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" + + " native optional sealed see serializable shared suppressWarnings tagged throws variable"), + isPunctuationChar: /[\[\]{}\(\),;\:\.`]/, + isOperatorChar: /[+\-*&%=<>!?|^~:\/]/, + numberStart: /[\d#$]/, + number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i, + multiLineStrings: true, + typeFirstDefinitions: true, + atoms: words("true false null larger smaller equal empty finished"), + indentSwitch: false, + styleDefs: false, + hooks: { + "@": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + }, + '"': function(stream, state) { + state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single"); + return state.tokenize(stream, state); + }, + '`': function(stream, state) { + if (!stringTokenizer || !stream.match('`')) return false; + state.tokenize = stringTokenizer; + stringTokenizer = null; + return state.tokenize(stream, state); + }, + "'": function(stream) { + stream.eatWhile(/[\w\$_\xa1-\uffff]/); + return "atom"; + }, + token: function(_stream, state, style) { + if ((style == "variable" || style == "type") && + state.prevToken == ".") { + return "variable-2"; + } + } + }, + modeProps: { + fold: ["brace", "import"], + closeBrackets: {triples: '"'} + } + }); + +}); diff --git a/lib/redactor/codemirror/mode/css/css.js b/lib/redactor/codemirror/mode/css/css.js new file mode 100644 index 0000000..05742c5 --- /dev/null +++ b/lib/redactor/codemirror/mode/css/css.js @@ -0,0 +1,831 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("css", function(config, parserConfig) { + var inline = parserConfig.inline + if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); + + var indentUnit = config.indentUnit, + tokenHooks = parserConfig.tokenHooks, + documentTypes = parserConfig.documentTypes || {}, + mediaTypes = parserConfig.mediaTypes || {}, + mediaFeatures = parserConfig.mediaFeatures || {}, + mediaValueKeywords = parserConfig.mediaValueKeywords || {}, + propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, + fontProperties = parserConfig.fontProperties || {}, + counterDescriptors = parserConfig.counterDescriptors || {}, + colorKeywords = parserConfig.colorKeywords || {}, + valueKeywords = parserConfig.valueKeywords || {}, + allowNested = parserConfig.allowNested, + lineComment = parserConfig.lineComment, + supportsAtComponent = parserConfig.supportsAtComponent === true; + + var type, override; + function ret(style, tp) { type = tp; return style; } + + // Tokenizers + + function tokenBase(stream, state) { + var ch = stream.next(); + if (tokenHooks[ch]) { + var result = tokenHooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == "@") { + stream.eatWhile(/[\w\\\-]/); + return ret("def", stream.current()); + } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) { + return ret(null, "compare"); + } else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "#") { + stream.eatWhile(/[\w\\\-]/); + return ret("atom", "hash"); + } else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (ch === "-") { + if (/[\d.]/.test(stream.peek())) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } else if (stream.match(/^-[\w\\\-]*/)) { + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ret("variable-2", "variable-definition"); + return ret("variable-2", "variable"); + } else if (stream.match(/^\w+-/)) { + return ret("meta", "meta"); + } + } else if (/[,+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) { + return ret("qualifier", "qualifier"); + } else if (/[:;{}\[\]\(\)]/.test(ch)) { + return ret(null, ch); + } else if (stream.match(/[\w-.]+(?=\()/)) { + if (/^(url(-prefix)?|domain|regexp)$/.test(stream.current().toLowerCase())) { + state.tokenize = tokenParenthesized; + } + return ret("variable callee", "variable"); + } else if (/[\w\\\-]/.test(ch)) { + stream.eatWhile(/[\w\\\-]/); + return ret("property", "word"); + } else { + return ret(null, null); + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + if (quote == ")") stream.backUp(1); + break; + } + escaped = !escaped && ch == "\\"; + } + if (ch == quote || !escaped && quote != ")") state.tokenize = null; + return ret("string", "string"); + }; + } + + function tokenParenthesized(stream, state) { + stream.next(); // Must be '(' + if (!stream.match(/\s*[\"\')]/, false)) + state.tokenize = tokenString(")"); + else + state.tokenize = null; + return ret(null, "("); + } + + // Context management + + function Context(type, indent, prev) { + this.type = type; + this.indent = indent; + this.prev = prev; + } + + function pushContext(state, stream, type, indent) { + state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context); + return type; + } + + function popContext(state) { + if (state.context.prev) + state.context = state.context.prev; + return state.context.type; + } + + function pass(type, stream, state) { + return states[state.context.type](type, stream, state); + } + function popAndPass(type, stream, state, n) { + for (var i = n || 1; i > 0; i--) + state.context = state.context.prev; + return pass(type, stream, state); + } + + // Parser + + function wordAsValue(stream) { + var word = stream.current().toLowerCase(); + if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "variable"; + } + + var states = {}; + + states.top = function(type, stream, state) { + if (type == "{") { + return pushContext(state, stream, "block"); + } else if (type == "}" && state.context.prev) { + return popContext(state); + } else if (supportsAtComponent && /@component/i.test(type)) { + return pushContext(state, stream, "atComponentBlock"); + } else if (/^@(-moz-)?document$/i.test(type)) { + return pushContext(state, stream, "documentTypes"); + } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) { + return pushContext(state, stream, "atBlock"); + } else if (/^@(font-face|counter-style)/i.test(type)) { + state.stateArg = type; + return "restricted_atBlock_before"; + } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) { + return "keyframes"; + } else if (type && type.charAt(0) == "@") { + return pushContext(state, stream, "at"); + } else if (type == "hash") { + override = "builtin"; + } else if (type == "word") { + override = "tag"; + } else if (type == "variable-definition") { + return "maybeprop"; + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } else if (type == ":") { + return "pseudo"; + } else if (allowNested && type == "(") { + return pushContext(state, stream, "parens"); + } + return state.context.type; + }; + + states.block = function(type, stream, state) { + if (type == "word") { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { + override = "property"; + return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; + } else if (allowNested) { + override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; + return "block"; + } else { + override += " error"; + return "maybeprop"; + } + } else if (type == "meta") { + return "block"; + } else if (!allowNested && (type == "hash" || type == "qualifier")) { + override = "error"; + return "block"; + } else { + return states.top(type, stream, state); + } + }; + + states.maybeprop = function(type, stream, state) { + if (type == ":") return pushContext(state, stream, "prop"); + return pass(type, stream, state); + }; + + states.prop = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" && allowNested) return pushContext(state, stream, "propBlock"); + if (type == "}" || type == "{") return popAndPass(type, stream, state); + if (type == "(") return pushContext(state, stream, "parens"); + + if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) { + override += " error"; + } else if (type == "word") { + wordAsValue(stream); + } else if (type == "interpolation") { + return pushContext(state, stream, "interpolation"); + } + return "prop"; + }; + + states.propBlock = function(type, _stream, state) { + if (type == "}") return popContext(state); + if (type == "word") { override = "property"; return "maybeprop"; } + return state.context.type; + }; + + states.parens = function(type, stream, state) { + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == ")") return popContext(state); + if (type == "(") return pushContext(state, stream, "parens"); + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + if (type == "word") wordAsValue(stream); + return "parens"; + }; + + states.pseudo = function(type, stream, state) { + if (type == "meta") return "pseudo"; + + if (type == "word") { + override = "variable-3"; + return state.context.type; + } + return pass(type, stream, state); + }; + + states.documentTypes = function(type, stream, state) { + if (type == "word" && documentTypes.hasOwnProperty(stream.current())) { + override = "tag"; + return state.context.type; + } else { + return states.atBlock(type, stream, state); + } + }; + + states.atBlock = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "atBlock_parens"); + if (type == "}" || type == ";") return popAndPass(type, stream, state); + if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); + + if (type == "interpolation") return pushContext(state, stream, "interpolation"); + + if (type == "word") { + var word = stream.current().toLowerCase(); + if (word == "only" || word == "not" || word == "and" || word == "or") + override = "keyword"; + else if (mediaTypes.hasOwnProperty(word)) + override = "attribute"; + else if (mediaFeatures.hasOwnProperty(word)) + override = "property"; + else if (mediaValueKeywords.hasOwnProperty(word)) + override = "keyword"; + else if (propertyKeywords.hasOwnProperty(word)) + override = "property"; + else if (nonStandardPropertyKeywords.hasOwnProperty(word)) + override = "string-2"; + else if (valueKeywords.hasOwnProperty(word)) + override = "atom"; + else if (colorKeywords.hasOwnProperty(word)) + override = "keyword"; + else + override = "error"; + } + return state.context.type; + }; + + states.atComponentBlock = function(type, stream, state) { + if (type == "}") + return popAndPass(type, stream, state); + if (type == "{") + return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false); + if (type == "word") + override = "error"; + return state.context.type; + }; + + states.atBlock_parens = function(type, stream, state) { + if (type == ")") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); + return states.atBlock(type, stream, state); + }; + + states.restricted_atBlock_before = function(type, stream, state) { + if (type == "{") + return pushContext(state, stream, "restricted_atBlock"); + if (type == "word" && state.stateArg == "@counter-style") { + override = "variable"; + return "restricted_atBlock_before"; + } + return pass(type, stream, state); + }; + + states.restricted_atBlock = function(type, stream, state) { + if (type == "}") { + state.stateArg = null; + return popContext(state); + } + if (type == "word") { + if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || + (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) + override = "error"; + else + override = "property"; + return "maybeprop"; + } + return "restricted_atBlock"; + }; + + states.keyframes = function(type, stream, state) { + if (type == "word") { override = "variable"; return "keyframes"; } + if (type == "{") return pushContext(state, stream, "top"); + return pass(type, stream, state); + }; + + states.at = function(type, stream, state) { + if (type == ";") return popContext(state); + if (type == "{" || type == "}") return popAndPass(type, stream, state); + if (type == "word") override = "tag"; + else if (type == "hash") override = "builtin"; + return "at"; + }; + + states.interpolation = function(type, stream, state) { + if (type == "}") return popContext(state); + if (type == "{" || type == ";") return popAndPass(type, stream, state); + if (type == "word") override = "variable"; + else if (type != "variable" && type != "(" && type != ")") override = "error"; + return "interpolation"; + }; + + return { + startState: function(base) { + return {tokenize: null, + state: inline ? "block" : "top", + stateArg: null, + context: new Context(inline ? "block" : "top", base || 0, null)}; + }, + + token: function(stream, state) { + if (!state.tokenize && stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style && typeof style == "object") { + type = style[1]; + style = style[0]; + } + override = style; + if (type != "comment") + state.state = states[state.state](type, stream, state); + return override; + }, + + indent: function(state, textAfter) { + var cx = state.context, ch = textAfter && textAfter.charAt(0); + var indent = cx.indent; + if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; + if (cx.prev) { + if (ch == "}" && (cx.type == "block" || cx.type == "top" || + cx.type == "interpolation" || cx.type == "restricted_atBlock")) { + // Resume indentation from parent context. + cx = cx.prev; + indent = cx.indent; + } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || + ch == "{" && (cx.type == "at" || cx.type == "atBlock")) { + // Dedent relative to current context. + indent = Math.max(0, cx.indent - indentUnit); + } + } + return indent; + }, + + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", + lineComment: lineComment, + fold: "brace" + }; +}); + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i].toLowerCase()] = true; + } + return keys; + } + + var documentTypes_ = [ + "domain", "regexp", "url", "url-prefix" + ], documentTypes = keySet(documentTypes_); + + var mediaTypes_ = [ + "all", "aural", "braille", "handheld", "print", "projection", "screen", + "tty", "tv", "embossed" + ], mediaTypes = keySet(mediaTypes_); + + var mediaFeatures_ = [ + "width", "min-width", "max-width", "height", "min-height", "max-height", + "device-width", "min-device-width", "max-device-width", "device-height", + "min-device-height", "max-device-height", "aspect-ratio", + "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio", + "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color", + "max-color", "color-index", "min-color-index", "max-color-index", + "monochrome", "min-monochrome", "max-monochrome", "resolution", + "min-resolution", "max-resolution", "scan", "grid", "orientation", + "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", + "pointer", "any-pointer", "hover", "any-hover" + ], mediaFeatures = keySet(mediaFeatures_); + + var mediaValueKeywords_ = [ + "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", + "interlace", "progressive" + ], mediaValueKeywords = keySet(mediaValueKeywords_); + + var propertyKeywords_ = [ + "align-content", "align-items", "align-self", "alignment-adjust", + "alignment-baseline", "anchor-point", "animation", "animation-delay", + "animation-direction", "animation-duration", "animation-fill-mode", + "animation-iteration-count", "animation-name", "animation-play-state", + "animation-timing-function", "appearance", "azimuth", "backface-visibility", + "background", "background-attachment", "background-blend-mode", "background-clip", + "background-color", "background-image", "background-origin", "background-position", + "background-repeat", "background-size", "baseline-shift", "binding", + "bleed", "bookmark-label", "bookmark-level", "bookmark-state", + "bookmark-target", "border", "border-bottom", "border-bottom-color", + "border-bottom-left-radius", "border-bottom-right-radius", + "border-bottom-style", "border-bottom-width", "border-collapse", + "border-color", "border-image", "border-image-outset", + "border-image-repeat", "border-image-slice", "border-image-source", + "border-image-width", "border-left", "border-left-color", + "border-left-style", "border-left-width", "border-radius", "border-right", + "border-right-color", "border-right-style", "border-right-width", + "border-spacing", "border-style", "border-top", "border-top-color", + "border-top-left-radius", "border-top-right-radius", "border-top-style", + "border-top-width", "border-width", "bottom", "box-decoration-break", + "box-shadow", "box-sizing", "break-after", "break-before", "break-inside", + "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count", + "column-fill", "column-gap", "column-rule", "column-rule-color", + "column-rule-style", "column-rule-width", "column-span", "column-width", + "columns", "content", "counter-increment", "counter-reset", "crop", "cue", + "cue-after", "cue-before", "cursor", "direction", "display", + "dominant-baseline", "drop-initial-after-adjust", + "drop-initial-after-align", "drop-initial-before-adjust", + "drop-initial-before-align", "drop-initial-size", "drop-initial-value", + "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis", + "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap", + "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings", + "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust", + "font-stretch", "font-style", "font-synthesis", "font-variant", + "font-variant-alternates", "font-variant-caps", "font-variant-east-asian", + "font-variant-ligatures", "font-variant-numeric", "font-variant-position", + "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow", + "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap", + "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap", + "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns", + "grid-template-rows", "hanging-punctuation", "height", "hyphens", + "icon", "image-orientation", "image-rendering", "image-resolution", + "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing", + "line-break", "line-height", "line-stacking", "line-stacking-ruby", + "line-stacking-shift", "line-stacking-strategy", "list-style", + "list-style-image", "list-style-position", "list-style-type", "margin", + "margin-bottom", "margin-left", "margin-right", "margin-top", + "marks", "marquee-direction", "marquee-loop", + "marquee-play-count", "marquee-speed", "marquee-style", "max-height", + "max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index", + "nav-left", "nav-right", "nav-up", "object-fit", "object-position", + "opacity", "order", "orphans", "outline", + "outline-color", "outline-offset", "outline-style", "outline-width", + "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y", + "padding", "padding-bottom", "padding-left", "padding-right", "padding-top", + "page", "page-break-after", "page-break-before", "page-break-inside", + "page-policy", "pause", "pause-after", "pause-before", "perspective", + "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position", + "presentation-level", "punctuation-trim", "quotes", "region-break-after", + "region-break-before", "region-break-inside", "region-fragment", + "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", + "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang", + "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin", + "shape-outside", "size", "speak", "speak-as", "speak-header", + "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set", + "tab-size", "table-layout", "target", "target-name", "target-new", + "target-position", "text-align", "text-align-last", "text-decoration", + "text-decoration-color", "text-decoration-line", "text-decoration-skip", + "text-decoration-style", "text-emphasis", "text-emphasis-color", + "text-emphasis-position", "text-emphasis-style", "text-height", + "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow", + "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position", + "text-wrap", "top", "transform", "transform-origin", "transform-style", + "transition", "transition-delay", "transition-duration", + "transition-property", "transition-timing-function", "unicode-bidi", + "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", + "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", + "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break", + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", + "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", + "color-interpolation", "color-interpolation-filters", + "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", + "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", + "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", + "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", + "glyph-orientation-vertical", "text-anchor", "writing-mode" + ], propertyKeywords = keySet(propertyKeywords_); + + var nonStandardPropertyKeywords_ = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); + + var fontProperties_ = [ + "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", + "font-stretch", "font-weight", "font-style" + ], fontProperties = keySet(fontProperties_); + + var counterDescriptors_ = [ + "additive-symbols", "fallback", "negative", "pad", "prefix", "range", + "speak-as", "suffix", "symbols", "system" + ], counterDescriptors = keySet(counterDescriptors_); + + var colorKeywords_ = [ + "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", + "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", + "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", + "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", + "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", + "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", + "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", + "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", + "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", + "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", + "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", + "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", + "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", + "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", + "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", + "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", + "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", + "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", + "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", + "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", + "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", + "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", + "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", + "whitesmoke", "yellow", "yellowgreen" + ], colorKeywords = keySet(colorKeywords_); + + var valueKeywords_ = [ + "above", "absolute", "activeborder", "additive", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", + "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", + "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", + "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", + "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", + "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", + "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", + "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", + "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", + "compact", "condensed", "contain", "content", "contents", + "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", + "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", + "destination-in", "destination-out", "destination-over", "devanagari", "difference", + "disc", "discard", "disclosure-closed", "disclosure-open", "document", + "dot-dash", "dot-dot-dash", + "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", + "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", + "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", + "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", + "ethiopic-halehame-gez", "ethiopic-halehame-om-et", + "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", + "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", + "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", + "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", + "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", + "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", + "help", "hidden", "hide", "higher", "highlight", "highlighttext", + "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore", + "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", + "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", + "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert", + "italic", "japanese-formal", "japanese-informal", "justify", "kannada", + "katakana", "katakana-iroha", "keep-all", "khmer", + "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", + "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten", + "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", + "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", + "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", + "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d", + "media-controls-background", "media-current-time-display", + "media-fullscreen-button", "media-mute-button", "media-play-button", + "media-return-to-realtime-button", "media-rewind-button", + "media-seek-back-button", "media-seek-forward-button", "media-slider", + "media-sliderthumb", "media-time-remaining-display", "media-volume-slider", + "media-volume-slider-container", "media-volume-sliderthumb", "medium", + "menu", "menulist", "menulist-button", "menulist-text", + "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", + "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", + "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", + "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", + "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", + "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", + "progress", "push-button", "radial-gradient", "radio", "read-only", + "read-write", "read-write-plaintext-only", "rectangle", "region", + "relative", "repeat", "repeating-linear-gradient", + "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", + "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", + "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", + "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", + "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", + "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end", + "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "simp-chinese-formal", "simp-chinese-informal", "single", + "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", + "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", + "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", + "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", + "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", + "table-caption", "table-cell", "table-column", "table-column-group", + "table-footer-group", "table-header-group", "table-row", "table-row-group", + "tamil", + "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", + "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", + "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", + "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", + "trad-chinese-formal", "trad-chinese-informal", "transform", + "translate", "translate3d", "translateX", "translateY", "translateZ", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up", + "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", + "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", + "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", + "xx-large", "xx-small" + ], valueKeywords = keySet(valueKeywords_); + + var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_) + .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_) + .concat(valueKeywords_); + CodeMirror.registerHelper("hintWords", "css", allWords); + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + CodeMirror.defineMIME("text/css", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css" + }); + + CodeMirror.defineMIME("text/x-scss", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + lineComment: "//", + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + ":": function(stream) { + if (stream.match(/\s*\{/, false)) + return [null, null] + return false; + }, + "$": function(stream) { + stream.match(/^[\w-]+/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "#": function(stream) { + if (!stream.eat("{")) return false; + return [null, "interpolation"]; + } + }, + name: "css", + helperType: "scss" + }); + + CodeMirror.defineMIME("text/x-less", { + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + mediaValueKeywords: mediaValueKeywords, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + fontProperties: fontProperties, + allowNested: true, + lineComment: "//", + tokenHooks: { + "/": function(stream, state) { + if (stream.eat("/")) { + stream.skipToEnd(); + return ["comment", "comment"]; + } else if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + "@": function(stream) { + if (stream.eat("{")) return [null, "interpolation"]; + if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false; + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ["variable-2", "variable-definition"]; + return ["variable-2", "variable"]; + }, + "&": function() { + return ["atom", "atom"]; + } + }, + name: "css", + helperType: "less" + }); + + CodeMirror.defineMIME("text/x-gss", { + documentTypes: documentTypes, + mediaTypes: mediaTypes, + mediaFeatures: mediaFeatures, + propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, + supportsAtComponent: true, + tokenHooks: { + "/": function(stream, state) { + if (!stream.eat("*")) return false; + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + }, + name: "css", + helperType: "gss" + }); + +}); diff --git a/lib/redactor/codemirror/mode/htmlembedded/htmlembedded.js b/lib/redactor/codemirror/mode/htmlembedded/htmlembedded.js new file mode 100644 index 0000000..439e63a --- /dev/null +++ b/lib/redactor/codemirror/mode/htmlembedded/htmlembedded.js @@ -0,0 +1,37 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), + require("../../addon/mode/multiplex")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", + "../../addon/mode/multiplex"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { + var closeComment = parserConfig.closeComment || "--%>" + return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), { + open: parserConfig.openComment || "<%--", + close: closeComment, + delimStyle: "comment", + mode: {token: function(stream) { + stream.skipTo(closeComment) || stream.skipToEnd() + return "comment" + }} + }, { + open: parserConfig.open || parserConfig.scriptStartRegex || "<%", + close: parserConfig.close || parserConfig.scriptEndRegex || "%>", + mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec) + }); + }, "htmlmixed"); + + CodeMirror.defineMIME("application/x-ejs", {name: "htmlembedded", scriptingModeSpec:"javascript"}); + CodeMirror.defineMIME("application/x-aspx", {name: "htmlembedded", scriptingModeSpec:"text/x-csharp"}); + CodeMirror.defineMIME("application/x-jsp", {name: "htmlembedded", scriptingModeSpec:"text/x-java"}); + CodeMirror.defineMIME("application/x-erb", {name: "htmlembedded", scriptingModeSpec:"ruby"}); +}); diff --git a/lib/redactor/codemirror/mode/htmlmixed/htmlmixed.js b/lib/redactor/codemirror/mode/htmlmixed/htmlmixed.js new file mode 100644 index 0000000..8341ac8 --- /dev/null +++ b/lib/redactor/codemirror/mode/htmlmixed/htmlmixed.js @@ -0,0 +1,152 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + var defaultTags = { + script: [ + ["lang", /(javascript|babel)/i, "javascript"], + ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"], + ["type", /./, "text/plain"], + [null, null, "javascript"] + ], + style: [ + ["lang", /^css$/i, "css"], + ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"], + ["type", /./, "text/plain"], + [null, null, "css"] + ] + }; + + function maybeBackup(stream, pat, style) { + var cur = stream.current(), close = cur.search(pat); + if (close > -1) { + stream.backUp(cur.length - close); + } else if (cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur); + } + return style; + } + + var attrRegexpCache = {}; + function getAttrRegexp(attr) { + var regexp = attrRegexpCache[attr]; + if (regexp) return regexp; + return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*"); + } + + function getAttrValue(text, attr) { + var match = text.match(getAttrRegexp(attr)) + return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : "" + } + + function getTagRegexp(tagName, anchored) { + return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i"); + } + + function addTags(from, to) { + for (var tag in from) { + var dest = to[tag] || (to[tag] = []); + var source = from[tag]; + for (var i = source.length - 1; i >= 0; i--) + dest.unshift(source[i]) + } + } + + function findMatchingMode(tagInfo, tagText) { + for (var i = 0; i < tagInfo.length; i++) { + var spec = tagInfo[i]; + if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2]; + } + } + + CodeMirror.defineMode("htmlmixed", function (config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, { + name: "xml", + htmlMode: true, + multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag + }); + + var tags = {}; + var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes; + addTags(defaultTags, tags); + if (configTags) addTags(configTags, tags); + if (configScript) for (var i = configScript.length - 1; i >= 0; i--) + tags.script.unshift(["type", configScript[i].matches, configScript[i].mode]) + + function html(stream, state) { + var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName + if (tag && !/[<>\s\/]/.test(stream.current()) && + (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) && + tags.hasOwnProperty(tagName)) { + state.inTag = tagName + " " + } else if (state.inTag && tag && />$/.test(stream.current())) { + var inTag = /^([\S]+) (.*)/.exec(state.inTag) + state.inTag = null + var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2]) + var mode = CodeMirror.getMode(config, modeSpec) + var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false); + state.token = function (stream, state) { + if (stream.match(endTagA, false)) { + state.token = html; + state.localState = state.localMode = null; + return null; + } + return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState)); + }; + state.localMode = mode; + state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, "", "")); + } else if (state.inTag) { + state.inTag += stream.current() + if (stream.eol()) state.inTag += " " + } + return style; + }; + + return { + startState: function () { + var state = CodeMirror.startState(htmlMode); + return {token: html, inTag: null, localMode: null, localState: null, htmlState: state}; + }, + + copyState: function (state) { + var local; + if (state.localState) { + local = CodeMirror.copyState(state.localMode, state.localState); + } + return {token: state.token, inTag: state.inTag, + localMode: state.localMode, localState: local, + htmlState: CodeMirror.copyState(htmlMode, state.htmlState)}; + }, + + token: function (stream, state) { + return state.token(stream, state); + }, + + indent: function (state, textAfter, line) { + if (!state.localMode || /^\s*<\//.test(textAfter)) + return htmlMode.indent(state.htmlState, textAfter, line); + else if (state.localMode.indent) + return state.localMode.indent(state.localState, textAfter, line); + else + return CodeMirror.Pass; + }, + + innerMode: function (state) { + return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode}; + } + }; + }, "xml", "javascript", "css"); + + CodeMirror.defineMIME("text/html", "htmlmixed"); +}); diff --git a/lib/redactor/codemirror/mode/javascript/javascript.js b/lib/redactor/codemirror/mode/javascript/javascript.js new file mode 100644 index 0000000..16943a9 --- /dev/null +++ b/lib/redactor/codemirror/mode/javascript/javascript.js @@ -0,0 +1,930 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("javascript", function(config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; + + // Tokenizer + + var keywords = function(){ + function kw(type) {return {type: type, style: "keyword"};} + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d"); + var operator = kw("operator"), atom = {type: "atom", style: "atom"}; + + return { + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C, + "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this"), "class": kw("class"), "super": kw("atom"), + "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, + "await": C + }; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|~^@]/; + var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, next, inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == "/" && !inSet) return; + if (next == "[") inSet = true; + else if (inSet && next == "]") inSet = false; + } + escaped = !escaped && next == "\\"; + } + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "." && stream.match(/^\d[\d_]*(?:[eE][+\-]?[\d_]+)?/)) { + return ret("number", "number"); + } else if (ch == "." && stream.match("..")) { + return ret("spread", "meta"); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == "=" && stream.eat(">")) { + return ret("=>", "operator"); + } else if (ch == "0" && stream.match(/^(?:x[\dA-Fa-f_]+|o[0-7_]+|b[01_]+)n?/)) { + return ret("number", "number"); + } else if (/\d/.test(ch)) { + stream.match(/^[\d_]*(?:n|(?:\.[\d_]*)?(?:[eE][+\-]?[\d_]+)?)?/); + return ret("number", "number"); + } else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else if (expressionAllowed(stream, state, 1)) { + readRegexp(stream); + stream.match(/^\b(([gimyus])(?![gimyus]*\2))+\b/); + return ret("regexp", "string-2"); + } else { + stream.eat("="); + return ret("operator", "operator", stream.current()); + } + } else if (ch == "`") { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } else if (ch == "<" && stream.match("!--") || ch == "-" && stream.match("->")) { + stream.skipToEnd() + return ret("comment", "comment") + } else if (isOperatorChar.test(ch)) { + if (ch != ">" || !state.lexical || state.lexical.type != ">") { + if (stream.eat("=")) { + if (ch == "!" || ch == "=") stream.eat("=") + } else if (/[<>*+\-]/.test(ch)) { + stream.eat(ch) + if (ch == ">") stream.eat(ch) + } + } + return ret("operator", "operator", stream.current()); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); + var word = stream.current() + if (state.lastType != ".") { + if (keywords.propertyIsEnumerable(word)) { + var kw = keywords[word] + return ret(kw.type, kw.style, word) + } + if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false)) + return ret("async", "keyword", word) + } + return ret("variable", "variable", word) + } + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next; + if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){ + state.tokenize = tokenBase; + return ret("jsonld-keyword", "meta"); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenQuasi(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == "\\"; + } + return ret("quasi", "string-2", stream.current()); + } + + var brackets = "([{}])"; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf("=>", stream.start); + if (arrow < 0) return; + + if (isTS) { // Try to skip TypeScript return type declarations after the arguments + var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow)) + if (m) arrow = m.index + } + + var depth = 0, sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { ++pos; break; } + if (--depth == 0) { if (ch == "(") sawSomething = true; break; } + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (wordRE.test(ch)) { + sawSomething = true; + } else if (/["'\/`]/.test(ch)) { + for (;; --pos) { + if (pos == 0) return + var next = stream.string.charAt(pos - 1) + if (next == ch && stream.string.charAt(pos - 2) != "\\") { pos--; break } + } + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true}; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while(true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while(cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = {state: null, column: null, marked: null, cc: null}; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function inList(name, list) { + for (var v = list; v; v = v.next) if (v.name == name) return true + return false; + } + function register(varname) { + var state = cx.state; + cx.marked = "def"; + if (state.context) { + if (state.lexical.info == "var" && state.context && state.context.block) { + // FIXME function decls are also not block scoped + var newContext = registerVarScoped(varname, state.context) + if (newContext != null) { + state.context = newContext + return + } + } else if (!inList(varname, state.localVars)) { + state.localVars = new Var(varname, state.localVars) + return + } + } + // Fall through means this is global + if (parserConfig.globalVars && !inList(varname, state.globalVars)) + state.globalVars = new Var(varname, state.globalVars) + } + function registerVarScoped(varname, context) { + if (!context) { + return null + } else if (context.block) { + var inner = registerVarScoped(varname, context.prev) + if (!inner) return null + if (inner == context.prev) return context + return new Context(inner, context.vars, true) + } else if (inList(varname, context.vars)) { + return context + } else { + return new Context(context.prev, new Var(varname, context.vars), false) + } + } + + function isModifier(name) { + return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly" + } + + // Combinators + + function Context(prev, vars, block) { this.prev = prev; this.vars = vars; this.block = block } + function Var(name, next) { this.name = name; this.next = next } + + var defaultVars = new Var("this", new Var("arguments", null)) + function pushcontext() { + cx.state.context = new Context(cx.state.context, cx.state.localVars, false) + cx.state.localVars = defaultVars + } + function pushblockcontext() { + cx.state.context = new Context(cx.state.context, cx.state.localVars, true) + cx.state.localVars = null + } + function popcontext() { + cx.state.localVars = cx.state.context.vars + cx.state.context = cx.state.context.prev + } + popcontext.lex = true + function pushlex(type, info) { + var result = function() { + var state = cx.state, indent = state.indented; + if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; + state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ";" || type == "}" || type == ")" || type == "]") return pass(); + else return cont(exp); + }; + return exp; + } + + function statement(type, value) { + if (type == "var") return cont(pushlex("vardef", value), vardef, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex); + if (type == "debugger") return cont(expect(";")); + if (type == "{") return cont(pushlex("}"), pushblockcontext, block, poplex, popcontext); + if (type == ";") return cont(); + if (type == "if") { + if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) + cx.state.cc.pop()(); + return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); + } + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "class" || (isTS && value == "interface")) { + cx.marked = "keyword" + return cont(pushlex("form", type == "class" ? type : value), className, poplex) + } + if (type == "variable") { + if (isTS && value == "declare") { + cx.marked = "keyword" + return cont(statement) + } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) { + cx.marked = "keyword" + if (value == "enum") return cont(enumdef); + else if (value == "type") return cont(typename, expect("operator"), typeexpr, expect(";")); + else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) + } else if (isTS && value == "namespace") { + cx.marked = "keyword" + return cont(pushlex("form"), expression, statement, poplex) + } else if (isTS && value == "abstract") { + cx.marked = "keyword" + return cont(statement) + } else { + return cont(pushlex("stat"), maybelabel); + } + } + if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"), pushblockcontext, + block, poplex, poplex, popcontext); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, maybeCatchBinding, statement, poplex, popcontext); + if (type == "export") return cont(pushlex("stat"), afterExport, poplex); + if (type == "import") return cont(pushlex("stat"), afterImport, poplex); + if (type == "async") return cont(statement) + if (value == "@") return cont(expression, statement) + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function maybeCatchBinding(type) { + if (type == "(") return cont(funarg, expect(")")) + } + function expression(type, value) { + return expressionInner(type, value, false); + } + function expressionNoComma(type, value) { + return expressionInner(type, value, true); + } + function parenExpr(type) { + if (type != "(") return pass() + return cont(pushlex(")"), expression, expect(")"), poplex) + } + function expressionInner(type, value, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext); + else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == "function") return cont(functiondef, maybeop); + if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); } + if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression); + if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); + if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); + if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); + if (type == "{") return contCommasep(objprop, "}", null, maybeop); + if (type == "quasi") return pass(quasi, maybeop); + if (type == "new") return cont(maybeTarget(noComma)); + if (type == "import") return cont(expression); + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "operator") { + if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); + if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false)) + return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me); + if (value == "?") return cont(expression, expect(":"), expr); + return cont(expr); + } + if (type == "quasi") { return pass(quasi, me); } + if (type == ";") return; + if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); + if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) } + if (type == "regexp") { + cx.state.lastType = cx.marked = "operator" + cx.stream.backUp(cx.stream.pos - cx.stream.start - 1) + return cont(expr) + } + } + function quasi(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expressionNoComma); + } + function maybeTarget(noComma) { + return function(type) { + if (type == ".") return cont(noComma ? targetNoComma : target); + else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma) + else return pass(noComma ? expressionNoComma : expression); + }; + } + function target(_, value) { + if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } + } + function targetNoComma(_, value) { + if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperatorComma, expect(";"), poplex); + } + function property(type) { + if (type == "variable") {cx.marked = "property"; return cont();} + } + function objprop(type, value) { + if (type == "async") { + cx.marked = "property"; + return cont(objprop); + } else if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(getterSetter); + var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params + if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false))) + cx.state.fatArrowAt = cx.stream.pos + m[0].length + return cont(afterprop); + } else if (type == "number" || type == "string") { + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); + } else if (isTS && isModifier(value)) { + cx.marked = "keyword" + return cont(objprop) + } else if (type == "[") { + return cont(expression, maybetype, expect("]"), afterprop); + } else if (type == "spread") { + return cont(expressionNoComma, afterprop); + } else if (value == "*") { + cx.marked = "keyword"; + return cont(objprop); + } else if (type == ":") { + return pass(afterprop) + } + } + function getterSetter(type) { + if (type != "variable") return pass(afterprop); + cx.marked = "property"; + return cont(functiondef); + } + function afterprop(type) { + if (type == ":") return cont(expressionNoComma); + if (type == "(") return pass(functiondef); + } + function commasep(what, end, sep) { + function proceed(type, value) { + if (sep ? sep.indexOf(type) > -1 : type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(function(type, value) { + if (type == end || value == end) return pass() + return pass(what) + }, proceed); + } + if (type == end || value == end) return cont(); + if (sep && sep.indexOf(";") > -1) return pass(what) + return cont(expect(end)); + } + return function(type, value) { + if (type == end || value == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) + cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function maybetype(type, value) { + if (isTS) { + if (type == ":") return cont(typeexpr); + if (value == "?") return cont(maybetype); + } + } + function maybetypeOrIn(type, value) { + if (isTS && (type == ":" || value == "in")) return cont(typeexpr) + } + function mayberettype(type) { + if (isTS && type == ":") { + if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr) + else return cont(typeexpr) + } + } + function isKW(_, value) { + if (value == "is") { + cx.marked = "keyword" + return cont() + } + } + function typeexpr(type, value) { + if (value == "keyof" || value == "typeof" || value == "infer") { + cx.marked = "keyword" + return cont(value == "typeof" ? expressionNoComma : typeexpr) + } + if (type == "variable" || value == "void") { + cx.marked = "type" + return cont(afterType) + } + if (value == "|" || value == "&") return cont(typeexpr) + if (type == "string" || type == "number" || type == "atom") return cont(afterType); + if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) + if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) + if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType) + if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) + } + function maybeReturnType(type) { + if (type == "=>") return cont(typeexpr) + } + function typeprop(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property" + return cont(typeprop) + } else if (value == "?" || type == "number" || type == "string") { + return cont(typeprop) + } else if (type == ":") { + return cont(typeexpr) + } else if (type == "[") { + return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop) + } else if (type == "(") { + return pass(functiondecl, typeprop) + } + } + function typearg(type, value) { + if (type == "variable" && cx.stream.match(/^\s*[?:]/, false) || value == "?") return cont(typearg) + if (type == ":") return cont(typeexpr) + if (type == "spread") return cont(typearg) + return pass(typeexpr) + } + function afterType(type, value) { + if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) + if (value == "|" || type == "." || value == "&") return cont(typeexpr) + if (type == "[") return cont(typeexpr, expect("]"), afterType) + if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } + if (value == "?") return cont(typeexpr, expect(":"), typeexpr) + } + function maybeTypeArgs(_, value) { + if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) + } + function typeparam() { + return pass(typeexpr, maybeTypeDefault) + } + function maybeTypeDefault(_, value) { + if (value == "=") return cont(typeexpr) + } + function vardef(_, value) { + if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)} + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) } + if (type == "variable") { register(value); return cont(); } + if (type == "spread") return cont(pattern); + if (type == "[") return contCommasep(eltpattern, "]"); + if (type == "{") return contCommasep(proppattern, "}"); + } + function proppattern(type, value) { + if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == "variable") cx.marked = "property"; + if (type == "spread") return cont(pattern); + if (type == "}") return pass(); + if (type == "[") return cont(expression, expect(']'), expect(':'), proppattern); + return cont(expect(":"), pattern, maybeAssign); + } + function eltpattern() { + return pass(pattern, maybeAssign) + } + function maybeAssign(_type, value) { + if (value == "=") return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ",") return cont(vardef); + } + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); + } + function forspec(type, value) { + if (value == "await") return cont(forspec); + if (type == "(") return cont(pushlex(")"), forspec1, poplex); + } + function forspec1(type) { + if (type == "var") return cont(vardef, forspec2); + if (type == "variable") return cont(forspec2); + return pass(forspec2) + } + function forspec2(type, value) { + if (type == ")") return cont() + if (type == ";") return cont(forspec2) + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression, forspec2) } + return pass(expression, forspec2) + } + function functiondef(type, value) { + if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} + if (type == "variable") {register(value); return cont(functiondef);} + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext); + if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef) + } + function functiondecl(type, value) { + if (value == "*") {cx.marked = "keyword"; return cont(functiondecl);} + if (type == "variable") {register(value); return cont(functiondecl);} + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, popcontext); + if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondecl) + } + function typename(type, value) { + if (type == "keyword" || type == "variable") { + cx.marked = "type" + return cont(typename) + } else if (value == "<") { + return cont(pushlex(">"), commasep(typeparam, ">"), poplex) + } + } + function funarg(type, value) { + if (value == "@") cont(expression, funarg) + if (type == "spread") return cont(funarg); + if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); } + if (isTS && type == "this") return cont(maybetype, maybeAssign) + return pass(pattern, maybetype, maybeAssign); + } + function classExpression(type, value) { + // Class expressions may have an optional name. + if (type == "variable") return className(type, value); + return classNameAfter(type, value); + } + function className(type, value) { + if (type == "variable") {register(value); return cont(classNameAfter);} + } + function classNameAfter(type, value) { + if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) + if (value == "extends" || value == "implements" || (isTS && type == ",")) { + if (value == "implements") cx.marked = "keyword"; + return cont(isTS ? typeexpr : expression, classNameAfter); + } + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "async" || + (type == "variable" && + (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) && + cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + return cont(isTS ? classfield : functiondef, classBody); + } + if (type == "number" || type == "string") return cont(isTS ? classfield : functiondef, classBody); + if (type == "[") + return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody) + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (isTS && type == "(") return pass(functiondecl, classBody) + if (type == ";" || type == ",") return cont(classBody); + if (type == "}") return cont(); + if (value == "@") return cont(expression, classBody) + } + function classfield(type, value) { + if (value == "?") return cont(classfield) + if (type == ":") return cont(typeexpr, maybeAssign) + if (value == "=") return cont(expressionNoComma) + var context = cx.state.lexical.prev, isInterface = context && context.info == "interface" + return pass(isInterface ? functiondecl : functiondef) + } + function afterExport(type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } + if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";")); + return pass(statement); + } + function exportField(type, value) { + if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); } + if (type == "variable") return pass(expressionNoComma, exportField); + } + function afterImport(type) { + if (type == "string") return cont(); + if (type == "(") return pass(expression); + return pass(importSpec, maybeMoreImports, maybeFrom); + } + function importSpec(type, value) { + if (type == "{") return contCommasep(importSpec, "}"); + if (type == "variable") register(value); + if (value == "*") cx.marked = "keyword"; + return cont(maybeAs); + } + function maybeMoreImports(type) { + if (type == ",") return cont(importSpec, maybeMoreImports) + } + function maybeAs(_type, value) { + if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } + } + function maybeFrom(_type, value) { + if (value == "from") { cx.marked = "keyword"; return cont(expression); } + } + function arrayLiteral(type) { + if (type == "]") return cont(); + return pass(commasep(expressionNoComma, "]")); + } + function enumdef() { + return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex) + } + function enummember() { + return pass(pattern, maybeAssign); + } + + function isContinuedStatement(state, textAfter) { + return state.lastType == "operator" || state.lastType == "," || + isOperatorChar.test(textAfter.charAt(0)) || + /[,.]/.test(textAfter.charAt(0)); + } + + function expressionAllowed(stream, state, backUp) { + return state.tokenize == tokenBase && + /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) || + (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) + } + + // Interface + + return { + startState: function(basecolumn) { + var state = { + tokenize: tokenBase, + lastType: "sof", + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && new Context(null, null, false), + indented: basecolumn || 0 + }; + if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function(state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + while ((lexical.type == "stat" || lexical.type == "form") && + (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && + (top == maybeoperatorComma || top == maybeoperatorNoComma) && + !/^[,\.=+\-*:?[\(]/.test(textAfter)))) + lexical = lexical.prev; + if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") + lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info.length + 1 : 0); + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "form") return lexical.indented + indentUnit; + else if (type == "stat") + return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); + else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + blockCommentContinue: jsonMode ? null : " * ", + lineComment: jsonMode ? null : "//", + fold: "brace", + closeBrackets: "()[]{}''\"\"``", + + helperType: jsonMode ? "json" : "javascript", + jsonldMode: jsonldMode, + jsonMode: jsonMode, + + expressionAllowed: expressionAllowed, + + skipExpression: function(state) { + var top = state.cc[state.cc.length - 1] + if (top == expression || top == expressionNoComma) state.cc.pop() + } + }; +}); + +CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); + +CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("text/ecmascript", "javascript"); +CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/x-javascript", "javascript"); +CodeMirror.defineMIME("application/ecmascript", "javascript"); +CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); +CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); +CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + +}); diff --git a/lib/redactor/codemirror/mode/meta.js b/lib/redactor/codemirror/mode/meta.js new file mode 100644 index 0000000..d44590f --- /dev/null +++ b/lib/redactor/codemirror/mode/meta.js @@ -0,0 +1,220 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.modeInfo = [ + {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]}, + {name: "PGP", mimes: ["application/pgp", "application/pgp-encrypted", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["asc", "pgp", "sig"]}, + {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]}, + {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i}, + {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]}, + {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]}, + {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, + {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, + {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp", "cs"]}, + {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]}, + {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]}, + {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]}, + {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, + {name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, + {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]}, + {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]}, + {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]}, + {name: "Crystal", mime: "text/x-crystal", mode: "crystal", ext: ["cr"]}, + {name: "CSS", mime: "text/css", mode: "css", ext: ["css"]}, + {name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]}, + {name: "D", mime: "text/x-d", mode: "d", ext: ["d"]}, + {name: "Dart", mimes: ["application/dart", "text/x-dart"], mode: "dart", ext: ["dart"]}, + {name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]}, + {name: "Django", mime: "text/x-django", mode: "django"}, + {name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile", file: /^Dockerfile$/}, + {name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]}, + {name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]}, + {name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"}, + {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]}, + {name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]}, + {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]}, + {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]}, + {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, + {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]}, + {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]}, + {name: "Esper", mime: "text/x-esper", mode: "sql"}, + {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]}, + {name: "FCL", mime: "text/x-fcl", mode: "fcl"}, + {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]}, + {name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90", "f95"]}, + {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]}, + {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]}, + {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]}, + {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i}, + {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]}, + {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/}, + {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]}, + {name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]}, + {name: "Haskell (Literate)", mime: "text/x-literate-haskell", mode: "haskell-literate", ext: ["lhs"]}, + {name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]}, + {name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]}, + {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]}, + {name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm", "handlebars", "hbs"], alias: ["xhtml"]}, + {name: "HTTP", mime: "message/http", mode: "http"}, + {name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]}, + {name: "Pug", mime: "text/x-pug", mode: "pug", ext: ["jade", "pug"], alias: ["jade"]}, + {name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]}, + {name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]}, + {name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"], + mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]}, + {name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]}, + {name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]}, + {name: "JSX", mime: "text/jsx", mode: "jsx", ext: ["jsx"]}, + {name: "Jinja2", mime: "text/jinja2", mode: "jinja2", ext: ["j2", "jinja", "jinja2"]}, + {name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]}, + {name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]}, + {name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]}, + {name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]}, + {name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]}, + {name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]}, + {name: "mIRC", mime: "text/mirc", mode: "mirc"}, + {name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"}, + {name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb", "wl", "wls"]}, + {name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]}, + {name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]}, + {name: "MS SQL", mime: "text/x-mssql", mode: "sql"}, + {name: "mbox", mime: "application/mbox", mode: "mbox", ext: ["mbox"]}, + {name: "MySQL", mime: "text/x-mysql", mode: "sql"}, + {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i}, + {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]}, + {name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"], + mode: "ntriples", ext: ["nt", "nq"]}, + {name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m"], alias: ["objective-c", "objc"]}, + {name: "Objective-C++", mime: "text/x-objectivec++", mode: "clike", ext: ["mm"], alias: ["objective-c++", "objc++"]}, + {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]}, + {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]}, + {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]}, + {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]}, + {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]}, + {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]}, + {name: "PHP", mimes: ["text/x-php", "application/x-httpd-php", "application/x-httpd-php-open"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]}, + {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, + {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, + {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, + {name: "PostgreSQL", mime: "text/x-pgsql", mode: "sql"}, + {name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]}, + {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]}, + {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]}, + {name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/}, + {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, + {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, + {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r", "R"], alias: ["rscript"]}, + {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]}, + {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"}, + {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]}, + {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]}, + {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]}, + {name: "SAS", mime: "text/x-sas", mode: "sas", ext: ["sas"]}, + {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]}, + {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]}, + {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]}, + {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]}, + {name: "Shell", mimes: ["text/x-sh", "application/x-sh"], mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/}, + {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]}, + {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]}, + {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]}, + {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]}, + {name: "Solr", mime: "text/x-solr", mode: "solr"}, + {name: "SML", mime: "text/x-sml", mode: "mllike", ext: ["sml", "sig", "fun", "smackspec"]}, + {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]}, + {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]}, + {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]}, + {name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]}, + {name: "SQLite", mime: "text/x-sqlite", mode: "sql"}, + {name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]}, + {name: "Stylus", mime: "text/x-styl", mode: "stylus", ext: ["styl"]}, + {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]}, + {name: "sTeX", mime: "text/x-stex", mode: "stex"}, + {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx", "tex"], alias: ["tex"]}, + {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]}, + {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]}, + {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]}, + {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"}, + {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"}, + {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]}, + {name: "Tornado", mime: "text/x-tornado", mode: "tornado"}, + {name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]}, + {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]}, + {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]}, + {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]}, + {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]}, + {name: "TypeScript-JSX", mime: "text/typescript-jsx", mode: "jsx", ext: ["tsx"], alias: ["tsx"]}, + {name: "Twig", mime: "text/x-twig", mode: "twig"}, + {name: "Web IDL", mime: "text/x-webidl", mode: "webidl", ext: ["webidl"]}, + {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]}, + {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]}, + {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]}, + {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]}, + {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]}, + {name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]}, + {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd", "svg"], alias: ["rss", "wsdl", "xsd"]}, + {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, + {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]}, + {name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]}, + {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]}, + {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]}, + {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]}, + {name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]} + ]; + // Ensure all modes have a mime property for backwards compatibility + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.mimes) info.mime = info.mimes[0]; + } + + CodeMirror.findModeByMIME = function(mime) { + mime = mime.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.mime == mime) return info; + if (info.mimes) for (var j = 0; j < info.mimes.length; j++) + if (info.mimes[j] == mime) return info; + } + if (/\+xml$/.test(mime)) return CodeMirror.findModeByMIME("application/xml") + if (/\+json$/.test(mime)) return CodeMirror.findModeByMIME("application/json") + }; + + CodeMirror.findModeByExtension = function(ext) { + ext = ext.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.ext) for (var j = 0; j < info.ext.length; j++) + if (info.ext[j] == ext) return info; + } + }; + + CodeMirror.findModeByFileName = function(filename) { + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.file && info.file.test(filename)) return info; + } + var dot = filename.lastIndexOf("."); + var ext = dot > -1 && filename.substring(dot + 1, filename.length); + if (ext) return CodeMirror.findModeByExtension(ext); + }; + + CodeMirror.findModeByName = function(name) { + name = name.toLowerCase(); + for (var i = 0; i < CodeMirror.modeInfo.length; i++) { + var info = CodeMirror.modeInfo[i]; + if (info.name.toLowerCase() == name) return info; + if (info.alias) for (var j = 0; j < info.alias.length; j++) + if (info.alias[j].toLowerCase() == name) return info; + } + }; +}); diff --git a/lib/redactor/codemirror/mode/php/php.js b/lib/redactor/codemirror/mode/php/php.js new file mode 100644 index 0000000..5f3a143 --- /dev/null +++ b/lib/redactor/codemirror/mode/php/php.js @@ -0,0 +1,234 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../clike/clike"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // Helper for phpString + function matchSequence(list, end, escapes) { + if (list.length == 0) return phpString(end); + return function (stream, state) { + var patterns = list[0]; + for (var i = 0; i < patterns.length; i++) if (stream.match(patterns[i][0])) { + state.tokenize = matchSequence(list.slice(1), end); + return patterns[i][1]; + } + state.tokenize = phpString(end, escapes); + return "string"; + }; + } + function phpString(closing, escapes) { + return function(stream, state) { return phpString_(stream, state, closing, escapes); }; + } + function phpString_(stream, state, closing, escapes) { + // "Complex" syntax + if (escapes !== false && stream.match("${", false) || stream.match("{$", false)) { + state.tokenize = null; + return "string"; + } + + // Simple syntax + if (escapes !== false && stream.match(/^\$[a-zA-Z_][a-zA-Z0-9_]*/)) { + // After the variable name there may appear array or object operator. + if (stream.match("[", false)) { + // Match array operator + state.tokenize = matchSequence([ + [["[", null]], + [[/\d[\w\.]*/, "number"], + [/\$[a-zA-Z_][a-zA-Z0-9_]*/, "variable-2"], + [/[\w\$]+/, "variable"]], + [["]", null]] + ], closing, escapes); + } + if (stream.match(/\-\>\w/, false)) { + // Match object operator + state.tokenize = matchSequence([ + [["->", null]], + [[/[\w]+/, "variable"]] + ], closing, escapes); + } + return "variable-2"; + } + + var escaped = false; + // Normal string + while (!stream.eol() && + (escaped || escapes === false || + (!stream.match("{$", false) && + !stream.match(/^(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{)/, false)))) { + if (!escaped && stream.match(closing)) { + state.tokenize = null; + state.tokStack.pop(); state.tokStack.pop(); + break; + } + escaped = stream.next() == "\\" && !escaped; + } + return "string"; + } + + var phpKeywords = "abstract and array as break case catch class clone const continue declare default " + + "do else elseif enddeclare endfor endforeach endif endswitch endwhile extends final " + + "for foreach function global goto if implements interface instanceof namespace " + + "new or private protected public static switch throw trait try use var while xor " + + "die echo empty exit eval include include_once isset list require require_once return " + + "print unset __halt_compiler self static parent yield insteadof finally"; + var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"; + var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents file_put_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists array_intersect_key array_combine array_column pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count"; + CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" ")); + CodeMirror.registerHelper("wordChars", "php", /[\w$]/); + + var phpConfig = { + name: "clike", + helperType: "php", + keywords: keywords(phpKeywords), + blockKeywords: keywords("catch do else elseif for foreach if switch try while finally"), + defKeywords: keywords("class function interface namespace trait"), + atoms: keywords(phpAtoms), + builtin: keywords(phpBuiltin), + multiLineStrings: true, + hooks: { + "$": function(stream) { + stream.eatWhile(/[\w\$_]/); + return "variable-2"; + }, + "<": function(stream, state) { + var before; + if (before = stream.match(/<<\s*/)) { + var quoted = stream.eat(/['"]/); + stream.eatWhile(/[\w\.]/); + var delim = stream.current().slice(before[0].length + (quoted ? 2 : 1)); + if (quoted) stream.eat(quoted); + if (delim) { + (state.tokStack || (state.tokStack = [])).push(delim, 0); + state.tokenize = phpString(delim, quoted != "'"); + return "string"; + } + } + return false; + }, + "#": function(stream) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + }, + "/": function(stream) { + if (stream.eat("/")) { + while (!stream.eol() && !stream.match("?>", false)) stream.next(); + return "comment"; + } + return false; + }, + '"': function(_stream, state) { + (state.tokStack || (state.tokStack = [])).push('"', 0); + state.tokenize = phpString('"'); + return "string"; + }, + "{": function(_stream, state) { + if (state.tokStack && state.tokStack.length) + state.tokStack[state.tokStack.length - 1]++; + return false; + }, + "}": function(_stream, state) { + if (state.tokStack && state.tokStack.length > 0 && + !--state.tokStack[state.tokStack.length - 1]) { + state.tokenize = phpString(state.tokStack[state.tokStack.length - 2]); + } + return false; + } + } + }; + + CodeMirror.defineMode("php", function(config, parserConfig) { + var htmlMode = CodeMirror.getMode(config, (parserConfig && parserConfig.htmlMode) || "text/html"); + var phpMode = CodeMirror.getMode(config, phpConfig); + + function dispatch(stream, state) { + var isPHP = state.curMode == phpMode; + if (stream.sol() && state.pending && state.pending != '"' && state.pending != "'") state.pending = null; + if (!isPHP) { + if (stream.match(/^<\?\w*/)) { + state.curMode = phpMode; + if (!state.php) state.php = CodeMirror.startState(phpMode, htmlMode.indent(state.html, "", "")) + state.curState = state.php; + return "meta"; + } + if (state.pending == '"' || state.pending == "'") { + while (!stream.eol() && stream.next() != state.pending) {} + var style = "string"; + } else if (state.pending && stream.pos < state.pending.end) { + stream.pos = state.pending.end; + var style = state.pending.style; + } else { + var style = htmlMode.token(stream, state.curState); + } + if (state.pending) state.pending = null; + var cur = stream.current(), openPHP = cur.search(/<\?/), m; + if (openPHP != -1) { + if (style == "string" && (m = cur.match(/[\'\"]$/)) && !/\?>/.test(cur)) state.pending = m[0]; + else state.pending = {end: stream.pos, style: style}; + stream.backUp(cur.length - openPHP); + } + return style; + } else if (isPHP && state.php.tokenize == null && stream.match("?>")) { + state.curMode = htmlMode; + state.curState = state.html; + if (!state.php.context.prev) state.php = null; + return "meta"; + } else { + return phpMode.token(stream, state.curState); + } + } + + return { + startState: function() { + var html = CodeMirror.startState(htmlMode) + var php = parserConfig.startOpen ? CodeMirror.startState(phpMode) : null + return {html: html, + php: php, + curMode: parserConfig.startOpen ? phpMode : htmlMode, + curState: parserConfig.startOpen ? php : html, + pending: null}; + }, + + copyState: function(state) { + var html = state.html, htmlNew = CodeMirror.copyState(htmlMode, html), + php = state.php, phpNew = php && CodeMirror.copyState(phpMode, php), cur; + if (state.curMode == htmlMode) cur = htmlNew; + else cur = phpNew; + return {html: htmlNew, php: phpNew, curMode: state.curMode, curState: cur, + pending: state.pending}; + }, + + token: dispatch, + + indent: function(state, textAfter, line) { + if ((state.curMode != phpMode && /^\s*<\//.test(textAfter)) || + (state.curMode == phpMode && /^\?>/.test(textAfter))) + return htmlMode.indent(state.html, textAfter, line); + return state.curMode.indent(state.curState, textAfter, line); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", + + innerMode: function(state) { return {state: state.curState, mode: state.curMode}; } + }; + }, "htmlmixed", "clike"); + + CodeMirror.defineMIME("application/x-httpd-php", "php"); + CodeMirror.defineMIME("application/x-httpd-php-open", {name: "php", startOpen: true}); + CodeMirror.defineMIME("text/x-php", phpConfig); +}); diff --git a/lib/redactor/codemirror/mode/smarty/smarty.js b/lib/redactor/codemirror/mode/smarty/smarty.js new file mode 100644 index 0000000..57852fe --- /dev/null +++ b/lib/redactor/codemirror/mode/smarty/smarty.js @@ -0,0 +1,225 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +/** + * Smarty 2 and 3 mode. + */ + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("smarty", function(config, parserConf) { + var rightDelimiter = parserConf.rightDelimiter || "}"; + var leftDelimiter = parserConf.leftDelimiter || "{"; + var version = parserConf.version || 2; + var baseMode = CodeMirror.getMode(config, parserConf.baseMode || "null"); + + var keyFunctions = ["debug", "extends", "function", "include", "literal"]; + var regs = { + operatorChars: /[+\-*&%=<>!?]/, + validIdentifier: /[a-zA-Z0-9_]/, + stringChar: /['"]/ + }; + + var last; + function cont(style, lastType) { + last = lastType; + return style; + } + + function chain(stream, state, parser) { + state.tokenize = parser; + return parser(stream, state); + } + + // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode + function doesNotCount(stream, pos) { + if (pos == null) pos = stream.pos; + return version === 3 && leftDelimiter == "{" && + (pos == stream.string.length || /\s/.test(stream.string.charAt(pos))); + } + + function tokenTop(stream, state) { + var string = stream.string; + for (var scan = stream.pos;;) { + var nextMatch = string.indexOf(leftDelimiter, scan); + scan = nextMatch + leftDelimiter.length; + if (nextMatch == -1 || !doesNotCount(stream, nextMatch + leftDelimiter.length)) break; + } + if (nextMatch == stream.pos) { + stream.match(leftDelimiter); + if (stream.eat("*")) { + return chain(stream, state, tokenBlock("comment", "*" + rightDelimiter)); + } else { + state.depth++; + state.tokenize = tokenSmarty; + last = "startTag"; + return "tag"; + } + } + + if (nextMatch > -1) stream.string = string.slice(0, nextMatch); + var token = baseMode.token(stream, state.base); + if (nextMatch > -1) stream.string = string; + return token; + } + + // parsing Smarty content + function tokenSmarty(stream, state) { + if (stream.match(rightDelimiter, true)) { + if (version === 3) { + state.depth--; + if (state.depth <= 0) { + state.tokenize = tokenTop; + } + } else { + state.tokenize = tokenTop; + } + return cont("tag", null); + } + + if (stream.match(leftDelimiter, true)) { + state.depth++; + return cont("tag", "startTag"); + } + + var ch = stream.next(); + if (ch == "$") { + stream.eatWhile(regs.validIdentifier); + return cont("variable-2", "variable"); + } else if (ch == "|") { + return cont("operator", "pipe"); + } else if (ch == ".") { + return cont("operator", "property"); + } else if (regs.stringChar.test(ch)) { + state.tokenize = tokenAttribute(ch); + return cont("string", "string"); + } else if (regs.operatorChars.test(ch)) { + stream.eatWhile(regs.operatorChars); + return cont("operator", "operator"); + } else if (ch == "[" || ch == "]") { + return cont("bracket", "bracket"); + } else if (ch == "(" || ch == ")") { + return cont("bracket", "operator"); + } else if (/\d/.test(ch)) { + stream.eatWhile(/\d/); + return cont("number", "number"); + } else { + + if (state.last == "variable") { + if (ch == "@") { + stream.eatWhile(regs.validIdentifier); + return cont("property", "property"); + } else if (ch == "|") { + stream.eatWhile(regs.validIdentifier); + return cont("qualifier", "modifier"); + } + } else if (state.last == "pipe") { + stream.eatWhile(regs.validIdentifier); + return cont("qualifier", "modifier"); + } else if (state.last == "whitespace") { + stream.eatWhile(regs.validIdentifier); + return cont("attribute", "modifier"); + } if (state.last == "property") { + stream.eatWhile(regs.validIdentifier); + return cont("property", null); + } else if (/\s/.test(ch)) { + last = "whitespace"; + return null; + } + + var str = ""; + if (ch != "/") { + str += ch; + } + var c = null; + while (c = stream.eat(regs.validIdentifier)) { + str += c; + } + for (var i=0, j=keyFunctions.length; i +* @version 3.0 +* @date 05.07.2013 +*/ +CodeMirror.defineMode("smartymixed", function(config) { + var settings, regs, helpers, parsers, + htmlMixedMode = CodeMirror.getMode(config, "htmlmixed"), + smartyMode = CodeMirror.getMode(config, "smarty"), + + settings = { + rightDelimiter: '}', + leftDelimiter: '{' + }; + + if (config.hasOwnProperty("leftDelimiter")) { + settings.leftDelimiter = config.leftDelimiter; + } + if (config.hasOwnProperty("rightDelimiter")) { + settings.rightDelimiter = config.rightDelimiter; + } + + regs = { + smartyComment: new RegExp("^" + settings.leftDelimiter + "\\*"), + literalOpen: new RegExp(settings.leftDelimiter + "literal" + settings.rightDelimiter), + literalClose: new RegExp(settings.leftDelimiter + "\/literal" + settings.rightDelimiter), + hasLeftDelimeter: new RegExp(".*" + settings.leftDelimiter), + htmlHasLeftDelimeter: new RegExp("[^<>]*" + settings.leftDelimiter) + }; + + helpers = { + chain: function(stream, state, parser) { + state.tokenize = parser; + return parser(stream, state); + }, + + cleanChain: function(stream, state, parser) { + state.tokenize = null; + state.localState = null; + state.localMode = null; + return (typeof parser == "string") ? (parser ? parser : null) : parser(stream, state); + }, + + maybeBackup: function(stream, pat, style) { + var cur = stream.current(); + var close = cur.search(pat), + m; + if (close > - 1) stream.backUp(cur.length - close); + else if (m = cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur[0]); + } + return style; + } + }; + + parsers = { + html: function(stream, state) { + if (!state.inLiteral && stream.match(regs.htmlHasLeftDelimeter, false) && state.htmlMixedState.htmlState.tagName === null) { + state.tokenize = parsers.smarty; + state.localMode = smartyMode; + state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); + return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); + } else if (!state.inLiteral && stream.match(settings.leftDelimiter, false)) { + state.tokenize = parsers.smarty; + state.localMode = smartyMode; + state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); + return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); + } + return htmlMixedMode.token(stream, state.htmlMixedState); + }, + + smarty: function(stream, state) { + if (stream.match(settings.leftDelimiter, false)) { + if (stream.match(regs.smartyComment, false)) { + return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter)); + } + } else if (stream.match(settings.rightDelimiter, false)) { + stream.eat(settings.rightDelimiter); + state.tokenize = parsers.html; + state.localMode = htmlMixedMode; + state.localState = state.htmlMixedState; + return "tag"; + } + + return helpers.maybeBackup(stream, settings.rightDelimiter, smartyMode.token(stream, state.localState)); + }, + + inBlock: function(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + helpers.cleanChain(stream, state, ""); + break; + } + stream.next(); + } + return style; + }; + } + }; + + return { + startState: function() { + var state = htmlMixedMode.startState(); + return { + token: parsers.html, + localMode: null, + localState: null, + htmlMixedState: state, + tokenize: null, + inLiteral: false + }; + }, + + copyState: function(state) { + var local = null, tok = (state.tokenize || state.token); + if (state.localState) { + local = CodeMirror.copyState((tok != parsers.html ? smartyMode : htmlMixedMode), state.localState); + } + return { + token: state.token, + tokenize: state.tokenize, + localMode: state.localMode, + localState: local, + htmlMixedState: CodeMirror.copyState(htmlMixedMode, state.htmlMixedState), + inLiteral: state.inLiteral + }; + }, + + token: function(stream, state) { + if (stream.match(settings.leftDelimiter, false)) { + if (!state.inLiteral && stream.match(regs.literalOpen, true)) { + state.inLiteral = true; + return "keyword"; + } else if (state.inLiteral && stream.match(regs.literalClose, true)) { + state.inLiteral = false; + return "keyword"; + } + } + if (state.inLiteral && state.localState != state.htmlMixedState) { + state.tokenize = parsers.html; + state.localMode = htmlMixedMode; + state.localState = state.htmlMixedState; + } + + var style = (state.tokenize || state.token)(stream, state); + return style; + }, + + indent: function(state, textAfter) { + if (state.localMode == smartyMode + || (state.inLiteral && !state.localMode) + || regs.hasLeftDelimeter.test(textAfter)) { + return CodeMirror.Pass; + } + return htmlMixedMode.indent(state.htmlMixedState, textAfter); + }, + + innerMode: function(state) { + return { + state: state.localState || state.htmlMixedState, + mode: state.localMode || htmlMixedMode + }; + } + }; +}, +"htmlmixed"); + +CodeMirror.defineMIME("text/x-smarty", "smartymixed"); +// vim: et ts=2 sts=2 sw=2 \ No newline at end of file diff --git a/lib/redactor/codemirror/mode/sql/sql.js b/lib/redactor/codemirror/mode/sql/sql.js new file mode 100644 index 0000000..e43495d --- /dev/null +++ b/lib/redactor/codemirror/mode/sql/sql.js @@ -0,0 +1,503 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("sql", function(config, parserConfig) { + var client = parserConfig.client || {}, + atoms = parserConfig.atoms || {"false": true, "true": true, "null": true}, + builtin = parserConfig.builtin || set(defaultBuiltin), + keywords = parserConfig.keywords || set(sqlKeywords), + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^\/]/, + support = parserConfig.support || {}, + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}, + backslashStringEscapes = parserConfig.backslashStringEscapes !== false, + brackets = parserConfig.brackets || /^[\{}\(\)\[\]]/, + punctuation = parserConfig.punctuation || /^[;.,:]/ + + function tokenBase(stream, state) { + var ch = stream.next(); + + // call hooks from the mime type + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + + if (support.hexNumber && + ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) + || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) { + // hex + // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html + return "number"; + } else if (support.binaryNumber && + (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) + || (ch == "0" && stream.match(/^b[01]+/)))) { + // bitstring + // ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html + return "number"; + } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { + // numbers + // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html + stream.match(/^[0-9]*(\.[0-9]+)?([eE][-+]?[0-9]+)?/); + support.decimallessFloat && stream.match(/^\.(?!\.)/); + return "number"; + } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) { + // placeholders + return "variable-3"; + } else if (ch == "'" || (ch == '"' && support.doubleQuote)) { + // strings + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } else if ((((support.nCharCast && (ch == "n" || ch == "N")) + || (support.charsetCast && ch == "_" && stream.match(/[a-z][a-z0-9]*/i))) + && (stream.peek() == "'" || stream.peek() == '"'))) { + // charset casting: _utf8'str', N'str', n'str' + // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html + return "keyword"; + } else if (support.escapeConstant && (ch == "e" || ch == "E") + && (stream.peek() == "'" || (stream.peek() == '"' && support.doubleQuote))) { + // escape constant: E'str', e'str' + // ref: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-STRINGS-ESCAPE + state.tokenize = function(stream, state) { + return (state.tokenize = tokenLiteral(stream.next(), true))(stream, state); + } + return "keyword"; + } else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) { + // 1-line comment + stream.skipToEnd(); + return "comment"; + } else if ((support.commentHash && ch == "#") + || (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) { + // 1-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + stream.skipToEnd(); + return "comment"; + } else if (ch == "/" && stream.eat("*")) { + // multi-line comments + // ref: https://kb.askmonty.org/en/comment-syntax/ + state.tokenize = tokenComment(1); + return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (support.zerolessFloat && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) + return "number"; + if (stream.match(/^\.+/)) + return null + // .table_name (ODBC) + // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + if (support.ODBCdotTable && stream.match(/^[\w\d_]+/)) + return "variable-2"; + } else if (operatorChars.test(ch)) { + // operators + stream.eatWhile(operatorChars); + return "operator"; + } else if (brackets.test(ch)) { + // brackets + return "bracket"; + } else if (punctuation.test(ch)) { + // punctuation + stream.eatWhile(punctuation); + return "punctuation"; + } else if (ch == '{' && + (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { + // dates (weird ODBC syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + return "number"; + } else { + stream.eatWhile(/^[_\w\d]/); + var word = stream.current().toLowerCase(); + // dates (standard SQL syntax) + // ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; + if (atoms.hasOwnProperty(word)) return "atom"; + if (builtin.hasOwnProperty(word)) return "builtin"; + if (keywords.hasOwnProperty(word)) return "keyword"; + if (client.hasOwnProperty(word)) return "string-2"; + return null; + } + } + + // 'string', with char specified in quote escaped by '\' + function tokenLiteral(quote, backslashEscapes) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = (backslashStringEscapes || backslashEscapes) && !escaped && ch == "\\"; + } + return "string"; + }; + } + function tokenComment(depth) { + return function(stream, state) { + var m = stream.match(/^.*?(\/\*|\*\/)/) + if (!m) stream.skipToEnd() + else if (m[1] == "/*") state.tokenize = tokenComment(depth + 1) + else if (depth > 1) state.tokenize = tokenComment(depth - 1) + else state.tokenize = tokenBase + return "comment" + } + } + + function pushContext(stream, state, type) { + state.context = { + prev: state.context, + indent: stream.indentation(), + col: stream.column(), + type: type + }; + } + + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function() { + return {tokenize: tokenBase, context: null}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) + state.context.align = false; + } + if (state.tokenize == tokenBase && stream.eatSpace()) return null; + + var style = state.tokenize(stream, state); + if (style == "comment") return style; + + if (state.context && state.context.align == null) + state.context.align = true; + + var tok = stream.current(); + if (tok == "(") + pushContext(stream, state, ")"); + else if (tok == "[") + pushContext(stream, state, "]"); + else if (state.context && state.context.type == tok) + popContext(state); + return style; + }, + + indent: function(state, textAfter) { + var cx = state.context; + if (!cx) return CodeMirror.Pass; + var closing = textAfter.charAt(0) == cx.type; + if (cx.align) return cx.col + (closing ? 0 : 1); + else return cx.indent + (closing ? 0 : config.indentUnit); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : "--", + closeBrackets: "()[]{}''\"\"``" + }; +}); + + // `identifier` + function hookIdentifier(stream) { + // MySQL/MariaDB identifiers + // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "`" && !stream.eat("`")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // "identifier" + function hookIdentifierDoublequote(stream) { + // Standard SQL /SQLite identifiers + // ref: http://web.archive.org/web/20160813185132/http://savage.net.au/SQL/sql-99.bnf.html#delimited%20identifier + // ref: http://sqlite.org/lang_keywords.html + var ch; + while ((ch = stream.next()) != null) { + if (ch == "\"" && !stream.eat("\"")) return "variable-2"; + } + stream.backUp(stream.current().length - 1); + return stream.eatWhile(/\w/) ? "variable-2" : null; + } + + // variable token + function hookVar(stream) { + // variables + // @@prefix.varName @varName + // varName can be quoted with ` or ' or " + // ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html + if (stream.eat("@")) { + stream.match(/^session\./); + stream.match(/^local\./); + stream.match(/^global\./); + } + + if (stream.eat("'")) { + stream.match(/^.*'/); + return "variable-2"; + } else if (stream.eat('"')) { + stream.match(/^.*"/); + return "variable-2"; + } else if (stream.eat("`")) { + stream.match(/^.*`/); + return "variable-2"; + } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { + return "variable-2"; + } + return null; + }; + + // short client keyword token + function hookClient(stream) { + // \N means NULL + // ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html + if (stream.eat("N")) { + return "atom"; + } + // \g, etc + // ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html + return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null; + } + + // these keywords are used by all SQL dialects (however, a mode can still overwrite it) + var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit "; + + // turn a space-separated list into an array + function set(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var defaultBuiltin = "bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric" + + // A generic SQL Mode. It's not a standard, it just try to support what is generally supported + CodeMirror.defineMIME("text/x-sql", { + name: "sql", + keywords: set(sqlKeywords + "begin"), + builtin: set(defaultBuiltin), + atoms: set("false true null unknown"), + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); + + CodeMirror.defineMIME("text/x-mssql", { + name: "sql", + client: set("$partition binary_checksum checksum connectionproperty context_info current_request_id error_line error_message error_number error_procedure error_severity error_state formatmessage get_filestream_transaction_context getansinull host_id host_name isnull isnumeric min_active_rowversion newid newsequentialid rowcount_big xact_state object_id"), + keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare exec go if use index holdlock nolock nowait paglock readcommitted readcommittedlock readpast readuncommitted repeatableread rowlock serializable snapshot tablock tablockx updlock with"), + builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "), + atoms: set("is not null like and or in left right between inner outer join all any some cross unpivot pivot exists"), + operatorChars: /^[*+\-%<>!=^\&|\/]/, + brackets: /^[\{}\(\)]/, + punctuation: /^[;.,:/]/, + backslashStringEscapes: false, + dateSQL: set("date datetimeoffset datetime2 smalldatetime datetime time"), + hooks: { + "@": hookVar + } + }); + + CodeMirror.defineMIME("text/x-mysql", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general get global grant grants group group_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + CodeMirror.defineMIME("text/x-mariadb", { + name: "sql", + client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), + keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance diagnostics directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated get global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show shutdown signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + hooks: { + "@": hookVar, + "`": hookIdentifier, + "\\": hookClient + } + }); + + // provided by the phpLiteAdmin project - phpliteadmin.org + CodeMirror.defineMIME("text/x-sqlite", { + name: "sql", + // commands of the official SQLite client, ref: https://www.sqlite.org/cli.html#dotcmd + client: set("auth backup bail binary changes check clone databases dbinfo dump echo eqp exit explain fullschema headers help import imposter indexes iotrace limit lint load log mode nullvalue once open output print prompt quit read restore save scanstats schema separator session shell show stats system tables testcase timeout timer trace vfsinfo vfslist vfsname width"), + // ref: http://sqlite.org/lang_keywords.html + keywords: set(sqlKeywords + "abort action add after all analyze attach autoincrement before begin cascade case cast check collate column commit conflict constraint cross current_date current_time current_timestamp database default deferrable deferred detach each else end escape except exclusive exists explain fail for foreign full glob if ignore immediate index indexed initially inner instead intersect isnull key left limit match natural no notnull null of offset outer plan pragma primary query raise recursive references regexp reindex release rename replace restrict right rollback row savepoint temp temporary then to transaction trigger unique using vacuum view virtual when with without"), + // SQLite is weakly typed, ref: http://sqlite.org/datatype3.html. This is just a list of some common types. + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text clob bigint int int2 int8 integer float double char varchar date datetime year unsigned signed numeric real"), + // ref: http://sqlite.org/syntax/literal-value.html + atoms: set("null current_date current_time current_timestamp"), + // ref: http://sqlite.org/lang_expr.html#binaryops + operatorChars: /^[*+\-%<>!=&|/~]/, + // SQLite is weakly typed, ref: http://sqlite.org/datatype3.html. This is just a list of some common types. + dateSQL: set("date time timestamp datetime"), + support: set("decimallessFloat zerolessFloat"), + identifierQuote: "\"", //ref: http://sqlite.org/lang_keywords.html + hooks: { + // bind-parameters ref:http://sqlite.org/lang_expr.html#varparam + "@": hookVar, + ":": hookVar, + "?": hookVar, + "$": hookVar, + // The preferred way to escape Identifiers is using double quotes, ref: http://sqlite.org/lang_keywords.html + "\"": hookIdentifierDoublequote, + // there is also support for backtics, ref: http://sqlite.org/lang_keywords.html + "`": hookIdentifier + } + }); + + // the query language used by Apache Cassandra is called CQL, but this mime type + // is called Cassandra to avoid confusion with Contextual Query Language + CodeMirror.defineMIME("text/x-cassandra", { + name: "sql", + client: { }, + keywords: set("add all allow alter and any apply as asc authorize batch begin by clustering columnfamily compact consistency count create custom delete desc distinct drop each_quorum exists filtering from grant if in index insert into key keyspace keyspaces level limit local_one local_quorum modify nan norecursive nosuperuser not of on one order password permission permissions primary quorum rename revoke schema select set storage superuser table three to token truncate ttl two type unlogged update use user users using values where with writetime"), + builtin: set("ascii bigint blob boolean counter decimal double float frozen inet int list map static text timestamp timeuuid tuple uuid varchar varint"), + atoms: set("false true infinity NaN"), + operatorChars: /^[<>=]/, + dateSQL: { }, + support: set("commentSlashSlash decimallessFloat"), + hooks: { } + }); + + // this is based on Peter Raganitsch's 'plsql' mode + CodeMirror.defineMIME("text/x-plsql", { + name: "sql", + client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), + keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elseif elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning returns reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), + builtin: set("abs acos add_months ascii asin atan atan2 average bfile bfilename bigserial bit blob ceil character chartorowid chr clob concat convert cos cosh count dec decode deref dual dump dup_val_on_index empty error exp false float floor found glb greatest hextoraw initcap instr instrb int integer isopen last_day least length lengthb ln lower lpad ltrim lub make_ref max min mlslabel mod months_between natural naturaln nchar nclob new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null number numeric nvarchar2 nvl others power rawtohex real reftohex round rowcount rowidtochar rowtype rpad rtrim serial sign signtype sin sinh smallint soundex sqlcode sqlerrm sqrt stddev string substr substrb sum sysdate tan tanh to_char text to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid unlogged upper user userenv varchar varchar2 variance varying vsize xml"), + operatorChars: /^[*\/+\-%<>!=~]/, + dateSQL: set("date time timestamp"), + support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber") + }); + + // Created to support specific hive keywords + CodeMirror.defineMIME("text/x-hive", { + name: "sql", + keywords: set("select alter $elem$ $key$ $value$ add after all analyze and archive as asc before between binary both bucket buckets by cascade case cast change cluster clustered clusterstatus collection column columns comment compute concatenate continue create cross cursor data database databases dbproperties deferred delete delimited desc describe directory disable distinct distribute drop else enable end escaped exclusive exists explain export extended external fetch fields fileformat first format formatted from full function functions grant group having hold_ddltime idxproperties if import in index indexes inpath inputdriver inputformat insert intersect into is items join keys lateral left like limit lines load local location lock locks mapjoin materialized minus msck no_drop nocompress not of offline on option or order out outer outputdriver outputformat overwrite partition partitioned partitions percent plus preserve procedure purge range rcfile read readonly reads rebuild recordreader recordwriter recover reduce regexp rename repair replace restrict revoke right rlike row schema schemas semi sequencefile serde serdeproperties set shared show show_database sort sorted ssl statistics stored streamtable table tables tablesample tblproperties temporary terminated textfile then tmp to touch transform trigger unarchive undo union uniquejoin unlock update use using utc utc_tmestamp view when where while with admin authorization char compact compactions conf cube current current_date current_timestamp day decimal defined dependency directories elem_type exchange file following for grouping hour ignore inner interval jar less logical macro minute month more none noscan over owner partialscan preceding pretty principals protection reload rewrite role roles rollup rows second server sets skewed transactions truncate unbounded unset uri user values window year"), + builtin: set("bool boolean long timestamp tinyint smallint bigint int float double date datetime unsigned string array struct map uniontype key_type utctimestamp value_type varchar"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date timestamp"), + support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + }); + + CodeMirror.defineMIME("text/x-pgsql", { + name: "sql", + client: set("source"), + // For PostgreSQL - https://www.postgresql.org/docs/11/sql-keywords-appendix.html + // For pl/pgsql lang - https://github.com/postgres/postgres/blob/REL_11_2/src/pl/plpgsql/src/pl_scanner.c + keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate alias all allocate also alter always analyse analyze and any are array array_agg array_max_cardinality as asc asensitive assert assertion assignment asymmetric at atomic attach attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli between bigint binary bit bit_length blob blocked bom boolean both breadth by c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain char char_length character character_length character_set_catalog character_set_name character_set_schema characteristics characters check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column column_name columns command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constant constraint constraint_catalog constraint_name constraint_schema constraints constructor contains content continue control conversion convert copy corr corresponding cost count covar_pop covar_samp create cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datatype date datetime_interval_code datetime_interval_precision day db deallocate debug dec decimal declare default defaults deferrable deferred defined definer degree delete delimiter delimiters dense_rank depends depth deref derived desc describe descriptor detach detail deterministic diagnostics dictionary disable discard disconnect dispatch distinct dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain double drop dump dynamic dynamic_function dynamic_function_code each element else elseif elsif empty enable encoding encrypted end end_frame end_partition endexec enforced enum equals errcode error escape event every except exception exclude excluding exclusive exec execute exists exit exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreach foreign fortran forward found frame_row free freeze from fs full function functions fusion g general generated get global go goto grant granted greatest group grouping groups handler having header hex hierarchy hint hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import in include including increment indent index indexes indicator info inherit inherits initially inline inner inout input insensitive insert instance instantiable instead int integer integrity intersect intersection interval into invoker is isnull isolation join k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like like_regex limit link listen ln load local localtime localtimestamp location locator lock locked log logged loop lower m map mapping match matched materialized max max_cardinality maxvalue member merge message message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized not nothing notice notify notnull nowait nth_value ntile null nullable nullif nulls number numeric object occurrences_regex octet_length octets of off offset oids old on only open operator option options or order ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parallel parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password path percent percent_rank percentile_cont percentile_disc perform period permission pg_context pg_datatype_name pg_exception_context pg_exception_detail pg_exception_hint placing plans pli policy portion position position_regex power precedes preceding precision prepare prepared preserve primary print_strict_params prior privileges procedural procedure procedures program public publication query quote raise range rank read reads real reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict result result_oid return returned_cardinality returned_length returned_octet_length returned_sqlstate returning returns reverse revoke right role rollback rollup routine routine_catalog routine_name routine_schema routines row row_count row_number rows rowtype rule savepoint scale schema schema_name schemas scope scope_catalog scope_name scope_schema scroll search second section security select selective self sensitive sequence sequences serializable server server_name session session_user set setof sets share show similar simple size skip slice smallint snapshot some source space specific specific_name specifictype sql sqlcode sqlerror sqlexception sqlstate sqlwarning sqrt stable stacked standalone start state statement static statistics stddev_pop stddev_samp stdin stdout storage strict strip structure style subclass_origin submultiset subscription substring substring_regex succeeds sum symmetric sysid system system_time system_user t table table_name tables tablesample tablespace temp template temporary text then ties time timestamp timezone_hour timezone_minute to token top_level_count trailing transaction transaction_active transactions_committed transactions_rolled_back transform transforms translate translate_regex translation treat trigger trigger_catalog trigger_name trigger_schema trim trim_array true truncate trusted type types uescape unbounded uncommitted under unencrypted union unique unknown unlink unlisten unlogged unnamed unnest until untyped update upper uri usage use_column use_variable user user_defined_type_catalog user_defined_type_code user_defined_type_name user_defined_type_schema using vacuum valid validate validator value value_of values var_pop var_samp varbinary varchar variable_conflict variadic varying verbose version versioning view views volatile warning when whenever where while whitespace width_bucket window with within without work wrapper write xml xmlagg xmlattributes xmlbinary xmlcast xmlcomment xmlconcat xmldeclaration xmldocument xmlelement xmlexists xmlforest xmliterate xmlnamespaces xmlparse xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltext xmlvalidate year yes zone"), + // https://www.postgresql.org/docs/11/datatype.html + builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"), + atoms: set("false true null unknown"), + operatorChars: /^[*\/+\-%<>!=&|^\/#@?~]/, + backslashStringEscapes: false, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast escapeConstant") + }); + + // Google's SQL-like query language, GQL + CodeMirror.defineMIME("text/x-gql", { + name: "sql", + keywords: set("ancestor and asc by contains desc descendant distinct from group has in is limit offset on order select superset where"), + atoms: set("false true"), + builtin: set("blob datetime first key __key__ string integer double boolean null"), + operatorChars: /^[*+\-%<>!=]/ + }); + + // Greenplum + CodeMirror.defineMIME("text/x-gpsql", { + name: "sql", + client: set("source"), + //https://github.com/greenplum-db/gpdb/blob/master/src/include/parser/kwlist.h + keywords: set("abort absolute access action active add admin after aggregate all also alter always analyse analyze and any array as asc assertion assignment asymmetric at authorization backward before begin between bigint binary bit boolean both by cache called cascade cascaded case cast chain char character characteristics check checkpoint class close cluster coalesce codegen collate column comment commit committed concurrency concurrently configuration connection constraint constraints contains content continue conversion copy cost cpu_rate_limit create createdb createexttable createrole createuser cross csv cube current current_catalog current_date current_role current_schema current_time current_timestamp current_user cursor cycle data database day deallocate dec decimal declare decode default defaults deferrable deferred definer delete delimiter delimiters deny desc dictionary disable discard distinct distributed do document domain double drop dxl each else enable encoding encrypted end enum errors escape every except exchange exclude excluding exclusive execute exists explain extension external extract false family fetch fields filespace fill filter first float following for force foreign format forward freeze from full function global grant granted greatest group group_id grouping handler hash having header hold host hour identity if ignore ilike immediate immutable implicit in including inclusive increment index indexes inherit inherits initially inline inner inout input insensitive insert instead int integer intersect interval into invoker is isnull isolation join key language large last leading least left level like limit list listen load local localtime localtimestamp location lock log login mapping master match maxvalue median merge minute minvalue missing mode modifies modify month move name names national natural nchar new newline next no nocreatedb nocreateexttable nocreaterole nocreateuser noinherit nologin none noovercommit nosuperuser not nothing notify notnull nowait null nullif nulls numeric object of off offset oids old on only operator option options or order ordered others out outer over overcommit overlaps overlay owned owner parser partial partition partitions passing password percent percentile_cont percentile_disc placing plans position preceding precision prepare prepared preserve primary prior privileges procedural procedure protocol queue quote randomly range read readable reads real reassign recheck recursive ref references reindex reject relative release rename repeatable replace replica reset resource restart restrict returning returns revoke right role rollback rollup rootpartition row rows rule savepoint scatter schema scroll search second security segment select sequence serializable session session_user set setof sets share show similar simple smallint some split sql stable standalone start statement statistics stdin stdout storage strict strip subpartition subpartitions substring superuser symmetric sysid system table tablespace temp template temporary text then threshold ties time timestamp to trailing transaction treat trigger trim true truncate trusted type unbounded uncommitted unencrypted union unique unknown unlisten until update user using vacuum valid validation validator value values varchar variadic varying verbose version view volatile web when where whitespace window with within without work writable write xml xmlattributes xmlconcat xmlelement xmlexists xmlforest xmlparse xmlpi xmlroot xmlserialize year yes zone"), + builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"), + atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^\/#@?~]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast") + }); + + // Spark SQL + CodeMirror.defineMIME("text/x-sparksql", { + name: "sql", + keywords: set("add after all alter analyze and anti archive array as asc at between bucket buckets by cache cascade case cast change clear cluster clustered codegen collection column columns comment commit compact compactions compute concatenate cost create cross cube current current_date current_timestamp database databases datata dbproperties defined delete delimited deny desc describe dfs directories distinct distribute drop else end escaped except exchange exists explain export extended external false fields fileformat first following for format formatted from full function functions global grant group grouping having if ignore import in index indexes inner inpath inputformat insert intersect interval into is items join keys last lateral lazy left like limit lines list load local location lock locks logical macro map minus msck natural no not null nulls of on optimize option options or order out outer outputformat over overwrite partition partitioned partitions percent preceding principals purge range recordreader recordwriter recover reduce refresh regexp rename repair replace reset restrict revoke right rlike role roles rollback rollup row rows schema schemas select semi separated serde serdeproperties set sets show skewed sort sorted start statistics stored stratify struct table tables tablesample tblproperties temp temporary terminated then to touch transaction transactions transform true truncate unarchive unbounded uncache union unlock unset use using values view when where window with"), + builtin: set("tinyint smallint int bigint boolean float double string binary timestamp decimal array map struct uniontype delimited serde sequencefile textfile rcfile inputformat outputformat"), + atoms: set("false true null"), + operatorChars: /^[*\/+\-%<>!=~&|^]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable doubleQuote zerolessFloat") + }); + + // Esper + CodeMirror.defineMIME("text/x-esper", { + name: "sql", + client: set("source"), + // http://www.espertech.com/esper/release-5.5.0/esper-reference/html/appendix_keywords.html + keywords: set("alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit after all and as at asc avedev avg between by case cast coalesce count create current_timestamp day days delete define desc distinct else end escape events every exists false first from full group having hour hours in inner insert instanceof into irstream is istream join last lastweekday left limit like max match_recognize matches median measures metadatasql min minute minutes msec millisecond milliseconds not null offset on or order outer output partition pattern prev prior regexp retain-union retain-intersection right rstream sec second seconds select set some snapshot sql stddev sum then true unidirectional until update variable weekday when where window"), + builtin: {}, + atoms: set("false true null"), + operatorChars: /^[*+\-%<>!=&|^\/#@?~]/, + dateSQL: set("time"), + support: set("decimallessFloat zerolessFloat binaryNumber hexNumber") + }); +}); + +/* + How Properties of Mime Types are used by SQL Mode + ================================================= + + keywords: + A list of keywords you want to be highlighted. + builtin: + A list of builtin types you want to be highlighted (if you want types to be of class "builtin" instead of "keyword"). + operatorChars: + All characters that must be handled as operators. + client: + Commands parsed and executed by the client (not the server). + support: + A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. + * ODBCdotTable: .tableName + * zerolessFloat: .1 + * doubleQuote + * nCharCast: N'string' + * charsetCast: _utf8'string' + * commentHash: use # char for comments + * commentSlashSlash: use // for comments + * commentSpaceRequired: require a space after -- for comments + atoms: + Keywords that must be highlighted as atoms,. Some DBMS's support more atoms than others: + UNKNOWN, INFINITY, UNDERFLOW, NaN... + dateSQL: + Used for date/time SQL standard syntax, because not all DBMS's support same temporal types. +*/ diff --git a/lib/redactor/codemirror/mode/xml/xml.js b/lib/redactor/codemirror/mode/xml/xml.js new file mode 100644 index 0000000..73c6e0e --- /dev/null +++ b/lib/redactor/codemirror/mode/xml/xml.js @@ -0,0 +1,413 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +var htmlConfig = { + autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, + 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, + 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, + 'track': true, 'wbr': true, 'menuitem': true}, + implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, + 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, + 'th': true, 'tr': true}, + contextGrabbers: { + 'dd': {'dd': true, 'dt': true}, + 'dt': {'dd': true, 'dt': true}, + 'li': {'li': true}, + 'option': {'option': true, 'optgroup': true}, + 'optgroup': {'optgroup': true}, + 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, + 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, + 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, + 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, + 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, + 'rp': {'rp': true, 'rt': true}, + 'rt': {'rp': true, 'rt': true}, + 'tbody': {'tbody': true, 'tfoot': true}, + 'td': {'td': true, 'th': true}, + 'tfoot': {'tbody': true}, + 'th': {'td': true, 'th': true}, + 'thead': {'tbody': true, 'tfoot': true}, + 'tr': {'tr': true} + }, + doNotIndent: {"pre": true}, + allowUnquoted: true, + allowMissing: true, + caseFold: true +} + +var xmlConfig = { + autoSelfClosers: {}, + implicitlyClosed: {}, + contextGrabbers: {}, + doNotIndent: {}, + allowUnquoted: false, + allowMissing: false, + allowMissingTagName: false, + caseFold: false +} + +CodeMirror.defineMode("xml", function(editorConf, config_) { + var indentUnit = editorConf.indentUnit + var config = {} + var defaults = config_.htmlMode ? htmlConfig : xmlConfig + for (var prop in defaults) config[prop] = defaults[prop] + for (var prop in config_) config[prop] = config_[prop] + + // Return variables for tokenizers + var type, setStyle; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); + else return null; + } else if (stream.match("--")) { + return chain(inBlock("comment", "-->")); + } else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } else { + return null; + } + } else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } else { + type = stream.eat("/") ? "closeTag" : "openTag"; + state.tokenize = inTag; + return "tag bracket"; + } + } else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } else { + stream.eatWhile(/[^&<]/); + return null; + } + } + inText.isInText = true; + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag bracket"; + } else if (ch == "=") { + type = "equals"; + return null; + } else if (ch == "<") { + state.tokenize = inText; + state.state = baseState; + state.tagName = state.tagStart = null; + var next = state.tokenize(stream, state); + return next ? next + " tag error" : "tag error"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + state.stringStartCol = stream.column(); + return state.tokenize(stream, state); + } else { + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); + return "word"; + } + } + + function inAttribute(quote) { + var closure = function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + closure.isInAttribute = true; + return closure; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + } + } + + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + function Context(state, tagName, startOfLine) { + this.prev = state.context; + this.tagName = tagName; + this.indent = state.indented; + this.startOfLine = startOfLine; + if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) + this.noIndent = true; + } + function popContext(state) { + if (state.context) state.context = state.context.prev; + } + function maybePopContext(state, nextTagName) { + var parentTagName; + while (true) { + if (!state.context) { + return; + } + parentTagName = state.context.tagName; + if (!config.contextGrabbers.hasOwnProperty(parentTagName) || + !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(state); + } + } + + function baseState(type, stream, state) { + if (type == "openTag") { + state.tagStart = stream.column(); + return tagNameState; + } else if (type == "closeTag") { + return closeTagNameState; + } else { + return baseState; + } + } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else if (config.allowMissingTagName && type == "endTag") { + setStyle = "tag bracket"; + return attrState(type, stream, state); + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + config.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { + setStyle = "tag"; + return closeState; + } else { + setStyle = "tag error"; + return closeStateErr; + } + } else if (config.allowMissingTagName && type == "endTag") { + setStyle = "tag bracket"; + return closeState(type, stream, state); + } else { + setStyle = "error"; + return closeStateErr; + } + } + + function closeState(type, _stream, state) { + if (type != "endTag") { + setStyle = "error"; + return closeState; + } + popContext(state); + return baseState; + } + function closeStateErr(type, stream, state) { + setStyle = "error"; + return closeState(type, stream, state); + } + + function attrState(type, _stream, state) { + if (type == "word") { + setStyle = "attribute"; + return attrEqState; + } else if (type == "endTag" || type == "selfcloseTag") { + var tagName = state.tagName, tagStart = state.tagStart; + state.tagName = state.tagStart = null; + if (type == "selfcloseTag" || + config.autoSelfClosers.hasOwnProperty(tagName)) { + maybePopContext(state, tagName); + } else { + maybePopContext(state, tagName); + state.context = new Context(state, tagName, tagStart == state.indented); + } + return baseState; + } + setStyle = "error"; + return attrState; + } + function attrEqState(type, stream, state) { + if (type == "equals") return attrValueState; + if (!config.allowMissing) setStyle = "error"; + return attrState(type, stream, state); + } + function attrValueState(type, stream, state) { + if (type == "string") return attrContinuedState; + if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;} + setStyle = "error"; + return attrState(type, stream, state); + } + function attrContinuedState(type, stream, state) { + if (type == "string") return attrContinuedState; + return attrState(type, stream, state); + } + + return { + startState: function(baseIndent) { + var state = {tokenize: inText, + state: baseState, + indented: baseIndent || 0, + tagName: null, tagStart: null, + context: null} + if (baseIndent != null) state.baseIndent = baseIndent + return state + }, + + token: function(stream, state) { + if (!state.tagName && stream.sol()) + state.indented = stream.indentation(); + + if (stream.eatSpace()) return null; + type = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + setStyle = null; + state.state = state.state(type || style, stream, state); + if (setStyle) + style = setStyle == "error" ? style + " error" : setStyle; + } + return style; + }, + + indent: function(state, textAfter, fullLine) { + var context = state.context; + // Indent multi-line strings (e.g. css). + if (state.tokenize.isInAttribute) { + if (state.tagStart == state.indented) + return state.stringStartCol + 1; + else + return state.indented + indentUnit; + } + if (context && context.noIndent) return CodeMirror.Pass; + if (state.tokenize != inTag && state.tokenize != inText) + return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + // Indent the starts of attribute names. + if (state.tagName) { + if (config.multilineTagIndentPastTag !== false) + return state.tagStart + state.tagName.length + 2; + else + return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1); + } + if (config.alignCDATA && /$/, + blockCommentStart: "", + + configuration: config.htmlMode ? "html" : "xml", + helperType: config.htmlMode ? "html" : "xml", + + skipAttribute: function(state) { + if (state.state == attrValueState) + state.state = attrState + }, + + xmlCurrentTag: function(state) { + return state.tagName ? {name: state.tagName, close: state.type == "closeTag"} : null + }, + + xmlCurrentContext: function(state) { + var context = [] + for (var cx = state.context; cx; cx = cx.prev) + if (cx.tagName) context.push(cx.tagName) + return context.reverse() + } + }; +}); + +CodeMirror.defineMIME("text/xml", "xml"); +CodeMirror.defineMIME("application/xml", "xml"); +if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) + CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); + +}); diff --git a/lib/redactor/codemirror/theme/3024-day.css b/lib/redactor/codemirror/theme/3024-day.css new file mode 100644 index 0000000..7132655 --- /dev/null +++ b/lib/redactor/codemirror/theme/3024-day.css @@ -0,0 +1,41 @@ +/* + + Name: 3024 day + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-day.CodeMirror { background: #f7f7f7; color: #3a3432; } +.cm-s-3024-day div.CodeMirror-selected { background: #d6d5d4; } + +.cm-s-3024-day .CodeMirror-line::selection, .cm-s-3024-day .CodeMirror-line > span::selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d6d5d4; } +.cm-s-3024-day .CodeMirror-line::-moz-selection, .cm-s-3024-day .CodeMirror-line > span::-moz-selection, .cm-s-3024-day .CodeMirror-line > span > span::selection { background: #d9d9d9; } + +.cm-s-3024-day .CodeMirror-gutters { background: #f7f7f7; border-right: 0px; } +.cm-s-3024-day .CodeMirror-guttermarker { color: #db2d20; } +.cm-s-3024-day .CodeMirror-guttermarker-subtle { color: #807d7c; } +.cm-s-3024-day .CodeMirror-linenumber { color: #807d7c; } + +.cm-s-3024-day .CodeMirror-cursor { border-left: 1px solid #5c5855; } + +.cm-s-3024-day span.cm-comment { color: #cdab53; } +.cm-s-3024-day span.cm-atom { color: #a16a94; } +.cm-s-3024-day span.cm-number { color: #a16a94; } + +.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute { color: #01a252; } +.cm-s-3024-day span.cm-keyword { color: #db2d20; } +.cm-s-3024-day span.cm-string { color: #fded02; } + +.cm-s-3024-day span.cm-variable { color: #01a252; } +.cm-s-3024-day span.cm-variable-2 { color: #01a0e4; } +.cm-s-3024-day span.cm-def { color: #e8bbd0; } +.cm-s-3024-day span.cm-bracket { color: #3a3432; } +.cm-s-3024-day span.cm-tag { color: #db2d20; } +.cm-s-3024-day span.cm-link { color: #a16a94; } +.cm-s-3024-day span.cm-error { background: #db2d20; color: #5c5855; } + +.cm-s-3024-day .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: #a16a94 !important; } diff --git a/lib/redactor/codemirror/theme/3024-night.css b/lib/redactor/codemirror/theme/3024-night.css new file mode 100644 index 0000000..adc5900 --- /dev/null +++ b/lib/redactor/codemirror/theme/3024-night.css @@ -0,0 +1,39 @@ +/* + + Name: 3024 night + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-night.CodeMirror { background: #090300; color: #d6d5d4; } +.cm-s-3024-night div.CodeMirror-selected { background: #3a3432; } +.cm-s-3024-night .CodeMirror-line::selection, .cm-s-3024-night .CodeMirror-line > span::selection, .cm-s-3024-night .CodeMirror-line > span > span::selection { background: rgba(58, 52, 50, .99); } +.cm-s-3024-night .CodeMirror-line::-moz-selection, .cm-s-3024-night .CodeMirror-line > span::-moz-selection, .cm-s-3024-night .CodeMirror-line > span > span::-moz-selection { background: rgba(58, 52, 50, .99); } +.cm-s-3024-night .CodeMirror-gutters { background: #090300; border-right: 0px; } +.cm-s-3024-night .CodeMirror-guttermarker { color: #db2d20; } +.cm-s-3024-night .CodeMirror-guttermarker-subtle { color: #5c5855; } +.cm-s-3024-night .CodeMirror-linenumber { color: #5c5855; } + +.cm-s-3024-night .CodeMirror-cursor { border-left: 1px solid #807d7c; } + +.cm-s-3024-night span.cm-comment { color: #cdab53; } +.cm-s-3024-night span.cm-atom { color: #a16a94; } +.cm-s-3024-night span.cm-number { color: #a16a94; } + +.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute { color: #01a252; } +.cm-s-3024-night span.cm-keyword { color: #db2d20; } +.cm-s-3024-night span.cm-string { color: #fded02; } + +.cm-s-3024-night span.cm-variable { color: #01a252; } +.cm-s-3024-night span.cm-variable-2 { color: #01a0e4; } +.cm-s-3024-night span.cm-def { color: #e8bbd0; } +.cm-s-3024-night span.cm-bracket { color: #d6d5d4; } +.cm-s-3024-night span.cm-tag { color: #db2d20; } +.cm-s-3024-night span.cm-link { color: #a16a94; } +.cm-s-3024-night span.cm-error { background: #db2d20; color: #807d7c; } + +.cm-s-3024-night .CodeMirror-activeline-background { background: #2F2F2F; } +.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/abcdef.css b/lib/redactor/codemirror/theme/abcdef.css new file mode 100644 index 0000000..cf93530 --- /dev/null +++ b/lib/redactor/codemirror/theme/abcdef.css @@ -0,0 +1,32 @@ +.cm-s-abcdef.CodeMirror { background: #0f0f0f; color: #defdef; } +.cm-s-abcdef div.CodeMirror-selected { background: #515151; } +.cm-s-abcdef .CodeMirror-line::selection, .cm-s-abcdef .CodeMirror-line > span::selection, .cm-s-abcdef .CodeMirror-line > span > span::selection { background: rgba(56, 56, 56, 0.99); } +.cm-s-abcdef .CodeMirror-line::-moz-selection, .cm-s-abcdef .CodeMirror-line > span::-moz-selection, .cm-s-abcdef .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 56, 56, 0.99); } +.cm-s-abcdef .CodeMirror-gutters { background: #555; border-right: 2px solid #314151; } +.cm-s-abcdef .CodeMirror-guttermarker { color: #222; } +.cm-s-abcdef .CodeMirror-guttermarker-subtle { color: azure; } +.cm-s-abcdef .CodeMirror-linenumber { color: #FFFFFF; } +.cm-s-abcdef .CodeMirror-cursor { border-left: 1px solid #00FF00; } + +.cm-s-abcdef span.cm-keyword { color: darkgoldenrod; font-weight: bold; } +.cm-s-abcdef span.cm-atom { color: #77F; } +.cm-s-abcdef span.cm-number { color: violet; } +.cm-s-abcdef span.cm-def { color: #fffabc; } +.cm-s-abcdef span.cm-variable { color: #abcdef; } +.cm-s-abcdef span.cm-variable-2 { color: #cacbcc; } +.cm-s-abcdef span.cm-variable-3, .cm-s-abcdef span.cm-type { color: #def; } +.cm-s-abcdef span.cm-property { color: #fedcba; } +.cm-s-abcdef span.cm-operator { color: #ff0; } +.cm-s-abcdef span.cm-comment { color: #7a7b7c; font-style: italic;} +.cm-s-abcdef span.cm-string { color: #2b4; } +.cm-s-abcdef span.cm-meta { color: #C9F; } +.cm-s-abcdef span.cm-qualifier { color: #FFF700; } +.cm-s-abcdef span.cm-builtin { color: #30aabc; } +.cm-s-abcdef span.cm-bracket { color: #8a8a8a; } +.cm-s-abcdef span.cm-tag { color: #FFDD44; } +.cm-s-abcdef span.cm-attribute { color: #DDFF00; } +.cm-s-abcdef span.cm-error { color: #FF0000; } +.cm-s-abcdef span.cm-header { color: aquamarine; font-weight: bold; } +.cm-s-abcdef span.cm-link { color: blueviolet; } + +.cm-s-abcdef .CodeMirror-activeline-background { background: #314151; } diff --git a/lib/redactor/codemirror/theme/ambiance-mobile.css b/lib/redactor/codemirror/theme/ambiance-mobile.css new file mode 100644 index 0000000..88d332e --- /dev/null +++ b/lib/redactor/codemirror/theme/ambiance-mobile.css @@ -0,0 +1,5 @@ +.cm-s-ambiance.CodeMirror { + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} diff --git a/lib/redactor/codemirror/theme/ambiance.css b/lib/redactor/codemirror/theme/ambiance.css new file mode 100644 index 0000000..782fca4 --- /dev/null +++ b/lib/redactor/codemirror/theme/ambiance.css @@ -0,0 +1,74 @@ +/* ambiance theme for codemirror */ + +/* Color scheme */ + +.cm-s-ambiance .cm-header { color: blue; } +.cm-s-ambiance .cm-quote { color: #24C2C7; } + +.cm-s-ambiance .cm-keyword { color: #cda869; } +.cm-s-ambiance .cm-atom { color: #CF7EA9; } +.cm-s-ambiance .cm-number { color: #78CF8A; } +.cm-s-ambiance .cm-def { color: #aac6e3; } +.cm-s-ambiance .cm-variable { color: #ffb795; } +.cm-s-ambiance .cm-variable-2 { color: #eed1b3; } +.cm-s-ambiance .cm-variable-3, .cm-s-ambiance .cm-type { color: #faded3; } +.cm-s-ambiance .cm-property { color: #eed1b3; } +.cm-s-ambiance .cm-operator { color: #fa8d6a; } +.cm-s-ambiance .cm-comment { color: #555; font-style:italic; } +.cm-s-ambiance .cm-string { color: #8f9d6a; } +.cm-s-ambiance .cm-string-2 { color: #9d937c; } +.cm-s-ambiance .cm-meta { color: #D2A8A1; } +.cm-s-ambiance .cm-qualifier { color: yellow; } +.cm-s-ambiance .cm-builtin { color: #9999cc; } +.cm-s-ambiance .cm-bracket { color: #24C2C7; } +.cm-s-ambiance .cm-tag { color: #fee4ff; } +.cm-s-ambiance .cm-attribute { color: #9B859D; } +.cm-s-ambiance .cm-hr { color: pink; } +.cm-s-ambiance .cm-link { color: #F4C20B; } +.cm-s-ambiance .cm-special { color: #FF9D00; } +.cm-s-ambiance .cm-error { color: #AF2018; } + +.cm-s-ambiance .CodeMirror-matchingbracket { color: #0f0; } +.cm-s-ambiance .CodeMirror-nonmatchingbracket { color: #f22; } + +.cm-s-ambiance div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); } +.cm-s-ambiance.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } +.cm-s-ambiance .CodeMirror-line::selection, .cm-s-ambiance .CodeMirror-line > span::selection, .cm-s-ambiance .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-ambiance .CodeMirror-line::-moz-selection, .cm-s-ambiance .CodeMirror-line > span::-moz-selection, .cm-s-ambiance .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } + +/* Editor styling */ + +.cm-s-ambiance.CodeMirror { + line-height: 1.40em; + color: #E6E1DC; + background-color: #202020; + -webkit-box-shadow: inset 0 0 10px black; + -moz-box-shadow: inset 0 0 10px black; + box-shadow: inset 0 0 10px black; +} + +.cm-s-ambiance .CodeMirror-gutters { + background: #3D3D3D; + border-right: 1px solid #4D4D4D; + box-shadow: 0 10px 20px black; +} + +.cm-s-ambiance .CodeMirror-linenumber { + text-shadow: 0px 1px 1px #4d4d4d; + color: #111; + padding: 0 5px; +} + +.cm-s-ambiance .CodeMirror-guttermarker { color: #aaa; } +.cm-s-ambiance .CodeMirror-guttermarker-subtle { color: #111; } + +.cm-s-ambiance .CodeMirror-cursor { border-left: 1px solid #7991E8; } + +.cm-s-ambiance .CodeMirror-activeline-background { + background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031); +} + +.cm-s-ambiance.CodeMirror, +.cm-s-ambiance .CodeMirror-gutters { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC"); +} diff --git a/lib/redactor/codemirror/theme/ayu-dark.css b/lib/redactor/codemirror/theme/ayu-dark.css new file mode 100644 index 0000000..fd41ba3 --- /dev/null +++ b/lib/redactor/codemirror/theme/ayu-dark.css @@ -0,0 +1,42 @@ +/* Based on https://github.com/dempfi/ayu */ + +.cm-s-ayu-dark.CodeMirror { background: #0a0e14; color: #b3b1ad; } +.cm-s-ayu-dark div.CodeMirror-selected { background: #273747; } +.cm-s-ayu-dark .CodeMirror-line::selection, .cm-s-ayu-dark .CodeMirror-line > span::selection, .cm-s-ayu-dark .CodeMirror-line > span > span::selection { background: rgba(39, 55, 71, 99); } +.cm-s-ayu-dark .CodeMirror-line::-moz-selection, .cm-s-ayu-dark .CodeMirror-line > span::-moz-selection, .cm-s-ayu-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 55, 71, 99); } +.cm-s-ayu-dark .CodeMirror-gutters { background: #0a0e14; border-right: 0px; } +.cm-s-ayu-dark .CodeMirror-guttermarker { color: white; } +.cm-s-ayu-dark .CodeMirror-guttermarker-subtle { color: #3d424d; } +.cm-s-ayu-dark .CodeMirror-linenumber { color: #3d424d; } +.cm-s-ayu-dark .CodeMirror-cursor { border-left: 1px solid #e6b450; } + +.cm-s-ayu-dark span.cm-comment { color: #626a73; } +.cm-s-ayu-dark span.cm-atom { color: #ae81ff; } +.cm-s-ayu-dark span.cm-number { color: #e6b450; } + +.cm-s-ayu-dark span.cm-comment.cm-attribute { color: #ffb454; } +.cm-s-ayu-dark span.cm-comment.cm-def { color: rgba(57, 186, 230, 80); } +.cm-s-ayu-dark span.cm-comment.cm-tag { color: #39bae6; } +.cm-s-ayu-dark span.cm-comment.cm-type { color: #5998a6; } + +.cm-s-ayu-dark span.cm-property, .cm-s-ayu-dark span.cm-attribute { color: #ffb454; } +.cm-s-ayu-dark span.cm-keyword { color: #ff8f40; } +.cm-s-ayu-dark span.cm-builtin { color: #e6b450; } +.cm-s-ayu-dark span.cm-string { color: #c2d94c; } + +.cm-s-ayu-dark span.cm-variable { color: #b3b1ad; } +.cm-s-ayu-dark span.cm-variable-2 { color: #f07178; } +.cm-s-ayu-dark span.cm-variable-3 { color: #39bae6; } +.cm-s-ayu-dark span.cm-type { color: #ff8f40; } +.cm-s-ayu-dark span.cm-def { color: #ffee99; } +.cm-s-ayu-dark span.cm-bracket { color: #f8f8f2; } +.cm-s-ayu-dark span.cm-tag { color: rgba(57, 186, 230, 80); } +.cm-s-ayu-dark span.cm-header { color: #c2d94c; } +.cm-s-ayu-dark span.cm-link { color: #39bae6; } +.cm-s-ayu-dark span.cm-error { color: #ff3333; } + +.cm-s-ayu-dark .CodeMirror-activeline-background { background: #01060e; } +.cm-s-ayu-dark .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/lib/redactor/codemirror/theme/ayu-mirage.css b/lib/redactor/codemirror/theme/ayu-mirage.css new file mode 100644 index 0000000..7a5b50c --- /dev/null +++ b/lib/redactor/codemirror/theme/ayu-mirage.css @@ -0,0 +1,43 @@ +/* Based on https://github.com/dempfi/ayu */ + +.cm-s-ayu-mirage.CodeMirror { background: #1f2430; color: #cbccc6; } +.cm-s-ayu-mirage div.CodeMirror-selected { background: #34455a; } +.cm-s-ayu-mirage .CodeMirror-line::selection, .cm-s-ayu-mirage .CodeMirror-line > span::selection, .cm-s-ayu-mirage .CodeMirror-line > span > span::selection { background: #34455a; } +.cm-s-ayu-mirage .CodeMirror-line::-moz-selection, .cm-s-ayu-mirage .CodeMirror-line > span::-moz-selection, .cm-s-ayu-mirage .CodeMirror-line > span > span::-moz-selection { background: rgba(25, 30, 42, 99); } +.cm-s-ayu-mirage .CodeMirror-gutters { background: #1f2430; border-right: 0px; } +.cm-s-ayu-mirage .CodeMirror-guttermarker { color: white; } +.cm-s-ayu-mirage .CodeMirror-guttermarker-subtle { color: rgba(112, 122, 140, 66); } +.cm-s-ayu-mirage .CodeMirror-linenumber { color: rgba(61, 66, 77, 99); } +.cm-s-ayu-mirage .CodeMirror-cursor { border-left: 1px solid #ffcc66; } + +.cm-s-ayu-mirage span.cm-comment { color: #5c6773; font-style:italic; } +.cm-s-ayu-mirage span.cm-atom { color: #ae81ff; } +.cm-s-ayu-mirage span.cm-number { color: #ffcc66; } + +.cm-s-ayu-mirage span.cm-comment.cm-attribute { color: #ffd580; } +.cm-s-ayu-mirage span.cm-comment.cm-def { color: #d4bfff; } +.cm-s-ayu-mirage span.cm-comment.cm-tag { color: #5ccfe6; } +.cm-s-ayu-mirage span.cm-comment.cm-type { color: #5998a6; } + +.cm-s-ayu-mirage span.cm-property { color: #f29e74; } +.cm-s-ayu-mirage span.cm-attribute { color: #ffd580; } +.cm-s-ayu-mirage span.cm-keyword { color: #ffa759; } +.cm-s-ayu-mirage span.cm-builtin { color: #ffcc66; } +.cm-s-ayu-mirage span.cm-string { color: #bae67e; } + +.cm-s-ayu-mirage span.cm-variable { color: #cbccc6; } +.cm-s-ayu-mirage span.cm-variable-2 { color: #f28779; } +.cm-s-ayu-mirage span.cm-variable-3 { color: #5ccfe6; } +.cm-s-ayu-mirage span.cm-type { color: #ffa759; } +.cm-s-ayu-mirage span.cm-def { color: #ffd580; } +.cm-s-ayu-mirage span.cm-bracket { color: rgba(92, 207, 230, 80); } +.cm-s-ayu-mirage span.cm-tag { color: #5ccfe6; } +.cm-s-ayu-mirage span.cm-header { color: #bae67e; } +.cm-s-ayu-mirage span.cm-link { color: #5ccfe6; } +.cm-s-ayu-mirage span.cm-error { color: #ff3333; } + +.cm-s-ayu-mirage .CodeMirror-activeline-background { background: #191e2a; } +.cm-s-ayu-mirage .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/lib/redactor/codemirror/theme/base16-dark.css b/lib/redactor/codemirror/theme/base16-dark.css new file mode 100644 index 0000000..026a816 --- /dev/null +++ b/lib/redactor/codemirror/theme/base16-dark.css @@ -0,0 +1,38 @@ +/* + + Name: Base16 Default Dark + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-dark.CodeMirror { background: #151515; color: #e0e0e0; } +.cm-s-base16-dark div.CodeMirror-selected { background: #303030; } +.cm-s-base16-dark .CodeMirror-line::selection, .cm-s-base16-dark .CodeMirror-line > span::selection, .cm-s-base16-dark .CodeMirror-line > span > span::selection { background: rgba(48, 48, 48, .99); } +.cm-s-base16-dark .CodeMirror-line::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span::-moz-selection, .cm-s-base16-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(48, 48, 48, .99); } +.cm-s-base16-dark .CodeMirror-gutters { background: #151515; border-right: 0px; } +.cm-s-base16-dark .CodeMirror-guttermarker { color: #ac4142; } +.cm-s-base16-dark .CodeMirror-guttermarker-subtle { color: #505050; } +.cm-s-base16-dark .CodeMirror-linenumber { color: #505050; } +.cm-s-base16-dark .CodeMirror-cursor { border-left: 1px solid #b0b0b0; } + +.cm-s-base16-dark span.cm-comment { color: #8f5536; } +.cm-s-base16-dark span.cm-atom { color: #aa759f; } +.cm-s-base16-dark span.cm-number { color: #aa759f; } + +.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute { color: #90a959; } +.cm-s-base16-dark span.cm-keyword { color: #ac4142; } +.cm-s-base16-dark span.cm-string { color: #f4bf75; } + +.cm-s-base16-dark span.cm-variable { color: #90a959; } +.cm-s-base16-dark span.cm-variable-2 { color: #6a9fb5; } +.cm-s-base16-dark span.cm-def { color: #d28445; } +.cm-s-base16-dark span.cm-bracket { color: #e0e0e0; } +.cm-s-base16-dark span.cm-tag { color: #ac4142; } +.cm-s-base16-dark span.cm-link { color: #aa759f; } +.cm-s-base16-dark span.cm-error { background: #ac4142; color: #b0b0b0; } + +.cm-s-base16-dark .CodeMirror-activeline-background { background: #202020; } +.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/base16-light.css b/lib/redactor/codemirror/theme/base16-light.css new file mode 100644 index 0000000..1d5f582 --- /dev/null +++ b/lib/redactor/codemirror/theme/base16-light.css @@ -0,0 +1,38 @@ +/* + + Name: Base16 Default Light + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-light.CodeMirror { background: #f5f5f5; color: #202020; } +.cm-s-base16-light div.CodeMirror-selected { background: #e0e0e0; } +.cm-s-base16-light .CodeMirror-line::selection, .cm-s-base16-light .CodeMirror-line > span::selection, .cm-s-base16-light .CodeMirror-line > span > span::selection { background: #e0e0e0; } +.cm-s-base16-light .CodeMirror-line::-moz-selection, .cm-s-base16-light .CodeMirror-line > span::-moz-selection, .cm-s-base16-light .CodeMirror-line > span > span::-moz-selection { background: #e0e0e0; } +.cm-s-base16-light .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; } +.cm-s-base16-light .CodeMirror-guttermarker { color: #ac4142; } +.cm-s-base16-light .CodeMirror-guttermarker-subtle { color: #b0b0b0; } +.cm-s-base16-light .CodeMirror-linenumber { color: #b0b0b0; } +.cm-s-base16-light .CodeMirror-cursor { border-left: 1px solid #505050; } + +.cm-s-base16-light span.cm-comment { color: #8f5536; } +.cm-s-base16-light span.cm-atom { color: #aa759f; } +.cm-s-base16-light span.cm-number { color: #aa759f; } + +.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute { color: #90a959; } +.cm-s-base16-light span.cm-keyword { color: #ac4142; } +.cm-s-base16-light span.cm-string { color: #f4bf75; } + +.cm-s-base16-light span.cm-variable { color: #90a959; } +.cm-s-base16-light span.cm-variable-2 { color: #6a9fb5; } +.cm-s-base16-light span.cm-def { color: #d28445; } +.cm-s-base16-light span.cm-bracket { color: #202020; } +.cm-s-base16-light span.cm-tag { color: #ac4142; } +.cm-s-base16-light span.cm-link { color: #aa759f; } +.cm-s-base16-light span.cm-error { background: #ac4142; color: #505050; } + +.cm-s-base16-light .CodeMirror-activeline-background { background: #DDDCDC; } +.cm-s-base16-light .CodeMirror-matchingbracket { color: #f5f5f5 !important; background-color: #6A9FB5 !important} diff --git a/lib/redactor/codemirror/theme/bespin.css b/lib/redactor/codemirror/theme/bespin.css new file mode 100644 index 0000000..60913ba --- /dev/null +++ b/lib/redactor/codemirror/theme/bespin.css @@ -0,0 +1,34 @@ +/* + + Name: Bespin + Author: Mozilla / Jan T. Sott + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-bespin.CodeMirror {background: #28211c; color: #9d9b97;} +.cm-s-bespin div.CodeMirror-selected {background: #36312e !important;} +.cm-s-bespin .CodeMirror-gutters {background: #28211c; border-right: 0px;} +.cm-s-bespin .CodeMirror-linenumber {color: #666666;} +.cm-s-bespin .CodeMirror-cursor {border-left: 1px solid #797977 !important;} + +.cm-s-bespin span.cm-comment {color: #937121;} +.cm-s-bespin span.cm-atom {color: #9b859d;} +.cm-s-bespin span.cm-number {color: #9b859d;} + +.cm-s-bespin span.cm-property, .cm-s-bespin span.cm-attribute {color: #54be0d;} +.cm-s-bespin span.cm-keyword {color: #cf6a4c;} +.cm-s-bespin span.cm-string {color: #f9ee98;} + +.cm-s-bespin span.cm-variable {color: #54be0d;} +.cm-s-bespin span.cm-variable-2 {color: #5ea6ea;} +.cm-s-bespin span.cm-def {color: #cf7d34;} +.cm-s-bespin span.cm-error {background: #cf6a4c; color: #797977;} +.cm-s-bespin span.cm-bracket {color: #9d9b97;} +.cm-s-bespin span.cm-tag {color: #cf6a4c;} +.cm-s-bespin span.cm-link {color: #9b859d;} + +.cm-s-bespin .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} +.cm-s-bespin .CodeMirror-activeline-background { background: #404040; } diff --git a/lib/redactor/codemirror/theme/blackboard.css b/lib/redactor/codemirror/theme/blackboard.css new file mode 100644 index 0000000..b6eaedb --- /dev/null +++ b/lib/redactor/codemirror/theme/blackboard.css @@ -0,0 +1,32 @@ +/* Port of TextMate's Blackboard theme */ + +.cm-s-blackboard.CodeMirror { background: #0C1021; color: #F8F8F8; } +.cm-s-blackboard div.CodeMirror-selected { background: #253B76; } +.cm-s-blackboard .CodeMirror-line::selection, .cm-s-blackboard .CodeMirror-line > span::selection, .cm-s-blackboard .CodeMirror-line > span > span::selection { background: rgba(37, 59, 118, .99); } +.cm-s-blackboard .CodeMirror-line::-moz-selection, .cm-s-blackboard .CodeMirror-line > span::-moz-selection, .cm-s-blackboard .CodeMirror-line > span > span::-moz-selection { background: rgba(37, 59, 118, .99); } +.cm-s-blackboard .CodeMirror-gutters { background: #0C1021; border-right: 0; } +.cm-s-blackboard .CodeMirror-guttermarker { color: #FBDE2D; } +.cm-s-blackboard .CodeMirror-guttermarker-subtle { color: #888; } +.cm-s-blackboard .CodeMirror-linenumber { color: #888; } +.cm-s-blackboard .CodeMirror-cursor { border-left: 1px solid #A7A7A7; } + +.cm-s-blackboard .cm-keyword { color: #FBDE2D; } +.cm-s-blackboard .cm-atom { color: #D8FA3C; } +.cm-s-blackboard .cm-number { color: #D8FA3C; } +.cm-s-blackboard .cm-def { color: #8DA6CE; } +.cm-s-blackboard .cm-variable { color: #FF6400; } +.cm-s-blackboard .cm-operator { color: #FBDE2D; } +.cm-s-blackboard .cm-comment { color: #AEAEAE; } +.cm-s-blackboard .cm-string { color: #61CE3C; } +.cm-s-blackboard .cm-string-2 { color: #61CE3C; } +.cm-s-blackboard .cm-meta { color: #D8FA3C; } +.cm-s-blackboard .cm-builtin { color: #8DA6CE; } +.cm-s-blackboard .cm-tag { color: #8DA6CE; } +.cm-s-blackboard .cm-attribute { color: #8DA6CE; } +.cm-s-blackboard .cm-header { color: #FF6400; } +.cm-s-blackboard .cm-hr { color: #AEAEAE; } +.cm-s-blackboard .cm-link { color: #8DA6CE; } +.cm-s-blackboard .cm-error { background: #9D1E15; color: #F8F8F8; } + +.cm-s-blackboard .CodeMirror-activeline-background { background: #3C3636; } +.cm-s-blackboard .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; } diff --git a/lib/redactor/codemirror/theme/cobalt.css b/lib/redactor/codemirror/theme/cobalt.css new file mode 100644 index 0000000..bbbda3b --- /dev/null +++ b/lib/redactor/codemirror/theme/cobalt.css @@ -0,0 +1,25 @@ +.cm-s-cobalt.CodeMirror { background: #002240; color: white; } +.cm-s-cobalt div.CodeMirror-selected { background: #b36539; } +.cm-s-cobalt .CodeMirror-line::selection, .cm-s-cobalt .CodeMirror-line > span::selection, .cm-s-cobalt .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); } +.cm-s-cobalt .CodeMirror-line::-moz-selection, .cm-s-cobalt .CodeMirror-line > span::-moz-selection, .cm-s-cobalt .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); } +.cm-s-cobalt .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-cobalt .CodeMirror-guttermarker { color: #ffee80; } +.cm-s-cobalt .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-cobalt .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-cobalt .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-cobalt span.cm-comment { color: #08f; } +.cm-s-cobalt span.cm-atom { color: #845dc4; } +.cm-s-cobalt span.cm-number, .cm-s-cobalt span.cm-attribute { color: #ff80e1; } +.cm-s-cobalt span.cm-keyword { color: #ffee80; } +.cm-s-cobalt span.cm-string { color: #3ad900; } +.cm-s-cobalt span.cm-meta { color: #ff9d00; } +.cm-s-cobalt span.cm-variable-2, .cm-s-cobalt span.cm-tag { color: #9effff; } +.cm-s-cobalt span.cm-variable-3, .cm-s-cobalt span.cm-def, .cm-s-cobalt .cm-type { color: white; } +.cm-s-cobalt span.cm-bracket { color: #d8d8d8; } +.cm-s-cobalt span.cm-builtin, .cm-s-cobalt span.cm-special { color: #ff9e59; } +.cm-s-cobalt span.cm-link { color: #845dc4; } +.cm-s-cobalt span.cm-error { color: #9d1e15; } + +.cm-s-cobalt .CodeMirror-activeline-background { background: #002D57; } +.cm-s-cobalt .CodeMirror-matchingbracket { outline:1px solid grey;color:white !important; } diff --git a/lib/redactor/codemirror/theme/colorforth.css b/lib/redactor/codemirror/theme/colorforth.css new file mode 100644 index 0000000..19095e4 --- /dev/null +++ b/lib/redactor/codemirror/theme/colorforth.css @@ -0,0 +1,33 @@ +.cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; } +.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; } +.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; } +.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; } +.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-colorforth span.cm-comment { color: #ededed; } +.cm-s-colorforth span.cm-def { color: #ff1c1c; font-weight:bold; } +.cm-s-colorforth span.cm-keyword { color: #ffd900; } +.cm-s-colorforth span.cm-builtin { color: #00d95a; } +.cm-s-colorforth span.cm-variable { color: #73ff00; } +.cm-s-colorforth span.cm-string { color: #007bff; } +.cm-s-colorforth span.cm-number { color: #00c4ff; } +.cm-s-colorforth span.cm-atom { color: #606060; } + +.cm-s-colorforth span.cm-variable-2 { color: #EEE; } +.cm-s-colorforth span.cm-variable-3, .cm-s-colorforth span.cm-type { color: #DDD; } +.cm-s-colorforth span.cm-property {} +.cm-s-colorforth span.cm-operator {} + +.cm-s-colorforth span.cm-meta { color: yellow; } +.cm-s-colorforth span.cm-qualifier { color: #FFF700; } +.cm-s-colorforth span.cm-bracket { color: #cc7; } +.cm-s-colorforth span.cm-tag { color: #FFBD40; } +.cm-s-colorforth span.cm-attribute { color: #FFF700; } +.cm-s-colorforth span.cm-error { color: #f00; } + +.cm-s-colorforth div.CodeMirror-selected { background: #333d53; } + +.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); } + +.cm-s-colorforth .CodeMirror-activeline-background { background: #253540; } diff --git a/lib/redactor/codemirror/theme/darcula.css b/lib/redactor/codemirror/theme/darcula.css new file mode 100644 index 0000000..2ec81a3 --- /dev/null +++ b/lib/redactor/codemirror/theme/darcula.css @@ -0,0 +1,53 @@ +/** + Name: IntelliJ IDEA darcula theme + From IntelliJ IDEA by JetBrains + */ + +.cm-s-darcula { font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif;} +.cm-s-darcula.CodeMirror { background: #2B2B2B; color: #A9B7C6; } + +.cm-s-darcula span.cm-meta { color: #BBB529; } +.cm-s-darcula span.cm-number { color: #6897BB; } +.cm-s-darcula span.cm-keyword { color: #CC7832; line-height: 1em; font-weight: bold; } +.cm-s-darcula span.cm-def { color: #A9B7C6; font-style: italic; } +.cm-s-darcula span.cm-variable { color: #A9B7C6; } +.cm-s-darcula span.cm-variable-2 { color: #A9B7C6; } +.cm-s-darcula span.cm-variable-3 { color: #9876AA; } +.cm-s-darcula span.cm-type { color: #AABBCC; font-weight: bold; } +.cm-s-darcula span.cm-property { color: #FFC66D; } +.cm-s-darcula span.cm-operator { color: #A9B7C6; } +.cm-s-darcula span.cm-string { color: #6A8759; } +.cm-s-darcula span.cm-string-2 { color: #6A8759; } +.cm-s-darcula span.cm-comment { color: #61A151; font-style: italic; } +.cm-s-darcula span.cm-link { color: #CC7832; } +.cm-s-darcula span.cm-atom { color: #CC7832; } +.cm-s-darcula span.cm-error { color: #BC3F3C; } +.cm-s-darcula span.cm-tag { color: #629755; font-weight: bold; font-style: italic; text-decoration: underline; } +.cm-s-darcula span.cm-attribute { color: #6897bb; } +.cm-s-darcula span.cm-qualifier { color: #6A8759; } +.cm-s-darcula span.cm-bracket { color: #A9B7C6; } +.cm-s-darcula span.cm-builtin { color: #FF9E59; } +.cm-s-darcula span.cm-special { color: #FF9E59; } +.cm-s-darcula span.cm-matchhighlight { color: #FFFFFF; background-color: rgba(50, 89, 48, .7); font-weight: normal;} +.cm-s-darcula span.cm-searching { color: #FFFFFF; background-color: rgba(61, 115, 59, .7); font-weight: normal;} + +.cm-s-darcula .CodeMirror-cursor { border-left: 1px solid #A9B7C6; } +.cm-s-darcula .CodeMirror-activeline-background { background: #323232; } +.cm-s-darcula .CodeMirror-gutters { background: #313335; border-right: 1px solid #313335; } +.cm-s-darcula .CodeMirror-guttermarker { color: #FFEE80; } +.cm-s-darcula .CodeMirror-guttermarker-subtle { color: #D0D0D0; } +.cm-s-darcula .CodeMirrir-linenumber { color: #606366; } +.cm-s-darcula .CodeMirror-matchingbracket { background-color: #3B514D; color: #FFEF28 !important; font-weight: bold; } + +.cm-s-darcula div.CodeMirror-selected { background: #214283; } + +.CodeMirror-hints.darcula { + font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; + color: #9C9E9E; + background-color: #3B3E3F !important; +} + +.CodeMirror-hints.darcula .CodeMirror-hint-active { + background-color: #494D4E !important; + color: #9C9E9E !important; +} diff --git a/lib/redactor/codemirror/theme/dracula.css b/lib/redactor/codemirror/theme/dracula.css new file mode 100644 index 0000000..253133e --- /dev/null +++ b/lib/redactor/codemirror/theme/dracula.css @@ -0,0 +1,40 @@ +/* + + Name: dracula + Author: Michael Kaminsky (http://github.com/mkaminsky11) + + Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme) + +*/ + + +.cm-s-dracula.CodeMirror, .cm-s-dracula .CodeMirror-gutters { + background-color: #282a36 !important; + color: #f8f8f2 !important; + border: none; +} +.cm-s-dracula .CodeMirror-gutters { color: #282a36; } +.cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; } +.cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; } +.cm-s-dracula .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula span.cm-comment { color: #6272a4; } +.cm-s-dracula span.cm-string, .cm-s-dracula span.cm-string-2 { color: #f1fa8c; } +.cm-s-dracula span.cm-number { color: #bd93f9; } +.cm-s-dracula span.cm-variable { color: #50fa7b; } +.cm-s-dracula span.cm-variable-2 { color: white; } +.cm-s-dracula span.cm-def { color: #50fa7b; } +.cm-s-dracula span.cm-operator { color: #ff79c6; } +.cm-s-dracula span.cm-keyword { color: #ff79c6; } +.cm-s-dracula span.cm-atom { color: #bd93f9; } +.cm-s-dracula span.cm-meta { color: #f8f8f2; } +.cm-s-dracula span.cm-tag { color: #ff79c6; } +.cm-s-dracula span.cm-attribute { color: #50fa7b; } +.cm-s-dracula span.cm-qualifier { color: #50fa7b; } +.cm-s-dracula span.cm-property { color: #66d9ef; } +.cm-s-dracula span.cm-builtin { color: #50fa7b; } +.cm-s-dracula span.cm-variable-3, .cm-s-dracula span.cm-type { color: #ffb86c; } + +.cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); } +.cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/duotone-dark.css b/lib/redactor/codemirror/theme/duotone-dark.css new file mode 100644 index 0000000..88fdc76 --- /dev/null +++ b/lib/redactor/codemirror/theme/duotone-dark.css @@ -0,0 +1,35 @@ +/* +Name: DuoTone-Dark +Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes) + +CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/) +*/ + +.cm-s-duotone-dark.CodeMirror { background: #2a2734; color: #6c6783; } +.cm-s-duotone-dark div.CodeMirror-selected { background: #545167!important; } +.cm-s-duotone-dark .CodeMirror-gutters { background: #2a2734; border-right: 0px; } +.cm-s-duotone-dark .CodeMirror-linenumber { color: #545167; } + +/* begin cursor */ +.cm-s-duotone-dark .CodeMirror-cursor { border-left: 1px solid #ffad5c; /* border-left: 1px solid #ffad5c80; */ border-right: .5em solid #ffad5c; /* border-right: .5em solid #ffad5c80; */ opacity: .5; } +.cm-s-duotone-dark .CodeMirror-activeline-background { background: #363342; /* background: #36334280; */ opacity: .5;} +.cm-s-duotone-dark .cm-fat-cursor .CodeMirror-cursor { background: #ffad5c; /* background: #ffad5c80; */ opacity: .5;} +/* end cursor */ + +.cm-s-duotone-dark span.cm-atom, .cm-s-duotone-dark span.cm-number, .cm-s-duotone-dark span.cm-keyword, .cm-s-duotone-dark span.cm-variable, .cm-s-duotone-dark span.cm-attribute, .cm-s-duotone-dark span.cm-quote, .cm-s-duotone-dark span.cm-hr, .cm-s-duotone-dark span.cm-link { color: #ffcc99; } + +.cm-s-duotone-dark span.cm-property { color: #9a86fd; } +.cm-s-duotone-dark span.cm-punctuation, .cm-s-duotone-dark span.cm-unit, .cm-s-duotone-dark span.cm-negative { color: #e09142; } +.cm-s-duotone-dark span.cm-string { color: #ffb870; } +.cm-s-duotone-dark span.cm-operator { color: #ffad5c; } +.cm-s-duotone-dark span.cm-positive { color: #6a51e6; } + +.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-type, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; } +.cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; } +.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; } + +/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */ +.cm-s-duotone-dark span.cm-error, .cm-s-duotone-dark span.cm-invalidchar { color: #f00; } + +.cm-s-duotone-dark span.cm-header { font-weight: normal; } +.cm-s-duotone-dark .CodeMirror-matchingbracket { text-decoration: underline; color: #eeebff !important; } diff --git a/lib/redactor/codemirror/theme/duotone-light.css b/lib/redactor/codemirror/theme/duotone-light.css new file mode 100644 index 0000000..d99480f --- /dev/null +++ b/lib/redactor/codemirror/theme/duotone-light.css @@ -0,0 +1,36 @@ +/* +Name: DuoTone-Light +Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes) + +CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/) +*/ + +.cm-s-duotone-light.CodeMirror { background: #faf8f5; color: #b29762; } +.cm-s-duotone-light div.CodeMirror-selected { background: #e3dcce !important; } +.cm-s-duotone-light .CodeMirror-gutters { background: #faf8f5; border-right: 0px; } +.cm-s-duotone-light .CodeMirror-linenumber { color: #cdc4b1; } + +/* begin cursor */ +.cm-s-duotone-light .CodeMirror-cursor { border-left: 1px solid #93abdc; /* border-left: 1px solid #93abdc80; */ border-right: .5em solid #93abdc; /* border-right: .5em solid #93abdc80; */ opacity: .5; } +.cm-s-duotone-light .CodeMirror-activeline-background { background: #e3dcce; /* background: #e3dcce80; */ opacity: .5; } +.cm-s-duotone-light .cm-fat-cursor .CodeMirror-cursor { background: #93abdc; /* #93abdc80; */ opacity: .5; } +/* end cursor */ + +.cm-s-duotone-light span.cm-atom, .cm-s-duotone-light span.cm-number, .cm-s-duotone-light span.cm-keyword, .cm-s-duotone-light span.cm-variable, .cm-s-duotone-light span.cm-attribute, .cm-s-duotone-light span.cm-quote, .cm-s-duotone-light-light span.cm-hr, .cm-s-duotone-light-light span.cm-link { color: #063289; } + +.cm-s-duotone-light span.cm-property { color: #b29762; } +.cm-s-duotone-light span.cm-punctuation, .cm-s-duotone-light span.cm-unit, .cm-s-duotone-light span.cm-negative { color: #063289; } +.cm-s-duotone-light span.cm-string, .cm-s-duotone-light span.cm-operator { color: #1659df; } +.cm-s-duotone-light span.cm-positive { color: #896724; } + +.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-type, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; } +.cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; } +.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; } + +/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */ +/* .cm-s-duotone-light span.cm-error { background: #896724; color: #728fcb; } */ +.cm-s-duotone-light span.cm-error, .cm-s-duotone-light span.cm-invalidchar { color: #f00; } + +.cm-s-duotone-light span.cm-header { font-weight: normal; } +.cm-s-duotone-light .CodeMirror-matchingbracket { text-decoration: underline; color: #faf8f5 !important; } + diff --git a/lib/redactor/codemirror/theme/eclipse.css b/lib/redactor/codemirror/theme/eclipse.css new file mode 100644 index 0000000..800d603 --- /dev/null +++ b/lib/redactor/codemirror/theme/eclipse.css @@ -0,0 +1,23 @@ +.cm-s-eclipse span.cm-meta { color: #FF1717; } +.cm-s-eclipse span.cm-keyword { line-height: 1em; font-weight: bold; color: #7F0055; } +.cm-s-eclipse span.cm-atom { color: #219; } +.cm-s-eclipse span.cm-number { color: #164; } +.cm-s-eclipse span.cm-def { color: #00f; } +.cm-s-eclipse span.cm-variable { color: black; } +.cm-s-eclipse span.cm-variable-2 { color: #0000C0; } +.cm-s-eclipse span.cm-variable-3, .cm-s-eclipse span.cm-type { color: #0000C0; } +.cm-s-eclipse span.cm-property { color: black; } +.cm-s-eclipse span.cm-operator { color: black; } +.cm-s-eclipse span.cm-comment { color: #3F7F5F; } +.cm-s-eclipse span.cm-string { color: #2A00FF; } +.cm-s-eclipse span.cm-string-2 { color: #f50; } +.cm-s-eclipse span.cm-qualifier { color: #555; } +.cm-s-eclipse span.cm-builtin { color: #30a; } +.cm-s-eclipse span.cm-bracket { color: #cc7; } +.cm-s-eclipse span.cm-tag { color: #170; } +.cm-s-eclipse span.cm-attribute { color: #00c; } +.cm-s-eclipse span.cm-link { color: #219; } +.cm-s-eclipse span.cm-error { color: #f00; } + +.cm-s-eclipse .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } diff --git a/lib/redactor/codemirror/theme/elegant.css b/lib/redactor/codemirror/theme/elegant.css new file mode 100644 index 0000000..45b3ea6 --- /dev/null +++ b/lib/redactor/codemirror/theme/elegant.css @@ -0,0 +1,13 @@ +.cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; } +.cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; } +.cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; } +.cm-s-elegant span.cm-variable { color: black; } +.cm-s-elegant span.cm-variable-2 { color: #b11; } +.cm-s-elegant span.cm-qualifier { color: #555; } +.cm-s-elegant span.cm-keyword { color: #730; } +.cm-s-elegant span.cm-builtin { color: #30a; } +.cm-s-elegant span.cm-link { color: #762; } +.cm-s-elegant span.cm-error { background-color: #fdd; } + +.cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } diff --git a/lib/redactor/codemirror/theme/erlang-dark.css b/lib/redactor/codemirror/theme/erlang-dark.css new file mode 100644 index 0000000..8c8a417 --- /dev/null +++ b/lib/redactor/codemirror/theme/erlang-dark.css @@ -0,0 +1,34 @@ +.cm-s-erlang-dark.CodeMirror { background: #002240; color: white; } +.cm-s-erlang-dark div.CodeMirror-selected { background: #b36539; } +.cm-s-erlang-dark .CodeMirror-line::selection, .cm-s-erlang-dark .CodeMirror-line > span::selection, .cm-s-erlang-dark .CodeMirror-line > span > span::selection { background: rgba(179, 101, 57, .99); } +.cm-s-erlang-dark .CodeMirror-line::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span::-moz-selection, .cm-s-erlang-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(179, 101, 57, .99); } +.cm-s-erlang-dark .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-erlang-dark .CodeMirror-guttermarker { color: white; } +.cm-s-erlang-dark .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-erlang-dark span.cm-quote { color: #ccc; } +.cm-s-erlang-dark span.cm-atom { color: #f133f1; } +.cm-s-erlang-dark span.cm-attribute { color: #ff80e1; } +.cm-s-erlang-dark span.cm-bracket { color: #ff9d00; } +.cm-s-erlang-dark span.cm-builtin { color: #eaa; } +.cm-s-erlang-dark span.cm-comment { color: #77f; } +.cm-s-erlang-dark span.cm-def { color: #e7a; } +.cm-s-erlang-dark span.cm-keyword { color: #ffee80; } +.cm-s-erlang-dark span.cm-meta { color: #50fefe; } +.cm-s-erlang-dark span.cm-number { color: #ffd0d0; } +.cm-s-erlang-dark span.cm-operator { color: #d55; } +.cm-s-erlang-dark span.cm-property { color: #ccc; } +.cm-s-erlang-dark span.cm-qualifier { color: #ccc; } +.cm-s-erlang-dark span.cm-special { color: #ffbbbb; } +.cm-s-erlang-dark span.cm-string { color: #3ad900; } +.cm-s-erlang-dark span.cm-string-2 { color: #ccc; } +.cm-s-erlang-dark span.cm-tag { color: #9effff; } +.cm-s-erlang-dark span.cm-variable { color: #50fe50; } +.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; } +.cm-s-erlang-dark span.cm-variable-3, .cm-s-erlang-dark span.cm-type { color: #ccc; } +.cm-s-erlang-dark span.cm-error { color: #9d1e15; } + +.cm-s-erlang-dark .CodeMirror-activeline-background { background: #013461; } +.cm-s-erlang-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } diff --git a/lib/redactor/codemirror/theme/gruvbox-dark.css b/lib/redactor/codemirror/theme/gruvbox-dark.css new file mode 100644 index 0000000..ded215f --- /dev/null +++ b/lib/redactor/codemirror/theme/gruvbox-dark.css @@ -0,0 +1,37 @@ +/* + + Name: gruvbox-dark + Author: kRkk (https://github.com/krkk) + + Original gruvbox color scheme by Pavel Pertsev (https://github.com/morhetz/gruvbox) + +*/ + +.cm-s-gruvbox-dark.CodeMirror, .cm-s-gruvbox-dark .CodeMirror-gutters { background-color: #282828; color: #bdae93; } +.cm-s-gruvbox-dark .CodeMirror-gutters {background: #282828; border-right: 0px;} +.cm-s-gruvbox-dark .CodeMirror-linenumber {color: #7c6f64;} +.cm-s-gruvbox-dark .CodeMirror-cursor { border-left: 1px solid #ebdbb2; } +.cm-s-gruvbox-dark div.CodeMirror-selected { background: #928374; } +.cm-s-gruvbox-dark span.cm-meta { color: #83a598; } + +.cm-s-gruvbox-dark span.cm-comment { color: #928374; } +.cm-s-gruvbox-dark span.cm-number, span.cm-atom { color: #d3869b; } +.cm-s-gruvbox-dark span.cm-keyword { color: #f84934; } + +.cm-s-gruvbox-dark span.cm-variable { color: #ebdbb2; } +.cm-s-gruvbox-dark span.cm-variable-2 { color: #ebdbb2; } +.cm-s-gruvbox-dark span.cm-variable-3, .cm-s-gruvbox-dark span.cm-type { color: #fabd2f; } +.cm-s-gruvbox-dark span.cm-operator { color: #ebdbb2; } +.cm-s-gruvbox-dark span.cm-callee { color: #ebdbb2; } +.cm-s-gruvbox-dark span.cm-def { color: #ebdbb2; } +.cm-s-gruvbox-dark span.cm-property { color: #ebdbb2; } +.cm-s-gruvbox-dark span.cm-string { color: #b8bb26; } +.cm-s-gruvbox-dark span.cm-string-2 { color: #8ec07c; } +.cm-s-gruvbox-dark span.cm-qualifier { color: #8ec07c; } +.cm-s-gruvbox-dark span.cm-attribute { color: #8ec07c; } + +.cm-s-gruvbox-dark .CodeMirror-activeline-background { background: #3c3836; } +.cm-s-gruvbox-dark .CodeMirror-matchingbracket { background: #928374; color:#282828 !important; } + +.cm-s-gruvbox-dark span.cm-builtin { color: #fe8019; } +.cm-s-gruvbox-dark span.cm-tag { color: #fe8019; } diff --git a/lib/redactor/codemirror/theme/hopscotch.css b/lib/redactor/codemirror/theme/hopscotch.css new file mode 100644 index 0000000..7d05431 --- /dev/null +++ b/lib/redactor/codemirror/theme/hopscotch.css @@ -0,0 +1,34 @@ +/* + + Name: Hopscotch + Author: Jan T. Sott + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-hopscotch.CodeMirror {background: #322931; color: #d5d3d5;} +.cm-s-hopscotch div.CodeMirror-selected {background: #433b42 !important;} +.cm-s-hopscotch .CodeMirror-gutters {background: #322931; border-right: 0px;} +.cm-s-hopscotch .CodeMirror-linenumber {color: #797379;} +.cm-s-hopscotch .CodeMirror-cursor {border-left: 1px solid #989498 !important;} + +.cm-s-hopscotch span.cm-comment {color: #b33508;} +.cm-s-hopscotch span.cm-atom {color: #c85e7c;} +.cm-s-hopscotch span.cm-number {color: #c85e7c;} + +.cm-s-hopscotch span.cm-property, .cm-s-hopscotch span.cm-attribute {color: #8fc13e;} +.cm-s-hopscotch span.cm-keyword {color: #dd464c;} +.cm-s-hopscotch span.cm-string {color: #fdcc59;} + +.cm-s-hopscotch span.cm-variable {color: #8fc13e;} +.cm-s-hopscotch span.cm-variable-2 {color: #1290bf;} +.cm-s-hopscotch span.cm-def {color: #fd8b19;} +.cm-s-hopscotch span.cm-error {background: #dd464c; color: #989498;} +.cm-s-hopscotch span.cm-bracket {color: #d5d3d5;} +.cm-s-hopscotch span.cm-tag {color: #dd464c;} +.cm-s-hopscotch span.cm-link {color: #c85e7c;} + +.cm-s-hopscotch .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} +.cm-s-hopscotch .CodeMirror-activeline-background { background: #302020; } diff --git a/lib/redactor/codemirror/theme/icecoder.css b/lib/redactor/codemirror/theme/icecoder.css new file mode 100644 index 0000000..5440fbe --- /dev/null +++ b/lib/redactor/codemirror/theme/icecoder.css @@ -0,0 +1,43 @@ +/* +ICEcoder default theme by Matt Pass, used in code editor available at https://icecoder.net +*/ + +.cm-s-icecoder { color: #666; background: #1d1d1b; } + +.cm-s-icecoder span.cm-keyword { color: #eee; font-weight:bold; } /* off-white 1 */ +.cm-s-icecoder span.cm-atom { color: #e1c76e; } /* yellow */ +.cm-s-icecoder span.cm-number { color: #6cb5d9; } /* blue */ +.cm-s-icecoder span.cm-def { color: #b9ca4a; } /* green */ + +.cm-s-icecoder span.cm-variable { color: #6cb5d9; } /* blue */ +.cm-s-icecoder span.cm-variable-2 { color: #cc1e5c; } /* pink */ +.cm-s-icecoder span.cm-variable-3, .cm-s-icecoder span.cm-type { color: #f9602c; } /* orange */ + +.cm-s-icecoder span.cm-property { color: #eee; } /* off-white 1 */ +.cm-s-icecoder span.cm-operator { color: #9179bb; } /* purple */ +.cm-s-icecoder span.cm-comment { color: #97a3aa; } /* grey-blue */ + +.cm-s-icecoder span.cm-string { color: #b9ca4a; } /* green */ +.cm-s-icecoder span.cm-string-2 { color: #6cb5d9; } /* blue */ + +.cm-s-icecoder span.cm-meta { color: #555; } /* grey */ + +.cm-s-icecoder span.cm-qualifier { color: #555; } /* grey */ +.cm-s-icecoder span.cm-builtin { color: #214e7b; } /* bright blue */ +.cm-s-icecoder span.cm-bracket { color: #cc7; } /* grey-yellow */ + +.cm-s-icecoder span.cm-tag { color: #e8e8e8; } /* off-white 2 */ +.cm-s-icecoder span.cm-attribute { color: #099; } /* teal */ + +.cm-s-icecoder span.cm-header { color: #6a0d6a; } /* purple-pink */ +.cm-s-icecoder span.cm-quote { color: #186718; } /* dark green */ +.cm-s-icecoder span.cm-hr { color: #888; } /* mid-grey */ +.cm-s-icecoder span.cm-link { color: #e1c76e; } /* yellow */ +.cm-s-icecoder span.cm-error { color: #d00; } /* red */ + +.cm-s-icecoder .CodeMirror-cursor { border-left: 1px solid white; } +.cm-s-icecoder div.CodeMirror-selected { color: #fff; background: #037; } +.cm-s-icecoder .CodeMirror-gutters { background: #1d1d1b; min-width: 41px; border-right: 0; } +.cm-s-icecoder .CodeMirror-linenumber { color: #555; cursor: default; } +.cm-s-icecoder .CodeMirror-matchingbracket { color: #fff !important; background: #555 !important; } +.cm-s-icecoder .CodeMirror-activeline-background { background: #000; } diff --git a/lib/redactor/codemirror/theme/idea.css b/lib/redactor/codemirror/theme/idea.css new file mode 100644 index 0000000..eab3671 --- /dev/null +++ b/lib/redactor/codemirror/theme/idea.css @@ -0,0 +1,42 @@ +/** + Name: IDEA default theme + From IntelliJ IDEA by JetBrains + */ + +.cm-s-idea span.cm-meta { color: #808000; } +.cm-s-idea span.cm-number { color: #0000FF; } +.cm-s-idea span.cm-keyword { line-height: 1em; font-weight: bold; color: #000080; } +.cm-s-idea span.cm-atom { font-weight: bold; color: #000080; } +.cm-s-idea span.cm-def { color: #000000; } +.cm-s-idea span.cm-variable { color: black; } +.cm-s-idea span.cm-variable-2 { color: black; } +.cm-s-idea span.cm-variable-3, .cm-s-idea span.cm-type { color: black; } +.cm-s-idea span.cm-property { color: black; } +.cm-s-idea span.cm-operator { color: black; } +.cm-s-idea span.cm-comment { color: #808080; } +.cm-s-idea span.cm-string { color: #008000; } +.cm-s-idea span.cm-string-2 { color: #008000; } +.cm-s-idea span.cm-qualifier { color: #555; } +.cm-s-idea span.cm-error { color: #FF0000; } +.cm-s-idea span.cm-attribute { color: #0000FF; } +.cm-s-idea span.cm-tag { color: #000080; } +.cm-s-idea span.cm-link { color: #0000FF; } +.cm-s-idea .CodeMirror-activeline-background { background: #FFFAE3; } + +.cm-s-idea span.cm-builtin { color: #30a; } +.cm-s-idea span.cm-bracket { color: #cc7; } +.cm-s-idea { font-family: Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;} + + +.cm-s-idea .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } + +.CodeMirror-hints.idea { + font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; + color: #616569; + background-color: #ebf3fd !important; +} + +.CodeMirror-hints.idea .CodeMirror-hint-active { + background-color: #a2b8c9 !important; + color: #5c6065 !important; +} \ No newline at end of file diff --git a/lib/redactor/codemirror/theme/isotope.css b/lib/redactor/codemirror/theme/isotope.css new file mode 100644 index 0000000..d0d6263 --- /dev/null +++ b/lib/redactor/codemirror/theme/isotope.css @@ -0,0 +1,34 @@ +/* + + Name: Isotope + Author: David Desandro / Jan T. Sott + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-isotope.CodeMirror {background: #000000; color: #e0e0e0;} +.cm-s-isotope div.CodeMirror-selected {background: #404040 !important;} +.cm-s-isotope .CodeMirror-gutters {background: #000000; border-right: 0px;} +.cm-s-isotope .CodeMirror-linenumber {color: #808080;} +.cm-s-isotope .CodeMirror-cursor {border-left: 1px solid #c0c0c0 !important;} + +.cm-s-isotope span.cm-comment {color: #3300ff;} +.cm-s-isotope span.cm-atom {color: #cc00ff;} +.cm-s-isotope span.cm-number {color: #cc00ff;} + +.cm-s-isotope span.cm-property, .cm-s-isotope span.cm-attribute {color: #33ff00;} +.cm-s-isotope span.cm-keyword {color: #ff0000;} +.cm-s-isotope span.cm-string {color: #ff0099;} + +.cm-s-isotope span.cm-variable {color: #33ff00;} +.cm-s-isotope span.cm-variable-2 {color: #0066ff;} +.cm-s-isotope span.cm-def {color: #ff9900;} +.cm-s-isotope span.cm-error {background: #ff0000; color: #c0c0c0;} +.cm-s-isotope span.cm-bracket {color: #e0e0e0;} +.cm-s-isotope span.cm-tag {color: #ff0000;} +.cm-s-isotope span.cm-link {color: #cc00ff;} + +.cm-s-isotope .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} +.cm-s-isotope .CodeMirror-activeline-background { background: #202020; } diff --git a/lib/redactor/codemirror/theme/lesser-dark.css b/lib/redactor/codemirror/theme/lesser-dark.css new file mode 100644 index 0000000..f96bf43 --- /dev/null +++ b/lib/redactor/codemirror/theme/lesser-dark.css @@ -0,0 +1,47 @@ +/* +http://lesscss.org/ dark theme +Ported to CodeMirror by Peter Kroon +*/ +.cm-s-lesser-dark { + line-height: 1.3em; +} +.cm-s-lesser-dark.CodeMirror { background: #262626; color: #EBEFE7; text-shadow: 0 -1px 1px #262626; } +.cm-s-lesser-dark div.CodeMirror-selected { background: #45443B; } /* 33322B*/ +.cm-s-lesser-dark .CodeMirror-line::selection, .cm-s-lesser-dark .CodeMirror-line > span::selection, .cm-s-lesser-dark .CodeMirror-line > span > span::selection { background: rgba(69, 68, 59, .99); } +.cm-s-lesser-dark .CodeMirror-line::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span::-moz-selection, .cm-s-lesser-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(69, 68, 59, .99); } +.cm-s-lesser-dark .CodeMirror-cursor { border-left: 1px solid white; } +.cm-s-lesser-dark pre { padding: 0 8px; }/*editable code holder*/ + +.cm-s-lesser-dark.CodeMirror span.CodeMirror-matchingbracket { color: #7EFC7E; }/*65FC65*/ + +.cm-s-lesser-dark .CodeMirror-gutters { background: #262626; border-right:1px solid #aaa; } +.cm-s-lesser-dark .CodeMirror-guttermarker { color: #599eff; } +.cm-s-lesser-dark .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-lesser-dark .CodeMirror-linenumber { color: #777; } + +.cm-s-lesser-dark span.cm-header { color: #a0a; } +.cm-s-lesser-dark span.cm-quote { color: #090; } +.cm-s-lesser-dark span.cm-keyword { color: #599eff; } +.cm-s-lesser-dark span.cm-atom { color: #C2B470; } +.cm-s-lesser-dark span.cm-number { color: #B35E4D; } +.cm-s-lesser-dark span.cm-def { color: white; } +.cm-s-lesser-dark span.cm-variable { color:#D9BF8C; } +.cm-s-lesser-dark span.cm-variable-2 { color: #669199; } +.cm-s-lesser-dark span.cm-variable-3, .cm-s-lesser-dark span.cm-type { color: white; } +.cm-s-lesser-dark span.cm-property { color: #92A75C; } +.cm-s-lesser-dark span.cm-operator { color: #92A75C; } +.cm-s-lesser-dark span.cm-comment { color: #666; } +.cm-s-lesser-dark span.cm-string { color: #BCD279; } +.cm-s-lesser-dark span.cm-string-2 { color: #f50; } +.cm-s-lesser-dark span.cm-meta { color: #738C73; } +.cm-s-lesser-dark span.cm-qualifier { color: #555; } +.cm-s-lesser-dark span.cm-builtin { color: #ff9e59; } +.cm-s-lesser-dark span.cm-bracket { color: #EBEFE7; } +.cm-s-lesser-dark span.cm-tag { color: #669199; } +.cm-s-lesser-dark span.cm-attribute { color: #81a4d5; } +.cm-s-lesser-dark span.cm-hr { color: #999; } +.cm-s-lesser-dark span.cm-link { color: #7070E6; } +.cm-s-lesser-dark span.cm-error { color: #9d1e15; } + +.cm-s-lesser-dark .CodeMirror-activeline-background { background: #3C3A3A; } +.cm-s-lesser-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } diff --git a/lib/redactor/codemirror/theme/liquibyte.css b/lib/redactor/codemirror/theme/liquibyte.css new file mode 100644 index 0000000..393825e --- /dev/null +++ b/lib/redactor/codemirror/theme/liquibyte.css @@ -0,0 +1,95 @@ +.cm-s-liquibyte.CodeMirror { + background-color: #000; + color: #fff; + line-height: 1.2em; + font-size: 1em; +} +.cm-s-liquibyte .CodeMirror-focused .cm-matchhighlight { + text-decoration: underline; + text-decoration-color: #0f0; + text-decoration-style: wavy; +} +.cm-s-liquibyte .cm-trailingspace { + text-decoration: line-through; + text-decoration-color: #f00; + text-decoration-style: dotted; +} +.cm-s-liquibyte .cm-tab { + text-decoration: line-through; + text-decoration-color: #404040; + text-decoration-style: dotted; +} +.cm-s-liquibyte .CodeMirror-gutters { background-color: #262626; border-right: 1px solid #505050; padding-right: 0.8em; } +.cm-s-liquibyte .CodeMirror-gutter-elt div { font-size: 1.2em; } +.cm-s-liquibyte .CodeMirror-guttermarker { } +.cm-s-liquibyte .CodeMirror-guttermarker-subtle { } +.cm-s-liquibyte .CodeMirror-linenumber { color: #606060; padding-left: 0; } +.cm-s-liquibyte .CodeMirror-cursor { border-left: 1px solid #eee; } + +.cm-s-liquibyte span.cm-comment { color: #008000; } +.cm-s-liquibyte span.cm-def { color: #ffaf40; font-weight: bold; } +.cm-s-liquibyte span.cm-keyword { color: #c080ff; font-weight: bold; } +.cm-s-liquibyte span.cm-builtin { color: #ffaf40; font-weight: bold; } +.cm-s-liquibyte span.cm-variable { color: #5967ff; font-weight: bold; } +.cm-s-liquibyte span.cm-string { color: #ff8000; } +.cm-s-liquibyte span.cm-number { color: #0f0; font-weight: bold; } +.cm-s-liquibyte span.cm-atom { color: #bf3030; font-weight: bold; } + +.cm-s-liquibyte span.cm-variable-2 { color: #007f7f; font-weight: bold; } +.cm-s-liquibyte span.cm-variable-3, .cm-s-liquibyte span.cm-type { color: #c080ff; font-weight: bold; } +.cm-s-liquibyte span.cm-property { color: #999; font-weight: bold; } +.cm-s-liquibyte span.cm-operator { color: #fff; } + +.cm-s-liquibyte span.cm-meta { color: #0f0; } +.cm-s-liquibyte span.cm-qualifier { color: #fff700; font-weight: bold; } +.cm-s-liquibyte span.cm-bracket { color: #cc7; } +.cm-s-liquibyte span.cm-tag { color: #ff0; font-weight: bold; } +.cm-s-liquibyte span.cm-attribute { color: #c080ff; font-weight: bold; } +.cm-s-liquibyte span.cm-error { color: #f00; } + +.cm-s-liquibyte div.CodeMirror-selected { background-color: rgba(255, 0, 0, 0.25); } + +.cm-s-liquibyte span.cm-compilation { background-color: rgba(255, 255, 255, 0.12); } + +.cm-s-liquibyte .CodeMirror-activeline-background { background-color: rgba(0, 255, 0, 0.15); } + +/* Default styles for common addons */ +.cm-s-liquibyte .CodeMirror span.CodeMirror-matchingbracket { color: #0f0; font-weight: bold; } +.cm-s-liquibyte .CodeMirror span.CodeMirror-nonmatchingbracket { color: #f00; font-weight: bold; } +.CodeMirror-matchingtag { background-color: rgba(150, 255, 0, .3); } +/* Scrollbars */ +/* Simple */ +.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div:hover, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div:hover { + background-color: rgba(80, 80, 80, .7); +} +.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div, .cm-s-liquibyte div.CodeMirror-simplescroll-vertical div { + background-color: rgba(80, 80, 80, .3); + border: 1px solid #404040; + border-radius: 5px; +} +.cm-s-liquibyte div.CodeMirror-simplescroll-vertical div { + border-top: 1px solid #404040; + border-bottom: 1px solid #404040; +} +.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal div { + border-left: 1px solid #404040; + border-right: 1px solid #404040; +} +.cm-s-liquibyte div.CodeMirror-simplescroll-vertical { + background-color: #262626; +} +.cm-s-liquibyte div.CodeMirror-simplescroll-horizontal { + background-color: #262626; + border-top: 1px solid #404040; +} +/* Overlay */ +.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div, div.CodeMirror-overlayscroll-vertical div { + background-color: #404040; + border-radius: 5px; +} +.cm-s-liquibyte div.CodeMirror-overlayscroll-vertical div { + border: 1px solid #404040; +} +.cm-s-liquibyte div.CodeMirror-overlayscroll-horizontal div { + border: 1px solid #404040; +} diff --git a/lib/redactor/codemirror/theme/lucario.css b/lib/redactor/codemirror/theme/lucario.css new file mode 100644 index 0000000..17a1551 --- /dev/null +++ b/lib/redactor/codemirror/theme/lucario.css @@ -0,0 +1,37 @@ +/* + Name: lucario + Author: Raphael Amorim + + Original Lucario color scheme (https://github.com/raphamorim/lucario) +*/ + +.cm-s-lucario.CodeMirror, .cm-s-lucario .CodeMirror-gutters { + background-color: #2b3e50 !important; + color: #f8f8f2 !important; + border: none; +} +.cm-s-lucario .CodeMirror-gutters { color: #2b3e50; } +.cm-s-lucario .CodeMirror-cursor { border-left: solid thin #E6C845; } +.cm-s-lucario .CodeMirror-linenumber { color: #f8f8f2; } +.cm-s-lucario .CodeMirror-selected { background: #243443; } +.cm-s-lucario .CodeMirror-line::selection, .cm-s-lucario .CodeMirror-line > span::selection, .cm-s-lucario .CodeMirror-line > span > span::selection { background: #243443; } +.cm-s-lucario .CodeMirror-line::-moz-selection, .cm-s-lucario .CodeMirror-line > span::-moz-selection, .cm-s-lucario .CodeMirror-line > span > span::-moz-selection { background: #243443; } +.cm-s-lucario span.cm-comment { color: #5c98cd; } +.cm-s-lucario span.cm-string, .cm-s-lucario span.cm-string-2 { color: #E6DB74; } +.cm-s-lucario span.cm-number { color: #ca94ff; } +.cm-s-lucario span.cm-variable { color: #f8f8f2; } +.cm-s-lucario span.cm-variable-2 { color: #f8f8f2; } +.cm-s-lucario span.cm-def { color: #72C05D; } +.cm-s-lucario span.cm-operator { color: #66D9EF; } +.cm-s-lucario span.cm-keyword { color: #ff6541; } +.cm-s-lucario span.cm-atom { color: #bd93f9; } +.cm-s-lucario span.cm-meta { color: #f8f8f2; } +.cm-s-lucario span.cm-tag { color: #ff6541; } +.cm-s-lucario span.cm-attribute { color: #66D9EF; } +.cm-s-lucario span.cm-qualifier { color: #72C05D; } +.cm-s-lucario span.cm-property { color: #f8f8f2; } +.cm-s-lucario span.cm-builtin { color: #72C05D; } +.cm-s-lucario span.cm-variable-3, .cm-s-lucario span.cm-type { color: #ffb86c; } + +.cm-s-lucario .CodeMirror-activeline-background { background: #243443; } +.cm-s-lucario .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/material-darker.css b/lib/redactor/codemirror/theme/material-darker.css new file mode 100644 index 0000000..45b64ef --- /dev/null +++ b/lib/redactor/codemirror/theme/material-darker.css @@ -0,0 +1,135 @@ +/* + Name: material + Author: Mattia Astorino (http://github.com/equinusocio) + Website: https://material-theme.site/ +*/ + +.cm-s-material-darker.CodeMirror { + background-color: #212121; + color: #EEFFFF; +} + +.cm-s-material-darker .CodeMirror-gutters { + background: #212121; + color: #545454; + border: none; +} + +.cm-s-material-darker .CodeMirror-guttermarker, +.cm-s-material-darker .CodeMirror-guttermarker-subtle, +.cm-s-material-darker .CodeMirror-linenumber { + color: #545454; +} + +.cm-s-material-darker .CodeMirror-cursor { + border-left: 1px solid #FFCC00; +} + +.cm-s-material-darker div.CodeMirror-selected { + background: rgba(97, 97, 97, 0.2); +} + +.cm-s-material-darker.CodeMirror-focused div.CodeMirror-selected { + background: rgba(97, 97, 97, 0.2); +} + +.cm-s-material-darker .CodeMirror-line::selection, +.cm-s-material-darker .CodeMirror-line>span::selection, +.cm-s-material-darker .CodeMirror-line>span>span::selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material-darker .CodeMirror-line::-moz-selection, +.cm-s-material-darker .CodeMirror-line>span::-moz-selection, +.cm-s-material-darker .CodeMirror-line>span>span::-moz-selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material-darker .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.5); +} + +.cm-s-material-darker .cm-keyword { + color: #C792EA; +} + +.cm-s-material-darker .cm-operator { + color: #89DDFF; +} + +.cm-s-material-darker .cm-variable-2 { + color: #EEFFFF; +} + +.cm-s-material-darker .cm-variable-3, +.cm-s-material-darker .cm-type { + color: #f07178; +} + +.cm-s-material-darker .cm-builtin { + color: #FFCB6B; +} + +.cm-s-material-darker .cm-atom { + color: #F78C6C; +} + +.cm-s-material-darker .cm-number { + color: #FF5370; +} + +.cm-s-material-darker .cm-def { + color: #82AAFF; +} + +.cm-s-material-darker .cm-string { + color: #C3E88D; +} + +.cm-s-material-darker .cm-string-2 { + color: #f07178; +} + +.cm-s-material-darker .cm-comment { + color: #545454; +} + +.cm-s-material-darker .cm-variable { + color: #f07178; +} + +.cm-s-material-darker .cm-tag { + color: #FF5370; +} + +.cm-s-material-darker .cm-meta { + color: #FFCB6B; +} + +.cm-s-material-darker .cm-attribute { + color: #C792EA; +} + +.cm-s-material-darker .cm-property { + color: #C792EA; +} + +.cm-s-material-darker .cm-qualifier { + color: #DECB6B; +} + +.cm-s-material-darker .cm-variable-3, +.cm-s-material-darker .cm-type { + color: #DECB6B; +} + + +.cm-s-material-darker .cm-error { + color: rgba(255, 255, 255, 1.0); + background-color: #FF5370; +} + +.cm-s-material-darker .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} \ No newline at end of file diff --git a/lib/redactor/codemirror/theme/material-ocean.css b/lib/redactor/codemirror/theme/material-ocean.css new file mode 100644 index 0000000..86a6f3c --- /dev/null +++ b/lib/redactor/codemirror/theme/material-ocean.css @@ -0,0 +1,135 @@ +/* + Name: material + Author: Mattia Astorino (http://github.com/equinusocio) + Website: https://material-theme.site/ +*/ + +.cm-s-material-ocean.CodeMirror { + background-color: #0F111A; + color: #8F93A2; +} + +.cm-s-material-ocean .CodeMirror-gutters { + background: #0F111A; + color: #464B5D; + border: none; +} + +.cm-s-material-ocean .CodeMirror-guttermarker, +.cm-s-material-ocean .CodeMirror-guttermarker-subtle, +.cm-s-material-ocean .CodeMirror-linenumber { + color: #464B5D; +} + +.cm-s-material-ocean .CodeMirror-cursor { + border-left: 1px solid #FFCC00; +} + +.cm-s-material-ocean div.CodeMirror-selected { + background: rgba(113, 124, 180, 0.2); +} + +.cm-s-material-ocean.CodeMirror-focused div.CodeMirror-selected { + background: rgba(113, 124, 180, 0.2); +} + +.cm-s-material-ocean .CodeMirror-line::selection, +.cm-s-material-ocean .CodeMirror-line>span::selection, +.cm-s-material-ocean .CodeMirror-line>span>span::selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material-ocean .CodeMirror-line::-moz-selection, +.cm-s-material-ocean .CodeMirror-line>span::-moz-selection, +.cm-s-material-ocean .CodeMirror-line>span>span::-moz-selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material-ocean .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.5); +} + +.cm-s-material-ocean .cm-keyword { + color: #C792EA; +} + +.cm-s-material-ocean .cm-operator { + color: #89DDFF; +} + +.cm-s-material-ocean .cm-variable-2 { + color: #EEFFFF; +} + +.cm-s-material-ocean .cm-variable-3, +.cm-s-material-ocean .cm-type { + color: #f07178; +} + +.cm-s-material-ocean .cm-builtin { + color: #FFCB6B; +} + +.cm-s-material-ocean .cm-atom { + color: #F78C6C; +} + +.cm-s-material-ocean .cm-number { + color: #FF5370; +} + +.cm-s-material-ocean .cm-def { + color: #82AAFF; +} + +.cm-s-material-ocean .cm-string { + color: #C3E88D; +} + +.cm-s-material-ocean .cm-string-2 { + color: #f07178; +} + +.cm-s-material-ocean .cm-comment { + color: #464B5D; +} + +.cm-s-material-ocean .cm-variable { + color: #f07178; +} + +.cm-s-material-ocean .cm-tag { + color: #FF5370; +} + +.cm-s-material-ocean .cm-meta { + color: #FFCB6B; +} + +.cm-s-material-ocean .cm-attribute { + color: #C792EA; +} + +.cm-s-material-ocean .cm-property { + color: #C792EA; +} + +.cm-s-material-ocean .cm-qualifier { + color: #DECB6B; +} + +.cm-s-material-ocean .cm-variable-3, +.cm-s-material-ocean .cm-type { + color: #DECB6B; +} + + +.cm-s-material-ocean .cm-error { + color: rgba(255, 255, 255, 1.0); + background-color: #FF5370; +} + +.cm-s-material-ocean .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} \ No newline at end of file diff --git a/lib/redactor/codemirror/theme/material-palenight.css b/lib/redactor/codemirror/theme/material-palenight.css new file mode 100644 index 0000000..66d53dd --- /dev/null +++ b/lib/redactor/codemirror/theme/material-palenight.css @@ -0,0 +1,135 @@ +/* + Name: material + Author: Mattia Astorino (http://github.com/equinusocio) + Website: https://material-theme.site/ +*/ + +.cm-s-material-palenight.CodeMirror { + background-color: #292D3E; + color: #A6ACCD; +} + +.cm-s-material-palenight .CodeMirror-gutters { + background: #292D3E; + color: #676E95; + border: none; +} + +.cm-s-material-palenight .CodeMirror-guttermarker, +.cm-s-material-palenight .CodeMirror-guttermarker-subtle, +.cm-s-material-palenight .CodeMirror-linenumber { + color: #676E95; +} + +.cm-s-material-palenight .CodeMirror-cursor { + border-left: 1px solid #FFCC00; +} + +.cm-s-material-palenight div.CodeMirror-selected { + background: rgba(113, 124, 180, 0.2); +} + +.cm-s-material-palenight.CodeMirror-focused div.CodeMirror-selected { + background: rgba(113, 124, 180, 0.2); +} + +.cm-s-material-palenight .CodeMirror-line::selection, +.cm-s-material-palenight .CodeMirror-line>span::selection, +.cm-s-material-palenight .CodeMirror-line>span>span::selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material-palenight .CodeMirror-line::-moz-selection, +.cm-s-material-palenight .CodeMirror-line>span::-moz-selection, +.cm-s-material-palenight .CodeMirror-line>span>span::-moz-selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material-palenight .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.5); +} + +.cm-s-material-palenight .cm-keyword { + color: #C792EA; +} + +.cm-s-material-palenight .cm-operator { + color: #89DDFF; +} + +.cm-s-material-palenight .cm-variable-2 { + color: #EEFFFF; +} + +.cm-s-material-palenight .cm-variable-3, +.cm-s-material-palenight .cm-type { + color: #f07178; +} + +.cm-s-material-palenight .cm-builtin { + color: #FFCB6B; +} + +.cm-s-material-palenight .cm-atom { + color: #F78C6C; +} + +.cm-s-material-palenight .cm-number { + color: #FF5370; +} + +.cm-s-material-palenight .cm-def { + color: #82AAFF; +} + +.cm-s-material-palenight .cm-string { + color: #C3E88D; +} + +.cm-s-material-palenight .cm-string-2 { + color: #f07178; +} + +.cm-s-material-palenight .cm-comment { + color: #676E95; +} + +.cm-s-material-palenight .cm-variable { + color: #f07178; +} + +.cm-s-material-palenight .cm-tag { + color: #FF5370; +} + +.cm-s-material-palenight .cm-meta { + color: #FFCB6B; +} + +.cm-s-material-palenight .cm-attribute { + color: #C792EA; +} + +.cm-s-material-palenight .cm-property { + color: #C792EA; +} + +.cm-s-material-palenight .cm-qualifier { + color: #DECB6B; +} + +.cm-s-material-palenight .cm-variable-3, +.cm-s-material-palenight .cm-type { + color: #DECB6B; +} + + +.cm-s-material-palenight .cm-error { + color: rgba(255, 255, 255, 1.0); + background-color: #FF5370; +} + +.cm-s-material-palenight .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} \ No newline at end of file diff --git a/lib/redactor/codemirror/theme/material.css b/lib/redactor/codemirror/theme/material.css new file mode 100644 index 0000000..9ac17a3 --- /dev/null +++ b/lib/redactor/codemirror/theme/material.css @@ -0,0 +1,135 @@ +/* + Name: material + Author: Mattia Astorino (http://github.com/equinusocio) + Website: https://material-theme.site/ +*/ + +.cm-s-material.CodeMirror { + background-color: #263238; + color: #EEFFFF; +} + +.cm-s-material .CodeMirror-gutters { + background: #263238; + color: #546E7A; + border: none; +} + +.cm-s-material .CodeMirror-guttermarker, +.cm-s-material .CodeMirror-guttermarker-subtle, +.cm-s-material .CodeMirror-linenumber { + color: #546E7A; +} + +.cm-s-material .CodeMirror-cursor { + border-left: 1px solid #FFCC00; +} + +.cm-s-material div.CodeMirror-selected { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material.CodeMirror-focused div.CodeMirror-selected { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material .CodeMirror-line::selection, +.cm-s-material .CodeMirror-line>span::selection, +.cm-s-material .CodeMirror-line>span>span::selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material .CodeMirror-line::-moz-selection, +.cm-s-material .CodeMirror-line>span::-moz-selection, +.cm-s-material .CodeMirror-line>span>span::-moz-selection { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-material .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.5); +} + +.cm-s-material .cm-keyword { + color: #C792EA; +} + +.cm-s-material .cm-operator { + color: #89DDFF; +} + +.cm-s-material .cm-variable-2 { + color: #EEFFFF; +} + +.cm-s-material .cm-variable-3, +.cm-s-material .cm-type { + color: #f07178; +} + +.cm-s-material .cm-builtin { + color: #FFCB6B; +} + +.cm-s-material .cm-atom { + color: #F78C6C; +} + +.cm-s-material .cm-number { + color: #FF5370; +} + +.cm-s-material .cm-def { + color: #82AAFF; +} + +.cm-s-material .cm-string { + color: #C3E88D; +} + +.cm-s-material .cm-string-2 { + color: #f07178; +} + +.cm-s-material .cm-comment { + color: #546E7A; +} + +.cm-s-material .cm-variable { + color: #f07178; +} + +.cm-s-material .cm-tag { + color: #FF5370; +} + +.cm-s-material .cm-meta { + color: #FFCB6B; +} + +.cm-s-material .cm-attribute { + color: #C792EA; +} + +.cm-s-material .cm-property { + color: #C792EA; +} + +.cm-s-material .cm-qualifier { + color: #DECB6B; +} + +.cm-s-material .cm-variable-3, +.cm-s-material .cm-type { + color: #DECB6B; +} + + +.cm-s-material .cm-error { + color: rgba(255, 255, 255, 1.0); + background-color: #FF5370; +} + +.cm-s-material .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} \ No newline at end of file diff --git a/lib/redactor/codemirror/theme/mbo.css b/lib/redactor/codemirror/theme/mbo.css new file mode 100644 index 0000000..e164fcf --- /dev/null +++ b/lib/redactor/codemirror/theme/mbo.css @@ -0,0 +1,37 @@ +/****************************************************************/ +/* Based on mbonaci's Brackets mbo theme */ +/* https://github.com/mbonaci/global/blob/master/Mbo.tmTheme */ +/* Create your own: http://tmtheme-editor.herokuapp.com */ +/****************************************************************/ + +.cm-s-mbo.CodeMirror { background: #2c2c2c; color: #ffffec; } +.cm-s-mbo div.CodeMirror-selected { background: #716C62; } +.cm-s-mbo .CodeMirror-line::selection, .cm-s-mbo .CodeMirror-line > span::selection, .cm-s-mbo .CodeMirror-line > span > span::selection { background: rgba(113, 108, 98, .99); } +.cm-s-mbo .CodeMirror-line::-moz-selection, .cm-s-mbo .CodeMirror-line > span::-moz-selection, .cm-s-mbo .CodeMirror-line > span > span::-moz-selection { background: rgba(113, 108, 98, .99); } +.cm-s-mbo .CodeMirror-gutters { background: #4e4e4e; border-right: 0px; } +.cm-s-mbo .CodeMirror-guttermarker { color: white; } +.cm-s-mbo .CodeMirror-guttermarker-subtle { color: grey; } +.cm-s-mbo .CodeMirror-linenumber { color: #dadada; } +.cm-s-mbo .CodeMirror-cursor { border-left: 1px solid #ffffec; } + +.cm-s-mbo span.cm-comment { color: #95958a; } +.cm-s-mbo span.cm-atom { color: #00a8c6; } +.cm-s-mbo span.cm-number { color: #00a8c6; } + +.cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute { color: #9ddfe9; } +.cm-s-mbo span.cm-keyword { color: #ffb928; } +.cm-s-mbo span.cm-string { color: #ffcf6c; } +.cm-s-mbo span.cm-string.cm-property { color: #ffffec; } + +.cm-s-mbo span.cm-variable { color: #ffffec; } +.cm-s-mbo span.cm-variable-2 { color: #00a8c6; } +.cm-s-mbo span.cm-def { color: #ffffec; } +.cm-s-mbo span.cm-bracket { color: #fffffc; font-weight: bold; } +.cm-s-mbo span.cm-tag { color: #9ddfe9; } +.cm-s-mbo span.cm-link { color: #f54b07; } +.cm-s-mbo span.cm-error { border-bottom: #636363; color: #ffffec; } +.cm-s-mbo span.cm-qualifier { color: #ffffec; } + +.cm-s-mbo .CodeMirror-activeline-background { background: #494b41; } +.cm-s-mbo .CodeMirror-matchingbracket { color: #ffb928 !important; } +.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); } diff --git a/lib/redactor/codemirror/theme/mdn-like.css b/lib/redactor/codemirror/theme/mdn-like.css new file mode 100644 index 0000000..622ed3e --- /dev/null +++ b/lib/redactor/codemirror/theme/mdn-like.css @@ -0,0 +1,46 @@ +/* + MDN-LIKE Theme - Mozilla + Ported to CodeMirror by Peter Kroon + Report bugs/issues here: https://github.com/codemirror/CodeMirror/issues + GitHub: @peterkroon + + The mdn-like theme is inspired on the displayed code examples at: https://developer.mozilla.org/en-US/docs/Web/CSS/animation + +*/ +.cm-s-mdn-like.CodeMirror { color: #999; background-color: #fff; } +.cm-s-mdn-like div.CodeMirror-selected { background: #cfc; } +.cm-s-mdn-like .CodeMirror-line::selection, .cm-s-mdn-like .CodeMirror-line > span::selection, .cm-s-mdn-like .CodeMirror-line > span > span::selection { background: #cfc; } +.cm-s-mdn-like .CodeMirror-line::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span::-moz-selection, .cm-s-mdn-like .CodeMirror-line > span > span::-moz-selection { background: #cfc; } + +.cm-s-mdn-like .CodeMirror-gutters { background: #f8f8f8; border-left: 6px solid rgba(0,83,159,0.65); color: #333; } +.cm-s-mdn-like .CodeMirror-linenumber { color: #aaa; padding-left: 8px; } +.cm-s-mdn-like .CodeMirror-cursor { border-left: 2px solid #222; } + +.cm-s-mdn-like .cm-keyword { color: #6262FF; } +.cm-s-mdn-like .cm-atom { color: #F90; } +.cm-s-mdn-like .cm-number { color: #ca7841; } +.cm-s-mdn-like .cm-def { color: #8DA6CE; } +.cm-s-mdn-like span.cm-variable-2, .cm-s-mdn-like span.cm-tag { color: #690; } +.cm-s-mdn-like span.cm-variable-3, .cm-s-mdn-like span.cm-def, .cm-s-mdn-like span.cm-type { color: #07a; } + +.cm-s-mdn-like .cm-variable { color: #07a; } +.cm-s-mdn-like .cm-property { color: #905; } +.cm-s-mdn-like .cm-qualifier { color: #690; } + +.cm-s-mdn-like .cm-operator { color: #cda869; } +.cm-s-mdn-like .cm-comment { color:#777; font-weight:normal; } +.cm-s-mdn-like .cm-string { color:#07a; font-style:italic; } +.cm-s-mdn-like .cm-string-2 { color:#bd6b18; } /*?*/ +.cm-s-mdn-like .cm-meta { color: #000; } /*?*/ +.cm-s-mdn-like .cm-builtin { color: #9B7536; } /*?*/ +.cm-s-mdn-like .cm-tag { color: #997643; } +.cm-s-mdn-like .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-mdn-like .cm-header { color: #FF6400; } +.cm-s-mdn-like .cm-hr { color: #AEAEAE; } +.cm-s-mdn-like .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } +.cm-s-mdn-like .cm-error { border-bottom: 1px solid red; } + +div.cm-s-mdn-like .CodeMirror-activeline-background { background: #efefff; } +div.cm-s-mdn-like span.CodeMirror-matchingbracket { outline:1px solid grey; color: inherit; } + +.cm-s-mdn-like.CodeMirror { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFcAAAAyCAYAAAAp8UeFAAAHvklEQVR42s2b63bcNgyEQZCSHCdt2vd/0tWF7I+Q6XgMXiTtuvU5Pl57ZQKkKHzEAOtF5KeIJBGJ8uvL599FRFREZhFx8DeXv8trn68RuGaC8TRfo3SNp9dlDDHedyLyTUTeRWStXKPZrjtpZxaRw5hPqozRs1N8/enzIiQRWcCgy4MUA0f+XWliDhyL8Lfyvx7ei/Ae3iQFHyw7U/59pQVIMEEPEz0G7XiwdRjzSfC3UTtz9vchIntxvry5iMgfIhJoEflOz2CQr3F5h/HfeFe+GTdLaKcu9L8LTeQb/R/7GgbsfKedyNdoHsN31uRPWrfZ5wsj/NzzRQHuToIdU3ahwnsKPxXCjJITuOsi7XLc7SG/v5GdALs7wf8JjTFiB5+QvTEfRyGOfX3Lrx8wxyQi3sNq46O7QahQiCsRFgqddjBouVEHOKDgXAQHD9gJCr5sMKkEdjwsarG/ww3BMHBU7OBjXnzdyY7SfCxf5/z6ATccrwlKuwC/jhznnPF4CgVzhhVf4xp2EixcBActO75iZ8/fM9zAs2OMzKdslgXWJ9XG8PQoOAMA5fGcsvORgv0doBXyHrCwfLJAOwo71QLNkb8n2Pl6EWiR7OCibtkPaz4Kc/0NNAze2gju3zOwekALDaCFPI5vjPFmgGY5AZqyGEvH1x7QfIb8YtxMnA/b+QQ0aQDAwc6JMFg8CbQZ4qoYEEHbRwNojuK3EHwd7VALSgq+MNDKzfT58T8qdpADrgW0GmgcAS1lhzztJmkAzcPNOQbsWEALBDSlMKUG0Eq4CLAQWvEVQ9WU57gZJwZtgPO3r9oBTQ9WO8TjqXINx8R0EYpiZEUWOF3FxkbJkgU9B2f41YBrIj5ZfsQa0M5kTgiAAqM3ShXLgu8XMqcrQBvJ0CL5pnTsfMB13oB8athpAq2XOQmcGmoACCLydx7nToa23ATaSIY2ichfOdPTGxlasXMLaL0MLZAOwAKIM+y8CmicobGdCcbbK9DzN+yYGVoNNI5iUKTMyYOjPse4A8SM1MmcXgU0toOq1yO/v8FOxlASyc7TgeYaAMBJHcY1CcCwGI/TK4AmDbDyKYBBtFUkRwto8gygiQEaByFgJ00BH2M8JWwQS1nafDXQCidWyOI8AcjDCSjCLk8ngObuAm3JAHAdubAmOaK06V8MNEsKPJOhobSprwQa6gD7DclRQdqcwL4zxqgBrQcabUiBLclRDKAlWp+etPkBaNMA0AKlrHwTdEByZAA4GM+SNluSY6wAzcMNewxmgig5Ks0nkrSpBvSaQHMdKTBAnLojOdYyGpQ254602ZILPdTD1hdlggdIm74jbTp8vDwF5ZYUeLWGJpWsh6XNyXgcYwVoJQTEhhTYkxzZjiU5npU2TaB979TQehlaAVq4kaGpiPwwwLkYUuBbQwocyQTv1tA0+1UFWoJF3iv1oq+qoSk8EQdJmwHkziIF7oOZk14EGitibAdjLYYK78H5vZOhtWpoI0ATGHs0Q8OMb4Ey+2bU2UYztCtA0wFAs7TplGLRVQCcqaFdGSPCeTI1QNIC52iWNzof6Uib7xjEp07mNNoUYmVosVItHrHzRlLgBn9LFyRHaQCtVUMbtTNhoXWiTOO9k/V8BdAc1Oq0ArSQs6/5SU0hckNy9NnXqQY0PGYo5dWJ7nINaN6o958FWin27aBaWRka1r5myvLOAm0j30eBJqCxHLReVclxhxOEN2JfDWjxBtAC7MIH1fVaGdoOp4qJYDgKtKPSFNID2gSnGldrCqkFZ+5UeQXQBIRrSwocbdZYQT/2LwRahBPBXoHrB8nxaGROST62DKUbQOMMzZIC9abkuELfQzQALWTnDNAm8KHWFOJgJ5+SHIvTPcmx1xQyZRhNL5Qci689aXMEaN/uNIWkEwDAvFpOZmgsBaaGnbs1NPa1Jm32gBZAIh1pCtG7TSH4aE0y1uVY4uqoFPisGlpP2rSA5qTecWn5agK6BzSpgAyD+wFaqhnYoSZ1Vwr8CmlTQbrcO3ZaX0NAEyMbYaAlyquFoLKK3SPby9CeVUPThrSJmkCAE0CrKUQadi4DrdSlWhmah0YL9z9vClH59YGbHx1J8VZTyAjQepJjmXwAKTDQI3omc3p1U4gDUf6RfcdYfrUp5ClAi2J3Ba6UOXGo+K+bQrjjssitG2SJzshaLwMtXgRagUNpYYoVkMSBLM+9GGiJZMvduG6DRZ4qc04DMPtQQxOjEtACmhO7K1AbNbQDEggZyJwscFpAGwENhoBeUwh3bWolhe8BTYVKxQEWrSUn/uhcM5KhvUu/+eQu0Lzhi+VrK0PrZZNDQKs9cpYUuFYgMVpD4/NxenJTiMCNqdUEUf1qZWjppLT5qSkkUZbCwkbZMSuVnu80hfSkzRbQeqCZSAh6huR4VtoM2gHAlLf72smuWgE+VV7XpE25Ab2WFDgyhnSuKbs4GuGzCjR+tIoUuMFg3kgcWKLTwRqanJQ2W00hAsenfaApRC42hbCvK1SlE0HtE9BGgneJO+ELamitD1YjjOYnNYVcraGhtKkW0EqVVeDx733I2NH581k1NNxNLG0i0IJ8/NjVaOZ0tYZ2Vtr0Xv7tPV3hkWp9EFkgS/J0vosngTaSoaG06WHi+xObQkaAdlbanP8B2+2l0f90LmUAAAAASUVORK5CYII=); } diff --git a/lib/redactor/codemirror/theme/midnight.css b/lib/redactor/codemirror/theme/midnight.css new file mode 100644 index 0000000..fc26474 --- /dev/null +++ b/lib/redactor/codemirror/theme/midnight.css @@ -0,0 +1,39 @@ +/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */ + +/**/ +.cm-s-midnight .CodeMirror-activeline-background { background: #253540; } + +.cm-s-midnight.CodeMirror { + background: #0F192A; + color: #D1EDFF; +} + +.cm-s-midnight div.CodeMirror-selected { background: #314D67; } +.cm-s-midnight .CodeMirror-line::selection, .cm-s-midnight .CodeMirror-line > span::selection, .cm-s-midnight .CodeMirror-line > span > span::selection { background: rgba(49, 77, 103, .99); } +.cm-s-midnight .CodeMirror-line::-moz-selection, .cm-s-midnight .CodeMirror-line > span::-moz-selection, .cm-s-midnight .CodeMirror-line > span > span::-moz-selection { background: rgba(49, 77, 103, .99); } +.cm-s-midnight .CodeMirror-gutters { background: #0F192A; border-right: 1px solid; } +.cm-s-midnight .CodeMirror-guttermarker { color: white; } +.cm-s-midnight .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-midnight .CodeMirror-linenumber { color: #D0D0D0; } +.cm-s-midnight .CodeMirror-cursor { border-left: 1px solid #F8F8F0; } + +.cm-s-midnight span.cm-comment { color: #428BDD; } +.cm-s-midnight span.cm-atom { color: #AE81FF; } +.cm-s-midnight span.cm-number { color: #D1EDFF; } + +.cm-s-midnight span.cm-property, .cm-s-midnight span.cm-attribute { color: #A6E22E; } +.cm-s-midnight span.cm-keyword { color: #E83737; } +.cm-s-midnight span.cm-string { color: #1DC116; } + +.cm-s-midnight span.cm-variable { color: #FFAA3E; } +.cm-s-midnight span.cm-variable-2 { color: #FFAA3E; } +.cm-s-midnight span.cm-def { color: #4DD; } +.cm-s-midnight span.cm-bracket { color: #D1EDFF; } +.cm-s-midnight span.cm-tag { color: #449; } +.cm-s-midnight span.cm-link { color: #AE81FF; } +.cm-s-midnight span.cm-error { background: #F92672; color: #F8F8F0; } + +.cm-s-midnight .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/lib/redactor/codemirror/theme/monokai.css b/lib/redactor/codemirror/theme/monokai.css new file mode 100644 index 0000000..cd4cd55 --- /dev/null +++ b/lib/redactor/codemirror/theme/monokai.css @@ -0,0 +1,41 @@ +/* Based on Sublime Text's Monokai theme */ + +.cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; } +.cm-s-monokai div.CodeMirror-selected { background: #49483E; } +.cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); } +.cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; } +.cm-s-monokai .CodeMirror-guttermarker { color: white; } +.cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } + +.cm-s-monokai span.cm-comment { color: #75715e; } +.cm-s-monokai span.cm-atom { color: #ae81ff; } +.cm-s-monokai span.cm-number { color: #ae81ff; } + +.cm-s-monokai span.cm-comment.cm-attribute { color: #97b757; } +.cm-s-monokai span.cm-comment.cm-def { color: #bc9262; } +.cm-s-monokai span.cm-comment.cm-tag { color: #bc6283; } +.cm-s-monokai span.cm-comment.cm-type { color: #5998a6; } + +.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; } +.cm-s-monokai span.cm-keyword { color: #f92672; } +.cm-s-monokai span.cm-builtin { color: #66d9ef; } +.cm-s-monokai span.cm-string { color: #e6db74; } + +.cm-s-monokai span.cm-variable { color: #f8f8f2; } +.cm-s-monokai span.cm-variable-2 { color: #9effff; } +.cm-s-monokai span.cm-variable-3, .cm-s-monokai span.cm-type { color: #66d9ef; } +.cm-s-monokai span.cm-def { color: #fd971f; } +.cm-s-monokai span.cm-bracket { color: #f8f8f2; } +.cm-s-monokai span.cm-tag { color: #f92672; } +.cm-s-monokai span.cm-header { color: #ae81ff; } +.cm-s-monokai span.cm-link { color: #ae81ff; } +.cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; } + +.cm-s-monokai .CodeMirror-activeline-background { background: #373831; } +.cm-s-monokai .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/lib/redactor/codemirror/theme/moxer.css b/lib/redactor/codemirror/theme/moxer.css new file mode 100644 index 0000000..b3ca35e --- /dev/null +++ b/lib/redactor/codemirror/theme/moxer.css @@ -0,0 +1,143 @@ +/* + Name: Moxer Theme + Author: Mattia Astorino (http://github.com/equinusocio) + Website: https://github.com/moxer-theme/moxer-code +*/ + +.cm-s-moxer.CodeMirror { + background-color: #090A0F; + color: #8E95B4; + line-height: 1.8; +} + +.cm-s-moxer .CodeMirror-gutters { + background: #090A0F; + color: #35394B; + border: none; +} + +.cm-s-moxer .CodeMirror-guttermarker, +.cm-s-moxer .CodeMirror-guttermarker-subtle, +.cm-s-moxer .CodeMirror-linenumber { + color: #35394B; +} + + +.cm-s-moxer .CodeMirror-cursor { + border-left: 1px solid #FFCC00; +} + +.cm-s-moxer div.CodeMirror-selected { + background: rgba(128, 203, 196, 0.2); +} + +.cm-s-moxer.CodeMirror-focused div.CodeMirror-selected { + background: #212431; +} + +.cm-s-moxer .CodeMirror-line::selection, +.cm-s-moxer .CodeMirror-line>span::selection, +.cm-s-moxer .CodeMirror-line>span>span::selection { + background: #212431; +} + +.cm-s-moxer .CodeMirror-line::-moz-selection, +.cm-s-moxer .CodeMirror-line>span::-moz-selection, +.cm-s-moxer .CodeMirror-line>span>span::-moz-selection { + background: #212431; +} + +.cm-s-moxer .CodeMirror-activeline-background, +.cm-s-moxer .CodeMirror-activeline-gutter .CodeMirror-linenumber { + background: rgba(33, 36, 49, 0.5); +} + +.cm-s-moxer .cm-keyword { + color: #D46C6C; +} + +.cm-s-moxer .cm-operator { + color: #D46C6C; +} + +.cm-s-moxer .cm-variable-2 { + color: #81C5DA; +} + + +.cm-s-moxer .cm-variable-3, +.cm-s-moxer .cm-type { + color: #f07178; +} + +.cm-s-moxer .cm-builtin { + color: #FFCB6B; +} + +.cm-s-moxer .cm-atom { + color: #A99BE2; +} + +.cm-s-moxer .cm-number { + color: #7CA4C0; +} + +.cm-s-moxer .cm-def { + color: #F5DFA5; +} + +.cm-s-moxer .CodeMirror-line .cm-def ~ .cm-def { + color: #81C5DA; +} + +.cm-s-moxer .cm-string { + color: #B2E4AE; +} + +.cm-s-moxer .cm-string-2 { + color: #f07178; +} + +.cm-s-moxer .cm-comment { + color: #3F445A; +} + +.cm-s-moxer .cm-variable { + color: #8E95B4; +} + +.cm-s-moxer .cm-tag { + color: #FF5370; +} + +.cm-s-moxer .cm-meta { + color: #FFCB6B; +} + +.cm-s-moxer .cm-attribute { + color: #C792EA; +} + +.cm-s-moxer .cm-property { + color: #81C5DA; +} + +.cm-s-moxer .cm-qualifier { + color: #DECB6B; +} + +.cm-s-moxer .cm-variable-3, +.cm-s-moxer .cm-type { + color: #DECB6B; +} + + +.cm-s-moxer .cm-error { + color: rgba(255, 255, 255, 1.0); + background-color: #FF5370; +} + +.cm-s-moxer .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} \ No newline at end of file diff --git a/lib/redactor/codemirror/theme/neat.css b/lib/redactor/codemirror/theme/neat.css new file mode 100644 index 0000000..4267b1a --- /dev/null +++ b/lib/redactor/codemirror/theme/neat.css @@ -0,0 +1,12 @@ +.cm-s-neat span.cm-comment { color: #a86; } +.cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; } +.cm-s-neat span.cm-string { color: #a22; } +.cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; } +.cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; } +.cm-s-neat span.cm-variable { color: black; } +.cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; } +.cm-s-neat span.cm-meta { color: #555; } +.cm-s-neat span.cm-link { color: #3a3; } + +.cm-s-neat .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-neat .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } diff --git a/lib/redactor/codemirror/theme/neo.css b/lib/redactor/codemirror/theme/neo.css new file mode 100644 index 0000000..b28d5c6 --- /dev/null +++ b/lib/redactor/codemirror/theme/neo.css @@ -0,0 +1,43 @@ +/* neo theme for codemirror */ + +/* Color scheme */ + +.cm-s-neo.CodeMirror { + background-color:#ffffff; + color:#2e383c; + line-height:1.4375; +} +.cm-s-neo .cm-comment { color:#75787b; } +.cm-s-neo .cm-keyword, .cm-s-neo .cm-property { color:#1d75b3; } +.cm-s-neo .cm-atom,.cm-s-neo .cm-number { color:#75438a; } +.cm-s-neo .cm-node,.cm-s-neo .cm-tag { color:#9c3328; } +.cm-s-neo .cm-string { color:#b35e14; } +.cm-s-neo .cm-variable,.cm-s-neo .cm-qualifier { color:#047d65; } + + +/* Editor styling */ + +.cm-s-neo pre { + padding:0; +} + +.cm-s-neo .CodeMirror-gutters { + border:none; + border-right:10px solid transparent; + background-color:transparent; +} + +.cm-s-neo .CodeMirror-linenumber { + padding:0; + color:#e0e2e5; +} + +.cm-s-neo .CodeMirror-guttermarker { color: #1d75b3; } +.cm-s-neo .CodeMirror-guttermarker-subtle { color: #e0e2e5; } + +.cm-s-neo .CodeMirror-cursor { + width: auto; + border: 0; + background: rgba(155,157,162,0.37); + z-index: 1; +} diff --git a/lib/redactor/codemirror/theme/night.css b/lib/redactor/codemirror/theme/night.css new file mode 100644 index 0000000..f631bf4 --- /dev/null +++ b/lib/redactor/codemirror/theme/night.css @@ -0,0 +1,27 @@ +/* Loosely based on the Midnight Textmate theme */ + +.cm-s-night.CodeMirror { background: #0a001f; color: #f8f8f8; } +.cm-s-night div.CodeMirror-selected { background: #447; } +.cm-s-night .CodeMirror-line::selection, .cm-s-night .CodeMirror-line > span::selection, .cm-s-night .CodeMirror-line > span > span::selection { background: rgba(68, 68, 119, .99); } +.cm-s-night .CodeMirror-line::-moz-selection, .cm-s-night .CodeMirror-line > span::-moz-selection, .cm-s-night .CodeMirror-line > span > span::-moz-selection { background: rgba(68, 68, 119, .99); } +.cm-s-night .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-night .CodeMirror-guttermarker { color: white; } +.cm-s-night .CodeMirror-guttermarker-subtle { color: #bbb; } +.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; } +.cm-s-night .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-night span.cm-comment { color: #8900d1; } +.cm-s-night span.cm-atom { color: #845dc4; } +.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; } +.cm-s-night span.cm-keyword { color: #599eff; } +.cm-s-night span.cm-string { color: #37f14a; } +.cm-s-night span.cm-meta { color: #7678e2; } +.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; } +.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def, .cm-s-night span.cm-type { color: white; } +.cm-s-night span.cm-bracket { color: #8da6ce; } +.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; } +.cm-s-night span.cm-link { color: #845dc4; } +.cm-s-night span.cm-error { color: #9d1e15; } + +.cm-s-night .CodeMirror-activeline-background { background: #1C005A; } +.cm-s-night .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } diff --git a/lib/redactor/codemirror/theme/nord.css b/lib/redactor/codemirror/theme/nord.css new file mode 100644 index 0000000..41a8ad7 --- /dev/null +++ b/lib/redactor/codemirror/theme/nord.css @@ -0,0 +1,42 @@ +/* Based on arcticicestudio's Nord theme */ +/* https://github.com/arcticicestudio/nord */ + +.cm-s-nord.CodeMirror { background: #2e3440; color: #d8dee9; } +.cm-s-nord div.CodeMirror-selected { background: #434c5e; } +.cm-s-nord .CodeMirror-line::selection, .cm-s-nord .CodeMirror-line > span::selection, .cm-s-nord .CodeMirror-line > span > span::selection { background: #3b4252; } +.cm-s-nord .CodeMirror-line::-moz-selection, .cm-s-nord .CodeMirror-line > span::-moz-selection, .cm-s-nord .CodeMirror-line > span > span::-moz-selection { background: #3b4252; } +.cm-s-nord .CodeMirror-gutters { background: #2e3440; border-right: 0px; } +.cm-s-nord .CodeMirror-guttermarker { color: #4c566a; } +.cm-s-nord .CodeMirror-guttermarker-subtle { color: #4c566a; } +.cm-s-nord .CodeMirror-linenumber { color: #4c566a; } +.cm-s-nord .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } + +.cm-s-nord span.cm-comment { color: #4c566a; } +.cm-s-nord span.cm-atom { color: #b48ead; } +.cm-s-nord span.cm-number { color: #b48ead; } + +.cm-s-nord span.cm-comment.cm-attribute { color: #97b757; } +.cm-s-nord span.cm-comment.cm-def { color: #bc9262; } +.cm-s-nord span.cm-comment.cm-tag { color: #bc6283; } +.cm-s-nord span.cm-comment.cm-type { color: #5998a6; } + +.cm-s-nord span.cm-property, .cm-s-nord span.cm-attribute { color: #8FBCBB; } +.cm-s-nord span.cm-keyword { color: #81A1C1; } +.cm-s-nord span.cm-builtin { color: #81A1C1; } +.cm-s-nord span.cm-string { color: #A3BE8C; } + +.cm-s-nord span.cm-variable { color: #d8dee9; } +.cm-s-nord span.cm-variable-2 { color: #d8dee9; } +.cm-s-nord span.cm-variable-3, .cm-s-nord span.cm-type { color: #d8dee9; } +.cm-s-nord span.cm-def { color: #8FBCBB; } +.cm-s-nord span.cm-bracket { color: #81A1C1; } +.cm-s-nord span.cm-tag { color: #bf616a; } +.cm-s-nord span.cm-header { color: #b48ead; } +.cm-s-nord span.cm-link { color: #b48ead; } +.cm-s-nord span.cm-error { background: #bf616a; color: #f8f8f0; } + +.cm-s-nord .CodeMirror-activeline-background { background: #3b4252; } +.cm-s-nord .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/lib/redactor/codemirror/theme/oceanic-next.css b/lib/redactor/codemirror/theme/oceanic-next.css new file mode 100644 index 0000000..296277b --- /dev/null +++ b/lib/redactor/codemirror/theme/oceanic-next.css @@ -0,0 +1,44 @@ +/* + + Name: oceanic-next + Author: Filype Pereira (https://github.com/fpereira1) + + Original oceanic-next color scheme by Dmitri Voronianski (https://github.com/voronianski/oceanic-next-color-scheme) + +*/ + +.cm-s-oceanic-next.CodeMirror { background: #304148; color: #f8f8f2; } +.cm-s-oceanic-next div.CodeMirror-selected { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-line::selection, .cm-s-oceanic-next .CodeMirror-line > span::selection, .cm-s-oceanic-next .CodeMirror-line > span > span::selection { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-line::-moz-selection, .cm-s-oceanic-next .CodeMirror-line > span::-moz-selection, .cm-s-oceanic-next .CodeMirror-line > span > span::-moz-selection { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-gutters { background: #304148; border-right: 10px; } +.cm-s-oceanic-next .CodeMirror-guttermarker { color: white; } +.cm-s-oceanic-next .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-oceanic-next .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-oceanic-next .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } + +.cm-s-oceanic-next span.cm-comment { color: #65737E; } +.cm-s-oceanic-next span.cm-atom { color: #C594C5; } +.cm-s-oceanic-next span.cm-number { color: #F99157; } + +.cm-s-oceanic-next span.cm-property { color: #99C794; } +.cm-s-oceanic-next span.cm-attribute, +.cm-s-oceanic-next span.cm-keyword { color: #C594C5; } +.cm-s-oceanic-next span.cm-builtin { color: #66d9ef; } +.cm-s-oceanic-next span.cm-string { color: #99C794; } + +.cm-s-oceanic-next span.cm-variable, +.cm-s-oceanic-next span.cm-variable-2, +.cm-s-oceanic-next span.cm-variable-3 { color: #f8f8f2; } +.cm-s-oceanic-next span.cm-def { color: #6699CC; } +.cm-s-oceanic-next span.cm-bracket { color: #5FB3B3; } +.cm-s-oceanic-next span.cm-tag { color: #C594C5; } +.cm-s-oceanic-next span.cm-header { color: #C594C5; } +.cm-s-oceanic-next span.cm-link { color: #C594C5; } +.cm-s-oceanic-next span.cm-error { background: #C594C5; color: #f8f8f0; } + +.cm-s-oceanic-next .CodeMirror-activeline-background { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} diff --git a/lib/redactor/codemirror/theme/panda-syntax.css b/lib/redactor/codemirror/theme/panda-syntax.css new file mode 100644 index 0000000..de14e91 --- /dev/null +++ b/lib/redactor/codemirror/theme/panda-syntax.css @@ -0,0 +1,85 @@ +/* + Name: Panda Syntax + Author: Siamak Mokhtari (http://github.com/siamak/) + CodeMirror template by Siamak Mokhtari (https://github.com/siamak/atom-panda-syntax) +*/ +.cm-s-panda-syntax { + background: #292A2B; + color: #E6E6E6; + line-height: 1.5; + font-family: 'Operator Mono', 'Source Code Pro', Menlo, Monaco, Consolas, Courier New, monospace; +} +.cm-s-panda-syntax .CodeMirror-cursor { border-color: #ff2c6d; } +.cm-s-panda-syntax .CodeMirror-activeline-background { + background: rgba(99, 123, 156, 0.1); +} +.cm-s-panda-syntax .CodeMirror-selected { + background: #FFF; +} +.cm-s-panda-syntax .cm-comment { + font-style: italic; + color: #676B79; +} +.cm-s-panda-syntax .cm-operator { + color: #f3f3f3; +} +.cm-s-panda-syntax .cm-string { + color: #19F9D8; +} +.cm-s-panda-syntax .cm-string-2 { + color: #FFB86C; +} + +.cm-s-panda-syntax .cm-tag { + color: #ff2c6d; +} +.cm-s-panda-syntax .cm-meta { + color: #b084eb; +} + +.cm-s-panda-syntax .cm-number { + color: #FFB86C; +} +.cm-s-panda-syntax .cm-atom { + color: #ff2c6d; +} +.cm-s-panda-syntax .cm-keyword { + color: #FF75B5; +} +.cm-s-panda-syntax .cm-variable { + color: #ffb86c; +} +.cm-s-panda-syntax .cm-variable-2 { + color: #ff9ac1; +} +.cm-s-panda-syntax .cm-variable-3, .cm-s-panda-syntax .cm-type { + color: #ff9ac1; +} + +.cm-s-panda-syntax .cm-def { + color: #e6e6e6; +} +.cm-s-panda-syntax .cm-property { + color: #f3f3f3; +} +.cm-s-panda-syntax .cm-unit { + color: #ffb86c; +} + +.cm-s-panda-syntax .cm-attribute { + color: #ffb86c; +} + +.cm-s-panda-syntax .CodeMirror-matchingbracket { + border-bottom: 1px dotted #19F9D8; + padding-bottom: 2px; + color: #e6e6e6; +} +.cm-s-panda-syntax .CodeMirror-gutters { + background: #292a2b; + border-right-color: rgba(255, 255, 255, 0.1); +} +.cm-s-panda-syntax .CodeMirror-linenumber { + color: #e6e6e6; + opacity: 0.6; +} diff --git a/lib/redactor/codemirror/theme/paraiso-dark.css b/lib/redactor/codemirror/theme/paraiso-dark.css new file mode 100644 index 0000000..aa9d207 --- /dev/null +++ b/lib/redactor/codemirror/theme/paraiso-dark.css @@ -0,0 +1,38 @@ +/* + + Name: Paraíso (Dark) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-dark.CodeMirror { background: #2f1e2e; color: #b9b6b0; } +.cm-s-paraiso-dark div.CodeMirror-selected { background: #41323f; } +.cm-s-paraiso-dark .CodeMirror-line::selection, .cm-s-paraiso-dark .CodeMirror-line > span::selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::selection { background: rgba(65, 50, 63, .99); } +.cm-s-paraiso-dark .CodeMirror-line::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(65, 50, 63, .99); } +.cm-s-paraiso-dark .CodeMirror-gutters { background: #2f1e2e; border-right: 0px; } +.cm-s-paraiso-dark .CodeMirror-guttermarker { color: #ef6155; } +.cm-s-paraiso-dark .CodeMirror-guttermarker-subtle { color: #776e71; } +.cm-s-paraiso-dark .CodeMirror-linenumber { color: #776e71; } +.cm-s-paraiso-dark .CodeMirror-cursor { border-left: 1px solid #8d8687; } + +.cm-s-paraiso-dark span.cm-comment { color: #e96ba8; } +.cm-s-paraiso-dark span.cm-atom { color: #815ba4; } +.cm-s-paraiso-dark span.cm-number { color: #815ba4; } + +.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute { color: #48b685; } +.cm-s-paraiso-dark span.cm-keyword { color: #ef6155; } +.cm-s-paraiso-dark span.cm-string { color: #fec418; } + +.cm-s-paraiso-dark span.cm-variable { color: #48b685; } +.cm-s-paraiso-dark span.cm-variable-2 { color: #06b6ef; } +.cm-s-paraiso-dark span.cm-def { color: #f99b15; } +.cm-s-paraiso-dark span.cm-bracket { color: #b9b6b0; } +.cm-s-paraiso-dark span.cm-tag { color: #ef6155; } +.cm-s-paraiso-dark span.cm-link { color: #815ba4; } +.cm-s-paraiso-dark span.cm-error { background: #ef6155; color: #8d8687; } + +.cm-s-paraiso-dark .CodeMirror-activeline-background { background: #4D344A; } +.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/paraiso-light.css b/lib/redactor/codemirror/theme/paraiso-light.css new file mode 100644 index 0000000..ae0c755 --- /dev/null +++ b/lib/redactor/codemirror/theme/paraiso-light.css @@ -0,0 +1,38 @@ +/* + + Name: Paraíso (Light) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-light.CodeMirror { background: #e7e9db; color: #41323f; } +.cm-s-paraiso-light div.CodeMirror-selected { background: #b9b6b0; } +.cm-s-paraiso-light .CodeMirror-line::selection, .cm-s-paraiso-light .CodeMirror-line > span::selection, .cm-s-paraiso-light .CodeMirror-line > span > span::selection { background: #b9b6b0; } +.cm-s-paraiso-light .CodeMirror-line::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span::-moz-selection, .cm-s-paraiso-light .CodeMirror-line > span > span::-moz-selection { background: #b9b6b0; } +.cm-s-paraiso-light .CodeMirror-gutters { background: #e7e9db; border-right: 0px; } +.cm-s-paraiso-light .CodeMirror-guttermarker { color: black; } +.cm-s-paraiso-light .CodeMirror-guttermarker-subtle { color: #8d8687; } +.cm-s-paraiso-light .CodeMirror-linenumber { color: #8d8687; } +.cm-s-paraiso-light .CodeMirror-cursor { border-left: 1px solid #776e71; } + +.cm-s-paraiso-light span.cm-comment { color: #e96ba8; } +.cm-s-paraiso-light span.cm-atom { color: #815ba4; } +.cm-s-paraiso-light span.cm-number { color: #815ba4; } + +.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute { color: #48b685; } +.cm-s-paraiso-light span.cm-keyword { color: #ef6155; } +.cm-s-paraiso-light span.cm-string { color: #fec418; } + +.cm-s-paraiso-light span.cm-variable { color: #48b685; } +.cm-s-paraiso-light span.cm-variable-2 { color: #06b6ef; } +.cm-s-paraiso-light span.cm-def { color: #f99b15; } +.cm-s-paraiso-light span.cm-bracket { color: #41323f; } +.cm-s-paraiso-light span.cm-tag { color: #ef6155; } +.cm-s-paraiso-light span.cm-link { color: #815ba4; } +.cm-s-paraiso-light span.cm-error { background: #ef6155; color: #776e71; } + +.cm-s-paraiso-light .CodeMirror-activeline-background { background: #CFD1C4; } +.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/pastel-on-dark.css b/lib/redactor/codemirror/theme/pastel-on-dark.css new file mode 100644 index 0000000..60435dd --- /dev/null +++ b/lib/redactor/codemirror/theme/pastel-on-dark.css @@ -0,0 +1,52 @@ +/** + * Pastel On Dark theme ported from ACE editor + * @license MIT + * @copyright AtomicPages LLC 2014 + * @author Dennis Thompson, AtomicPages LLC + * @version 1.1 + * @source https://github.com/atomicpages/codemirror-pastel-on-dark-theme + */ + +.cm-s-pastel-on-dark.CodeMirror { + background: #2c2827; + color: #8F938F; + line-height: 1.5; +} +.cm-s-pastel-on-dark div.CodeMirror-selected { background: rgba(221,240,255,0.2); } +.cm-s-pastel-on-dark .CodeMirror-line::selection, .cm-s-pastel-on-dark .CodeMirror-line > span::selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::selection { background: rgba(221,240,255,0.2); } +.cm-s-pastel-on-dark .CodeMirror-line::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span::-moz-selection, .cm-s-pastel-on-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(221,240,255,0.2); } + +.cm-s-pastel-on-dark .CodeMirror-gutters { + background: #34302f; + border-right: 0px; + padding: 0 3px; +} +.cm-s-pastel-on-dark .CodeMirror-guttermarker { color: white; } +.cm-s-pastel-on-dark .CodeMirror-guttermarker-subtle { color: #8F938F; } +.cm-s-pastel-on-dark .CodeMirror-linenumber { color: #8F938F; } +.cm-s-pastel-on-dark .CodeMirror-cursor { border-left: 1px solid #A7A7A7; } +.cm-s-pastel-on-dark span.cm-comment { color: #A6C6FF; } +.cm-s-pastel-on-dark span.cm-atom { color: #DE8E30; } +.cm-s-pastel-on-dark span.cm-number { color: #CCCCCC; } +.cm-s-pastel-on-dark span.cm-property { color: #8F938F; } +.cm-s-pastel-on-dark span.cm-attribute { color: #a6e22e; } +.cm-s-pastel-on-dark span.cm-keyword { color: #AEB2F8; } +.cm-s-pastel-on-dark span.cm-string { color: #66A968; } +.cm-s-pastel-on-dark span.cm-variable { color: #AEB2F8; } +.cm-s-pastel-on-dark span.cm-variable-2 { color: #BEBF55; } +.cm-s-pastel-on-dark span.cm-variable-3, .cm-s-pastel-on-dark span.cm-type { color: #DE8E30; } +.cm-s-pastel-on-dark span.cm-def { color: #757aD8; } +.cm-s-pastel-on-dark span.cm-bracket { color: #f8f8f2; } +.cm-s-pastel-on-dark span.cm-tag { color: #C1C144; } +.cm-s-pastel-on-dark span.cm-link { color: #ae81ff; } +.cm-s-pastel-on-dark span.cm-qualifier,.cm-s-pastel-on-dark span.cm-builtin { color: #C1C144; } +.cm-s-pastel-on-dark span.cm-error { + background: #757aD8; + color: #f8f8f0; +} +.cm-s-pastel-on-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.031); } +.cm-s-pastel-on-dark .CodeMirror-matchingbracket { + border: 1px solid rgba(255,255,255,0.25); + color: #8F938F !important; + margin: -1px -1px 0 -1px; +} diff --git a/lib/redactor/codemirror/theme/railscasts.css b/lib/redactor/codemirror/theme/railscasts.css new file mode 100644 index 0000000..aeff044 --- /dev/null +++ b/lib/redactor/codemirror/theme/railscasts.css @@ -0,0 +1,34 @@ +/* + + Name: Railscasts + Author: Ryan Bates (http://railscasts.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-railscasts.CodeMirror {background: #2b2b2b; color: #f4f1ed;} +.cm-s-railscasts div.CodeMirror-selected {background: #272935 !important;} +.cm-s-railscasts .CodeMirror-gutters {background: #2b2b2b; border-right: 0px;} +.cm-s-railscasts .CodeMirror-linenumber {color: #5a647e;} +.cm-s-railscasts .CodeMirror-cursor {border-left: 1px solid #d4cfc9 !important;} + +.cm-s-railscasts span.cm-comment {color: #bc9458;} +.cm-s-railscasts span.cm-atom {color: #b6b3eb;} +.cm-s-railscasts span.cm-number {color: #b6b3eb;} + +.cm-s-railscasts span.cm-property, .cm-s-railscasts span.cm-attribute {color: #a5c261;} +.cm-s-railscasts span.cm-keyword {color: #da4939;} +.cm-s-railscasts span.cm-string {color: #ffc66d;} + +.cm-s-railscasts span.cm-variable {color: #a5c261;} +.cm-s-railscasts span.cm-variable-2 {color: #6d9cbe;} +.cm-s-railscasts span.cm-def {color: #cc7833;} +.cm-s-railscasts span.cm-error {background: #da4939; color: #d4cfc9;} +.cm-s-railscasts span.cm-bracket {color: #f4f1ed;} +.cm-s-railscasts span.cm-tag {color: #da4939;} +.cm-s-railscasts span.cm-link {color: #b6b3eb;} + +.cm-s-railscasts .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} +.cm-s-railscasts .CodeMirror-activeline-background { background: #303040; } diff --git a/lib/redactor/codemirror/theme/rubyblue.css b/lib/redactor/codemirror/theme/rubyblue.css new file mode 100644 index 0000000..1f181b0 --- /dev/null +++ b/lib/redactor/codemirror/theme/rubyblue.css @@ -0,0 +1,25 @@ +.cm-s-rubyblue.CodeMirror { background: #112435; color: white; } +.cm-s-rubyblue div.CodeMirror-selected { background: #38566F; } +.cm-s-rubyblue .CodeMirror-line::selection, .cm-s-rubyblue .CodeMirror-line > span::selection, .cm-s-rubyblue .CodeMirror-line > span > span::selection { background: rgba(56, 86, 111, 0.99); } +.cm-s-rubyblue .CodeMirror-line::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span::-moz-selection, .cm-s-rubyblue .CodeMirror-line > span > span::-moz-selection { background: rgba(56, 86, 111, 0.99); } +.cm-s-rubyblue .CodeMirror-gutters { background: #1F4661; border-right: 7px solid #3E7087; } +.cm-s-rubyblue .CodeMirror-guttermarker { color: white; } +.cm-s-rubyblue .CodeMirror-guttermarker-subtle { color: #3E7087; } +.cm-s-rubyblue .CodeMirror-linenumber { color: white; } +.cm-s-rubyblue .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-rubyblue span.cm-comment { color: #999; font-style:italic; line-height: 1em; } +.cm-s-rubyblue span.cm-atom { color: #F4C20B; } +.cm-s-rubyblue span.cm-number, .cm-s-rubyblue span.cm-attribute { color: #82C6E0; } +.cm-s-rubyblue span.cm-keyword { color: #F0F; } +.cm-s-rubyblue span.cm-string { color: #F08047; } +.cm-s-rubyblue span.cm-meta { color: #F0F; } +.cm-s-rubyblue span.cm-variable-2, .cm-s-rubyblue span.cm-tag { color: #7BD827; } +.cm-s-rubyblue span.cm-variable-3, .cm-s-rubyblue span.cm-def, .cm-s-rubyblue span.cm-type { color: white; } +.cm-s-rubyblue span.cm-bracket { color: #F0F; } +.cm-s-rubyblue span.cm-link { color: #F4C20B; } +.cm-s-rubyblue span.CodeMirror-matchingbracket { color:#F0F !important; } +.cm-s-rubyblue span.cm-builtin, .cm-s-rubyblue span.cm-special { color: #FF9D00; } +.cm-s-rubyblue span.cm-error { color: #AF2018; } + +.cm-s-rubyblue .CodeMirror-activeline-background { background: #173047; } diff --git a/lib/redactor/codemirror/theme/seti.css b/lib/redactor/codemirror/theme/seti.css new file mode 100644 index 0000000..814f76f --- /dev/null +++ b/lib/redactor/codemirror/theme/seti.css @@ -0,0 +1,44 @@ +/* + + Name: seti + Author: Michael Kaminsky (http://github.com/mkaminsky11) + + Original seti color scheme by Jesse Weed (https://github.com/jesseweed/seti-syntax) + +*/ + + +.cm-s-seti.CodeMirror { + background-color: #151718 !important; + color: #CFD2D1 !important; + border: none; +} +.cm-s-seti .CodeMirror-gutters { + color: #404b53; + background-color: #0E1112; + border: none; +} +.cm-s-seti .CodeMirror-cursor { border-left: solid thin #f8f8f0; } +.cm-s-seti .CodeMirror-linenumber { color: #6D8A88; } +.cm-s-seti.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } +.cm-s-seti .CodeMirror-line::selection, .cm-s-seti .CodeMirror-line > span::selection, .cm-s-seti .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-seti .CodeMirror-line::-moz-selection, .cm-s-seti .CodeMirror-line > span::-moz-selection, .cm-s-seti .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } +.cm-s-seti span.cm-comment { color: #41535b; } +.cm-s-seti span.cm-string, .cm-s-seti span.cm-string-2 { color: #55b5db; } +.cm-s-seti span.cm-number { color: #cd3f45; } +.cm-s-seti span.cm-variable { color: #55b5db; } +.cm-s-seti span.cm-variable-2 { color: #a074c4; } +.cm-s-seti span.cm-def { color: #55b5db; } +.cm-s-seti span.cm-keyword { color: #ff79c6; } +.cm-s-seti span.cm-operator { color: #9fca56; } +.cm-s-seti span.cm-keyword { color: #e6cd69; } +.cm-s-seti span.cm-atom { color: #cd3f45; } +.cm-s-seti span.cm-meta { color: #55b5db; } +.cm-s-seti span.cm-tag { color: #55b5db; } +.cm-s-seti span.cm-attribute { color: #9fca56; } +.cm-s-seti span.cm-qualifier { color: #9fca56; } +.cm-s-seti span.cm-property { color: #a074c4; } +.cm-s-seti span.cm-variable-3, .cm-s-seti span.cm-type { color: #9fca56; } +.cm-s-seti span.cm-builtin { color: #9fca56; } +.cm-s-seti .CodeMirror-activeline-background { background: #101213; } +.cm-s-seti .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/shadowfox.css b/lib/redactor/codemirror/theme/shadowfox.css new file mode 100644 index 0000000..32d59b1 --- /dev/null +++ b/lib/redactor/codemirror/theme/shadowfox.css @@ -0,0 +1,52 @@ +/* + + Name: shadowfox + Author: overdodactyl (http://github.com/overdodactyl) + + Original shadowfox color scheme by Firefox + +*/ + +.cm-s-shadowfox.CodeMirror { background: #2a2a2e; color: #b1b1b3; } +.cm-s-shadowfox div.CodeMirror-selected { background: #353B48; } +.cm-s-shadowfox .CodeMirror-line::selection, .cm-s-shadowfox .CodeMirror-line > span::selection, .cm-s-shadowfox .CodeMirror-line > span > span::selection { background: #353B48; } +.cm-s-shadowfox .CodeMirror-line::-moz-selection, .cm-s-shadowfox .CodeMirror-line > span::-moz-selection, .cm-s-shadowfox .CodeMirror-line > span > span::-moz-selection { background: #353B48; } +.cm-s-shadowfox .CodeMirror-gutters { background: #0c0c0d ; border-right: 1px solid #0c0c0d; } +.cm-s-shadowfox .CodeMirror-guttermarker { color: #555; } +.cm-s-shadowfox .CodeMirror-linenumber { color: #939393; } +.cm-s-shadowfox .CodeMirror-cursor { border-left: 1px solid #fff; } + +.cm-s-shadowfox span.cm-comment { color: #939393; } +.cm-s-shadowfox span.cm-atom { color: #FF7DE9; } +.cm-s-shadowfox span.cm-quote { color: #FF7DE9; } +.cm-s-shadowfox span.cm-builtin { color: #FF7DE9; } +.cm-s-shadowfox span.cm-attribute { color: #FF7DE9; } +.cm-s-shadowfox span.cm-keyword { color: #FF7DE9; } +.cm-s-shadowfox span.cm-error { color: #FF7DE9; } + +.cm-s-shadowfox span.cm-number { color: #6B89FF; } +.cm-s-shadowfox span.cm-string { color: #6B89FF; } +.cm-s-shadowfox span.cm-string-2 { color: #6B89FF; } + +.cm-s-shadowfox span.cm-meta { color: #939393; } +.cm-s-shadowfox span.cm-hr { color: #939393; } + +.cm-s-shadowfox span.cm-header { color: #75BFFF; } +.cm-s-shadowfox span.cm-qualifier { color: #75BFFF; } +.cm-s-shadowfox span.cm-variable-2 { color: #75BFFF; } + +.cm-s-shadowfox span.cm-property { color: #86DE74; } + +.cm-s-shadowfox span.cm-def { color: #75BFFF; } +.cm-s-shadowfox span.cm-bracket { color: #75BFFF; } +.cm-s-shadowfox span.cm-tag { color: #75BFFF; } +.cm-s-shadowfox span.cm-link:visited { color: #75BFFF; } + +.cm-s-shadowfox span.cm-variable { color: #B98EFF; } +.cm-s-shadowfox span.cm-variable-3 { color: #d7d7db; } +.cm-s-shadowfox span.cm-link { color: #737373; } +.cm-s-shadowfox span.cm-operator { color: #b1b1b3; } +.cm-s-shadowfox span.cm-special { color: #d7d7db; } + +.cm-s-shadowfox .CodeMirror-activeline-background { background: rgba(185, 215, 253, .15) } +.cm-s-shadowfox .CodeMirror-matchingbracket { outline: solid 1px rgba(255, 255, 255, .25); color: white !important; } diff --git a/lib/redactor/codemirror/theme/solarized.css b/lib/redactor/codemirror/theme/solarized.css new file mode 100644 index 0000000..fcd1d70 --- /dev/null +++ b/lib/redactor/codemirror/theme/solarized.css @@ -0,0 +1,168 @@ +/* +Solarized theme for code-mirror +http://ethanschoonover.com/solarized +*/ + +/* +Solarized color palette +http://ethanschoonover.com/solarized/img/solarized-palette.png +*/ + +.solarized.base03 { color: #002b36; } +.solarized.base02 { color: #073642; } +.solarized.base01 { color: #586e75; } +.solarized.base00 { color: #657b83; } +.solarized.base0 { color: #839496; } +.solarized.base1 { color: #93a1a1; } +.solarized.base2 { color: #eee8d5; } +.solarized.base3 { color: #fdf6e3; } +.solarized.solar-yellow { color: #b58900; } +.solarized.solar-orange { color: #cb4b16; } +.solarized.solar-red { color: #dc322f; } +.solarized.solar-magenta { color: #d33682; } +.solarized.solar-violet { color: #6c71c4; } +.solarized.solar-blue { color: #268bd2; } +.solarized.solar-cyan { color: #2aa198; } +.solarized.solar-green { color: #859900; } + +/* Color scheme for code-mirror */ + +.cm-s-solarized { + line-height: 1.45em; + color-profile: sRGB; + rendering-intent: auto; +} +.cm-s-solarized.cm-s-dark { + color: #839496; + background-color: #002b36; + text-shadow: #002b36 0 1px; +} +.cm-s-solarized.cm-s-light { + background-color: #fdf6e3; + color: #657b83; + text-shadow: #eee8d5 0 1px; +} + +.cm-s-solarized .CodeMirror-widget { + text-shadow: none; +} + +.cm-s-solarized .cm-header { color: #586e75; } +.cm-s-solarized .cm-quote { color: #93a1a1; } + +.cm-s-solarized .cm-keyword { color: #cb4b16; } +.cm-s-solarized .cm-atom { color: #d33682; } +.cm-s-solarized .cm-number { color: #d33682; } +.cm-s-solarized .cm-def { color: #2aa198; } + +.cm-s-solarized .cm-variable { color: #839496; } +.cm-s-solarized .cm-variable-2 { color: #b58900; } +.cm-s-solarized .cm-variable-3, .cm-s-solarized .cm-type { color: #6c71c4; } + +.cm-s-solarized .cm-property { color: #2aa198; } +.cm-s-solarized .cm-operator { color: #6c71c4; } + +.cm-s-solarized .cm-comment { color: #586e75; font-style:italic; } + +.cm-s-solarized .cm-string { color: #859900; } +.cm-s-solarized .cm-string-2 { color: #b58900; } + +.cm-s-solarized .cm-meta { color: #859900; } +.cm-s-solarized .cm-qualifier { color: #b58900; } +.cm-s-solarized .cm-builtin { color: #d33682; } +.cm-s-solarized .cm-bracket { color: #cb4b16; } +.cm-s-solarized .CodeMirror-matchingbracket { color: #859900; } +.cm-s-solarized .CodeMirror-nonmatchingbracket { color: #dc322f; } +.cm-s-solarized .cm-tag { color: #93a1a1; } +.cm-s-solarized .cm-attribute { color: #2aa198; } +.cm-s-solarized .cm-hr { + color: transparent; + border-top: 1px solid #586e75; + display: block; +} +.cm-s-solarized .cm-link { color: #93a1a1; cursor: pointer; } +.cm-s-solarized .cm-special { color: #6c71c4; } +.cm-s-solarized .cm-em { + color: #999; + text-decoration: underline; + text-decoration-style: dotted; +} +.cm-s-solarized .cm-error, +.cm-s-solarized .cm-invalidchar { + color: #586e75; + border-bottom: 1px dotted #dc322f; +} + +.cm-s-solarized.cm-s-dark div.CodeMirror-selected { background: #073642; } +.cm-s-solarized.cm-s-dark.CodeMirror ::selection { background: rgba(7, 54, 66, 0.99); } +.cm-s-solarized.cm-s-dark .CodeMirror-line::-moz-selection, .cm-s-dark .CodeMirror-line > span::-moz-selection, .cm-s-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(7, 54, 66, 0.99); } + +.cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; } +.cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; } +.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-ligh .CodeMirror-line > span::-moz-selection, .cm-s-ligh .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; } + +/* Editor styling */ + + + +/* Little shadow on the view-port of the buffer view */ +.cm-s-solarized.CodeMirror { + -moz-box-shadow: inset 7px 0 12px -6px #000; + -webkit-box-shadow: inset 7px 0 12px -6px #000; + box-shadow: inset 7px 0 12px -6px #000; +} + +/* Remove gutter border */ +.cm-s-solarized .CodeMirror-gutters { + border-right: 0; +} + +/* Gutter colors and line number styling based of color scheme (dark / light) */ + +/* Dark */ +.cm-s-solarized.cm-s-dark .CodeMirror-gutters { + background-color: #073642; +} + +.cm-s-solarized.cm-s-dark .CodeMirror-linenumber { + color: #586e75; + text-shadow: #021014 0 -1px; +} + +/* Light */ +.cm-s-solarized.cm-s-light .CodeMirror-gutters { + background-color: #eee8d5; +} + +.cm-s-solarized.cm-s-light .CodeMirror-linenumber { + color: #839496; +} + +/* Common */ +.cm-s-solarized .CodeMirror-linenumber { + padding: 0 5px; +} +.cm-s-solarized .CodeMirror-guttermarker-subtle { color: #586e75; } +.cm-s-solarized.cm-s-dark .CodeMirror-guttermarker { color: #ddd; } +.cm-s-solarized.cm-s-light .CodeMirror-guttermarker { color: #cb4b16; } + +.cm-s-solarized .CodeMirror-gutter .CodeMirror-gutter-text { + color: #586e75; +} + +/* Cursor */ +.cm-s-solarized .CodeMirror-cursor { border-left: 1px solid #819090; } + +/* Fat cursor */ +.cm-s-solarized.cm-s-light.cm-fat-cursor .CodeMirror-cursor { background: #77ee77; } +.cm-s-solarized.cm-s-light .cm-animate-fat-cursor { background-color: #77ee77; } +.cm-s-solarized.cm-s-dark.cm-fat-cursor .CodeMirror-cursor { background: #586e75; } +.cm-s-solarized.cm-s-dark .cm-animate-fat-cursor { background-color: #586e75; } + +/* Active line */ +.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background { + background: rgba(255, 255, 255, 0.06); +} +.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { + background: rgba(0, 0, 0, 0.06); +} diff --git a/lib/redactor/codemirror/theme/ssms.css b/lib/redactor/codemirror/theme/ssms.css new file mode 100644 index 0000000..9494c14 --- /dev/null +++ b/lib/redactor/codemirror/theme/ssms.css @@ -0,0 +1,16 @@ +.cm-s-ssms span.cm-keyword { color: blue; } +.cm-s-ssms span.cm-comment { color: darkgreen; } +.cm-s-ssms span.cm-string { color: red; } +.cm-s-ssms span.cm-def { color: black; } +.cm-s-ssms span.cm-variable { color: black; } +.cm-s-ssms span.cm-variable-2 { color: black; } +.cm-s-ssms span.cm-atom { color: darkgray; } +.cm-s-ssms .CodeMirror-linenumber { color: teal; } +.cm-s-ssms .CodeMirror-activeline-background { background: #ffffff; } +.cm-s-ssms span.cm-string-2 { color: #FF00FF; } +.cm-s-ssms span.cm-operator, +.cm-s-ssms span.cm-bracket, +.cm-s-ssms span.cm-punctuation { color: darkgray; } +.cm-s-ssms .CodeMirror-gutters { border-right: 3px solid #ffee62; background-color: #ffffff; } +.cm-s-ssms div.CodeMirror-selected { background: #ADD6FF; } + diff --git a/lib/redactor/codemirror/theme/the-matrix.css b/lib/redactor/codemirror/theme/the-matrix.css new file mode 100644 index 0000000..c4c93c1 --- /dev/null +++ b/lib/redactor/codemirror/theme/the-matrix.css @@ -0,0 +1,30 @@ +.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; } +.cm-s-the-matrix div.CodeMirror-selected { background: #2D2D2D; } +.cm-s-the-matrix .CodeMirror-line::selection, .cm-s-the-matrix .CodeMirror-line > span::selection, .cm-s-the-matrix .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-the-matrix .CodeMirror-line::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span::-moz-selection, .cm-s-the-matrix .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; } +.cm-s-the-matrix .CodeMirror-guttermarker { color: #0f0; } +.cm-s-the-matrix .CodeMirror-guttermarker-subtle { color: white; } +.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; } +.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00; } + +.cm-s-the-matrix span.cm-keyword { color: #008803; font-weight: bold; } +.cm-s-the-matrix span.cm-atom { color: #3FF; } +.cm-s-the-matrix span.cm-number { color: #FFB94F; } +.cm-s-the-matrix span.cm-def { color: #99C; } +.cm-s-the-matrix span.cm-variable { color: #F6C; } +.cm-s-the-matrix span.cm-variable-2 { color: #C6F; } +.cm-s-the-matrix span.cm-variable-3, .cm-s-the-matrix span.cm-type { color: #96F; } +.cm-s-the-matrix span.cm-property { color: #62FFA0; } +.cm-s-the-matrix span.cm-operator { color: #999; } +.cm-s-the-matrix span.cm-comment { color: #CCCCCC; } +.cm-s-the-matrix span.cm-string { color: #39C; } +.cm-s-the-matrix span.cm-meta { color: #C9F; } +.cm-s-the-matrix span.cm-qualifier { color: #FFF700; } +.cm-s-the-matrix span.cm-builtin { color: #30a; } +.cm-s-the-matrix span.cm-bracket { color: #cc7; } +.cm-s-the-matrix span.cm-tag { color: #FFBD40; } +.cm-s-the-matrix span.cm-attribute { color: #FFF700; } +.cm-s-the-matrix span.cm-error { color: #FF0000; } + +.cm-s-the-matrix .CodeMirror-activeline-background { background: #040; } diff --git a/lib/redactor/codemirror/theme/tomorrow-night-bright.css b/lib/redactor/codemirror/theme/tomorrow-night-bright.css new file mode 100644 index 0000000..b6dd4a9 --- /dev/null +++ b/lib/redactor/codemirror/theme/tomorrow-night-bright.css @@ -0,0 +1,35 @@ +/* + + Name: Tomorrow Night - Bright + Author: Chris Kempson + + Port done by Gerard Braad + +*/ + +.cm-s-tomorrow-night-bright.CodeMirror { background: #000000; color: #eaeaea; } +.cm-s-tomorrow-night-bright div.CodeMirror-selected { background: #424242; } +.cm-s-tomorrow-night-bright .CodeMirror-gutters { background: #000000; border-right: 0px; } +.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; } +.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-tomorrow-night-bright .CodeMirror-linenumber { color: #424242; } +.cm-s-tomorrow-night-bright .CodeMirror-cursor { border-left: 1px solid #6A6A6A; } + +.cm-s-tomorrow-night-bright span.cm-comment { color: #d27b53; } +.cm-s-tomorrow-night-bright span.cm-atom { color: #a16a94; } +.cm-s-tomorrow-night-bright span.cm-number { color: #a16a94; } + +.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute { color: #99cc99; } +.cm-s-tomorrow-night-bright span.cm-keyword { color: #d54e53; } +.cm-s-tomorrow-night-bright span.cm-string { color: #e7c547; } + +.cm-s-tomorrow-night-bright span.cm-variable { color: #b9ca4a; } +.cm-s-tomorrow-night-bright span.cm-variable-2 { color: #7aa6da; } +.cm-s-tomorrow-night-bright span.cm-def { color: #e78c45; } +.cm-s-tomorrow-night-bright span.cm-bracket { color: #eaeaea; } +.cm-s-tomorrow-night-bright span.cm-tag { color: #d54e53; } +.cm-s-tomorrow-night-bright span.cm-link { color: #a16a94; } +.cm-s-tomorrow-night-bright span.cm-error { background: #d54e53; color: #6A6A6A; } + +.cm-s-tomorrow-night-bright .CodeMirror-activeline-background { background: #2a2a2a; } +.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/tomorrow-night-eighties.css b/lib/redactor/codemirror/theme/tomorrow-night-eighties.css new file mode 100644 index 0000000..2a9debc --- /dev/null +++ b/lib/redactor/codemirror/theme/tomorrow-night-eighties.css @@ -0,0 +1,38 @@ +/* + + Name: Tomorrow Night - Eighties + Author: Chris Kempson + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-tomorrow-night-eighties.CodeMirror { background: #000000; color: #CCCCCC; } +.cm-s-tomorrow-night-eighties div.CodeMirror-selected { background: #2D2D2D; } +.cm-s-tomorrow-night-eighties .CodeMirror-line::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-tomorrow-night-eighties .CodeMirror-line::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); } +.cm-s-tomorrow-night-eighties .CodeMirror-gutters { background: #000000; border-right: 0px; } +.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; } +.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; } +.cm-s-tomorrow-night-eighties .CodeMirror-linenumber { color: #515151; } +.cm-s-tomorrow-night-eighties .CodeMirror-cursor { border-left: 1px solid #6A6A6A; } + +.cm-s-tomorrow-night-eighties span.cm-comment { color: #d27b53; } +.cm-s-tomorrow-night-eighties span.cm-atom { color: #a16a94; } +.cm-s-tomorrow-night-eighties span.cm-number { color: #a16a94; } + +.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute { color: #99cc99; } +.cm-s-tomorrow-night-eighties span.cm-keyword { color: #f2777a; } +.cm-s-tomorrow-night-eighties span.cm-string { color: #ffcc66; } + +.cm-s-tomorrow-night-eighties span.cm-variable { color: #99cc99; } +.cm-s-tomorrow-night-eighties span.cm-variable-2 { color: #6699cc; } +.cm-s-tomorrow-night-eighties span.cm-def { color: #f99157; } +.cm-s-tomorrow-night-eighties span.cm-bracket { color: #CCCCCC; } +.cm-s-tomorrow-night-eighties span.cm-tag { color: #f2777a; } +.cm-s-tomorrow-night-eighties span.cm-link { color: #a16a94; } +.cm-s-tomorrow-night-eighties span.cm-error { background: #f2777a; color: #6A6A6A; } + +.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background { background: #343600; } +.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } diff --git a/lib/redactor/codemirror/theme/ttcn.css b/lib/redactor/codemirror/theme/ttcn.css new file mode 100644 index 0000000..0b14ac3 --- /dev/null +++ b/lib/redactor/codemirror/theme/ttcn.css @@ -0,0 +1,64 @@ +.cm-s-ttcn .cm-quote { color: #090; } +.cm-s-ttcn .cm-negative { color: #d44; } +.cm-s-ttcn .cm-positive { color: #292; } +.cm-s-ttcn .cm-header, .cm-strong { font-weight: bold; } +.cm-s-ttcn .cm-em { font-style: italic; } +.cm-s-ttcn .cm-link { text-decoration: underline; } +.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; } +.cm-s-ttcn .cm-header { color: #00f; font-weight: bold; } + +.cm-s-ttcn .cm-atom { color: #219; } +.cm-s-ttcn .cm-attribute { color: #00c; } +.cm-s-ttcn .cm-bracket { color: #997; } +.cm-s-ttcn .cm-comment { color: #333333; } +.cm-s-ttcn .cm-def { color: #00f; } +.cm-s-ttcn .cm-em { font-style: italic; } +.cm-s-ttcn .cm-error { color: #f00; } +.cm-s-ttcn .cm-hr { color: #999; } +.cm-s-ttcn .cm-invalidchar { color: #f00; } +.cm-s-ttcn .cm-keyword { font-weight:bold; } +.cm-s-ttcn .cm-link { color: #00c; text-decoration: underline; } +.cm-s-ttcn .cm-meta { color: #555; } +.cm-s-ttcn .cm-negative { color: #d44; } +.cm-s-ttcn .cm-positive { color: #292; } +.cm-s-ttcn .cm-qualifier { color: #555; } +.cm-s-ttcn .cm-strikethrough { text-decoration: line-through; } +.cm-s-ttcn .cm-string { color: #006400; } +.cm-s-ttcn .cm-string-2 { color: #f50; } +.cm-s-ttcn .cm-strong { font-weight: bold; } +.cm-s-ttcn .cm-tag { color: #170; } +.cm-s-ttcn .cm-variable { color: #8B2252; } +.cm-s-ttcn .cm-variable-2 { color: #05a; } +.cm-s-ttcn .cm-variable-3, .cm-s-ttcn .cm-type { color: #085; } + +.cm-s-ttcn .cm-invalidchar { color: #f00; } + +/* ASN */ +.cm-s-ttcn .cm-accessTypes, +.cm-s-ttcn .cm-compareTypes { color: #27408B; } +.cm-s-ttcn .cm-cmipVerbs { color: #8B2252; } +.cm-s-ttcn .cm-modifier { color:#D2691E; } +.cm-s-ttcn .cm-status { color:#8B4545; } +.cm-s-ttcn .cm-storage { color:#A020F0; } +.cm-s-ttcn .cm-tags { color:#006400; } + +/* CFG */ +.cm-s-ttcn .cm-externalCommands { color: #8B4545; font-weight:bold; } +.cm-s-ttcn .cm-fileNCtrlMaskOptions, +.cm-s-ttcn .cm-sectionTitle { color: #2E8B57; font-weight:bold; } + +/* TTCN */ +.cm-s-ttcn .cm-booleanConsts, +.cm-s-ttcn .cm-otherConsts, +.cm-s-ttcn .cm-verdictConsts { color: #006400; } +.cm-s-ttcn .cm-configOps, +.cm-s-ttcn .cm-functionOps, +.cm-s-ttcn .cm-portOps, +.cm-s-ttcn .cm-sutOps, +.cm-s-ttcn .cm-timerOps, +.cm-s-ttcn .cm-verdictOps { color: #0000FF; } +.cm-s-ttcn .cm-preprocessor, +.cm-s-ttcn .cm-templateMatch, +.cm-s-ttcn .cm-ttcn3Macros { color: #27408B; } +.cm-s-ttcn .cm-types { color: #A52A2A; font-weight:bold; } +.cm-s-ttcn .cm-visibilityModifiers { font-weight:bold; } diff --git a/lib/redactor/codemirror/theme/twilight.css b/lib/redactor/codemirror/theme/twilight.css new file mode 100644 index 0000000..b2b1b2a --- /dev/null +++ b/lib/redactor/codemirror/theme/twilight.css @@ -0,0 +1,32 @@ +.cm-s-twilight.CodeMirror { background: #141414; color: #f7f7f7; } /**/ +.cm-s-twilight div.CodeMirror-selected { background: #323232; } /**/ +.cm-s-twilight .CodeMirror-line::selection, .cm-s-twilight .CodeMirror-line > span::selection, .cm-s-twilight .CodeMirror-line > span > span::selection { background: rgba(50, 50, 50, 0.99); } +.cm-s-twilight .CodeMirror-line::-moz-selection, .cm-s-twilight .CodeMirror-line > span::-moz-selection, .cm-s-twilight .CodeMirror-line > span > span::-moz-selection { background: rgba(50, 50, 50, 0.99); } + +.cm-s-twilight .CodeMirror-gutters { background: #222; border-right: 1px solid #aaa; } +.cm-s-twilight .CodeMirror-guttermarker { color: white; } +.cm-s-twilight .CodeMirror-guttermarker-subtle { color: #aaa; } +.cm-s-twilight .CodeMirror-linenumber { color: #aaa; } +.cm-s-twilight .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-twilight .cm-keyword { color: #f9ee98; } /**/ +.cm-s-twilight .cm-atom { color: #FC0; } +.cm-s-twilight .cm-number { color: #ca7841; } /**/ +.cm-s-twilight .cm-def { color: #8DA6CE; } +.cm-s-twilight span.cm-variable-2, .cm-s-twilight span.cm-tag { color: #607392; } /**/ +.cm-s-twilight span.cm-variable-3, .cm-s-twilight span.cm-def, .cm-s-twilight span.cm-type { color: #607392; } /**/ +.cm-s-twilight .cm-operator { color: #cda869; } /**/ +.cm-s-twilight .cm-comment { color:#777; font-style:italic; font-weight:normal; } /**/ +.cm-s-twilight .cm-string { color:#8f9d6a; font-style:italic; } /**/ +.cm-s-twilight .cm-string-2 { color:#bd6b18; } /*?*/ +.cm-s-twilight .cm-meta { background-color:#141414; color:#f7f7f7; } /*?*/ +.cm-s-twilight .cm-builtin { color: #cda869; } /*?*/ +.cm-s-twilight .cm-tag { color: #997643; } /**/ +.cm-s-twilight .cm-attribute { color: #d6bb6d; } /*?*/ +.cm-s-twilight .cm-header { color: #FF6400; } +.cm-s-twilight .cm-hr { color: #AEAEAE; } +.cm-s-twilight .cm-link { color:#ad9361; font-style:italic; text-decoration:none; } /**/ +.cm-s-twilight .cm-error { border-bottom: 1px solid red; } + +.cm-s-twilight .CodeMirror-activeline-background { background: #27282E; } +.cm-s-twilight .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } diff --git a/lib/redactor/codemirror/theme/vibrant-ink.css b/lib/redactor/codemirror/theme/vibrant-ink.css new file mode 100644 index 0000000..6358ad3 --- /dev/null +++ b/lib/redactor/codemirror/theme/vibrant-ink.css @@ -0,0 +1,34 @@ +/* Taken from the popular Visual Studio Vibrant Ink Schema */ + +.cm-s-vibrant-ink.CodeMirror { background: black; color: white; } +.cm-s-vibrant-ink div.CodeMirror-selected { background: #35493c; } +.cm-s-vibrant-ink .CodeMirror-line::selection, .cm-s-vibrant-ink .CodeMirror-line > span::selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::selection { background: rgba(53, 73, 60, 0.99); } +.cm-s-vibrant-ink .CodeMirror-line::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span::-moz-selection, .cm-s-vibrant-ink .CodeMirror-line > span > span::-moz-selection { background: rgba(53, 73, 60, 0.99); } + +.cm-s-vibrant-ink .CodeMirror-gutters { background: #002240; border-right: 1px solid #aaa; } +.cm-s-vibrant-ink .CodeMirror-guttermarker { color: white; } +.cm-s-vibrant-ink .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-vibrant-ink .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-vibrant-ink .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-vibrant-ink .cm-keyword { color: #CC7832; } +.cm-s-vibrant-ink .cm-atom { color: #FC0; } +.cm-s-vibrant-ink .cm-number { color: #FFEE98; } +.cm-s-vibrant-ink .cm-def { color: #8DA6CE; } +.cm-s-vibrant-ink span.cm-variable-2, .cm-s-vibrant span.cm-tag { color: #FFC66D; } +.cm-s-vibrant-ink span.cm-variable-3, .cm-s-vibrant span.cm-def, .cm-s-vibrant span.cm-type { color: #FFC66D; } +.cm-s-vibrant-ink .cm-operator { color: #888; } +.cm-s-vibrant-ink .cm-comment { color: gray; font-weight: bold; } +.cm-s-vibrant-ink .cm-string { color: #A5C25C; } +.cm-s-vibrant-ink .cm-string-2 { color: red; } +.cm-s-vibrant-ink .cm-meta { color: #D8FA3C; } +.cm-s-vibrant-ink .cm-builtin { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-tag { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-attribute { color: #8DA6CE; } +.cm-s-vibrant-ink .cm-header { color: #FF6400; } +.cm-s-vibrant-ink .cm-hr { color: #AEAEAE; } +.cm-s-vibrant-ink .cm-link { color: #5656F3; } +.cm-s-vibrant-ink .cm-error { border-bottom: 1px solid red; } + +.cm-s-vibrant-ink .CodeMirror-activeline-background { background: #27282E; } +.cm-s-vibrant-ink .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } diff --git a/lib/redactor/codemirror/theme/xq-dark.css b/lib/redactor/codemirror/theme/xq-dark.css new file mode 100644 index 0000000..7da1a0f --- /dev/null +++ b/lib/redactor/codemirror/theme/xq-dark.css @@ -0,0 +1,53 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +.cm-s-xq-dark.CodeMirror { background: #0a001f; color: #f8f8f8; } +.cm-s-xq-dark div.CodeMirror-selected { background: #27007A; } +.cm-s-xq-dark .CodeMirror-line::selection, .cm-s-xq-dark .CodeMirror-line > span::selection, .cm-s-xq-dark .CodeMirror-line > span > span::selection { background: rgba(39, 0, 122, 0.99); } +.cm-s-xq-dark .CodeMirror-line::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span::-moz-selection, .cm-s-xq-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 0, 122, 0.99); } +.cm-s-xq-dark .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-xq-dark .CodeMirror-guttermarker { color: #FFBD40; } +.cm-s-xq-dark .CodeMirror-guttermarker-subtle { color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-linenumber { color: #f8f8f8; } +.cm-s-xq-dark .CodeMirror-cursor { border-left: 1px solid white; } + +.cm-s-xq-dark span.cm-keyword { color: #FFBD40; } +.cm-s-xq-dark span.cm-atom { color: #6C8CD5; } +.cm-s-xq-dark span.cm-number { color: #164; } +.cm-s-xq-dark span.cm-def { color: #FFF; text-decoration:underline; } +.cm-s-xq-dark span.cm-variable { color: #FFF; } +.cm-s-xq-dark span.cm-variable-2 { color: #EEE; } +.cm-s-xq-dark span.cm-variable-3, .cm-s-xq-dark span.cm-type { color: #DDD; } +.cm-s-xq-dark span.cm-property {} +.cm-s-xq-dark span.cm-operator {} +.cm-s-xq-dark span.cm-comment { color: gray; } +.cm-s-xq-dark span.cm-string { color: #9FEE00; } +.cm-s-xq-dark span.cm-meta { color: yellow; } +.cm-s-xq-dark span.cm-qualifier { color: #FFF700; } +.cm-s-xq-dark span.cm-builtin { color: #30a; } +.cm-s-xq-dark span.cm-bracket { color: #cc7; } +.cm-s-xq-dark span.cm-tag { color: #FFBD40; } +.cm-s-xq-dark span.cm-attribute { color: #FFF700; } +.cm-s-xq-dark span.cm-error { color: #f00; } + +.cm-s-xq-dark .CodeMirror-activeline-background { background: #27282E; } +.cm-s-xq-dark .CodeMirror-matchingbracket { outline:1px solid grey; color:white !important; } diff --git a/lib/redactor/codemirror/theme/xq-light.css b/lib/redactor/codemirror/theme/xq-light.css new file mode 100644 index 0000000..7b182ea --- /dev/null +++ b/lib/redactor/codemirror/theme/xq-light.css @@ -0,0 +1,43 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +.cm-s-xq-light span.cm-keyword { line-height: 1em; font-weight: bold; color: #5A5CAD; } +.cm-s-xq-light span.cm-atom { color: #6C8CD5; } +.cm-s-xq-light span.cm-number { color: #164; } +.cm-s-xq-light span.cm-def { text-decoration:underline; } +.cm-s-xq-light span.cm-variable { color: black; } +.cm-s-xq-light span.cm-variable-2 { color:black; } +.cm-s-xq-light span.cm-variable-3, .cm-s-xq-light span.cm-type { color: black; } +.cm-s-xq-light span.cm-property {} +.cm-s-xq-light span.cm-operator {} +.cm-s-xq-light span.cm-comment { color: #0080FF; font-style: italic; } +.cm-s-xq-light span.cm-string { color: red; } +.cm-s-xq-light span.cm-meta { color: yellow; } +.cm-s-xq-light span.cm-qualifier { color: grey; } +.cm-s-xq-light span.cm-builtin { color: #7EA656; } +.cm-s-xq-light span.cm-bracket { color: #cc7; } +.cm-s-xq-light span.cm-tag { color: #3F7F7F; } +.cm-s-xq-light span.cm-attribute { color: #7F007F; } +.cm-s-xq-light span.cm-error { color: #f00; } + +.cm-s-xq-light .CodeMirror-activeline-background { background: #e8f2ff; } +.cm-s-xq-light .CodeMirror-matchingbracket { outline:1px solid grey;color:black !important;background:yellow; } diff --git a/lib/redactor/codemirror/theme/yeti.css b/lib/redactor/codemirror/theme/yeti.css new file mode 100644 index 0000000..d085f72 --- /dev/null +++ b/lib/redactor/codemirror/theme/yeti.css @@ -0,0 +1,44 @@ +/* + + Name: yeti + Author: Michael Kaminsky (http://github.com/mkaminsky11) + + Original yeti color scheme by Jesse Weed (https://github.com/jesseweed/yeti-syntax) + +*/ + + +.cm-s-yeti.CodeMirror { + background-color: #ECEAE8 !important; + color: #d1c9c0 !important; + border: none; +} + +.cm-s-yeti .CodeMirror-gutters { + color: #adaba6; + background-color: #E5E1DB; + border: none; +} +.cm-s-yeti .CodeMirror-cursor { border-left: solid thin #d1c9c0; } +.cm-s-yeti .CodeMirror-linenumber { color: #adaba6; } +.cm-s-yeti.CodeMirror-focused div.CodeMirror-selected { background: #DCD8D2; } +.cm-s-yeti .CodeMirror-line::selection, .cm-s-yeti .CodeMirror-line > span::selection, .cm-s-yeti .CodeMirror-line > span > span::selection { background: #DCD8D2; } +.cm-s-yeti .CodeMirror-line::-moz-selection, .cm-s-yeti .CodeMirror-line > span::-moz-selection, .cm-s-yeti .CodeMirror-line > span > span::-moz-selection { background: #DCD8D2; } +.cm-s-yeti span.cm-comment { color: #d4c8be; } +.cm-s-yeti span.cm-string, .cm-s-yeti span.cm-string-2 { color: #96c0d8; } +.cm-s-yeti span.cm-number { color: #a074c4; } +.cm-s-yeti span.cm-variable { color: #55b5db; } +.cm-s-yeti span.cm-variable-2 { color: #a074c4; } +.cm-s-yeti span.cm-def { color: #55b5db; } +.cm-s-yeti span.cm-operator { color: #9fb96e; } +.cm-s-yeti span.cm-keyword { color: #9fb96e; } +.cm-s-yeti span.cm-atom { color: #a074c4; } +.cm-s-yeti span.cm-meta { color: #96c0d8; } +.cm-s-yeti span.cm-tag { color: #96c0d8; } +.cm-s-yeti span.cm-attribute { color: #9fb96e; } +.cm-s-yeti span.cm-qualifier { color: #96c0d8; } +.cm-s-yeti span.cm-property { color: #a074c4; } +.cm-s-yeti span.cm-builtin { color: #a074c4; } +.cm-s-yeti span.cm-variable-3, .cm-s-yeti span.cm-type { color: #96c0d8; } +.cm-s-yeti .CodeMirror-activeline-background { background: #E7E4E0; } +.cm-s-yeti .CodeMirror-matchingbracket { text-decoration: underline; } diff --git a/lib/redactor/codemirror/theme/yonce.css b/lib/redactor/codemirror/theme/yonce.css new file mode 100644 index 0000000..975f078 --- /dev/null +++ b/lib/redactor/codemirror/theme/yonce.css @@ -0,0 +1,59 @@ +/* + + Name: yoncé + Author: Thomas MacLean (http://github.com/thomasmaclean) + + Original yoncé color scheme by Mina Markham (https://github.com/minamarkham) + +*/ + +.cm-s-yonce.CodeMirror { background: #1C1C1C; color: #d4d4d4; } /**/ +.cm-s-yonce div.CodeMirror-selected { background: rgba(252, 69, 133, 0.478); } /**/ +.cm-s-yonce .CodeMirror-selectedtext, +.cm-s-yonce .CodeMirror-selected, +.cm-s-yonce .CodeMirror-line::selection, +.cm-s-yonce .CodeMirror-line > span::selection, +.cm-s-yonce .CodeMirror-line > span > span::selection, +.cm-s-yonce .CodeMirror-line::-moz-selection, +.cm-s-yonce .CodeMirror-line > span::-moz-selection, +.cm-s-yonce .CodeMirror-line > span > span::-moz-selection { background: rgba(252, 67, 132, 0.47); } + +.cm-s-yonce.CodeMirror pre { padding-left: 0px; } +.cm-s-yonce .CodeMirror-gutters {background: #1C1C1C; border-right: 0px;} +.cm-s-yonce .CodeMirror-linenumber {color: #777777; padding-right: 10px; } +.cm-s-yonce .CodeMirror-activeline .CodeMirror-linenumber.CodeMirror-gutter-elt { background: #1C1C1C; color: #fc4384; } +.cm-s-yonce .CodeMirror-linenumber { color: #777; } +.cm-s-yonce .CodeMirror-cursor { border-left: 2px solid #FC4384; } +.cm-s-yonce .cm-searching { background: rgba(243, 155, 53, .3) !important; outline: 1px solid #F39B35; } +.cm-s-yonce .cm-searching.CodeMirror-selectedtext { background: rgba(243, 155, 53, .7) !important; color: white; } + +.cm-s-yonce .cm-keyword { color: #00A7AA; } /**/ +.cm-s-yonce .cm-atom { color: #F39B35; } +.cm-s-yonce .cm-number, .cm-s-yonce span.cm-type { color: #A06FCA; } /**/ +.cm-s-yonce .cm-def { color: #98E342; } +.cm-s-yonce .cm-property, +.cm-s-yonce span.cm-variable { color: #D4D4D4; font-style: italic; } +.cm-s-yonce span.cm-variable-2 { color: #da7dae; font-style: italic; } +.cm-s-yonce span.cm-variable-3 { color: #A06FCA; } +.cm-s-yonce .cm-type.cm-def { color: #FC4384; font-style: normal; text-decoration: underline; } +.cm-s-yonce .cm-property.cm-def { color: #FC4384; font-style: normal; } +.cm-s-yonce .cm-callee { color: #FC4384; font-style: normal; } +.cm-s-yonce .cm-operator { color: #FC4384; } /**/ +.cm-s-yonce .cm-qualifier, +.cm-s-yonce .cm-tag { color: #FC4384; } +.cm-s-yonce .cm-tag.cm-bracket { color: #D4D4D4; } +.cm-s-yonce .cm-attribute { color: #A06FCA; } +.cm-s-yonce .cm-comment { color:#696d70; font-style:italic; font-weight:normal; } /**/ +.cm-s-yonce .cm-comment.cm-tag { color: #FC4384 } +.cm-s-yonce .cm-comment.cm-attribute { color: #D4D4D4; } +.cm-s-yonce .cm-string { color:#E6DB74; } /**/ +.cm-s-yonce .cm-string-2 { color:#F39B35; } /*?*/ +.cm-s-yonce .cm-meta { color: #D4D4D4; background: inherit; } +.cm-s-yonce .cm-builtin { color: #FC4384; } /*?*/ +.cm-s-yonce .cm-header { color: #da7dae; } +.cm-s-yonce .cm-hr { color: #98E342; } +.cm-s-yonce .cm-link { color:#696d70; font-style:italic; text-decoration:none; } /**/ +.cm-s-yonce .cm-error { border-bottom: 1px solid #C42412; } + +.cm-s-yonce .CodeMirror-activeline-background { background: #272727; } +.cm-s-yonce .CodeMirror-matchingbracket { outline:1px solid grey; color:#D4D4D4 !important; } diff --git a/lib/redactor/codemirror/theme/zenburn.css b/lib/redactor/codemirror/theme/zenburn.css new file mode 100644 index 0000000..781c40a --- /dev/null +++ b/lib/redactor/codemirror/theme/zenburn.css @@ -0,0 +1,37 @@ +/** + * " + * Using Zenburn color palette from the Emacs Zenburn Theme + * https://github.com/bbatsov/zenburn-emacs/blob/master/zenburn-theme.el + * + * Also using parts of https://github.com/xavi/coderay-lighttable-theme + * " + * From: https://github.com/wisenomad/zenburn-lighttable-theme/blob/master/zenburn.css + */ + +.cm-s-zenburn .CodeMirror-gutters { background: #3f3f3f !important; } +.cm-s-zenburn .CodeMirror-foldgutter-open, .CodeMirror-foldgutter-folded { color: #999; } +.cm-s-zenburn .CodeMirror-cursor { border-left: 1px solid white; } +.cm-s-zenburn { background-color: #3f3f3f; color: #dcdccc; } +.cm-s-zenburn span.cm-builtin { color: #dcdccc; font-weight: bold; } +.cm-s-zenburn span.cm-comment { color: #7f9f7f; } +.cm-s-zenburn span.cm-keyword { color: #f0dfaf; font-weight: bold; } +.cm-s-zenburn span.cm-atom { color: #bfebbf; } +.cm-s-zenburn span.cm-def { color: #dcdccc; } +.cm-s-zenburn span.cm-variable { color: #dfaf8f; } +.cm-s-zenburn span.cm-variable-2 { color: #dcdccc; } +.cm-s-zenburn span.cm-string { color: #cc9393; } +.cm-s-zenburn span.cm-string-2 { color: #cc9393; } +.cm-s-zenburn span.cm-number { color: #dcdccc; } +.cm-s-zenburn span.cm-tag { color: #93e0e3; } +.cm-s-zenburn span.cm-property { color: #dfaf8f; } +.cm-s-zenburn span.cm-attribute { color: #dfaf8f; } +.cm-s-zenburn span.cm-qualifier { color: #7cb8bb; } +.cm-s-zenburn span.cm-meta { color: #f0dfaf; } +.cm-s-zenburn span.cm-header { color: #f0efd0; } +.cm-s-zenburn span.cm-operator { color: #f0efd0; } +.cm-s-zenburn span.CodeMirror-matchingbracket { box-sizing: border-box; background: transparent; border-bottom: 1px solid; } +.cm-s-zenburn span.CodeMirror-nonmatchingbracket { border-bottom: 1px solid; background: none; } +.cm-s-zenburn .CodeMirror-activeline { background: #000000; } +.cm-s-zenburn .CodeMirror-activeline-background { background: #000000; } +.cm-s-zenburn div.CodeMirror-selected { background: #545454; } +.cm-s-zenburn .CodeMirror-focused div.CodeMirror-selected { background: #4f4f4f; } diff --git a/lib/redactor/elfinder/css/elfinder.full.css b/lib/redactor/elfinder/css/elfinder.full.css new file mode 100644 index 0000000..1a31217 --- /dev/null +++ b/lib/redactor/elfinder/css/elfinder.full.css @@ -0,0 +1,5314 @@ +/*! + * elFinder - file manager for web + * Version 2.1.66 (2025-08-28) + * http://elfinder.org + * + * Copyright 2009-2025, Studio 42 + * Licensed under a 3-clauses BSD license + */ + +/* File: /css/commands.css */ +/******************************************************************/ +/* COMMANDS STYLES */ +/******************************************************************/ + +/********************** COMMAND "RESIZE" ****************************/ +.elfinder-resize-container { + margin-top: .3em; +} + +.elfinder-resize-type { + float: left; + margin-bottom: .4em; +} + +.elfinder-resize-control { + float: left; +} + +.elfinder-resize-control input[type=number] { + border: 1px solid #aaa; + text-align: right; + width: 4.5em; +} + +.elfinder-mobile .elfinder-resize-control input[type=number] { + width: 3.5em; +} + +.elfinder-resize-control input.elfinder-resize-bg { + text-align: center; + width: 5em; + direction: ltr; +} + +.elfinder-dialog-resize .elfinder-resize-control-panel { + margin-top: 10px; +} + +.elfinder-dialog-resize .elfinder-resize-imgrotate, +.elfinder-dialog-resize .elfinder-resize-pallet { + cursor: pointer; +} + +.elfinder-dialog-resize .elfinder-resize-picking { + cursor: crosshair; +} + +.elfinder-dialog-resize .elfinder-resize-grid8 + button { + padding-top: 2px; + padding-bottom: 2px; +} + +.elfinder-resize-preview { + width: 400px; + height: 400px; + padding: 10px; + background: #fff; + border: 1px solid #aaa; + float: right; + position: relative; + overflow: hidden; + text-align: left; + direction: ltr; +} + +.elfinder-resize-handle { + position: relative; +} + +.elfinder-resize-handle-hline, +.elfinder-resize-handle-vline { + position: absolute; + background-image: url("../img/crop.gif"); +} + +.elfinder-resize-handle-hline { + width: 100%; + height: 1px !important; + background-repeat: repeat-x; +} + +.elfinder-resize-handle-vline { + width: 1px !important; + height: 100%; + background-repeat: repeat-y; +} + +.elfinder-resize-handle-hline-top { + top: 0; + left: 0; +} + +.elfinder-resize-handle-hline-bottom { + bottom: 0; + left: 0; +} + +.elfinder-resize-handle-vline-left { + top: 0; + left: 0; +} + +.elfinder-resize-handle-vline-right { + top: 0; + right: 0; +} + +.elfinder-resize-handle-point { + position: absolute; + width: 8px; + height: 8px; + border: 1px solid #777; + background: transparent; +} + +.elfinder-resize-handle-point-n { + top: 0; + left: 50%; + margin-top: -5px; + margin-left: -5px; +} + +.elfinder-resize-handle-point-ne { + top: 0; + right: 0; + margin-top: -5px; + margin-right: -5px; +} + +.elfinder-resize-handle-point-e { + top: 50%; + right: 0; + margin-top: -5px; + margin-right: -5px; +} + +.elfinder-resize-handle-point-se { + bottom: 0; + right: 0; + margin-bottom: -5px; + margin-right: -5px; +} + +.elfinder-resize-handle-point-s { + bottom: 0; + left: 50%; + margin-bottom: -5px; + margin-left: -5px; +} + +.elfinder-resize-handle-point-sw { + bottom: 0; + left: 0; + margin-bottom: -5px; + margin-left: -5px; +} + +.elfinder-resize-handle-point-w { + top: 50%; + left: 0; + margin-top: -5px; + margin-left: -5px; +} + +.elfinder-resize-handle-point-nw { + top: 0; + left: 0; + margin-top: -5px; + margin-left: -5px; +} + +.elfinder-dialog.elfinder-dialog-resize .ui-resizable-e { + width: 10px; + height: 100%; +} + +.elfinder-dialog.elfinder-dialog-resize .ui-resizable-s { + width: 100%; + height: 10px; +} + +.elfinder-resize-loading { + position: absolute; + width: 200px; + height: 30px; + top: 50%; + margin-top: -25px; + left: 50%; + margin-left: -100px; + text-align: center; + background: url(../img/progress.gif) center bottom repeat-x; +} + +.elfinder-resize-row { + margin-bottom: 9px; + position: relative; +} + +.elfinder-resize-label { + float: left; + width: 80px; + padding-top: 3px; +} + +.elfinder-resize-checkbox-label { + border: 1px solid transparent; +} + +.elfinder-dialog-resize .elfinder-resize-whctrls { + margin: -20px 5px 0 5px; +} + +.elfinder-ltr .elfinder-dialog-resize .elfinder-resize-whctrls { + float: right; +} + +.elfinder-rtl .elfinder-dialog-resize .elfinder-resize-whctrls { + float: left; +} + +.elfinder-dialog-resize .ui-resizable-e, +.elfinder-dialog-resize .ui-resizable-w { + height: 100%; + width: 10px; +} + +.elfinder-dialog-resize .ui-resizable-s, +.elfinder-dialog-resize .ui-resizable-n { + width: 100%; + height: 10px; +} + +.elfinder-dialog-resize .ui-resizable-e { + margin-right: -7px; +} + +.elfinder-dialog-resize .ui-resizable-w { + margin-left: -7px; +} + +.elfinder-dialog-resize .ui-resizable-s { + margin-bottom: -7px; +} + +.elfinder-dialog-resize .ui-resizable-n { + margin-top: -7px; +} + +.elfinder-dialog-resize .ui-resizable-se, +.elfinder-dialog-resize .ui-resizable-sw, +.elfinder-dialog-resize .ui-resizable-ne, +.elfinder-dialog-resize .ui-resizable-nw { + width: 10px; + height: 10px; +} + +.elfinder-dialog-resize .ui-resizable-se { + background: transparent; + bottom: 0; + right: 0; + margin-right: -7px; + margin-bottom: -7px; +} + +.elfinder-dialog-resize .ui-resizable-sw { + margin-left: -7px; + margin-bottom: -7px; +} + +.elfinder-dialog-resize .ui-resizable-ne { + margin-right: -7px; + margin-top: -7px; +} + +.elfinder-dialog-resize .ui-resizable-nw { + margin-left: -7px; + margin-top: -7px; +} + +.elfinder-touch .elfinder-dialog-resize .ui-resizable-s, +.elfinder-touch .elfinder-dialog-resize .ui-resizable-n { + height: 20px; +} + +.elfinder-touch .elfinder-dialog-resize .ui-resizable-e, +.elfinder-touch .elfinder-dialog-resize .ui-resizable-w { + width: 20px; +} + +.elfinder-touch .elfinder-dialog-resize .ui-resizable-se, +.elfinder-touch .elfinder-dialog-resize .ui-resizable-sw, +.elfinder-touch .elfinder-dialog-resize .ui-resizable-ne, +.elfinder-touch .elfinder-dialog-resize .ui-resizable-nw { + width: 30px; + height: 30px; +} + +.elfinder-touch .elfinder-dialog-resize .elfinder-resize-preview .ui-resizable-se { + width: 30px; + height: 30px; + margin: 0; +} + +.elfinder-dialog-resize .ui-icon-grip-solid-vertical { + position: absolute; + top: 50%; + right: 0; + margin-top: -8px; + margin-right: -11px; +} + +.elfinder-dialog-resize .ui-icon-grip-solid-horizontal { + position: absolute; + left: 50%; + bottom: 0; + margin-left: -8px; + margin-bottom: -11px;; +} + +.elfinder-dialog-resize .elfinder-resize-row .ui-buttonset { + float: right; +} + +.elfinder-dialog-resize .elfinder-resize-degree input, +.elfinder-dialog-resize input.elfinder-resize-quality { + width: 3.5em; +} + +.elfinder-mobile .elfinder-dialog-resize .elfinder-resize-degree input, +.elfinder-mobile .elfinder-dialog-resize input.elfinder-resize-quality { + width: 2.5em; +} + +.elfinder-dialog-resize .elfinder-resize-degree button.ui-button { + padding: 6px 8px; +} + +.elfinder-dialog-resize button.ui-button span { + padding: 0; +} + +.elfinder-dialog-resize .elfinder-resize-jpgsize { + font-size: 90%; +} + +.ui-widget-content .elfinder-resize-container .elfinder-resize-rotate-slider { + width: 195px; + margin: 10px 7px; + background-color: #fafafa; +} + +.elfinder-dialog-resize .elfinder-resize-type span.ui-checkboxradio-icon { + display: none; +} + +.elfinder-resize-preset-container { + box-sizing: border-box; + border-radius: 5px; +} + +/********************** COMMAND "EDIT" ****************************/ +/* edit text file textarea */ +.elfinder-file-edit { + width: 100%; + height: 100%; + margin: 0; + padding: 2px; + border: 1px solid #ccc; + box-sizing: border-box; + resize: none; +} + +.elfinder-touch .elfinder-file-edit { + font-size: 16px; +} + +/* edit area */ +.elfinder-dialog-edit .ui-dialog-content.elfinder-edit-editor { + background-color: #fff; +} + +.elfinder-dialog-edit .ui-dialog-content.elfinder-edit-editor .elfinder-edit-imageeditor { + width: 100%; + height: 300px; + max-height: 100%; + text-align: center; +} + +.elfinder-dialog-edit .ui-dialog-content.elfinder-edit-editor .elfinder-edit-imageeditor * { + -webkit-user-select: none; + -moz-user-select: none; + -khtml-user-select: none; + user-select: none; +} + +.elfinder-edit-imageeditor .tui-image-editor-main-container .tui-image-editor-main { + top: 0; +} + +.elfinder-edit-imageeditor .tui-image-editor-main-container .tui-image-editor-header { + display: none; +} + +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-crop .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-flip .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-rotate .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-draw .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-shape .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-icon .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-text .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-mask .tui-image-editor-wrap, +.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-filter .tui-image-editor-wrap { + height: calc(100% - 150px); +} + +/* bottom margen for softkeyboard on fullscreen mode */ +.elfinder-touch.elfinder-fullscreen-native textarea.elfinder-file-edit { + padding-bottom: 20em; + margin-bottom: -20em; +} + +.elfinder-dialog-edit .ui-dialog-buttonpane .elfinder-dialog-confirm-encoding { + font-size: 12px; +} + +.ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras { + margin: 0 1em 0 .2em; + float: left; +} + +.ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras-quality { + padding-top: 6px; +} + +.ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras select { + font-size: 12px; + margin-top: 8px; +} + +.elfinder-dialog-edit .ui-dialog-buttonpane .ui-icon { + cursor: pointer; +} + +.elfinder-edit-spinner { + position: absolute; + top: 50%; + text-align: center; + width: 100%; + font-size: 16pt; +} + +.elfinder-dialog-edit .elfinder-edit-spinner .elfinder-spinner, +.elfinder-dialog-edit .elfinder-edit-spinner .elfinder-spinner-text { + float: none; +} + +.elfinder-dialog-edit .elfinder-toast > div { + width: 280px; +} + +.elfinder-edit-onlineconvert-button { + display: inline-block; + width: 180px; + min-height: 30px; + vertical-align: top; +} +.elfinder-edit-onlineconvert-button button, +.elfinder-edit-onlineconvert-bottom-btn button { + cursor: pointer; +} +.elfinder-edit-onlineconvert-bottom-btn button.elfinder-button-ios-multiline { + -webkit-appearance: none; + border-radius: 16px; + color: #000; + text-align: center; + padding: 8px; + background-color: #eee; + background-image: -webkit-linear-gradient(top, hsl(0,0%,98%) 0%,hsl(0,0%,77%) 100%); + background-image: linear-gradient(to bottom, hsl(0,0%,98%) 0%,hsl(0,0%,77%) 100%); +} +.elfinder-edit-onlineconvert-button .elfinder-button-icon { + margin: 0 10px; + vertical-align: middle; + cursor: pointer; +} +.elfinder-edit-onlineconvert-bottom-btn { + text-align: center; + margin: 10px 0 0; +} + +.elfinder-edit-onlineconvert-link { + margin-top: 1em; + text-align: center; +} +.elfinder-edit-onlineconvert-link .elfinder-button-icon { + background-image: url("../img/editor-icons.png"); + background-repeat: no-repeat; + background-position: 0 -144px; + margin-bottom: -3px; +} +.elfinder-edit-onlineconvert-link a { + text-decoration: none; +} + +/********************** COMMAND "SORT" ****************************/ +/* for list table header sort triangle icon */ +div.elfinder-cwd-wrapper-list tr.ui-state-default td { + position: relative; +} + +div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon { + position: absolute; + top: 4px; + left: 0; + right: 0; + margin: auto 0px auto auto; +} + +.elfinder-touch div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon { + top: 7px; +} + +.elfinder-rtl div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon { + margin: auto auto auto 0px; +} + +/********************** COMMAND "HELP" ****************************/ +/* help dialog */ +.elfinder-help { + margin-bottom: .5em; + -webkit-overflow-scrolling: touch; +} + +/* fix tabs */ +.elfinder-help .ui-tabs-panel { + padding: .5em; + overflow: auto; + padding: 10px; +} + +.elfinder-dialog .ui-tabs .ui-tabs-nav li { + overflow: hidden; +} + +.elfinder-dialog .ui-tabs .ui-tabs-nav li a { + padding: .2em .8em; + display: inline-block; +} + +.elfinder-touch .elfinder-dialog .ui-tabs .ui-tabs-nav li a { + padding: .5em .5em; +} + +.elfinder-dialog .ui-tabs-active a { + background: inherit; +} + +.elfinder-help-shortcuts { + height: auto; + padding: 10px; + margin: 0; + box-sizing: border-box; +} + +.elfinder-help-shortcut { + white-space: nowrap; + clear: both; +} + +.elfinder-help-shortcut-pattern { + float: left; + width: 160px; +} + +.elfinder-help-logo { + width: 100px; + height: 96px; + float: left; + margin-right: 1em; + background: url('../img/logo.png') center center no-repeat; +} + +.elfinder-help h3 { + font-size: 1.5em; + margin: .2em 0 .3em 0; +} + +.elfinder-help-separator { + clear: both; + padding: .5em; +} + +.elfinder-help-link { + display: inline-block; + margin-right: 12px; + padding: 2px 0; + white-space: nowrap; +} + +.elfinder-rtl .elfinder-help-link { + margin-right: 0; + margin-left: 12px; +} + +.elfinder-help .ui-priority-secondary { + font-size: .9em; +} + +.elfinder-help .ui-priority-primary { + margin-bottom: 7px; +} + +.elfinder-help-team { + clear: both; + text-align: right; + border-bottom: 1px solid #ccc; + margin: .5em 0; + font-size: .9em; +} + +.elfinder-help-team div { + float: left; +} + +.elfinder-help-license { + font-size: .9em; +} + +.elfinder-help-disabled { + font-weight: bold; + text-align: center; + margin: 90px 0; +} + +.elfinder-help .elfinder-dont-panic { + display: block; + border: 1px solid transparent; + width: 200px; + height: 200px; + margin: 30px auto; + text-decoration: none; + text-align: center; + position: relative; + background: #d90004; + -moz-box-shadow: 5px 5px 9px #111; + -webkit-box-shadow: 5px 5px 9px #111; + box-shadow: 5px 5px 9px #111; + background: -moz-radial-gradient(80px 80px, circle farthest-corner, #d90004 35%, #960004 100%); + background: -webkit-gradient(radial, 80 80, 60, 80 80, 120, from(#d90004), to(#960004)); + -moz-border-radius: 100px; + -webkit-border-radius: 100px; + border-radius: 100px; + outline: none; +} + +.elfinder-help .elfinder-dont-panic span { + font-size: 3em; + font-weight: bold; + text-align: center; + color: #fff; + position: absolute; + left: 0; + top: 45px; +} + +ul.elfinder-help-integrations ul { + margin-bottom: 1em; + padding: 0; + margin: 0 1em 1em; +} + +ul.elfinder-help-integrations a { + text-decoration: none; +} + +ul.elfinder-help-integrations a:hover { + text-decoration: underline; +} + +.elfinder-help-debug { + height: 100%; + padding: 0; + margin: 0; + overflow: none; + border: none; +} + +.elfinder-help-debug .ui-tabs-panel { + padding: 0; + margin: 0; + overflow: auto; +} + +.elfinder-help-debug fieldset { + margin-bottom: 10px; + border-color: #778899; + border-radius: 10px; +} + +.elfinder-help-debug legend { + font-size: 1.2em; + font-weight: bold; + color: #2e8b57; +} + +.elfinder-help-debug dl { + margin: 0; +} + +.elfinder-help-debug dt { + color: #778899; +} + +.elfinder-help-debug dt:before { + content: "["; +} + +.elfinder-help-debug dt:after { + content: "]"; +} + +.elfinder-help-debug dd { + margin-left: 1em; +} + +.elfinder-help-debug dd span { + /*font-size: 1.2em;*/ +} + +/********************** COMMAND "PREFERENCE" ****************************/ +.elfinder-dialog .elfinder-preference .ui-tabs-nav { + margin-bottom: 1px; + height: auto; +} + +/* fix tabs */ +.elfinder-preference .ui-tabs-panel { + padding: 10px 10px 0; + overflow: auto; + box-sizing: border-box; + -webkit-overflow-scrolling: touch; +} + +.elfinder-preference a.ui-state-hover, +.elfinder-preference label.ui-state-hover { + border: none; +} + +.elfinder-preference dl { + width: 100%; + display: inline-block; + margin: .5em 0; +} + +.elfinder-preference dt { + display: block; + width: 200px; + clear: left; + float: left; + max-width: 50%; +} + +.elfinder-rtl .elfinder-preference dt { + clear: right; + float: right; +} + +.elfinder-preference dd { + margin-bottom: 1em; +} + +.elfinder-preference dt label { + cursor: pointer; +} + +.elfinder-preference dd label, +.elfinder-preference dd input[type=checkbox] { + white-space: nowrap; + display: inline-block; + cursor: pointer; +} + +.elfinder-preference dt.elfinder-preference-checkboxes { + width: 100%; + max-width: none; +} + +.elfinder-preference dd.elfinder-preference-checkboxes { + padding-top: 3ex; +} + +.elfinder-preference select { + max-width: 100%; +} + +.elfinder-preference dd.elfinder-preference-iconSize .ui-slider { + width: 50%; + max-width: 100px; + display: inline-block; + margin: 0 10px; +} + +.elfinder-preference button { + margin: 0 16px; +} + +.elfinder-preference button + button { + margin: 0 -10px; +} + +.elfinder-preference .elfinder-preference-taball .elfinder-reference-hide-taball { + display: none; +} + +.elfinder-preference-theme fieldset { + margin-bottom: 10px; +} + +.elfinder-preference-theme legend a { + font-size: 1.8em; + text-decoration: none; + cursor: pointer; +} + +.elfinder-preference-theme dt { + width: 20%; + word-break: break-all; +} + +.elfinder-preference-theme dt:after { + content: " :"; +} + +.elfinder-preference-theme dd { + margin-inline-start: 20%; +} + +.elfinder-preference img.elfinder-preference-theme-image { + display: block; + margin-left: auto; + margin-right: auto; + max-width: 90%; + max-height: 200px; + cursor: pointer; +} + +.elfinder-preference-theme-btn { + text-align: center; +} + +.elfinder-preference-theme button.elfinder-preference-theme-default { + display: inline; + margin: 0 10px; + font-size: 8pt; +} + +/********************** COMMAND "INFO" ****************************/ +.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon:before { + right: 33px; + left: auto; +} + +.elfinder-info-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + content: none; +} + +/********************** COMMAND "UPLOAD" ****************************/ +.elfinder-upload-dialog-wrapper .elfinder-upload-dirselect { + position: absolute; + bottom: 2px; + width: 16px; + height: 16px; + padding: 10px; + border: none; + overflow: hidden; + cursor: pointer; +} + +.elfinder-ltr .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect { + left: 2px; +} + +.elfinder-rtl .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect { + right: 2px; +} + +/********************** COMMAND "RM" ****************************/ +.elfinder-ltr .elfinder-rm-title .elfinder-cwd-icon:before { + left: 38px; +} + +.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon:before { + right: 86px; + left: auto; +} + +.elfinder-rm-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + content: none; +} + +/********************** COMMAND "RENAME" ****************************/ +.elfinder-rename-batch div { + margin: 5px 8px; +} + +.elfinder-rename-batch .elfinder-rename-batch-name input { + width: 100%; + font-size: 1.6em; +} + +.elfinder-rename-batch-type { + text-align: center; +} + +.elfinder-rename-batch .elfinder-rename-batch-type label { + margin: 2px; + font-size: .9em; +} + +.elfinder-rename-batch-preview { + padding: 0 8px; + font-size: 1.1em; + min-height: 4ex; +} + + +/* File: /css/common.css */ +/*********************************************/ +/* COMMON ELFINDER STUFFS */ +/*********************************************/ + +/* for old jQuery UI */ +.ui-front { + z-index: 100; +} + +/* style reset */ +div.elfinder *, +div.elfinder :after, +div.elfinder :before { + box-sizing: content-box; +} + +div.elfinder fieldset { + display: block; + margin-inline-start: 2px; + margin-inline-end: 2px; + padding-block-start: 0.35em; + padding-inline-start: 0.75em; + padding-inline-end: 0.75em; + padding-block-end: 0.625em; + min-inline-size: min-content; + border-width: 2px; + border-style: groove; + border-color: threedface; + border-image: initial; +} + +div.elfinder legend { + display: block; + padding-inline-start: 2px; + padding-inline-end: 2px; + border-width: initial; + border-style: none; + border-color: initial; + border-image: initial; + width: auto; + margin-bottom: 0; +} + +/* base container */ +div.elfinder { + padding: 0; + position: relative; + display: block; + visibility: visible; + font-size: 18px; + font-family: Verdana, Arial, Helvetica, sans-serif; +} + +/* prevent auto zoom on iOS */ +.elfinder-ios input, +.elfinder-ios select, +.elfinder-ios textarea { + font-size: 16px !important; +} + +/* full screen mode */ +.elfinder.elfinder-fullscreen > .ui-resizable-handle { + display: none; +} + +.elfinder-font-mono { + line-height: 2ex; +} + +/* in lazy execution status */ +.elfinder.elfinder-processing * { + cursor: progress !important +} + +.elfinder.elfinder-processing.elfinder-touch .elfinder-workzone:after { + position: absolute; + top: 0; + width: 100%; + height: 3px; + content: ''; + left: 0; + background-image: url(../img/progress.gif); + opacity: .6; + pointer-events: none; +} + +/* for disable select of Touch devices */ +.elfinder *:not(input):not(textarea):not(select):not([contenteditable=true]), +.elfinder-contextmenu *:not(input):not(textarea):not(select):not([contenteditable=true]) { + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + /*-webkit-touch-callout:none;*/ + -webkit-user-select: none; + -moz-user-select: none; + -khtml-user-select: none; + user-select: none; +} + +.elfinder .overflow-scrolling-touch { + -webkit-overflow-scrolling: touch; +} + +/* right to left enviroment */ +.elfinder-rtl { + text-align: right; + direction: rtl; +} + +/* nav and cwd container */ +.elfinder-workzone { + padding: 0; + position: relative; + overflow: hidden; +} + +/* dir/file permissions and symlink markers */ +.elfinder-lock, +.elfinder-perms, +.elfinder-symlink { + position: absolute; + width: 16px; + height: 16px; + background-image: url(../img/toolbar.png); + background-repeat: no-repeat; + background-position: 0 -528px; +} + +.elfinder-symlink { +} + +/* noaccess */ +.elfinder-na .elfinder-perms { + background-position: 0 -96px; +} + +/* read only */ +.elfinder-ro .elfinder-perms { + background-position: 0 -64px; +} + +/* write only */ +.elfinder-wo .elfinder-perms { + background-position: 0 -80px; +} + +/* volume type group */ +.elfinder-group .elfinder-perms { + background-position: 0 0px; +} + +/* locked */ +.elfinder-lock { + background-position: 0 -656px; +} + +/* drag helper */ +.elfinder-drag-helper { + top: 0px; + left: 0px; + width: 70px; + height: 60px; + padding: 0 0 0 25px; + z-index: 100000; + will-change: left, top; +} + +.elfinder-drag-helper.html5-native { + position: absolute; + top: -1000px; + left: -1000px; +} + +/* drag helper status icon (default no-drop) */ +.elfinder-drag-helper-icon-status { + position: absolute; + width: 16px; + height: 16px; + left: 42px; + top: 60px; + background: url('../img/toolbar.png') 0 -96px no-repeat; + display: block; +} + +/* show "up-arrow" icon for move item */ +.elfinder-drag-helper-move .elfinder-drag-helper-icon-status { + background-position: 0 -720px; +} + +/* show "plus" icon when ctrl/shift pressed */ +.elfinder-drag-helper-plus .elfinder-drag-helper-icon-status { + background-position: 0 -544px; +} + +/* files num in drag helper */ +.elfinder-drag-num { + display: inline-box; + position: absolute; + top: 0; + left: 0; + width: auto; + height: 14px; + text-align: center; + padding: 1px 3px 1px 3px; + + font-weight: bold; + color: #fff; + background-color: red; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +/* icon in drag helper */ +.elfinder-drag-helper .elfinder-cwd-icon { + margin: 0 0 0 -24px; + float: left; +} + +/* transparent overlay */ +.elfinder-overlay { + position: absolute; + opacity: .2; + filter: Alpha(Opacity=20); +} + +/* panels under/below cwd (for search field etc) */ +.elfinder .elfinder-panel { + position: relative; + background-image: none; + padding: 7px 12px; +} + +/* for html5 drag and drop */ +[draggable=true] { + -khtml-user-drag: element; +} + +/* for place holder to content editable elements */ +.elfinder [contentEditable=true]:empty:not(:focus):before { + content: attr(data-ph); +} + +/* bottom tray */ +.elfinder div.elfinder-bottomtray { + position: fixed; + bottom: 0; + max-width: 100%; + opacity: .8; +} + +.elfinder div.elfinder-bottomtray > div { + top: initial; + right: initial; + left: initial; +} + +.elfinder.elfinder-ltr div.elfinder-bottomtray { + left: 0; +} + +.elfinder.elfinder-rtl div.elfinder-bottomtray { + right: 0; +} + +/* tooltip */ +.elfinder-ui-tooltip, +.elfinder .elfinder-ui-tooltip { + font-size: 14px; + padding: 2px 4px; +} + +/* progressbar */ +.elfinder-ui-progressbar { + pointer-events: none; + position: absolute; + width: 0; + height: 2px; + top: 0px; + border-radius: 2px; + filter: blur(1px); +} + +.elfinder-ltr .elfinder-ui-progressbar { + left: 0; +} + +.elfinder-rtl .elfinder-ui-progressbar { + right: 0; +} +/* File: /css/contextmenu.css */ +/* menu and submenu */ +.elfinder .elfinder-contextmenu, +.elfinder .elfinder-contextmenu-sub { + position: absolute; + border: 1px solid #aaa; + background: #fff; + color: #555; + padding: 4px 0; + top: 0; + left: 0; +} + +/* submenu */ +.elfinder .elfinder-contextmenu-sub { + top: 5px; +} + +/* submenu in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub { + margin-left: -5px; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub { + margin-right: -5px; +} + +/* menu item */ +.elfinder .elfinder-contextmenu-header { + margin-top: -4px; + padding: 0 .5em .2ex; + border: none; + text-align: center; +} + +.elfinder .elfinder-contextmenu-header span { + font-weight: normal; + font-size: 0.8em; + font-weight: bolder; +} + +.elfinder .elfinder-contextmenu-item { + position: relative; + display: block; + padding: 4px 30px; + text-decoration: none; + white-space: nowrap; + cursor: default; +} + +.elfinder .elfinder-contextmenu-item.ui-state-active { + border: none; +} + +.elfinder .elfinder-contextmenu-item .ui-icon { + width: 16px; + height: 16px; + position: absolute; + left: auto; + right: auto; + top: 50%; + margin-top: -8px; +} + +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item .ui-icon { + left: 2px; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item .ui-icon { + right: 2px; +} + +.elfinder-touch .elfinder-contextmenu-item { + padding: 12px 38px; +} + +/* root icon of each volume */ +.elfinder-navbar-root-local.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_local.svg"); + background-size: contain; +} + +.elfinder-navbar-root-trash.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_trash.svg"); + background-size: contain; +} + +.elfinder-navbar-root-ftp.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_ftp.svg"); + background-size: contain; +} + +.elfinder-navbar-root-sql.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_sql.svg"); + background-size: contain; +} + +.elfinder-navbar-root-dropbox.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_dropbox.svg"); + background-size: contain; +} + +.elfinder-navbar-root-googledrive.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_googledrive.svg"); + background-size: contain; +} + +.elfinder-navbar-root-onedrive.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_onedrive.svg"); + background-size: contain; +} + +.elfinder-navbar-root-box.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_box.svg"); + background-size: contain; +} + +.elfinder-navbar-root-zip.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_zip.svg"); + background-size: contain; +} + +.elfinder-navbar-root-network.elfinder-contextmenu-icon { + background-image: url("../img/volume_icon_network.svg"); + background-size: contain; +} + +/* text in item */ +.elfinder .elfinder-contextmenu .elfinder-contextmenu-item span { + display: block; +} + +/* submenu item in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-sub .elfinder-contextmenu-item { + padding-left: 12px; + padding-right: 12px; +} + +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item { + text-align: left; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item { + text-align: right; +} + +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { + padding-left: 28px; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { + padding-right: 28px; +} + +.elfinder-touch .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { + padding-left: 36px; +} + +.elfinder-touch .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon { + padding-right: 36px; +} + +/* command/submenu icon */ +.elfinder .elfinder-contextmenu-extra-icon, +.elfinder .elfinder-contextmenu-arrow, +.elfinder .elfinder-contextmenu-icon { + position: absolute; + top: 50%; + margin-top: -8px; + overflow: hidden; +} + +.elfinder-touch .elfinder-button-icon.elfinder-contextmenu-icon { + transform-origin: center center; +} + +/* command icon in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-icon { + left: 8px; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-icon { + right: 8px; +} + +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-extra-icon { + right: 8px; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-extra-icon { + left: 8px; +} + +/* arrow icon */ +.elfinder .elfinder-contextmenu-arrow { + width: 16px; + height: 16px; + background: url('../img/arrows-normal.png') 5px 4px no-repeat; +} + +/* arrow icon in rtl/ltr enviroment */ +.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-arrow { + right: 5px; +} + +.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-arrow { + left: 5px; + background-position: 0 -10px; +} + +/* command extra icon's , tag */ +.elfinder .elfinder-contextmenu-extra-icon a, +.elfinder .elfinder-contextmenu-extra-icon span { + position: relative; + width: 100%; + height: 100%; + margin: 0; + color: transparent !important; + text-decoration: none; + cursor: pointer; +} + +/* disable ui border/bg image on hover */ +.elfinder .elfinder-contextmenu .ui-state-hover { + border: 0 solid; + background-image: none; +} + +/* separator */ +.elfinder .elfinder-contextmenu-separator { + height: 0px; + border-top: 1px solid #ccc; + margin: 0 1px; +} + +/* for CSS style priority to ui-state-disabled - "background-image: none" */ +.elfinder .elfinder-contextmenu-item .elfinder-button-icon.ui-state-disabled { + background-image: url('../img/toolbar.png'); +} + +/* File: /css/cwd.css */ +/******************************************************************/ +/* CURRENT DIRECTORY STYLES */ +/******************************************************************/ +/* cwd container to avoid selectable on scrollbar */ +.elfinder-cwd-wrapper { + overflow: auto; + position: relative; + padding: 2px; + margin: 0; +} + +.elfinder-cwd-wrapper-list { + padding: 0; +} + +/* container */ +.elfinder-cwd { + position: absolute; + top: 0; + cursor: default; + padding: 0; + margin: 0; + -ms-touch-action: auto; + touch-action: auto; + min-width: 100%; +} + +.elfinder-ltr .elfinder-cwd { + left: 0; +} + +.elfinder-rtl .elfinder-cwd { + right: 0; +} + +.elfinder-cwd.elfinder-table-header-sticky { + position: -webkit-sticky; + position: -ms-sticky; + position: sticky; + top: 0; + left: auto; + right: auto; + width: -webkit-max-content; + width: -moz-max-content; + width: -ms-max-content; + width: max-content; + height: 0; + overflow: visible; +} + +.elfinder-cwd.elfinder-table-header-sticky table { + border-top: 2px solid; + padding-top: 0; +} + +.elfinder-cwd.elfinder-table-header-sticky td { + display: inline-block; +} + +.elfinder-droppable-active .elfinder-cwd.elfinder-table-header-sticky table { + border-top: 2px solid transparent; +} + +/* fixed table header container */ +.elfinder-cwd-fixheader .elfinder-cwd { + position: relative; +} + +/* container active on dropenter */ +.elfinder .elfinder-cwd-wrapper.elfinder-droppable-active { + outline: 2px solid #8cafed; + outline-offset: -2px; +} + +.elfinder-cwd-wrapper-empty .elfinder-cwd:after { + display: block; + position: absolute; + height: auto; + width: 90%; + width: calc(100% - 20px); + position: absolute; + top: 50%; + left: 50%; + -ms-transform: translateY(-50%) translateX(-50%); + -webkit-transform: translateY(-50%) translateX(-50%); + transform: translateY(-50%) translateX(-50%); + line-height: 1.5em; + text-align: center; + white-space: pre-wrap; + opacity: 0.6; + filter: Alpha(Opacity=60); + font-weight: bold; +} + +.elfinder-cwd-file .elfinder-cwd-select { + position: absolute; + top: 0px; + left: 0px; + background-color: transparent; + opacity: .4; + filter: Alpha(Opacity=40); +} + +.elfinder-mobile .elfinder-cwd-file .elfinder-cwd-select { + width: 30px; + height: 30px; +} + +.elfinder-cwd-file.ui-selected .elfinder-cwd-select { + opacity: .8; + filter: Alpha(Opacity=80); +} + +.elfinder-rtl .elfinder-cwd-file .elfinder-cwd-select { + left: auto; + right: 0px; +} + +.elfinder .elfinder-cwd-selectall { + position: absolute; + width: 30px; + height: 30px; + top: 0px; + opacity: .8; + filter: Alpha(Opacity=80); +} + +.elfinder .elfinder-workzone.elfinder-cwd-wrapper-empty .elfinder-cwd-selectall { + display: none; +} + +/************************** ICONS VIEW ********************************/ + +.elfinder-ltr .elfinder-workzone .elfinder-cwd-selectall { + text-align: right; + right: 18px; + left: auto; +} + +.elfinder-rtl .elfinder-workzone .elfinder-cwd-selectall { + text-align: left; + right: auto; + left: 18px; +} + +.elfinder-ltr.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall { + right: 0px; +} + +.elfinder-rtl.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall { + left: 0px; +} + +.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-select.ui-state-hover { + background-color: transparent; +} + +/* file container */ +.elfinder-cwd-view-icons .elfinder-cwd-file { + width: 120px; + height: 90px; + padding-bottom: 2px; + cursor: default; + border: none; + position: relative; +} + +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-active { + border: none; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-icons .elfinder-cwd-file { + float: left; + margin: 0 3px 2px 0; +} + +.elfinder-rtl .elfinder-cwd-view-icons .elfinder-cwd-file { + float: right; + margin: 0 0 5px 3px; +} + +/* remove ui hover class border */ +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover { + border: 0 solid; +} + +/* icon wrapper to create selected highlight around icon */ +.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper { + width: 52px; + height: 52px; + margin: 1px auto 1px auto; + padding: 2px; + position: relative; +} + +/*** Custom Icon Size size1 - size3 ***/ +/* type badge */ +.elfinder-cwd-size1 .elfinder-cwd-icon:before, +.elfinder-cwd-size2 .elfinder-cwd-icon:before, +.elfinder-cwd-size3 .elfinder-cwd-icon:before { + top: 3px; + display: block; +} + +/* size1 */ +.elfinder-cwd-size1.elfinder-cwd-view-icons .elfinder-cwd-file { + width: 120px; + height: 112px; +} + +.elfinder-cwd-size1.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper { + width: 74px; + height: 74px; +} + +.elfinder-cwd-size1 .elfinder-cwd-icon { + -ms-transform-origin: top center; + -ms-transform: scale(1.5); + -webkit-transform-origin: top center; + -webkit-transform: scale(1.5); + transform-origin: top center; + transform: scale(1.5); +} + +.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl:before { + -ms-transform-origin: top left; + -ms-transform: scale(1.35) translate(-4px, 15%); + -webkit-transform-origin: top left; + -webkit-transform: scale(1.35) translate(-4px, 15%); + transform-origin: top left; + transform: scale(1.35) translate(-4px, 15%); +} + +.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + -ms-transform: scale(1) translate(10px, -5px); + -webkit-transform: scale(1) translate(10px, -5px); + transform: scale(1) translate(10px, -5px); +} + +.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl { + -ms-transform-origin: center center; + -ms-transform: scale(1); + -webkit-transform-origin: center center; + -webkit-transform: scale(1); + transform-origin: center center; + transform: scale(1); + width: 72px; + height: 72px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; +} + +/* size2 */ +.elfinder-cwd-size2.elfinder-cwd-view-icons .elfinder-cwd-file { + width: 140px; + height: 134px; +} + +.elfinder-cwd-size2.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper { + width: 98px; + height: 98px; +} + +.elfinder-cwd-size2 .elfinder-cwd-icon { + -ms-transform-origin: top center; + -ms-transform: scale(2); + -webkit-transform-origin: top center; + -webkit-transform: scale(2); + transform-origin: top center; + transform: scale(2); +} + +.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl:before { + -ms-transform-origin: top left; + -ms-transform: scale(1.8) translate(-5px, 18%); + -webkit-transform-origin: top left; + -webkit-transform: scale(1.8) translate(-5px, 18%); + transform-origin: top left; + transform: scale(1.8) translate(-5px, 18%); +} + +.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + -ms-transform: scale(1.1) translate(0px, 10px); + -webkit-transform: scale(1.1) translate(0px, 10px); + transform: scale(1.1) translate(0px, 10px); +} + +.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl { + -ms-transform-origin: center center; + -ms-transform: scale(1); + -webkit-transform-origin: center center; + -webkit-transform: scale(1); + transform-origin: center center; + transform: scale(1); + width: 96px; + height: 96px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +/* size3 */ +.elfinder-cwd-size3.elfinder-cwd-view-icons .elfinder-cwd-file { + width: 174px; + height: 158px; +} + +.elfinder-cwd-size3.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper { + width: 122px; + height: 122px; +} + +.elfinder-cwd-size3 .elfinder-cwd-icon { + -ms-transform-origin: top center; + -ms-transform: scale(2.5); + -webkit-transform-origin: top center; + -webkit-transform: scale(2.5); + transform-origin: top center; + transform: scale(2.5); +} + +.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl:before { + -ms-transform-origin: top left; + -ms-transform: scale(2.25) translate(-6px, 20%); + -webkit-transform-origin: top left; + -webkit-transform: scale(2.25) translate(-6px, 20%); + transform-origin: top left; + transform: scale(2.25) translate(-6px, 20%); +} + +.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl:after { + -ms-transform: scale(1.2) translate(-9px, 22px); + -webkit-transform: scale(1.2) translate(-9px, 22px); + transform: scale(1.2) translate(-9px, 22px); +} + +.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl { + -ms-transform-origin: center center; + -ms-transform: scale(1); + -webkit-transform-origin: center center; + -webkit-transform: scale(1); + transform-origin: center center; + transform: scale(1); + width: 120px; + height: 120px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; +} + +/* file name place */ +.elfinder-cwd-view-icons .elfinder-cwd-filename { + text-align: center; + max-height: 2.4em; + line-height: 1.2em; + white-space: pre-line; + overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + margin: 3px 1px 0 1px; + padding: 1px; + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; + /* for webkit CSS3 */ + word-break: break-word; + overflow-wrap: break-word; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +/* permissions/symlink markers */ +.elfinder-cwd-view-icons .elfinder-perms { + bottom: 4px; + right: 2px; +} + +.elfinder-cwd-view-icons .elfinder-lock { + top: -3px; + right: -2px; +} + +.elfinder-cwd-view-icons .elfinder-symlink { + bottom: 6px; + left: 0px; +} + +/* icon/thumbnail */ +.elfinder-cwd-icon { + display: block; + width: 48px; + height: 48px; + margin: 0 auto; + background-image: url('../img/icons-big.svg'); + background-image: url('../img/icons-big.png') \9; + background-position: 0 0; + background-repeat: no-repeat; + -moz-background-clip: padding; + -webkit-background-clip: padding-box; + background-clip: padding-box; +} + +/* volume icon of root in folder */ +.elfinder-navbar-root-local .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_local.svg"); + background-image: url("../img/volume_icon_local.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +.elfinder-navbar-root-trash .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_trash.svg"); + background-image: url("../img/volume_icon_trash.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +.elfinder-navbar-root-ftp .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_ftp.svg"); + background-image: url("../img/volume_icon_ftp.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +.elfinder-navbar-root-sql .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_sql.svg"); + background-image: url("../img/volume_icon_sql.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +.elfinder-navbar-root-dropbox .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-dropbox td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_dropbox.svg"); + background-image: url("../img/volume_icon_dropbox.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +.elfinder-navbar-root-googledrive .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_googledrive.svg"); + background-image: url("../img/volume_icon_googledrive.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-navbar-root-onedrive .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_onedrive.svg"); + background-image: url("../img/volume_icon_onedrive.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-navbar-root-box .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_box.svg"); + background-image: url("../img/volume_icon_box.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-navbar-root-zip .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-zip.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-zip td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_zip.svg"); + background-image: url("../img/volume_icon_zip.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +.elfinder-navbar-root-network .elfinder-cwd-icon, +.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon, +.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon { + background-image: url("../img/volume_icon_network.svg"); + background-image: url("../img/volume_icon_network.png") \9; + background-position: 0 0; + background-size: contain; +} + +.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon { + background-position: 1px -1px; +} + +/* type badge in "icons" view */ +.elfinder-cwd-icon:before { + content: none; + position: absolute; + left: 0px; + top: 5px; + min-width: 20px; + max-width: 84px; + text-align: center; + padding: 0px 4px 1px; + border-radius: 4px; + font-family: Verdana; + font-size: 10px; + line-height: 1.3em; + -webkit-transform: scale(0.9); + -moz-transform: scale(0.9); + -ms-transform: scale(0.9); + -o-transform: scale(0.9); + transform: scale(0.9); +} + +.elfinder-cwd-view-icons .elfinder-cwd-icon.elfinder-cwd-bgurl:before { + left: -10px; +} + +/* addtional type badge name */ +.elfinder-cwd-icon.elfinder-cwd-icon-mp2t:before { + content: 'ts' +} + +.elfinder-cwd-icon.elfinder-cwd-icon-dash-xml:before { + content: 'dash' +} + +.elfinder-cwd-icon.elfinder-cwd-icon-x-mpegurl:before { + content: 'hls' +} + +.elfinder-cwd-icon.elfinder-cwd-icon-x-c:before { + content: 'c++' +} + +/* thumbnail image */ +.elfinder-cwd-icon.elfinder-cwd-bgurl { + background-position: center center; + background-repeat: no-repeat; + -moz-background-size: contain; + background-size: contain; +} + +/* thumbnail self */ +.elfinder-cwd-icon.elfinder-cwd-bgurl.elfinder-cwd-bgself { + -moz-background-size: cover; + background-size: cover; +} + +/* thumbnail crop*/ +.elfinder-cwd-icon.elfinder-cwd-bgurl { + -moz-background-size: cover; + background-size: cover; +} + +.elfinder-cwd-icon.elfinder-cwd-bgurl:after { + content: ' '; +} + +.elfinder-cwd-bgurl:after { + position: relative; + display: inline-block; + top: 36px; + left: -38px; + width: 48px; + height: 48px; + background-image: url('../img/icons-big.svg'); + background-image: url('../img/icons-big.png') \9; + background-repeat: no-repeat; + background-size: auto !important; + opacity: .8; + filter: Alpha(Opacity=60); + -webkit-transform-origin: 54px -24px; + -webkit-transform: scale(.6); + -moz-transform-origin: 54px -24px; + -moz-transform: scale(.6); + -ms-transform-origin: 54px -24px; + -ms-transform: scale(.6); + -o-transform-origin: 54px -24px; + -o-transform: scale(.6); + transform-origin: 54px -24px; + transform: scale(.6); +} + +/* thumbnail image and draging icon */ +.elfinder-cwd-icon.elfinder-cwd-icon-drag { + width: 48px; + height: 48px; +} + +/* thumbnail image and draging icon overlay none */ +.elfinder-cwd-icon.elfinder-cwd-icon-drag:before, +.elfinder-cwd-icon.elfinder-cwd-icon-drag:after, +.elfinder-cwd-icon-image.elfinder-cwd-bgurl:after, +.elfinder-cwd-icon-directory.elfinder-cwd-bgurl:after { + content: none; +} + +/* "opened folder" icon on dragover */ +.elfinder-cwd .elfinder-droppable-active .elfinder-cwd-icon { + background-position: 0 -100px; +} + +.elfinder-cwd .elfinder-droppable-active { + outline: 2px solid #8cafed; + outline-offset: -2px; +} + +/* mimetypes icons */ +.elfinder-cwd-icon-directory { + background-position: 0 -50px; +} + +.elfinder-cwd-icon-application:after, +.elfinder-cwd-icon-application { + background-position: 0 -150px; +} + +.elfinder-cwd-icon-text:after, +.elfinder-cwd-icon-text { + background-position: 0 -1350px; +} + +.elfinder-cwd-icon-plain:after, +.elfinder-cwd-icon-plain, +.elfinder-cwd-icon-x-empty:after, +.elfinder-cwd-icon-x-empty { + background-position: 0 -200px; +} + +.elfinder-cwd-icon-image:after, +.elfinder-cwd-icon-vnd-adobe-photoshop:after, +.elfinder-cwd-icon-image, +.elfinder-cwd-icon-vnd-adobe-photoshop { + background-position: 0 -250px; +} + +.elfinder-cwd-icon-postscript:after, +.elfinder-cwd-icon-postscript { + background-position: 0 -1550px; +} + +.elfinder-cwd-icon-audio:after, +.elfinder-cwd-icon-audio { + background-position: 0 -300px; +} + +.elfinder-cwd-icon-video:after, +.elfinder-cwd-icon-video, +.elfinder-cwd-icon-flash-video, +.elfinder-cwd-icon-dash-xml, +.elfinder-cwd-icon-vnd-apple-mpegurl, +.elfinder-cwd-icon-x-mpegurl { + background-position: 0 -350px; +} + +.elfinder-cwd-icon-rtf:after, +.elfinder-cwd-icon-rtfd:after, +.elfinder-cwd-icon-rtf, +.elfinder-cwd-icon-rtfd { + background-position: 0 -400px; +} + +.elfinder-cwd-icon-pdf:after, +.elfinder-cwd-icon-pdf { + background-position: 0 -450px; +} + +.elfinder-cwd-icon-ms-excel, +.elfinder-cwd-icon-ms-excel:after, +.elfinder-cwd-icon-vnd-ms-excel, +.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-excel:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template:after { + background-position: 0 -1450px +} + +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet:after { + background-position: 0 -1700px +} + +.elfinder-cwd-icon-vnd-ms-powerpoint, +.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-powerpoint:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template:after { + background-position: 0 -1400px +} + +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation:after { + background-position: 0 -1650px +} + +.elfinder-cwd-icon-msword, +.elfinder-cwd-icon-msword:after, +.elfinder-cwd-icon-vnd-ms-word, +.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12, +.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12:after, +.elfinder-cwd-icon-vnd-ms-word:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document:after, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template:after { + background-position: 0 -1500px +} + +.elfinder-cwd-icon-vnd-oasis-opendocument-text, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-master, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-master:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-web, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-web:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-text:after { + background-position: 0 -1750px +} + +.elfinder-cwd-icon-vnd-ms-office, +.elfinder-cwd-icon-vnd-ms-office:after { + background-position: 0 -500px +} + +.elfinder-cwd-icon-vnd-oasis-opendocument-chart, +.elfinder-cwd-icon-vnd-oasis-opendocument-chart:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-database, +.elfinder-cwd-icon-vnd-oasis-opendocument-database:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-formula, +.elfinder-cwd-icon-vnd-oasis-opendocument-formula:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics:after, +.elfinder-cwd-icon-vnd-oasis-opendocument-image, +.elfinder-cwd-icon-vnd-oasis-opendocument-image:after, +.elfinder-cwd-icon-vnd-openofficeorg-extension, +.elfinder-cwd-icon-vnd-openofficeorg-extension:after { + background-position: 0 -1600px +} + +.elfinder-cwd-icon-html:after, +.elfinder-cwd-icon-html { + background-position: 0 -550px; +} + +.elfinder-cwd-icon-css:after, +.elfinder-cwd-icon-css { + background-position: 0 -600px; +} + +.elfinder-cwd-icon-javascript:after, +.elfinder-cwd-icon-x-javascript:after, +.elfinder-cwd-icon-javascript, +.elfinder-cwd-icon-x-javascript { + background-position: 0 -650px; +} + +.elfinder-cwd-icon-x-perl:after, +.elfinder-cwd-icon-x-perl { + background-position: 0 -700px; +} + +.elfinder-cwd-icon-x-python:after, +.elfinder-cwd-icon-x-python { + background-position: 0 -750px; +} + +.elfinder-cwd-icon-x-ruby:after, +.elfinder-cwd-icon-x-ruby { + background-position: 0 -800px; +} + +.elfinder-cwd-icon-x-sh:after, +.elfinder-cwd-icon-x-shellscript:after, +.elfinder-cwd-icon-x-sh, +.elfinder-cwd-icon-x-shellscript { + background-position: 0 -850px; +} + +.elfinder-cwd-icon-x-c:after, +.elfinder-cwd-icon-x-csrc:after, +.elfinder-cwd-icon-x-chdr:after, +.elfinder-cwd-icon-x-c--:after, +.elfinder-cwd-icon-x-c--src:after, +.elfinder-cwd-icon-x-c--hdr:after, +.elfinder-cwd-icon-x-java:after, +.elfinder-cwd-icon-x-java-source:after, +.elfinder-cwd-icon-x-c, +.elfinder-cwd-icon-x-csrc, +.elfinder-cwd-icon-x-chdr, +.elfinder-cwd-icon-x-c--, +.elfinder-cwd-icon-x-c--src, +.elfinder-cwd-icon-x-c--hdr, +.elfinder-cwd-icon-x-java, +.elfinder-cwd-icon-x-java-source { + background-position: 0 -900px; +} + +.elfinder-cwd-icon-x-php:after, +.elfinder-cwd-icon-x-php { + background-position: 0 -950px; +} + +.elfinder-cwd-icon-xml:after, +.elfinder-cwd-icon-xml { + background-position: 0 -1000px; +} + +.elfinder-cwd-icon-zip:after, +.elfinder-cwd-icon-x-zip:after, +.elfinder-cwd-icon-x-xz:after, +.elfinder-cwd-icon-x-7z-compressed:after, +.elfinder-cwd-icon-zip, +.elfinder-cwd-icon-x-zip, +.elfinder-cwd-icon-x-xz, +.elfinder-cwd-icon-x-7z-compressed { + background-position: 0 -1050px; +} + +.elfinder-cwd-icon-x-gzip:after, +.elfinder-cwd-icon-x-tar:after, +.elfinder-cwd-icon-x-gzip, +.elfinder-cwd-icon-x-tar { + background-position: 0 -1100px; +} + +.elfinder-cwd-icon-x-bzip:after, +.elfinder-cwd-icon-x-bzip2:after, +.elfinder-cwd-icon-x-bzip, +.elfinder-cwd-icon-x-bzip2 { + background-position: 0 -1150px; +} + +.elfinder-cwd-icon-x-rar:after, +.elfinder-cwd-icon-x-rar-compressed:after, +.elfinder-cwd-icon-x-rar, +.elfinder-cwd-icon-x-rar-compressed { + background-position: 0 -1200px; +} + +.elfinder-cwd-icon-x-shockwave-flash:after, +.elfinder-cwd-icon-x-shockwave-flash { + background-position: 0 -1250px; +} + +.elfinder-cwd-icon-group { + background-position: 0 -1300px; +} + +/* textfield inside icon */ +.elfinder-cwd-filename input { + width: 100%; + border: none; + margin: 0; + padding: 0; +} + +.elfinder-cwd-view-icons input { + text-align: center; +} + +.elfinder-cwd-view-icons textarea { + width: 100%; + border: 0px solid; + margin: 0; + padding: 0; + text-align: center; + overflow: hidden; + resize: none; +} + +.elfinder-cwd-view-icons { + text-align: center; +} + +/************************************ LIST VIEW ************************************/ + +/*.elfinder-cwd-view-list { padding:0 0 4px 0; }*/ + +.elfinder-cwd-wrapper.elfinder-cwd-fixheader .elfinder-cwd::after { + display: none; +} + +.elfinder-cwd table { + width: 100%; + border-collapse: separate; + border: 0 solid; + margin: 0 0 10px 0; + border-spacing: 0; + box-sizing: padding-box; + padding: 2px; + position: relative; +} + +.elfinder-cwd table td { + /* fix conflict with Bootstrap CSS */ + box-sizing: content-box; +} + +.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader { + position: absolute; + overflow: hidden; +} + +.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before { + content: ''; + position: absolute; + width: 100%; + top: 0; + height: 3px; + background-color: white; +} + +.elfinder-droppable-active + .elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before { + background-color: #8cafed; +} + +.elfinder .elfinder-workzone div.elfinder-cwd-fixheader table { + table-layout: fixed; +} + +.elfinder .elfinder-cwd table tbody.elfinder-cwd-fixheader { + position: relative; +} + +.elfinder-ltr .elfinder-cwd thead .elfinder-cwd-selectall { + text-align: left; + right: auto; + left: 0px; + padding-top: 3px; +} + +.elfinder-rtl .elfinder-cwd thead .elfinder-cwd-selectall { + text-align: right; + right: 0px; + left: auto; + padding-top: 3px; +} + +.elfinder-touch .elfinder-cwd thead .elfinder-cwd-selectall { + padding-top: 4px; +} + +.elfinder .elfinder-cwd table thead tr { + border-left: 0 solid; + border-top: 0 solid; + border-right: 0 solid; +} + +.elfinder .elfinder-cwd table thead td { + padding: 4px 14px; +} + +.elfinder-ltr .elfinder-cwd.elfinder-has-checkbox table thead td:first-child { + padding: 4px 14px 4px 22px; +} + +.elfinder-rtl .elfinder-cwd.elfinder-has-checkbox table thead td:first-child { + padding: 4px 22px 4px 14px; +} + +.elfinder-touch .elfinder-cwd table thead td, +.elfinder-touch .elfinder-cwd.elfinder-has-checkbox table thead td:first-child { + padding-top: 8px; + padding-bottom: 8px; +} + +.elfinder .elfinder-cwd table thead td.ui-state-active { + background: #ebf1f6; + background: -moz-linear-gradient(top, #ebf1f6 0%, #abd3ee 50%, #89c3eb 51%, #d5ebfb 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ebf1f6), color-stop(50%, #abd3ee), color-stop(51%, #89c3eb), color-stop(100%, #d5ebfb)); + background: -webkit-linear-gradient(top, #ebf1f6 0%, #abd3ee 50%, #89c3eb 51%, #d5ebfb 100%); + background: -o-linear-gradient(top, #ebf1f6 0%, #abd3ee 50%, #89c3eb 51%, #d5ebfb 100%); + background: -ms-linear-gradient(top, #ebf1f6 0%, #abd3ee 50%, #89c3eb 51%, #d5ebfb 100%); + background: linear-gradient(to bottom, #ebf1f6 0%, #abd3ee 50%, #89c3eb 51%, #d5ebfb 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ebf1f6', endColorstr='#d5ebfb', GradientType=0); +} + +.elfinder .elfinder-cwd table td { + padding: 0 12px; + white-space: pre; + overflow: hidden; + text-align: right; + cursor: default; + border: 0 solid; +} + +.elfinder .elfinder-cwd table tbody td:first-child { + position: relative +} + +.elfinder .elfinder-cwd table td div { + box-sizing: content-box; +} + +tr.elfinder-cwd-file td .elfinder-cwd-select { + padding-top: 3px; +} + +.elfinder-mobile tr.elfinder-cwd-file td .elfinder-cwd-select { + width: 40px; +} + +.elfinder-touch tr.elfinder-cwd-file td .elfinder-cwd-select { + padding-top: 10px; +} + +.elfinder-touch .elfinder-cwd tr td { + padding: 10px 12px; +} + +.elfinder-touch .elfinder-cwd tr.elfinder-cwd-file td { + padding: 13px 12px; +} + +.elfinder-ltr .elfinder-cwd table td { + text-align: right; +} + +.elfinder-ltr .elfinder-cwd table td:first-child { + text-align: left; +} + +.elfinder-rtl .elfinder-cwd table td { + text-align: left; +} + +.elfinder-rtl .elfinder-cwd table td:first-child { + text-align: right; +} + +.elfinder-odd-row { + background: #eee; +} + +/* filename container */ +.elfinder-cwd-view-list .elfinder-cwd-file-wrapper { + width: 97%; + position: relative; +} + +/* filename container in ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper { + margin-left: 8px; +} + +.elfinder-rtl .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper { + margin-right: 8px; +} + +.elfinder-cwd-view-list .elfinder-cwd-filename { + padding-top: 4px; + padding-bottom: 4px; + display: inline-block; +} + +.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-filename { + padding-left: 23px; +} + +.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-filename { + padding-right: 23px; +} + +/* premissions/symlink marker */ +.elfinder-cwd-view-list .elfinder-perms, +.elfinder-cwd-view-list .elfinder-lock, +.elfinder-cwd-view-list .elfinder-symlink { + margin-top: -6px; + opacity: .6; + filter: Alpha(Opacity=60); +} + +.elfinder-cwd-view-list .elfinder-perms { + bottom: -4px; +} + +.elfinder-cwd-view-list .elfinder-lock { + top: 0px; +} + +.elfinder-cwd-view-list .elfinder-symlink { + bottom: -4px; +} + +/* markers in ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-list .elfinder-perms { + left: 8px; +} + +.elfinder-rtl .elfinder-cwd-view-list .elfinder-perms { + right: -8px; +} + +.elfinder-ltr .elfinder-cwd-view-list .elfinder-lock { + left: 10px; +} + +.elfinder-rtl .elfinder-cwd-view-list .elfinder-lock { + right: -10px; +} + +.elfinder-ltr .elfinder-cwd-view-list .elfinder-symlink { + left: -7px; +} + +.elfinder-rtl .elfinder-cwd-view-list .elfinder-symlink { + right: 7px; +} + +/* file icon */ +.elfinder-cwd-view-list td .elfinder-cwd-icon { + width: 16px; + height: 16px; + position: absolute; + top: 50%; + margin-top: -8px; + background-image: url(../img/icons-small.png); +} + +/* icon in ltr/rtl enviroment */ +.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-icon { + left: 0; +} + +.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-icon { + right: 0; +} + +/* type badge, thumbnail image overlay */ +.elfinder-cwd-view-list .elfinder-cwd-icon:before, +.elfinder-cwd-view-list .elfinder-cwd-icon:after { + content: none; +} + +/* table header resize handle */ +.elfinder-cwd-view-list thead td .ui-resizable-handle { + height: 100%; + top: 6px; +} + +.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-handle { + top: -4px; + margin: 10px; +} + +.elfinder-cwd-view-list thead td .ui-resizable-e { + right: -7px; +} + +.elfinder-cwd-view-list thead td .ui-resizable-w { + left: -7px; +} + +.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-e { + right: -16px; +} + +.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-w { + left: -16px; +} + +/* empty message */ +.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list.elfinder-cwd:after { + margin-top: 0; +} + +/* overlay message board */ +.elfinder-cwd-message-board { + position: absolute; + position: -webkit-sticky; + position: sticky; + width: 100%; + height: calc(100% - 0.01px); /* for Firefox scroll problem */ + top: 0; + left: 0; + margin: 0; + padding: 0; + pointer-events: none; + background-color: transparent; +} + +/* overlay message board for trash */ +.elfinder-cwd-wrapper-trash .elfinder-cwd-message-board { + background-image: url(../img/trashmesh.png); +} + +.elfinder-cwd-message-board .elfinder-cwd-trash { + position: absolute; + bottom: 0; + font-size: 30px; + width: 100%; + text-align: right; + display: none; +} + +.elfinder-rtl .elfinder-cwd-message-board .elfinder-cwd-trash { + text-align: left; +} + +.elfinder-mobile .elfinder-cwd-message-board .elfinder-cwd-trash { + font-size: 20px; +} + +.elfinder-cwd-wrapper-trash .elfinder-cwd-message-board .elfinder-cwd-trash { + display: block; + opacity: .3; +} + +/* overlay message board for expires */ +.elfinder-cwd-message-board .elfinder-cwd-expires { + position: absolute; + bottom: 0; + font-size: 24px; + width: 100%; + text-align: right; + opacity: .25; +} + +.elfinder-rtl .elfinder-cwd-message-board .elfinder-cwd-expires { + text-align: left; +} + +.elfinder-mobile .elfinder-cwd-message-board .elfinder-cwd-expires { + font-size: 20px; +} + +/* File: /css/dialog.css */ +/*********************************************/ +/* DIALOGS STYLES */ +/*********************************************/ + +/* common dialogs class */ +.std42-dialog { + padding: 0; + position: absolute; + left: auto; + right: auto; + box-sizing: border-box; +} + +.std42-dialog.elfinder-dialog-minimized { + overFlow: hidden; + position: relative; + float: left; + width: auto; + cursor: pointer; +} + +.elfinder-rtl .std42-dialog.elfinder-dialog-minimized { + float: right; +} + +.std42-dialog input { + border: 1px solid; +} + +/* titlebar */ +.std42-dialog .ui-dialog-titlebar { + border-left: 0 solid transparent; + border-top: 0 solid transparent; + border-right: 0 solid transparent; + font-weight: normal; + padding: .2em 1em; +} + +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar { + padding: 0 .5em; + height: 20px; +} + +.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar { + padding: .3em .5em; +} + +.std42-dialog.ui-draggable-disabled .ui-dialog-titlebar { + cursor: default; +} + +.std42-dialog .ui-dialog-titlebar .ui-widget-header { + border: none; + cursor: pointer; +} + +.std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title { + display: inherit; + word-break: break-all; +} + +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title { + display: list-item; + display: -moz-inline-box; + white-space: nowrap; + word-break: normal; + overflow: hidden; + word-wrap: normal; + overflow-wrap: normal; + max-width: -webkit-calc(100% - 24px); + max-width: -moz-calc(100% - 24px); + max-width: calc(100% - 24px); +} + +.elfinder-touch .std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title { + padding-top: .15em; +} + +.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title { + max-width: -webkit-calc(100% - 36px); + max-width: -moz-calc(100% - 36px); + max-width: calc(100% - 36px); +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button { + position: relative; + float: left; + top: 10px; + left: -10px; + right: 10px; + width: 20px; + height: 20px; + padding: 1px; + margin: -10px 1px 0 1px; + background-color: transparent; + background-image: none; +} + +.elfinder-touch .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button { + -moz-transform: scale(1.2); + zoom: 1.2; + padding-left: 6px; + padding-right: 6px; + height: 24px; +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button-right { + float: right; +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button.elfinder-titlebar-button-right { + left: 10px; + right: -10px; +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon { + width: 17px; + height: 17px; + border-width: 1px; + opacity: .7; + filter: Alpha(Opacity=70); + -moz-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; +} + +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon { + opacity: .5; + filter: Alpha(Opacity=50); +} + +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon { + opacity: 1; + filter: Alpha(Opacity=100); +} + +.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar select { + display: none; +} + +.elfinder-spinner { + width: 14px; + height: 14px; + background: url("../img/spinner-mini.gif") center center no-repeat; + margin: 0 5px; + display: inline-block; + vertical-align: middle; +} + +.elfinder-ltr .elfinder-spinner, +.elfinder-ltr .elfinder-spinner-text { + float: left; +} + +.elfinder-rtl .elfinder-spinner, +.elfinder-rtl .elfinder-spinner-text { + float: right; +} + + + +/* resize handle for touch devices */ +.elfinder-touch .std42-dialog.ui-dialog:not(ui-resizable-disabled) .ui-resizable-se { + width: 12px; + height: 12px; + -moz-transform-origin: bottom right; + -moz-transform: scale(1.5); + zoom: 1.5; + right: -7px; + bottom: -7px; + margin: 3px 7px 7px 3px; + background-position: -64px -224px; +} + +.elfinder-rtl .elfinder-dialog .ui-dialog-titlebar { + text-align: right; +} + +/* content */ +.std42-dialog .ui-dialog-content { + padding: .3em .5em; +} + +.elfinder .std42-dialog .ui-dialog-content, +.elfinder .std42-dialog .ui-dialog-content * { + -webkit-user-select: auto; + -moz-user-select: text; + -khtml-user-select: text; + user-select: text; +} + +.elfinder .std42-dialog .ui-dialog-content label { + border: none; +} + +/* buttons */ +.std42-dialog .ui-dialog-buttonpane { + border: 0 solid; + margin: 0; + padding: .5em; + text-align: right; +} + +.elfinder-rtl .std42-dialog .ui-dialog-buttonpane { + text-align: left; +} + +.std42-dialog .ui-dialog-buttonpane button { + margin: .2em 0 0 .4em; + padding: .2em; + outline: 0px solid; +} + +.std42-dialog .ui-dialog-buttonpane button span { + padding: 2px 9px; +} + +.std42-dialog .ui-dialog-buttonpane button span.ui-icon { + padding: 2px; +} + +.elfinder-dialog .ui-resizable-e, +.elfinder-dialog .ui-resizable-s { + width: 0; + height: 0; +} + +.std42-dialog .ui-button input { + cursor: pointer; +} + +.std42-dialog select { + border: 1px solid #ccc; +} + +/* error/notify/confirm dialogs icon */ +.elfinder-dialog-icon { + position: absolute; + width: 32px; + height: 32px; + left: 10px; + top: 50%; + margin-top: -15px; + background: url("../img/dialogs.png") 0 0 no-repeat; +} + +.elfinder-rtl .elfinder-dialog-icon { + left: auto; + right: 10px; +} + +/*********************** ERROR DIALOG **************************/ + +.elfinder-dialog-error .ui-dialog-content, +.elfinder-dialog-confirm .ui-dialog-content { + padding-left: 56px; + min-height: 35px; +} + +.elfinder-rtl .elfinder-dialog-error .ui-dialog-content, +.elfinder-rtl .elfinder-dialog-confirm .ui-dialog-content { + padding-left: 0; + padding-right: 56px; +} + +.elfinder-dialog-error .elfinder-err-var { + word-break: break-all; +} + +/*********************** NOTIFY DIALOG **************************/ + +.elfinder-dialog-notify { + top : 36px; + width : 280px; +} + +.elfinder-ltr .elfinder-dialog-notify { + right : 12px; +} + +.elfinder-rtl .elfinder-dialog-notify { + left : 12px; +} + +.elfinder-dialog-notify .ui-dialog-titlebar { + height: 5px; + overflow: hidden; +} + +.elfinder.elfinder-touch > .elfinder-dialog-notify .ui-dialog-titlebar { + height: 10px; +} + +.elfinder > .elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button { + top: 2px; +} + +.elfinder.elfinder-touch > .elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button { + top: 4px; +} + +.elfinder > .elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button { + left: -18px; + right: 18px; +} + +.elfinder > .elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button.elfinder-titlebar-button-right { + left: 18px; + right: -18px; +} + +.ui-dialog-titlebar .elfinder-ui-progressbar { + position: absolute; + top: 17px; +} + +.elfinder-touch .ui-dialog-titlebar .elfinder-ui-progressbar { + top: 26px; +} + +.elfinder-dialog-notify.elfinder-titlebar-button-hide .ui-dialog-titlebar-close { + display: none; +} + +.elfinder-dialog-notify.elfinder-dialog-minimized.elfinder-titlebar-button-hide .ui-dialog-titlebar span.elfinder-dialog-title { + max-width: initial; +} + +.elfinder-dialog-notify .ui-dialog-content { + padding: 0; +} + +/* one notification container */ +.elfinder-notify { + border-bottom: 1px solid #ccc; + position: relative; + padding: .5em; + + text-align: center; + overflow: hidden; +} + +.elfinder-ltr .elfinder-notify { + padding-left: 36px; +} + +.elfinder-rtl .elfinder-notify { + padding-right: 36px; +} + +.elfinder-notify:last-child { + border: 0 solid; +} + +/* progressbar */ +.elfinder-notify-progressbar { + width: 180px; + height: 8px; + border: 1px solid #aaa; + background: #f5f5f5; + margin: 5px auto; + overflow: hidden; +} + +.elfinder-notify-progress { + width: 100%; + height: 8px; + background: url(../img/progress.gif) center center repeat-x; +} + +.elfinder-notify-progressbar, .elfinder-notify-progress { + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; +} + +.elfinder-notify-cancel { + position: relative; + top: -18px; + right: calc(-50% + 15px); +} + +.elfinder-notify-cancel .ui-icon-close { + background-position: -80px -128px; + width: 18px; + height: 18px; + border-radius: 9px; + border: none; + background-position: -80px -128px; + cursor: pointer; +} + +/* icons */ +.elfinder-dialog-icon-open, +.elfinder-dialog-icon-readdir, +.elfinder-dialog-icon-file { + background-position: 0 -225px; +} + +.elfinder-dialog-icon-reload { + background-position: 0 -225px; +} + +.elfinder-dialog-icon-mkdir { + background-position: 0 -64px; +} + +.elfinder-dialog-icon-mkfile { + background-position: 0 -96px; +} + +.elfinder-dialog-icon-copy, +.elfinder-dialog-icon-prepare, +.elfinder-dialog-icon-move { + background-position: 0 -128px; +} + +.elfinder-dialog-icon-upload { + background-position: 0 -160px; +} + +.elfinder-dialog-icon-chunkmerge { + background-position: 0 -160px; +} + +.elfinder-dialog-icon-rm { + background-position: 0 -192px; +} + +.elfinder-dialog-icon-download { + background-position: 0 -260px; +} + +.elfinder-dialog-icon-save { + background-position: 0 -295px; +} + +.elfinder-dialog-icon-rename, +.elfinder-dialog-icon-chkcontent { + background-position: 0 -330px; +} + +.elfinder-dialog-icon-zipdl, +.elfinder-dialog-icon-archive, +.elfinder-dialog-icon-extract { + background-position: 0 -365px; +} + +.elfinder-dialog-icon-search { + background-position: 0 -402px; +} + +.elfinder-dialog-icon-resize, +.elfinder-dialog-icon-loadimg, +.elfinder-dialog-icon-netmount, +.elfinder-dialog-icon-netunmount, +.elfinder-dialog-icon-chmod, +.elfinder-dialog-icon-preupload, +.elfinder-dialog-icon-url, +.elfinder-dialog-icon-dim { + background-position: 0 -434px; +} + +/*********************** CONFIRM DIALOG **************************/ + +.elfinder-dialog-confirm-applyall, +.elfinder-dialog-confirm-encoding { + padding: 0 1em; + margin: 0; +} + +.elfinder-ltr .elfinder-dialog-confirm-applyall, +.elfinder-ltr .elfinder-dialog-confirm-encoding { + text-align: left; +} + +.elfinder-rtl .elfinder-dialog-confirm-applyall, +.elfinder-rtl .elfinder-dialog-confirm-encoding { + text-align: right; +} + +.elfinder-dialog-confirm .elfinder-dialog-icon { + background-position: 0 -32px; +} + +.elfinder-dialog-confirm .ui-dialog-buttonset { + width: auto; +} + +/*********************** FILE INFO DIALOG **************************/ + +.elfinder-info-title .elfinder-cwd-icon { + float: left; + width: 48px; + height: 48px; + margin-right: 1em; +} + +.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon { + float: right; + margin-right: 0; + margin-left: 1em; +} + +.elfinder-info-title strong { + display: block; + padding: .3em 0 .5em 0; +} + +.elfinder-info-tb { + min-width: 200px; + border: 0 solid; + margin: 1em .2em 1em .2em; + width: 100%; +} + +.elfinder-info-tb td { + white-space: pre-wrap; + padding: 2px; +} + +.elfinder-info-tb td.elfinder-info-label { + white-space: nowrap; +} + +.elfinder-info-tb td.elfinder-info-hash { + display: inline-block; + word-break: break-all; + max-width: 32ch; +} + +.elfinder-ltr .elfinder-info-tb tr td:first-child { + text-align: right; +} + +.elfinder-ltr .elfinder-info-tb span { + float: left; +} + +.elfinder-rtl .elfinder-info-tb tr td:first-child { + text-align: left; +} + +.elfinder-rtl .elfinder-info-tb span { + float: right; +} + +.elfinder-info-tb a { + outline: none; + text-decoration: underline; +} + +.elfinder-info-tb a:hover { + text-decoration: none; +} + +.elfinder-netmount-tb { + margin: 0 auto; +} + +.elfinder-netmount-tb select, +.elfinder-netmount-tb .elfinder-button-icon { + cursor: pointer; +} + +button.elfinder-info-button { + margin: -3.5px 0; + cursor: pointer; +} + +/*********************** UPLOAD DIALOG **************************/ + +.elfinder-upload-dropbox { + display: table-cell; + text-align: center; + vertical-align: middle; + padding: 0.5em; + border: 3px dashed #aaa; + width: 9999px; + height: 80px; + overflow: hidden; + word-break: keep-all; +} + +.elfinder-upload-dropbox.ui-state-hover { + background: #dfdfdf; + border: 3px dashed #555; +} + +.elfinder-upload-dialog-or { + margin: .3em 0; + text-align: center; +} + +.elfinder-upload-dialog-wrapper { + text-align: center; +} + +.elfinder-upload-dialog-wrapper .ui-button { + position: relative; + overflow: hidden; +} + +.elfinder-upload-dialog-wrapper .ui-button form { + position: absolute; + right: 0; + top: 0; + width: 100%; + opacity: 0; + filter: Alpha(Opacity=0); +} + +.elfinder-upload-dialog-wrapper .ui-button form input { + padding: 50px 0 0; + font-size: 3em; + width: 100%; +} + +/* dialog for elFinder itself */ +.dialogelfinder .dialogelfinder-drag { + border-left: 0 solid; + border-top: 0 solid; + border-right: 0 solid; + font-weight: normal; + padding: 2px 12px; + cursor: move; + position: relative; + text-align: left; +} + +.elfinder-rtl .dialogelfinder-drag { + text-align: right; +} + +.dialogelfinder-drag-close { + position: absolute; + top: 50%; + margin-top: -8px; +} + +.elfinder-ltr .dialogelfinder-drag-close { + right: 12px; +} + +.elfinder-rtl .dialogelfinder-drag-close { + left: 12px; +} + +/*********************** RM CONFIRM **************************/ +.elfinder-rm-title { + margin-bottom: .5ex; +} + +.elfinder-rm-title .elfinder-cwd-icon { + float: left; + width: 48px; + height: 48px; + margin-right: 1em; +} + +.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon { + float: right; + margin-right: 0; + margin-left: 1em; +} + +.elfinder-rm-title strong { + display: block; + /*word-wrap: break-word;*/ + white-space: pre-wrap; + word-break: normal; + overflow: hidden; + text-overflow: ellipsis; +} + +.elfinder-rm-title + br { + display: none; +} + +/* File: /css/fonts.css */ +.dialogelfinder .dialogelfinder-drag, +.elfinder-place-drag .elfinder-navbar-dir, +.elfinder-quicklook-preview-text-wrapper, +.elfinder-info-tb { + font-size: .9em; +} + +.std42-dialog .ui-dialog-titlebar { + font-size: .82em; +} + +.elfinder-button-search input { + font-size: .8em; +} + +.std42-dialog .ui-dialog-buttonpane, .elfinder-toast { + font-size: .76em; +} + +.elfinder-contextmenu .elfinder-contextmenu-item span, +.std42-dialog .ui-dialog-content, +.elfinder .elfinder-navbar, +.elfinder-quicklook-info-data, +.elfinder-button-menu-item { + font-size: .72em; +} + +.elfinder-cwd-view-icons .elfinder-cwd-filename, +.elfinder-cwd-view-list td, +.elfinder-quicklook-title, +.elfinder-statusbar div { + font-size: .7em; +} + +.elfinder-upload-dropbox, .elfinder-upload-dialog-or { + font-size: 1.2em; +} + +.elfinder-font-mono { + font-family: "Ricty Diminished", "Myrica M", Consolas, "Courier New", Courier, Monaco, monospace; + font-size: 1.1em; +} + +.elfinder-drag-num { + font-size: 12px; +} + +.elfinder-quicklook-title { + font-weight: normal; +} + +/* File: /css/navbar.css */ +/*********************************************/ +/* NAVIGATION PANEL */ +/*********************************************/ + +/* container */ +.elfinder .elfinder-navbar { + /*box-sizing: border-box;*/ + width: 230px; + padding: 3px 5px; + background-image: none; + border-top: 0 solid; + border-bottom: 0 solid; + overflow: auto; + position: relative; +} + +.elfinder .elfinder-navdock { + box-sizing: border-box; + width: 230px; + height: auto; + position: absolute; + bottom: 0; + overflow: auto; +} + +.elfinder-navdock .ui-resizable-n { + top: 0; + height: 20px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar { + float: left; + border-left: 0 solid; +} + +.elfinder-rtl .elfinder-navbar { + float: right; + border-right: 0 solid; +} + +.elfinder-ltr .ui-resizable-e { + margin-left: 10px; +} + +/* folders tree container */ +.elfinder-tree { + display: table; + width: 100%; + margin: 0 0 .5em 0; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +/* one folder wrapper */ +.elfinder-navbar-wrapper, .elfinder-place-wrapper { +} + +/* folder */ +.elfinder-navbar-dir { + position: relative; + display: block; + white-space: nowrap; + padding: 3px 12px; + margin: 0; + outline: 0px solid; + border: 1px solid transparent; + cursor: default; +} + +.elfinder-touch .elfinder-navbar-dir { + padding: 12px 12px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-dir { + padding-left: 35px; +} + +.elfinder-rtl .elfinder-navbar-dir { + padding-right: 35px; +} + +/* arrow before icon */ +.elfinder-navbar-arrow { + width: 12px; + height: 14px; + position: absolute; + display: none; + top: 50%; + margin-top: -8px; + background-image: url("../img/arrows-normal.png"); + background-repeat: no-repeat; + /* border:1px solid #111;*/ +} + +.elfinder-ltr .elfinder-navbar-arrow { + left: 0; +} + +.elfinder-rtl .elfinder-navbar-arrow { + right: 0; +} + +.elfinder-touch .elfinder-navbar-arrow { + -moz-transform-origin: top left; + -moz-transform: scale(1.4); + zoom: 1.4; + margin-bottom: 7px; +} + +.elfinder-ltr.elfinder-touch .elfinder-navbar-arrow { + left: -3px; + margin-right: 20px; +} + +.elfinder-rtl.elfinder-touch .elfinder-navbar-arrow { + right: -3px; + margin-left: 20px; +} + +.ui-state-active .elfinder-navbar-arrow { + background-image: url("../img/arrows-active.png"); +} + +/* collapsed/expanded arrow view */ +.elfinder-navbar-collapsed .elfinder-navbar-arrow { + display: block; +} + +.elfinder-subtree-chksubdir .elfinder-navbar-arrow { + opacity: .25; + filter: Alpha(Opacity=25); +} + +/* arrow ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-collapsed .elfinder-navbar-arrow { + background-position: 0 4px; +} + +.elfinder-rtl .elfinder-navbar-collapsed .elfinder-navbar-arrow { + background-position: 0 -10px; +} + +.elfinder-ltr .elfinder-navbar-expanded .elfinder-navbar-arrow, +.elfinder-rtl .elfinder-navbar-expanded .elfinder-navbar-arrow { + background-position: 0 -21px; +} + +/* folder icon */ +.elfinder-navbar-icon { + width: 16px; + height: 16px; + position: absolute; + top: 50%; + margin-top: -8px; + background-image: url("../img/toolbar.png"); + background-repeat: no-repeat; + background-position: 0 -16px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-icon { + left: 14px; +} + +.elfinder-rtl .elfinder-navbar-icon { + right: 14px; +} + +/* places icon */ +.elfinder-places .elfinder-navbar-root .elfinder-navbar-icon { + background-position: 0 -704px; +} + +/* root folder */ +.elfinder-tree .elfinder-navbar-root-local .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-trash .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-ftp .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-sql .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-dropbox .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-googledrive .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-onedrive .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-box .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-zip .elfinder-navbar-icon, +.elfinder-tree .elfinder-navbar-root-network .elfinder-navbar-icon { + background-position: 0 0; + background-size: contain; +} + +/* root icon of each volume "\9" for IE8 trick */ +.elfinder-tree .elfinder-navbar-root-local .elfinder-navbar-icon { + background-image: url("../img/volume_icon_local.svg"); + background-image: url("../img/volume_icon_local.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-trash .elfinder-navbar-icon { + background-image: url("../img/volume_icon_trash.svg"); + background-image: url("../img/volume_icon_trash.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-ftp .elfinder-navbar-icon { + background-image: url("../img/volume_icon_ftp.svg"); + background-image: url("../img/volume_icon_ftp.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-sql .elfinder-navbar-icon { + background-image: url("../img/volume_icon_sql.svg"); + background-image: url("../img/volume_icon_sql.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-dropbox .elfinder-navbar-icon { + background-image: url("../img/volume_icon_dropbox.svg"); + background-image: url("../img/volume_icon_dropbox.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-googledrive .elfinder-navbar-icon { + background-image: url("../img/volume_icon_googledrive.svg"); + background-image: url("../img/volume_icon_googledrive.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-onedrive .elfinder-navbar-icon { + background-image: url("../img/volume_icon_onedrive.svg"); + background-image: url("../img/volume_icon_onedrive.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-box .elfinder-navbar-icon { + background-image: url("../img/volume_icon_box.svg"); + background-image: url("../img/volume_icon_box.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-zip .elfinder-navbar-icon { + background-image: url("../img/volume_icon_zip.svg"); + background-image: url("../img/volume_icon_zip.png") \9; +} + +.elfinder-tree .elfinder-navbar-root-network .elfinder-navbar-icon { + background-image: url("../img/volume_icon_network.svg"); + background-image: url("../img/volume_icon_network.png") \9; +} + +/* icon in active/hove/dropactive state */ +.ui-state-active .elfinder-navbar-icon, +.elfinder-droppable-active .elfinder-navbar-icon, +.ui-state-hover .elfinder-navbar-icon { + background-position: 0 -32px; +} + +/* ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar-subtree { + margin-left: 12px; +} + +.elfinder-rtl .elfinder-navbar-subtree { + margin-right: 12px; +} + +/* spinner */ +.elfinder-tree .elfinder-spinner { + position: absolute; + top: 50%; + margin: -7px 0 0; +} + +/* spinner ltr/rtl enviroment */ +.elfinder-ltr .elfinder-tree .elfinder-spinner { + left: 0; + margin-left: -2px; +} + +.elfinder-rtl .elfinder-tree .elfinder-spinner { + right: 0; + margin-right: -2px; +} + +/* marker */ +.elfinder-navbar .elfinder-perms, +.elfinder-navbar .elfinder-lock, +.elfinder-navbar .elfinder-symlink { + opacity: .6; + filter: Alpha(Opacity=60); +} + +/* permissions marker */ +.elfinder-navbar .elfinder-perms { + bottom: -1px; + margin-top: -8px; +} + +/* locked marker */ +.elfinder-navbar .elfinder-lock { + top: -2px; +} + +/* permissions/symlink markers ltr/rtl enviroment */ +.elfinder-ltr .elfinder-navbar .elfinder-perms { + left: 20px; + transform: scale(0.8); +} + +.elfinder-rtl .elfinder-navbar .elfinder-perms { + right: 20px; + transform: scale(0.8); +} + +.elfinder-ltr .elfinder-navbar .elfinder-lock { + left: 20px; + transform: scale(0.8); +} + +.elfinder-rtl .elfinder-navbar .elfinder-lock { + right: 20px; + transform: scale(0.8); +} + +.elfinder-ltr .elfinder-navbar .elfinder-symlink { + left: 8px; + transform: scale(0.8); +} + +.elfinder-rtl .elfinder-navbar .elfinder-symlink { + right: 8px; + transform: scale(0.8); +} + +/* navbar input */ +.elfinder-navbar input { + width: 100%; + border: 0px solid; + margin: 0; + padding: 0; +} + +/* resizable */ +.elfinder-navbar .ui-resizable-handle { + width: 12px; + background: transparent url('../img/resize.png') center center no-repeat; +} + +.elfinder-nav-handle-icon { + position: absolute; + top: 50%; + margin: -8px 2px 0 2px; + opacity: .5; + filter: Alpha(Opacity=50); +} + +/* pager button */ +.elfinder-navbar-pager { + width: 100%; + box-sizing: border-box; + padding-top: 3px; + padding-bottom: 3px; +} + +.elfinder-touch .elfinder-navbar-pager { + padding-top: 10px; + padding-bottom: 10px; +} + +.elfinder-places { + border: none; + margin: 0; + padding: 0; +} + +.elfinder-places.elfinder-droppable-active { + /*border:1px solid #8cafed;*/ +} + +/* navbar swipe handle */ +.elfinder-navbar-swipe-handle { + position: absolute; + top: 0px; + height: 100%; + width: 50px; + pointer-events: none; +} + +.elfinder-ltr .elfinder-navbar-swipe-handle { + left: 0px; + background: linear-gradient(to right, + rgba(221, 228, 235, 1) 0, + rgba(221, 228, 235, 0.8) 5px, + rgba(216, 223, 230, 0.3) 8px, + rgba(0, 0, 0, 0.1) 95%, + rgba(0, 0, 0, 0) 100%); +} + +.elfinder-rtl .elfinder-navbar-swipe-handle { + right: 0px; + background: linear-gradient(to left, + rgba(221, 228, 235, 1) 0, + rgba(221, 228, 235, 0.8) 5px, + rgba(216, 223, 230, 0.3) 8px, + rgba(0, 0, 0, 0.1) 95%, + rgba(0, 0, 0, 0) 100%); +} + +/* File: /css/places.css */ +/*********************************************/ +/* PLACES STYLES */ +/*********************************************/ +/* root extra icon */ +.elfinder-navbar-root .elfinder-places-root-icon { + position: absolute; + top: 50%; + margin-top: -9px; + cursor: pointer; +} + +.elfinder-ltr .elfinder-places-root-icon { + right: 10px; +} + +.elfinder-rtl .elfinder-places-root-icon { + left: 10px; +} + +.elfinder-navbar-expanded .elfinder-places-root-icon { + display: block; +} + +/* dragging helper base */ +.elfinder-place-drag { + font-size: 0.8em; +} + +/* File: /css/quicklook.css */ +/* quicklook window */ +.elfinder-quicklook { + position: absolute; + background: url("../img/quicklook-bg.png"); + overflow: hidden; + -moz-border-radius: 7px; + -webkit-border-radius: 7px; + border-radius: 7px; + padding: 20px 0 40px 0; +} + +.elfinder-navdock .elfinder-quicklook { + -moz-border-radius: 0; + -webkit-border-radius: 0; + border-radius: 0; + font-size: 90%; + overflow: auto; +} + +.elfinder-quicklook.elfinder-touch { + padding: 30px 0 40px 0; +} + +.elfinder-quicklook .ui-resizable-se { + width: 14px; + height: 14px; + right: 5px; + bottom: 3px; + background: url("../img/toolbar.png") 0 -496px no-repeat; +} + +.elfinder-quicklook.elfinder-touch .ui-resizable-se { + -moz-transform-origin: bottom right; + -moz-transform: scale(1.5); + zoom: 1.5; +} + +/* quicklook fullscreen window */ +.elfinder-quicklook.elfinder-quicklook-fullscreen { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + margin: 0; + box-sizing: border-box; + width: 100%; + height: 100%; + object-fit: contain; + border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + -webkit-background-clip: padding-box; + padding: 0; + background: #000; + display: block; +} + +/* hide titlebar in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-titlebar, +.elfinder-quicklook-fullscreen.elfinder-quicklook .ui-resizable-handle { + display: none; +} + +/* hide preview border in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-preview { + border: 0 solid; +} + +/*.elfinder-quicklook-fullscreen iframe { + height: 100%; +}*/ + +.elfinder-quicklook-cover { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; +} + +.elfinder-quicklook-cover.elfinder-quicklook-coverbg { + /* background need to catch mouse event over browser plugin (eg PDF preview) */ + background-color: #fff; + opacity: 0.000001; + filter: Alpha(Opacity=0.0001); +} + +/* quicklook titlebar */ +.elfinder-quicklook-titlebar { + text-align: center; + background: #777; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 20px; + -moz-border-radius-topleft: 7px; + -webkit-border-top-left-radius: 7px; + border-top-left-radius: 7px; + -moz-border-radius-topright: 7px; + -webkit-border-top-right-radius: 7px; + border-top-right-radius: 7px; + border: none; + line-height: 1.2; +} + +.elfinder-navdock .elfinder-quicklook-titlebar { + -moz-border-radius-topleft: 0; + -webkit-border-top-left-radius: 0; + border-top-left-radius: 0; + -moz-border-radius-topright: 0; + -webkit-border-top-right-radius: 0; + border-top-right-radius: 0; + cursor: default; +} + +.elfinder-touch .elfinder-quicklook-titlebar { + height: 30px; +} + +/* window title */ +.elfinder-quicklook-title { + display: inline-block; + white-space: nowrap; + overflow: hidden; +} + +.elfinder-touch .elfinder-quicklook-title { + padding: 8px 0; +} + +/* icon "close" in titlebar */ +.elfinder-quicklook-titlebar-icon { + position: absolute; + left: 4px; + top: 50%; + margin-top: -8px; + height: 16px; + border: none; +} +.elfinder-touch .elfinder-quicklook-titlebar-icon { + height: 22px; +} + +.elfinder-quicklook-titlebar-icon .ui-icon { + position: relative; + margin: -9px 3px 0px 0px; + cursor: pointer; + border-radius: 10px; + border: 1px solid; + opacity: .7; + filter: Alpha(Opacity=70); +} + +.elfinder-quicklook-titlebar-icon .ui-icon.ui-icon-closethick { + padding-left: 1px; +} + +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon { + opacity: .6; + filter: Alpha(Opacity=60); +} + +.elfinder-touch .elfinder-quicklook-titlebar-icon .ui-icon { + margin-top: -5px; +} + +.elfinder-quicklook-titlebar-icon.elfinder-titlebar-button-right { + left: auto; + right: 4px; + direction: rtl; +} + +.elfinder-quicklook-titlebar-icon.elfinder-titlebar-button-right .ui-icon { + margin: -9px 0px 0px 3px; +} + +.elfinder-touch .elfinder-quicklook-titlebar .ui-icon { + -moz-transform-origin: center center; + -moz-transform: scale(1.2); + zoom: 1.2; +} + +.elfinder-touch .elfinder-quicklook-titlebar-icon .ui-icon { + margin-right: 10px; +} + +.elfinder-touch .elfinder-quicklook-titlebar-icon.elfinder-titlebar-button-right .ui-icon { + margin-left: 10px; +} + +/* main part of quicklook window */ +.elfinder-quicklook-preview { + overflow: hidden; + position: relative; + border: 0 solid; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + height: 100%; +} + +.elfinder-navdock .elfinder-quicklook-preview { + border-left: 0; + border-right: 0; +} + +.elfinder-quicklook-preview.elfinder-overflow-auto { + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +/* wrapper for file info/icon */ +.elfinder-quicklook-info-wrapper { + display: table; + position: absolute; + width: 100%; + height: 100%; + height: calc(100% - 80px); + left: 0; + top: 20px; +} + +.elfinder-navdock .elfinder-quicklook-info-wrapper { + height: calc(100% - 20px); +} + +/* file info */ +.elfinder-quicklook-info { + display: table-cell; + vertical-align: middle; +} + +.elfinder-ltr .elfinder-quicklook-info { + padding: 0 12px 0 112px; +} + +.elfinder-rtl .elfinder-quicklook-info { + padding: 0 112px 0 12px; +} + +.elfinder-ltr .elfinder-navdock .elfinder-quicklook-info { + padding: 0 0 0 80px; +} + +.elfinder-rtl .elfinder-navdock .elfinder-quicklook-info { + padding: 0 80px 0 0; +} + +/* file name in info */ +.elfinder-quicklook-info .elfinder-quicklook-info-data:first-child { + color: #fff; + font-weight: bold; + padding-bottom: .5em; +} + +/* other data in info */ +.elfinder-quicklook-info-data { + clear: both; + padding-bottom: .2em; + color: #fff; +} + +.elfinder-quicklook-info-progress { + width: 0; + height: 4px; + border-radius: 2px; +} + +/* file icon */ +.elfinder-quicklook .elfinder-cwd-icon { + position: absolute; + left: 32px; + top: 50%; + margin-top: -20px; +} + +.elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon { + left: 16px; +} + +.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon { + left: auto; + right: 32px; +} + +.elfinder-rtl .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon { + right: 6px; +} + +.elfinder-quicklook .elfinder-cwd-icon:before { + top: -10px; +} + +.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:before { + left: -20px; +} + +.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:before { + left: -14px; +} + +.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:after { + left: -42px; +} + +.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:after { + left: -12px; +} + +.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:before { + left: auto; + right: 40px; +} + +.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:after { + left: auto; + right: 42px; +} + +/* image in preview */ +.elfinder-quicklook-preview > img, +.elfinder-quicklook-preview > div > canvas { + display: block; + margin: auto; +} + +/* navigation bar on quicklook window bottom */ +.elfinder-quicklook-navbar { + position: absolute; + left: 50%; + bottom: 4px; + width: 140px; + height: 32px; + padding: 0px; + margin-left: -70px; + border: 1px solid transparent; + border-radius: 19px; + -moz-border-radius: 19px; + -webkit-border-radius: 19px; +} + +/* navigation bar in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar { + width: 188px; + margin-left: -94px; + padding: 5px; + border: 1px solid #eee; + background: #000; + opacity: 0.4; + filter: Alpha(Opacity=40); +} + +/* show close icon in fullscreen mode */ +.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-icon-close, +.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-separator { + display: inline; +} + +/* icons in navbar */ +.elfinder-quicklook-navbar-icon { + width: 32px; + height: 32px; + margin: 0 7px; + float: left; + background: url("../img/quicklook-icons.png") 0 0 no-repeat; + +} + +/* fullscreen icon */ +.elfinder-quicklook-navbar-icon-fullscreen { + background-position: 0 -64px; +} + +/* exit fullscreen icon */ +.elfinder-quicklook-navbar-icon-fullscreen-off { + background-position: 0 -96px; +} + +/* prev file icon */ +.elfinder-quicklook-navbar-icon-prev { + background-position: 0 0; +} + +/* next file icon */ +.elfinder-quicklook-navbar-icon-next { + background-position: 0 -32px; +} + +/* close icon */ +.elfinder-quicklook-navbar-icon-close { + background-position: 0 -128px; + display: none; +} + +/* icons separator */ +.elfinder-quicklook-navbar-separator { + width: 1px; + height: 32px; + float: left; + border-left: 1px solid #fff; + display: none; +} + +/* text encoding selector */ +.elfinder-quicklook-encoding { + height: 40px; +} +.elfinder-quicklook-encoding > select { + color: #fff; + background: #000; + border: 0; + font-size: 12px; + max-width: 100px; + display: inline-block; + position: relative; + top: 6px; + left: 5px; +} +.elfinder-navdock .elfinder-quicklook .elfinder-quicklook-encoding { + display: none; +} + + +/* text files preview wrapper */ +.elfinder-quicklook-preview-text-wrapper { + width: 100%; + height: 100%; + background: #fff; + color: #222; + overflow: auto; + -webkit-overflow-scrolling: touch; +} + +/* archive files preview wrapper */ +.elfinder-quicklook-preview-archive-wrapper { + width: 100%; + height: 100%; + background: #fff; + color: #222; + font-size: 90%; + overflow: auto; + -webkit-overflow-scrolling: touch +} + +/* archive files preview header */ +.elfinder-quicklook-preview-archive-wrapper strong { + padding: 0 5px; +} + +/* text preview */ +pre.elfinder-quicklook-preview-text, +pre.elfinder-quicklook-preview-text.prettyprint { + width: auto; + height: auto; + margin: 0; + padding: 3px 9px; + border: none; + overflow: visible; + -o-tab-size: 4; + -moz-tab-size: 4; + tab-size: 4; +} + +.elfinder-quicklook-preview-charsleft hr { + border: none; + border-top: dashed 1px; +} + +.elfinder-quicklook-preview-charsleft span { + font-size: 90%; + font-style: italic; + cursor: pointer; +} + +/* html/pdf preview */ +.elfinder-quicklook-preview-html, +.elfinder-quicklook-preview-pdf, +.elfinder-quicklook-preview-iframe { + width: 100%; + height: 100%; + background: #fff; + margin: 0; + border: none; + display: block; +} + +/* swf preview container */ +.elfinder-quicklook-preview-flash { + width: 100%; + height: 100%; +} + +/* audio preview container */ +.elfinder-quicklook-preview-audio { + width: 100%; + position: absolute; + bottom: 0; + left: 0; +} + +/* audio preview using embed */ +embed.elfinder-quicklook-preview-audio { + height: 30px; + background: transparent; +} + +/* video preview container */ +.elfinder-quicklook-preview-video { + width: 100%; + height: 100%; +} + +/* video.js error message */ +.elfinder-quicklook-preview .vjs-error .vjs-error-display .vjs-modal-dialog-content { + font-size: 12pt; + padding: 0; + color: #fff; +} + +/* allow user select */ +.elfinder .elfinder-quicklook .elfinder-quicklook-info *, +.elfinder .elfinder-quicklook .elfinder-quicklook-preview * { + -webkit-user-select: auto; + -moz-user-select: text; + -khtml-user-select: text; + user-select: text; +} + +/* File: /css/statusbar.css */ +/******************************************************************/ +/* STATUSBAR STYLES */ +/******************************************************************/ + +/* statusbar container */ +.elfinder-statusbar { + display: flex; + justify-content: space-between; + cursor: default; + text-align: center; + font-weight: normal; + padding: .2em .5em; + border-right: 0 solid transparent; + border-bottom: 0 solid transparent; + border-left: 0 solid transparent; +} + +.elfinder-statusbar:before, +.elfinder-statusbar:after { + display: none; +} + +.elfinder-statusbar span { + vertical-align: bottom; + overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; +} + +.elfinder-statusbar span.elfinder-path-other { + flex-shrink: 0; + text-overflow: clip; + -o-text-overflow: clip; +} + +.elfinder-statusbar span.ui-state-hover, +.elfinder-statusbar span.ui-state-active { + border: none; +} + +.elfinder-statusbar span.elfinder-path-cwd { + cursor: default; +} + +/* path in statusbar */ +.elfinder-path { + display: flex; + order: 1; + flex-grow: 1; + cursor: pointer; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + -o-text-overflow: ellipsis; + max-width: 30%\9; +} + +.elfinder-ltr .elfinder-path { + text-align: left; + float: left\9; +} + +.elfinder-rtl .elfinder-path { + text-align: right; + float: right\9; +} + +/* path in workzone (case of swipe to navbar close) */ +.elfinder-workzone-path { + position: relative; +} + +.elfinder-workzone-path .elfinder-path { + position: relative; + font-size: .75em; + font-weight: normal; + float: none; + max-width: none; + overflow: hidden; + overflow-x: hidden; + text-overflow: initial; + -o-text-overflow: initial; +} + +.elfinder-mobile .elfinder-workzone-path .elfinder-path { + overflow: auto; + overflow-x: scroll; +} + +.elfinder-ltr .elfinder-workzone-path .elfinder-path { + margin-left: 24px; +} + +.elfinder-rtl .elfinder-workzone-path .elfinder-path { + margin-right: 24px; +} + +.elfinder-workzone-path .elfinder-path span { + display: inline-block; + padding: 5px 3px; +} + +.elfinder-workzone-path .elfinder-path span.elfinder-path-cwd { + font-weight: bold; +} + +.elfinder-workzone-path .elfinder-path span.ui-state-hover, +.elfinder-workzone-path .elfinder-path span.ui-state-active { + border: none; +} + +.elfinder-workzone-path .elfinder-path-roots { + position: absolute; + top: 0; + width: 24px; + height: 20px; + padding: 2px; + border: none; + overflow: hidden; +} + +.elfinder-ltr .elfinder-workzone-path .elfinder-path-roots { + left: 0; +} + +.elfinder-rtl .elfinder-workzone-path .elfinder-path-roots { + right: 0; +} + +/* total/selected size in statusbar */ +.elfinder-stat-size { + order: 3; + flex-grow: 1; + overflow: hidden; + white-space: nowrap; +} + +.elfinder-ltr .elfinder-stat-size { + text-align: right; + float: right\9; +} + +.elfinder-rtl .elfinder-stat-size { + text-align: left; + float: left\9; +} + +/* info of current selected item */ +.elfinder-stat-selected { + order: 2; + margin: 0 .5em; + white-space: nowrap; + overflow: hidden; +} + +/* File: /css/toast.css */ +/* + * CSS for Toastr + * Copyright 2012-2015 + * Authors: John Papa, Hans Fjällemark, and Tim Ferrell. + * All Rights Reserved. + * Use, reproduction, distribution, and modification of this code is subject to the terms and + * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php + * + * ARIA Support: Greta Krafsig + * + * Project: https://github.com/CodeSeven/toastr + */ + +.elfinder .elfinder-toast { + position: absolute; + top: 12px; + right: 12px; + max-width: 90%; + cursor: default; +} + +.elfinder .elfinder-toast > div { + position: relative; + pointer-events: auto; + overflow: hidden; + margin: 0 0 6px; + padding: 8px 16px 8px 50px; + -moz-border-radius: 3px 3px 3px 3px; + -webkit-border-radius: 3px 3px 3px 3px; + border-radius: 3px 3px 3px 3px; + background-position: 15px center; + background-repeat: no-repeat; + -moz-box-shadow: 0 0 12px #999999; + -webkit-box-shadow: 0 0 12px #999999; + box-shadow: 0 0 12px #999999; + color: #FFFFFF; + opacity: 0.9; + filter: alpha(opacity=90); + background-color: #030303; + text-align: center; +} + +.elfinder .elfinder-toast > .toast-info { + background-color: #2F96B4; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important; +} + +.elfinder .elfinder-toast > .toast-error { + background-color: #BD362F; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important; +} + +.elfinder .elfinder-toast > .toast-success { + background-color: #51A351; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important; +} + +.elfinder .elfinder-toast > .toast-warning { + background-color: #F89406; + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important; +} + +.elfinder .elfinder-toast > div button.ui-button { + background-image: none; + margin-top: 8px; + padding: .5em .8em; +} + +.elfinder .elfinder-toast > .toast-success button.ui-button { + background-color: green; + color: #FFF; +} + +.elfinder .elfinder-toast > .toast-success button.ui-button.ui-state-hover { + background-color: #add6ad; + color: #254b25; +} + +.elfinder .elfinder-toast > .toast-info button.ui-button { + background-color: #046580; + color: #FFF; +} + +.elfinder .elfinder-toast > .toast-info button.ui-button.ui-state-hover { + background-color: #7DC6DB; + color: #046580; +} + +.elfinder .elfinder-toast > .toast-warning button.ui-button { + background-color: #dd8c1a; + color: #FFF; +} + +.elfinder .elfinder-toast > .toast-warning button.ui-button.ui-state-hover { + background-color: #e7ae5e; + color: #422a07; +} + +/* File: /css/toolbar.css */ +/*********************************************/ +/* TOOLBAR STYLES */ +/*********************************************/ +/* toolbar container */ +.elfinder-toolbar { + padding: 4px 0 3px 0; + border-left: 0 solid transparent; + border-top: 0 solid transparent; + border-right: 0 solid transparent; + max-height: 50%; + overflow-y: auto; +} + +/* container for button's group */ +.elfinder-buttonset { + margin: 1px 4px; + float: left; + background: transparent; + padding: 0; + overflow: hidden; +} + +/*.elfinder-buttonset:first-child { margin:0; }*/ + +/* button */ +.elfinder .elfinder-button { + min-width: 16px; + height: 16px; + margin: 0; + padding: 4px; + float: left; + overflow: hidden; + position: relative; + border: 0 solid; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + line-height: 1; + cursor: default; +} + +.elfinder-rtl .elfinder-button { + float: right; +} + +.elfinder-touch .elfinder-button { + min-width: 20px; + height: 20px; +} + +.elfinder .ui-icon-search { + cursor: pointer; +} + +/* separator between buttons, required for berder between button with ui color */ +.elfinder-toolbar-button-separator { + float: left; + padding: 0; + height: 24px; + border-top: 0 solid; + border-right: 0 solid; + border-bottom: 0 solid; + width: 0; +} + +.elfinder-rtl .elfinder-toolbar-button-separator { + float: right; +} + +.elfinder-touch .elfinder-toolbar-button-separator { + height: 28px; +} + +/* change icon opacity^ not button */ +.elfinder .elfinder-button.ui-state-disabled { + opacity: 1; + filter: Alpha(Opacity=100); +} + +.elfinder .elfinder-button.ui-state-disabled .elfinder-button-icon, +.elfinder .elfinder-button.ui-state-disabled .elfinder-button-text { + opacity: .4; + filter: Alpha(Opacity=40); +} + +/* rtl enviroment */ +.elfinder-rtl .elfinder-buttonset { + float: right; +} + +/* icon inside button */ +.elfinder-button-icon { + width: 16px; + height: 16px; + /*display:block;*/ + display: inline-block; + background: url('../img/toolbar.png') no-repeat; +} + +.elfinder-button-text { + position: relative; + display: inline-block; + top: -4px; + margin: 0 2px; + font-size: 12px; +} + +.elfinder-touch .elfinder-button-icon { + transform: scale(1.25); + transform-origin: top left; +} + +.elfinder-rtl.elfinder-touch .elfinder-button-icon { + transform-origin: top right; +} + +.elfinder-touch .elfinder-button-text { + transform: translate(3px, 3px); + top: -5px; +} + +.elfinder-rtl.elfinder-touch .elfinder-button-text { + transform: translate(-3px, 3px); +} + +.elfinder-touch .elfinder-button-icon.elfinder-contextmenu-extra-icon { + transform: scale(2); + transform-origin: 12px 8px; +} + +.elfinder-rtl.elfinder-touch .elfinder-button-icon.elfinder-contextmenu-extra-icon { + transform-origin: 4px 8px; +} + +/* buttons icons */ +.elfinder-button-icon-home { + background-position: 0 0; +} + +.elfinder-button-icon-back { + background-position: 0 -112px; +} + +.elfinder-button-icon-forward { + background-position: 0 -128px; +} + +.elfinder-button-icon-up { + background-position: 0 -144px; +} + +.elfinder-button-icon-dir { + background-position: 0 -16px; +} + +.elfinder-button-icon-opendir { + background-position: 0 -32px; +} + +.elfinder-button-icon-reload { + background-position: 0 -160px; +} + +.elfinder-button-icon-open { + background-position: 0 -176px; +} + +.elfinder-button-icon-mkdir { + background-position: 0 -192px; +} + +.elfinder-button-icon-mkfile { + background-position: 0 -208px; +} + +.elfinder-button-icon-rm { + background-position: 0 -832px; +} + +.elfinder-button-icon-trash { + background-position: 0 -224px; +} + +.elfinder-button-icon-restore { + background-position: 0 -816px; +} + +.elfinder-button-icon-copy { + background-position: 0 -240px; +} + +.elfinder-button-icon-cut { + background-position: 0 -256px; +} + +.elfinder-button-icon-paste { + background-position: 0 -272px; +} + +.elfinder-button-icon-getfile { + background-position: 0 -288px; +} + +.elfinder-button-icon-duplicate { + background-position: 0 -304px; +} + +.elfinder-button-icon-rename { + background-position: 0 -320px; +} + +.elfinder-button-icon-edit { + background-position: 0 -336px; +} + +.elfinder-button-icon-quicklook { + background-position: 0 -352px; +} + +.elfinder-button-icon-upload { + background-position: 0 -368px; +} + +.elfinder-button-icon-download { + background-position: 0 -384px; +} + +.elfinder-button-icon-info { + background-position: 0 -400px; +} + +.elfinder-button-icon-extract { + background-position: 0 -416px; +} + +.elfinder-button-icon-archive { + background-position: 0 -432px; +} + +.elfinder-button-icon-view { + background-position: 0 -448px; +} + +.elfinder-button-icon-view-list { + background-position: 0 -464px; +} + +.elfinder-button-icon-help { + background-position: 0 -480px; +} + +.elfinder-button-icon-resize { + background-position: 0 -512px; +} + +.elfinder-button-icon-link { + background-position: 0 -528px; +} + +.elfinder-button-icon-search { + background-position: 0 -561px; +} + +.elfinder-button-icon-sort { + background-position: 0 -577px; +} + +.elfinder-button-icon-rotate-r { + background-position: 0 -625px; +} + +.elfinder-button-icon-rotate-l { + background-position: 0 -641px; +} + +.elfinder-button-icon-netmount { + background-position: 0 -688px; +} + +.elfinder-button-icon-netunmount { + background-position: 0 -96px; +} + +.elfinder-button-icon-places { + background-position: 0 -704px; +} + +.elfinder-button-icon-chmod { + background-position: 0 -48px; +} + +.elfinder-button-icon-accept { + background-position: 0 -736px; +} + +.elfinder-button-icon-menu { + background-position: 0 -752px; +} + +.elfinder-button-icon-colwidth { + background-position: 0 -768px; +} + +.elfinder-button-icon-fullscreen { + background-position: 0 -784px; +} + +.elfinder-button-icon-unfullscreen { + background-position: 0 -800px; +} + +.elfinder-button-icon-empty { + background-position: 0 -848px; +} + +.elfinder-button-icon-undo { + background-position: 0 -864px; +} + +.elfinder-button-icon-redo { + background-position: 0 -880px; +} + +.elfinder-button-icon-preference { + background-position: 0 -896px; +} + +.elfinder-button-icon-mkdirin { + background-position: 0 -912px; +} + +.elfinder-button-icon-selectall { + background-position: 0 -928px; +} + +.elfinder-button-icon-selectnone { + background-position: 0 -944px; +} + +.elfinder-button-icon-selectinvert { + background-position: 0 -960px; +} + +.elfinder-button-icon-opennew { + background-position: 0 -976px; +} + +.elfinder-button-icon-hide { + background-position: 0 -992px; +} + +.elfinder-button-icon-text { + background-position: 0 -1008px; +} + +/* button icon mirroring for rtl */ +.elfinder-rtl .elfinder-button-icon-back, +.elfinder-rtl .elfinder-button-icon-forward, +.elfinder-rtl .elfinder-button-icon-getfile, +.elfinder-rtl .elfinder-button-icon-help, +.elfinder-rtl .elfinder-button-icon-redo, +.elfinder-rtl .elfinder-button-icon-rename, +.elfinder-rtl .elfinder-button-icon-search, +.elfinder-rtl .elfinder-button-icon-undo, +.elfinder-rtl .elfinder-button-icon-view-list, +.elfinder-rtl .ui-icon-search { + -ms-transform: scale(-1, 1); + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); +} + +.elfinder-rtl.elfinder-touch .elfinder-button-icon-back, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-forward, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-getfile, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-help, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-redo, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-rename, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-search, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-undo, +.elfinder-rtl.elfinder-touch .elfinder-button-icon-view-list, +.elfinder-rtl.elfinder-touch .ui-icon-search { + -ms-transform: scale(-1.25, 1.25) translateX(16px); + -webkit-transform: scale(-1.25, 1.25) translateX(16px); + transform: scale(-1.25, 1.25) translateX(16px); +} + +/* button with dropdown menu*/ +.elfinder .elfinder-menubutton { + overflow: visible; +} + +/* button with spinner icon */ +.elfinder-button-icon-spinner { + background: url("../img/spinner-mini.gif") center center no-repeat; +} + +/* menu */ +.elfinder-button-menu { + position: absolute; + margin-top: 24px; + padding: 3px 0; + overflow-y: auto; +} + +.elfinder-touch .elfinder-button-menu { + margin-top: 30px; +} + +/* menu item */ +.elfinder-button-menu-item { + white-space: nowrap; + cursor: default; + padding: 5px 19px; + position: relative; +} + +.elfinder-touch .elfinder-button-menu-item { + padding: 12px 19px +} + +/* fix hover ui class */ +.elfinder-button-menu .ui-state-hover { + border: 0 solid; +} + +.elfinder-button-menu-item-separated { + border-top: 1px solid #ccc; +} + +.elfinder-button-menu-item .ui-icon { + width: 16px; + height: 16px; + position: absolute; + left: 2px; + top: 50%; + margin-top: -8px; + display: none; +} + +.elfinder-button-menu-item-selected .ui-icon { + display: block; +} + +.elfinder-button-menu-item-selected-asc .ui-icon-arrowthick-1-s { + display: none; +} + +.elfinder-button-menu-item-selected-desc .ui-icon-arrowthick-1-n { + display: none; +} + +/* hack for upload button */ +.elfinder-button form { + position: absolute; + top: 0; + right: 0; + opacity: 0; + filter: Alpha(Opacity=0); + cursor: pointer; +} + +.elfinder .elfinder-button form input { + background: transparent; + cursor: default; +} + +/* search "button" */ +.elfinder .elfinder-button-search { + border: 0 solid; + background: transparent; + padding: 0; + margin: 1px 4px; + height: auto; + min-height: 26px; + width: 70px; + overflow: visible; +} + +.elfinder .elfinder-button-search.ui-state-active { + width: 220px; +} + +/* search "pull down menu" */ +.elfinder .elfinder-button-search-menu { + font-size: 8pt; + text-align: center; + width: auto; + min-width: 180px; + position: absolute; + top: 30px; + padding-right: 5px; + padding-left: 5px; +} + +.elfinder-ltr .elfinder-button-search-menu { + right: 22px; + left: auto; +} + +.elfinder-rtl .elfinder-button-search-menu { + right: auto; + left: 22px; +} + +.elfinder-touch .elfinder-button-search-menu { + top: 34px; +} + +.elfinder .elfinder-button-search-menu div { + margin-left: auto; + margin-right: auto; + margin-top: 5px; + margin-bottom: 5px; + display: table; +} + +.elfinder .elfinder-button-search-menu div .ui-state-hover { + border: 1px solid; +} + +/* ltr/rte enviroment */ +.elfinder-ltr .elfinder-button-search { + float: right; + margin-right: 10px; +} + +.elfinder-rtl .elfinder-button-search { + float: left; + margin-left: 10px; +} + +.elfinder-rtl .ui-controlgroup > .ui-controlgroup-item { + float: right; +} + +/* search text field */ +.elfinder-button-search input[type=text] { + box-sizing: border-box; + width: 100%; + height: 26px; + padding: 0 20px; + line-height: 22px; + border: 0 solid; + border: 1px solid #aaa; + -moz-border-radius: 12px; + -webkit-border-radius: 12px; + border-radius: 12px; + outline: 0px solid; +} + +.elfinder-button-search input::-ms-clear { + display: none; +} + +.elfinder-touch .elfinder-button-search input { + height: 30px; + line-height: 28px; +} + +.elfinder-rtl .elfinder-button-search input { + direction: rtl; +} + +/* icons */ +.elfinder-button-search .ui-icon { + position: absolute; + height: 18px; + top: 50%; + margin: -8px 4px 0 4px; + opacity: .6; + filter: Alpha(Opacity=60); +} + +.elfinder-button-search-menu .ui-checkboxradio-icon { + display: none; +} + +/* search/close icons */ +.elfinder-ltr .elfinder-button-search .ui-icon-search { + left: 0; +} + +.elfinder-rtl .elfinder-button-search .ui-icon-search { + right: 0; +} + +.elfinder-ltr .elfinder-button-search .ui-icon-close { + right: 0; +} + +.elfinder-rtl .elfinder-button-search .ui-icon-close { + left: 0; +} + +/* toolbar swipe handle */ +.elfinder-toolbar-swipe-handle { + position: absolute; + top: 0px; + left: 0px; + height: 50px; + width: 100%; + pointer-events: none; + background: linear-gradient(to bottom, + rgba(221, 228, 235, 1) 0, + rgba(221, 228, 235, 0.8) 2px, + rgba(216, 223, 230, 0.3) 5px, + rgba(0, 0, 0, 0.1) 95%, + rgba(0, 0, 0, 0) 100%); +} + diff --git a/lib/redactor/elfinder/css/elfinder.min.css b/lib/redactor/elfinder/css/elfinder.min.css new file mode 100644 index 0000000..da43235 --- /dev/null +++ b/lib/redactor/elfinder/css/elfinder.min.css @@ -0,0 +1,9 @@ +/*! + * elFinder - file manager for web + * Version 2.1.66 (2025-08-28) + * http://elfinder.org + * + * Copyright 2009-2025, Studio 42 + * Licensed under a 3-clauses BSD license + */ +.elfinder-resize-container{margin-top:.3em}.elfinder-resize-type{float:left;margin-bottom:.4em}.elfinder-resize-control{float:left}.elfinder-resize-control input[type=number]{border:1px solid #aaa;text-align:right;width:4.5em}.elfinder-resize-control input.elfinder-resize-bg{text-align:center;width:5em;direction:ltr}.elfinder-dialog-resize .elfinder-resize-control-panel{margin-top:10px}.elfinder-dialog-resize .elfinder-resize-imgrotate,.elfinder-dialog-resize .elfinder-resize-pallet{cursor:pointer}.elfinder-dialog-resize .elfinder-resize-picking{cursor:crosshair}.elfinder-dialog-resize .elfinder-resize-grid8+button{padding-top:2px;padding-bottom:2px}.elfinder-resize-preview{width:400px;height:400px;padding:10px;background:#fff;border:1px solid #aaa;float:right;position:relative;overflow:hidden;text-align:left;direction:ltr}.elfinder-resize-handle,div.elfinder-cwd-wrapper-list tr.ui-state-default td{position:relative}.elfinder-resize-handle-hline,.elfinder-resize-handle-vline{position:absolute;background-image:url(../img/crop.gif)}.elfinder-resize-handle-hline{width:100%;height:1px!important;background-repeat:repeat-x}.elfinder-resize-handle-vline{width:1px!important;height:100%;background-repeat:repeat-y}.elfinder-resize-handle-hline-top{top:0;left:0}.elfinder-resize-handle-hline-bottom{bottom:0;left:0}.elfinder-resize-handle-vline-left{top:0;left:0}.elfinder-resize-handle-vline-right{top:0;right:0}.elfinder-resize-handle-point{position:absolute;width:8px;height:8px;border:1px solid #777;background:0 0}.elfinder-resize-handle-point-n{top:0;left:50%;margin-top:-5px;margin-left:-5px}.elfinder-resize-handle-point-e,.elfinder-resize-handle-point-ne{top:0;right:0;margin-top:-5px;margin-right:-5px}.elfinder-resize-handle-point-e{top:50%}.elfinder-resize-handle-point-se{bottom:0;right:0;margin-bottom:-5px;margin-right:-5px}.elfinder-resize-handle-point-s,.elfinder-resize-handle-point-sw{bottom:0;left:50%;margin-bottom:-5px;margin-left:-5px}.elfinder-resize-handle-point-sw{left:0}.elfinder-resize-handle-point-nw,.elfinder-resize-handle-point-w{top:50%;left:0;margin-top:-5px;margin-left:-5px}.elfinder-resize-handle-point-nw{top:0}.elfinder-dialog.elfinder-dialog-resize .ui-resizable-e{width:10px;height:100%}.elfinder-dialog.elfinder-dialog-resize .ui-resizable-s{width:100%;height:10px}.elfinder-resize-loading{position:absolute;width:200px;height:30px;top:50%;margin-top:-25px;left:50%;margin-left:-100px;text-align:center;background:url(../img/progress.gif) center bottom repeat-x}.elfinder-resize-row{margin-bottom:9px;position:relative}.elfinder-resize-label{float:left;width:80px;padding-top:3px}.elfinder-resize-checkbox-label{border:1px solid transparent}.elfinder-dialog-resize .elfinder-resize-whctrls{margin:-20px 5px 0}.elfinder-ltr .elfinder-dialog-resize .elfinder-resize-whctrls{float:right}.elfinder-help-team div,.elfinder-rtl .elfinder-dialog-resize .elfinder-resize-whctrls{float:left}.elfinder-dialog-resize .ui-resizable-e,.elfinder-dialog-resize .ui-resizable-w{height:100%;width:10px}.elfinder-dialog-resize .ui-resizable-n,.elfinder-dialog-resize .ui-resizable-s{width:100%;height:10px}.elfinder-dialog-resize .ui-resizable-e{margin-right:-7px}.elfinder-dialog-resize .ui-resizable-w{margin-left:-7px}.elfinder-dialog-resize .ui-resizable-s{margin-bottom:-7px}.elfinder-dialog-resize .ui-resizable-n{margin-top:-7px}.elfinder-dialog-resize .ui-resizable-ne,.elfinder-dialog-resize .ui-resizable-nw,.elfinder-dialog-resize .ui-resizable-se,.elfinder-dialog-resize .ui-resizable-sw{width:10px;height:10px}.elfinder-dialog-resize .ui-resizable-se{background:0 0;bottom:0;right:0;margin-right:-7px;margin-bottom:-7px}.elfinder-dialog-resize .ui-resizable-sw{margin-left:-7px;margin-bottom:-7px}.elfinder-dialog-resize .ui-resizable-ne{margin-right:-7px;margin-top:-7px}.elfinder-dialog-resize .ui-resizable-nw{margin-left:-7px;margin-top:-7px}.elfinder-touch .elfinder-dialog-resize .ui-resizable-n,.elfinder-touch .elfinder-dialog-resize .ui-resizable-s{height:20px}.elfinder-touch .elfinder-dialog-resize .ui-resizable-e,.elfinder-touch .elfinder-dialog-resize .ui-resizable-w{width:20px}.elfinder-touch .elfinder-dialog-resize .ui-resizable-ne,.elfinder-touch .elfinder-dialog-resize .ui-resizable-nw,.elfinder-touch .elfinder-dialog-resize .ui-resizable-se,.elfinder-touch .elfinder-dialog-resize .ui-resizable-sw{width:30px;height:30px}.elfinder-touch .elfinder-dialog-resize .elfinder-resize-preview .ui-resizable-se{width:30px;height:30px;margin:0}.elfinder-dialog-resize .ui-icon-grip-solid-vertical{position:absolute;top:50%;right:0;margin-top:-8px;margin-right:-11px}.elfinder-dialog-resize .ui-icon-grip-solid-horizontal{position:absolute;left:50%;bottom:0;margin-left:-8px;margin-bottom:-11px}.elfinder-dialog-resize .elfinder-resize-row .ui-buttonset{float:right}.elfinder-dialog-resize .elfinder-resize-degree input,.elfinder-dialog-resize input.elfinder-resize-quality,.elfinder-mobile .elfinder-resize-control input[type=number]{width:3.5em}.elfinder-mobile .elfinder-dialog-resize .elfinder-resize-degree input,.elfinder-mobile .elfinder-dialog-resize input.elfinder-resize-quality{width:2.5em}.elfinder-dialog-resize .elfinder-resize-degree button.ui-button{padding:6px 8px}.elfinder-dialog-resize button.ui-button span{padding:0}.elfinder-dialog-resize .elfinder-resize-jpgsize{font-size:90%}.ui-widget-content .elfinder-resize-container .elfinder-resize-rotate-slider{width:195px;margin:10px 7px;background-color:#fafafa}.elfinder-dialog-resize .elfinder-resize-type span.ui-checkboxradio-icon{display:none}.elfinder-resize-preset-container{box-sizing:border-box;border-radius:5px}.elfinder-file-edit{width:100%;height:100%;margin:0;padding:2px;border:1px solid #ccc;box-sizing:border-box;resize:none}.elfinder-touch .elfinder-file-edit{font-size:16px}.elfinder-dialog-edit .ui-dialog-content.elfinder-edit-editor{background-color:#fff}.elfinder-dialog-edit .ui-dialog-content.elfinder-edit-editor .elfinder-edit-imageeditor{width:100%;height:300px;max-height:100%;text-align:center}.elfinder-dialog-edit .ui-dialog-content.elfinder-edit-editor .elfinder-edit-imageeditor *{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;user-select:none}.elfinder-edit-imageeditor .tui-image-editor-main-container .tui-image-editor-main{top:0}.elfinder-edit-imageeditor .tui-image-editor-main-container .tui-image-editor-header{display:none}.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-crop .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-draw .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-filter .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-flip .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-icon .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-mask .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-rotate .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-shape .tui-image-editor-wrap,.elfinder-edit-imageeditor .tui-image-editor-main.tui-image-editor-menu-text .tui-image-editor-wrap{height:calc(100% - 150px)}.elfinder-touch.elfinder-fullscreen-native textarea.elfinder-file-edit{padding-bottom:20em;margin-bottom:-20em}.elfinder-dialog-edit .ui-dialog-buttonpane .elfinder-dialog-confirm-encoding{font-size:12px}.ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras{margin:0 1em 0 .2em;float:left}.ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras-quality{padding-top:6px}.ui-dialog-buttonpane .ui-dialog-buttonset.elfinder-edit-extras select{font-size:12px;margin-top:8px}.elfinder-dialog-edit .ui-dialog-buttonpane .ui-icon,.elfinder-edit-onlineconvert-bottom-btn button,.elfinder-edit-onlineconvert-button button,.elfinder-preference dt label{cursor:pointer}.elfinder-edit-spinner{position:absolute;top:50%;text-align:center;width:100%;font-size:16pt}.elfinder-dialog-edit .elfinder-edit-spinner .elfinder-spinner,.elfinder-dialog-edit .elfinder-edit-spinner .elfinder-spinner-text{float:none}.elfinder-dialog-edit .elfinder-toast>div{width:280px}.elfinder-edit-onlineconvert-button{display:inline-block;width:180px;min-height:30px;vertical-align:top}.elfinder-edit-onlineconvert-bottom-btn button.elfinder-button-ios-multiline{-webkit-appearance:none;border-radius:16px;color:#000;text-align:center;padding:8px;background-color:#eee;background-image:-webkit-linear-gradient(top,#fafafa 0%,#c4c4c4 100%);background-image:linear-gradient(to bottom,#fafafa 0%,#c4c4c4 100%)}.elfinder-edit-onlineconvert-button .elfinder-button-icon{margin:0 10px;vertical-align:middle;cursor:pointer}.elfinder-edit-onlineconvert-bottom-btn{text-align:center;margin:10px 0 0}.elfinder-edit-onlineconvert-link{margin-top:1em;text-align:center}.elfinder-edit-onlineconvert-link .elfinder-button-icon{background-image:url(../img/editor-icons.png);background-repeat:no-repeat;background-position:0 -144px;margin-bottom:-3px}.elfinder-edit-onlineconvert-link a,ul.elfinder-help-integrations a{text-decoration:none}div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{position:absolute;top:4px;left:0;right:0;margin:auto 0 auto auto}.elfinder-touch div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{top:7px}.elfinder-rtl div.elfinder-cwd-wrapper-list tr.ui-state-default td span.ui-icon{margin:auto auto auto 0}.elfinder-help{margin-bottom:.5em;-webkit-overflow-scrolling:touch}.elfinder-help .ui-tabs-panel{overflow:auto;padding:10px}.elfinder-dialog .ui-tabs .ui-tabs-nav li{overflow:hidden}.elfinder-dialog .ui-tabs .ui-tabs-nav li a{padding:.2em .8em;display:inline-block}.elfinder-touch .elfinder-dialog .ui-tabs .ui-tabs-nav li a{padding:.5em}.elfinder-dialog .ui-tabs-active a{background:inherit}.elfinder-help-shortcuts{height:auto;padding:10px;margin:0;box-sizing:border-box}.elfinder-help-shortcut{white-space:nowrap;clear:both}.elfinder-help-shortcut-pattern{float:left;width:160px}.elfinder-help-logo{width:100px;height:96px;float:left;margin-right:1em;background:url(../img/logo.png) center center no-repeat}.elfinder-help h3{font-size:1.5em;margin:.2em 0 .3em}.elfinder-help-separator{clear:both;padding:.5em}.elfinder-help-link{display:inline-block;margin-right:12px;padding:2px 0;white-space:nowrap}.elfinder-rtl .elfinder-help-link{margin-right:0;margin-left:12px}.elfinder-help .ui-priority-secondary{font-size:.9em}.elfinder-help .ui-priority-primary{margin-bottom:7px}.elfinder-help-team{clear:both;text-align:right;border-bottom:1px solid #ccc;margin:.5em 0;font-size:.9em}.elfinder-help-license{font-size:.9em}.elfinder-help-disabled{font-weight:700;text-align:center;margin:90px 0}.elfinder-help .elfinder-dont-panic{display:block;border:1px solid transparent;width:200px;height:200px;margin:30px auto;text-decoration:none;text-align:center;position:relative;background:#d90004;-moz-box-shadow:5px 5px 9px #111;-webkit-box-shadow:5px 5px 9px #111;box-shadow:5px 5px 9px #111;background:-moz-radial-gradient(80px 80px,circle farthest-corner,#d90004 35%,#960004 100%);background:-webkit-gradient(radial,80 80,60,80 80,120,from(#d90004),to(#960004));-moz-border-radius:100px;-webkit-border-radius:100px;border-radius:100px;outline:none}.elfinder-help .elfinder-dont-panic span{font-size:3em;font-weight:700;text-align:center;color:#fff;position:absolute;left:0;top:45px}ul.elfinder-help-integrations ul{padding:0;margin:0 1em 1em}ul.elfinder-help-integrations a:hover{text-decoration:underline}.elfinder-help-debug{height:100%;padding:0;margin:0;overflow:none;border:none}.elfinder-help-debug .ui-tabs-panel{padding:0;margin:0;overflow:auto}.elfinder-help-debug fieldset{margin-bottom:10px;border-color:#789;border-radius:10px}.elfinder-help-debug legend{font-size:1.2em;font-weight:700;color:#2e8b57}.elfinder-help-debug dl{margin:0}.elfinder-help-debug dt{color:#789}.elfinder-help-debug dt:before{content:"["}.elfinder-help-debug dt:after{content:"]"}.elfinder-help-debug dd{margin-left:1em}.elfinder-dialog .elfinder-preference .ui-tabs-nav{margin-bottom:1px;height:auto}.elfinder-preference .ui-tabs-panel{padding:10px 10px 0;overflow:auto;box-sizing:border-box;-webkit-overflow-scrolling:touch}.elfinder-preference a.ui-state-hover,.elfinder-preference label.ui-state-hover{border:none}.elfinder-preference dl{width:100%;display:inline-block;margin:.5em 0}.elfinder-preference dt{display:block;width:200px;clear:left;float:left;max-width:50%}.elfinder-rtl .elfinder-preference dt{clear:right;float:right}.elfinder-preference dd{margin-bottom:1em}.elfinder-preference dd input[type=checkbox],.elfinder-preference dd label{white-space:nowrap;display:inline-block;cursor:pointer}.elfinder-preference dt.elfinder-preference-checkboxes{width:100%;max-width:none}.elfinder-preference dd.elfinder-preference-checkboxes{padding-top:3ex}.elfinder-preference select{max-width:100%}.elfinder-preference dd.elfinder-preference-iconSize .ui-slider{width:50%;max-width:100px;display:inline-block;margin:0 10px}.elfinder-preference button{margin:0 16px}.elfinder-preference button+button{margin:0 -10px}.elfinder-preference .elfinder-preference-taball .elfinder-reference-hide-taball{display:none}.elfinder-preference-theme fieldset{margin-bottom:10px}.elfinder-preference-theme legend a{font-size:1.8em;text-decoration:none;cursor:pointer}.elfinder-preference-theme dt{width:20%;word-break:break-all}.elfinder-preference-theme dt:after{content:" :"}.elfinder-preference-theme dd{margin-inline-start:20%}.elfinder-preference img.elfinder-preference-theme-image{display:block;margin-left:auto;margin-right:auto;max-width:90%;max-height:200px;cursor:pointer}.elfinder-preference-theme-btn,.elfinder-rename-batch-type{text-align:center}.elfinder-preference-theme button.elfinder-preference-theme-default{display:inline;margin:0 10px;font-size:8pt}.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon:before{right:33px;left:auto}.elfinder-info-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after{content:none}.elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{position:absolute;bottom:2px;width:16px;height:16px;padding:10px;border:none;overflow:hidden;cursor:pointer}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item .ui-icon,.elfinder-ltr .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{left:2px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item .ui-icon,.elfinder-rtl .elfinder-upload-dialog-wrapper .elfinder-upload-dirselect{right:2px}.elfinder-ltr .elfinder-rm-title .elfinder-cwd-icon:before{left:38px}.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon:before{right:86px;left:auto}.elfinder-rm-title .elfinder-cwd-icon.elfinder-cwd-bgurl:after{content:none}.elfinder-rename-batch div{margin:5px 8px}.elfinder-rename-batch .elfinder-rename-batch-name input{width:100%;font-size:1.6em}.elfinder-rename-batch .elfinder-rename-batch-type label{margin:2px;font-size:.9em}.elfinder-rename-batch-preview{padding:0 8px;font-size:1.1em;min-height:4ex}.ui-front{z-index:100}.elfinder .elfinder-cwd table td div,.elfinder-cwd table td,div.elfinder *,div.elfinder :after,div.elfinder :before{box-sizing:content-box}div.elfinder fieldset{display:block;margin-inline-start:2px;margin-inline-end:2px;padding-block-start:.35em;padding-inline-start:.75em;padding-inline-end:.75em;padding-block-end:.625em;min-inline-size:min-content;border-width:2px;border-style:groove;border-color:threedface;border-image:initial}div.elfinder legend{display:block;padding-inline-start:2px;padding-inline-end:2px;border-width:initial;border-style:none;border-color:initial;border-image:initial;width:auto;margin-bottom:0}div.elfinder{padding:0;position:relative;display:block;visibility:visible;font-size:18px;font-family:Verdana,Arial,Helvetica,sans-serif}.elfinder-ios input,.elfinder-ios select,.elfinder-ios textarea{font-size:16px!important}.elfinder.elfinder-fullscreen>.ui-resizable-handle{display:none}.elfinder-font-mono{line-height:2ex}.elfinder.elfinder-processing *{cursor:progress!important}.elfinder.elfinder-processing.elfinder-touch .elfinder-workzone:after{position:absolute;top:0;width:100%;height:3px;content:'';left:0;background-image:url(../img/progress.gif);opacity:.6;pointer-events:none}.elfinder :not(input):not(textarea):not(select):not([contenteditable=true]),.elfinder-contextmenu :not(input):not(textarea):not(select):not([contenteditable=true]){-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;user-select:none}.elfinder .overflow-scrolling-touch{-webkit-overflow-scrolling:touch}.elfinder-rtl{text-align:right;direction:rtl}.elfinder-workzone{padding:0;position:relative;overflow:hidden}.elfinder-lock,.elfinder-perms,.elfinder-symlink{position:absolute;width:16px;height:16px;background-image:url(../img/toolbar.png);background-repeat:no-repeat}.elfinder-perms,.elfinder-symlink{background-position:0 -528px}.elfinder-na .elfinder-perms{background-position:0 -96px}.elfinder-ro .elfinder-perms{background-position:0 -64px}.elfinder-wo .elfinder-perms{background-position:0 -80px}.elfinder-group .elfinder-perms{background-position:0 0}.elfinder-lock{background-position:0 -656px}.elfinder-drag-helper{top:0;left:0;width:70px;height:60px;padding:0 0 0 25px;z-index:100000;will-change:left,top}.elfinder-drag-helper.html5-native{position:absolute;top:-1000px;left:-1000px}.elfinder-drag-helper-icon-status{position:absolute;width:16px;height:16px;left:42px;top:60px;background:url(../img/toolbar.png) 0 -96px no-repeat;display:block}.elfinder-drag-helper-move .elfinder-drag-helper-icon-status{background-position:0 -720px}.elfinder-drag-helper-plus .elfinder-drag-helper-icon-status{background-position:0 -544px}.elfinder-drag-num{display:inline-box;position:absolute;top:0;left:0;width:auto;height:14px;text-align:center;padding:1px 3px;font-weight:700;color:#fff;background-color:red;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.elfinder-drag-helper .elfinder-cwd-icon{margin:0 0 0 -24px;float:left}.elfinder-overlay{position:absolute;opacity:.2;filter:Alpha(Opacity=20)}.elfinder .elfinder-panel{position:relative;background-image:none;padding:7px 12px}[draggable=true]{-khtml-user-drag:element}.elfinder [contentEditable=true]:empty:not(:focus):before{content:attr(data-ph)}.elfinder div.elfinder-bottomtray{position:fixed;bottom:0;max-width:100%;opacity:.8}.elfinder div.elfinder-bottomtray>div{top:initial;right:initial;left:initial}.elfinder.elfinder-ltr div.elfinder-bottomtray{left:0}.elfinder.elfinder-rtl div.elfinder-bottomtray{right:0}.elfinder .elfinder-ui-tooltip,.elfinder-ui-tooltip{font-size:14px;padding:2px 4px}.elfinder-ui-progressbar{pointer-events:none;position:absolute;width:0;height:2px;top:0;border-radius:2px;filter:blur(1px)}.elfinder-ltr .elfinder-ui-progressbar{left:0}.elfinder-rtl .elfinder-ui-progressbar{right:0}.elfinder .elfinder-contextmenu,.elfinder .elfinder-contextmenu-sub{position:absolute;border:1px solid #aaa;background:#fff;color:#555;padding:4px 0;top:0;left:0}.elfinder .elfinder-contextmenu-sub{top:5px}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub{margin-left:-5px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub{margin-right:-5px}.elfinder .elfinder-contextmenu-header{margin-top:-4px;padding:0 .5em .2ex;border:none;text-align:center}.elfinder .elfinder-contextmenu-header span{font-size:.8em;font-weight:bolder}.elfinder .elfinder-contextmenu-item{position:relative;display:block;padding:4px 30px;text-decoration:none;white-space:nowrap;cursor:default}.elfinder .elfinder-contextmenu-item.ui-state-active{border:none}.elfinder .elfinder-contextmenu-item .ui-icon{width:16px;height:16px;position:absolute;left:auto;right:auto;top:50%;margin-top:-8px}.elfinder-touch .elfinder-contextmenu-item{padding:12px 38px}.elfinder-navbar-root-local.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_local.svg);background-size:contain}.elfinder-navbar-root-trash.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_trash.svg);background-size:contain}.elfinder-navbar-root-ftp.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_ftp.svg);background-size:contain}.elfinder-navbar-root-sql.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_sql.svg);background-size:contain}.elfinder-navbar-root-dropbox.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_dropbox.svg);background-size:contain}.elfinder-navbar-root-googledrive.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_googledrive.svg);background-size:contain}.elfinder-navbar-root-onedrive.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_onedrive.svg);background-size:contain}.elfinder-navbar-root-box.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_box.svg);background-size:contain}.elfinder-navbar-root-zip.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_zip.svg);background-size:contain}.elfinder-navbar-root-network.elfinder-contextmenu-icon{background-image:url(../img/volume_icon_network.svg);background-size:contain}.elfinder .elfinder-contextmenu .elfinder-contextmenu-item span{display:block}.elfinder .elfinder-contextmenu-sub .elfinder-contextmenu-item{padding-left:12px;padding-right:12px}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-item{text-align:left}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-item{text-align:right}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-left:28px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-right:28px}.elfinder-touch .elfinder-contextmenu-ltr .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-left:36px}.elfinder-touch .elfinder-contextmenu-rtl .elfinder-contextmenu-sub .elfinder-contextsubmenu-item-icon{padding-right:36px}.elfinder .elfinder-contextmenu-arrow,.elfinder .elfinder-contextmenu-extra-icon,.elfinder .elfinder-contextmenu-icon{position:absolute;top:50%;margin-top:-8px;overflow:hidden}.elfinder-touch .elfinder-button-icon.elfinder-contextmenu-icon{transform-origin:center center}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-icon{left:8px}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-extra-icon,.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-icon{right:8px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-extra-icon{left:8px}.elfinder .elfinder-contextmenu-arrow{width:16px;height:16px;background:url(../img/arrows-normal.png) 5px 4px no-repeat}.elfinder .elfinder-contextmenu-ltr .elfinder-contextmenu-arrow{right:5px}.elfinder .elfinder-contextmenu-rtl .elfinder-contextmenu-arrow{left:5px;background-position:0 -10px}.elfinder .elfinder-contextmenu-extra-icon a,.elfinder .elfinder-contextmenu-extra-icon span{position:relative;width:100%;height:100%;margin:0;color:transparent!important;text-decoration:none;cursor:pointer}.elfinder .elfinder-contextmenu .ui-state-hover{border:0 solid;background-image:none}.elfinder .elfinder-contextmenu-separator{height:0;border-top:1px solid #ccc;margin:0 1px}.elfinder .elfinder-contextmenu-item .elfinder-button-icon.ui-state-disabled{background-image:url(../img/toolbar.png)}.elfinder-cwd-wrapper{overflow:auto;position:relative;padding:2px;margin:0}.elfinder-cwd-wrapper-list{padding:0}.elfinder-cwd{position:absolute;top:0;cursor:default;padding:0;margin:0;-ms-touch-action:auto;touch-action:auto;min-width:100%}.elfinder-ltr .elfinder-cwd{left:0}.elfinder-rtl .elfinder-cwd{right:0}.elfinder-cwd.elfinder-table-header-sticky{position:-webkit-sticky;position:-ms-sticky;position:sticky;top:0;left:auto;right:auto;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:max-content;height:0;overflow:visible}.elfinder-cwd.elfinder-table-header-sticky table{border-top:2px solid;padding-top:0}.elfinder-cwd.elfinder-table-header-sticky td{display:inline-block}.elfinder-droppable-active .elfinder-cwd.elfinder-table-header-sticky table{border-top:2px solid transparent}.elfinder .elfinder-cwd table tbody.elfinder-cwd-fixheader,.elfinder-cwd-fixheader .elfinder-cwd{position:relative}.elfinder .elfinder-cwd-wrapper.elfinder-droppable-active{outline:2px solid #8cafed;outline-offset:-2px}.elfinder-cwd-wrapper-empty .elfinder-cwd:after{display:block;height:auto;width:90%;width:calc(100% - 20px);position:absolute;top:50%;left:50%;-ms-transform:translateY(-50%) translateX(-50%);-webkit-transform:translateY(-50%) translateX(-50%);transform:translateY(-50%) translateX(-50%);line-height:1.5em;text-align:center;white-space:pre-wrap;opacity:.6;filter:Alpha(Opacity=60);font-weight:700}.elfinder-cwd-file .elfinder-cwd-select{position:absolute;top:0;left:0;background-color:transparent;opacity:.4;filter:Alpha(Opacity=40)}.elfinder-mobile .elfinder-cwd-file .elfinder-cwd-select{width:30px;height:30px}.elfinder .elfinder-cwd-selectall,.elfinder-cwd-file.ui-selected .elfinder-cwd-select{opacity:.8;filter:Alpha(Opacity=80)}.elfinder-rtl .elfinder-cwd-file .elfinder-cwd-select{left:auto;right:0}.elfinder .elfinder-cwd-selectall{position:absolute;width:30px;height:30px;top:0}.elfinder .elfinder-workzone.elfinder-cwd-wrapper-empty .elfinder-cwd-selectall{display:none}.elfinder-ltr .elfinder-workzone .elfinder-cwd-selectall{text-align:right;right:18px;left:auto}.elfinder-rtl .elfinder-workzone .elfinder-cwd-selectall{text-align:left;right:auto;left:18px}.elfinder-ltr.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall{right:0}.elfinder-rtl.elfinder-mobile .elfinder-workzone .elfinder-cwd-selectall{left:0}.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-select.ui-state-hover{background-color:transparent}.elfinder-cwd-view-icons .elfinder-cwd-file{width:120px;height:90px;padding-bottom:2px;cursor:default;border:none;position:relative}.elfinder .std42-dialog .ui-dialog-content label,.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-active{border:none}.elfinder-ltr .elfinder-cwd-view-icons .elfinder-cwd-file{float:left;margin:0 3px 2px 0}.elfinder-rtl .elfinder-cwd-view-icons .elfinder-cwd-file{float:right;margin:0 0 5px 3px}.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover{border:0 solid}.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper{width:52px;height:52px;margin:1px auto;padding:2px;position:relative}.elfinder-cwd-size1 .elfinder-cwd-icon:before,.elfinder-cwd-size2 .elfinder-cwd-icon:before,.elfinder-cwd-size3 .elfinder-cwd-icon:before{top:3px;display:block}.elfinder-cwd-size1.elfinder-cwd-view-icons .elfinder-cwd-file{width:120px;height:112px}.elfinder-cwd-size1.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper{width:74px;height:74px}.elfinder-cwd-size1 .elfinder-cwd-icon,.elfinder-cwd-size2 .elfinder-cwd-icon,.elfinder-cwd-size3 .elfinder-cwd-icon{-ms-transform-origin:top center;-ms-transform:scale(1.5);-webkit-transform-origin:top center;-webkit-transform:scale(1.5);transform-origin:top center;transform:scale(1.5)}.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl:before{-ms-transform-origin:top left;-ms-transform:scale(1.35) translate(-4px,15%);-webkit-transform-origin:top left;-webkit-transform:scale(1.35) translate(-4px,15%);transform-origin:top left;transform:scale(1.35) translate(-4px,15%)}.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl:after{-ms-transform:scale(1) translate(10px,-5px);-webkit-transform:scale(1) translate(10px,-5px);transform:scale(1) translate(10px,-5px)}.elfinder-cwd-size1 .elfinder-cwd-icon.elfinder-cwd-bgurl{-ms-transform-origin:center center;-ms-transform:scale(1);-webkit-transform-origin:center center;-webkit-transform:scale(1);transform-origin:center center;transform:scale(1);width:72px;height:72px;-moz-border-radius:6px;-webkit-border-radius:6px;border-radius:6px}.elfinder-cwd-size2.elfinder-cwd-view-icons .elfinder-cwd-file{width:140px;height:134px}.elfinder-cwd-size2.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper{width:98px;height:98px}.elfinder-cwd-size2 .elfinder-cwd-icon,.elfinder-cwd-size3 .elfinder-cwd-icon{-ms-transform:scale(2);-webkit-transform:scale(2);transform:scale(2)}.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl:before{-ms-transform-origin:top left;-ms-transform:scale(1.8) translate(-5px,18%);-webkit-transform-origin:top left;-webkit-transform:scale(1.8) translate(-5px,18%);transform-origin:top left;transform:scale(1.8) translate(-5px,18%)}.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl:after{-ms-transform:scale(1.1) translate(0,10px);-webkit-transform:scale(1.1) translate(0,10px);transform:scale(1.1) translate(0,10px)}.elfinder-cwd-size2 .elfinder-cwd-icon.elfinder-cwd-bgurl{-ms-transform-origin:center center;-ms-transform:scale(1);-webkit-transform-origin:center center;-webkit-transform:scale(1);transform-origin:center center;transform:scale(1);width:96px;height:96px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.elfinder-cwd-size3.elfinder-cwd-view-icons .elfinder-cwd-file{width:174px;height:158px}.elfinder-cwd-size3.elfinder-cwd-view-icons .elfinder-cwd-file-wrapper{width:122px;height:122px}.elfinder-cwd-size3 .elfinder-cwd-icon{-ms-transform:scale(2.5);-webkit-transform:scale(2.5);transform:scale(2.5)}.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl:before{-ms-transform-origin:top left;-ms-transform:scale(2.25) translate(-6px,20%);-webkit-transform-origin:top left;-webkit-transform:scale(2.25) translate(-6px,20%);transform-origin:top left;transform:scale(2.25) translate(-6px,20%)}.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl:after{-ms-transform:scale(1.2) translate(-9px,22px);-webkit-transform:scale(1.2) translate(-9px,22px);transform:scale(1.2) translate(-9px,22px)}.elfinder-cwd-size3 .elfinder-cwd-icon.elfinder-cwd-bgurl{-ms-transform-origin:center center;-ms-transform:scale(1);-webkit-transform-origin:center center;-webkit-transform:scale(1);transform-origin:center center;transform:scale(1);width:120px;height:120px;-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px}.elfinder-cwd-view-icons .elfinder-cwd-filename{text-align:center;max-height:2.4em;line-height:1.2em;white-space:pre-line;overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis;margin:3px 1px 0;padding:1px;-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px;word-break:break-word;overflow-wrap:break-word;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.elfinder-cwd-view-icons .elfinder-perms{bottom:4px;right:2px}.elfinder-cwd-view-icons .elfinder-lock{top:-3px;right:-2px}.elfinder-cwd-view-icons .elfinder-symlink{bottom:6px;left:0}.elfinder-cwd-icon{display:block;width:48px;height:48px;margin:0 auto;background-image:url(../img/icons-big.svg);background-image:url(../img/icons-big.png) \9;background-position:0 0;background-repeat:no-repeat;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-local td .elfinder-cwd-icon,.elfinder-navbar-root-local .elfinder-cwd-icon{background-image:url(../img/volume_icon_local.svg);background-image:url(../img/volume_icon_local.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-local.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-trash td .elfinder-cwd-icon,.elfinder-navbar-root-trash .elfinder-cwd-icon{background-image:url(../img/volume_icon_trash.svg);background-image:url(../img/volume_icon_trash.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-trash.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-ftp td .elfinder-cwd-icon,.elfinder-navbar-root-ftp .elfinder-cwd-icon{background-image:url(../img/volume_icon_ftp.svg);background-image:url(../img/volume_icon_ftp.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-ftp.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-sql td .elfinder-cwd-icon,.elfinder-navbar-root-sql .elfinder-cwd-icon{background-image:url(../img/volume_icon_sql.svg);background-image:url(../img/volume_icon_sql.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-sql.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-dropbox td .elfinder-cwd-icon,.elfinder-navbar-root-dropbox .elfinder-cwd-icon{background-image:url(../img/volume_icon_dropbox.svg);background-image:url(../img/volume_icon_dropbox.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-dropbox.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon,.elfinder-navbar-root-googledrive .elfinder-cwd-icon{background-position:0 0}.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-googledrive td .elfinder-cwd-icon,.elfinder-navbar-root-googledrive .elfinder-cwd-icon{background-image:url(../img/volume_icon_googledrive.svg);background-image:url(../img/volume_icon_googledrive.png) \9;background-size:contain}.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon,.elfinder-navbar-root-onedrive .elfinder-cwd-icon{background-position:0 0}.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-onedrive td .elfinder-cwd-icon,.elfinder-navbar-root-onedrive .elfinder-cwd-icon{background-image:url(../img/volume_icon_onedrive.svg);background-image:url(../img/volume_icon_onedrive.png) \9;background-size:contain}.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon,.elfinder-navbar-root-box .elfinder-cwd-icon{background-position:0 0}.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-box td .elfinder-cwd-icon,.elfinder-navbar-root-box .elfinder-cwd-icon{background-image:url(../img/volume_icon_box.svg);background-image:url(../img/volume_icon_box.png) \9;background-size:contain}.elfinder-cwd .elfinder-navbar-root-zip.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-zip td .elfinder-cwd-icon,.elfinder-navbar-root-zip .elfinder-cwd-icon{background-image:url(../img/volume_icon_zip.svg);background-image:url(../img/volume_icon_zip.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-box.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd .elfinder-navbar-root-googledrive.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd .elfinder-navbar-root-onedrive.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon,.elfinder-cwd-view-list .elfinder-navbar-root-network td .elfinder-cwd-icon,.elfinder-navbar-root-network .elfinder-cwd-icon{background-image:url(../img/volume_icon_network.svg);background-image:url(../img/volume_icon_network.png) \9;background-position:0 0;background-size:contain}.elfinder-cwd .elfinder-navbar-root-network.elfinder-droppable-active .elfinder-cwd-icon{background-position:1px -1px}.elfinder-cwd-icon:before{content:none;position:absolute;left:0;top:5px;min-width:20px;max-width:84px;text-align:center;padding:0 4px 1px;border-radius:4px;font-family:Verdana;font-size:10px;line-height:1.3em;-webkit-transform:scale(.9);-moz-transform:scale(.9);-ms-transform:scale(.9);-o-transform:scale(.9);transform:scale(.9)}.elfinder-cwd-view-icons .elfinder-cwd-icon.elfinder-cwd-bgurl:before{left:-10px}.elfinder-cwd-icon.elfinder-cwd-icon-mp2t:before{content:'ts'}.elfinder-cwd-icon.elfinder-cwd-icon-dash-xml:before{content:'dash'}.elfinder-cwd-icon.elfinder-cwd-icon-x-mpegurl:before{content:'hls'}.elfinder-cwd-icon.elfinder-cwd-icon-x-c:before{content:'c++'}.elfinder-cwd-icon.elfinder-cwd-bgurl{background-position:center center;background-repeat:no-repeat}.elfinder-cwd-icon.elfinder-cwd-bgurl,.elfinder-cwd-icon.elfinder-cwd-bgurl.elfinder-cwd-bgself{-moz-background-size:cover;background-size:cover}.elfinder-cwd-icon.elfinder-cwd-bgurl:after{content:' '}.elfinder-cwd-bgurl:after{position:relative;display:inline-block;top:36px;left:-38px;width:48px;height:48px;background-image:url(../img/icons-big.svg);background-image:url(../img/icons-big.png) \9;background-repeat:no-repeat;background-size:auto!important;opacity:.8;filter:Alpha(Opacity=60);-webkit-transform-origin:54px -24px;-webkit-transform:scale(.6);-moz-transform-origin:54px -24px;-moz-transform:scale(.6);-ms-transform-origin:54px -24px;-ms-transform:scale(.6);-o-transform-origin:54px -24px;-o-transform:scale(.6);transform-origin:54px -24px;transform:scale(.6)}.elfinder-cwd-icon.elfinder-cwd-icon-drag{width:48px;height:48px}.elfinder-cwd-icon-directory.elfinder-cwd-bgurl:after,.elfinder-cwd-icon-image.elfinder-cwd-bgurl:after,.elfinder-cwd-icon.elfinder-cwd-icon-drag:after,.elfinder-cwd-icon.elfinder-cwd-icon-drag:before{content:none}.elfinder-cwd .elfinder-droppable-active .elfinder-cwd-icon{background-position:0 -100px}.elfinder-cwd .elfinder-droppable-active{outline:2px solid #8cafed;outline-offset:-2px}.elfinder-cwd-icon-directory{background-position:0 -50px}.elfinder-cwd-icon-application,.elfinder-cwd-icon-application:after{background-position:0 -150px}.elfinder-cwd-icon-text,.elfinder-cwd-icon-text:after{background-position:0 -1350px}.elfinder-cwd-icon-plain,.elfinder-cwd-icon-plain:after,.elfinder-cwd-icon-x-empty,.elfinder-cwd-icon-x-empty:after{background-position:0 -200px}.elfinder-cwd-icon-image,.elfinder-cwd-icon-image:after,.elfinder-cwd-icon-vnd-adobe-photoshop,.elfinder-cwd-icon-vnd-adobe-photoshop:after{background-position:0 -250px}.elfinder-cwd-icon-postscript,.elfinder-cwd-icon-postscript:after{background-position:0 -1550px}.elfinder-cwd-icon-audio,.elfinder-cwd-icon-audio:after{background-position:0 -300px}.elfinder-cwd-icon-dash-xml,.elfinder-cwd-icon-flash-video,.elfinder-cwd-icon-video,.elfinder-cwd-icon-video:after,.elfinder-cwd-icon-vnd-apple-mpegurl,.elfinder-cwd-icon-x-mpegurl{background-position:0 -350px}.elfinder-cwd-icon-rtf,.elfinder-cwd-icon-rtf:after,.elfinder-cwd-icon-rtfd,.elfinder-cwd-icon-rtfd:after{background-position:0 -400px}.elfinder-cwd-icon-pdf,.elfinder-cwd-icon-pdf:after{background-position:0 -450px}.elfinder-cwd-icon-ms-excel,.elfinder-cwd-icon-ms-excel:after,.elfinder-cwd-icon-vnd-ms-excel,.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-excel:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template:after{background-position:0 -1450px}.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet:after{background-position:0 -1700px}.elfinder-cwd-icon-vnd-ms-powerpoint,.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-powerpoint:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template:after{background-position:0 -1400px}.elfinder-cwd-icon-vnd-oasis-opendocument-presentation,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-presentation:after{background-position:0 -1650px}.elfinder-cwd-icon-msword,.elfinder-cwd-icon-msword:after,.elfinder-cwd-icon-vnd-ms-word,.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12,.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12:after,.elfinder-cwd-icon-vnd-ms-word:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document:after,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template,.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template:after{background-position:0 -1500px}.elfinder-cwd-icon-vnd-oasis-opendocument-text,.elfinder-cwd-icon-vnd-oasis-opendocument-text-master,.elfinder-cwd-icon-vnd-oasis-opendocument-text-master:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text-template,.elfinder-cwd-icon-vnd-oasis-opendocument-text-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text-web,.elfinder-cwd-icon-vnd-oasis-opendocument-text-web:after,.elfinder-cwd-icon-vnd-oasis-opendocument-text:after{background-position:0 -1750px}.elfinder-cwd-icon-vnd-ms-office,.elfinder-cwd-icon-vnd-ms-office:after{background-position:0 -500px}.elfinder-cwd-icon-vnd-oasis-opendocument-chart,.elfinder-cwd-icon-vnd-oasis-opendocument-chart:after,.elfinder-cwd-icon-vnd-oasis-opendocument-database,.elfinder-cwd-icon-vnd-oasis-opendocument-database:after,.elfinder-cwd-icon-vnd-oasis-opendocument-formula,.elfinder-cwd-icon-vnd-oasis-opendocument-formula:after,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template:after,.elfinder-cwd-icon-vnd-oasis-opendocument-graphics:after,.elfinder-cwd-icon-vnd-oasis-opendocument-image,.elfinder-cwd-icon-vnd-oasis-opendocument-image:after,.elfinder-cwd-icon-vnd-openofficeorg-extension,.elfinder-cwd-icon-vnd-openofficeorg-extension:after{background-position:0 -1600px}.elfinder-cwd-icon-html,.elfinder-cwd-icon-html:after{background-position:0 -550px}.elfinder-cwd-icon-css,.elfinder-cwd-icon-css:after{background-position:0 -600px}.elfinder-cwd-icon-javascript,.elfinder-cwd-icon-javascript:after,.elfinder-cwd-icon-x-javascript,.elfinder-cwd-icon-x-javascript:after{background-position:0 -650px}.elfinder-cwd-icon-x-perl,.elfinder-cwd-icon-x-perl:after{background-position:0 -700px}.elfinder-cwd-icon-x-python,.elfinder-cwd-icon-x-python:after{background-position:0 -750px}.elfinder-cwd-icon-x-ruby,.elfinder-cwd-icon-x-ruby:after{background-position:0 -800px}.elfinder-cwd-icon-x-sh,.elfinder-cwd-icon-x-sh:after,.elfinder-cwd-icon-x-shellscript,.elfinder-cwd-icon-x-shellscript:after{background-position:0 -850px}.elfinder-cwd-icon-x-c,.elfinder-cwd-icon-x-c--,.elfinder-cwd-icon-x-c--:after,.elfinder-cwd-icon-x-c--hdr,.elfinder-cwd-icon-x-c--hdr:after,.elfinder-cwd-icon-x-c--src,.elfinder-cwd-icon-x-c--src:after,.elfinder-cwd-icon-x-c:after,.elfinder-cwd-icon-x-chdr,.elfinder-cwd-icon-x-chdr:after,.elfinder-cwd-icon-x-csrc,.elfinder-cwd-icon-x-csrc:after,.elfinder-cwd-icon-x-java,.elfinder-cwd-icon-x-java-source,.elfinder-cwd-icon-x-java-source:after,.elfinder-cwd-icon-x-java:after{background-position:0 -900px}.elfinder-cwd-icon-x-php,.elfinder-cwd-icon-x-php:after{background-position:0 -950px}.elfinder-cwd-icon-xml,.elfinder-cwd-icon-xml:after{background-position:0 -1000px}.elfinder-cwd-icon-x-7z-compressed,.elfinder-cwd-icon-x-7z-compressed:after,.elfinder-cwd-icon-x-xz,.elfinder-cwd-icon-x-xz:after,.elfinder-cwd-icon-x-zip,.elfinder-cwd-icon-x-zip:after,.elfinder-cwd-icon-zip,.elfinder-cwd-icon-zip:after{background-position:0 -1050px}.elfinder-cwd-icon-x-gzip,.elfinder-cwd-icon-x-gzip:after,.elfinder-cwd-icon-x-tar,.elfinder-cwd-icon-x-tar:after{background-position:0 -1100px}.elfinder-cwd-icon-x-bzip,.elfinder-cwd-icon-x-bzip2,.elfinder-cwd-icon-x-bzip2:after,.elfinder-cwd-icon-x-bzip:after{background-position:0 -1150px}.elfinder-cwd-icon-x-rar,.elfinder-cwd-icon-x-rar-compressed,.elfinder-cwd-icon-x-rar-compressed:after,.elfinder-cwd-icon-x-rar:after{background-position:0 -1200px}.elfinder-cwd-icon-x-shockwave-flash,.elfinder-cwd-icon-x-shockwave-flash:after{background-position:0 -1250px}.elfinder-cwd-icon-group{background-position:0 -1300px}.elfinder-cwd-filename input{width:100%;border:none;margin:0;padding:0}.elfinder-cwd-view-icons,.elfinder-cwd-view-icons input{text-align:center}.elfinder-cwd-view-icons textarea{width:100%;border:0 solid;margin:0;padding:0;text-align:center;overflow:hidden;resize:none}.elfinder-cwd-wrapper.elfinder-cwd-fixheader .elfinder-cwd::after,.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar select{display:none}.elfinder-cwd table{width:100%;border-collapse:separate;border:0 solid;margin:0 0 10px;border-spacing:0;box-sizing:padding-box;padding:2px;position:relative}.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader{position:absolute;overflow:hidden}.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before{content:'';position:absolute;width:100%;top:0;height:3px;background-color:#fff}.elfinder-droppable-active+.elfinder-cwd-wrapper-list.elfinder-cwd-fixheader:before{background-color:#8cafed}.elfinder .elfinder-workzone div.elfinder-cwd-fixheader table{table-layout:fixed}.elfinder-ltr .elfinder-cwd thead .elfinder-cwd-selectall{text-align:left;right:auto;left:0;padding-top:3px}.elfinder-rtl .elfinder-cwd thead .elfinder-cwd-selectall{text-align:right;right:0;left:auto;padding-top:3px}.elfinder-touch .elfinder-cwd thead .elfinder-cwd-selectall{padding-top:4px}.elfinder .elfinder-cwd table thead tr{border-left:0 solid;border-top:0 solid;border-right:0 solid}.elfinder .elfinder-cwd table thead td{padding:4px 14px}.elfinder-ltr .elfinder-cwd.elfinder-has-checkbox table thead td:first-child{padding:4px 14px 4px 22px}.elfinder-rtl .elfinder-cwd.elfinder-has-checkbox table thead td:first-child{padding:4px 22px 4px 14px}.elfinder-touch .elfinder-cwd table thead td,.elfinder-touch .elfinder-cwd.elfinder-has-checkbox table thead td:first-child{padding-top:8px;padding-bottom:8px}.elfinder .elfinder-cwd table thead td.ui-state-active{background:#ebf1f6;background:-moz-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ebf1f6),color-stop(50%,#abd3ee),color-stop(51%,#89c3eb),color-stop(100%,#d5ebfb));background:-webkit-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:-o-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:-ms-linear-gradient(top,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);background:linear-gradient(to bottom,#ebf1f6 0%,#abd3ee 50%,#89c3eb 51%,#d5ebfb 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ebf1f6', endColorstr='#d5ebfb', GradientType=0)}.elfinder .elfinder-cwd table td{padding:0 12px;white-space:pre;overflow:hidden;text-align:right;cursor:default;border:0 solid}.elfinder .elfinder-cwd table tbody td:first-child{position:relative}tr.elfinder-cwd-file td .elfinder-cwd-select{padding-top:3px}.elfinder-mobile tr.elfinder-cwd-file td .elfinder-cwd-select{width:40px}.elfinder-touch tr.elfinder-cwd-file td .elfinder-cwd-select{padding-top:10px}.elfinder-touch .elfinder-cwd tr td{padding:10px 12px}.elfinder-touch .elfinder-cwd tr.elfinder-cwd-file td{padding:13px 12px}.elfinder-ltr .elfinder-cwd table td{text-align:right}.elfinder-ltr .elfinder-cwd table td:first-child{text-align:left}.elfinder-rtl .elfinder-cwd table td{text-align:left}.elfinder-ltr .elfinder-info-tb tr td:first-child,.elfinder-rtl .elfinder-cwd table td:first-child{text-align:right}.elfinder-odd-row{background:#eee}.elfinder-cwd-view-list .elfinder-cwd-file-wrapper{width:97%;position:relative}.elfinder-ltr .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper{margin-left:8px}.elfinder-rtl .elfinder-cwd-view-list.elfinder-has-checkbox .elfinder-cwd-file-wrapper{margin-right:8px}.elfinder-cwd-view-list .elfinder-cwd-filename{padding-top:4px;padding-bottom:4px;display:inline-block}.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-filename{padding-left:23px}.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-filename{padding-right:23px}.elfinder-cwd-view-list .elfinder-lock,.elfinder-cwd-view-list .elfinder-perms,.elfinder-cwd-view-list .elfinder-symlink{margin-top:-6px;opacity:.6;filter:Alpha(Opacity=60)}.elfinder-cwd-view-list .elfinder-perms{bottom:-4px}.elfinder-cwd-view-list .elfinder-lock{top:0}.elfinder-cwd-view-list .elfinder-symlink{bottom:-4px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-perms{left:8px}.elfinder-rtl .elfinder-cwd-view-list .elfinder-perms{right:-8px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-lock{left:10px}.elfinder-rtl .elfinder-cwd-view-list .elfinder-lock{right:-10px}.elfinder-ltr .elfinder-cwd-view-list .elfinder-symlink{left:-7px}.elfinder-rtl .elfinder-cwd-view-list .elfinder-symlink{right:7px}.elfinder-cwd-view-list td .elfinder-cwd-icon{width:16px;height:16px;position:absolute;top:50%;margin-top:-8px;background-image:url(../img/icons-small.png)}.elfinder-ltr .elfinder-cwd-view-list .elfinder-cwd-icon{left:0}.elfinder-rtl .elfinder-cwd-view-list .elfinder-cwd-icon{right:0}.elfinder-cwd-view-list .elfinder-cwd-icon:after,.elfinder-cwd-view-list .elfinder-cwd-icon:before{content:none}.elfinder-cwd-view-list thead td .ui-resizable-handle{height:100%;top:6px}.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-handle{top:-4px;margin:10px}.elfinder-cwd-view-list thead td .ui-resizable-e{right:-7px}.elfinder-cwd-view-list thead td .ui-resizable-w{left:-7px}.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-e{right:-16px}.elfinder-touch .elfinder-cwd-view-list thead td .ui-resizable-w{left:-16px}.elfinder-cwd-wrapper-empty .elfinder-cwd-view-list.elfinder-cwd:after{margin-top:0}.elfinder-cwd-message-board{position:-webkit-sticky;position:sticky;width:100%;height:calc(100% - .01px);top:0;left:0;margin:0;padding:0;pointer-events:none;background-color:transparent}.elfinder-cwd-wrapper-trash .elfinder-cwd-message-board{background-image:url(../img/trashmesh.png)}.elfinder-cwd-message-board .elfinder-cwd-trash{position:absolute;bottom:0;font-size:30px;width:100%;text-align:right;display:none}.elfinder-rtl .elfinder-cwd-message-board .elfinder-cwd-trash{text-align:left}.elfinder-mobile .elfinder-cwd-message-board .elfinder-cwd-trash{font-size:20px}.elfinder-cwd-wrapper-trash .elfinder-cwd-message-board .elfinder-cwd-trash{display:block;opacity:.3}.elfinder-cwd-message-board .elfinder-cwd-expires{position:absolute;bottom:0;font-size:24px;width:100%;text-align:right;opacity:.25}.elfinder-rtl .elfinder-cwd-message-board .elfinder-cwd-expires{text-align:left}.elfinder-mobile .elfinder-cwd-message-board .elfinder-cwd-expires{font-size:20px}.std42-dialog{padding:0;position:absolute;left:auto;right:auto;box-sizing:border-box}.std42-dialog.elfinder-dialog-minimized{overFlow:hidden;position:relative;float:left;width:auto;cursor:pointer}.elfinder-rtl .std42-dialog.elfinder-dialog-minimized{float:right}.std42-dialog input{border:1px solid}.std42-dialog .ui-dialog-titlebar{border-left:0 solid transparent;border-top:0 solid transparent;border-right:0 solid transparent;font-weight:400;padding:.2em 1em}.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar{padding:0 .5em;height:20px}.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar{padding:.3em .5em}.std42-dialog.ui-draggable-disabled .ui-dialog-titlebar{cursor:default}.std42-dialog .ui-dialog-titlebar .ui-widget-header{border:none;cursor:pointer}.std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title{display:inherit;word-break:break-all}.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title{display:list-item;display:-moz-inline-box;white-space:nowrap;word-break:normal;overflow:hidden;word-wrap:normal;overflow-wrap:normal;max-width:-webkit-calc(100% - 24px);max-width:-moz-calc(100% - 24px);max-width:calc(100% - 24px)}.elfinder-touch .std42-dialog .ui-dialog-titlebar span.elfinder-dialog-title{padding-top:.15em}.elfinder-touch .std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar span.elfinder-dialog-title{max-width:-webkit-calc(100% - 36px);max-width:-moz-calc(100% - 36px);max-width:calc(100% - 36px)}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button{position:relative;float:left;top:10px;left:-10px;right:10px;width:20px;height:20px;padding:1px;margin:-10px 1px 0;background-color:transparent;background-image:none}.elfinder-touch .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button{-moz-transform:scale(1.2);zoom:1.2;padding-left:6px;padding-right:6px;height:24px}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button-right{float:right}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button.elfinder-titlebar-button-right{left:10px;right:-10px}.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon{width:17px;height:17px;border-width:1px;opacity:.7;filter:Alpha(Opacity=70);-moz-border-radius:8px;-webkit-border-radius:8px;border-radius:8px}.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon{opacity:.5;filter:Alpha(Opacity=50)}.std42-dialog.elfinder-dialog-minimized .ui-dialog-titlebar .elfinder-titlebar-button .ui-icon{opacity:1;filter:Alpha(Opacity=100)}.elfinder-spinner{width:14px;height:14px;background:url(../img/spinner-mini.gif) center center no-repeat;margin:0 5px;display:inline-block;vertical-align:middle}.elfinder-ltr .elfinder-info-tb span,.elfinder-ltr .elfinder-spinner,.elfinder-ltr .elfinder-spinner-text{float:left}.elfinder-rtl .elfinder-info-tb span,.elfinder-rtl .elfinder-spinner,.elfinder-rtl .elfinder-spinner-text{float:right}.elfinder-touch .std42-dialog.ui-dialog:not(ui-resizable-disabled) .ui-resizable-se{width:12px;height:12px;-moz-transform-origin:bottom right;-moz-transform:scale(1.5);zoom:1.5;right:-7px;bottom:-7px;margin:3px 7px 7px 3px;background-position:-64px -224px}.elfinder-rtl .elfinder-dialog .ui-dialog-titlebar{text-align:right}.std42-dialog .ui-dialog-content{padding:.3em .5em}.elfinder .std42-dialog .ui-dialog-content,.elfinder .std42-dialog .ui-dialog-content *{-webkit-user-select:auto;-moz-user-select:text;-khtml-user-select:text;user-select:text}.std42-dialog .ui-dialog-buttonpane{border:0 solid;margin:0;padding:.5em;text-align:right}.elfinder-rtl .std42-dialog .ui-dialog-buttonpane{text-align:left}.std42-dialog .ui-dialog-buttonpane button{margin:.2em 0 0 .4em;padding:.2em;outline:0 solid}.std42-dialog .ui-dialog-buttonpane button span{padding:2px 9px}.std42-dialog .ui-dialog-buttonpane button span.ui-icon{padding:2px}.elfinder-dialog .ui-resizable-e,.elfinder-dialog .ui-resizable-s{width:0;height:0}.std42-dialog .ui-button input{cursor:pointer}.std42-dialog select{border:1px solid #ccc}.elfinder-dialog-icon{position:absolute;width:32px;height:32px;left:10px;top:50%;margin-top:-15px;background:url(../img/dialogs.png) 0 0 no-repeat}.elfinder-rtl .elfinder-dialog-icon{left:auto;right:10px}.elfinder-dialog-confirm .ui-dialog-content,.elfinder-dialog-error .ui-dialog-content{padding-left:56px;min-height:35px}.elfinder-rtl .elfinder-dialog-confirm .ui-dialog-content,.elfinder-rtl .elfinder-dialog-error .ui-dialog-content{padding-left:0;padding-right:56px}.elfinder-dialog-error .elfinder-err-var{word-break:break-all}.elfinder-dialog-notify{top:36px;width:280px}.elfinder-ltr .elfinder-dialog-notify{right:12px}.elfinder-rtl .elfinder-dialog-notify{left:12px}.elfinder-dialog-notify .ui-dialog-titlebar{height:5px;overflow:hidden}.elfinder.elfinder-touch>.elfinder-dialog-notify .ui-dialog-titlebar{height:10px}.elfinder>.elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button{top:2px;left:-18px;right:18px}.elfinder.elfinder-touch>.elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button{top:4px}.elfinder>.elfinder-dialog-notify .ui-dialog-titlebar .elfinder-titlebar-button.elfinder-titlebar-button-right{left:18px;right:-18px}.ui-dialog-titlebar .elfinder-ui-progressbar{position:absolute;top:17px}.elfinder-touch .ui-dialog-titlebar .elfinder-ui-progressbar{top:26px}.elfinder-dialog-notify.elfinder-titlebar-button-hide .ui-dialog-titlebar-close,.elfinder-rm-title+br{display:none}.elfinder-dialog-notify.elfinder-dialog-minimized.elfinder-titlebar-button-hide .ui-dialog-titlebar span.elfinder-dialog-title{max-width:initial}.elfinder-dialog-notify .ui-dialog-content{padding:0}.elfinder-notify{border-bottom:1px solid #ccc;position:relative;padding:.5em;text-align:center;overflow:hidden}.elfinder-ltr .elfinder-notify{padding-left:36px}.elfinder-rtl .elfinder-notify{padding-right:36px}.elfinder-notify:last-child{border:0 solid}.elfinder-notify-progressbar{width:180px;height:8px;border:1px solid #aaa;background:#f5f5f5;margin:5px auto;overflow:hidden}.elfinder-notify-progress{width:100%;height:8px;background:url(../img/progress.gif) center center repeat-x}.elfinder-notify-progress,.elfinder-notify-progressbar{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px}.elfinder-notify-cancel{position:relative;top:-18px;right:calc(-50% + 15px)}.elfinder-notify-cancel .ui-icon-close{width:18px;height:18px;border-radius:9px;border:none;background-position:-80px -128px;cursor:pointer}.elfinder-dialog-icon-file,.elfinder-dialog-icon-open,.elfinder-dialog-icon-readdir,.elfinder-dialog-icon-reload{background-position:0 -225px}.elfinder-dialog-icon-mkdir{background-position:0 -64px}.elfinder-dialog-icon-mkfile{background-position:0 -96px}.elfinder-dialog-icon-copy,.elfinder-dialog-icon-move,.elfinder-dialog-icon-prepare{background-position:0 -128px}.elfinder-dialog-icon-chunkmerge,.elfinder-dialog-icon-upload{background-position:0 -160px}.elfinder-dialog-icon-rm{background-position:0 -192px}.elfinder-dialog-icon-download{background-position:0 -260px}.elfinder-dialog-icon-save{background-position:0 -295px}.elfinder-dialog-icon-chkcontent,.elfinder-dialog-icon-rename{background-position:0 -330px}.elfinder-dialog-icon-archive,.elfinder-dialog-icon-extract,.elfinder-dialog-icon-zipdl{background-position:0 -365px}.elfinder-dialog-icon-search{background-position:0 -402px}.elfinder-dialog-icon-chmod,.elfinder-dialog-icon-dim,.elfinder-dialog-icon-loadimg,.elfinder-dialog-icon-netmount,.elfinder-dialog-icon-netunmount,.elfinder-dialog-icon-preupload,.elfinder-dialog-icon-resize,.elfinder-dialog-icon-url{background-position:0 -434px}.elfinder-dialog-confirm-applyall,.elfinder-dialog-confirm-encoding{padding:0 1em;margin:0}.elfinder-ltr .elfinder-dialog-confirm-applyall,.elfinder-ltr .elfinder-dialog-confirm-encoding{text-align:left}.elfinder-rtl .elfinder-dialog-confirm-applyall,.elfinder-rtl .elfinder-dialog-confirm-encoding{text-align:right}.elfinder-dialog-confirm .elfinder-dialog-icon{background-position:0 -32px}.elfinder-dialog-confirm .ui-dialog-buttonset{width:auto}.elfinder-info-title .elfinder-cwd-icon{float:left;width:48px;height:48px;margin-right:1em}.elfinder-rtl .elfinder-info-title .elfinder-cwd-icon,.elfinder-rtl .elfinder-rm-title .elfinder-cwd-icon{float:right;margin-right:0;margin-left:1em}.elfinder-info-title strong{display:block;padding:.3em 0 .5em}.elfinder-info-tb{min-width:200px;border:0 solid;margin:1em .2em;width:100%}.elfinder-info-tb td{white-space:pre-wrap;padding:2px}.elfinder-info-tb td.elfinder-info-label{white-space:nowrap}.elfinder-info-tb td.elfinder-info-hash{display:inline-block;word-break:break-all;max-width:32ch}.elfinder-rtl .elfinder-info-tb tr td:first-child{text-align:left}.elfinder-info-tb a{outline:none;text-decoration:underline}.elfinder-info-tb a:hover{text-decoration:none}.elfinder-netmount-tb{margin:0 auto}.elfinder-netmount-tb .elfinder-button-icon,.elfinder-netmount-tb select{cursor:pointer}button.elfinder-info-button{margin:-3.5px 0;cursor:pointer}.elfinder-upload-dropbox{display:table-cell;text-align:center;vertical-align:middle;padding:.5em;border:3px dashed #aaa;width:9999px;height:80px;overflow:hidden;word-break:keep-all}.elfinder-upload-dropbox.ui-state-hover{background:#dfdfdf;border:3px dashed #555}.elfinder-upload-dialog-or{margin:.3em 0;text-align:center}.elfinder-upload-dialog-wrapper{text-align:center}.elfinder-upload-dialog-wrapper .ui-button{position:relative;overflow:hidden}.elfinder-upload-dialog-wrapper .ui-button form{position:absolute;right:0;top:0;width:100%;opacity:0;filter:Alpha(Opacity=0)}.elfinder-upload-dialog-wrapper .ui-button form input{padding:50px 0 0;font-size:3em;width:100%}.dialogelfinder .dialogelfinder-drag{border-left:0 solid;border-top:0 solid;border-right:0 solid;font-weight:400;padding:2px 12px;cursor:move;position:relative;text-align:left}.elfinder-rtl .dialogelfinder-drag{text-align:right}.dialogelfinder-drag-close{position:absolute;top:50%;margin-top:-8px}.elfinder-ltr .dialogelfinder-drag-close{right:12px}.elfinder-rtl .dialogelfinder-drag-close{left:12px}.elfinder-rm-title{margin-bottom:.5ex}.elfinder-rm-title .elfinder-cwd-icon{float:left;width:48px;height:48px;margin-right:1em}.elfinder-rm-title strong{display:block;white-space:pre-wrap;word-break:normal;overflow:hidden;text-overflow:ellipsis}.dialogelfinder .dialogelfinder-drag,.elfinder-info-tb,.elfinder-place-drag .elfinder-navbar-dir,.elfinder-quicklook-preview-text-wrapper{font-size:.9em}.std42-dialog .ui-dialog-titlebar{font-size:.82em}.elfinder-button-search input{font-size:.8em}.elfinder-toast,.std42-dialog .ui-dialog-buttonpane{font-size:.76em}.elfinder .elfinder-navbar,.elfinder-button-menu-item,.elfinder-contextmenu .elfinder-contextmenu-item span,.elfinder-quicklook-info-data,.std42-dialog .ui-dialog-content{font-size:.72em}.elfinder-cwd-view-icons .elfinder-cwd-filename,.elfinder-cwd-view-list td,.elfinder-quicklook-title,.elfinder-statusbar div{font-size:.7em}.elfinder-upload-dialog-or,.elfinder-upload-dropbox{font-size:1.2em}.elfinder-font-mono{font-family:"Ricty Diminished","Myrica M",Consolas,"Courier New",Courier,Monaco,monospace;font-size:1.1em}.elfinder-drag-num{font-size:12px}.elfinder-quicklook-title{font-weight:400}.elfinder .elfinder-navbar{width:230px;padding:3px 5px;background-image:none;border-top:0 solid;border-bottom:0 solid;overflow:auto;position:relative}.elfinder .elfinder-navdock{box-sizing:border-box;width:230px;height:auto;position:absolute;bottom:0;overflow:auto}.elfinder-navdock .ui-resizable-n{top:0;height:20px}.elfinder-ltr .elfinder-navbar{float:left;border-left:0 solid}.elfinder-rtl .elfinder-navbar{float:right;border-right:0 solid}.elfinder-ltr .ui-resizable-e,.elfinder-touch .elfinder-quicklook-titlebar-icon.elfinder-titlebar-button-right .ui-icon{margin-left:10px}.elfinder-tree{display:table;width:100%;margin:0 0 .5em;-webkit-tap-highlight-color:rgba(0,0,0,0)}.elfinder-navbar-dir{position:relative;display:block;white-space:nowrap;padding:3px 12px;margin:0;outline:0 solid;border:1px solid transparent;cursor:default}.elfinder-touch .elfinder-navbar-dir{padding:12px}.elfinder-ltr .elfinder-navbar-dir{padding-left:35px}.elfinder-rtl .elfinder-navbar-dir{padding-right:35px}.elfinder-navbar-arrow,.elfinder-navbar-icon{position:absolute;top:50%;margin-top:-8px;background-repeat:no-repeat}.elfinder-navbar-arrow{display:none;width:12px;height:14px;background-image:url(../img/arrows-normal.png)}.elfinder-ltr .elfinder-navbar-arrow{left:0}.elfinder-rtl .elfinder-navbar-arrow{right:0}.elfinder-touch .elfinder-navbar-arrow{-moz-transform-origin:top left;-moz-transform:scale(1.4);zoom:1.4;margin-bottom:7px}.elfinder-ltr.elfinder-touch .elfinder-navbar-arrow{left:-3px;margin-right:20px}.elfinder-rtl.elfinder-touch .elfinder-navbar-arrow{right:-3px;margin-left:20px}.ui-state-active .elfinder-navbar-arrow{background-image:url(../img/arrows-active.png)}.elfinder-navbar-collapsed .elfinder-navbar-arrow{display:block}.elfinder-subtree-chksubdir .elfinder-navbar-arrow{opacity:.25;filter:Alpha(Opacity=25)}.elfinder-ltr .elfinder-navbar-collapsed .elfinder-navbar-arrow{background-position:0 4px}.elfinder-rtl .elfinder-navbar-collapsed .elfinder-navbar-arrow{background-position:0 -10px}.elfinder-ltr .elfinder-navbar-expanded .elfinder-navbar-arrow,.elfinder-rtl .elfinder-navbar-expanded .elfinder-navbar-arrow{background-position:0 -21px}.elfinder-navbar-icon{width:16px;height:16px;background-image:url(../img/toolbar.png);background-position:0 -16px}.elfinder-ltr .elfinder-navbar-icon{left:14px}.elfinder-rtl .elfinder-navbar-icon{right:14px}.elfinder-places .elfinder-navbar-root .elfinder-navbar-icon{background-position:0 -704px}.elfinder-tree .elfinder-navbar-root-box .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-dropbox .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-ftp .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-googledrive .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-local .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-network .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-onedrive .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-sql .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-trash .elfinder-navbar-icon,.elfinder-tree .elfinder-navbar-root-zip .elfinder-navbar-icon{background-position:0 0;background-size:contain}.elfinder-tree .elfinder-navbar-root-local .elfinder-navbar-icon{background-image:url(../img/volume_icon_local.svg);background-image:url(../img/volume_icon_local.png) \9}.elfinder-tree .elfinder-navbar-root-trash .elfinder-navbar-icon{background-image:url(../img/volume_icon_trash.svg);background-image:url(../img/volume_icon_trash.png) \9}.elfinder-tree .elfinder-navbar-root-ftp .elfinder-navbar-icon{background-image:url(../img/volume_icon_ftp.svg);background-image:url(../img/volume_icon_ftp.png) \9}.elfinder-tree .elfinder-navbar-root-sql .elfinder-navbar-icon{background-image:url(../img/volume_icon_sql.svg);background-image:url(../img/volume_icon_sql.png) \9}.elfinder-tree .elfinder-navbar-root-dropbox .elfinder-navbar-icon{background-image:url(../img/volume_icon_dropbox.svg);background-image:url(../img/volume_icon_dropbox.png) \9}.elfinder-tree .elfinder-navbar-root-googledrive .elfinder-navbar-icon{background-image:url(../img/volume_icon_googledrive.svg);background-image:url(../img/volume_icon_googledrive.png) \9}.elfinder-tree .elfinder-navbar-root-onedrive .elfinder-navbar-icon{background-image:url(../img/volume_icon_onedrive.svg);background-image:url(../img/volume_icon_onedrive.png) \9}.elfinder-tree .elfinder-navbar-root-box .elfinder-navbar-icon{background-image:url(../img/volume_icon_box.svg);background-image:url(../img/volume_icon_box.png) \9}.elfinder-tree .elfinder-navbar-root-zip .elfinder-navbar-icon{background-image:url(../img/volume_icon_zip.svg);background-image:url(../img/volume_icon_zip.png) \9}.elfinder-tree .elfinder-navbar-root-network .elfinder-navbar-icon{background-image:url(../img/volume_icon_network.svg);background-image:url(../img/volume_icon_network.png) \9}.elfinder-droppable-active .elfinder-navbar-icon,.ui-state-active .elfinder-navbar-icon,.ui-state-hover .elfinder-navbar-icon{background-position:0 -32px}.elfinder-ltr .elfinder-navbar-subtree{margin-left:12px}.elfinder-rtl .elfinder-navbar-subtree{margin-right:12px}.elfinder-tree .elfinder-spinner{position:absolute;top:50%;margin:-7px 0 0}.elfinder-ltr .elfinder-tree .elfinder-spinner{left:0;margin-left:-2px}.elfinder-rtl .elfinder-tree .elfinder-spinner{right:0;margin-right:-2px}.elfinder-navbar .elfinder-lock,.elfinder-navbar .elfinder-perms,.elfinder-navbar .elfinder-symlink{opacity:.6;filter:Alpha(Opacity=60)}.elfinder-navbar .elfinder-perms{bottom:-1px;margin-top:-8px}.elfinder-navbar .elfinder-lock{top:-2px}.elfinder-ltr .elfinder-navbar .elfinder-perms{left:20px;transform:scale(.8)}.elfinder-rtl .elfinder-navbar .elfinder-perms{right:20px;transform:scale(.8)}.elfinder-ltr .elfinder-navbar .elfinder-lock{left:20px;transform:scale(.8)}.elfinder-rtl .elfinder-navbar .elfinder-lock{right:20px;transform:scale(.8)}.elfinder-ltr .elfinder-navbar .elfinder-symlink{left:8px;transform:scale(.8)}.elfinder-rtl .elfinder-navbar .elfinder-symlink{right:8px;transform:scale(.8)}.elfinder-navbar input{width:100%;border:0 solid;margin:0;padding:0}.elfinder-navbar .ui-resizable-handle{width:12px;background:url(../img/resize.png) center center no-repeat}.elfinder-nav-handle-icon{position:absolute;top:50%;margin:-8px 2px 0;opacity:.5;filter:Alpha(Opacity=50)}.elfinder-navbar-pager{width:100%;box-sizing:border-box;padding-top:3px;padding-bottom:3px}.elfinder-touch .elfinder-navbar-pager{padding-top:10px;padding-bottom:10px}.elfinder-places{border:none;margin:0;padding:0}.elfinder-navbar-swipe-handle{position:absolute;top:0;height:100%;width:50px;pointer-events:none}.elfinder-ltr .elfinder-navbar-swipe-handle{left:0;background:linear-gradient(to right,#dde4eb 0,rgba(221,228,235,.8) 5px,rgba(216,223,230,.3) 8px,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%)}.elfinder-rtl .elfinder-navbar-swipe-handle{right:0;background:linear-gradient(to left,#dde4eb 0,rgba(221,228,235,.8) 5px,rgba(216,223,230,.3) 8px,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%)}.elfinder-navbar-root .elfinder-places-root-icon{position:absolute;top:50%;margin-top:-9px;cursor:pointer}.elfinder-ltr .elfinder-places-root-icon{right:10px}.elfinder-rtl .elfinder-places-root-icon{left:10px}.elfinder-navbar-expanded .elfinder-places-root-icon{display:block}.elfinder-place-drag{font-size:.8em}.elfinder-quicklook{position:absolute;background:url(../img/quicklook-bg.png);overflow:hidden;-moz-border-radius:7px;-webkit-border-radius:7px;border-radius:7px;padding:20px 0 40px}.elfinder-navdock .elfinder-quicklook{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;font-size:90%;overflow:auto}.elfinder-quicklook.elfinder-touch{padding:30px 0 40px}.elfinder-quicklook .ui-resizable-se{width:14px;height:14px;right:5px;bottom:3px;background:url(../img/toolbar.png) 0 -496px no-repeat}.elfinder-quicklook.elfinder-touch .ui-resizable-se{-moz-transform-origin:bottom right;-moz-transform:scale(1.5);zoom:1.5}.elfinder-quicklook.elfinder-quicklook-fullscreen{position:fixed;top:0;right:0;bottom:0;left:0;margin:0;box-sizing:border-box;width:100%;height:100%;object-fit:contain;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;-webkit-background-clip:padding-box;padding:0;background:#000;display:block}.elfinder-quicklook-fullscreen .elfinder-quicklook-titlebar,.elfinder-quicklook-fullscreen.elfinder-quicklook .ui-resizable-handle{display:none}.elfinder-quicklook-fullscreen .elfinder-quicklook-preview{border:0 solid}.elfinder-quicklook-cover,.elfinder-quicklook-titlebar{width:100%;height:100%;top:0;left:0;position:absolute}.elfinder-quicklook-cover.elfinder-quicklook-coverbg{background-color:#fff;opacity:.000001;filter:Alpha(Opacity=.0001)}.elfinder-quicklook-titlebar{text-align:center;background:#777;height:20px;-moz-border-radius-topleft:7px;-webkit-border-top-left-radius:7px;border-top-left-radius:7px;-moz-border-radius-topright:7px;-webkit-border-top-right-radius:7px;border-top-right-radius:7px;border:none;line-height:1.2}.elfinder-navdock .elfinder-quicklook-titlebar{-moz-border-radius-topleft:0;-webkit-border-top-left-radius:0;border-top-left-radius:0;-moz-border-radius-topright:0;-webkit-border-top-right-radius:0;border-top-right-radius:0;cursor:default}.elfinder-touch .elfinder-quicklook-titlebar{height:30px}.elfinder-quicklook-title{display:inline-block;white-space:nowrap;overflow:hidden}.elfinder-touch .elfinder-quicklook-title{padding:8px 0}.elfinder-quicklook-titlebar-icon{position:absolute;left:4px;top:50%;margin-top:-8px;height:16px;border:none}.elfinder-touch .elfinder-quicklook-titlebar-icon{height:22px}.elfinder-quicklook-titlebar-icon .ui-icon{position:relative;margin:-9px 3px 0 0;cursor:pointer;border-radius:10px;border:1px solid;opacity:.7;filter:Alpha(Opacity=70)}.elfinder-quicklook-titlebar-icon .ui-icon.ui-icon-closethick{padding-left:1px}.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon{opacity:.6;filter:Alpha(Opacity=60)}.elfinder-touch .elfinder-quicklook-titlebar-icon .ui-icon{margin-top:-5px}.elfinder-quicklook-titlebar-icon.elfinder-titlebar-button-right{left:auto;right:4px;direction:rtl}.elfinder-quicklook-titlebar-icon.elfinder-titlebar-button-right .ui-icon{margin:-9px 0 0 3px}.elfinder-touch .elfinder-quicklook-titlebar .ui-icon{-moz-transform-origin:center center;-moz-transform:scale(1.2);zoom:1.2}.elfinder-touch .elfinder-quicklook-titlebar-icon .ui-icon{margin-right:10px}.elfinder-quicklook-preview{overflow:hidden;position:relative;border:0 solid;border-left:1px solid transparent;border-right:1px solid transparent;height:100%}.elfinder-navdock .elfinder-quicklook-preview{border-left:0;border-right:0}.elfinder-quicklook-preview.elfinder-overflow-auto{overflow:auto;-webkit-overflow-scrolling:touch}.elfinder-quicklook-info-wrapper{display:table;position:absolute;width:100%;height:100%;height:calc(100% - 80px);left:0;top:20px}.elfinder-navdock .elfinder-quicklook-info-wrapper{height:calc(100% - 20px)}.elfinder-quicklook-info{display:table-cell;vertical-align:middle}.elfinder-ltr .elfinder-quicklook-info{padding:0 12px 0 112px}.elfinder-rtl .elfinder-quicklook-info{padding:0 112px 0 12px}.elfinder-ltr .elfinder-navdock .elfinder-quicklook-info{padding:0 0 0 80px}.elfinder-rtl .elfinder-navdock .elfinder-quicklook-info{padding:0 80px 0 0}.elfinder-quicklook-info .elfinder-quicklook-info-data:first-child{color:#fff;font-weight:700;padding-bottom:.5em}.elfinder-quicklook-info-data{clear:both;padding-bottom:.2em;color:#fff}.elfinder-quicklook-info-progress{width:0;height:4px;border-radius:2px}.elfinder-quicklook .elfinder-cwd-icon{position:absolute;left:32px;top:50%;margin-top:-20px}.elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon{left:16px}.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon{left:auto;right:32px}.elfinder-rtl .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon{right:6px}.elfinder-quicklook .elfinder-cwd-icon:before{top:-10px}.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:before{left:-20px}.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:before{left:-14px}.elfinder-ltr .elfinder-quicklook .elfinder-cwd-icon:after{left:-42px}.elfinder-ltr .elfinder-navdock .elfinder-quicklook .elfinder-cwd-icon:after{left:-12px}.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:before{left:auto;right:40px}.elfinder-rtl .elfinder-quicklook .elfinder-cwd-icon:after{left:auto;right:42px}.elfinder-quicklook-preview>div>canvas,.elfinder-quicklook-preview>img{display:block;margin:auto}.elfinder-quicklook-navbar{position:absolute;left:50%;bottom:4px;width:140px;height:32px;padding:0;margin-left:-70px;border:1px solid transparent;border-radius:19px;-moz-border-radius:19px;-webkit-border-radius:19px}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar{width:188px;margin-left:-94px;padding:5px;border:1px solid #eee;background:#000;opacity:.4;filter:Alpha(Opacity=40)}.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-icon-close,.elfinder-quicklook-fullscreen .elfinder-quicklook-navbar-separator{display:inline}.elfinder-quicklook-navbar-icon{width:32px;height:32px;margin:0 7px;float:left;background:url(../img/quicklook-icons.png) 0 0 no-repeat}.elfinder-quicklook-navbar-icon-fullscreen{background-position:0 -64px}.elfinder-quicklook-navbar-icon-fullscreen-off{background-position:0 -96px}.elfinder-quicklook-navbar-icon-prev{background-position:0 0}.elfinder-quicklook-navbar-icon-next{background-position:0 -32px}.elfinder-quicklook-navbar-icon-close{background-position:0 -128px;display:none}.elfinder-quicklook-navbar-separator{width:1px;height:32px;float:left;border-left:1px solid #fff;display:none}.elfinder-quicklook-encoding{height:40px}.elfinder-quicklook-encoding>select{color:#fff;background:#000;border:0;font-size:12px;max-width:100px;display:inline-block;position:relative;top:6px;left:5px}.elfinder-navdock .elfinder-quicklook .elfinder-quicklook-encoding,.elfinder-statusbar:after,.elfinder-statusbar:before{display:none}.elfinder-quicklook-preview-archive-wrapper,.elfinder-quicklook-preview-text-wrapper{width:100%;height:100%;background:#fff;color:#222;overflow:auto;-webkit-overflow-scrolling:touch}.elfinder-quicklook-preview-archive-wrapper{font-size:90%}.elfinder-quicklook-preview-archive-wrapper strong{padding:0 5px}pre.elfinder-quicklook-preview-text,pre.elfinder-quicklook-preview-text.prettyprint{width:auto;height:auto;margin:0;padding:3px 9px;border:none;overflow:visible;-o-tab-size:4;-moz-tab-size:4;tab-size:4}.elfinder-quicklook-preview-charsleft hr{border:none;border-top:dashed 1px}.elfinder-quicklook-preview-charsleft span{font-size:90%;font-style:italic;cursor:pointer}.elfinder-quicklook-preview-html,.elfinder-quicklook-preview-iframe,.elfinder-quicklook-preview-pdf{width:100%;height:100%;background:#fff;margin:0;border:none;display:block}.elfinder-quicklook-preview-flash{width:100%;height:100%}.elfinder-quicklook-preview-audio{width:100%;position:absolute;bottom:0;left:0}embed.elfinder-quicklook-preview-audio{height:30px;background:0 0}.elfinder-quicklook-preview-video{width:100%;height:100%}.elfinder-quicklook-preview .vjs-error .vjs-error-display .vjs-modal-dialog-content{font-size:12pt;padding:0;color:#fff}.elfinder .elfinder-quicklook .elfinder-quicklook-info *,.elfinder .elfinder-quicklook .elfinder-quicklook-preview *{-webkit-user-select:auto;-moz-user-select:text;-khtml-user-select:text;user-select:text}.elfinder-statusbar{display:flex;justify-content:space-between;cursor:default;text-align:center;font-weight:400;padding:.2em .5em;border-right:0 solid transparent;border-bottom:0 solid transparent;border-left:0 solid transparent}.elfinder-path,.elfinder-statusbar span{overflow:hidden;text-overflow:ellipsis;-o-text-overflow:ellipsis}.elfinder-statusbar span{vertical-align:bottom}.elfinder-statusbar span.elfinder-path-other{flex-shrink:0;text-overflow:clip;-o-text-overflow:clip}.elfinder-statusbar span.ui-state-active,.elfinder-statusbar span.ui-state-hover{border:none}.elfinder-statusbar span.elfinder-path-cwd{cursor:default}.elfinder-path{display:flex;order:1;flex-grow:1;cursor:pointer;white-space:nowrap;max-width:30%\9}.elfinder-ltr .elfinder-path{text-align:left;float:left\9}.elfinder-rtl .elfinder-path{text-align:right;float:right\9}.elfinder-workzone-path{position:relative}.elfinder-workzone-path .elfinder-path{position:relative;font-size:.75em;font-weight:400;float:none;max-width:none;overflow:hidden;overflow-x:hidden;text-overflow:initial;-o-text-overflow:initial}.elfinder-mobile .elfinder-workzone-path .elfinder-path{overflow:auto;overflow-x:scroll}.elfinder-ltr .elfinder-workzone-path .elfinder-path{margin-left:24px}.elfinder-rtl .elfinder-workzone-path .elfinder-path{margin-right:24px}.elfinder-workzone-path .elfinder-path span{display:inline-block;padding:5px 3px}.elfinder-workzone-path .elfinder-path span.elfinder-path-cwd{font-weight:700}.elfinder-workzone-path .elfinder-path span.ui-state-active,.elfinder-workzone-path .elfinder-path span.ui-state-hover{border:none}.elfinder-workzone-path .elfinder-path-roots{position:absolute;top:0;width:24px;height:20px;padding:2px;border:none;overflow:hidden}.elfinder-ltr .elfinder-workzone-path .elfinder-path-roots{left:0}.elfinder-rtl .elfinder-workzone-path .elfinder-path-roots{right:0}.elfinder-stat-size{order:3;flex-grow:1;overflow:hidden;white-space:nowrap}.elfinder-ltr .elfinder-stat-size{text-align:right;float:right\9}.elfinder-rtl .elfinder-stat-size{text-align:left;float:left\9}.elfinder-stat-selected{order:2;margin:0 .5em;white-space:nowrap;overflow:hidden}.elfinder .elfinder-toast{position:absolute;top:12px;right:12px;max-width:90%;cursor:default}.elfinder .elfinder-toast>div{position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:8px 16px 8px 50px;-moz-border-radius:3px 3px 3px 3px;-webkit-border-radius:3px 3px 3px 3px;border-radius:3px 3px 3px 3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.9;filter:alpha(opacity=90);background-color:#030303;text-align:center}.elfinder .elfinder-toast>.toast-info{background-color:#2f96b4;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}.elfinder .elfinder-toast>.toast-error{background-color:#bd362f;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}.elfinder .elfinder-toast>.toast-success{background-color:#51a351;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}.elfinder .elfinder-toast>.toast-warning{background-color:#f89406;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}.elfinder .elfinder-toast>div button.ui-button{background-image:none;margin-top:8px;padding:.5em .8em}.elfinder .elfinder-toast>.toast-success button.ui-button{background-color:green;color:#fff}.elfinder .elfinder-toast>.toast-success button.ui-button.ui-state-hover{background-color:#add6ad;color:#254b25}.elfinder .elfinder-toast>.toast-info button.ui-button{background-color:#046580;color:#fff}.elfinder .elfinder-toast>.toast-info button.ui-button.ui-state-hover{background-color:#7dc6db;color:#046580}.elfinder .elfinder-toast>.toast-warning button.ui-button{background-color:#dd8c1a;color:#fff}.elfinder .elfinder-toast>.toast-warning button.ui-button.ui-state-hover{background-color:#e7ae5e;color:#422a07}.elfinder-toolbar{padding:4px 0 3px;border-left:0 solid transparent;border-top:0 solid transparent;border-right:0 solid transparent;max-height:50%;overflow-y:auto}.elfinder-buttonset{margin:1px 4px;float:left;background:0 0;padding:0;overflow:hidden}.elfinder .elfinder-button{min-width:16px;height:16px;margin:0;padding:4px;float:left;overflow:hidden;position:relative;border:0 solid;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;line-height:1;cursor:default}.elfinder-rtl .elfinder-button{float:right}.elfinder-touch .elfinder-button{min-width:20px;height:20px}.elfinder .ui-icon-search{cursor:pointer}.elfinder-toolbar-button-separator{float:left;padding:0;height:24px;border-top:0 solid;border-right:0 solid;border-bottom:0 solid;width:0}.elfinder-rtl .elfinder-toolbar-button-separator{float:right}.elfinder-touch .elfinder-toolbar-button-separator{height:28px}.elfinder .elfinder-button.ui-state-disabled{opacity:1;filter:Alpha(Opacity=100)}.elfinder .elfinder-button.ui-state-disabled .elfinder-button-icon,.elfinder .elfinder-button.ui-state-disabled .elfinder-button-text{opacity:.4;filter:Alpha(Opacity=40)}.elfinder-rtl .elfinder-buttonset{float:right}.elfinder-button-icon{width:16px;height:16px;display:inline-block;background:url(../img/toolbar.png) no-repeat}.elfinder-button-text{position:relative;display:inline-block;top:-4px;margin:0 2px;font-size:12px}.elfinder-touch .elfinder-button-icon{transform:scale(1.25);transform-origin:top left}.elfinder-rtl.elfinder-touch .elfinder-button-icon{transform-origin:top right}.elfinder-touch .elfinder-button-text{transform:translate(3px,3px);top:-5px}.elfinder-rtl.elfinder-touch .elfinder-button-text{transform:translate(-3px,3px)}.elfinder-touch .elfinder-button-icon.elfinder-contextmenu-extra-icon{transform:scale(2);transform-origin:12px 8px}.elfinder-rtl.elfinder-touch .elfinder-button-icon.elfinder-contextmenu-extra-icon{transform-origin:4px 8px}.elfinder-button-icon-home{background-position:0 0}.elfinder-button-icon-back{background-position:0 -112px}.elfinder-button-icon-forward{background-position:0 -128px}.elfinder-button-icon-up{background-position:0 -144px}.elfinder-button-icon-dir{background-position:0 -16px}.elfinder-button-icon-opendir{background-position:0 -32px}.elfinder-button-icon-reload{background-position:0 -160px}.elfinder-button-icon-open{background-position:0 -176px}.elfinder-button-icon-mkdir{background-position:0 -192px}.elfinder-button-icon-mkfile{background-position:0 -208px}.elfinder-button-icon-rm{background-position:0 -832px}.elfinder-button-icon-trash{background-position:0 -224px}.elfinder-button-icon-restore{background-position:0 -816px}.elfinder-button-icon-copy{background-position:0 -240px}.elfinder-button-icon-cut{background-position:0 -256px}.elfinder-button-icon-paste{background-position:0 -272px}.elfinder-button-icon-getfile{background-position:0 -288px}.elfinder-button-icon-duplicate{background-position:0 -304px}.elfinder-button-icon-rename{background-position:0 -320px}.elfinder-button-icon-edit{background-position:0 -336px}.elfinder-button-icon-quicklook{background-position:0 -352px}.elfinder-button-icon-upload{background-position:0 -368px}.elfinder-button-icon-download{background-position:0 -384px}.elfinder-button-icon-info{background-position:0 -400px}.elfinder-button-icon-extract{background-position:0 -416px}.elfinder-button-icon-archive{background-position:0 -432px}.elfinder-button-icon-view{background-position:0 -448px}.elfinder-button-icon-view-list{background-position:0 -464px}.elfinder-button-icon-help{background-position:0 -480px}.elfinder-button-icon-resize{background-position:0 -512px}.elfinder-button-icon-link{background-position:0 -528px}.elfinder-button-icon-search{background-position:0 -561px}.elfinder-button-icon-sort{background-position:0 -577px}.elfinder-button-icon-rotate-r{background-position:0 -625px}.elfinder-button-icon-rotate-l{background-position:0 -641px}.elfinder-button-icon-netmount{background-position:0 -688px}.elfinder-button-icon-netunmount{background-position:0 -96px}.elfinder-button-icon-places{background-position:0 -704px}.elfinder-button-icon-chmod{background-position:0 -48px}.elfinder-button-icon-accept{background-position:0 -736px}.elfinder-button-icon-menu{background-position:0 -752px}.elfinder-button-icon-colwidth{background-position:0 -768px}.elfinder-button-icon-fullscreen{background-position:0 -784px}.elfinder-button-icon-unfullscreen{background-position:0 -800px}.elfinder-button-icon-empty{background-position:0 -848px}.elfinder-button-icon-undo{background-position:0 -864px}.elfinder-button-icon-redo{background-position:0 -880px}.elfinder-button-icon-preference{background-position:0 -896px}.elfinder-button-icon-mkdirin{background-position:0 -912px}.elfinder-button-icon-selectall{background-position:0 -928px}.elfinder-button-icon-selectnone{background-position:0 -944px}.elfinder-button-icon-selectinvert{background-position:0 -960px}.elfinder-button-icon-opennew{background-position:0 -976px}.elfinder-button-icon-hide{background-position:0 -992px}.elfinder-button-icon-text{background-position:0 -1008px}.elfinder-rtl .elfinder-button-icon-back,.elfinder-rtl .elfinder-button-icon-forward,.elfinder-rtl .elfinder-button-icon-getfile,.elfinder-rtl .elfinder-button-icon-help,.elfinder-rtl .elfinder-button-icon-redo,.elfinder-rtl .elfinder-button-icon-rename,.elfinder-rtl .elfinder-button-icon-search,.elfinder-rtl .elfinder-button-icon-undo,.elfinder-rtl .elfinder-button-icon-view-list,.elfinder-rtl .ui-icon-search{-ms-transform:scale(-1,1);-webkit-transform:scale(-1,1);transform:scale(-1,1)}.elfinder-rtl.elfinder-touch .elfinder-button-icon-back,.elfinder-rtl.elfinder-touch .elfinder-button-icon-forward,.elfinder-rtl.elfinder-touch .elfinder-button-icon-getfile,.elfinder-rtl.elfinder-touch .elfinder-button-icon-help,.elfinder-rtl.elfinder-touch .elfinder-button-icon-redo,.elfinder-rtl.elfinder-touch .elfinder-button-icon-rename,.elfinder-rtl.elfinder-touch .elfinder-button-icon-search,.elfinder-rtl.elfinder-touch .elfinder-button-icon-undo,.elfinder-rtl.elfinder-touch .elfinder-button-icon-view-list,.elfinder-rtl.elfinder-touch .ui-icon-search{-ms-transform:scale(-1.25,1.25) translateX(16px);-webkit-transform:scale(-1.25,1.25) translateX(16px);transform:scale(-1.25,1.25) translateX(16px)}.elfinder .elfinder-menubutton{overflow:visible}.elfinder-button-icon-spinner{background:url(../img/spinner-mini.gif) center center no-repeat}.elfinder-button-menu{position:absolute;margin-top:24px;padding:3px 0;overflow-y:auto}.elfinder-touch .elfinder-button-menu{margin-top:30px}.elfinder-button-menu-item{white-space:nowrap;cursor:default;padding:5px 19px;position:relative}.elfinder-touch .elfinder-button-menu-item{padding:12px 19px}.elfinder-button-menu .ui-state-hover{border:0 solid}.elfinder-button-menu-item-separated{border-top:1px solid #ccc}.elfinder-button-menu-item .ui-icon{width:16px;height:16px;position:absolute;left:2px;top:50%;margin-top:-8px;display:none}.elfinder-button-menu-item-selected .ui-icon{display:block}.elfinder-button-menu-item-selected-asc .ui-icon-arrowthick-1-s,.elfinder-button-menu-item-selected-desc .ui-icon-arrowthick-1-n{display:none}.elfinder-button form{position:absolute;top:0;right:0;opacity:0;filter:Alpha(Opacity=0);cursor:pointer}.elfinder .elfinder-button form input{background:0 0;cursor:default}.elfinder .elfinder-button-search{border:0 solid;background:0 0;padding:0;margin:1px 4px;height:auto;min-height:26px;width:70px;overflow:visible}.elfinder .elfinder-button-search.ui-state-active{width:220px}.elfinder .elfinder-button-search-menu{font-size:8pt;text-align:center;width:auto;min-width:180px;position:absolute;top:30px;padding-right:5px;padding-left:5px}.elfinder-ltr .elfinder-button-search-menu{right:22px;left:auto}.elfinder-rtl .elfinder-button-search-menu{right:auto;left:22px}.elfinder-touch .elfinder-button-search-menu{top:34px}.elfinder .elfinder-button-search-menu div{margin:5px auto;display:table}.elfinder .elfinder-button-search-menu div .ui-state-hover{border:1px solid}.elfinder-ltr .elfinder-button-search{float:right;margin-right:10px}.elfinder-rtl .elfinder-button-search{float:left;margin-left:10px}.elfinder-rtl .ui-controlgroup>.ui-controlgroup-item{float:right}.elfinder-button-search input[type=text]{box-sizing:border-box;width:100%;height:26px;padding:0 20px;line-height:22px;border:1px solid #aaa;-moz-border-radius:12px;-webkit-border-radius:12px;border-radius:12px;outline:0 solid}.elfinder-button-search input::-ms-clear{display:none}.elfinder-touch .elfinder-button-search input{height:30px;line-height:28px}.elfinder-rtl .elfinder-button-search input{direction:rtl}.elfinder-button-search .ui-icon{position:absolute;height:18px;top:50%;margin:-8px 4px 0;opacity:.6;filter:Alpha(Opacity=60)}.elfinder-button-search-menu .ui-checkboxradio-icon{display:none}.elfinder-ltr .elfinder-button-search .ui-icon-search{left:0}.elfinder-ltr .elfinder-button-search .ui-icon-close,.elfinder-rtl .elfinder-button-search .ui-icon-search{right:0}.elfinder-rtl .elfinder-button-search .ui-icon-close{left:0}.elfinder-toolbar-swipe-handle{position:absolute;top:0;left:0;height:50px;width:100%;pointer-events:none;background:linear-gradient(to bottom,#dde4eb 0,rgba(221,228,235,.8) 2px,rgba(216,223,230,.3) 5px,rgba(0,0,0,.1) 95%,rgba(0,0,0,0) 100%)} \ No newline at end of file diff --git a/lib/redactor/elfinder/css/theme.css b/lib/redactor/elfinder/css/theme.css new file mode 100644 index 0000000..dde0535 --- /dev/null +++ b/lib/redactor/elfinder/css/theme.css @@ -0,0 +1,430 @@ +/** + * MacOS X like theme for elFinder. + * Required jquery ui "smoothness" theme. + * + * @author Dmitry (dio) Levashov + **/ + +/* scrollbar for Chrome and Safari */ +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-track { + border-radius: 10px; + box-shadow: inset 0 0 6px rgba(0, 0, 0, .1); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 50, 0.08); + border-radius: 10px; + box-shadow:0 0 0 1px rgba(255, 255, 255, .3); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-thumb:hover { + background-color: rgba(0, 0, 50, 0.16); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-thumb:active { + background-color: rgba(0, 0, 50, 0.24); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-corner { + background-color: transparent; +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button { + background-color: transparent; + width: 10px; + height: 10px; + border: 5px solid transparent; +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button:hover { + border: 5px solid rgba(0, 0, 50, 0.08); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button:active { + border: 5px solid rgba(0, 0, 50, 0.5); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button:single-button:vertical:decrement { + border-bottom: 8px solid rgba(0, 0, 50, 0.3); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button:single-button:vertical:increment { + border-top: 8px solid rgba(0, 0, 50, 0.3); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button:single-button:horizontal:decrement { + border-right: 8px solid rgba(0, 0, 50, 0.3); +} + +.elfinder:not(.elfinder-mobile) *::-webkit-scrollbar-button:single-button:horizontal:increment { + border-left: 8px solid rgba(0, 0, 50, 0.3); +} + +/* input textarea */ +.elfinder input, +.elfinder textarea { + color: #000; + background-color: #FFF; + border-color: #ccc; +} + +/* dialogs */ +.std42-dialog, .std42-dialog .ui-widget-content { + background-color: #ededed; + background-image: none; + background-clip: content-box; +} + +.std42-dialog.elfinder-bg-translucent { + background-color: #fff; + background-color: rgba(255, 255, 255, 0.9); +} + +.std42-dialog.elfinder-bg-translucent .ui-widget-content { + background-color: transparent; +} + +.elfinder-quicklook-title { + color: #fff; +} + +.elfinder-quicklook-titlebar-icon { + background-color: transparent; + background-image: none; +} + +.elfinder-quicklook-titlebar-icon .ui-icon { + background-color: #d4d4d4; + border-color: #8a8a8a; +} + +.elfinder-quicklook-info-progress { + background-color: gray; +} + +.std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .ui-dialog-titlebar-close .ui-icon, +.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-close:hover, +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-close { + background-color: #ff6252; + border-color: #e5695d; + background-image: url("../img/ui-icons_ffffff_256x240.png"); +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-minimize .ui-icon, +.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-minimize:hover, +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-minimize { + background-color: #ffbc00; + border-color: #e3a40b; + background-image: url("../img/ui-icons_ffffff_256x240.png"); +} + +.std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full:hover .ui-icon, +.elfinder-mobile .std42-dialog .ui-dialog-titlebar .elfinder-titlebar-full .ui-icon, +.elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-full:hover, +.elfinder-mobile .elfinder-quicklook-titlebar-icon .ui-icon.elfinder-icon-full { + background-color: #26c82f; + border-color: #13ae10; + background-image: url("../img/ui-icons_ffffff_256x240.png"); +} + +.std42-dialog .elfinder-help, +.std42-dialog .elfinder-help .ui-widget-content { + background: #fff; +} + +/* navbar */ +.elfinder .elfinder-navbar { + background: #dde4eb; +} + +.elfinder-navbar .ui-state-hover { + color: #000; + background-color: #edf1f4; + border-color: #bdcbd8; +} + +.elfinder-navbar .ui-droppable-hover { + background: transparent; +} + +.elfinder-navbar .ui-state-active { + background: #3875d7; + border-color: #3875d7; + color: #fff; +} + +.elfinder-navbar .elfinder-droppable-active { + background: #A7C6E5; +} + +/* disabled elfinder */ +.elfinder-disabled .elfinder-navbar .ui-state-active { + background: #dadada; + border-color: #aaa; + color: #777; +} + +/* workzone */ +.elfinder-workzone { + background: #fff; +} + +/* current directory */ +/* Is in trash */ +.elfinder-cwd-wrapper.elfinder-cwd-wrapper-trash { + background-color: #f0f0f0; +} + +/* selected file in "icons" view */ +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-hover, +.elfinder-cwd-view-icons .elfinder-cwd-file .ui-state-active { + background: #ccc; +} + +/* type badge in "icons" view */ +/* default */ +.elfinder-cwd-icon:before { + color: white; + background-color: #798da7; +} + +/* type */ +.elfinder-cwd-icon-text:before { + background-color: #6f99e6 +} + +.elfinder-cwd-icon-image:before { + background-color: #2ea26c +} + +.elfinder-cwd-icon-audio:before { + background-color: #7bad2a +} + +.elfinder-cwd-icon-video:before { + background-color: #322aad +} + +/* subtype */ +.elfinder-cwd-icon-x-empty:before, +.elfinder-cwd-icon-plain:before { + background-color: #719be6 +} + +.elfinder-cwd-icon-rtf:before, +.elfinder-cwd-icon-rtfd:before { + background-color: #83aae7 +} + +.elfinder-cwd-icon-pdf:before { + background-color: #db7424 +} + +.elfinder-cwd-icon-html:before { + background-color: #82bc12 +} + +.elfinder-cwd-icon-xml:before, +.elfinder-cwd-icon-css:before { + background-color: #7c7c7c +} + +.elfinder-cwd-icon-x-shockwave-flash:before { + background-color: #f43a36 +} + +.elfinder-cwd-icon-zip:before, +.elfinder-cwd-icon-x-zip:before, +.elfinder-cwd-icon-x-xz:before, +.elfinder-cwd-icon-x-7z-compressed:before, +.elfinder-cwd-icon-x-gzip:before, +.elfinder-cwd-icon-x-tar:before, +.elfinder-cwd-icon-x-bzip:before, +.elfinder-cwd-icon-x-bzip2:before, +.elfinder-cwd-icon-x-rar:before, +.elfinder-cwd-icon-x-rar-compressed:before { + background-color: #97638e +} + +.elfinder-cwd-icon-javascript:before, +.elfinder-cwd-icon-x-javascript:before, +.elfinder-cwd-icon-x-perl:before, +.elfinder-cwd-icon-x-python:before, +.elfinder-cwd-icon-x-ruby:before, +.elfinder-cwd-icon-x-sh:before, +.elfinder-cwd-icon-x-shellscript:before, +.elfinder-cwd-icon-x-c:before, +.elfinder-cwd-icon-x-csrc:before, +.elfinder-cwd-icon-x-chdr:before, +.elfinder-cwd-icon-x-c--:before, +.elfinder-cwd-icon-x-c--src:before, +.elfinder-cwd-icon-x-c--hdr:before, +.elfinder-cwd-icon-x-java:before, +.elfinder-cwd-icon-x-java-source:before, +.elfinder-cwd-icon-x-php:before { + background-color: #7c607c +} + +.elfinder-cwd-icon-msword:before, +.elfinder-cwd-icon-vnd-ms-office:before, +.elfinder-cwd-icon-vnd-ms-word:before, +.elfinder-cwd-icon-vnd-ms-word-document-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-word-template-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-document:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-wordprocessingml-template:before { + background-color: #2b569a +} + +.elfinder-cwd-icon-ms-excel:before, +.elfinder-cwd-icon-vnd-ms-excel:before, +.elfinder-cwd-icon-vnd-ms-excel-addin-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-excel-sheet-binary-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-excel-sheet-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-excel-template-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-sheet:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-spreadsheetml-template:before { + background-color: #107b10 +} + +.elfinder-cwd-icon-vnd-ms-powerpoint:before, +.elfinder-cwd-icon-vnd-ms-powerpoint-addin-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-powerpoint-presentation-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-powerpoint-slide-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-powerpoint-slideshow-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-ms-powerpoint-template-macroEnabled-12:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-presentation:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slide:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-slideshow:before, +.elfinder-cwd-icon-vnd-openxmlformats-officedocument-presentationml-template:before { + background-color: #d24625 +} + +.elfinder-cwd-icon-vnd-oasis-opendocument-chart:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-database:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-formula:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-graphics-template:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-image:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-presentation-template:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-spreadsheet-template:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-text:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-master:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-template:before, +.elfinder-cwd-icon-vnd-oasis-opendocument-text-web:before, +.elfinder-cwd-icon-vnd-openofficeorg-extension:before { + background-color: #00a500 +} + +.elfinder-cwd-icon-postscript:before { + background-color: #ff5722 +} + +/* list view*/ +.elfinder-cwd table thead td.ui-state-hover { + background: #ddd; +} + +.elfinder-cwd table tr:nth-child(odd) { + background-color: #edf3fe; +} + +.elfinder-cwd table tr { + border: 1px solid transparent; + border-top: 1px solid #fff; +} + +.elfinder-cwd .elfinder-droppable-active td { + background: #A7C6E5; +} + +.elfinder-cwd.elfinder-table-header-sticky table { + border-top-color: #fff; +} + +.elfinder-droppable-active .elfinder-cwd.elfinder-table-header-sticky table { + border-top-color: #A7C6E5; +} + +/* common selected background/color */ +.elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, +.elfinder-cwd table td.ui-state-hover, +.elfinder-button-menu .ui-state-hover { + background: #3875d7; + color: #fff; +} + +/* disabled elfinder */ +.elfinder-disabled .elfinder-cwd-view-icons .elfinder-cwd-file .elfinder-cwd-filename.ui-state-hover, +.elfinder-disabled .elfinder-cwd table td.ui-state-hover { + background: #dadada; +} + +/* statusbar */ +.elfinder .elfinder-statusbar { + color: #555; +} + +.elfinder .elfinder-statusbar a { + text-decoration: none; + color: #555; +} + +/* contextmenu */ +.elfinder-contextmenu .ui-state-active { + background: #6293df; + color: #fff; +} + +.elfinder-contextmenu .ui-state-hover { + background: #3875d7; + color: #fff; +} + +.elfinder-contextmenu .ui-state-hover .elfinder-contextmenu-arrow { + background-image: url('../img/arrows-active.png'); +} + +/* dialog */ +.elfinder .ui-dialog input:text.ui-state-hover, +.elfinder .ui-dialog textarea.ui-state-hover { + background-image: none; + background-color: inherit; +} + +.elfinder-notify-cancel .elfinder-notify-button { + background-color: #707070; + background-image: url("../img/ui-icons_ffffff_256x240.png"); +} + +.elfinder-notify-cancel .elfinder-notify-button.ui-state-hover { + background-color: #aaa; +} + +/* edit dialog */ +.elfinder-dialog-edit select.elfinder-edit-changed { + border-bottom: 2px solid #13ae10; +} + +/* tooltip */ +.ui-widget-content.elfinder-ui-tooltip { + background-color: #fff; +} + +.elfinder-ui-tooltip.ui-widget-shadow, +.elfinder .elfinder-ui-tooltip.ui-widget-shadow { + box-shadow: 2px 6px 4px -4px #cecdcd; +} + +/* progressbar */ +.elfinder-ui-progressbar { + background-color: #419bf3; +} \ No newline at end of file diff --git a/lib/redactor/elfinder/files/.gitkeep b/lib/redactor/elfinder/files/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/redactor/elfinder/files/.trash/.gitkeep b/lib/redactor/elfinder/files/.trash/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lib/redactor/elfinder/img/arrows-active.png b/lib/redactor/elfinder/img/arrows-active.png new file mode 100644 index 0000000..eab3fda Binary files /dev/null and b/lib/redactor/elfinder/img/arrows-active.png differ diff --git a/lib/redactor/elfinder/img/arrows-normal.png b/lib/redactor/elfinder/img/arrows-normal.png new file mode 100644 index 0000000..8bdeb5a Binary files /dev/null and b/lib/redactor/elfinder/img/arrows-normal.png differ diff --git a/lib/redactor/elfinder/img/crop.gif b/lib/redactor/elfinder/img/crop.gif new file mode 100644 index 0000000..cc55e8c Binary files /dev/null and b/lib/redactor/elfinder/img/crop.gif differ diff --git a/lib/redactor/elfinder/img/dialogs.png b/lib/redactor/elfinder/img/dialogs.png new file mode 100644 index 0000000..3249553 Binary files /dev/null and b/lib/redactor/elfinder/img/dialogs.png differ diff --git a/lib/redactor/elfinder/img/edit_aceeditor.png b/lib/redactor/elfinder/img/edit_aceeditor.png new file mode 100644 index 0000000..e8d5ce6 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_aceeditor.png differ diff --git a/lib/redactor/elfinder/img/edit_ckeditor.png b/lib/redactor/elfinder/img/edit_ckeditor.png new file mode 100644 index 0000000..be7e076 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_ckeditor.png differ diff --git a/lib/redactor/elfinder/img/edit_ckeditor5.png b/lib/redactor/elfinder/img/edit_ckeditor5.png new file mode 100644 index 0000000..9bb20be Binary files /dev/null and b/lib/redactor/elfinder/img/edit_ckeditor5.png differ diff --git a/lib/redactor/elfinder/img/edit_codemirror.png b/lib/redactor/elfinder/img/edit_codemirror.png new file mode 100644 index 0000000..4defa57 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_codemirror.png differ diff --git a/lib/redactor/elfinder/img/edit_creativecloud.png b/lib/redactor/elfinder/img/edit_creativecloud.png new file mode 100644 index 0000000..ab67ad9 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_creativecloud.png differ diff --git a/lib/redactor/elfinder/img/edit_onlineconvert.png b/lib/redactor/elfinder/img/edit_onlineconvert.png new file mode 100644 index 0000000..e90d3cf Binary files /dev/null and b/lib/redactor/elfinder/img/edit_onlineconvert.png differ diff --git a/lib/redactor/elfinder/img/edit_pixlreditor.png b/lib/redactor/elfinder/img/edit_pixlreditor.png new file mode 100644 index 0000000..d2e3095 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_pixlreditor.png differ diff --git a/lib/redactor/elfinder/img/edit_pixlrexpress.png b/lib/redactor/elfinder/img/edit_pixlrexpress.png new file mode 100644 index 0000000..2447ed8 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_pixlrexpress.png differ diff --git a/lib/redactor/elfinder/img/edit_simplemde.png b/lib/redactor/elfinder/img/edit_simplemde.png new file mode 100644 index 0000000..0dc676f Binary files /dev/null and b/lib/redactor/elfinder/img/edit_simplemde.png differ diff --git a/lib/redactor/elfinder/img/edit_tinymce.png b/lib/redactor/elfinder/img/edit_tinymce.png new file mode 100644 index 0000000..cc654a1 Binary files /dev/null and b/lib/redactor/elfinder/img/edit_tinymce.png differ diff --git a/lib/redactor/elfinder/img/edit_tuiimgedit.png b/lib/redactor/elfinder/img/edit_tuiimgedit.png new file mode 100644 index 0000000..f60b60a Binary files /dev/null and b/lib/redactor/elfinder/img/edit_tuiimgedit.png differ diff --git a/lib/redactor/elfinder/img/edit_zohooffice.png b/lib/redactor/elfinder/img/edit_zohooffice.png new file mode 100644 index 0000000..badecca Binary files /dev/null and b/lib/redactor/elfinder/img/edit_zohooffice.png differ diff --git a/lib/redactor/elfinder/img/editor-icons.png b/lib/redactor/elfinder/img/editor-icons.png new file mode 100644 index 0000000..8712b61 Binary files /dev/null and b/lib/redactor/elfinder/img/editor-icons.png differ diff --git a/lib/redactor/elfinder/img/icons-big.png b/lib/redactor/elfinder/img/icons-big.png new file mode 100644 index 0000000..586f912 Binary files /dev/null and b/lib/redactor/elfinder/img/icons-big.png differ diff --git a/lib/redactor/elfinder/img/icons-big.svg b/lib/redactor/elfinder/img/icons-big.svg new file mode 100644 index 0000000..56a3d76 --- /dev/null +++ b/lib/redactor/elfinder/img/icons-big.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/icons-small.png b/lib/redactor/elfinder/img/icons-small.png new file mode 100644 index 0000000..cca5d0c Binary files /dev/null and b/lib/redactor/elfinder/img/icons-small.png differ diff --git a/lib/redactor/elfinder/img/logo.png b/lib/redactor/elfinder/img/logo.png new file mode 100644 index 0000000..ea973a3 Binary files /dev/null and b/lib/redactor/elfinder/img/logo.png differ diff --git a/lib/redactor/elfinder/img/progress.gif b/lib/redactor/elfinder/img/progress.gif new file mode 100644 index 0000000..385fc57 Binary files /dev/null and b/lib/redactor/elfinder/img/progress.gif differ diff --git a/lib/redactor/elfinder/img/quicklook-bg.png b/lib/redactor/elfinder/img/quicklook-bg.png new file mode 100644 index 0000000..3566b9e Binary files /dev/null and b/lib/redactor/elfinder/img/quicklook-bg.png differ diff --git a/lib/redactor/elfinder/img/quicklook-icons.png b/lib/redactor/elfinder/img/quicklook-icons.png new file mode 100644 index 0000000..cc66cb9 Binary files /dev/null and b/lib/redactor/elfinder/img/quicklook-icons.png differ diff --git a/lib/redactor/elfinder/img/resize.png b/lib/redactor/elfinder/img/resize.png new file mode 100644 index 0000000..25b1fea Binary files /dev/null and b/lib/redactor/elfinder/img/resize.png differ diff --git a/lib/redactor/elfinder/img/spinner-mini.gif b/lib/redactor/elfinder/img/spinner-mini.gif new file mode 100644 index 0000000..ea4f8f1 Binary files /dev/null and b/lib/redactor/elfinder/img/spinner-mini.gif differ diff --git a/lib/redactor/elfinder/img/toolbar.png b/lib/redactor/elfinder/img/toolbar.png new file mode 100644 index 0000000..e31cf94 Binary files /dev/null and b/lib/redactor/elfinder/img/toolbar.png differ diff --git a/lib/redactor/elfinder/img/trashmesh.png b/lib/redactor/elfinder/img/trashmesh.png new file mode 100644 index 0000000..80a91c5 Binary files /dev/null and b/lib/redactor/elfinder/img/trashmesh.png differ diff --git a/lib/redactor/elfinder/img/tui-icon-a.svg b/lib/redactor/elfinder/img/tui-icon-a.svg new file mode 100644 index 0000000..7e1efb8 --- /dev/null +++ b/lib/redactor/elfinder/img/tui-icon-a.svg @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/tui-icon-b.svg b/lib/redactor/elfinder/img/tui-icon-b.svg new file mode 100644 index 0000000..c1ea625 --- /dev/null +++ b/lib/redactor/elfinder/img/tui-icon-b.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/tui-icon-c.svg b/lib/redactor/elfinder/img/tui-icon-c.svg new file mode 100644 index 0000000..8074cf0 --- /dev/null +++ b/lib/redactor/elfinder/img/tui-icon-c.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/tui-icon-d.svg b/lib/redactor/elfinder/img/tui-icon-d.svg new file mode 100644 index 0000000..52e6ffa --- /dev/null +++ b/lib/redactor/elfinder/img/tui-icon-d.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/ui-icons_ffffff_256x240.png b/lib/redactor/elfinder/img/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000..5d1f173 Binary files /dev/null and b/lib/redactor/elfinder/img/ui-icons_ffffff_256x240.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_box.png b/lib/redactor/elfinder/img/volume_icon_box.png new file mode 100644 index 0000000..52eaec2 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_box.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_box.svg b/lib/redactor/elfinder/img/volume_icon_box.svg new file mode 100644 index 0000000..721787e --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_box.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_dropbox.png b/lib/redactor/elfinder/img/volume_icon_dropbox.png new file mode 100644 index 0000000..db19ef1 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_dropbox.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_dropbox.svg b/lib/redactor/elfinder/img/volume_icon_dropbox.svg new file mode 100644 index 0000000..38c0968 --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_dropbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_ftp.png b/lib/redactor/elfinder/img/volume_icon_ftp.png new file mode 100644 index 0000000..e0bf129 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_ftp.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_ftp.svg b/lib/redactor/elfinder/img/volume_icon_ftp.svg new file mode 100644 index 0000000..eec3569 --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_ftp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_googledrive.png b/lib/redactor/elfinder/img/volume_icon_googledrive.png new file mode 100644 index 0000000..92c5f1f Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_googledrive.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_googledrive.svg b/lib/redactor/elfinder/img/volume_icon_googledrive.svg new file mode 100644 index 0000000..0f32b8b --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_googledrive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_local.png b/lib/redactor/elfinder/img/volume_icon_local.png new file mode 100644 index 0000000..b77d9a7 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_local.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_local.svg b/lib/redactor/elfinder/img/volume_icon_local.svg new file mode 100644 index 0000000..97d81fb --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_local.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_network.png b/lib/redactor/elfinder/img/volume_icon_network.png new file mode 100644 index 0000000..caf1f60 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_network.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_network.svg b/lib/redactor/elfinder/img/volume_icon_network.svg new file mode 100644 index 0000000..c2348c8 --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_network.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_onedrive.png b/lib/redactor/elfinder/img/volume_icon_onedrive.png new file mode 100644 index 0000000..18b97ca Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_onedrive.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_onedrive.svg b/lib/redactor/elfinder/img/volume_icon_onedrive.svg new file mode 100644 index 0000000..4a69e47 --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_onedrive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_sql.png b/lib/redactor/elfinder/img/volume_icon_sql.png new file mode 100644 index 0000000..8ac2e53 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_sql.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_sql.svg b/lib/redactor/elfinder/img/volume_icon_sql.svg new file mode 100644 index 0000000..d02adc4 --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_sql.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_trash.png b/lib/redactor/elfinder/img/volume_icon_trash.png new file mode 100644 index 0000000..551be42 Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_trash.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_trash.svg b/lib/redactor/elfinder/img/volume_icon_trash.svg new file mode 100644 index 0000000..5a9bc57 --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/img/volume_icon_zip.png b/lib/redactor/elfinder/img/volume_icon_zip.png new file mode 100644 index 0000000..39604ea Binary files /dev/null and b/lib/redactor/elfinder/img/volume_icon_zip.png differ diff --git a/lib/redactor/elfinder/img/volume_icon_zip.svg b/lib/redactor/elfinder/img/volume_icon_zip.svg new file mode 100644 index 0000000..022169e --- /dev/null +++ b/lib/redactor/elfinder/img/volume_icon_zip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/lib/redactor/elfinder/js/elFinder.options.js b/lib/redactor/elfinder/js/elFinder.options.js new file mode 100644 index 0000000..0cc3337 --- /dev/null +++ b/lib/redactor/elfinder/js/elFinder.options.js @@ -0,0 +1,343 @@ +/** + * Default elFinder config + * + * @type Object + * @autor Dmitry (dio) Levashov + */ +elFinder.prototype._options = { + /** + * Connector url. Required! + * + * @type String + */ + url : '', + + /** + * Ajax request type. + * + * @type String + * @default "get" + */ + requestType : 'get', + + /** + * Transport to send request to backend. + * Required for future extensions using websockets/webdav etc. + * Must be an object with "send" method. + * transport.send must return $.Deferred() object + * + * @type Object + * @default null + * @example + * transport : { + * init : function(elfinderInstance) { }, + * send : function(options) { + * var dfrd = $.Deferred(); + * // connect to backend ... + * return dfrd; + * }, + * upload : function(data) { + * var dfrd = $.Deferred(); + * // upload ... + * return dfrd; + * } + * + * } + **/ + transport : {}, + + /** + * Allow to drag and drop to upload files + * + * @type Boolean|String + * @default 'auto' + */ + dragUploadAllow : 'auto', + + /** + * Timeout for upload using iframe + * + * @type Number + * @default 0 - no timeout + */ + iframeTimeout : 0, + + /** + * Data to append to all requests and to upload files + * + * @type Object + * @default {} + */ + customData : {token : '42', test : 'test'}, + + /** + * Event listeners to bind on elFinder init + * + * @type Object + * @default {} + */ + handlers : {}, + + /** + * Interface language + * + * @type String + * @default "en" + */ + lang : 'en', + + /** + * Additional css class for filemanager node. + * + * @type String + */ + cssClass : '', + + /** + * Active commands list + * If some required commands will be missed here, elFinder will add its + * + * @type Array + */ + commands : [ + 'open', 'reload', 'home', 'up', 'back', 'forward', 'getfile', 'quicklook', + 'download', 'rm', 'duplicate', 'rename', 'mkdir', 'mkfile', 'upload', 'copy', + 'cut', 'paste', 'edit', 'extract', 'archive', 'search', 'info', 'view', 'help' + ], + + /** + * Commands options. + * + * @type Object + **/ + commandsOptions : { + // "getfile" command options. + getfile : { + onlyURL : true, + // allow to return multiple files info + multiple : false, + // allow to return filers info + folders : false, + // action after callback (""/"close"/"destroy") + oncomplete : '' + }, + // "upload" command options. + upload : { + ui : 'uploadbutton' + }, + // "quicklook" command options. + quicklook : { + autoplay : true, + jplayer : 'extensions/jplayer' + } + }, + + /** + * Callback for "getfile" commands. + * Required to use elFinder with WYSIWYG editors etc.. + * + * @type Function + * @default null (command not active) + */ + getFileCallback : null, + + /** + * UI plugins to load. + * Current dir ui and dialogs loads always. + * Here set not required plugins as folders tree/toolbar/statusbar etc. + * + * @type Array + * @default ['toolbar', 'places', 'tree', 'path', 'stat'] + */ + ui : ['toolbar', 'places', 'tree', 'path', 'stat'], + + /** + * Some UI plugins options. + * @type Object + */ + uiOptions : { + // toolbar configuration + toolbar : [ + ['back', 'forward'], + // ['reload'], + // ['home', 'up'], + ['mkdir', 'mkfile', 'upload'], + ['open', 'download', 'getfile'], + ['info'], + ['quicklook'], + ['copy', 'cut', 'paste'], + ['rm'], + ['duplicate', 'rename', 'edit'], + ['extract', 'archive'], + ['search'], + ['view'], + ['help'] + ], + // directories tree options + tree : { + // expand current root on init + openRootOnLoad : true, + // auto load current dir parents + syncTree : true + }, + // navbar options + navbar : { + minWidth : 150, + maxWidth : 500 + } + }, + + /** + * Display only required files by types + * + * @type Array + * @default [] + * @example + * onlyMimes : ["image"] - display all images + * onlyMimes : ["image/png", "application/x-shockwave-flash"] - display png and flash + */ + onlyMimes : [], + + /** + * How to sort files in current directory + * + * @type String + * @default "nameDirsFirst" + * @example + * - sort : 'nameDirsFirst' - sort by name, directory first + * - sort : 'kindDirsFirst' - sort by kind, name, directory first + * - sort : 'sizeDirsFirst' - sort by size, name, directory first + * - sort : 'name' - sort by name + * - sort : 'kind' - sort by kind, name + * - sort : 'size' - sort by size, name + */ + sort : 'nameDirsFirst', + + /** + * elFinder width + * + * @type String|Number + * @default "auto" + */ + width : 'auto', + + /** + * elFinder height + * + * @type Number + * @default "auto" + */ + height : 400, + + /** + * Make elFinder resizable if jquery ui resizable available + * + * @type Boolean + * @default true + */ + resizable : true, + + /** + * Timeout before open notifications dialogs + * + * @type Number + * @default 500 (.5 sec) + */ + notifyDelay : 500, + + /** + * Allow shortcuts + * + * @type Boolean + * @default true + */ + allowShortcuts : true, + + /** + * Remeber last opened dir to open it after reload or in next session + * + * @type Boolean + * @default true + */ + rememberLastDir : true, + + /** + * Lazy load config. + * How many files display at once? + * + * @type Number + * @default 50 + */ + showFiles : 30, + + /** + * Lazy load config. + * Distance in px to cwd bottom edge to start display files + * + * @type Number + * @default 50 + */ + showThreshold : 50, + + /** + * Additional rule to valid new file name. + * By default not allowed empty names or '..' + * + * @type false|RegExp|function + * @default false + * @example + * disable names with spaces: + * validName : /^[^\s]$/ + */ + validName : false, + + /** + * Sync content interval + * @todo - fix in elFinder + * @type Number + * @default 0 (do not sync) + */ + sync : 0, + + /** + * How many thumbnails create in one request + * + * @type Number + * @default 5 + */ + loadTmbs : 5, + + /** + * Cookie option for browsersdoes not suppot localStorage + * + * @type Object + */ + cookie : { + expires : 30, + domain : '', + path : '/', + secure : false + }, + + /** + * Contextmenu config + * + * @type Object + */ + contextmenu : { + // navbarfolder menu + navbar : ['open', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', '|', 'info'], + // current directory menu + cwd : ['reload', 'back', '|', 'upload', 'mkdir', 'mkfile', 'paste', '|', 'info'], + // current directory file menu + files : ['getfile', '|','open', 'quicklook', '|', 'download', '|', 'copy', 'cut', 'paste', 'duplicate', '|', 'rm', '|', 'edit', 'rename', '|', 'archive', 'extract', '|', 'info'] + }, + + /** + * Debug config + * + * @type Array|Boolean + */ + // debug : true + debug : ['error', 'warning', 'event-destroy'] +} diff --git a/lib/redactor/elfinder/js/elfinder.full.js b/lib/redactor/elfinder/js/elfinder.full.js new file mode 100644 index 0000000..b525a61 --- /dev/null +++ b/lib/redactor/elfinder/js/elfinder.full.js @@ -0,0 +1,36173 @@ +/*! + * elFinder - file manager for web + * Version 2.1.66 (2025-08-28) + * http://elfinder.org + * + * Copyright 2009-2025, Studio 42 + * Licensed under a 3-clauses BSD license + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery','jquery-ui'], factory); + } else if (typeof exports !== 'undefined') { + // CommonJS + var $, ui; + try { + $ = require('jquery'); + ui = require('jquery-ui'); + } catch (e) {} + module.exports = factory($, ui); + } else { + // Browser globals (Note: root is window) + factory(root.jQuery, root.jQuery.ui, true); + } +}(this, function($, _ui, toGlobal) { +toGlobal = toGlobal || false; + + +/* + * File: /js/elFinder.js + */ + +/** + * @class elFinder - file manager for web + * + * @author Dmitry (dio) Levashov + **/ +var elFinder = function(elm, opts, bootCallback) { + //this.time('load'); + var self = this, + + /** + * Objects array of jQuery.Deferred that calls before elFinder boot up + * + * @type Array + */ + dfrdsBeforeBootup = [], + + /** + * Plugin name to check for conflicts with bootstrap etc + * + * @type Array + **/ + conflictChecks = ['button', 'tooltip'], + + /** + * Node on which elfinder creating + * + * @type jQuery + **/ + node = $(elm), + + /** + * Object of events originally registered in this node + * + * @type Object + */ + prevEvents = $.extend(true, {}, $._data(node.get(0), 'events')), + + /** + * Store node contents. + * + * @see this.destroy + * @type jQuery + **/ + prevContent = $('

      ').append(node.contents()).attr('class', node.attr('class') || '').attr('style', node.attr('style') || ''), + + /** + * Instance ID. Required to get/set cookie + * + * @type String + **/ + id = node.attr('id') || node.attr('id', 'elfauto' + $('.elfinder').length).attr('id'), + + /** + * Events namespace + * + * @type String + **/ + namespace = 'elfinder-' + id, + + /** + * Mousedown event + * + * @type String + **/ + mousedown = 'mousedown.'+namespace, + + /** + * Keydown event + * + * @type String + **/ + keydown = 'keydown.'+namespace, + + /** + * Keypress event + * + * @type String + **/ + keypress = 'keypress.'+namespace, + + /** + * Keypup event + * + * @type String + **/ + keyup = 'keyup.'+namespace, + + /** + * Is shortcuts/commands enabled + * + * @type Boolean + **/ + enabled = false, + + /** + * Store enabled value before ajax request + * + * @type Boolean + **/ + prevEnabled = false, + + /** + * List of build-in events which mapped into methods with same names + * + * @type Array + **/ + events = ['enable', 'disable', 'load', 'open', 'reload', 'select', 'add', 'remove', 'change', 'dblclick', 'getfile', 'lockfiles', 'unlockfiles', 'selectfiles', 'unselectfiles', 'dragstart', 'dragstop', 'search', 'searchend', 'viewchange'], + + /** + * Rules to validate data from backend + * + * @type Object + **/ + rules = {}, + + /** + * Current working directory hash + * + * @type String + **/ + cwd = '', + + /** + * Current working directory options default + * + * @type Object + **/ + cwdOptionsDefault = { + path : '', + url : '', + tmbUrl : '', + disabled : [], + separator : '/', + archives : [], + extract : [], + copyOverwrite : true, + uploadOverwrite : true, + uploadMaxSize : 0, + jpgQuality : 100, + tmbCrop : false, + tmbReqCustomData : false, + tmb : false // old API + }, + + /** + * Current working directory options + * + * @type Object + **/ + cwdOptions = {}, + + /** + * Files/dirs cache + * + * @type Object + **/ + files = {}, + + /** + * Hidden Files/dirs cache + * + * @type Object + **/ + hiddenFiles = {}, + + /** + * Files/dirs hash cache of each dirs + * + * @type Object + **/ + ownFiles = {}, + + /** + * Selected files hashes + * + * @type Array + **/ + selected = [], + + /** + * Events listeners + * + * @type Object + **/ + listeners = {}, + + /** + * Shortcuts + * + * @type Object + **/ + shortcuts = {}, + + /** + * Buffer for copied files + * + * @type Array + **/ + clipboard = [], + + /** + * Copied/cuted files hashes + * Prevent from remove its from cache. + * Required for dispaly correct files names in error messages + * + * @type Object + **/ + remember = {}, + + /** + * Queue for 'open' requests + * + * @type Array + **/ + queue = [], + + /** + * Queue for only cwd requests e.g. `tmb` + * + * @type Array + **/ + cwdQueue = [], + + /** + * Commands prototype + * + * @type Object + **/ + base = new self.command(self), + + /** + * elFinder node width + * + * @type String + * @default "auto" + **/ + width = 'auto', + + /** + * elFinder node height + * Number: pixcel or String: Number + "%" + * + * @type Number | String + * @default 400 + **/ + height = 400, + + /** + * Base node object or selector + * Element which is the reference of the height percentage + * + * @type Object|String + * @default null | $(window) (if height is percentage) + **/ + heightBase = null, + + /** + * MIME type list(Associative array) handled as a text file + * + * @type Object|null + */ + textMimes = null, + + /** + * elfinder path for sound played on remove + * @type String + * @default ./sounds/ + **/ + soundPath = 'sounds/', + + /** + * JSON.stringify of previous fm.sorters + * @type String + */ + prevSorterStr = '', + + /** + * Map table of file extention to MIME-Type + * @type Object + */ + extToMimeTable, + + /** + * Disabled page unload function + * @type Boolean + */ + diableUnloadCheck = false, + + beeper = $(document.createElement('audio')).hide().appendTo('body')[0], + + syncInterval, + autoSyncStop = 0, + + uiCmdMapPrev = '', + + gcJobRes = null, + + open = function(data) { + // NOTES: Do not touch data object + + var volumeid, contextmenu, emptyDirs = {}, stayDirs = {}, + rmClass, hashes, calc, gc, collapsed, prevcwd, sorterStr, diff; + + if (self.api >= 2.1) { + // support volume driver option `uiCmdMap` + self.commandMap = (data.options.uiCmdMap && Object.keys(data.options.uiCmdMap).length)? data.options.uiCmdMap : {}; + if (uiCmdMapPrev !== JSON.stringify(self.commandMap)) { + uiCmdMapPrev = JSON.stringify(self.commandMap); + } + } else { + self.options.sync = 0; + } + + if (data.init) { + // init - reset cache + files = {}; + ownFiles = {}; + } else { + // remove only files from prev cwd + // and collapsed directory (included 100+ directories) to empty for perfomance tune in DnD + prevcwd = cwd; + rmClass = 'elfinder-subtree-loaded ' + self.res('class', 'navexpand'); + collapsed = self.res('class', 'navcollapse'); + hashes = Object.keys(files); + calc = function(i) { + if (!files[i]) { + return true; + } + + var isDir = (files[i].mime === 'directory'), + phash = files[i].phash, + pnav; + + if ( + (!isDir + || emptyDirs[phash] + || (!stayDirs[phash] + && self.navHash2Elm(files[i].hash).is(':hidden') + && self.navHash2Elm(phash).next('.elfinder-navbar-subtree').children().length > 100 + ) + ) + && (isDir || phash !== cwd) + && ! remember[i] + ) { + if (isDir && !emptyDirs[phash]) { + emptyDirs[phash] = true; + self.navHash2Elm(phash) + .removeClass(rmClass) + .next('.elfinder-navbar-subtree').empty(); + } + deleteCache(files[i]); + } else if (isDir) { + stayDirs[phash] = true; + } + }; + gc = function() { + if (hashes.length) { + gcJobRes && gcJobRes._abort(); + gcJobRes = self.asyncJob(calc, hashes, { + interval : 20, + numPerOnce : 100 + }).done(function() { + var hd = self.storage('hide') || {items: {}}; + if (Object.keys(hiddenFiles).length) { + $.each(hiddenFiles, function(h) { + if (!hd.items[h]) { + delete hiddenFiles[h]; + } + }); + } + }); + } + }; + + self.trigger('filesgc').one('filesgc', function() { + hashes = []; + }); + + self.one('opendone', function() { + if (prevcwd !== cwd) { + if (! node.data('lazycnt')) { + gc(); + } else { + self.one('lazydone', gc); + } + } + }); + } + + self.sorters = {}; + cwd = data.cwd.hash; + cache(data.files); + if (!files[cwd]) { + cache([data.cwd]); + } else { + diff = self.diff([data.cwd], true); + if (diff.changed.length) { + cache(diff.changed, 'change'); + self.change({changed: diff.changed}); + } + } + data.changed && data.changed.length && cache(data.changed, 'change'); + + // trigger event 'sorterupdate' + sorterStr = JSON.stringify(self.sorters); + if (prevSorterStr !== sorterStr) { + self.trigger('sorterupdate'); + prevSorterStr = sorterStr; + } + + self.lastDir(cwd); + + self.autoSync(); + }, + + /** + * Store info about files/dirs in "files" object. + * + * @param Array files + * @param String data type + * @return void + **/ + cache = function(data, type) { + var type = type || 'files', + keeps = ['sizeInfo', 'encoding'], + defsorter = { name: true, perm: true, date: true, size: true, kind: true }, + sorterChk = !self.sorters._checked && (type === 'files'), + l = data.length, + setSorter = function(file) { + var f = file || {}, + sorters = []; + $.each(self.sortRules, function(key) { + if (defsorter[key] || typeof f[key] !== 'undefined' || (key === 'mode' && typeof f.perm !== 'undefined')) { + sorters.push(key); + } + }); + self.sorters = self.arrayFlip(sorters, true); + self.sorters._checked = true; + }, + changedParents = {}, + hideData = self.storage('hide') || {}, + hides = hideData.items || {}, + f, i, i1, keepProp, parents, hidden; + + for (i = 0; i < l; i++) { + f = Object.assign({}, data[i]); + hidden = (!hideData.show && hides[f.hash])? true : false; + if (f.name && f.hash && f.mime) { + if (!hidden) { + if (sorterChk && f.phash === cwd) { + setSorter(f); + sorterChk = false; + } + + if (f.phash && (type === 'add' || (type === 'change' && (!files[f.hash] || f.size !== files[f.hash])))) { + if (parents = self.parents(f.phash)) { + $.each(parents, function() { + changedParents[this] = true; + }); + } + } + } + + if (files[f.hash]) { + for (i1 =0; i1 < keeps.length; i1++) { + if(files[f.hash][keeps[i1]] && ! f[keeps[i1]]) { + f[keeps[i1]] = files[f.hash][keeps[i1]]; + } + } + if (f.sizeInfo && !f.size) { + f.size = f.sizeInfo.size; + } + deleteCache(files[f.hash], true); + } + if (hides[f.hash]) { + hiddenFiles[f.hash] = f; + } + if (hidden) { + l--; + data.splice(i--, 1); + } else { + files[f.hash] = f; + if (f.mime === 'directory' && !ownFiles[f.hash]) { + ownFiles[f.hash] = {}; + } + if (f.phash) { + if (!ownFiles[f.phash]) { + ownFiles[f.phash] = {}; + } + ownFiles[f.phash][f.hash] = true; + } + } + } + } + // delete sizeInfo cache + $.each(Object.keys(changedParents), function() { + var target = files[this]; + if (target && target.sizeInfo) { + delete target.sizeInfo; + } + }); + + // for empty folder + sorterChk && setSorter(); + }, + + /** + * Delete file object from files caches + * + * @param Array removed hashes + * @return void + */ + remove = function(removed) { + var l = removed.length, + roots = {}, + rm = function(hash) { + var file = files[hash], i; + if (file) { + if (file.mime === 'directory') { + if (roots[hash]) { + delete self.roots[roots[hash]]; + } + // restore stats of deleted root parent directory + $.each(self.leafRoots, function(phash, roots) { + var idx, pdir; + if ((idx = $.inArray(hash, roots))!== -1) { + if (roots.length === 1) { + if ((pdir = Object.assign({}, files[phash])) && pdir._realStats) { + $.each(pdir._realStats, function(k, v) { + pdir[k] = v; + }); + remove(files[phash]._realStats); + self.change({ changed: [pdir] }); + } + delete self.leafRoots[phash]; + } else { + self.leafRoots[phash].splice(idx, 1); + } + } + }); + if (self.searchStatus.state < 2) { + $.each(files, function(h, f) { + f.phash == hash && rm(h); + }); + } + } + if (file.phash) { + if (parents = self.parents(file.phash)) { + $.each(parents, function() { + changedParents[this] = true; + }); + } + } + deleteCache(files[hash]); + } + }, + changedParents = {}, + parents; + + $.each(self.roots, function(k, v) { + roots[v] = k; + }); + while (l--) { + rm(removed[l]); + } + // delete sizeInfo cache + $.each(Object.keys(changedParents), function() { + var target = files[this]; + if (target && target.sizeInfo) { + delete target.sizeInfo; + } + }); + }, + + /** + * Update file object in files caches + * + * @param Array changed file objects + * @return void + * @deprecated should be use `cache(updatesArrayData, 'change');` + */ + change = function(changed) { + $.each(changed, function(i, file) { + var hash = file.hash; + if (files[hash]) { + $.each(Object.keys(files[hash]), function(i, v){ + if (typeof file[v] === 'undefined') { + delete files[hash][v]; + } + }); + } + files[hash] = files[hash] ? Object.assign(files[hash], file) : file; + }); + }, + + /** + * Delete cache data of files, ownFiles and self.optionsByHashes + * + * @param Object file + * @param Boolean update + * @return void + */ + deleteCache = function(file, update) { + var hash = file.hash, + phash = file.phash; + + if (phash && ownFiles[phash]) { + delete ownFiles[phash][hash]; + } + if (!update) { + ownFiles[hash] && delete ownFiles[hash]; + self.optionsByHashes[hash] && delete self.optionsByHashes[hash]; + } + delete files[hash]; + }, + + /** + * Maximum number of concurrent connections on request + * + * @type Number + */ + requestMaxConn, + + /** + * Current number of connections + * + * @type Number + */ + requestCnt = 0, + + /** + * Queue waiting for connection + * + * @type Array + */ + requestQueue = [], + + /** + * Current open command instance + * + * @type Object + */ + currentOpenCmd = null, + + /** + * Exec shortcut + * + * @param jQuery.Event keydown/keypress event + * @return void + */ + execShortcut = function(e) { + var code = e.keyCode, + ctrlKey = !!(e.ctrlKey || e.metaKey), + isMousedown = e.type === 'mousedown', + ddm; + + !isMousedown && (self.keyState.keyCode = code); + self.keyState.ctrlKey = ctrlKey; + self.keyState.shiftKey = e.shiftKey; + self.keyState.metaKey = e.metaKey; + self.keyState.altKey = e.altKey; + if (isMousedown) { + return; + } else if (e.type === 'keyup') { + self.keyState.keyCode = null; + return; + } + + if (enabled) { + + $.each(shortcuts, function(i, shortcut) { + if (shortcut.type == e.type + && shortcut.keyCode == code + && shortcut.shiftKey == e.shiftKey + && shortcut.ctrlKey == ctrlKey + && shortcut.altKey == e.altKey) { + e.preventDefault(); + e.stopPropagation(); + shortcut.callback(e, self); + self.debug('shortcut-exec', i+' : '+shortcut.description); + } + }); + + // prevent tab out of elfinder + if (code == $.ui.keyCode.TAB && !$(e.target).is(':input')) { + e.preventDefault(); + } + + // cancel any actions by [Esc] key + if (e.type === 'keydown' && code == $.ui.keyCode.ESCAPE) { + // copy or cut + if (! node.find('.ui-widget:visible').length) { + self.clipboard().length && self.clipboard([]); + } + // dragging + if ($.ui.ddmanager) { + ddm = $.ui.ddmanager.current; + ddm && ddm.helper && ddm.cancel(); + } + // button menus + self.toHide(node.find('.ui-widget.elfinder-button-menu.elfinder-frontmost:visible')); + // trigger keydownEsc + self.trigger('keydownEsc', e); + } + + } + }, + date = new Date(), + utc, + i18n, + inFrame = (window.parent !== window), + parentIframe = (function() { + var pifm, ifms; + if (inFrame) { + try { + ifms = $('iframe', window.parent.document); + if (ifms.length) { + $.each(ifms, function(i, ifm) { + if (ifm.contentWindow === window) { + pifm = $(ifm); + return false; + } + }); + } + } catch(e) {} + } + return pifm; + })(), + /** + * elFinder boot up function + * + * @type Function + */ + bootUp, + /** + * Original function of XMLHttpRequest.prototype.send + * + * @type Function + */ + savedXhrSend; + + // opts must be an object + if (!opts) { + opts = {}; + } + + // set UA.Angle, UA.Rotated for mobile devices + if (self.UA.Mobile) { + $(window).on('orientationchange.'+namespace, function() { + var a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0; + if (a === -90) { + a = 270; + } + self.UA.Angle = a; + self.UA.Rotated = a % 180 === 0? false : true; + }).trigger('orientationchange.'+namespace); + } + + // check opt.bootCallback + if (opts.bootCallback && typeof opts.bootCallback === 'function') { + (function() { + var func = bootCallback, + opFunc = opts.bootCallback; + bootCallback = function(fm, extraObj) { + func && typeof func === 'function' && func.call(this, fm, extraObj); + opFunc.call(this, fm, extraObj); + }; + })(); + } + delete opts.bootCallback; + + /** + * Protocol version + * + * @type String + **/ + this.api = null; + + /** + * elFinder use new api + * + * @type Boolean + **/ + this.newAPI = false; + + /** + * elFinder use old api + * + * @type Boolean + **/ + this.oldAPI = false; + + /** + * Net drivers names + * + * @type Array + **/ + this.netDrivers = []; + + /** + * Base URL of elfFinder library starting from Manager HTML + * + * @type String + */ + this.baseUrl = ''; + + /** + * Base URL of i18n js files + * baseUrl + "js/i18n/" when empty value + * + * @type String + */ + this.i18nBaseUrl = ''; + + /** + * Base URL of worker js files + * baseUrl + "js/worker/" when empty value + * + * @type String + */ + this.workerBaseUrl = ''; + + /** + * Is elFinder CSS loaded + * + * @type Boolean + */ + this.cssloaded = false; + + /** + * Current theme object + * + * @type Object|Null + */ + this.theme = null; + + this.mimesCanMakeEmpty = {}; + + /** + * Callback function at boot up that option specified at elFinder starting + * + * @type Function + */ + this.bootCallback; + + /** + * Callback function at reload(restart) elFinder + * + * @type Function + */ + this.reloadCallback; + + /** + * ID. Required to create unique cookie name + * + * @type String + **/ + this.id = id; + + /** + * Method to store/fetch data + * + * @type Function + **/ + this.storage = (function() { + try { + if ('localStorage' in window && window.localStorage !== null) { + if (self.UA.Safari) { + // check for Mac/iOS safari private browsing mode + window.localStorage.setItem('elfstoragecheck', 1); + window.localStorage.removeItem('elfstoragecheck'); + } + return self.localStorage; + } else { + return self.cookie; + } + } catch (e) { + return self.cookie; + } + })(); + + /** + * Set pause page unload check function or Get state + * + * @param Boolean state To set state + * @param Boolean keep Keep disabled + * @return Boolean|void + */ + this.pauseUnloadCheck = function(state, keep) { + if (typeof state === 'undefined') { + return diableUnloadCheck; + } else { + diableUnloadCheck = !!state; + if (state && !keep) { + requestAnimationFrame(function() { + diableUnloadCheck = false; + }); + } + } + }; + + /** + * Configuration options + * + * @type Object + **/ + //this.options = $.extend(true, {}, this._options, opts); + this.options = Object.assign({}, this._options); + + // for old type configuration + if (opts.uiOptions) { + if (opts.uiOptions.toolbar && Array.isArray(opts.uiOptions.toolbar)) { + if ($.isPlainObject(opts.uiOptions.toolbar[opts.uiOptions.toolbar.length - 1])) { + self.options.uiOptions.toolbarExtra = Object.assign(self.options.uiOptions.toolbarExtra || {}, opts.uiOptions.toolbar.pop()); + } + } + } + + // Overwrite if opts value is an array + (function() { + var arrOv = function(obj, base) { + if ($.isPlainObject(obj)) { + $.each(obj, function(k, v) { + if ($.isPlainObject(v)) { + if (!base[k]) { + base[k] = {}; + } + arrOv(v, base[k]); + } else { + base[k] = v; + } + }); + } + }; + arrOv(opts, self.options); + })(); + + // join toolbarExtra to toolbar + this.options.uiOptions.toolbar.push(this.options.uiOptions.toolbarExtra); + delete this.options.uiOptions.toolbarExtra; + + /** + * Arrays that has to unbind events + * + * @type Object + */ + this.toUnbindEvents = {}; + + /** + * Attach listener to events + * To bind to multiply events at once, separate events names by space + * + * @param String event(s) name(s) + * @param Object event handler or {done: handler} + * @param Boolean priority first + * @return elFinder + */ + this.bind = function(event, callback, priorityFirst) { + var i, len; + + if (callback && (typeof callback === 'function' || typeof callback.done === 'function')) { + event = ('' + event).toLowerCase().replace(/^\s+|\s+$/g, '').split(/\s+/); + + len = event.length; + for (i = 0; i < len; i++) { + if (listeners[event[i]] === void(0)) { + listeners[event[i]] = []; + } + listeners[event[i]][priorityFirst? 'unshift' : 'push'](callback); + } + } + return this; + }; + + /** + * Remove event listener if exists + * To un-bind to multiply events at once, separate events names by space + * + * @param String event(s) name(s) + * @param Function callback + * @return elFinder + */ + this.unbind = function(event, callback) { + var i, len, l, ci; + + event = ('' + event).toLowerCase().split(/\s+/); + + len = event.length; + for (i = 0; i < len; i++) { + if (l = listeners[event[i]]) { + ci = $.inArray(callback, l); + ci > -1 && l.splice(ci, 1); + } + } + + callback = null; + return this; + }; + + /** + * Fire event - send notification to all event listeners + * In the callback `this` becames an event object + * + * @param String event type + * @param Object data to send across event + * @param Boolean allow modify data (call by reference of data) default: true + * @return elFinder + */ + this.trigger = function(evType, data, allowModify) { + var type = evType.toLowerCase(), + isopen = (type === 'open'), + dataIsObj = (typeof data === 'object'), + handlers = listeners[type] || [], + dones = [], + i, l, jst, event; + + this.debug('event-'+type, data); + + if (! dataIsObj || typeof allowModify === 'undefined') { + allowModify = true; + } + if (l = handlers.length) { + event = $.Event(type); + if (data) { + data._getEvent = function() { + return event; + }; + } + if (allowModify) { + event.data = data; + } + + for (i = 0; i < l; i++) { + if (! handlers[i]) { + // probably un-binded this handler + continue; + } + + // handler is $.Deferred(), call all functions upon completion + if (handlers[i].done) { + dones.push(handlers[i].done); + continue; + } + + // set `event.data` only callback has argument + if (handlers[i].length) { + if (!allowModify) { + // to avoid data modifications. remember about "sharing" passing arguments in js :) + if (typeof jst === 'undefined') { + try { + jst = JSON.stringify(data); + } catch(e) { + jst = false; + } + } + event.data = jst? JSON.parse(jst) : data; + } + } + + try { + if (handlers[i].call(event, event, this) === false || event.isDefaultPrevented()) { + this.debug('event-stoped', event.type); + break; + } + } catch (ex) { + window.console && window.console.log && window.console.log(ex); + } + + } + + // call done functions + if (l = dones.length) { + for (i = 0; i < l; i++) { + try { + if (dones[i].call(event, event, this) === false || event.isDefaultPrevented()) { + this.debug('event-stoped', event.type + '(done)'); + break; + } + } catch (ex) { + window.console && window.console.log && window.console.log(ex); + } + } + } + + if (this.toUnbindEvents[type] && this.toUnbindEvents[type].length) { + $.each(this.toUnbindEvents[type], function(i, v) { + self.unbind(v.type, v.callback); + }); + delete this.toUnbindEvents[type]; + } + } + return this; + }; + + /** + * Get event listeners + * + * @param String event type + * @return Array listed event functions + */ + this.getListeners = function(event) { + return event? listeners[event.toLowerCase()] : listeners; + }; + + // set fm.baseUrl + this.baseUrl = (function() { + var myTag, base, baseUrl; + + if (self.options.baseUrl) { + return self.options.baseUrl; + } else { + baseUrl = ''; + myTag = null; + $('head > script').each(function() { + if (this.src && this.src.match(/js\/elfinder(?:-[a-z0-9_-]+)?\.(?:min|full)\.js(?:$|\?)/i)) { + myTag = $(this); + return false; + } + }); + if (myTag) { + baseUrl = myTag.attr('src').replace(/js\/[^\/]+$/, ''); + if (! baseUrl.match(/^(https?\/\/|\/)/)) { + // check tag + if (base = $('head > base[href]').attr('href')) { + baseUrl = base.replace(/\/$/, '') + '/' + baseUrl; + } + } + } + if (baseUrl !== '') { + self.options.baseUrl = baseUrl; + } else { + if (! self.options.baseUrl) { + self.options.baseUrl = './'; + } + baseUrl = self.options.baseUrl; + } + return baseUrl; + } + })(); + + this.i18nBaseUrl = (this.options.i18nBaseUrl || this.baseUrl + 'js/i18n').replace(/\/$/, '') + '/'; + this.workerBaseUrl = (this.options.workerBaseUrl || this.baseUrl + 'js/worker').replace(/\/$/, '') + '/'; + + this.options.maxErrorDialogs = Math.max(1, parseInt(this.options.maxErrorDialogs || 5)); + + // set dispInlineRegex + cwdOptionsDefault.dispInlineRegex = this.options.dispInlineRegex; + + // auto load required CSS + if (this.options.cssAutoLoad) { + (function() { + var baseUrl = self.baseUrl, + myCss = $('head > link[href$="css/elfinder.min.css"],link[href$="css/elfinder.full.css"]:first').length, + rmTag = function() { + if (node.data('cssautoloadHide')) { + node.data('cssautoloadHide').remove(); + node.removeData('cssautoloadHide'); + } + }, + loaded = function() { + if (!self.cssloaded) { + rmTag(); + self.cssloaded = true; + self.trigger('cssloaded'); + } + }; + + if (! myCss) { + // to request CSS auto loading + self.cssloaded = null; + } + + // additional CSS files + if (Array.isArray(self.options.cssAutoLoad)) { + if (!self.options.themes.default) { + // set as default theme + self.options.themes = Object.assign({ + 'default' : { + 'name': 'default', + 'cssurls': self.options.cssAutoLoad + } + }, self.options.themes); + if (!self.options.theme) { + self.options.theme = 'default'; + } + } else { + if (self.cssloaded === true) { + self.loadCss(self.options.cssAutoLoad); + } else { + self.bind('cssloaded', function() { + self.loadCss(self.options.cssAutoLoad); + }); + } + } + } + + // try to load main css + if (self.cssloaded === null) { + // hide elFinder node while css loading + node.addClass('elfinder') + .data('cssautoloadHide', $('')); + $('head').append(node.data('cssautoloadHide')); + + // set default theme + if (!self.options.themes.default) { + self.options.themes = Object.assign({ + 'default' : { + 'name': 'default', + 'cssurls': 'css/theme.css', + 'author': 'elFinder Project', + 'license': '3-clauses BSD' + } + }, self.options.themes); + if (!self.options.theme) { + self.options.theme = 'default'; + } + } + + // Delay 'visibility' check it required for browsers such as Safari + requestAnimationFrame(function() { + if (node.css('visibility') === 'hidden') { + // load CSS + self.loadCss([baseUrl+'css/elfinder.min.css'], { + dfd: $.Deferred().done(function() { + loaded(); + }).fail(function() { + rmTag(); + if (!self.cssloaded) { + self.cssloaded = false; + self.bind('init', function() { + if (!self.cssloaded) { + self.error(['errRead', 'CSS (elfinder.min)']); + } + }); + } + }) + }); + } else { + loaded(); + } + }); + } + })(); + } + + // load theme if exists + (function() { + var theme, + themes = self.options.themes, + ids = Object.keys(themes || {}); + if (ids.length) { + theme = self.storage('theme') || self.options.theme; + if (!themes[theme]) { + theme = ids[0]; + } + if (self.cssloaded) { + self.changeTheme(theme); + } else { + self.bind('cssloaded', function() { + self.changeTheme(theme); + }); + } + } + })(); + + /** + * Volume option to set the properties of the root Stat + * + * @type Object + */ + this.optionProperties = { + icon: void(0), + csscls: void(0), + tmbUrl: void(0), + uiCmdMap: {}, + netkey: void(0), + disabled: [] + }; + + if (! inFrame && ! this.options.enableAlways && $('body').children().length === 2) { // only node and beeper + this.options.enableAlways = true; + } + + // make options.debug + if (this.options.debug === true) { + this.options.debug = 'all'; + } else if (Array.isArray(this.options.debug)) { + (function() { + var d = {}; + $.each(self.options.debug, function() { + d[this] = true; + }); + self.options.debug = d; + })(); + } else { + this.options.debug = false; + } + + /** + * Original functions evacuated by conflict check + * + * @type Object + */ + this.noConflicts = {}; + + /** + * Check and save conflicts with bootstrap etc + * + * @type Function + */ + this.noConflict = function() { + $.each(conflictChecks, function(i, p) { + if ($.fn[p] && typeof $.fn[p].noConflict === 'function') { + self.noConflicts[p] = $.fn[p].noConflict(); + } + }); + }; + // do check conflict + this.noConflict(); + + /** + * Is elFinder over CORS + * + * @type Boolean + **/ + this.isCORS = false; + + // configure for CORS + (function(){ + if (typeof self.options.cors !== 'undefined' && self.options.cors !== null) { + self.isCORS = self.options.cors? true : false; + } else { + var parseUrl = document.createElement('a'), + parseUploadUrl, + selfProtocol = window.location.protocol, + portReg = function(protocol) { + protocol = (!protocol || protocol === ':')? selfProtocol : protocol; + return protocol === 'https:'? /\:443$/ : /\:80$/; + }, + selfHost = window.location.host.replace(portReg(selfProtocol), ''); + parseUrl.href = opts.url; + if (opts.urlUpload && (opts.urlUpload !== opts.url)) { + parseUploadUrl = document.createElement('a'); + parseUploadUrl.href = opts.urlUpload; + } + if (selfHost !== parseUrl.host.replace(portReg(parseUrl.protocol), '') + || (parseUrl.protocol !== ':'&& parseUrl.protocol !== '' && (selfProtocol !== parseUrl.protocol)) + || (parseUploadUrl && + (selfHost !== parseUploadUrl.host.replace(portReg(parseUploadUrl.protocol), '') + || (parseUploadUrl.protocol !== ':' && parseUploadUrl.protocol !== '' && (selfProtocol !== parseUploadUrl.protocol)) + ) + ) + ) { + self.isCORS = true; + } + } + if (self.isCORS) { + if (!$.isPlainObject(self.options.customHeaders)) { + self.options.customHeaders = {}; + } + if (!$.isPlainObject(self.options.xhrFields)) { + self.options.xhrFields = {}; + } + self.options.requestType = 'post'; + self.options.customHeaders['X-Requested-With'] = 'XMLHttpRequest'; + self.options.xhrFields['withCredentials'] = true; + } + })(); + + /** + * Ajax request type + * + * @type String + * @default "get" + **/ + this.requestType = /^(get|post)$/i.test(this.options.requestType) ? this.options.requestType.toLowerCase() : 'get'; + + // set `requestMaxConn` by option + requestMaxConn = Math.max(parseInt(this.options.requestMaxConn), 1); + + /** + * Custom data that given as options + * + * @type Object + * @default {} + */ + this.optsCustomData = $.isPlainObject(this.options.customData) ? this.options.customData : {}; + + /** + * Any data to send across every ajax request + * + * @type Object + * @default {} + **/ + this.customData = Object.assign({}, this.optsCustomData); + + /** + * Previous custom data from connector + * + * @type Object|null + */ + this.prevCustomData = null; + + /** + * Any custom headers to send across every ajax request + * + * @type Object + * @default {} + */ + this.customHeaders = $.isPlainObject(this.options.customHeaders) ? this.options.customHeaders : {}; + + /** + * Any custom xhrFields to send across every ajax request + * + * @type Object + * @default {} + */ + this.xhrFields = $.isPlainObject(this.options.xhrFields) ? this.options.xhrFields : {}; + + /** + * Replace XMLHttpRequest.prototype.send to extended function for 3rd party libs XHR request etc. + * + * @type Function + */ + this.replaceXhrSend = function() { + if (! savedXhrSend) { + savedXhrSend = XMLHttpRequest.prototype.send; + } + XMLHttpRequest.prototype.send = function() { + var xhr = this; + // set request headers + if (self.customHeaders) { + $.each(self.customHeaders, function(key) { + xhr.setRequestHeader(key, this); + }); + } + // set xhrFields + if (self.xhrFields) { + $.each(self.xhrFields, function(key) { + if (key in xhr) { + xhr[key] = this; + } + }); + } + return savedXhrSend.apply(this, arguments); + }; + }; + + /** + * Restore saved original XMLHttpRequest.prototype.send + * + * @type Function + */ + this.restoreXhrSend = function() { + savedXhrSend && (XMLHttpRequest.prototype.send = savedXhrSend); + }; + + /** + * command names for into queue for only cwd requests + * these commands aborts before `open` request + * + * @type Array + * @default ['tmb', 'parents'] + */ + this.abortCmdsOnOpen = this.options.abortCmdsOnOpen || ['tmb', 'parents']; + + /** + * ui.nav id prefix + * + * @type String + */ + this.navPrefix = 'nav' + (elFinder.prototype.uniqueid? elFinder.prototype.uniqueid : '') + '-'; + + /** + * ui.cwd id prefix + * + * @type String + */ + this.cwdPrefix = elFinder.prototype.uniqueid? ('cwd' + elFinder.prototype.uniqueid + '-') : ''; + + // Increment elFinder.prototype.uniqueid + ++elFinder.prototype.uniqueid; + + /** + * URL to upload files + * + * @type String + **/ + this.uploadURL = opts.urlUpload || opts.url; + + /** + * Events namespace + * + * @type String + **/ + this.namespace = namespace; + + /** + * Today timestamp + * + * @type Number + **/ + this.today = (new Date(date.getFullYear(), date.getMonth(), date.getDate())).getTime()/1000; + + /** + * Yesterday timestamp + * + * @type Number + **/ + this.yesterday = this.today - 86400; + + utc = this.options.UTCDate ? 'UTC' : ''; + + this.getHours = 'get'+utc+'Hours'; + this.getMinutes = 'get'+utc+'Minutes'; + this.getSeconds = 'get'+utc+'Seconds'; + this.getDate = 'get'+utc+'Date'; + this.getDay = 'get'+utc+'Day'; + this.getMonth = 'get'+utc+'Month'; + this.getFullYear = 'get'+utc+'FullYear'; + + /** + * elFinder node z-index (auto detect on elFinder load) + * + * @type null | Number + **/ + this.zIndex; + + /** + * Current search status + * + * @type Object + */ + this.searchStatus = { + state : 0, // 0: search ended, 1: search started, 2: in search result + query : '', + target : '', + mime : '', + mixed : false, // in multi volumes search: false or Array that target volume ids + ininc : false // in incremental search + }; + + /** + * Interface language + * + * @type String + * @default "en" + **/ + this.lang = this.storage('lang') || this.options.lang; + if (this.lang === 'jp') { + this.lang = this.options.lang = 'ja'; + } + + this.viewType = this.storage('view') || this.options.defaultView || 'icons'; + + this.sortType = this.storage('sortType') || this.options.sortType || 'name'; + + this.sortOrder = this.storage('sortOrder') || this.options.sortOrder || 'asc'; + + this.sortStickFolders = this.storage('sortStickFolders'); + if (this.sortStickFolders === null) { + this.sortStickFolders = !!this.options.sortStickFolders; + } else { + this.sortStickFolders = !!this.sortStickFolders; + } + + this.sortAlsoTreeview = this.storage('sortAlsoTreeview'); + if (this.sortAlsoTreeview === null || this.options.sortAlsoTreeview === null) { + this.sortAlsoTreeview = !!this.options.sortAlsoTreeview; + } else { + this.sortAlsoTreeview = !!this.sortAlsoTreeview; + } + + this.sortRules = $.extend(true, {}, this._sortRules, this.options.sortRules); + + $.each(this.sortRules, function(name, method) { + if (typeof method != 'function') { + delete self.sortRules[name]; + } + }); + + this.compare = $.proxy(this.compare, this); + + /** + * Delay in ms before open notification dialog + * + * @type Number + * @default 500 + **/ + this.notifyDelay = this.options.notifyDelay > 0 ? parseInt(this.options.notifyDelay) : 500; + + /** + * Dragging UI Helper object + * + * @type jQuery | null + **/ + this.draggingUiHelper = null; + + /** + * Base droppable options + * + * @type Object + **/ + this.droppable = { + greedy : true, + tolerance : 'pointer', + accept : '.elfinder-cwd-file-wrapper,.elfinder-navbar-dir,.elfinder-cwd-file,.elfinder-cwd-filename', + hoverClass : this.res('class', 'adroppable'), + classes : { // Deprecated hoverClass jQueryUI>=1.12.0 + 'ui-droppable-hover': this.res('class', 'adroppable') + }, + autoDisable: true, // elFinder original, see jquery.elfinder.js + drop : function(e, ui) { + var dst = $(this), + targets = $.grep(ui.helper.data('files')||[], function(h) { return h? true : false; }), + result = [], + dups = [], + faults = [], + isCopy = ui.helper.hasClass('elfinder-drag-helper-plus'), + c = 'class', + cnt, hash, i, h; + + if (typeof e.button === 'undefined' || ui.helper.data('namespace') !== namespace || ! self.insideWorkzone(e.pageX, e.pageY)) { + return false; + } + if (dst.hasClass(self.res(c, 'cwdfile'))) { + hash = self.cwdId2Hash(dst.attr('id')); + } else if (dst.hasClass(self.res(c, 'navdir'))) { + hash = self.navId2Hash(dst.attr('id')); + } else { + hash = cwd; + } + + cnt = targets.length; + + while (cnt--) { + h = targets[cnt]; + // ignore drop into itself or in own location + if (h != hash && files[h].phash != hash) { + result.push(h); + } else { + ((isCopy && h !== hash && files[hash].write)? dups : faults).push(h); + } + } + + if (faults.length) { + return false; + } + + ui.helper.data('droped', true); + + if (dups.length) { + ui.helper.hide(); + self.exec('duplicate', dups, {_userAction: true}); + } + + if (result.length) { + ui.helper.hide(); + self.clipboard(result, !isCopy); + self.exec('paste', hash, {_userAction: true}, hash).always(function(){ + self.clipboard([]); + self.trigger('unlockfiles', {files : targets}); + }); + self.trigger('drop', {files : targets}); + } + } + }; + + /** + * Return true if filemanager is active + * + * @return Boolean + **/ + this.enabled = function() { + return enabled && this.visible(); + }; + + /** + * Return true if filemanager is visible + * + * @return Boolean + **/ + this.visible = function() { + return node[0].elfinder && node.is(':visible'); + }; + + /** + * Return file is root? + * + * @param Object target file object + * @return Boolean + */ + this.isRoot = function(file) { + return (file.isroot || ! file.phash)? true : false; + }; + + /** + * Return root dir hash for current working directory + * + * @param String target hash + * @param Boolean include fake parent (optional) + * @return String + */ + this.root = function(hash, fake) { + hash = hash || cwd; + var dir, i; + + if (! fake) { + $.each(self.roots, function(id, rhash) { + if (hash.indexOf(id) === 0) { + dir = rhash; + return false; + } + }); + if (dir) { + return dir; + } + } + + dir = files[hash]; + while (dir && dir.phash && (fake || ! dir.isroot)) { + dir = files[dir.phash]; + } + if (dir) { + return dir.hash; + } + + while (i in files && files.hasOwnProperty(i)) { + dir = files[i]; + if (dir.mime === 'directory' && !dir.phash && dir.read) { + return dir.hash; + } + } + + return ''; + }; + + /** + * Return current working directory info + * + * @return Object + */ + this.cwd = function() { + return files[cwd] || {}; + }; + + /** + * Return required cwd option + * + * @param String option name + * @param String target hash (optional) + * @return mixed + */ + this.option = function(name, target) { + var res, item; + target = target || cwd; + if (self.optionsByHashes[target] && typeof self.optionsByHashes[target][name] !== 'undefined') { + return self.optionsByHashes[target][name]; + } + if (self.hasVolOptions && cwd !== target && (!(item = self.file(target)) || item.phash !== cwd)) { + res = ''; + $.each(self.volOptions, function(id, opt) { + if (target.indexOf(id) === 0) { + res = opt[name] || ''; + return false; + } + }); + return res; + } else { + return cwdOptions[name] || ''; + } + }; + + /** + * Return disabled commands by each folder + * + * @param Array target hashes + * @return Array + */ + this.getDisabledCmds = function(targets, flip) { + var disabled = {'hidden': true}; + if (! Array.isArray(targets)) { + targets = [ targets ]; + } + $.each(targets, function(i, h) { + var disCmds = self.option('disabledFlip', h); + if (disCmds) { + Object.assign(disabled, disCmds); + } + }); + return flip? disabled : Object.keys(disabled); + }; + + /** + * Return file data from current dir or tree by it's hash + * + * @param String file hash + * @return Object + */ + this.file = function(hash, alsoHidden) { + return hash? (files[hash] || (alsoHidden? hiddenFiles[hash] : void(0))) : void(0); + }; + + /** + * Return all cached files + * + * @param String parent hash + * @return Object + */ + this.files = function(phash) { + var items = {}; + if (phash) { + if (!ownFiles[phash]) { + return {}; + } + $.each(ownFiles[phash], function(h) { + if (files[h]) { + items[h] = files[h]; + } else { + delete ownFiles[phash][h]; + } + }); + return Object.assign({}, items); + } + return Object.assign({}, files); + }; + + /** + * Return list of file parents hashes include file hash + * + * @param String file hash + * @return Array + */ + this.parents = function(hash) { + var parents = [], + dir; + + while (hash && (dir = this.file(hash))) { + parents.unshift(dir.hash); + hash = dir.phash; + } + return parents; + }; + + this.path2array = function(hash, i18) { + var file, + path = []; + + while (hash) { + if ((file = files[hash]) && file.hash) { + path.unshift(i18 && file.i18 ? file.i18 : file.name); + hash = file.isroot? null : file.phash; + } else { + path = []; + break; + } + } + + return path; + }; + + /** + * Return file path or Get path async with jQuery.Deferred + * + * @param Object file + * @param Boolean i18 + * @param Object asyncOpt + * @return String|jQuery.Deferred + */ + this.path = function(hash, i18, asyncOpt) { + var path = files[hash] && files[hash].path + ? files[hash].path + : this.path2array(hash, i18).join(cwdOptions.separator); + if (! asyncOpt || ! files[hash]) { + return path; + } else { + asyncOpt = Object.assign({notify: {type : 'parents', cnt : 1, hideCnt : true}}, asyncOpt); + + var dfd = $.Deferred(), + notify = asyncOpt.notify, + noreq = false, + req = function() { + self.request({ + data : {cmd : 'parents', target : files[hash].phash}, + notify : notify, + preventFail : true + }) + .done(done) + .fail(function() { + dfd.reject(); + }); + }, + done = function() { + self.one('parentsdone', function() { + path = self.path(hash, i18); + if (path === '' && noreq) { + //retry with request + noreq = false; + req(); + } else { + if (notify) { + clearTimeout(ntftm); + notify.cnt = -(parseInt(notify.cnt || 0)); + self.notify(notify); + } + dfd.resolve(path); + } + }); + }, + ntftm; + + if (path) { + return dfd.resolve(path); + } else { + if (self.ui['tree']) { + // try as no request + if (notify) { + ntftm = setTimeout(function() { + self.notify(notify); + }, self.notifyDelay); + } + noreq = true; + done(true); + } else { + req(); + } + return dfd; + } + } + }; + + /** + * Return file url if set + * + * @param String file hash + * @param Object Options + * @return String|Object of jQuery Deferred + */ + this.url = function(hash, o) { + var file = files[hash], + opts = o || {}, + async = opts.async || false, + temp = opts.temporary || false, + onetm = (opts.onetime && self.option('onetimeUrl', hash)) || false, + absurl = opts.absurl || false, + dfrd = (async || onetm)? $.Deferred() : null, + filter = function(url) { + if (url && absurl) { + url = self.convAbsUrl(url); + } + return url; + }, + getUrl = function(url) { + if (url) { + return filter(url); + } + if (file.url) { + return filter(file.url); + } + + if (typeof baseUrl === 'undefined') { + baseUrl = getBaseUrl(); + } + + if (baseUrl) { + return filter(baseUrl + $.map(self.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/')); + } + + var params = Object.assign({}, self.customData, { + cmd: 'file', + target: file.hash + }); + if (self.oldAPI) { + params.cmd = 'open'; + params.current = file.phash; + } + return filter(self.options.url + (self.options.url.indexOf('?') === -1 ? '?' : '&') + $.param(params, true)); + }, + getBaseUrl = function() { + return self.option('url', (!self.isRoot(file) && file.phash) || file.hash); + }, + baseUrl, res; + + if (!file || !file.read) { + return async? dfrd.resolve('') : ''; + } + + if (onetm && (!file.url || file.url == '1') && !(baseUrl = getBaseUrl())) { + async = true; + this.request({ + data : { cmd : 'url', target : hash, options : { onetime: 1 } }, + preventDefault : true, + options: {async: async}, + notify: {type : 'file', cnt : 1, hideCnt : true}, + progressBar: opts.progressBar + }).done(function(data) { + dfrd.resolve(filter(data.url || '')); + }).fail(function() { + dfrd.resolve(''); + }); + } else { + if (file.url == '1' || (temp && !file.url && !(baseUrl = getBaseUrl()))) { + this.request({ + data : { cmd : 'url', target : hash, options : { temporary: temp? 1 : 0 } }, + preventDefault : true, + options: {async: async}, + notify: async? {type : temp? 'file' : 'url', cnt : 1, hideCnt : true} : {}, + progressBar: opts.progressBar + }) + .done(function(data) { + file.url = data.url || ''; + }) + .fail(function() { + file.url = ''; + }) + .always(function() { + var url; + if (file.url && temp) { + url = file.url; + file.url = '1'; // restore + } + if (async) { + dfrd.resolve(getUrl(url)); + } else { + return getUrl(url); + } + }); + } else { + if (async) { + dfrd.resolve(getUrl()); + } else { + return getUrl(); + } + } + } + if (async) { + return dfrd; + } + }; + + /** + * Return file url for the extarnal service + * + * @param String hash The hash + * @param Object options The options + * @return Object jQuery Deferred + */ + this.forExternalUrl = function(hash, options) { + var onetime = self.option('onetimeUrl', hash), + opts = { + async: true, + absurl: true + }; + + opts[onetime? 'onetime' : 'temporary'] = true; + return self.url(hash, Object.assign({}, options, opts)); + }; + + /** + * Return file url for open in elFinder + * + * @param String file hash + * @param Boolean for download link + * @param Object requestOpts The request options + * @return String + */ + this.openUrl = function(hash, download, callback, requestOpts) { + var file = files[hash], + url = '', + onetimeSize = (requestOpts || {}).onetimeSize || (5 * 1024 * 1024); + + if (!file || !file.read) { + return ''; + } + + if (!download || download === 'sameorigin') { + if (file.url) { + if (file.url != 1) { + url = file.url; + } + } else if (cwdOptions.url && file.hash.indexOf(self.cwd().volumeid) === 0) { + url = cwdOptions.url + $.map(this.path2array(hash), function(n) { return encodeURIComponent(n); }).slice(1).join('/'); + } + if (!download || this.isSameOrigin(url)) { + if (url) { + url += (url.match(/\?/)? '&' : '?') + '_'.repeat((url.match(/[\?&](_+)t=/g) || ['&t=']).sort().shift().match(/[\?&](_*)t=/)[1].length + 1) + 't=' + (file.ts || parseInt(+new Date()/1000)); + if (callback) { + callback(url); + return; + } else { + return url; + } + } + } + } + + if (callback && this.hasParrotHeaders()) { + if (!requestOpts) { + requestOpts = {}; + } else { + delete requestOpts.onetimeSize; + } + if (!requestOpts.onetime && !requestOpts.temporary && file.size > onetimeSize) { + if (file.mime.match(/^video|audio/)) { + requestOpts.temporary = true; + } else { + requestOpts.onetime = true; + } + } + if (requestOpts.onetime || requestOpts.temporary) { + return this.url(file.hash, Object.assign({ + async: true + }, requestOpts)).done(function(url) { + callback(url); + }).fail(function() { + callback(''); + }); + } else { + return this.getContents(hash, 'blob', requestOpts).done(function(blob){ + url = (window.URL || window.webkitURL).createObjectURL(blob); + callback(url); + }).fail(function() { + callback(''); + }); + } + } else { + url = this.options.url; + url = url + (url.indexOf('?') === -1 ? '?' : '&') + + (this.oldAPI ? 'cmd=open¤t='+file.phash : 'cmd=file') + + '&target=' + file.hash + + '&_t=' + (file.ts || parseInt(+new Date()/1000)); + + if (download === true) { + url += '&download=1'; + } + + $.each(this.customData, function(key, val) { + url += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val); + }); + if (callback) { + callback(url); + return; + } else { + return url; + } + } + }; + + /** + * Return thumbnail url + * + * @param Object file object + * @return String + */ + this.tmb = function(file) { + var tmbUrl, tmbCrop, + cls = 'elfinder-cwd-bgurl', + url = '', + cData = {}, + n = 0; + + if ($.isPlainObject(file)) { + if (self.searchStatus.state && file.hash.indexOf(self.cwd().volumeid) !== 0) { + tmbUrl = self.option('tmbUrl', file.hash); + tmbCrop = self.option('tmbCrop', file.hash); + } else { + tmbUrl = cwdOptions.tmbUrl; + tmbCrop = cwdOptions.tmbCrop; + } + if (tmbCrop) { + cls += ' elfinder-cwd-bgurl-crop'; + } + if (tmbUrl === 'self' && file.mime.indexOf('image/') === 0) { + url = self.openUrl(file.hash); + cls += ' elfinder-cwd-bgself'; + } else if ((self.oldAPI || tmbUrl) && file && file.tmb && file.tmb != 1) { + url = tmbUrl + file.tmb; + } else if (self.newAPI && file && file.tmb && file.tmb != 1) { + url = file.tmb; + } + if (url) { + if (tmbUrl !== 'self') { + if (file.ts) { + cData._t = file.ts; + } + if (cwdOptions.tmbReqCustomData && Object.keys(this.customData).length) { + cData = Object.assign(cData, this.customData); + } + if (Object.keys(cData).length) { + url += (url.match(/\?/) ? '&' : '?'); + $.each(cData, function (key, val) { + url += ((n++ === 0)? '' : '&') + encodeURIComponent(key) + '=' + encodeURIComponent(val); + }); + } + } + return { url: url, className: cls }; + } + } + + return false; + }; + + /** + * Return selected files hashes + * + * @return Array + **/ + this.selected = function() { + return selected.slice(0); + }; + + /** + * Return selected files info + * + * @return Array + */ + this.selectedFiles = function() { + return $.map(selected, function(hash) { return files[hash] ? Object.assign({}, files[hash]) : null; }); + }; + + /** + * Return true if file with required name existsin required folder + * + * @param String file name + * @param String parent folder hash + * @return Boolean + */ + this.fileByName = function(name, phash) { + var hash; + + for (hash in files) { + if (files.hasOwnProperty(hash) && files[hash].phash == phash && files[hash].name == name) { + return files[hash]; + } + } + }; + + /** + * Valid data for required command based on rules + * + * @param String command name + * @param Object cammand's data + * @return Boolean + */ + this.validResponse = function(cmd, data) { + return data.error || this.rules[this.rules[cmd] ? cmd : 'defaults'](data); + }; + + /** + * Return bytes from ini formated size + * + * @param String ini formated size + * @return Integer + */ + this.returnBytes = function(val) { + var last; + if (isNaN(val)) { + if (! val) { + val = ''; + } + // for ex. 1mb, 1KB + val = val.replace(/b$/i, ''); + last = val.charAt(val.length - 1).toLowerCase(); + val = val.replace(/[tgmk]$/i, ''); + if (last == 't') { + val = val * 1024 * 1024 * 1024 * 1024; + } else if (last == 'g') { + val = val * 1024 * 1024 * 1024; + } else if (last == 'm') { + val = val * 1024 * 1024; + } else if (last == 'k') { + val = val * 1024; + } + val = isNaN(val)? 0 : parseInt(val); + } else { + val = parseInt(val); + if (val < 1) val = 0; + } + return val; + }; + + /** + * Process ajax request. + * Fired events : + * @todo + * @example + * @todo + * @return $.Deferred + */ + this.request = function(opts) { + var self = this, + o = this.options, + dfrd = $.Deferred(), + // request ID + reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16), + // request data + data = Object.assign({}, self.customData, {mimes : o.onlyMimes}, opts.data || opts), + // command name + cmd = data.cmd, + // request type is binary + isBinary = (opts.options || {}).dataType === 'binary', + // current cmd is "open" + isOpen = (!opts.asNotOpen && cmd === 'open'), + // the tree option is enabled (for "open" command) + isTree = (data.tree === 1), + // call default fail callback (display error dialog) ? + deffail = !(isBinary || opts.preventDefault || opts.preventFail), + // call default success callback ? + defdone = !(isBinary || opts.preventDefault || opts.preventDone), + // current progress of receive data + prog = opts.progressVal || 20, + // timer of fake progress + progTm = null, + // whether the notification dialog is currently displayed + hasNotify= false, + // options for notify dialog + notify = !opts.progressBar? (opts.notify? Object.assign({progress: prog * opts.notify.cnt}, opts.notify) : {}) : {}, + // make cancel button + cancel = !!opts.cancel, + // do not normalize data - return as is + raw = isBinary || !!opts.raw, + // sync files on request fail + syncOnFail = opts.syncOnFail, + // use lazy() + lazy = !!opts.lazy, + // prepare function before done() + prepare = opts.prepare, + // navigate option object when cmd done + navigate = opts.navigate, + // open notify dialog timeout + timeout, + // use browser cache + useCache = (opts.options || {}).cache, + // request options + options = Object.assign({ + url : o.url, + async : true, + type : this.requestType, + dataType : 'json', + cache : (self.api >= 2.1029), // api >= 2.1029 has unique request ID + data : data, + headers : this.customHeaders, + xhrFields: this.xhrFields, + progress : function(e) { + var p = e.loaded / e.total * 100; + progTm && clearTimeout(progTm); + if (opts.progressBar) { + try { + opts.progressBar.width(p + '%'); + } catch(e) {} + } else { + if (hasNotify && notify.type) { + p = p * notify.cnt; + if (prog < p) { + self.notify({ + type: notify.type, + progress: p - prog, + cnt: 0, + hideCnt: notify.hideCnt + }); + prog = p; + } + } + } + if (opts.progress) { + try { + opts.progress(e); + } catch(e) {} + } + } + }, opts.options || {}), + /** + * Default success handler. + * Call default data handlers and fire event with command name. + * + * @param Object normalized response data + * @return void + **/ + done = function(data) { + data.warning && self.error(data.warning); + + if (isOpen) { + open(data); + } else { + self.updateCache(data); + } + + self.lazy(function() { + // fire some event to update cache/ui + data.removed && data.removed.length && self.remove(data); + data.added && data.added.length && self.add(data); + data.changed && data.changed.length && self.change(data); + }).then(function() { + // fire event with command name + return self.lazy(function() { + self.trigger(cmd, data, false); + }); + }).then(function() { + // fire event with command name + 'done' + return self.lazy(function() { + self.trigger(cmd + 'done'); + }); + }).then(function() { + // make toast message + if (data.toasts && Array.isArray(data.toasts)) { + $.each(data.toasts, function() { + this.msg && self.toast(this); + }); + } + // force update content + data.sync && self.sync(); + }); + }, + /** + * Request error handler. Reject dfrd with correct error message. + * + * @param jqxhr request object + * @param String request status + * @return void + **/ + error = function(xhr, status) { + var error, data, + d = self.options.debug; + + switch (status) { + case 'abort': + error = xhr.quiet ? '' : ['errConnect', 'errAbort']; + break; + case 'timeout': + error = ['errConnect', 'errTimeout']; + break; + case 'parsererror': + error = ['errResponse', 'errDataNotJSON']; + if (xhr.responseText) { + if (! cwd || (d && (d === 'all' || d['backend-error']))) { + error.push(xhr.responseText); + } + } + break; + default: + if (xhr.responseText) { + // check responseText, Is that JSON? + try { + data = JSON.parse(xhr.responseText); + if (data && data.error) { + error = data.error; + } + } catch(e) {} + } + if (! error) { + if (xhr.status == 403) { + error = ['errConnect', 'errAccess', 'HTTP error ' + xhr.status]; + } else if (xhr.status == 404) { + error = ['errConnect', 'errNotFound', 'HTTP error ' + xhr.status]; + } else if (xhr.status >= 500) { + error = ['errResponse', 'errServerError', 'HTTP error ' + xhr.status]; + } else { + if (xhr.status == 414 && options.type === 'get') { + // retry by POST method + options.type = 'post'; + self.abortXHR(xhr); + dfrd.xhr = xhr = self.transport.send(options).fail(error).done(success); + return; + } + error = xhr.quiet ? '' : ['errConnect', 'HTTP error ' + xhr.status]; + } + } + } + + self.trigger(cmd + 'done'); + dfrd.reject({error: error}, xhr, status); + }, + /** + * Request success handler. Valid response data and reject/resolve dfrd. + * + * @param Object response data + * @param String request status + * @return void + **/ + success = function(response) { + // Set currrent request command name + self.currentReqCmd = cmd; + + response.debug && self.responseDebug(response); + + self.setCustomHeaderByXhr(xhr); + + if (raw) { + self.abortXHR(xhr); + response && response.debug && self.debug('backend-debug', response); + return dfrd.resolve(response); + } + + if (!response) { + return dfrd.reject({error :['errResponse', 'errDataEmpty']}, xhr, response); + } else if (!$.isPlainObject(response)) { + return dfrd.reject({error :['errResponse', 'errDataNotJSON']}, xhr, response); + } else if (response.error) { + if (isOpen) { + // check leafRoots + $.each(self.leafRoots, function(phash, roots) { + self.leafRoots[phash] = $.grep(roots, function(h) { return h !== data.target; }); + }); + } + return dfrd.reject({error :response.error}, xhr, response); + } + + var resolve = function() { + var pushLeafRoots = function(name) { + if (self.leafRoots[data.target] && response[name]) { + $.each(self.leafRoots[data.target], function(i, h) { + var root; + if (root = self.file(h)) { + response[name].push(root); + } + }); + } + }, + setTextMimes = function() { + self.textMimes = {}; + $.each(self.res('mimes', 'text'), function() { + self.textMimes[this.toLowerCase()] = true; + }); + }, + actionTarget; + + if (isOpen && !isTree) { + pushLeafRoots('files'); + } else if (cmd === 'tree') { + pushLeafRoots('tree'); + } + + response = self.normalize(response); + + if (!self.validResponse(cmd, response)) { + return dfrd.reject({error :(response.norError || 'errResponse')}, xhr, response); + } + + if (isOpen) { + if (!self.api) { + self.api = response.api || 1; + if (self.api == '2.0' && typeof response.options.uploadMaxSize !== 'undefined') { + self.api = '2.1'; + } + self.newAPI = self.api >= 2; + self.oldAPI = !self.newAPI; + } + + if (response.textMimes && Array.isArray(response.textMimes)) { + self.resources.mimes.text = response.textMimes; + setTextMimes(); + } + !self.textMimes && setTextMimes(); + + if (response.options) { + cwdOptions = Object.assign({}, cwdOptionsDefault, response.options); + } + + if (response.netDrivers) { + self.netDrivers = response.netDrivers; + } + + if (response.maxTargets) { + self.maxTargets = response.maxTargets; + } + + if (!!data.init) { + self.uplMaxSize = self.returnBytes(response.uplMaxSize); + self.uplMaxFile = !!response.uplMaxFile? Math.min(parseInt(response.uplMaxFile), 50) : 20; + } + } + + if (typeof prepare === 'function') { + prepare(response); + } + + if (navigate) { + actionTarget = navigate.target || 'added'; + if (response[actionTarget] && response[actionTarget].length) { + self.one(cmd + 'done', function() { + var targets = response[actionTarget], + newItems = self.findCwdNodes(targets), + inCwdHashes = function() { + var cwdHash = self.cwd().hash; + return $.map(targets, function(f) { return (f.phash && cwdHash === f.phash)? f.hash : null; }); + }, + hashes = inCwdHashes(), + makeToast = function(t) { + var node = void(0), + data = t.action? t.action.data : void(0), + cmd, msg, done; + if ((data || hashes.length) && t.action && (msg = t.action.msg) && (cmd = t.action.cmd) && (!t.action.cwdNot || t.action.cwdNot !== self.cwd().hash)) { + done = t.action.done; + data = t.action.data; + node = $('
      ') + .append( + $('') + .on('mouseenter mouseleave', function(e) { + $(this).toggleClass('ui-state-hover', e.type == 'mouseenter'); + }) + .on('click', function() { + self.exec(cmd, data || hashes, {_userAction: true, _currentType: 'toast', _currentNode: $(this) }); + if (done) { + self.one(cmd+'done', function() { + if (typeof done === 'function') { + done(); + } else if (done === 'select') { + self.trigger('selectfiles', {files : inCwdHashes()}); + } + }); + } + }) + ); + } + delete t.action; + t.extNode = node; + return t; + }; + + if (! navigate.toast) { + navigate.toast = {}; + } + + !navigate.noselect && self.trigger('selectfiles', {files : self.searchStatus.state > 1 ? $.map(targets, function(f) { return f.hash; }) : hashes}); + + if (newItems.length) { + if (!navigate.noscroll) { + newItems.first().trigger('scrolltoview', {blink : false}); + self.resources.blink(newItems, 'lookme'); + } + if ($.isPlainObject(navigate.toast.incwd)) { + self.toast(makeToast(navigate.toast.incwd)); + } + } else { + if ($.isPlainObject(navigate.toast.inbuffer)) { + self.toast(makeToast(navigate.toast.inbuffer)); + } + } + }); + } + } + + dfrd.resolve(response); + + response.debug && self.debug('backend-debug', response); + }; + self.abortXHR(xhr); + lazy? self.lazy(resolve) : resolve(); + }, + xhr, _xhr, + xhrAbort = function(e) { + if (xhr && xhr.state() === 'pending') { + self.abortXHR(xhr, { quiet: true , abort: true }); + if (!e || (e.type !== 'unload' && e.type !== 'destroy')) { + self.autoSync(); + } + } + }, + abort = function(e){ + self.trigger(cmd + 'done'); + if (e.type == 'autosync') { + if (e.data.action != 'stop') return; + } else if (e.type != 'unload' && e.type != 'destroy' && e.type != 'openxhrabort') { + if (!e.data.added || !e.data.added.length) { + return; + } + } + xhrAbort(e); + }, + request = function(mode) { + var queueAbort = function() { + syncOnFail = false; + dfrd.reject(); + }; + + if (mode) { + if (mode === 'cmd') { + return cmd; + } + } + + if (isOpen) { + if (currentOpenCmd && currentOpenCmd.state() === 'pending') { + if (currentOpenCmd._target === data.target) { + return dfrd.reject('openabort'); + } else { + if (currentOpenCmd.xhr) { + currentOpenCmd.xhr.queueAbort(); + } else { + currentOpenCmd.reject('openabort'); + } + } + } + currentOpenCmd = dfrd; + currentOpenCmd._target = data.target; + } + + dfrd.always(function() { + delete options.headers['X-elFinderReqid']; + if (isOpen) { + currentOpenCmd = null; + } + }).fail(function(error, xhr, response) { + var errData, errMsg; + + if (isOpen && error === 'openabort') { + error = ''; + syncOnFail = false; + } + + errData = { + cmd: cmd, + err: error, + xhr: xhr, + rc: response + }; + + // unset this cmd queue when user canceling + // see notify : function - `cancel.reject(0);` + if (error === 0) { + if (requestQueue.length) { + requestQueue = $.grep(requestQueue, function(req) { + return (req('cmd') === cmd) ? false : true; + }); + } + } + // trigger "requestError" event + self.trigger('requestError', errData); + if (errData._getEvent && errData._getEvent().isDefaultPrevented()) { + deffail = false; + syncOnFail = false; + if (error) { + error.error = ''; + } + } + // abort xhr + xhrAbort(); + if (isOpen) { + openDir = self.file(data.target); + openDir && openDir.volumeid && self.isRoot(openDir) && delete self.volumeExpires[openDir.volumeid]; + } + self.trigger(cmd + 'fail', response); + errMsg = (typeof error === 'object')? error.error : error; + if (errMsg) { + deffail ? self.error(errMsg) : self.debug('error', self.i18n(errMsg)); + } + syncOnFail && self.sync(); + }); + + if (!cmd) { + syncOnFail = false; + return dfrd.reject({error :'errCmdReq'}); + } + + if (self.maxTargets && data.targets && data.targets.length > self.maxTargets) { + syncOnFail = false; + return dfrd.reject({error :['errMaxTargets', self.maxTargets]}); + } + + defdone && dfrd.done(done); + + // quiet abort not completed "open" requests + if (isOpen) { + while ((_xhr = queue.pop())) { + _xhr.queueAbort(); + } + if (cwd !== data.target) { + while ((_xhr = cwdQueue.pop())) { + _xhr.queueAbort(); + } + } + } + + // trigger abort autoSync for commands to add the item + if ($.inArray(cmd, (self.cmdsToAdd + ' autosync').split(' ')) !== -1) { + if (cmd !== 'autosync') { + self.autoSync('stop'); + dfrd.always(function() { + self.autoSync(); + }); + } + self.trigger('openxhrabort'); + } + + delete options.preventFail; + + if (self.api >= 2.1029) { + if (useCache) { + options.headers['X-elFinderReqid'] = reqId; + } else { + Object.assign(options.data, { reqid : reqId }); + } + } + + // function for set value of this syncOnFail + dfrd.syncOnFail = function(state) { + syncOnFail = !!state; + }; + + requestCnt++; + + dfrd.xhr = xhr = self.transport.send(options).always(function() { + // set responseURL from native xhr object + if (options._xhr && typeof options._xhr.responseURL !== 'undefined') { + xhr.responseURL = options._xhr.responseURL || ''; + } + --requestCnt; + if (requestQueue.length) { + requestQueue.shift()(); + } + }).fail(error).done(success); + + if (self.api >= 2.1029) { + xhr._requestId = reqId; + } + + if (isOpen || (data.compare && cmd === 'info')) { + // regist function queueAbort + xhr.queueAbort = queueAbort; + // add autoSync xhr into queue + queue.unshift(xhr); + // bind abort() + data.compare && self.bind(self.cmdsToAdd + ' autosync openxhrabort', abort); + dfrd.always(function() { + var ndx = $.inArray(xhr, queue); + data.compare && self.unbind(self.cmdsToAdd + ' autosync openxhrabort', abort); + ndx !== -1 && queue.splice(ndx, 1); + }); + } else if ($.inArray(cmd, self.abortCmdsOnOpen) !== -1) { + // regist function queueAbort + xhr.queueAbort = queueAbort; + // add "open" xhr, only cwd xhr into queue + cwdQueue.unshift(xhr); + dfrd.always(function() { + var ndx = $.inArray(xhr, cwdQueue); + ndx !== -1 && cwdQueue.splice(ndx, 1); + }); + } + + // abort pending xhr on window unload or elFinder destroy + self.bind('unload destroy', abort); + dfrd.always(function() { + self.unbind('unload destroy', abort); + }); + + return dfrd; + }, + queueingRequest = function() { + // show notify + if (notify.type && notify.cnt) { + if (cancel) { + notify.cancel = dfrd; + opts.eachCancel && (notify.id = +new Date()); + } + timeout = setTimeout(function() { + // start fake count up + progTm = setTimeout(progFakeUp, 1000); + self.notify(notify); + hasNotify = true; + dfrd.always(function() { + notify.cnt = -(parseInt(notify.cnt)||0); + self.notify(notify); + hasNotify = false; + }); + }, self.notifyDelay); + + dfrd.always(function() { + clearTimeout(timeout); + }); + } + // queueing + if (requestCnt < requestMaxConn) { + // do request + return request(); + } else { + if (isOpen) { + requestQueue.unshift(request); + } else { + requestQueue.push(request); + } + return dfrd; + } + }, + progFakeUp = function() { + var add; + if (hasNotify && progTm) { + add = 1 * notify.cnt; + progTm = null; + self.notify({ + type: notify.type, + progress: add, + cnt: 0, + hideCnt: notify.hideCnt + }); + prog += add; + if ((prog / notify.cnt) < 80) { + progTm = setTimeout(progFakeUp, 500); + } + } + }, + bindData = {opts: opts, result: true}, + openDir; + + // prevent request initial request is completed + if (!self.api && !data.init) { + syncOnFail = false; + return dfrd.reject(); + } + + // trigger "request.cmd" that callback be able to cancel request by substituting "false" for "event.data.result" + self.trigger('request.' + cmd, bindData, true); + + if (! bindData.result) { + self.trigger(cmd + 'done'); + return dfrd.reject(); + } else if (typeof bindData.result === 'object' && bindData.result.promise) { + bindData.result + .done(queueingRequest) + .fail(function() { + self.trigger(cmd + 'done'); + dfrd.reject(); + }); + return dfrd; + } + + return queueingRequest(); + }; + + /** + * Call cache() + * Store info about files/dirs in "files" object. + * + * @param Array files + * @param String type + * @return void + */ + this.cache = function(dataArray, type) { + if (! Array.isArray(dataArray)) { + dataArray = [ dataArray ]; + } + cache(dataArray, type); + }; + + /** + * Update file object caches by respose data object + * + * @param Object respose data object + * @return void + */ + this.updateCache = function(data) { + if ($.isPlainObject(data)) { + data.files && data.files.length && cache(data.files, 'files'); + data.tree && data.tree.length && cache(data.tree, 'tree'); + data.removed && data.removed.length && remove(data.removed); + data.added && data.added.length && cache(data.added, 'add'); + data.changed && data.changed.length && cache(data.changed, 'change'); + } + }; + + /** + * Compare current files cache with new files and return diff + * + * @param Array new files + * @param String target folder hash + * @param Array exclude properties to compare + * @return Object + */ + this.diff = function(incoming, onlydir, excludeProps) { + var raw = {}, + added = [], + removed = [], + changed = [], + excludes = null, + isChanged = function(hash) { + var l = changed.length; + + while (l--) { + if (changed[l].hash == hash) { + return true; + } + } + }; + + $.each(incoming, function(i, f) { + raw[f.hash] = f; + }); + + // make excludes object + if (excludeProps && excludeProps.length) { + excludes = {}; + $.each(excludeProps, function() { + excludes[this] = true; + }); + } + + // find removed + $.each(files, function(hash, f) { + if (! raw[hash] && (! onlydir || f.phash === onlydir)) { + removed.push(hash); + } + }); + + // compare files + $.each(raw, function(hash, file) { + var origin = files[hash], + orgKeys = {}, + chkKeyLen; + + if (!origin) { + added.push(file); + } else { + // make orgKeys object + $.each(Object.keys(origin), function() { + orgKeys[this] = true; + }); + $.each(file, function(prop) { + delete orgKeys[prop]; + if (! excludes || ! excludes[prop]) { + if (file[prop] !== origin[prop]) { + changed.push(file); + orgKeys = {}; + return false; + } + } + }); + chkKeyLen = Object.keys(orgKeys).length; + if (chkKeyLen !== 0) { + if (excludes) { + $.each(orgKeys, function(prop) { + if (excludes[prop]) { + --chkKeyLen; + } + }); + } + (chkKeyLen !== 0) && changed.push(file); + } + } + }); + + // parents of removed dirs mark as changed (required for tree correct work) + $.each(removed, function(i, hash) { + var file = files[hash], + phash = file.phash; + + if (phash + && file.mime == 'directory' + && $.inArray(phash, removed) === -1 + && raw[phash] + && !isChanged(phash)) { + changed.push(raw[phash]); + } + }); + + return { + added : added, + removed : removed, + changed : changed + }; + }; + + /** + * Sync Stopper + * + * @type Boolean + */ + this.syncStopper = false; + + /** + * Sync content + * + * @return jQuery.Deferred + */ + this.sync = function(onlydir, polling) { + if (this.syncStopper) { + return $.Deferred().reject(); + } + this.syncStopper = true; + this.autoSync('stop'); + var self = this, + compare = function(){ + var c = '', cnt = 0, mtime = 0; + if (onlydir && polling) { + $.each(files, function(h, f) { + if (f.phash && f.phash === onlydir) { + ++cnt; + mtime = Math.max(mtime, f.ts); + } + c = cnt+':'+mtime; + }); + } + return c; + }, + comp = compare(), + odataRoots, + dfrd = $.Deferred().always(function() { !reqFail && self.trigger('sync'); }), + tree = (! onlydir && this.ui.tree) ? 1 : 0, + opts = [this.request({ + data : {cmd : 'open', reload : 1, target : cwd, tree : tree, compare : comp}, + preventDefault : true + })], + exParents = function() { + var parents = [], + curRoot = self.file(self.root(cwd)), + curId = curRoot? curRoot.volumeid : null, + phash = self.cwd().phash, + isroot,pdir; + + while(phash) { + if (pdir = self.file(phash)) { + if (phash.indexOf(curId) !== 0) { + parents.push( {target: phash, cmd: 'tree'} ); + if (! self.isRoot(pdir)) { + parents.push( {target: phash, cmd: 'parents'} ); + } + curRoot = self.file(self.root(phash)); + curId = curRoot? curRoot.volumeid : null; + } + phash = pdir.phash; + } else { + phash = null; + } + } + return parents; + }, + reqFail; + + if (! onlydir && self.api >= 2) { + (cwd !== this.root()) && opts.push(this.request({ + data : {cmd : 'parents', target : cwd}, + preventDefault : true + })); + $.each(exParents(), function(i, data) { + opts.push(self.request({ + data : {cmd : data.cmd, target : data.target}, + preventDefault : true + })); + }); + } + $.when.apply($, opts) + .fail(function(error, xhr) { + reqFail = (xhr && xhr.status != 200); + if (! polling || $.inArray('errOpen', error) !== -1) { + dfrd.reject(error); + self.parseError(error) && self.request({ + data : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1}, + notify : {type : 'open', cnt : 1, hideCnt : true} + }); + } else { + dfrd.reject((error && xhr.status != 0)? error : void 0); + } + }) + .done(function(odata) { + var pdata, argLen, i; + + if (odata.cwd.compare) { + if (comp === odata.cwd.compare) { + return dfrd.reject(); + } + } + + // for 2nd and more requests + pdata = {tree : []}; + + // results marge of 2nd and more requests + argLen = arguments.length; + if (argLen > 1) { + for(i = 1; i < argLen; i++) { + if (arguments[i].tree && arguments[i].tree.length) { + pdata.tree.push.apply(pdata.tree, arguments[i].tree); + } + } + } + + if (self.api < 2.1) { + if (! pdata.tree) { + pdata.tree = []; + } + pdata.tree.push(odata.cwd); + } + + // data normalize + odata = self.normalize(odata); + if (!self.validResponse('open', odata)) { + return dfrd.reject((odata.norError || 'errResponse')); + } + pdata = self.normalize(pdata); + if (!self.validResponse('tree', pdata)) { + return dfrd.reject((pdata.norError || 'errResponse')); + } + + // When tree = 1, the server will return all volumes in response to the open command. + // Remove volumes from the tree command that do not exist anymore. + if (tree && pdata && pdata.tree) { + odataRoots = $.map($.grep(odata.files, function(f) {return f.isroot;}), function(f) {return f.hash;}); + pdata.tree = $.grep(pdata.tree, function(f) {return !f.isroot || odataRoots.indexOf(f.hash) >= 0;}); + } + + var diff = self.diff(odata.files.concat(pdata && pdata.tree ? pdata.tree : []), onlydir); + + diff.added.push(odata.cwd); + + self.updateCache(diff); + + // trigger events + diff.removed.length && self.remove(diff); + diff.added.length && self.add(diff); + diff.changed.length && self.change(diff); + return dfrd.resolve(diff); + }) + .always(function() { + self.syncStopper = false; + self.autoSync(); + }); + + return dfrd; + }; + + this.upload = function(files) { + return this.transport.upload(files, this); + }; + + /** + * Bind keybord shortcut to keydown event + * + * @example + * elfinder.shortcut({ + * pattern : 'ctrl+a', + * description : 'Select all files', + * callback : function(e) { ... }, + * keypress : true|false (bind to keypress instead of keydown) + * }) + * + * @param Object shortcut config + * @return elFinder + */ + this.shortcut = function(s) { + var patterns, pattern, code, i, parts; + + if (this.options.allowShortcuts && s.pattern && typeof s.callback === 'function') { + patterns = s.pattern.toUpperCase().split(/\s+/); + + for (i= 0; i < patterns.length; i++) { + pattern = patterns[i]; + parts = pattern.split('+'); + code = (code = parts.pop()).length == 1 + ? (code > 0 ? code : code.charCodeAt(0)) + : (code > 0 ? code : $.ui.keyCode[code]); + + if (code && !shortcuts[pattern]) { + shortcuts[pattern] = { + keyCode : code, + altKey : $.inArray('ALT', parts) != -1, + ctrlKey : $.inArray('CTRL', parts) != -1, + shiftKey : $.inArray('SHIFT', parts) != -1, + type : s.type || 'keydown', + callback : s.callback, + description : s.description, + pattern : pattern + }; + } + } + } + return this; + }; + + /** + * Registered shortcuts + * + * @type Object + **/ + this.shortcuts = function() { + var ret = []; + + $.each(shortcuts, function(i, s) { + ret.push([s.pattern, self.i18n(s.description)]); + }); + return ret; + }; + + /** + * Get/set clipboard content. + * Return new clipboard content. + * + * @example + * this.clipboard([]) - clean clipboard + * this.clipboard([{...}, {...}], true) - put 2 files in clipboard and mark it as cutted + * + * @param Array new files hashes + * @param Boolean cut files? + * @return Array + */ + this.clipboard = function(hashes, cut) { + var map = function() { return $.map(clipboard, function(f) { return f.hash; }); }; + + if (hashes !== void(0)) { + clipboard.length && this.trigger('unlockfiles', {files : map()}); + remember = {}; + + clipboard = $.map(hashes||[], function(hash) { + var file = files[hash]; + if (file) { + + remember[hash] = true; + + return { + hash : hash, + phash : file.phash, + name : file.name, + mime : file.mime, + read : file.read, + locked : file.locked, + cut : !!cut + }; + } + return null; + }); + this.trigger('changeclipboard', {clipboard : clipboard.slice(0, clipboard.length)}); + cut && this.trigger('lockfiles', {files : map()}); + } + + // return copy of clipboard instead of refrence + return clipboard.slice(0, clipboard.length); + }; + + /** + * Return true if command enabled + * + * @param String command name + * @param String|void hash for check of own volume's disabled cmds + * @return Boolean + */ + this.isCommandEnabled = function(name, dstHash) { + var disabled, cmd, + cvid = self.cwd().volumeid || ''; + + // In serach results use selected item hash to check + if (!dstHash && self.searchStatus.state > 1 && self.selected().length) { + dstHash = self.selected()[0]; + } + if (dstHash && (! cvid || dstHash.indexOf(cvid) !== 0)) { + disabled = self.option('disabledFlip', dstHash); + //if (! disabled) { + // disabled = {}; + //} + } else { + disabled = cwdOptions.disabledFlip/* || {}*/; + } + cmd = this._commands[name]; + return cmd ? (cmd.alwaysEnabled || !disabled[name]) : false; + }; + + /** + * Exec command and return result; + * + * @param String command name + * @param String|Array usualy files hashes + * @param String|Array command options + * @param String|void hash for enabled check of own volume's disabled cmds + * @return $.Deferred + */ + this.exec = function(cmd, files, opts, dstHash) { + var dfrd, resType; + + // apply commandMap for keyboard shortcut + if (!dstHash && this.commandMap[cmd] && this.commandMap[cmd] !== 'hidden') { + cmd = this.commandMap[cmd]; + } + + if (cmd === 'open') { + if (this.searchStatus.state || this.searchStatus.ininc) { + this.trigger('searchend', { noupdate: true }); + } + this.autoSync('stop'); + } + if (!dstHash && files) { + if ($.isArray(files)) { + if (files.length) { + dstHash = files[0]; + } + } else { + dstHash = files; + } + } + dfrd = this._commands[cmd] && this.isCommandEnabled(cmd, dstHash) + ? this._commands[cmd].exec(files, opts) + : $.Deferred().reject('errUnknownCmd'); + + resType = typeof dfrd; + if (!(resType === 'object' && dfrd.promise)) { + self.debug('warning', '"cmd.exec()" should be returned "$.Deferred" but cmd "' + cmd + '" returned "' + resType + '"'); + dfrd = $.Deferred().resolve(); + } + + this.trigger('exec', { dfrd : dfrd, cmd : cmd, files : files, opts : opts, dstHash : dstHash }); + return dfrd; + }; + + /** + * Create and return dialog. + * + * @param String|DOMElement dialog content + * @param Object dialog options + * @return jQuery + */ + this.dialog = function(content, options) { + var dialog = $('
      ').append(content).appendTo(node).elfinderdialog(options, self), + dnode = dialog.closest('.ui-dialog'), + resize = function(){ + ! dialog.data('draged') && dialog.is(':visible') && dialog.elfinderdialog('posInit'); + }; + if (dnode.length) { + self.bind('resize', resize); + dnode.on('remove', function() { + self.unbind('resize', resize); + }); + } + return dialog; + }; + + /** + * Create and return toast. + * + * @param Object toast options - see ui/toast.js + * @return jQuery + */ + this.toast = function(options) { + return $('
      ').appendTo(this.ui.toast).elfindertoast(options || {}, this); + }; + + /** + * Return UI widget or node + * + * @param String ui name + * @return jQuery + */ + this.getUI = function(ui) { + return ui? (this.ui[ui] || $()) : node; + }; + + /** + * Return elFinder.command instance or instances array + * + * @param String command name + * @return Object | Array + */ + this.getCommand = function(name) { + return name === void(0) ? this._commands : this._commands[name]; + }; + + /** + * Resize elfinder node + * + * @param String|Number width + * @param String|Number height + * @return void + */ + this.resize = function(w, h) { + var getMargin = function() { + var m = node.outerHeight(true) - node.innerHeight(), + p = node; + + while(p.get(0) !== heightBase.get(0)) { + p = p.parent(); + m += p.outerHeight(true) - p.innerHeight(); + if (! p.parent().length) { + // reached the document + break; + } + } + return m; + }, + fit = ! node.hasClass('ui-resizable'), + prv = node.data('resizeSize') || {w: 0, h: 0}, + mt, size = {}; + + if (heightBase && heightBase.data('resizeTm')) { + clearTimeout(heightBase.data('resizeTm')); + } + + if (! self.options.noResizeBySelf) { + if (typeof h === 'string') { + if (mt = h.match(/^([0-9.]+)%$/)) { + // setup heightBase + if (! heightBase || ! heightBase.length) { + heightBase = $(window); + } + if (! heightBase.data('marginToMyNode')) { + heightBase.data('marginToMyNode', getMargin()); + } + if (! heightBase.data('fitToBaseFunc')) { + heightBase.data('fitToBaseFunc', function(e) { + var tm = heightBase.data('resizeTm'); + e.preventDefault(); + e.stopPropagation(); + tm && cancelAnimationFrame(tm); + if (! node.hasClass('elfinder-fullscreen') && (!self.UA.Mobile || heightBase.data('rotated') !== self.UA.Rotated)) { + heightBase.data('rotated', self.UA.Rotated); + heightBase.data('resizeTm', requestAnimationFrame(function() { + self.restoreSize(); + })); + } + }); + } + if (typeof heightBase.data('rotated') === 'undefined') { + heightBase.data('rotated', self.UA.Rotated); + } + h = heightBase.height() * (mt[1] / 100) - heightBase.data('marginToMyNode'); + + heightBase.off('resize.' + self.namespace, heightBase.data('fitToBaseFunc')); + fit && heightBase.on('resize.' + self.namespace, heightBase.data('fitToBaseFunc')); + } + } + + node.css({ width : w, height : parseInt(h) }); + } + + size.w = Math.round(node.width()); + size.h = Math.round(node.height()); + node.data('resizeSize', size); + if (size.w !== prv.w || size.h !== prv.h) { + node.trigger('resize'); + this.trigger('resize', {width : size.w, height : size.h}); + } + }; + + /** + * Restore elfinder node size + * + * @return elFinder + */ + this.restoreSize = function() { + this.resize(width, height); + }; + + this.show = function() { + node.show(); + this.enable().trigger('show'); + }; + + this.hide = function() { + if (this.options.enableAlways) { + prevEnabled = enabled; + enabled = false; + } + this.disable(); + this.trigger('hide'); + node.hide(); + }; + + /** + * Lazy execution function + * + * @param Object function + * @param Number delay + * @param Object options + * @return Object jQuery.Deferred + */ + this.lazy = function(func, delay, opts) { + var busy = function(state) { + var cnt = node.data('lazycnt'), + repaint; + + if (state) { + repaint = node.data('lazyrepaint')? false : opts.repaint; + if (! cnt) { + node.data('lazycnt', 1) + .addClass('elfinder-processing'); + } else { + node.data('lazycnt', ++cnt); + } + if (repaint) { + node.data('lazyrepaint', true).css('display'); // force repaint + } + } else { + if (cnt && cnt > 1) { + node.data('lazycnt', --cnt); + } else { + repaint = node.data('lazyrepaint'); + node.data('lazycnt', 0) + .removeData('lazyrepaint') + .removeClass('elfinder-processing'); + repaint && node.css('display'); // force repaint; + self.trigger('lazydone'); + } + } + }, + dfd = $.Deferred(), + callFunc = function() { + dfd.resolve(func.call(dfd)); + busy(false); + }; + + delay = delay || 0; + opts = opts || {}; + busy(true); + + if (delay) { + setTimeout(callFunc, delay); + } else { + requestAnimationFrame(callFunc); + } + + return dfd; + }; + + /** + * Destroy this elFinder instance + * + * @return void + **/ + this.destroy = function() { + if (node && node[0].elfinder) { + node.hasClass('elfinder-fullscreen') && self.toggleFullscreen(node); + this.options.syncStart = false; + this.autoSync('forcestop'); + this.trigger('destroy').disable(); + clipboard = []; + selected = []; + listeners = {}; + shortcuts = {}; + $(window).off('.' + namespace); + $(document).off('.' + namespace); + self.trigger = function(){}; + $(beeper).remove(); + node.off() + .removeData() + .empty() + .append(prevContent.contents()) + .attr('class', prevContent.attr('class')) + .attr('style', prevContent.attr('style')); + delete node[0].elfinder; + // restore kept events + $.each(prevEvents, function(n, arr) { + $.each(arr, function(i, o) { + node.on(o.type + (o.namespace? '.'+o.namespace : ''), o.selector, o.handler); + }); + }); + } + }; + + /** + * Start or stop auto sync + * + * @param String|Bool stop + * @return void + */ + this.autoSync = function(mode) { + var sync; + if (self.options.sync >= 1000) { + if (syncInterval) { + clearTimeout(syncInterval); + syncInterval = null; + self.trigger('autosync', {action : 'stop'}); + } + + if (mode === 'stop') { + ++autoSyncStop; + } else { + autoSyncStop = Math.max(0, --autoSyncStop); + } + + if (autoSyncStop || mode === 'forcestop' || ! self.options.syncStart) { + return; + } + + // run interval sync + sync = function(start){ + var timeout; + if (cwdOptions.syncMinMs && (start || syncInterval)) { + start && self.trigger('autosync', {action : 'start'}); + timeout = Math.max(self.options.sync, cwdOptions.syncMinMs); + syncInterval && clearTimeout(syncInterval); + syncInterval = setTimeout(function() { + var dosync = true, hash = cwd, cts; + if (cwdOptions.syncChkAsTs && files[hash] && (cts = files[hash].ts)) { + self.request({ + data : {cmd : 'info', targets : [hash], compare : cts, reload : 1}, + preventDefault : true + }) + .done(function(data){ + var ts; + dosync = true; + if (data.compare) { + ts = data.compare; + if (ts == cts) { + dosync = false; + } + } + if (dosync) { + self.sync(hash).always(function(){ + if (ts) { + // update ts for cache clear etc. + files[hash].ts = ts; + } + sync(); + }); + } else { + sync(); + } + }) + .fail(function(error, xhr){ + var err = self.parseError(error); + if (err && xhr.status != 0) { + self.error(err); + if (Array.isArray(err) && $.inArray('errOpen', err) !== -1) { + self.request({ + data : {cmd : 'open', target : (self.lastDir('') || self.root()), tree : 1, init : 1}, + notify : {type : 'open', cnt : 1, hideCnt : true} + }); + } + } else { + syncInterval = setTimeout(function() { + sync(); + }, timeout); + } + }); + } else { + self.sync(cwd, true).always(function(){ + sync(); + }); + } + }, timeout); + } + }; + sync(true); + } + }; + + /** + * Return bool is inside work zone of specific point + * + * @param Number event.pageX + * @param Number event.pageY + * @return Bool + */ + this.insideWorkzone = function(x, y, margin) { + var rectangle = this.getUI('workzone').data('rectangle'); + + margin = margin || 1; + if (x < rectangle.left + margin + || x > rectangle.left + rectangle.width + margin + || y < rectangle.top + margin + || y > rectangle.top + rectangle.height + margin) { + return false; + } + return true; + }; + + /** + * Target ui node move to last of children of elFinder node fot to show front + * + * @param Object target Target jQuery node object + */ + this.toFront = function(target) { + var nodes = node.children('.ui-front').removeClass('elfinder-frontmost'), + lastnode = nodes.last(); + nodes.css('z-index', ''); + $(target).addClass('ui-front elfinder-frontmost').css('z-index', lastnode.css('z-index') + 1); + }; + + /** + * Remove class 'elfinder-frontmost' and hide() to target ui node + * + * @param Object target Target jQuery node object + * @param Boolean nohide Do not hide + */ + this.toHide =function(target, nohide) { + var tgt = $(target), + last; + + !nohide && tgt.hide(); + if (tgt.hasClass('elfinder-frontmost')) { + tgt.removeClass('elfinder-frontmost'); + last = node.children('.ui-front:visible:not(.elfinder-frontmost)').last(); + if (last.length) { + requestAnimationFrame(function() { + if (!node.children('.elfinder-frontmost:visible').length) { + self.toFront(last); + last.trigger('frontmost'); + } + }); + } + } + }; + + /** + * Return css object for maximize + * + * @return Object + */ + this.getMaximizeCss = function() { + return { + width : '100%', + height : '100%', + margin : 0, + top : 0, + left : 0, + display : 'block', + position: 'fixed', + zIndex : Math.max(self.zIndex? (self.zIndex + 1) : 0 , 1000), + maxWidth : '', + maxHeight: '' + }; + }; + + // Closure for togglefullscreen + (function() { + // check is in iframe + if (inFrame && self.UA.Fullscreen) { + self.UA.Fullscreen = false; + if (parentIframe && typeof parentIframe.attr('allowfullscreen') !== 'undefined') { + self.UA.Fullscreen = true; + } + } + + var orgStyle, bodyOvf, resizeTm, fullElm, exitFull, toFull, funcObj, + cls = 'elfinder-fullscreen', + clsN = 'elfinder-fullscreen-native', + checkDialog = function() { + var t = 0, + l = 0; + $.each(node.children('.ui-dialog,.ui-draggable'), function(i, d) { + var $d = $(d), + pos = $d.position(); + + if (pos.top < 0) { + $d.css('top', t); + t += 20; + } + if (pos.left < 0) { + $d.css('left', l); + l += 20; + } + }); + }, + setFuncObj = function() { + var useFullscreen = self.storage('useFullscreen'); + funcObj = self.UA.Fullscreen && (useFullscreen? useFullscreen > 0 : self.options.commandsOptions.fullscreen.mode === 'screen') ? { + // native full screen mode + + fullElm: function() { + return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null; + }, + + exitFull: function() { + if (document.exitFullscreen) { + return document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + return document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + return document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + return document.msExitFullscreen(); + } + }, + + toFull: function(elem) { + if (elem.requestFullscreen) { + return elem.requestFullscreen(); + } else if (elem.webkitRequestFullscreen) { + return elem.webkitRequestFullscreen(); + } else if (elem.mozRequestFullScreen) { + return elem.mozRequestFullScreen(); + } else if (elem.msRequestFullscreen) { + return elem.msRequestFullscreen(); + } + return false; + } + } : { + // node element maximize mode + + fullElm: function() { + var full; + if (node.hasClass(cls)) { + return node.get(0); + } else { + full = node.find('.' + cls); + if (full.length) { + return full.get(0); + } + } + return null; + }, + + exitFull: function() { + var elm; + + $(window).off('resize.' + namespace, resize); + if (bodyOvf !== void(0)) { + $('body').css('overflow', bodyOvf); + } + bodyOvf = void(0); + + if (orgStyle) { + elm = orgStyle.elm; + restoreStyle(elm); + $(elm).trigger('resize', {fullscreen: 'off'}); + } + + $(window).trigger('resize'); + }, + + toFull: function(elem) { + bodyOvf = $('body').css('overflow') || ''; + $('body').css('overflow', 'hidden'); + + $(elem).css(self.getMaximizeCss()) + .addClass(cls) + .trigger('resize', {fullscreen: 'on'}); + + checkDialog(); + + $(window).on('resize.' + namespace, resize).trigger('resize'); + + return true; + } + }; + }, + restoreStyle = function(elem) { + if (orgStyle && orgStyle.elm == elem) { + $(elem).removeClass(cls + ' ' + clsN).attr('style', orgStyle.style); + orgStyle = null; + } + }, + resize = function(e) { + var elm; + if (e.target === window) { + resizeTm && cancelAnimationFrame(resizeTm); + resizeTm = requestAnimationFrame(function() { + if (elm = funcObj.fullElm()) { + $(elm).trigger('resize', {fullscreen: 'on'}); + } + }); + } + }; + + setFuncObj(); + + $(document).on('fullscreenchange.' + namespace + ' webkitfullscreenchange.' + namespace + ' mozfullscreenchange.' + namespace + ' MSFullscreenChange.' + namespace, function(e){ + if (self.UA.Fullscreen) { + var elm = funcObj.fullElm(), + win = $(window); + + resizeTm && cancelAnimationFrame(resizeTm); + if (elm === null) { + win.off('resize.' + namespace, resize); + if (orgStyle) { + elm = orgStyle.elm; + restoreStyle(elm); + $(elm).trigger('resize', {fullscreen: 'off'}); + } + } else { + $(elm).addClass(cls + ' ' + clsN) + .attr('style', 'width:100%; height:100%; margin:0; padding:0;') + .trigger('resize', {fullscreen: 'on'}); + win.on('resize.' + namespace, resize); + checkDialog(); + } + win.trigger('resize'); + } + }); + + /** + * Toggle Full Scrren Mode + * + * @param Object target + * @param Bool full + * @return Object | Null DOM node object of current full scrren + */ + self.toggleFullscreen = function(target, full) { + var elm = $(target).get(0), + curElm = null; + + curElm = funcObj.fullElm(); + if (curElm) { + if (curElm == elm) { + if (full === true) { + return curElm; + } + } else { + if (full === false) { + return curElm; + } + } + funcObj.exitFull(); + return null; + } else { + if (full === false) { + return null; + } + } + + setFuncObj(); + orgStyle = {elm: elm, style: $(elm).attr('style')}; + if (funcObj.toFull(elm) !== false) { + return elm; + } else { + orgStyle = null; + return null; + } + }; + })(); + + // Closure for toggleMaximize + (function(){ + var cls = 'elfinder-maximized', + resizeTm, + resize = function(e) { + if (e.target === window && e.data && e.data.elm) { + var elm = e.data.elm; + resizeTm && cancelAnimationFrame(resizeTm); + resizeTm = requestAnimationFrame(function() { + elm.trigger('resize', {maximize: 'on'}); + }); + } + }, + exitMax = function(elm) { + $(window).off('resize.' + namespace, resize); + $('body').css('overflow', elm.data('bodyOvf')); + elm.removeClass(cls) + .attr('style', elm.data('orgStyle')) + .removeData('bodyOvf') + .removeData('orgStyle'); + elm.trigger('resize', {maximize: 'off'}); + }, + toMax = function(elm) { + elm.data('bodyOvf', $('body').css('overflow') || '') + .data('orgStyle', elm.attr('style')) + .addClass(cls) + .css(self.getMaximizeCss()); + $('body').css('overflow', 'hidden'); + $(window).on('resize.' + namespace, {elm: elm}, resize); + elm.trigger('resize', {maximize: 'on'}); + }; + + /** + * Toggle Maximize target node + * + * @param Object target + * @param Bool max + * @return void + */ + self.toggleMaximize = function(target, max) { + var elm = $(target), + maximized = elm.hasClass(cls); + + if (maximized) { + if (max === true) { + return; + } + exitMax(elm); + } else { + if (max === false) { + return; + } + toMax(elm); + } + }; + })(); + + /************* init stuffs ****************/ + Object.assign($.ui.keyCode, { + 'F1' : 112, + 'F2' : 113, + 'F3' : 114, + 'F4' : 115, + 'F5' : 116, + 'F6' : 117, + 'F7' : 118, + 'F8' : 119, + 'F9' : 120, + 'F10' : 121, + 'F11' : 122, + 'F12' : 123, + 'DIG0' : 48, + 'DIG1' : 49, + 'DIG2' : 50, + 'DIG3' : 51, + 'DIG4' : 52, + 'DIG5' : 53, + 'DIG6' : 54, + 'DIG7' : 55, + 'DIG8' : 56, + 'DIG9' : 57, + 'NUM0' : 96, + 'NUM1' : 97, + 'NUM2' : 98, + 'NUM3' : 99, + 'NUM4' : 100, + 'NUM5' : 101, + 'NUM6' : 102, + 'NUM7' : 103, + 'NUM8' : 104, + 'NUM9' : 105, + 'CONTEXTMENU' : 93, + 'DOT' : 190 + }); + + this.dragUpload = false; + this.xhrUpload = (typeof XMLHttpRequestUpload != 'undefined' || typeof XMLHttpRequestEventTarget != 'undefined') && typeof File != 'undefined' && typeof FormData != 'undefined'; + + // configure transport object + this.transport = {}; + + if (typeof(this.options.transport) == 'object') { + this.transport = this.options.transport; + if (typeof(this.transport.init) == 'function') { + this.transport.init(this); + } + } + + if (typeof(this.transport.send) != 'function') { + this.transport.send = function(opts) { + if (!self.UA.IE) { + // keep native xhr object for handling property responseURL + opts._xhr = new XMLHttpRequest(); + opts.xhr = function() { + if (opts.progress) { + opts._xhr.addEventListener('progress', opts.progress); + } + return opts._xhr; + }; + } + return $.ajax(opts); + }; + } + + if (this.transport.upload == 'iframe') { + this.transport.upload = $.proxy(this.uploads.iframe, this); + } else if (typeof(this.transport.upload) == 'function') { + this.dragUpload = !!this.options.dragUploadAllow; + } else if (this.xhrUpload && !!this.options.dragUploadAllow) { + this.transport.upload = $.proxy(this.uploads.xhr, this); + this.dragUpload = true; + } else { + this.transport.upload = $.proxy(this.uploads.iframe, this); + } + + /** + * Decoding 'raw' string converted to unicode + * + * @param String str + * @return String + */ + this.decodeRawString = function(str) { + var charCodes = function(str) { + var i, len, arr; + for (i=0,len=str.length,arr=[]; i= 0xd800 && c <= 0xdbff) { + scalars.push((c & 1023) + 64 << 10 | arr[++i] & 1023); + } else { + scalars.push(c); + } + } + return scalars; + }, + decodeUTF8 = function(arr) { + var i, len, c, str, char = String.fromCharCode; + for (i=0,len=arr.length,str=""; c=arr[i],i= 0xc2) { + str += char((c&31)<<6 | arr[++i]&63); + } else if (c <= 0xef && c >= 0xe0) { + str += char((c&15)<<12 | (arr[++i]&63)<<6 | arr[++i]&63); + } else if (c <= 0xf7 && c >= 0xf0) { + str += char( + 0xd800 | ((c&7)<<8 | (arr[++i]&63)<<2 | arr[++i]>>>4&3) - 64, + 0xdc00 | (arr[i++]&15)<<6 | arr[i]&63 + ); + } else { + str += char(0xfffd); + } + } + return str; + }; + + return decodeUTF8(scalarValues(str)); + }; + + /** + * Gets target file contents by file.hash + * + * @param String hash The hash + * @param String responseType 'blob' or 'arraybuffer' (default) + * @param Object requestOpts The request options + * @return arraybuffer|blob The contents. + */ + this.getContents = function(hash, responseType, requestOpts) { + var self = this, + dfd = $.Deferred(), + type = responseType || 'arraybuffer', + url, req; + + dfd.fail(function() { + req && req.state() === 'pending' && req.reject(); + }); + + url = self.openUrl(hash); + if (!self.isSameOrigin(url)) { + url = self.openUrl(hash, true); + } + req = self.request(Object.assign({ + data : {cmd : 'get'}, + options : { + url: url, + type: 'get', + cache : true, + dataType : 'binary', + responseType : type, + processData: false + }, + notify : { + type: 'file', + cnt: 1, + hideCnt: true + }, + cancel : true + }, requestOpts || {})) + .fail(function() { + dfd.reject(); + }) + .done(function(data) { + dfd.resolve(data); + }); + + return dfd; + }; + + /** + * Gets the binary by url. + * + * @param {Object} opts The options + * @param {Function} callback The callback + * @param {Object} requestOpts The request options + * @return arraybuffer|blob The contents. + */ + this.getBinaryByUrl = function(opts, callback, requestOpts) { + var self = this, + dfd = $.Deferred(), + url, req; + + dfd.fail(function() { + req && req.state() === 'pending' && req.reject(); + }); + + req = self.request(Object.assign({ + data : {cmd : 'get'}, + options : Object.assign({ + type: 'get', + cache : true, + dataType : 'binary', + responseType : 'blob', + processData: false + }, opts) + }, requestOpts || {})) + .fail(function() { + dfd.reject(); + }) + .done(function(data) { + callback && callback(data); + dfd.resolve(data); + }); + + return dfd; + }; + + /** + * Gets the mimetype. + * + * @param {string} name The name + * @param {string} orgMime The organization mime + * @return {string} The mimetype. + */ + this.getMimetype = function(name, orgMime) { + var mime = orgMime, + ext, m; + m = (name + '').match(/\.([^.]+)$/); + if (m && (ext = m[1])) { + if (!extToMimeTable) { + extToMimeTable = self.arrayFlip(self.mimeTypes); + } + if (!(mime = extToMimeTable[ext.toLowerCase()])) { + mime = orgMime; + } + } + return mime; + }; + + /** + * Supported check hash algorisms + * + * @type Array + */ + self.hashCheckers = []; + + /** + * Closure of getContentsHashes() + */ + (function(self) { + var hashLibs = {}; + + if (window.Worker && window.ArrayBuffer) { + // make fm.hashCheckers + if (self.options.cdns.sparkmd5) { + hashLibs.SparkMD5 = true; + self.hashCheckers.push('md5'); + } + if (self.options.cdns.jssha) { + hashLibs.jsSHA = true; + self.hashCheckers = self.hashCheckers.concat(['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'sha3-224', 'sha3-256', 'sha3-384', 'sha3-512', 'shake128', 'shake256']); + } + } + + /** + * Gets the contents hashes. + * + * @param String target target file.hash + * @param Object needHashes need hash lib names + * @param Object requestOpts The request options + * @return Object hashes with lib name as key + */ + self.getContentsHashes = function(target, needHashes, hashOpts, requestOpts) { + var dfd = $.Deferred(), + needs = self.arrayFlip(needHashes || ['md5'], true), + libs = [], + jobs = [], + res = {}, + opts = hashOpts? hashOpts : { + shake128len : 256, + shake256len : 512 + }, + req; + + dfd.fail(function() { + req && req.reject(); + }); + + if (Object.keys(hashLibs).length) { + req = self.getContents(target, 'arraybuffer', requestOpts).done(function(arrayBuffer) { + if (needs.md5 && hashLibs.SparkMD5) { + jobs.push((function() { + var job = $.Deferred(); + try { + var wk = self.getWorker(); + job.fail(function() { + wk && wk.terminate(); + }); + wk.onmessage = function(ans) { + wk && wk.terminate(); + if (ans.data.hash) { + var f; + res.md5 = ans.data.hash; + if (f = self.file(target)) { + f.md5 = res.md5; + } + } else if (ans.data.error) { + res.md5 = ans.data.error; + } + dfd.notify(res); + job.resolve(); + }; + wk.onerror = function(e) { + job.reject(); + }; + wk.postMessage({ + scripts: [self.options.cdns.sparkmd5, self.getWorkerUrl('calcfilehash.js')], + data: { type: 'md5', bin: arrayBuffer } + }); + dfd.fail(function() { + job.reject(); + }); + } catch(e) { + job.reject(); + delete hashLibs.SparkMD5; + } + return job; + })()); + } + if (hashLibs.jsSHA) { + $.each(['1', '224', '256', '384', '512', '3-224', '3-256', '3-384', '3-512', 'ke128', 'ke256'], function(i, v) { + if (needs['sha' + v]) { + jobs.push((function() { + var job = $.Deferred(); + try { + var wk = self.getWorker(); + job.fail(function() { + wk && wk.terminate(); + }); + wk.onmessage = function(ans) { + wk && wk.terminate(); + if (ans.data.hash) { + var f; + res['sha' + v] = ans.data.hash; + if (f = self.file(target)) { + f['sha' + v] = res['sha' + v]; + } + } else if (ans.data.error) { + res['sha' + v] = ans.data.error; + } + dfd.notify(res); + job.resolve(); + }; + wk.onerror = function(e) { + job.reject(); + }; + wk.postMessage({ + scripts: [self.options.cdns.jssha, self.getWorkerUrl('calcfilehash.js')], + data: { type: v, bin: arrayBuffer, hashOpts: opts } + }); + dfd.fail(function() { + job.reject(); + }); + } catch(e) { + job.reject(); + delete hashLibs.jsSHA; + } + return job; + })()); + } + }); + } + if (jobs.length) { + $.when.apply(null, jobs).always(function() { + dfd.resolve(res); + }); + } else { + dfd.reject(); + } + }).fail(function() { + dfd.reject(); + }); + } else { + dfd.reject(); + } + + return dfd; + }; + })(this); + + /** + * Parse error value to display + * + * @param Mixed error + * @return Mixed parsed error + */ + this.parseError = function(error) { + var arg = error; + if ($.isPlainObject(arg)) { + arg = arg.error; + } + return arg; + }; + + /** + * Alias for this.trigger('error', {error : 'message'}) + * + * @param String error message + * @return elFinder + **/ + this.error = function() { + var arg = arguments[0], + opts = arguments[1] || null, + err; + if (arguments.length == 1 && typeof(arg) === 'function') { + return self.bind('error', arg); + } else { + err = this.parseError(arg); + return (err === true || !err)? this : self.trigger('error', {error: err, opts : opts}); + } + }; + + // create bind/trigger aliases for build-in events + $.each(events, function(i, name) { + self[name] = function() { + var arg = arguments[0]; + return arguments.length == 1 && typeof(arg) == 'function' + ? self.bind(name, arg) + : self.trigger(name, $.isPlainObject(arg) ? arg : {}); + }; + }); + + // bind core event handlers + this + .enable(function() { + if (!enabled && self.api && self.visible() && self.ui.overlay.is(':hidden') && ! node.children('.elfinder-dialog.' + self.res('class', 'editing') + ':visible').length) { + enabled = true; + document.activeElement && document.activeElement.blur(); + node.removeClass('elfinder-disabled'); + } + }) + .disable(function() { + prevEnabled = enabled; + enabled = false; + node.addClass('elfinder-disabled'); + }) + .open(function() { + selected = []; + }) + .select(function(e) { + var cnt = 0, + unselects = []; + selected = $.grep(e.data.selected || e.data.value|| [], function(hash) { + if (unselects.length || (self.maxTargets && ++cnt > self.maxTargets)) { + unselects.push(hash); + return false; + } else { + return files[hash] ? true : false; + } + }); + if (unselects.length) { + self.trigger('unselectfiles', {files: unselects, inselect: true}); + self.toast({mode: 'warning', msg: self.i18n(['errMaxTargets', self.maxTargets])}); + } + }) + .error(function(e) { + var opts = { + cssClass : 'elfinder-dialog-error', + title : self.i18n('error'), + resizable : false, + destroyOnClose : true, + buttons : {} + }, + node = self.getUI(), + cnt = node.children('.elfinder-dialog-error').length, + last, counter; + + if (cnt < self.options.maxErrorDialogs) { + opts.buttons[self.i18n(self.i18n('btnClose'))] = function() { $(this).elfinderdialog('close'); }; + + if (e.data.opts && $.isPlainObject(e.data.opts)) { + Object.assign(opts, e.data.opts); + } + + self.dialog(''+self.i18n(e.data.error), opts); + } else { + last = node.children('.elfinder-dialog-error:last').children('.ui-dialog-content:first'); + counter = last.children('.elfinder-error-counter'); + if (counter.length) { + counter.data('cnt', parseInt(counter.data('cnt')) + 1).html(self.i18n(['moreErrors', counter.data('cnt')])); + } else { + counter = $(''+ self.i18n(['moreErrors', 1]) +'').data('cnt', 1); + last.append('
      ', counter); + } + } + }) + .bind('tmb', function(e) { + $.each(e.data.images||[], function(hash, tmb) { + if (files[hash]) { + files[hash].tmb = tmb; + } + }); + }) + .bind('searchstart', function(e) { + Object.assign(self.searchStatus, e.data); + self.searchStatus.state = 1; + }) + .bind('search', function(e) { + self.searchStatus.state = 2; + }) + .bind('searchend', function() { + self.searchStatus.state = 0; + self.searchStatus.ininc = false; + self.searchStatus.mixed = false; + }) + .bind('canMakeEmptyFile', function(e) { + var data = e.data, + obj = {}; + if (data && Array.isArray(data.mimes)) { + if (!data.unshift) { + obj = self.mimesCanMakeEmpty; + } + $.each(data.mimes, function() { + if (!obj[this]) { + obj[this] = self.mimeTypes[this]; + } + }); + if (data.unshift) { + self.mimesCanMakeEmpty = Object.assign(obj, self.mimesCanMakeEmpty); + } + } + }) + .bind('themechange', function() { + requestAnimationFrame(function() { + self.trigger('uiresize'); + }); + }) + ; + + // We listen and emit a sound on delete according to option + if (true === this.options.sound) { + this.bind('playsound', function(e) { + var play = beeper.canPlayType && beeper.canPlayType('audio/wav; codecs="1"'), + file = e.data && e.data.soundFile; + + play && file && play != '' && play != 'no' && $(beeper).html('')[0].play(); + }); + } + + // bind external event handlers + $.each(this.options.handlers, function(event, callback) { + self.bind(event, callback); + }); + + /** + * History object. Store visited folders + * + * @type Object + **/ + this.history = new this.history(this); + + /** + * Root hashed + * + * @type Object + */ + this.roots = {}; + + /** + * leaf roots + * + * @type Object + */ + this.leafRoots = {}; + + this.volumeExpires = {}; + + /** + * Loaded commands + * + * @type Object + **/ + this._commands = {}; + + if (!Array.isArray(this.options.commands)) { + this.options.commands = []; + } + + if ($.inArray('*', this.options.commands) !== -1) { + this.options.commands = Object.keys(this.commands); + } + + /** + * UI command map of cwd volume ( That volume driver option `uiCmdMap` ) + * + * @type Object + **/ + this.commandMap = {}; + + /** + * cwd options of each volume + * key: volumeid + * val: options object + * + * @type Object + */ + this.volOptions = {}; + + /** + * Has volOptions data + * + * @type Boolean + */ + this.hasVolOptions = false; + + /** + * Hash of trash holders + * key: trash folder hash + * val: source volume hash + * + * @type Object + */ + this.trashes = {}; + + /** + * cwd options of each folder/file + * key: hash + * val: options object + * + * @type Object + */ + this.optionsByHashes = {}; + + /** + * UI Auto Hide Functions + * Each auto hide function mast be call to `fm.trigger('uiautohide')` at end of process + * + * @type Array + **/ + this.uiAutoHide = []; + + // trigger `uiautohide` + this.one('open', function() { + if (self.uiAutoHide.length) { + setTimeout(function() { + self.trigger('uiautohide'); + }, 500); + } + }); + + // Auto Hide Functions sequential processing start + this.bind('uiautohide', function() { + if (self.uiAutoHide.length) { + self.uiAutoHide.shift()(); + } + }); + + if (this.options.width) { + width = this.options.width; + } + + if (this.options.height) { + height = this.options.height; + } + + if (this.options.heightBase) { + heightBase = $(this.options.heightBase); + } + + if (this.options.soundPath) { + soundPath = this.options.soundPath.replace(/\/+$/, '') + '/'; + } else { + soundPath = this.baseUrl + soundPath; + } + + if (this.options.parrotHeaders && Array.isArray(this.options.parrotHeaders) && this.options.parrotHeaders.length) { + this.parrotHeaders = this.options.parrotHeaders; + // check sessionStorage + $.each(this.parrotHeaders, function(i, h) { + var v = self.sessionStorage('core-ph:' + h); + if (v) { + self.customHeaders[h] = v; + } + }); + } else { + this.parrotHeaders = []; + } + + self.one('opendone', function() { + var tm; + // attach events to document + $(document) + // disable elfinder on click outside elfinder + .on('click.'+namespace, function(e) { enabled && ! self.options.enableAlways && !$(e.target).closest(node).length && self.disable(); }) + // exec shortcuts + .on(keydown+' '+keypress+' '+keyup+' '+mousedown, execShortcut); + + // attach events to window + self.options.useBrowserHistory && $(window) + .on('popstate.' + namespace, function(ev) { + var state = ev.originalEvent.state || {}, + hasThash = state.thash? true : false, + dialog = node.find('.elfinder-frontmost:visible'), + input = node.find('.elfinder-navbar-dir,.elfinder-cwd-filename').find('input,textarea'), + onOpen, toast; + if (!hasThash) { + state = { thash: self.cwd().hash }; + // scroll to elFinder node + $('html,body').animate({ scrollTop: node.offset().top }); + } + if (dialog.length || input.length) { + history.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash); + if (dialog.length) { + if (!dialog.hasClass(self.res('class', 'preventback'))) { + if (dialog.hasClass('elfinder-contextmenu')) { + $(document).trigger($.Event('keydown', { keyCode: $.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false })); + } else if (dialog.hasClass('elfinder-dialog')) { + dialog.elfinderdialog('close'); + } else { + dialog.trigger('close'); + } + } + } else { + input.trigger($.Event('keydown', { keyCode: $.ui.keyCode.ESCAPE, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false })); + } + } else { + if (hasThash) { + !$.isEmptyObject(self.files()) && self.request({ + data : {cmd : 'open', target : state.thash, onhistory : 1}, + notify : {type : 'open', cnt : 1, hideCnt : true}, + syncOnFail : true + }); + } else { + onOpen = function() { + toast.trigger('click'); + }; + self.one('open', onOpen, true); + toast = self.toast({ + msg: self.i18n('pressAgainToExit'), + onHidden: function() { + self.unbind('open', onOpen); + history.pushState(state, null, location.pathname + location.search + '#elf_' + state.thash); + } + }); + } + } + }); + + $(window).on('resize.' + namespace, function(e){ + if (e.target === this) { + tm && cancelAnimationFrame(tm); + tm = requestAnimationFrame(function() { + var prv = node.data('resizeSize') || {w: 0, h: 0}, + size = {w: Math.round(node.width()), h: Math.round(node.height())}; + node.data('resizeSize', size); + if (size.w !== prv.w || size.h !== prv.h) { + node.trigger('resize'); + self.trigger('resize', {width : size.w, height : size.h}); + } + }); + } + }) + .on('beforeunload.' + namespace,function(e){ + var msg, cnt; + if (!self.pauseUnloadCheck()) { + if (node.is(':visible')) { + if (self.ui.notify.children().length && $.inArray('hasNotifyDialog', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('ntfsmth'); + } else if (node.find('.'+self.res('class', 'editing')).length && $.inArray('editingFile', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('editingFile'); + } else if ((cnt = Object.keys(self.selected()).length) && $.inArray('hasSelectedItem', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('hasSelected', ''+cnt); + } else if ((cnt = Object.keys(self.clipboard()).length) && $.inArray('hasClipboardData', self.options.windowCloseConfirm) !== -1) { + msg = self.i18n('hasClipboard', ''+cnt); + } + if (msg) { + e.returnValue = msg; + return msg; + } + } + self.trigger('unload'); + } + }); + + // bind window onmessage for CORS + $(window).on('message.' + namespace, function(e){ + var res = e.originalEvent || null, + obj, data; + if (res && (self.convAbsUrl(self.options.url).indexOf(res.origin) === 0 || self.convAbsUrl(self.uploadURL).indexOf(res.origin) === 0)) { + try { + try { + if (typeof res.data !== 'string') { + return; + } + obj = JSON.parse(res.data); + if (obj.type !== "io.studio-42.github") { + return; + } + data = obj.data || null; + } catch (e2) { + return; + } + if (data) { + if (data.error) { + if (obj.bind) { + self.trigger(obj.bind+'fail', data); + } + self.error(data.error); + } else { + data.warning && self.error(data.warning); + self.updateCache(data); + data.removed && data.removed.length && self.remove(data); + data.added && data.added.length && self.add(data); + data.changed && data.changed.length && self.change(data); + if (obj.bind) { + self.trigger(obj.bind, data); + self.trigger(obj.bind+'done'); + } + data.sync && self.sync(); + } + } + } catch (e) { + self.sync(); + } + } + }); + + // elFinder enable always + if (self.options.enableAlways) { + $(window).on('focus.' + namespace, function(e){ + (e.target === this) && self.enable(); + }); + if (inFrame) { + $(window.top).on('focus.' + namespace, function() { + if (self.enable() && (! parentIframe || parentIframe.is(':visible'))) { + requestAnimationFrame(function() { + $(window).trigger('focus'); + }); + } + }); + } + } else if (inFrame) { + $(window).on('blur.' + namespace, function(e){ + enabled && e.target === this && self.disable(); + }); + } + + // return focus to the window on click (elFInder in the frame) + if (inFrame) { + node.on('click', function(e) { + $(window).trigger('focus'); + }); + } + + // elFinder to enable by mouse over + if (self.options.enableByMouseOver) { + node.on('mouseenter touchstart', function(e) { + (inFrame) && $(window).trigger('focus'); + ! self.enabled() && self.enable(); + }); + } + + // When the browser tab turn to foreground/background + $(window).on('visibilitychange.' + namespace, function(e) { + var background = document.hidden || document.webkitHidden || document.msHidden; + // AutoSync turn On/Off + if (self.options.syncStart) { + self.autoSync(background? 'stop' : void(0)); + } + }); + }); + + // store instance in node + node[0].elfinder = this; + + // auto load language file + dfrdsBeforeBootup.push((function() { + var lang = self.lang, + langJs = self.i18nBaseUrl + 'elfinder.' + lang + '.js', + dfd = $.Deferred().done(function() { + if (self.i18[lang]) { + self.lang = lang; + } + self.trigger('i18load'); + i18n = self.lang === 'en' + ? self.i18['en'] + : $.extend(true, {}, self.i18['en'], self.i18[self.lang]); + }); + + if (!self.i18[lang]) { + self.lang = 'en'; + if (self.hasRequire) { + require([langJs], function() { + dfd.resolve(); + }, function() { + dfd.resolve(); + }); + } else { + self.loadScript([langJs], function() { + dfd.resolve(); + }, { + loadType: 'tag', + error : function() { + dfd.resolve(); + } + }); + } + } else { + dfd.resolve(); + } + return dfd; + })()); + + // elFinder boot up function + bootUp = function() { + var columnNames; + + /** + * i18 messages + * + * @type Object + **/ + self.messages = i18n.messages; + + // check jquery ui + if (!($.fn.selectable && $.fn.draggable && $.fn.droppable && $.fn.resizable && $.fn.button && $.fn.slider)) { + return alert(self.i18n('errJqui')); + } + + // check node + if (!node.length) { + return alert(self.i18n('errNode')); + } + // check connector url + if (!self.options.url) { + return alert(self.i18n('errURL')); + } + + // column key/name map for fm.getColumnName() + columnNames = Object.assign({ + name : self.i18n('name'), + perm : self.i18n('perms'), + date : self.i18n('modify'), + size : self.i18n('size'), + kind : self.i18n('kind'), + modestr : self.i18n('mode'), + modeoct : self.i18n('mode'), + modeboth : self.i18n('mode') + }, self.options.uiOptions.cwd.listView.columnsCustomName); + + /** + * Gets the column name of cwd list view + * + * @param String key The key + * @return String The column name. + */ + self.getColumnName = function(key) { + var res = columnNames[key] || self.i18n(key); + return typeof res === 'function'? res() : res; + }; + + /** + * Interface direction + * + * @type String + * @default "ltr" + **/ + self.direction = i18n.direction; + + /** + * Date/time format + * + * @type String + * @default "m.d.Y" + **/ + self.dateFormat = self.options.dateFormat || i18n.dateFormat; + + /** + * Date format like "Yesterday 10:20:12" + * + * @type String + * @default "{day} {time}" + **/ + self.fancyFormat = self.options.fancyDateFormat || i18n.fancyDateFormat; + + /** + * Date format for if upload file has not original unique name + * e.g. Clipboard image data, Image data taken with iOS + * + * @type String + * @default "ymd-His" + **/ + self.nonameDateFormat = (self.options.nonameDateFormat || i18n.nonameDateFormat).replace(/[\/\\]/g, '_'); + + /** + * Css classes + * + * @type String + **/ + self.cssClass = 'ui-helper-reset ui-helper-clearfix ui-widget ui-widget-content ui-corner-all elfinder elfinder-' + +(self.direction == 'rtl' ? 'rtl' : 'ltr') + +(self.UA.Touch? (' elfinder-touch' + (self.options.resizable ? ' touch-punch' : '')) : '') + +(self.UA.Mobile? ' elfinder-mobile' : '') + +(self.UA.iOS? ' elfinder-ios' : '') + +' '+self.options.cssClass; + + // prepare node + node.addClass(self.cssClass) + .on(mousedown, function() { + !enabled && self.enable(); + }); + + // draggable closure + (function() { + var ltr, wzRect, wzBottom, wzBottom2, nodeStyle, + keyEvt = keydown + 'draggable' + ' keyup.' + namespace + 'draggable'; + + /** + * Base draggable options + * + * @type Object + **/ + self.draggable = { + appendTo : node, + addClasses : false, + distance : 4, + revert : true, + refreshPositions : false, + cursor : 'crosshair', + cursorAt : {left : 50, top : 47}, + scroll : false, + start : function(e, ui) { + var helper = ui.helper, + targets = $.grep(helper.data('files')||[], function(h) { + if (h) { + remember[h] = true; + return true; + } + return false; + }), + locked = false, + cnt, h; + + // fix node size + nodeStyle = node.attr('style'); + node.width(node.width()).height(node.height()); + + // set var for drag() + ltr = (self.direction === 'ltr'); + wzRect = self.getUI('workzone').data('rectangle'); + wzBottom = wzRect.top + wzRect.height; + wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true); + + self.draggingUiHelper = helper; + cnt = targets.length; + while (cnt--) { + h = targets[cnt]; + if (files[h].locked) { + locked = true; + helper.data('locked', true); + break; + } + } + !locked && self.trigger('lockfiles', {files : targets}); + + helper.data('autoScrTm', setInterval(function() { + if (helper.data('autoScr')) { + self.autoScroll[helper.data('autoScr')](helper.data('autoScrVal')); + } + }, 50)); + }, + drag : function(e, ui) { + var helper = ui.helper, + autoScr, autoUp, bottom; + + if ((autoUp = wzRect.top > e.pageY) || wzBottom2 < e.pageY) { + if (wzRect.cwdEdge > e.pageX) { + autoScr = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down'); + } else { + autoScr = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down'); + } + if (!autoUp) { + if (autoScr.substr(0, 3) === 'cwd') { + if (wzBottom < e.pageY) { + bottom = wzBottom; + } else { + autoScr = null; + } + } else { + bottom = wzBottom2; + } + } + if (autoScr) { + helper.data('autoScr', autoScr); + helper.data('autoScrVal', Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - bottom), 1.3)); + } + } + if (! autoScr) { + if (helper.data('autoScr')) { + helper.data('refreshPositions', 1).data('autoScr', null); + } + } + if (helper.data('refreshPositions') && $(this).elfUiWidgetInstance('draggable')) { + if (helper.data('refreshPositions') > 0) { + $(this).draggable('option', { refreshPositions : true, elfRefresh : true }); + helper.data('refreshPositions', -1); + } else { + $(this).draggable('option', { refreshPositions : false, elfRefresh : false }); + helper.data('refreshPositions', null); + } + } + }, + stop : function(e, ui) { + var helper = ui.helper, + files; + + $(document).off(keyEvt); + $(this).elfUiWidgetInstance('draggable') && $(this).draggable('option', { refreshPositions : false }); + self.draggingUiHelper = null; + self.trigger('focus').trigger('dragstop'); + if (! helper.data('droped')) { + files = $.grep(helper.data('files')||[], function(h) { return h? true : false ;}); + self.trigger('unlockfiles', {files : files}); + self.trigger('selectfiles', {files : self.selected()}); + } + self.enable(); + + // restore node style + node.attr('style', nodeStyle); + + helper.data('autoScrTm') && clearInterval(helper.data('autoScrTm')); + }, + helper : function(e, ui) { + var element = this.id ? $(this) : $(this).parents('[id]:first'), + helper = $('
      '), + icon = function(f) { + var mime = f.mime, i, tmb = self.tmb(f); + i = '
      '; + if (tmb) { + i = $(i).addClass(tmb.className).css('background-image', "url('"+tmb.url+"')").get(0).outerHTML; + } else if (f.icon) { + i = $(i).css(self.getIconStyle(f, true)).get(0).outerHTML; + } + if (f.csscls) { + i = '
      ' + i + '
      '; + } + return i; + }, + hashes, l, ctr; + + self.draggingUiHelper && self.draggingUiHelper.stop(true, true); + + self.trigger('dragstart', {target : element[0], originalEvent : e}, true); + + hashes = element.hasClass(self.res('class', 'cwdfile')) + ? self.selected() + : [self.navId2Hash(element.attr('id'))]; + + helper.append(icon(files[hashes[0]])).data('files', hashes).data('locked', false).data('droped', false).data('namespace', namespace).data('dropover', 0); + + if ((l = hashes.length) > 1) { + helper.append(icon(files[hashes[l-1]]) + ''+l+''); + } + + $(document).on(keyEvt, function(e){ + if (self._commands.copy) { + var chk = (e.shiftKey||e.ctrlKey||e.metaKey); + if (ctr !== chk) { + ctr = chk; + if (helper.is(':visible') && helper.data('dropover') && ! helper.data('droped')) { + helper.toggleClass('elfinder-drag-helper-plus', helper.data('locked')? true : ctr); + self.trigger(ctr? 'unlockfiles' : 'lockfiles', {files : hashes, helper: helper}); + } + } + } + }); + + return helper; + } + }; + })(); + + // in getFileCallback set - change default actions on double click/enter/ctrl+enter + if (self.commands.getfile) { + if (typeof(self.options.getFileCallback) == 'function') { + self.bind('dblclick', function(e) { + e.preventDefault(); + self.exec('getfile').fail(function() { + self.exec('open', e.data && e.data.file? [ e.data.file ]: void(0)); + }); + }); + self.shortcut({ + pattern : 'enter', + description : self.i18n('cmdgetfile'), + callback : function() { self.exec('getfile').fail(function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); }); } + }) + .shortcut({ + pattern : 'ctrl+enter', + description : self.i18n(self.OS == 'mac' ? 'cmdrename' : 'cmdopen'), + callback : function() { self.exec(self.OS == 'mac' ? 'rename' : 'open'); } + }); + } else { + self.options.getFileCallback = null; + } + } + + // load commands + $.each(self.commands, function(name, cmd) { + var proto = Object.assign({}, cmd.prototype), + extendsCmd, opts; + if (typeof cmd === 'function' && !self._commands[name] && (cmd.prototype.forceLoad || $.inArray(name, self.options.commands) !== -1)) { + extendsCmd = cmd.prototype.extendsCmd || ''; + if (extendsCmd) { + if (typeof self.commands[extendsCmd] === 'function') { + cmd.prototype = Object.assign({}, base, new self.commands[extendsCmd](), cmd.prototype); + } else { + return true; + } + } else { + cmd.prototype = Object.assign({}, base, cmd.prototype); + } + self._commands[name] = new cmd(); + cmd.prototype = proto; + opts = self.options.commandsOptions[name] || {}; + if (extendsCmd && self.options.commandsOptions[extendsCmd]) { + opts = $.extend(true, {}, self.options.commandsOptions[extendsCmd], opts); + } + self._commands[name].setup(name, opts); + // setup linked commands + if (self._commands[name].linkedCmds.length) { + $.each(self._commands[name].linkedCmds, function(i, n) { + var lcmd = self.commands[n]; + if (typeof lcmd === 'function' && !self._commands[n]) { + lcmd.prototype = base; + self._commands[n] = new lcmd(); + self._commands[n].setup(n, self.options.commandsOptions[n]||{}); + } + }); + } + } + }); + + /** + * UI nodes + * + * @type Object + **/ + self.ui = { + // container for nav panel and current folder container + workzone : $('
      ').appendTo(node).elfinderworkzone(self), + // contaainer for folders tree / places + navbar : $('
      ').appendTo(node).elfindernavbar(self, self.options.uiOptions.navbar || {}), + // container for for preview etc at below the navbar + navdock : $('
      ').appendTo(node).elfindernavdock(self, self.options.uiOptions.navdock || {}), + // contextmenu + contextmenu : $('
      ').appendTo(node).elfindercontextmenu(self), + // overlay + overlay : $('
      ').appendTo(node).elfinderoverlay({ + show : function() { self.disable(); }, + hide : function() { prevEnabled && self.enable(); } + }), + // current folder container + cwd : $('
      ').appendTo(node).elfindercwd(self, self.options.uiOptions.cwd || {}), + // notification dialog window + notify : self.dialog('', { + cssClass : 'elfinder-dialog-notify' + (self.options.notifyDialog.canClose? '' : ' elfinder-titlebar-button-hide'), + position : self.options.notifyDialog.position, + absolute : true, + resizable : false, + autoOpen : false, + allowMinimize : true, + closeOnEscape : self.options.notifyDialog.canClose? true : false, + title : ' ', + width : self.options.notifyDialog.width? parseInt(self.options.notifyDialog.width) : null, + minHeight : null, + minimize : function() { self.ui.notify.trigger('minimize'); } + }), + statusbar : $('
      ').hide().appendTo(node), + toast : $('
      ').appendTo(node), + bottomtray : $('
      ').appendTo(node), + progressbar : $('
      ').appendTo(node) + }; + + self.trigger('uiready'); + + // load required ui + $.each(self.options.ui || [], function(i, ui) { + var name = 'elfinder'+ui, + opts = self.options.uiOptions[ui] || {}; + + if (!self.ui[ui] && $.fn[name]) { + // regist to self.ui before make instance + self.ui[ui] = $('<'+(opts.tag || 'div')+'/>').appendTo(node); + self.ui[ui][name](self, opts); + } + }); + + self.ui.progressbar.appendTo(self.ui.workzone); + self.ui.notify.prev('.ui-dialog-titlebar').append('
      '); + + // update size + self.resize(width, height); + + // make node resizable + if (self.options.resizable) { + node.resizable({ + resize : function(e, ui) { + self.resize(ui.size.width, ui.size.height); + }, + handles : 'se', + minWidth : 300, + minHeight : 200 + }); + if (self.UA.Touch) { + node.addClass('touch-punch'); + } + } + + (function() { + var navbar = self.getUI('navbar'), + cwd = self.getUI('cwd').parent(); + + self.autoScroll = { + navbarUp : function(v) { + navbar.scrollTop(Math.max(0, navbar.scrollTop() - v)); + }, + navbarDown : function(v) { + navbar.scrollTop(navbar.scrollTop() + v); + }, + cwdUp : function(v) { + cwd.scrollTop(Math.max(0, cwd.scrollTop() - v)); + }, + cwdDown : function(v) { + cwd.scrollTop(cwd.scrollTop() + v); + } + }; + })(); + + // Swipe on the touch devices to show/hide of toolbar or navbar + if (self.UA.Touch) { + (function() { + var lastX, lastY, nodeOffset, nodeWidth, nodeTop, navbarW, toolbarH, + navbar = self.getUI('navbar'), + toolbar = self.getUI('toolbar'), + moveEv = 'touchmove.stopscroll', + moveTm, + moveUpOn = function(e) { + var touches = e.originalEvent.touches || [{}], + y = touches[0].pageY || null; + if (!lastY || y < lastY) { + e.preventDefault(); + moveTm && clearTimeout(moveTm); + } + }, + moveDownOn = function(e) { + e.preventDefault(); + moveTm && clearTimeout(moveTm); + }, + moveOff = function() { + moveTm = setTimeout(function() { + node.off(moveEv); + }, 100); + }, + handleW, handleH = 50; + + navbar = navbar.children().length? navbar : null; + toolbar = toolbar.length? toolbar : null; + node.on('touchstart touchmove touchend', function(e) { + if (e.type === 'touchend') { + lastX = false; + lastY = false; + moveOff(); + return; + } + + var touches = e.originalEvent.touches || [{}], + x = touches[0].pageX || null, + y = touches[0].pageY || null, + ltr = (self.direction === 'ltr'), + navbarMode, treeWidth, swipeX, moveX, toolbarT, mode; + + if (x === null || y === null || (e.type === 'touchstart' && touches.length > 1)) { + return; + } + + if (e.type === 'touchstart') { + nodeOffset = node.offset(); + nodeWidth = node.width(); + if (navbar) { + lastX = false; + if (navbar.is(':hidden')) { + if (! handleW) { + handleW = Math.max(50, nodeWidth / 10); + } + if ((ltr? (x - nodeOffset.left) : (nodeWidth + nodeOffset.left - x)) < handleW) { + lastX = x; + } + } else if (! e.originalEvent._preventSwipeX) { + navbarW = navbar.width(); + if (ltr) { + swipeX = (x < nodeOffset.left + navbarW); + } else { + swipeX = (x > nodeOffset.left + nodeWidth - navbarW); + } + if (swipeX) { + handleW = Math.max(50, nodeWidth / 10); + lastX = x; + } else { + lastX = false; + } + } + } + if (toolbar) { + lastY = false; + if (! e.originalEvent._preventSwipeY) { + toolbarH = toolbar.height(); + nodeTop = nodeOffset.top; + if (y - nodeTop < (toolbar.is(':hidden')? handleH : (toolbarH + 30))) { + lastY = y; + node.on(moveEv, toolbar.is(':hidden')? moveDownOn: moveUpOn); + } + } + } + } else { + if (navbar && lastX !== false) { + navbarMode = (ltr? (lastX > x) : (lastX < x))? 'navhide' : 'navshow'; + moveX = Math.abs(lastX - x); + if (navbarMode === 'navhide' && moveX > navbarW * 0.6 + || (moveX > (navbarMode === 'navhide'? navbarW / 3 : 45) + && (navbarMode === 'navshow' + || (ltr? x < nodeOffset.left + 20 : x > nodeOffset.left + nodeWidth - 20) + )) + ) { + self.getUI('navbar').trigger(navbarMode, {handleW: handleW}); + lastX = false; + } + } + if (toolbar && lastY !== false ) { + toolbarT = toolbar.offset().top; + if (Math.abs(lastY - y) > Math.min(45, toolbarH / 3)) { + mode = (lastY > y)? 'slideUp' : 'slideDown'; + if (mode === 'slideDown' || toolbarT + 20 > y) { + if (toolbar.is(mode === 'slideDown' ? ':hidden' : ':visible')) { + toolbar.stop(true, true).trigger('toggle', {duration: 100, handleH: handleH}); + } + lastY = false; + } + } + } + } + }); + })(); + } + + if (self.dragUpload) { + // add event listener for HTML5 DnD upload + (function() { + var isin = function(e) { + return (e.target.nodeName !== 'TEXTAREA' && e.target.nodeName !== 'INPUT' && $(e.target).closest('div.ui-dialog-content').length === 0); + }, + ent = 'native-drag-enter', + disable = 'native-drag-disable', + c = 'class', + navdir = self.res(c, 'navdir'), + droppable = self.res(c, 'droppable'), + dropover = self.res(c, 'adroppable'), + arrow = self.res(c, 'navarrow'), + clDropActive = self.res(c, 'adroppable'), + wz = self.getUI('workzone'), + ltr = (self.direction === 'ltr'), + clearTm = function() { + autoScrTm && cancelAnimationFrame(autoScrTm); + autoScrTm = null; + }, + wzRect, autoScrFn, autoScrTm; + + node.on('dragenter', function(e) { + clearTm(); + if (isin(e)) { + e.preventDefault(); + e.stopPropagation(); + wzRect = wz.data('rectangle'); + } + }) + .on('dragleave', function(e) { + clearTm(); + if (isin(e)) { + e.preventDefault(); + e.stopPropagation(); + } + }) + .on('dragover', function(e) { + var autoUp; + if (isin(e)) { + e.preventDefault(); + e.stopPropagation(); + e.originalEvent.dataTransfer.dropEffect = 'none'; + if (! autoScrTm) { + autoScrTm = requestAnimationFrame(function() { + var wzBottom = wzRect.top + wzRect.height, + wzBottom2 = wzBottom - self.getUI('navdock').outerHeight(true), + fn; + if ((autoUp = e.pageY < wzRect.top) || e.pageY > wzBottom2 ) { + if (wzRect.cwdEdge > e.pageX) { + fn = (ltr? 'navbar' : 'cwd') + (autoUp? 'Up' : 'Down'); + } else { + fn = (ltr? 'cwd' : 'navbar') + (autoUp? 'Up' : 'Down'); + } + if (!autoUp) { + if (fn.substr(0, 3) === 'cwd') { + if (wzBottom < e.pageY) { + wzBottom2 = wzBottom; + } else { + fn = ''; + } + } + } + fn && self.autoScroll[fn](Math.pow((autoUp? wzRect.top - e.pageY : e.pageY - wzBottom2), 1.3)); + } + autoScrTm = null; + }); + } + } else { + clearTm(); + } + }) + .on('drop', function(e) { + clearTm(); + if (isin(e)) { + e.stopPropagation(); + e.preventDefault(); + } + }); + + node.on('dragenter', '.native-droppable', function(e){ + if (e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget), + id = e.currentTarget.id || null, + cwd = null, + elfFrom; + if (!id) { // target is cwd + cwd = self.cwd(); + $elm.data(disable, false); + try { + $.each(e.originalEvent.dataTransfer.types, function(i, v){ + if (v.substr(0, 13) === 'elfinderfrom:') { + elfFrom = v.substr(13).toLowerCase(); + } + }); + } catch(e) {} + } + if (!cwd || (cwd.write && (!elfFrom || elfFrom !== (window.location.href + cwd.hash).toLowerCase()))) { + e.preventDefault(); + e.stopPropagation(); + $elm.data(ent, true); + $elm.addClass(clDropActive); + } else { + $elm.data(disable, true); + } + } + }) + .on('dragleave', '.native-droppable', function(e){ + if (e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget); + e.preventDefault(); + e.stopPropagation(); + if ($elm.data(ent)) { + $elm.data(ent, false); + } else { + $elm.removeClass(clDropActive); + } + } + }) + .on('dragover', '.native-droppable', function(e){ + if (e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget); + e.preventDefault(); + e.stopPropagation(); + e.originalEvent.dataTransfer.dropEffect = $elm.data(disable)? 'none' : 'copy'; + $elm.data(ent, false); + } + }) + .on('drop', '.native-droppable', function(e){ + if (e.originalEvent && e.originalEvent.dataTransfer) { + var $elm = $(e.currentTarget), + id; + e.preventDefault(); + e.stopPropagation(); + $elm.removeClass(clDropActive); + if (e.currentTarget.id) { + id = $elm.hasClass(navdir)? self.navId2Hash(e.currentTarget.id) : self.cwdId2Hash(e.currentTarget.id); + } else { + id = self.cwd().hash; + } + e.originalEvent._target = id; + self.exec('upload', {dropEvt: e.originalEvent, target: id}, void 0, id); + } + }); + })(); + } + + // trigger event cssloaded if cssAutoLoad disabled + if (self.cssloaded === false) { + self.cssloaded = true; + self.trigger('cssloaded'); + } + + // calculate elFinder node z-index + self.zIndexCalc(); + + // send initial request and start to pray >_< + self.trigger('init') + .request({ + data : {cmd : 'open', target : self.startDir(), init : 1, tree : 1}, + preventDone : true, + notify : {type : 'open', cnt : 1, hideCnt : true}, + freeze : true + }) + .fail(function() { + self.trigger('fail').disable().lastDir(''); + listeners = {}; + shortcuts = {}; + $(document).add(node).off('.'+namespace); + self.trigger = function() { }; + }) + .done(function(data) { + var trashDisable = function(th) { + var src = self.file(self.trashes[th]), + d = self.options.debug, + error; + + if (src && src.volumeid) { + delete self.volOptions[src.volumeid].trashHash; + } + self.trashes[th] = false; + self.debug('backend-error', 'Trash hash "'+th+'" was not found or not writable.'); + }, + toChkTh = {}; + + // regist rawStringDecoder + if (self.options.rawStringDecoder) { + self.registRawStringDecoder(self.options.rawStringDecoder); + } + + // re-calculate elFinder node z-index + self.zIndexCalc(); + + self.load().debug('api', self.api); + // update ui's size after init + node.trigger('resize'); + // initial open + open(data); + self.trigger('open', data, false); + self.trigger('opendone'); + + if (inFrame && self.options.enableAlways) { + $(window).trigger('focus'); + } + + // check self.trashes + $.each(self.trashes, function(th) { + var dir = self.file(th), + src; + if (! dir) { + toChkTh[th] = true; + } else if (dir.mime !== 'directory' || ! dir.write) { + trashDisable(th); + } + }); + if (Object.keys(toChkTh).length) { + self.request({ + data : {cmd : 'info', targets : Object.keys(toChkTh)}, + preventDefault : true + }).done(function(data) { + if (data && data.files) { + $.each(data.files, function(i, dir) { + if (dir.mime === 'directory' && dir.write) { + delete toChkTh[dir.hash]; + } + }); + } + }).always(function() { + $.each(toChkTh, trashDisable); + }); + } + // to enable / disable + self[self.options.enableAlways? 'enable' : 'disable'](); + }); + + // self.timeEnd('load'); + // End of bootUp() + }; + + // call bootCallback function with elFinder instance, extraObject - { dfrdsBeforeBootup: dfrdsBeforeBootup } + if (bootCallback && typeof bootCallback === 'function') { + self.bootCallback = bootCallback; + bootCallback.call(node.get(0), self, { dfrdsBeforeBootup: dfrdsBeforeBootup }); + } + + // call dfrdsBeforeBootup functions then boot up elFinder + $.when.apply(null, dfrdsBeforeBootup).done(function() { + bootUp(); + }).fail(function(error) { + self.error(error); + }); +}; + +//register elFinder to global scope +if (typeof toGlobal === 'undefined' || toGlobal) { + window.elFinder = elFinder; +} + +/** + * Prototype + * + * @type Object + */ +elFinder.prototype = { + + uniqueid : 0, + + res : function(type, id) { + return this.resources[type] && this.resources[type][id]; + }, + + /** + * User os. Required to bind native shortcuts for open/rename + * + * @type String + **/ + OS : navigator.userAgent.indexOf('Mac') !== -1 ? 'mac' : navigator.userAgent.indexOf('Win') !== -1 ? 'win' : 'other', + + /** + * User browser UA. + * jQuery.browser: version deprecated: 1.3, removed: 1.9 + * + * @type Object + **/ + UA : (function(){ + var self = this, + webkit = !document.unqueID && !window.opera && !window.sidebar && 'localStorage' in window && 'WebkitAppearance' in document.documentElement.style, + chrome = webkit && window.chrome, + /*setRotated = function() { + var a = ((screen && screen.orientation && screen.orientation.angle) || window.orientation || 0) + 0; + if (a === -90) { + a = 270; + } + UA.Angle = a; + UA.Rotated = a % 180 === 0? false : true; + },*/ + UA = { + // Browser IE <= IE 6 + ltIE6 : typeof window.addEventListener == "undefined" && typeof document.documentElement.style.maxHeight == "undefined", + // Browser IE <= IE 7 + ltIE7 : typeof window.addEventListener == "undefined" && typeof document.querySelectorAll == "undefined", + // Browser IE <= IE 8 + ltIE8 : typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined", + // Browser IE <= IE 9 + ltIE9 : document.uniqueID && document.documentMode <= 9, + // Browser IE <= IE 10 + ltIE10 : document.uniqueID && document.documentMode <= 10, + // Browser IE >= IE 11 + gtIE11 : document.uniqueID && document.documentMode >= 11, + IE : document.uniqueID, + Firefox : window.sidebar, + Opera : window.opera, + Webkit : webkit, + Chrome : chrome, + Edge : (chrome && window.msCredentials)? true : false, + Safari : webkit && !window.chrome, + Mobile : typeof window.orientation != "undefined", + Touch : typeof window.ontouchstart != "undefined", + iOS : navigator.platform.match(/^iP(?:[ao]d|hone)/), + Mac : navigator.platform.match(/^Mac/), + Fullscreen : (typeof (document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen) !== 'undefined'), + Angle : 0, + Rotated : false, + CSS : (function() { + var aStyle = document.createElement('a').style, + pStyle = document.createElement('p').style, + css; + css = 'position:sticky;position:-webkit-sticky;'; + css += 'width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:max-content;'; + aStyle.cssText = css; + return { + positionSticky : aStyle.position.indexOf('sticky')!==-1, + widthMaxContent : aStyle.width.indexOf('max-content')!==-1, + flex : typeof pStyle.flex !== 'undefined' + }; + })() + }; + return UA; + })(), + + /** + * Is cookie enabled + * + * @type Boolean + */ + cookieEnabled : window.navigator.cookieEnabled, + + /** + * Has RequireJS? + * + * @type Boolean + */ + hasRequire : (typeof define === 'function' && define.amd), + + /** + * Current request command + * + * @type String + */ + currentReqCmd : '', + + /** + * Current keyboard state + * + * @type Object + */ + keyState : {}, + + /** + * Internationalization object + * + * @type Object + */ + i18 : { + en : { + translator : '', + language : 'English', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', + fancyDateFormat : '$1 H:i', + nonameDateFormat : 'ymd-His', + messages : {} + }, + months : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + monthsShort : ['msJan', 'msFeb', 'msMar', 'msApr', 'msMay', 'msJun', 'msJul', 'msAug', 'msSep', 'msOct', 'msNov', 'msDec'], + + days : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + daysShort : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] + }, + + /** + * File mimetype to kind mapping + * + * @type Object + */ + kinds : { + 'unknown' : 'Unknown', + 'directory' : 'Folder', + 'group' : 'Selects', + 'symlink' : 'Alias', + 'symlink-broken' : 'AliasBroken', + 'application/x-empty' : 'TextPlain', + 'application/postscript' : 'Postscript', + 'application/vnd.ms-office' : 'MsOffice', + 'application/msword' : 'MsWord', + 'application/vnd.ms-word' : 'MsWord', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' : 'MsWord', + 'application/vnd.ms-word.document.macroEnabled.12' : 'MsWord', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' : 'MsWord', + 'application/vnd.ms-word.template.macroEnabled.12' : 'MsWord', + 'application/vnd.ms-excel' : 'MsExcel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'MsExcel', + 'application/vnd.ms-excel.sheet.macroEnabled.12' : 'MsExcel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' : 'MsExcel', + 'application/vnd.ms-excel.template.macroEnabled.12' : 'MsExcel', + 'application/vnd.ms-excel.sheet.binary.macroEnabled.12' : 'MsExcel', + 'application/vnd.ms-excel.addin.macroEnabled.12' : 'MsExcel', + 'application/vnd.ms-powerpoint' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' : 'MsPP', + 'application/vnd.ms-powerpoint.presentation.macroEnabled.12' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' : 'MsPP', + 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.template' : 'MsPP', + 'application/vnd.ms-powerpoint.template.macroEnabled.12' : 'MsPP', + 'application/vnd.ms-powerpoint.addin.macroEnabled.12' : 'MsPP', + 'application/vnd.openxmlformats-officedocument.presentationml.slide' : 'MsPP', + 'application/vnd.ms-powerpoint.slide.macroEnabled.12' : 'MsPP', + 'application/pdf' : 'PDF', + 'application/xml' : 'XML', + 'application/vnd.oasis.opendocument.text' : 'OO', + 'application/vnd.oasis.opendocument.text-template' : 'OO', + 'application/vnd.oasis.opendocument.text-web' : 'OO', + 'application/vnd.oasis.opendocument.text-master' : 'OO', + 'application/vnd.oasis.opendocument.graphics' : 'OO', + 'application/vnd.oasis.opendocument.graphics-template' : 'OO', + 'application/vnd.oasis.opendocument.presentation' : 'OO', + 'application/vnd.oasis.opendocument.presentation-template' : 'OO', + 'application/vnd.oasis.opendocument.spreadsheet' : 'OO', + 'application/vnd.oasis.opendocument.spreadsheet-template' : 'OO', + 'application/vnd.oasis.opendocument.chart' : 'OO', + 'application/vnd.oasis.opendocument.formula' : 'OO', + 'application/vnd.oasis.opendocument.database' : 'OO', + 'application/vnd.oasis.opendocument.image' : 'OO', + 'application/vnd.openofficeorg.extension' : 'OO', + 'application/x-shockwave-flash' : 'AppFlash', + 'application/flash-video' : 'Flash video', + 'application/x-bittorrent' : 'Torrent', + 'application/javascript' : 'JS', + 'application/rtf' : 'RTF', + 'application/rtfd' : 'RTF', + 'application/x-font-ttf' : 'TTF', + 'application/x-font-otf' : 'OTF', + 'application/x-rpm' : 'RPM', + 'application/x-web-config' : 'TextPlain', + 'application/xhtml+xml' : 'HTML', + 'application/docbook+xml' : 'DOCBOOK', + 'application/x-awk' : 'AWK', + 'application/x-gzip' : 'GZIP', + 'application/x-bzip2' : 'BZIP', + 'application/x-xz' : 'XZ', + 'application/zip' : 'ZIP', + 'application/x-zip' : 'ZIP', + 'application/x-rar' : 'RAR', + 'application/x-tar' : 'TAR', + 'application/x-7z-compressed' : '7z', + 'application/x-jar' : 'JAR', + 'text/plain' : 'TextPlain', + 'text/x-php' : 'PHP', + 'text/html' : 'HTML', + 'text/javascript' : 'JS', + 'text/css' : 'CSS', + 'text/rtf' : 'RTF', + 'text/rtfd' : 'RTF', + 'text/x-c' : 'C', + 'text/x-csrc' : 'C', + 'text/x-chdr' : 'CHeader', + 'text/x-c++' : 'CPP', + 'text/x-c++src' : 'CPP', + 'text/x-c++hdr' : 'CPPHeader', + 'text/x-shellscript' : 'Shell', + 'application/x-csh' : 'Shell', + 'text/x-python' : 'Python', + 'text/x-java' : 'Java', + 'text/x-java-source' : 'Java', + 'text/x-ruby' : 'Ruby', + 'text/x-perl' : 'Perl', + 'text/x-sql' : 'SQL', + 'text/xml' : 'XML', + 'text/x-comma-separated-values' : 'CSV', + 'text/x-markdown' : 'Markdown', + 'image/x-ms-bmp' : 'BMP', + 'image/jpeg' : 'JPEG', + 'image/gif' : 'GIF', + 'image/png' : 'PNG', + 'image/tiff' : 'TIFF', + 'image/x-targa' : 'TGA', + 'image/vnd.adobe.photoshop' : 'PSD', + 'image/xbm' : 'XBITMAP', + 'image/pxm' : 'PXM', + 'image/webp' : 'WEBP', + 'application/vnd.ms-fontobject' : 'EOT', + 'font/sfnt' : 'SFNT', + 'application/font-sfnt' : 'SFNT', + 'font/ttf' : 'TTF', + 'font/opentype' : 'OTF', + 'font/otf' : 'OTF', + 'application/x-font-opentype' : 'OTF', + 'font/woff' : 'WOFF', + 'application/font-woff' : 'WOFF', + 'font/woff2' : 'WOFF2', + 'application/font-woff2' : 'WOFF2', + 'audio/mpeg' : 'AudioMPEG', + 'audio/midi' : 'AudioMIDI', + 'audio/ogg' : 'AudioOGG', + 'audio/mp4' : 'AudioMPEG4', + 'audio/x-m4a' : 'AudioMPEG4', + 'audio/wav' : 'AudioWAV', + 'audio/x-mp3-playlist' : 'AudioPlaylist', + 'video/x-dv' : 'VideoDV', + 'video/mp4' : 'VideoMPEG4', + 'video/mpeg' : 'VideoMPEG', + 'video/x-msvideo' : 'VideoAVI', + 'video/quicktime' : 'VideoMOV', + 'video/x-ms-wmv' : 'VideoWM', + 'video/x-flv' : 'VideoFlash', + 'video/x-matroska' : 'VideoMKV', + 'video/ogg' : 'VideoOGG' + }, + + /** + * File mimetype to file extention mapping + * + * @type Object + * @see elFinder.mimetypes.js + */ + mimeTypes : {}, + + /** + * Ajax request data validation rules + * + * @type Object + */ + rules : { + defaults : function(data) { + if (!data + || (data.added && !Array.isArray(data.added)) + || (data.removed && !Array.isArray(data.removed)) + || (data.changed && !Array.isArray(data.changed))) { + return false; + } + return true; + }, + open : function(data) { return data && data.cwd && data.files && $.isPlainObject(data.cwd) && Array.isArray(data.files); }, + tree : function(data) { return data && data.tree && Array.isArray(data.tree); }, + parents : function(data) { return data && data.tree && Array.isArray(data.tree); }, + tmb : function(data) { return data && data.images && ($.isPlainObject(data.images) || Array.isArray(data.images)); }, + upload : function(data) { return data && ($.isPlainObject(data.added) || Array.isArray(data.added));}, + search : function(data) { return data && data.files && Array.isArray(data.files); } + }, + + /** + * Commands costructors + * + * @type Object + */ + commands : {}, + + /** + * Commands to add the item (space delimited) + * + * @type String + */ + cmdsToAdd : 'archive duplicate extract mkdir mkfile paste rm upload', + + parseUploadData : function(text) { + var self = this, + data; + + if (!$.trim(text)) { + return {error : ['errResponse', 'errDataEmpty']}; + } + + try { + data = JSON.parse(text); + } catch (e) { + return {error : ['errResponse', 'errDataNotJSON']}; + } + + data = self.normalize(data); + if (!self.validResponse('upload', data)) { + return {error : (data.norError || ['errResponse'])}; + } + data.removed = $.merge((data.removed || []), $.map(data.added || [], function(f) { return self.file(f.hash)? f.hash : null; })); + return data; + + }, + + iframeCnt : 0, + + uploads : { + // xhr muiti uploading flag + xhrUploading: false, + + // Timer of request fail to sync + failSyncTm: null, + + // current chunkfail requesting chunk + chunkfailReq: {}, + + // check file/dir exists + checkExists: function(files, target, fm, isDir) { + var dfrd = $.Deferred(), + names, renames = [], hashes = {}, chkFiles = [], + cancel = function() { + var i = files.length; + while (--i > -1) { + files[i]._remove = true; + } + }, + resolve = function() { + dfrd.resolve(renames, hashes); + }, + check = function() { + var existed = [], exists = [], i, c, + pathStr = target !== fm.cwd().hash? fm.path(target, true) + fm.option('separator', target) : '', + confirm = function(ndx) { + var last = ndx == exists.length-1, + opts = { + cssClass : 'elfinder-confirm-upload', + title : fm.i18n('cmdupload'), + text : ['errExists', pathStr + exists[ndx].name, 'confirmRepl'], + all : !last, + accept : { + label : 'btnYes', + callback : function(all) { + !last && !all + ? confirm(++ndx) + : resolve(); + } + }, + reject : { + label : 'btnNo', + callback : function(all) { + var i; + + if (all) { + i = exists.length; + while (ndx < i--) { + files[exists[i].i]._remove = true; + } + } else { + files[exists[ndx].i]._remove = true; + } + + !last && !all + ? confirm(++ndx) + : resolve(); + } + }, + cancel : { + label : 'btnCancel', + callback : function() { + cancel(); + resolve(); + } + }, + buttons : [ + { + label : 'btnBackup', + cssClass : 'elfinder-confirm-btn-backup', + callback : function(all) { + var i; + if (all) { + i = exists.length; + while (ndx < i--) { + renames.push(exists[i].name); + } + } else { + renames.push(exists[ndx].name); + } + !last && !all + ? confirm(++ndx) + : resolve(); + } + } + ] + }; + + if (!isDir) { + opts.buttons.push({ + label : 'btnRename' + (last? '' : 'All'), + cssClass : 'elfinder-confirm-btn-rename', + callback : function() { + renames = null; + resolve(); + } + }); + } + if (fm.iframeCnt > 0) { + delete opts.reject; + } + fm.confirm(opts); + }; + + if (! fm.file(target).read) { + // for dropbox type + resolve(); + return; + } + + names = $.map(files, function(file, i) { return file.name && (!fm.UA.iOS || file.name !== 'image.jpg')? {i: i, name: file.name} : null ;}); + + fm.request({ + data : {cmd : 'ls', target : target, intersect : $.map(names, function(item) { return item.name;})}, + notify : {type : 'preupload', cnt : 1, hideCnt : true}, + preventDefault : true + }) + .done(function(data) { + var existedArr, cwdItems; + if (data) { + if (data.error) { + cancel(); + } else { + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + if (data.list) { + if (Array.isArray(data.list)) { + existed = data.list || []; + } else { + existedArr = []; + existed = $.map(data.list, function(n) { + if (typeof n === 'string') { + return n; + } else { + // support to >=2.1.11 plugin Normalizer, Sanitizer + existedArr = existedArr.concat(n); + return false; + } + }); + if (existedArr.length) { + existed = existed.concat(existedArr); + } + hashes = data.list; + } + exists = $.grep(names, function(name){ + return $.inArray(name.name, existed) !== -1 ? true : false ; + }); + if (exists.length && existed.length && target == fm.cwd().hash) { + cwdItems = $.map(fm.files(target), function(file) { return file.name; } ); + if ($.grep(existed, function(n) { + return $.inArray(n, cwdItems) === -1? true : false; + }).length){ + fm.sync(); + } + } + } + } + } + } + if (exists.length > 0) { + confirm(0); + } else { + resolve(); + } + }) + .fail(function(error) { + cancel(); + resolve(); + error && fm.error(error); + }); + }; + if (fm.api >= 2.1 && typeof files[0] == 'object') { + check(); + } else { + resolve(); + } + return dfrd; + }, + + // check droped contents + checkFile : function(data, fm, target) { + if (!!data.checked || data.type == 'files') { + return data.files; + } else if (data.type == 'data') { + var dfrd = $.Deferred(), + scanDfd = $.Deferred(), + files = [], + paths = [], + dirctorys = [], + processing = 0, + items, + mkdirs = [], + cancel = false, + toArray = function(list) { + return Array.prototype.slice.call(list || [], 0); + }, + doScan = function(items) { + var entry, readEntries, + excludes = fm.options.folderUploadExclude[fm.OS] || null, + length = items.length, + check = function() { + if (--processing < 1 && scanDfd.state() === 'pending') { + scanDfd.resolve(); + } + }, + pushItem = function(file) { + if (! excludes || ! file.name.match(excludes)) { + paths.push(entry.fullPath || ''); + files.push(file); + } + check(); + }, + readEntries = function(dirReader) { + var entries = [], + read = function() { + dirReader.readEntries(function(results) { + if (cancel || !results.length) { + for (var i = 0; i < entries.length; i++) { + if (cancel) { + scanDfd.reject(); + break; + } + doScan([entries[i]]); + } + check(); + } else { + entries = entries.concat(toArray(results)); + read(); + } + }, check); + }; + read(); + }; + + processing++; + for (var i = 0; i < length; i++) { + if (cancel) { + scanDfd.reject(); + break; + } + entry = items[i]; + if (entry) { + if (entry instanceof File) { + pushItem(entry); + } else if (entry.isFile) { + processing++; + entry.file(pushItem, check); + } else if (entry.isDirectory) { + if (fm.api >= 2.1) { + processing++; + mkdirs.push(entry.fullPath); + readEntries(entry.createReader()); // Start reading dirs. + } + } + } + } + check(); + return scanDfd; + }, hasDirs; + + items = $.map(data.files.items, function(item){ + if (item.kind === 'file') { + return (item.getAsEntry? item.getAsEntry() : item.webkitGetAsEntry()) || item.getAsFile(); + } else { + return null; + } + }); + $.each(items, function(i, item) { + if (item.isDirectory) { + hasDirs = true; + return false; + } + }); + if (items.length > 0) { + fm.uploads.checkExists(items, target, fm, hasDirs).done(function(renames, hashes){ + var dfds = []; + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + if (renames === null) { + data.overwrite = 0; + renames = []; + } + items = $.grep(items, function(item){ + var i, bak, hash, dfd, hi; + if (item.isDirectory && renames.length) { + i = $.inArray(item.name, renames); + if (i !== -1) { + renames.splice(i, 1); + bak = fm.uniqueName(item.name + fm.options.backupSuffix , null, ''); + $.each(hashes, function(h, name) { + if (item.name == name) { + hash = h; + return false; + } + }); + if (! hash) { + hash = fm.fileByName(item.name, target).hash; + } + fm.lockfiles({files : [hash]}); + dfd = fm.request({ + data : {cmd : 'rename', target : hash, name : bak}, + notify : {type : 'rename', cnt : 1} + }) + .fail(function() { + item._remove = true; + fm.sync(); + }) + .always(function() { + fm.unlockfiles({files : [hash]}); + }); + dfds.push(dfd); + } + } + return !item._remove? true : false; + }); + } + $.when.apply($, dfds).done(function(){ + var notifyto, msg, + id = +new Date(); + + if (items.length > 0) { + msg = fm.escape(items[0].name); + if (items.length > 1) { + msg += ' ... ' + items.length + fm.i18n('items'); + } + notifyto = setTimeout(function() { + fm.notify({ + type : 'readdir', + id : id, + cnt : 1, + hideCnt: true, + msg : fm.i18n('ntfreaddir') + ' (' + msg + ')', + cancel: function() { + cancel = true; + } + }); + }, fm.options.notifyDelay); + doScan(items).done(function() { + notifyto && clearTimeout(notifyto); + fm.notify({type : 'readdir', id: id, cnt : -1}); + if (cancel) { + dfrd.reject(); + } else { + dfrd.resolve([files, paths, renames, hashes, mkdirs]); + } + }).fail(function() { + dfrd.reject(); + }); + } else { + dfrd.reject(); + } + }); + }); + return dfrd.promise(); + } else { + return dfrd.reject(); + } + } else { + var ret = []; + var check = []; + var str = data.files[0]; + if (data.type == 'html') { + var tmp = $("").append($.parseHTML(str.replace(/ src=/ig, ' _elfsrc='))), + atag; + $('img[_elfsrc]', tmp).each(function(){ + var url, purl, + self = $(this), + pa = self.closest('a'); + if (pa && pa.attr('href') && pa.attr('href').match(/\.(?:jpe?g|gif|bmp|png)/i)) { + purl = pa.attr('href'); + } + url = self.attr('_elfsrc'); + if (url) { + if (purl) { + $.inArray(purl, ret) == -1 && ret.push(purl); + $.inArray(url, check) == -1 && check.push(url); + } else { + $.inArray(url, ret) == -1 && ret.push(url); + } + } + // Probably it's clipboard data + if (ret.length === 1 && ret[0].match(/^data:image\/png/)) { + data.clipdata = true; + } + }); + atag = $('a[href]', tmp); + atag.each(function(){ + var text, loc, + parseUrl = function(url) { + var a = document.createElement('a'); + a.href = url; + return a; + }; + if (text = $(this).text()) { + loc = parseUrl($(this).attr('href')); + if (loc.href && loc.href.match(/^(?:ht|f)tp/i) && (atag.length === 1 || ! loc.pathname.match(/(?:\.html?|\/[^\/.]*)$/i) || $.trim(text).match(/\.[a-z0-9-]{1,10}$/i))) { + if ($.inArray(loc.href, ret) == -1 && $.inArray(loc.href, check) == -1) ret.push(loc.href); + } + } + }); + } else { + var regex, m, url; + regex = /((?:ht|f)tps?:\/\/[-_.!~*\'()a-z0-9;/?:\@&=+\$,%#\*\[\]]+)/ig; + while (m = regex.exec(str)) { + url = m[1].replace(/&/g, '&'); + if ($.inArray(url, ret) == -1) ret.push(url); + } + } + return ret; + } + }, + + // upload transport using XMLHttpRequest + xhr : function(data, fm) { + var self = fm ? fm : this, + node = self.getUI(), + xhr = new XMLHttpRequest(), + notifyto = null, + notifyto1 = null, + notifyto2 = null, + dataChecked = data.checked, + isDataType = (data.isDataType || data.type == 'data'), + target = (data.target || self.cwd().hash), + dropEvt = (data.dropEvt || null), + extraData = data.extraData || null, + chunkEnable = (self.option('uploadMaxConn', target) != -1), + multiMax = Math.min(5, Math.max(1, self.option('uploadMaxConn', target))), + retryWait = 10000, // 10 sec + retryMax = 30, // 10 sec * 30 = 300 secs (Max 5 mins) + retry = 0, + getFile = function(files) { + var dfd = $.Deferred(), + file; + if (files.promise) { + files.always(function(f) { + dfd.resolve(Array.isArray(f) && f.length? (isDataType? f[0][0] : f[0]) : {}); + }); + } else { + dfd.resolve(files.length? (isDataType? files[0][0] : files[0]) : {}); + } + return dfd; + }, + dfrd = $.Deferred() + .fail(function(err) { + var error = self.parseError(err), + userAbort; + if (error === 'userabort') { + userAbort = true; + error = void 0; + } + if (files && (self.uploads.xhrUploading || userAbort)) { + // send request om fail + getFile(files).done(function(file) { + if (!userAbort) { + triggerError(error, file); + } + if (! file._cid) { + // send sync request + self.uploads.failSyncTm && clearTimeout(self.uploads.failSyncTm); + self.uploads.failSyncTm = setTimeout(function() { + self.sync(target); + }, 1000); + } else if (! self.uploads.chunkfailReq[file._cid]) { + // send chunkfail request + self.uploads.chunkfailReq[file._cid] = true; + setTimeout(function() { + fm.request({ + data : { + cmd: 'upload', + target: target, + chunk: file._chunk, + cid: file._cid, + upload: ['chunkfail'], + mimes: 'chunkfail' + }, + options : { + type: 'post', + url: self.uploadURL + }, + preventDefault: true + }).always(function() { + delete self.uploads.chunkfailReq[file._chunk]; + }); + }, 1000); + } + }); + } else { + triggerError(error); + } + !userAbort && self.sync(); + self.uploads.xhrUploading = false; + files = null; + }) + .done(function(data) { + self.uploads.xhrUploading = false; + files = null; + if (data) { + self.currentReqCmd = 'upload'; + data.warning && triggerError(data.warning); + self.updateCache(data); + data.removed && data.removed.length && self.remove(data); + data.added && data.added.length && self.add(data); + data.changed && data.changed.length && self.change(data); + self.trigger('upload', data, false); + self.trigger('uploaddone'); + if (data.toasts && Array.isArray(data.toasts)) { + $.each(data.toasts, function() { + this.msg && self.toast(this); + }); + } + data.sync && self.sync(); + if (data.debug) { + self.responseDebug(data); + fm.debug('backend-debug', data); + } + } + }) + .always(function() { + self.abortXHR(xhr); + // unregist fnAbort function + node.off('uploadabort', fnAbort); + $(window).off('unload', fnAbort); + notifyto && clearTimeout(notifyto); + notifyto1 && clearTimeout(notifyto1); + notifyto2 && clearTimeout(notifyto2); + dataChecked && !data.multiupload && checkNotify() && self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0}); + notifyto1 && uploadedNtf && self.notify({type : 'chunkmerge', cnt : -cnt}); + chunkMerge && notifyElm.children('.elfinder-notify-chunkmerge').length && self.notify({type : 'chunkmerge', cnt : -1}); + }), + formData = new FormData(), + files = data.input ? data.input.files : self.uploads.checkFile(data, self, target), + cnt = data.checked? (isDataType? files[0].length : files.length) : files.length, + isChunked = false, + loaded = 0, + prev = 0, + filesize = 0, + notify = false, + notifyElm = self.ui.notify, + cancelBtn = true, + uploadedNtf = false, + abort = false, + checkNotify = function() { + if (!notify && (ntfUpload = notifyElm.children('.elfinder-notify-upload')).length) { + notify = true; + } + return notify; + }, + fnAbort = function(e, error) { + abort = true; + self.abortXHR(xhr, { quiet: true, abort: true }); + dfrd.reject(error); + if (checkNotify()) { + self.notify({type : 'upload', cnt : ntfUpload.data('cnt') * -1, progress : 0, size : 0}); + } + }, + cancelToggle = function(show, hasChunk) { + ntfUpload.children('.elfinder-notify-cancel')[show? 'show':'hide'](); + cancelBtn = show; + }, + startNotify = function(size) { + if (!size) size = filesize; + return setTimeout(function() { + notify = true; + self.notify({type : 'upload', cnt : cnt, progress : loaded - prev, size : size, + cancel: function() { + node.trigger('uploadabort', 'userabort'); + } + }); + ntfUpload = notifyElm.children('.elfinder-notify-upload'); + prev = loaded; + if (data.multiupload) { + cancelBtn && cancelToggle(true); + } else { + cancelToggle(cancelBtn && loaded < size); + } + }, self.options.notifyDelay); + }, + doRetry = function() { + if (retry++ <= retryMax) { + if (checkNotify() && prev) { + self.notify({type : 'upload', cnt : 0, progress : 0, size : prev}); + } + self.abortXHR(xhr, { quiet: true }); + prev = loaded = 0; + setTimeout(function() { + var reqId; + if (! abort) { + xhr.open('POST', self.uploadURL, true); + if (self.api >= 2.1029) { + reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16); + (typeof formData['delete'] === 'function') && formData['delete']('reqid'); + formData.append('reqid', reqId); + xhr._requestId = reqId; + } + xhr.send(formData); + } + }, retryWait); + } else { + node.trigger('uploadabort', ['errAbort', 'errTimeout']); + } + }, + progress = function() { + var node; + if (notify) { + dfrd.notifyWith(ntfUpload, [{ + cnt: ntfUpload.data('cnt'), + progress: ntfUpload.data('progress'), + total: ntfUpload.data('total') + }]); + } + }, + triggerError = function(err, file, unite) { + err && self.trigger('xhruploadfail', { error: err, file: file }); + if (unite) { + if (err) { + if (errCnt < self.options.maxErrorDialogs) { + if (Array.isArray(err)) { + errors = errors.concat(err); + } else { + errors.push(err); + } + } + errCnt++; + } + } else { + if (err) { + self.error(err); + } else { + if (errors.length) { + if (errCnt >= self.options.maxErrorDialogs) { + errors = errors.concat('moreErrors', errCnt - self.options.maxErrorDialogs); + } + self.error(errors); + } + errors = []; + errCnt = 0; + } + } + }, + errors = [], + errCnt = 0, + renames = (data.renames || null), + hashes = (data.hashes || null), + chunkMerge = false, + ntfUpload = $(); + + // regist fnAbort function + node.one('uploadabort', fnAbort); + $(window).one('unload.' + fm.namespace, fnAbort); + + !chunkMerge && (prev = loaded); + + if (!isDataType && !cnt) { + return dfrd.reject(['errUploadNoFiles']); + } + + xhr.addEventListener('error', function() { + if (xhr.status == 0) { + if (abort) { + dfrd.reject(); + } else { + // ff bug while send zero sized file + // for safari - send directory + if (!isDataType && data.files && $.grep(data.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) { + dfrd.reject(['errAbort', 'errFolderUpload']); + } else if (data.input && $.grep(data.input.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) { + dfrd.reject(['errUploadNoFiles']); + } else { + doRetry(); + } + } + } else { + node.trigger('uploadabort', 'errConnect'); + } + }, false); + + xhr.addEventListener('load', function(e) { + var status = xhr.status, res, curr = 0, error = '', errData, errObj; + + self.setCustomHeaderByXhr(xhr); + + if (status >= 400) { + if (status > 500) { + error = 'errResponse'; + } else { + error = ['errResponse', 'errServerError']; + } + } else { + if (!xhr.responseText) { + error = ['errResponse', 'errDataEmpty']; + } + } + + if (error) { + node.trigger('uploadabort'); + getFile(files || {}).done(function(file) { + return dfrd.reject(file._cid? null : error); + }); + } + + loaded = filesize; + + if (checkNotify() && (curr = loaded - prev)) { + self.notify({type : 'upload', cnt : 0, progress : curr, size : 0}); + progress(); + } + + res = self.parseUploadData(xhr.responseText); + + // chunked upload commit + if (res._chunkmerged) { + formData = new FormData(); + var _file = [{_chunkmerged: res._chunkmerged, _name: res._name, _mtime: res._mtime}]; + chunkMerge = true; + node.off('uploadabort', fnAbort); + notifyto2 = setTimeout(function() { + self.notify({type : 'chunkmerge', cnt : 1}); + }, self.options.notifyDelay); + isDataType? send(_file, files[1]) : send(_file); + return; + } + + res._multiupload = data.multiupload? true : false; + if (res.error) { + errData = { + cmd: 'upload', + err: res, + xhr: xhr, + rc: xhr.status + }; + self.trigger('uploadfail', res); + // trigger "requestError" event + self.trigger('requestError', errData); + if (errData._getEvent && errData._getEvent().isDefaultPrevented()) { + res.error = ''; + } + if (res._chunkfailure || res._multiupload) { + abort = true; + self.uploads.xhrUploading = false; + notifyto && clearTimeout(notifyto); + if (ntfUpload.length) { + self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0}); + dfrd.reject(res); + } else { + // for multi connection + dfrd.reject(); + } + } else { + dfrd.reject(res); + } + } else { + dfrd.resolve(res); + } + }, false); + + xhr.upload.addEventListener('loadstart', function(e) { + if (!chunkMerge && e.lengthComputable) { + loaded = e.loaded; + retry && (loaded = 0); + filesize = e.total; + if (!loaded) { + loaded = parseInt(filesize * 0.05); + } + if (checkNotify()) { + self.notify({type : 'upload', cnt : 0, progress : loaded - prev, size : data.multiupload? 0 : filesize}); + prev = loaded; + progress(); + } + } + }, false); + + xhr.upload.addEventListener('progress', function(e) { + var curr; + + if (e.lengthComputable && !chunkMerge && xhr.readyState < 2) { + + loaded = e.loaded; + + // to avoid strange bug in safari (not in chrome) with drag&drop. + // bug: macos finder opened in any folder, + // reset safari cache (option+command+e), reload elfinder page, + // drop file from finder + // on first attempt request starts (progress callback called ones) but never ends. + // any next drop - successfull. + if (!data.checked && loaded > 0 && !notifyto) { + notifyto = startNotify(xhr._totalSize - loaded); + } + + if (!filesize) { + filesize = e.total; + if (!loaded) { + loaded = parseInt(filesize * 0.05); + } + } + + curr = loaded - prev; + if (checkNotify() && (curr/e.total) >= 0.05) { + self.notify({type : 'upload', cnt : 0, progress : curr, size : 0}); + prev = loaded; + progress(); + } + + if (!uploadedNtf && loaded >= filesize && !isChunked) { + // Use "chunkmerge" for "server-in-process" notification + uploadedNtf = true; + notifyto1 = setTimeout(function() { + self.notify({type : 'chunkmerge', cnt : cnt}); + }, self.options.notifyDelay); + } + + if (cancelBtn && ! data.multiupload && loaded >= filesize) { + checkNotify() && cancelToggle(false); + } + } + }, false); + + var send = function(files, paths){ + var size = 0, + fcnt = 1, + sfiles = [], + c = 0, + total = cnt, + maxFileSize, + totalSize = 0, + chunked = [], + chunkID = new Date().getTime().toString().substr(-9), // for take care of the 32bit backend system + BYTES_PER_CHUNK = Math.min((fm.uplMaxSize? fm.uplMaxSize : 2097152) - 8190, fm.options.uploadMaxChunkSize), // uplMaxSize margin 8kb or options.uploadMaxChunkSize + blobSlice = chunkEnable? false : '', + blobSize, blobMtime, blobName, i, start, end, chunks, blob, chunk, added, done, last, failChunk, + multi = function(files, num){ + var sfiles = [], cid, sfilesLen = 0, cancelChk, hasChunk; + if (!abort) { + while(files.length && sfiles.length < num) { + sfiles.push(files.shift()); + } + sfilesLen = sfiles.length; + if (sfilesLen) { + cancelChk = sfilesLen; + for (var i=0; i < sfilesLen; i++) { + if (abort) { + break; + } + cid = isDataType? (sfiles[i][0][0]._cid || null) : (sfiles[i][0]._cid || null); + hasChunk = (hasChunk || cid)? true : false; + if (!!failChunk[cid]) { + last--; + continue; + } + fm.exec('upload', { + type: data.type, + isDataType: isDataType, + files: sfiles[i], + checked: true, + target: target, + dropEvt: dropEvt, + renames: renames, + hashes: hashes, + multiupload: true, + overwrite: data.overwrite === 0? 0 : void 0, + clipdata: data.clipdata + }, void 0, target) + .fail(function(error) { + if (error && error === 'No such command') { + abort = true; + fm.error(['errUpload', 'errPerm']); + } + if (cid) { + failChunk[cid] = true; + } + }) + .always(function(e) { + if (e && e.added) added = $.merge(added, e.added); + if (last <= ++done) { + fm.trigger('multiupload', {added: added}); + notifyto && clearTimeout(notifyto); + if (checkNotify()) { + self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0}); + } + } + if (files.length) { + multi(files, 1); // Next one + } else { + if (--cancelChk <= 1) { + if (cancelBtn) { + cancelToggle(false, hasChunk); + } + } + dfrd.resolve(); + } + }); + } + } + } + if (sfiles.length < 1 || abort) { + if (abort) { + notifyto && clearTimeout(notifyto); + if (cid) { + failChunk[cid] = true; + } + dfrd.reject(); + } else { + dfrd.resolve(); + self.uploads.xhrUploading = false; + } + } + }, + check = function(){ + if (!self.uploads.xhrUploading) { + self.uploads.xhrUploading = true; + multi(sfiles, multiMax); // Max connection: 3 + } else { + setTimeout(check, 100); + } + }, + reqId, err; + + if (! dataChecked && (isDataType || data.type == 'files')) { + if (! (maxFileSize = fm.option('uploadMaxSize', target))) { + maxFileSize = 0; + } + for (i=0; i < files.length; i++) { + try { + blob = files[i]; + blobSize = blob.size; + if (blobSlice === false) { + blobSlice = ''; + if (self.api >= 2.1) { + if ('slice' in blob) { + blobSlice = 'slice'; + } else if ('mozSlice' in blob) { + blobSlice = 'mozSlice'; + } else if ('webkitSlice' in blob) { + blobSlice = 'webkitSlice'; + } + } + } + } catch(e) { + cnt--; + total--; + continue; + } + + // file size check + if ((maxFileSize && blobSize > maxFileSize) || (!blobSlice && fm.uplMaxSize && blobSize > fm.uplMaxSize)) { + triggerError(['errUploadFile', blob.name, 'errUploadFileSize'], blob, true); + cnt--; + total--; + continue; + } + + // file mime check + if (blob.type && ! self.uploadMimeCheck(blob.type, target)) { + triggerError(['errUploadFile', blob.name, 'errUploadMime', '(' + blob.type + ')'], blob, true); + cnt--; + total--; + continue; + } + + if (blobSlice && blobSize > BYTES_PER_CHUNK) { + start = 0; + end = BYTES_PER_CHUNK; + chunks = -1; + total = Math.floor((blobSize - 1) / BYTES_PER_CHUNK); + blobMtime = blob.lastModified? Math.round(blob.lastModified/1000) : 0; + blobName = data.clipdata? fm.date(fm.nonameDateFormat) + '.png' : blob.name; + + totalSize += blobSize; + chunked[chunkID] = 0; + while(start < blobSize) { + chunk = blob[blobSlice](start, end); + chunk._chunk = blobName + '.' + (++chunks) + '_' + total + '.part'; + chunk._cid = chunkID; + chunk._range = start + ',' + chunk.size + ',' + blobSize; + chunk._mtime = blobMtime; + chunked[chunkID]++; + + if (size) { + c++; + } + if (typeof sfiles[c] == 'undefined') { + sfiles[c] = []; + if (isDataType) { + sfiles[c][0] = []; + sfiles[c][1] = []; + } + } + size = BYTES_PER_CHUNK; + fcnt = 1; + if (isDataType) { + sfiles[c][0].push(chunk); + sfiles[c][1].push(paths[i]); + } else { + sfiles[c].push(chunk); + } + + start = end; + end = start + BYTES_PER_CHUNK; + } + if (chunk == null) { + triggerError(['errUploadFile', blob.name, 'errUploadFileSize'], blob, true); + cnt--; + total--; + } else { + total += chunks; + size = 0; + fcnt = 1; + c++; + } + continue; + } + if ((fm.uplMaxSize && size + blobSize > fm.uplMaxSize) || fcnt > fm.uplMaxFile) { + size = 0; + fcnt = 1; + c++; + } + if (typeof sfiles[c] == 'undefined') { + sfiles[c] = []; + if (isDataType) { + sfiles[c][0] = []; + sfiles[c][1] = []; + } + } + if (isDataType) { + sfiles[c][0].push(blob); + sfiles[c][1].push(paths[i]); + } else { + sfiles[c].push(blob); + } + size += blobSize; + totalSize += blobSize; + fcnt++; + } + + if (errors.length) { + triggerError(); + } + + if (sfiles.length == 0) { + // no data + data.checked = true; + return false; + } + + if (sfiles.length > 1) { + // multi upload + notifyto = startNotify(totalSize); + added = []; + done = 0; + last = sfiles.length; + failChunk = []; + check(); + return true; + } + + // single upload + if (isDataType) { + files = sfiles[0][0]; + paths = sfiles[0][1]; + } else { + files = sfiles[0]; + } + } + + if (!dataChecked) { + if (!fm.UA.Safari || !data.files) { + notifyto = startNotify(totalSize); + } else { + xhr._totalSize = totalSize; + } + } + + dataChecked = true; + + if (! files.length) { + dfrd.reject(['errUploadNoFiles']); + } + + xhr.open('POST', self.uploadURL, true); + + // set request headers + if (fm.customHeaders) { + $.each(fm.customHeaders, function(key) { + xhr.setRequestHeader(key, this); + }); + } + + // set xhrFields + if (fm.xhrFields) { + $.each(fm.xhrFields, function(key) { + if (key in xhr) { + xhr[key] = this; + } + }); + } + + if (self.api >= 2.1029) { + // request ID + reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16); + formData.append('reqid', reqId); + xhr._requestId = reqId; + } + formData.append('cmd', 'upload'); + formData.append(self.newAPI ? 'target' : 'current', target); + if (renames && renames.length) { + $.each(renames, function(i, v) { + formData.append('renames[]', v); + }); + formData.append('suffix', fm.options.backupSuffix); + } + if (hashes) { + $.each(hashes, function(i, v) { + formData.append('hashes['+ i +']', v); + }); + } + $.each(self.customData, function(key, val) { + formData.append(key, val); + }); + $.each(self.options.onlyMimes, function(i, mime) { + formData.append('mimes[]', mime); + }); + + $.each(files, function(i, file) { + var name, relpath; + if (file._chunkmerged) { + formData.append('chunk', file._chunkmerged); + formData.append('upload[]', file._name); + formData.append('mtime[]', file._mtime); + data.clipdata && formData.append('overwrite', 0); + isChunked = true; + } else { + if (file._chunkfail) { + formData.append('upload[]', 'chunkfail'); + formData.append('mimes', 'chunkfail'); + } else { + if (data.clipdata) { + if (!file._chunk) { + data.overwrite = 0; + name = fm.date(fm.nonameDateFormat) + '.png'; + } + } else { + if (file.name) { + name = file.name; + if (fm.UA.iOS) { + if (name.match(/^image\.jpe?g$/i)) { + data.overwrite = 0; + name = fm.date(fm.nonameDateFormat) + '.jpg'; + } else if (name.match(/^capturedvideo\.mov$/i)) { + data.overwrite = 0; + name = fm.date(fm.nonameDateFormat) + '.mov'; + } + } + relpath = (file.webkitRelativePath || file.relativePath || file._relativePath || '').replace(/[^\/]+$/, ''); + name = relpath + name; + } + } + name? formData.append('upload[]', file, name) : formData.append('upload[]', file); + } + if (file._chunk) { + formData.append('chunk', file._chunk); + formData.append('cid' , file._cid); + formData.append('range', file._range); + formData.append('mtime[]', file._mtime); + isChunked = true; + } else { + formData.append('mtime[]', file.lastModified? Math.round(file.lastModified/1000) : 0); + } + } + }); + + if (isDataType) { + $.each(paths, function(i, path) { + formData.append('upload_path[]', path); + }); + } + + if (data.overwrite === 0) { + formData.append('overwrite', 0); + } + + // send int value that which meta key was pressed when dropped as `dropWith` + if (dropEvt) { + formData.append('dropWith', parseInt( + (dropEvt.altKey ? '1' : '0')+ + (dropEvt.ctrlKey ? '1' : '0')+ + (dropEvt.metaKey ? '1' : '0')+ + (dropEvt.shiftKey? '1' : '0'), 2)); + } + + // set extraData on current request + if (extraData) { + $.each(extraData, function(key, val) { + formData.append(key, val); + }); + } + + xhr.send(formData); + + return true; + }; + + if (! isDataType) { + if (files.length > 0) { + if (! data.clipdata && renames == null) { + var mkdirs = [], + paths = [], + excludes = fm.options.folderUploadExclude[fm.OS] || null; + $.each(files, function(i, file) { + var relPath = file.webkitRelativePath || file.relativePath || '', + idx, rootDir; + if (! relPath) { + return false; + } + if (excludes && file.name.match(excludes)) { + file._remove = true; + relPath = void(0); + } else { + // add '/' as prefix to make same to folder uploading with DnD, see #2607 + relPath = '/' + relPath.replace(/\/[^\/]*$/, '').replace(/^\//, ''); + if (relPath && $.inArray(relPath, mkdirs) === -1) { + mkdirs.push(relPath); + // checking the root directory to supports see #2378 + idx = relPath.substr(1).indexOf('/'); + if (idx !== -1 && (rootDir = relPath.substr(0, idx + 1)) && $.inArray(rootDir, mkdirs) === -1) { + mkdirs.unshift(rootDir); + } + } + } + paths.push(relPath); + }); + renames = []; + hashes = {}; + if (mkdirs.length) { + (function() { + var checkDirs = $.map(mkdirs, function(name) { return name.substr(1).indexOf('/') === -1 ? {name: name.substr(1)} : null;}), + cancelDirs = []; + fm.uploads.checkExists(checkDirs, target, fm, true).done( + function(res, res2) { + var dfds = [], dfd, bak, hash; + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + cancelDirs = $.map(checkDirs, function(dir) { return dir._remove? dir.name : null ;} ); + checkDirs = $.grep(checkDirs, function(dir) { return !dir._remove? true : false ;} ); + } + if (cancelDirs.length) { + $.each(paths.concat(), function(i, path) { + if ($.inArray(path, cancelDirs) === 0) { + files[i]._remove = true; + paths[i] = void(0); + } + }); + } + files = $.grep(files, function(file) { return file._remove? false : true; }); + paths = $.grep(paths, function(path) { return path === void 0 ? false : true; }); + if (checkDirs.length) { + dfd = $.Deferred(); + if (res.length) { + $.each(res, function(i, existName) { + // backup + bak = fm.uniqueName(existName + fm.options.backupSuffix , null, ''); + $.each(res2, function(h, name) { + if (res[0] == name) { + hash = h; + return false; + } + }); + if (! hash) { + hash = fm.fileByName(res[0], target).hash; + } + fm.lockfiles({files : [hash]}); + dfds.push( + fm.request({ + data : {cmd : 'rename', target : hash, name : bak}, + notify : {type : 'rename', cnt : 1} + }) + .fail(function(error) { + dfrd.reject(error); + fm.sync(); + }) + .always(function() { + fm.unlockfiles({files : [hash]}); + }) + ); + }); + } else { + dfds.push(null); + } + + $.when.apply($, dfds).done(function() { + // ensure directories + fm.request({ + data : {cmd : 'mkdir', target : target, dirs : mkdirs}, + notify : {type : 'mkdir', cnt : mkdirs.length}, + preventFail: true + }) + .fail(function(error) { + error = error || ['errUnknown']; + if (error[0] === 'errCmdParams') { + multiMax = 1; + } else { + multiMax = 0; + dfrd.reject(error); + } + }) + .done(function(data) { + var rm = false; + if (!data.hashes) { + data.hashes = {}; + } + paths = $.map(paths.concat(), function(p, i) { + if (p === '/') { + return target; + } else { + if (data.hashes[p]) { + return data.hashes[p]; + } else { + rm = true; + files[i]._remove = true; + return null; + } + } + }); + if (rm) { + files = $.grep(files, function(file) { return file._remove? false : true; }); + } + }) + .always(function(data) { + if (multiMax) { + isDataType = true; + if (! send(files, paths)) { + dfrd.reject(); + } + } + }); + }); + } else { + dfrd.reject(); + } + } + ); + })(); + } else { + fm.uploads.checkExists(files, target, fm).done( + function(res, res2){ + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + hashes = res2; + if (res === null) { + data.overwrite = 0; + } else { + renames = res; + } + files = $.grep(files, function(file){return !file._remove? true : false ;}); + } + cnt = files.length; + if (cnt > 0) { + if (! send(files)) { + dfrd.reject(); + } + } else { + dfrd.reject(); + } + } + ); + } + } else { + if (! send(files)) { + dfrd.reject(); + } + } + } else { + dfrd.reject(); + } + } else { + if (dataChecked) { + send(files[0], files[1]); + } else { + files.done(function(result) { // result: [files, paths, renames, hashes, mkdirs] + renames = []; + cnt = result[0].length; + if (cnt) { + if (result[4] && result[4].length) { + // ensure directories + fm.request({ + data : {cmd : 'mkdir', target : target, dirs : result[4]}, + notify : {type : 'mkdir', cnt : result[4].length}, + preventFail: true + }) + .fail(function(error) { + error = error || ['errUnknown']; + if (error[0] === 'errCmdParams') { + multiMax = 1; + } else { + multiMax = 0; + dfrd.reject(error); + } + }) + .done(function(data) { + var rm = false; + if (!data.hashes) { + data.hashes = {}; + } + result[1] = $.map(result[1], function(p, i) { + result[0][i]._relativePath = p.replace(/^\//, ''); + p = p.replace(/\/[^\/]*$/, ''); + if (p === '') { + return target; + } else { + if (data.hashes[p]) { + return data.hashes[p]; + } else { + rm = true; + result[0][i]._remove = true; + return null; + } + } + }); + if (rm) { + result[0] = $.grep(result[0], function(file) { return file._remove? false : true; }); + } + }) + .always(function(data) { + if (multiMax) { + renames = result[2]; + hashes = result[3]; + send(result[0], result[1]); + } + }); + return; + } else { + result[1] = $.map(result[1], function() { return target; }); + } + renames = result[2]; + hashes = result[3]; + send(result[0], result[1]); + } else { + dfrd.reject(['errUploadNoFiles']); + } + }).fail(function(){ + dfrd.reject(); + }); + } + } + + return dfrd; + }, + + // upload transport using iframe + iframe : function(data, fm) { + var self = fm ? fm : this, + input = data.input? data.input : false, + files = !input ? self.uploads.checkFile(data, self) : false, + dfrd = $.Deferred() + .fail(function(error) { + error && self.error(error); + }), + name = 'iframe-'+fm.namespace+(++self.iframeCnt), + form = $('
      '), + msie = this.UA.IE, + // clear timeouts, close notification dialog, remove form/iframe + onload = function() { + abortto && clearTimeout(abortto); + notifyto && clearTimeout(notifyto); + notify && self.notify({type : 'upload', cnt : -cnt}); + + setTimeout(function() { + msie && $('').appendTo(form); + form.remove(); + iframe.remove(); + }, 100); + }, + iframe = $('') + .on('load', function() { + iframe.off('load') + .on('load', function() { + onload(); + // data will be processed in callback response or window onmessage + dfrd.resolve(); + }); + + // notify dialog + notifyto = setTimeout(function() { + notify = true; + self.notify({type : 'upload', cnt : cnt}); + }, self.options.notifyDelay); + + // emulate abort on timeout + if (self.options.iframeTimeout > 0) { + abortto = setTimeout(function() { + onload(); + dfrd.reject(['errConnect', 'errTimeout']); + }, self.options.iframeTimeout); + } + + form.submit(); + }), + target = (data.target || self.cwd().hash), + names = [], + dfds = [], + renames = [], + hashes = {}, + cnt, notify, notifyto, abortto; + + if (files && files.length) { + $.each(files, function(i, val) { + form.append(''); + }); + cnt = 1; + } else if (input && $(input).is(':file') && $(input).val()) { + if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) { + names = input.files? input.files : [{ name: $(input).val().replace(/^(?:.+[\\\/])?([^\\\/]+)$/, '$1') }]; + //names = $.map(names, function(file){return file.name? { name: file.name } : null ;}); + dfds.push(self.uploads.checkExists(names, target, self).done( + function(res, res2){ + hashes = res2; + if (res === null) { + data.overwrite = 0; + } else{ + renames = res; + cnt = $.grep(names, function(file){return !file._remove? true : false ;}).length; + if (cnt != names.length) { + cnt = 0; + } + } + } + )); + } + cnt = input.files ? input.files.length : 1; + form.append(input); + } else { + return dfrd.reject(); + } + + $.when.apply($, dfds).done(function() { + if (cnt < 1) { + return dfrd.reject(); + } + form.append('') + .append('') + .append('') + .append($(input).attr('name', 'upload[]')); + + if (renames.length > 0) { + $.each(renames, function(i, rename) { + form.append(''); + }); + form.append(''); + } + if (hashes) { + $.each(renames, function(i, v) { + form.append(''); + }); + } + + if (data.overwrite === 0) { + form.append(''); + } + + $.each(self.options.onlyMimes||[], function(i, mime) { + form.append(''); + }); + + $.each(self.customData, function(key, val) { + form.append(''); + }); + + form.appendTo('body'); + iframe.appendTo('body'); + }); + + return dfrd; + } + }, + + + /** + * Bind callback to event(s) The callback is executed at most once per event. + * To bind to multiply events at once, separate events names by space + * + * @param String event name + * @param Function callback + * @param Boolan priority first + * @return elFinder + */ + one : function(ev, callback, priorityFirst) { + var self = this, + event = ev.toLowerCase(), + h = function(e, f) { + if (!self.toUnbindEvents[event]) { + self.toUnbindEvents[event] = []; + } + self.toUnbindEvents[event].push({ + type: event, + callback: h + }); + return (callback.done? callback.done : callback).apply(this, arguments); + }; + if (callback.done) { + h = {done: h}; + } + return this.bind(event, h, priorityFirst); + }, + + /** + * Set/get data into/from localStorage + * + * @param String key + * @param String|void value + * @return String|null + */ + localStorage : function(key, val) { + var self = this, + s = window.localStorage, + oldkey = 'elfinder-'+(key || '')+this.id, // old key of elFinder < 2.1.6 + prefix = window.location.pathname+'-elfinder-', + suffix = this.id, + clrs = [], + retval, oldval, t, precnt, sufcnt; + + // reset this node data + if (typeof(key) === 'undefined') { + precnt = prefix.length; + sufcnt = suffix.length * -1; + $.each(s, function(key) { + if (key.substr(0, precnt) === prefix && key.substr(sufcnt) === suffix) { + clrs.push(key); + } + }); + $.each(clrs, function(i, key) { + s.removeItem(key); + }); + return true; + } + + // new key of elFinder >= 2.1.6 + key = prefix+key+suffix; + + if (val === null) { + return s.removeItem(key); + } + + if (val === void(0) && !(retval = s.getItem(key)) && (oldval = s.getItem(oldkey))) { + val = oldval; + s.removeItem(oldkey); + } + + if (val !== void(0)) { + t = typeof val; + if (t !== 'string' && t !== 'number') { + val = JSON.stringify(val); + } + try { + s.setItem(key, val); + } catch (e) { + try { + s.clear(); + s.setItem(key, val); + } catch (e) { + self.debug('error', e.toString()); + } + } + retval = s.getItem(key); + } + + if (retval && (retval.substr(0,1) === '{' || retval.substr(0,1) === '[')) { + try { + return JSON.parse(retval); + } catch(e) {} + } + return retval; + }, + + /** + * Set/get data into/from sessionStorage + * + * @param String key + * @param String|void value + * @return String|null + */ + sessionStorage : function(key, val) { + var self = this, + s, retval, t; + + try { + s = window.sessionStorage; + } catch(e) {} + + if (!s) { + return; + } + + if (val === null) { + return s.removeItem(key); + } + + if (val !== void(0)) { + t = typeof val; + if (t !== 'string' && t !== 'number') { + val = JSON.stringify(val); + } + try { + s.setItem(key, val); + } catch (e) { + try { + s.clear(); + s.setItem(key, val); + } catch (e) { + self.debug('error', e.toString()); + } + } + } + retval = s.getItem(key); + + if (retval && (retval.substr(0,1) === '{' || retval.substr(0,1) === '[')) { + try { + return JSON.parse(retval); + } catch(e) {} + } + return retval; + }, + + /** + * Get/set cookie + * + * @param String cookie name + * @param String|void cookie value + * @return String|null + */ + cookie : function(name, value) { + var d, o, c, i, retval, t; + + name = 'elfinder-'+name+this.id; + + if (value === void(0)) { + if (this.cookieEnabled && document.cookie && document.cookie != '') { + c = document.cookie.split(';'); + name += '='; + for (i=0; i'), + + /** + * Replace not html-safe symbols to html entities + * + * @param String text to escape + * @return String + */ + escape : function(name) { + return this._node.text(name).html().replace(/"/g, '"').replace(/'/g, '''); + }, + + /** + * Cleanup ajax data. + * For old api convert data into new api format + * + * @param String command name + * @param Object data from backend + * @return Object + */ + normalize : function(data) { + var self = this, + fileFilter = (function() { + var func, filter; + if (filter = self.options.fileFilter) { + if (typeof filter === 'function') { + func = function(file) { + return filter.call(self, file); + }; + } else if (filter instanceof RegExp) { + func = function(file) { + return filter.test(file.name); + }; + } + } + return func? func : null; + })(), + chkCmdMap = function(opts) { + // Disable command to replace with other command + var disabled; + if (opts.uiCmdMap) { + if ($.isPlainObject(opts.uiCmdMap) && Object.keys(opts.uiCmdMap).length) { + if (!opts.disabledFlip) { + opts.disabledFlip = {}; + } + disabled = opts.disabledFlip; + $.each(opts.uiCmdMap, function(f, t) { + if (t === 'hidden' && !disabled[f]) { + opts.disabled.push(f); + opts.disabledFlip[f] = true; + } + }); + } else { + delete opts.uiCmdMap; + } + } + }, + normalizeOptions = function(opts) { + var getType = function(v) { + var type = typeof v; + if (type === 'object' && Array.isArray(v)) { + type = 'array'; + } + return type; + }; + $.each(self.optionProperties, function(k, empty) { + if (empty !== void(0)) { + if (opts[k] && getType(opts[k]) !== getType(empty)) { + opts[k] = empty; + } + } + }); + if (opts.disabled) { + opts.disabledFlip = self.arrayFlip(opts.disabled, true); + $.each(self.options.disabledCmdsRels, function(com, rels) { + var m, flg; + if (opts.disabledFlip[com]) { + flg = true; + } else if (m = com.match(/^([^&]+)&([^=]+)=(.*)$/)) { + if (opts.disabledFlip[m[1]] && opts[m[2]] == m[3]) { + flg = true; + } + } + if (flg) { + $.each(rels, function(i, rel) { + if (!opts.disabledFlip[rel]) { + opts.disabledFlip[rel] = true; + opts.disabled.push(rel); + } + }); + } + }); + } else { + opts.disabledFlip = {}; + } + return opts; + }, + filter = function(file, asMap, type) { + var res = asMap? file : true, + ign = asMap? null : false, + vid, targetOptions, isRoot, rootNames; + + if (file && file.hash && file.name && file.mime) { + if (file.mime === 'application/x-empty') { + file.mime = 'text/plain'; + } + + isRoot = self.isRoot(file); + if (isRoot && ! file.volumeid) { + self.debug('warning', 'The volume root statuses requires `volumeid` property.'); + } + if (isRoot || file.mime === 'directory') { + // Prevention of circular reference + if (file.phash) { + if (file.phash === file.hash) { + error = error.concat(['Parent folder of "$1" is itself.', file.name]); + return ign; + } + if (isRoot && file.volumeid && file.phash.indexOf(file.volumeid) === 0) { + error = error.concat(['Parent folder of "$1" is inner itself.', file.name]); + return ign; + } + } + + // set options, tmbUrls for each volume + if (file.volumeid) { + vid = file.volumeid; + + if (isRoot) { + // make or update of leaf roots cache + if (file.phash) { + if (! self.leafRoots[file.phash]) { + self.leafRoots[file.phash] = [ file.hash ]; + } else { + if ($.inArray(file.hash, self.leafRoots[file.phash]) === -1) { + self.leafRoots[file.phash].push(file.hash); + } + } + } + + self.hasVolOptions = true; + if (! self.volOptions[vid]) { + self.volOptions[vid] = { + // set dispInlineRegex + dispInlineRegex: self.options.dispInlineRegex + }; + } + + targetOptions = self.volOptions[vid]; + + if (file.options) { + // >= v.2.1.14 has file.options + Object.assign(targetOptions, file.options); + } + + // for compat <= v2.1.13 + if (file.disabled) { + targetOptions.disabled = file.disabled; + targetOptions.disabledFlip = self.arrayFlip(file.disabled, true); + } + if (file.tmbUrl) { + targetOptions.tmbUrl = file.tmbUrl; + } + + // '/' required at the end of url + if (targetOptions.url && targetOptions.url.substr(-1) !== '/') { + targetOptions.url += '/'; + } + + // check uiCmdMap + chkCmdMap(targetOptions); + + // check trash bin hash + if (targetOptions.trashHash) { + if (self.trashes[targetOptions.trashHash] === false) { + delete targetOptions.trashHash; + } else { + self.trashes[targetOptions.trashHash] = file.hash; + } + } + + // set immediate properties + $.each(self.optionProperties, function(k) { + if (targetOptions[k]) { + file[k] = targetOptions[k]; + } + }); + + // regist fm.roots + if (type !== 'cwd') { + self.roots[vid] = file.hash; + } + + // regist fm.volumeExpires + if (file.expires) { + self.volumeExpires[vid] = file.expires; + } + } + + if (prevId !== vid) { + prevId = vid; + i18nFolderName = self.option('i18nFolderName', vid); + } + } + + // volume root i18n name + if (isRoot && ! file.i18) { + name = 'volume_' + file.name, + i18 = self.i18n(false, name); + + if (name !== i18) { + file.i18 = i18; + } + } + + // i18nFolderName + if (i18nFolderName && ! file.i18) { + name = 'folder_' + file.name, + i18 = self.i18n(false, name); + + if (name !== i18) { + file.i18 = i18; + } + } + + if (isRoot && self.options.enableRootRename !== false) { + if (rootNames = self.storage('rootNames')) { + if (rootNames[file.hash]) { + file._name = file.name; + file._i18 = file.i18; + file.name = rootNames[file.hash] = rootNames[file.hash]; + delete file.i18; + } + self.storage('rootNames', rootNames); + } + } + + // lock trash bins holder + if (self.trashes[file.hash]) { + file.locked = true; + } + } else { + if (fileFilter) { + try { + if (! fileFilter(file)) { + return ign; + } + } catch(e) { + self.debug(e); + } + } + if (file.size == 0) { + file.mime = self.getMimetype(file.name, file.mime); + } + } + + if (file.options) { + self.optionsByHashes[file.hash] = normalizeOptions(file.options); + } + + delete file.options; + + return res; + } + return ign; + }, + getDescendants = function(hashes) { + var res = []; + $.each(self.files(), function(h, f) { + $.each(self.parents(h), function(i, ph) { + if ($.inArray(ph, hashes) !== -1 && $.inArray(h, hashes) === -1) { + res.push(h); + return false; + } + }); + }); + return res; + }, + applyLeafRootStats = function(dataArr, type) { + $.each(dataArr, function(i, f) { + var pfile, done; + if (self.leafRoots[f.hash]) { + self.applyLeafRootStats(f); + } + // update leaf root parent stat + if (type !== 'change' && f.phash && self.isRoot(f) && (pfile = self.file(f.phash))) { + self.applyLeafRootStats(pfile); + // add to data.changed + if (!data.changed) { + data.changed = [pfile]; + } else { + $.each(data.changed, function(i, f) { + if (f.hash === pfile.hash) { + data.changed[i] = pfile; + done = true; + return false; + } + }); + if (!done) { + data.changed.push(pfile); + } + } + } + }); + }, + error = [], + name, i18, i18nFolderName, prevId, cData; + + // set cunstom data + if (data.customData && (!self.prevCustomData || (JSON.stringify(data.customData) !== JSON.stringify(self.prevCustomData)))) { + self.prevCustomData = data.customData; + try { + cData = JSON.parse(data.customData); + if ($.isPlainObject(cData)) { + self.prevCustomData = cData; + $.each(Object.keys(cData), function(i, key) { + if (cData[key] === null) { + delete cData[key]; + delete self.optsCustomData[key]; + } + }); + self.customData = Object.assign({}, self.optsCustomData, cData); + } + } catch(e) {} + } + + if (data.options) { + normalizeOptions(data.options); + } + + if (data.cwd) { + if (data.cwd.volumeid && data.options && Object.keys(data.options).length && self.isRoot(data.cwd)) { + self.hasVolOptions = true; + self.volOptions[data.cwd.volumeid] = data.options; + } + data.cwd = filter(data.cwd, true, 'cwd'); + } + if (data.files) { + data.files = $.grep(data.files, filter); + } + if (data.tree) { + data.tree = $.grep(data.tree, filter); + } + if (data.added) { + data.added = $.grep(data.added, filter); + } + if (data.changed) { + data.changed = $.grep(data.changed, filter); + } + if (data.removed && data.removed.length && self.searchStatus.state === 2) { + data.removed = data.removed.concat(getDescendants(data.removed)); + } + if (data.api) { + data.init = true; + } + + if (Object.keys(self.leafRoots).length) { + data.files && applyLeafRootStats(data.files); + data.tree && applyLeafRootStats(data.tree); + data.added && applyLeafRootStats(data.added); + data.changed && applyLeafRootStats(data.changed, 'change'); + } + + // merge options that apply only to cwd + if (data.cwd && data.cwd.options && data.options) { + Object.assign(data.options, normalizeOptions(data.cwd.options)); + } + + // '/' required at the end of url + if (data.options && data.options.url && data.options.url.substr(-1) !== '/') { + data.options.url += '/'; + } + + // check error + if (error.length) { + data.norError = ['errResponse'].concat(error); + } + + return data; + }, + + /** + * Update sort options + * + * @param {String} sort type + * @param {String} sort order + * @param {Boolean} show folder first + */ + setSort : function(type, order, stickFolders, alsoTreeview) { + this.storage('sortType', (this.sortType = this.sortRules[type] ? type : 'name')); + this.storage('sortOrder', (this.sortOrder = /asc|desc/.test(order) ? order : 'asc')); + this.storage('sortStickFolders', (this.sortStickFolders = !!stickFolders) ? 1 : ''); + this.storage('sortAlsoTreeview', (this.sortAlsoTreeview = !!alsoTreeview) ? 1 : ''); + this.trigger('sortchange'); + }, + + _sortRules : { + name : function(file1, file2) { + return elFinder.prototype.naturalCompare(file1.i18 || file1.name, file2.i18 || file2.name); + }, + size : function(file1, file2) { + var size1 = parseInt(file1.size) || 0, + size2 = parseInt(file2.size) || 0; + + return size1 === size2 ? 0 : size1 > size2 ? 1 : -1; + }, + kind : function(file1, file2) { + return elFinder.prototype.naturalCompare(file1.mime, file2.mime); + }, + date : function(file1, file2) { + var date1 = file1.ts || file1.date || 0, + date2 = file2.ts || file2.date || 0; + + return date1 === date2 ? 0 : date1 > date2 ? 1 : -1; + }, + perm : function(file1, file2) { + var val = function(file) { return (file.write? 2 : 0) + (file.read? 1 : 0); }, + v1 = val(file1), + v2 = val(file2); + return v1 === v2 ? 0 : v1 > v2 ? 1 : -1; + }, + mode : function(file1, file2) { + var v1 = file1.mode || (file1.perm || ''), + v2 = file2.mode || (file2.perm || ''); + return elFinder.prototype.naturalCompare(v1, v2); + }, + owner : function(file1, file2) { + var v1 = file1.owner || '', + v2 = file2.owner || ''; + return elFinder.prototype.naturalCompare(v1, v2); + }, + group : function(file1, file2) { + var v1 = file1.group || '', + v2 = file2.group || ''; + return elFinder.prototype.naturalCompare(v1, v2); + } + }, + + /** + * Valid sort rule names + * + * @type Object + */ + sorters : {}, + + /** + * Compare strings for natural sort + * + * @param String + * @param String + * @return Number + */ + naturalCompare : function(a, b) { + var self = elFinder.prototype.naturalCompare; + if (typeof self.loc == 'undefined') { + self.loc = (navigator.userLanguage || navigator.browserLanguage || navigator.language || 'en-US'); + } + if (typeof self.sort == 'undefined') { + if ('11'.localeCompare('2', self.loc, {numeric: true}) > 0) { + // Native support + if (window.Intl && window.Intl.Collator) { + self.sort = new Intl.Collator(self.loc, {numeric: true}).compare; + } else { + self.sort = function(a, b) { + return a.localeCompare(b, self.loc, {numeric: true}); + }; + } + } else { + /* + * Edited for elFinder (emulates localeCompare() by numeric) by Naoki Sawada aka nao-pon + */ + /* + * Huddle/javascript-natural-sort (https://github.com/Huddle/javascript-natural-sort) + */ + /* + * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license + * Author: Jim Palmer (based on chunking idea from Dave Koelle) + * http://opensource.org/licenses/mit-license.php + */ + self.sort = function(a, b) { + var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi, + sre = /(^[ ]*|[ ]*$)/g, + dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, + hre = /^0x[0-9a-f]+$/i, + ore = /^0/, + syre = /^[\x01\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/, // symbol first - (Naoki Sawada) + i = function(s) { return self.sort.insensitive && (''+s).toLowerCase() || ''+s; }, + // convert all to strings strip whitespace + // first character is "_", it's smallest - (Naoki Sawada) + x = i(a).replace(sre, '').replace(/^_/, "\x01") || '', + y = i(b).replace(sre, '').replace(/^_/, "\x01") || '', + // chunk/tokenize + xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), + yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), + // numeric, hex or date detection + xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)), + yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null, + oFxNcL, oFyNcL, + locRes = 0; + + // first try and sort Hex codes or Dates + if (yD) { + if ( xD < yD ) return -1; + else if ( xD > yD ) return 1; + } + // natural sorting through split numeric strings and default strings + for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { + + // find floats not starting with '0', string or 0 if not defined (Clint Priest) + oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0; + oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; + + // handle numeric vs string comparison - number < string - (Kyle Adams) + // but symbol first < number - (Naoki Sawada) + if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { + if (isNaN(oFxNcL) && (typeof oFxNcL !== 'string' || ! oFxNcL.match(syre))) { + return 1; + } else if (typeof oFyNcL !== 'string' || ! oFyNcL.match(syre)) { + return -1; + } + } + + // use decimal number comparison if either value is string zero + if (parseInt(oFxNcL, 10) === 0) oFxNcL = 0; + if (parseInt(oFyNcL, 10) === 0) oFyNcL = 0; + + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + if (typeof oFxNcL !== typeof oFyNcL) { + oFxNcL += ''; + oFyNcL += ''; + } + + // use locale sensitive sort for strings when case insensitive + // note: localeCompare interleaves uppercase with lowercase (e.g. A,a,B,b) + if (self.sort.insensitive && typeof oFxNcL === 'string' && typeof oFyNcL === 'string') { + locRes = oFxNcL.localeCompare(oFyNcL, self.loc); + if (locRes !== 0) return locRes; + } + + if (oFxNcL < oFyNcL) return -1; + if (oFxNcL > oFyNcL) return 1; + } + return 0; + }; + self.sort.insensitive = true; + } + } + return self.sort(a, b); + }, + + /** + * Compare files based on elFinder.sort + * + * @param Object file + * @param Object file + * @return Number + */ + compare : function(file1, file2) { + var self = this, + type = self.sortType, + asc = self.sortOrder == 'asc', + stick = self.sortStickFolders, + rules = self.sortRules, + sort = rules[type], + d1 = file1.mime == 'directory', + d2 = file2.mime == 'directory', + res; + + if (stick) { + if (d1 && !d2) { + return -1; + } else if (!d1 && d2) { + return 1; + } + } + + res = asc ? sort(file1, file2) : sort(file2, file1); + + return type !== 'name' && res === 0 + ? res = asc ? rules.name(file1, file2) : rules.name(file2, file1) + : res; + }, + + /** + * Sort files based on config + * + * @param Array files + * @return Array + */ + sortFiles : function(files) { + return files.sort(this.compare); + }, + + /** + * Open notification dialog + * and append/update message for required notification type. + * + * @param Object options + * @example + * this.notify({ + * type : 'copy', + * msg : 'Copy files', // not required for known types @see this.notifyType + * cnt : 3, + * hideCnt : false, // true for not show count + * progress : 10, // progress bar percents (use cnt : 0 to update progress bar) + * cancel : callback // callback function for cancel button + * }) + * @return elFinder + */ + notify : function(opts) { + var self = this, + type = opts.type, + id = opts.id? 'elfinder-notify-'+opts.id : '', + msg = this.i18n((typeof opts.msg !== 'undefined')? opts.msg : (this.messages['ntf'+type] ? 'ntf'+type : 'ntfsmth')), + hiddens = this.arrayFlip(this.options.notifyDialog.hiddens || []), + ndialog = this.ui.notify, + dialog = ndialog.closest('.ui-dialog'), + notify = ndialog.children('.elfinder-notify-'+type+(id? ('.'+id) : '')), + button = notify.children('div.elfinder-notify-cancel').children('button'), + ntpl = '
      {msg}
      ', + delta = opts.cnt + 0, + size = (typeof opts.size != 'undefined')? parseInt(opts.size) : null, + progress = (typeof opts.progress != 'undefined' && opts.progress >= 0) ? opts.progress : null, + fakeint = opts.fakeinterval || 200, + cancel = opts.cancel, + clhover = 'ui-state-hover', + close = function() { + var prog = notify.find('.elfinder-notify-progress'), + rm = function() { + notify.remove(); + if (!ndialog.children(dialog.data('minimized')? void(0) : ':visible').length) { + if (dialog.data('minimized')) { + dialog.data('minimized').hide(); + } else { + ndialog.elfinderdialog('close'); + } + } + setProgressbar(); + }; + notify._esc && $(document).off('keydown', notify._esc); + if (notify.data('cur') < 100) { + prog.animate({ + width : '100%' + }, 50, function() { requestAnimationFrame(function() { rm(); }); }); + } else { + rm(); + } + }, + fakeUp = function(interval) { + var cur; + if (notify.length) { + cur = notify.data('cur') + 1; + if (cur <= 98) { + notify.find('.elfinder-notify-progress').width(cur + '%'); + notify.data('cur', cur); + setProgressbar(); + setTimeout(function() { + interval *= 1.05; + fakeUp(interval); + }, interval); + } + } + }, + setProgressbar = function() { + var cnt = 0, + val = 0, + ntfs = ndialog.children('.elfinder-notify'), + w; + if (ntfs.length) { + ntfs.each(function() { + cnt++; + val += Math.min($(this).data('cur'), 100); + }); + w = cnt? Math.floor(val / (cnt * 100) * 100) + '%' : 0; + self.ui.progressbar.width(w); + if (dialog.data('minimized')) { + dialog.data('minimized').title(w); + dialog.data('minimized').dialog().children('.ui-dialog-titlebar').children('.elfinder-ui-progressbar').width(w); + } + } else { + self.ui.progressbar.width(0); + dialog.data('minimized') && dialog.data('minimized').hide(); + } + }, + cnt, total, prc; + + if (!type) { + return this; + } + + if (!notify.length) { + notify = $(ntpl.replace(/\{type\}/g, type).replace(/\{msg\}/g, msg)); + if (hiddens[type]) { + notify.hide(); + } else { + ndialog.on('minimize', function(e) { + dialog.data('minimized') && setProgressbar(); + }); + } + notify.appendTo(ndialog).data('cnt', 0); + + if (progress != null) { + notify.data({progress : 0, total : 0, cur : 0}); + } else { + notify.data({cur : 0}); + fakeUp(fakeint); + } + + if (cancel) { + button = $('') + .on('mouseenter mouseleave', function(e) { + $(this).toggleClass(clhover, e.type === 'mouseenter'); + }); + notify.children('div.elfinder-notify-cancel').append(button); + } + ndialog.trigger('resize'); + } else if (typeof opts.msg !== 'undefined') { + notify.children('span.elfinder-notify-msg').html(msg); + } + + cnt = delta + parseInt(notify.data('cnt')); + + if (cnt > 0) { + if (cancel && button.length) { + if (typeof cancel === 'function' || (typeof cancel === 'object' && cancel.promise)) { + notify._esc = function(e) { + if (e.type == 'keydown' && e.keyCode != $.ui.keyCode.ESCAPE) { + return; + } + e.preventDefault(); + e.stopPropagation(); + close(); + if (cancel.promise) { + cancel.reject(0); // 0 is canceling flag + } else { + cancel(e); + } + }; + button.on('click', function(e) { + notify._esc(e); + }); + $(document).on('keydown.' + this.namespace, notify._esc); + } + } + + !opts.hideCnt && notify.children('.elfinder-notify-cnt').text('('+cnt+')'); + if (delta > 0 && ndialog.is(':hidden') && !hiddens[type]) { + if (dialog.data('minimized')) { + dialog.data('minimized').show(); + } else { + ndialog.elfinderdialog('open', this).height('auto'); + } + } + notify.data('cnt', cnt); + + if ((progress != null) + && (total = notify.data('total')) >= 0 + && (prc = notify.data('progress')) >= 0) { + + total += size != null? size : delta; + prc += progress; + (size == null && delta < 0) && (prc += delta * 100); + notify.data({progress : prc, total : total}); + if (size != null) { + prc *= 100; + total = Math.max(1, total); + } + progress = Math.min(parseInt(prc/total), 100); + + notify.find('.elfinder-notify-progress') + .animate({ + width : (progress < 100 ? progress : 100)+'%' + }, 20, function() { + notify.data('cur', progress); + setProgressbar(); + }); + } + + } else { + close(); + } + + return this; + }, + + /** + * Open confirmation dialog + * + * @param Object options + * @example + * this.confirm({ + * cssClass : 'elfinder-confirm-mydialog', + * title : 'Remove files', + * text : 'Here is question text', + * accept : { // accept callback - required + * label : 'Continue', + * callback : function(applyToAll) { fm.log('Ok') } + * }, + * cancel : { // cancel callback - required + * label : 'Cancel', + * callback : function() { fm.log('Cancel')} + * }, + * reject : { // reject callback - optionally + * label : 'No', + * callback : function(applyToAll) { fm.log('No')} + * }, + * buttons : [ // additional buttons callback - optionally + * { + * label : 'Btn1', + * callback : function(applyToAll) { fm.log('Btn1')} + * } + * ], + * all : true // display checkbox "Apply to all" + * }) + * @return elFinder + */ + confirm : function(opts) { + var self = this, + complete = false, + options = { + cssClass : 'elfinder-dialog-confirm', + modal : true, + resizable : false, + title : this.i18n(opts.title || 'confirmReq'), + buttons : {}, + close : function() { + !complete && opts.cancel.callback(); + $(this).elfinderdialog('destroy'); + } + }, + apply = this.i18n('apllyAll'), + label, checkbox, btnNum; + + if (opts.cssClass) { + options.cssClass += ' ' + opts.cssClass; + } + options.buttons[this.i18n(opts.accept.label)] = function() { + opts.accept.callback(!!(checkbox && checkbox.prop('checked'))); + complete = true; + $(this).elfinderdialog('close'); + }; + options.buttons[this.i18n(opts.accept.label)]._cssClass = 'elfinder-confirm-accept'; + + if (opts.reject) { + options.buttons[this.i18n(opts.reject.label)] = function() { + opts.reject.callback(!!(checkbox && checkbox.prop('checked'))); + complete = true; + $(this).elfinderdialog('close'); + }; + options.buttons[this.i18n(opts.reject.label)]._cssClass = 'elfinder-confirm-reject'; + } + + if (opts.buttons && opts.buttons.length > 0) { + btnNum = 1; + $.each(opts.buttons, function(i, v){ + options.buttons[self.i18n(v.label)] = function() { + v.callback(!!(checkbox && checkbox.prop('checked'))); + complete = true; + $(this).elfinderdialog('close'); + }; + options.buttons[self.i18n(v.label)]._cssClass = 'elfinder-confirm-extbtn' + (btnNum++); + if (v.cssClass) { + options.buttons[self.i18n(v.label)]._cssClass += ' ' + v.cssClass; + } + }); + } + + options.buttons[this.i18n(opts.cancel.label)] = function() { + $(this).elfinderdialog('close'); + }; + options.buttons[this.i18n(opts.cancel.label)]._cssClass = 'elfinder-confirm-cancel'; + + if (opts.all) { + options.create = function() { + var base = $('
      '); + checkbox = $(''); + $(this).next().find('.ui-dialog-buttonset') + .prepend(base.append($('').prepend(checkbox))); + }; + } + + if (opts.optionsCallback && typeof opts.optionsCallback === 'function') { + opts.optionsCallback(options); + } + + return this.dialog('' + this.i18n(opts.text), options); + }, + + /** + * Create unique file name in required dir + * + * @param String file name + * @param String parent dir hash + * @param String glue + * @return String + */ + uniqueName : function(prefix, phash, glue) { + var i = 0, ext = '', p, name; + + prefix = this.i18n(false, prefix); + phash = phash || this.cwd().hash; + glue = (typeof glue === 'undefined')? ' ' : glue; + + if (p = prefix.match(/^(.+)(\.[^.]+)$/)) { + ext = p[2]; + prefix = p[1]; + } + + name = prefix+ext; + + if (!this.fileByName(name, phash)) { + return name; + } + while (i < 10000) { + name = prefix + glue + (++i) + ext; + if (!this.fileByName(name, phash)) { + return name; + } + } + return prefix + Math.random() + ext; + }, + + /** + * Return message translated onto current language + * Allowed accept HTML element that was wrapped in jQuery object + * To be careful to XSS vulnerability of HTML element Ex. You should use `fm.escape(file.name)` + * + * @param String|Array message[s]|Object jQuery + * @return String + **/ + i18n : function() { + var self = this, + messages = this.messages, + input = [], + ignore = [], + message = function(m) { + var file; + if (m.indexOf('#') === 0) { + if ((file = self.file(m.substr(1)))) { + return file.name; + } + } + return m; + }, + i, j, m, escFunc, start = 0, isErr; + + if (arguments.length && arguments[0] === false) { + escFunc = function(m){ return m; }; + start = 1; + } + for (i = start; i< arguments.length; i++) { + m = arguments[i]; + + if (Array.isArray(m)) { + for (j = 0; j < m.length; j++) { + if (m[j] instanceof jQuery) { + // jQuery object is HTML element + input.push(m[j]); + } else if (typeof m[j] !== 'undefined'){ + input.push(message('' + m[j])); + } + } + } else if (m instanceof jQuery) { + // jQuery object is HTML element + input.push(m[j]); + } else if (typeof m !== 'undefined'){ + input.push(message('' + m)); + } + } + + for (i = 0; i < input.length; i++) { + // dont translate placeholders + if ($.inArray(i, ignore) !== -1) { + continue; + } + m = input[i]; + if (typeof m == 'string') { + isErr = !!(messages[m] && m.match(/^err/)); + // translate message + m = messages[m] || (escFunc? escFunc(m) : self.escape(m)); + // replace placeholders in message + m = m.replace(/\$(\d+)/g, function(match, placeholder) { + var res; + placeholder = i + parseInt(placeholder); + if (placeholder > 0 && input[placeholder]) { + ignore.push(placeholder); + } + res = escFunc? escFunc(input[placeholder]) : self.escape(input[placeholder]); + if (isErr) { + res = '' + res + ''; + } + return res; + }); + } else { + // get HTML from jQuery object + m = m.get(0).outerHTML; + } + + input[i] = m; + } + + return $.grep(input, function(m, i) { return $.inArray(i, ignore) === -1 ? true : false; }).join('
      '); + }, + + /** + * Get icon style from file.icon + * + * @param Object elFinder file object + * @return String|Object + */ + getIconStyle : function(file, asObject) { + var self = this, + template = { + 'background' : 'url(\'{url}\') 0 0 no-repeat', + 'background-size' : 'contain' + }, + style = '', + cssObj = {}, + i = 0; + if (file.icon) { + style = 'style="'; + $.each(template, function(k, v) { + if (i++ === 0) { + v = v.replace('{url}', self.escape(file.icon)); + } + if (asObject) { + cssObj[k] = v; + } else { + style += k+':'+v+';'; + } + }); + style += '"'; + } + return asObject? cssObj : style; + }, + + /** + * Convert mimetype into css classes + * + * @param String file mimetype + * @return String + */ + mime2class : function(mimeType) { + var prefix = 'elfinder-cwd-icon-', + mime = mimeType.toLowerCase(), + isText = this.textMimes[mime]; + + mime = mime.split('/'); + if (isText) { + mime[0] += ' ' + prefix + 'text'; + } else if (mime[1] && mime[1].match(/\+xml$/)) { + mime[0] += ' ' + prefix + 'xml'; + } + + return prefix + mime[0] + (mime[1] ? ' ' + prefix + mime[1].replace(/(\.|\+)/g, '-') : ''); + }, + + /** + * Return localized kind of file + * + * @param Object|String file or file mimetype + * @return String + */ + mime2kind : function(f) { + var isObj = typeof(f) == 'object' ? true : false, + mime = isObj ? f.mime : f, + kind; + + + if (isObj && f.alias && mime != 'symlink-broken') { + kind = 'Alias'; + } else if (this.kinds[mime]) { + if (isObj && mime === 'directory' && (! f.phash || f.isroot)) { + kind = 'Root'; + } else { + kind = this.kinds[mime]; + } + } else if (this.mimeTypes[mime]) { + kind = this.mimeTypes[mime].toUpperCase(); + if (!this.messages['kind'+kind]) { + kind = null; + } + } + if (! kind) { + if (mime.indexOf('text') === 0) { + kind = 'Text'; + } else if (mime.indexOf('image') === 0) { + kind = 'Image'; + } else if (mime.indexOf('audio') === 0) { + kind = 'Audio'; + } else if (mime.indexOf('video') === 0) { + kind = 'Video'; + } else if (mime.indexOf('application') === 0) { + kind = 'App'; + } else if (mime.indexOf('font') === 0) { + kind = 'Font'; + } else { + kind = mime; + } + } + + return this.messages['kind'+kind] ? this.i18n('kind'+kind) : mime; + }, + + /** + * Return boolean Is mime-type text file + * + * @param String mime-type + * @return Boolean + */ + mimeIsText : function(mime) { + return (this.textMimes[mime.toLowerCase()] || (mime.indexOf('text/') === 0 && mime.substr(5, 3) !== 'rtf') || mime.match(/^application\/.+\+xml$/))? true : false; + }, + + /** + * Returns a date string formatted according to the given format string + * + * @param String format string + * @param Object Date object + * @return String + */ + date : function(format, date) { + var self = this, + output, d, dw, m, y, h, g, i, s; + + if (! date) { + date = new Date(); + } + + h = date[self.getHours](); + g = h > 12 ? h - 12 : h; + i = date[self.getMinutes](); + s = date[self.getSeconds](); + d = date[self.getDate](); + dw = date[self.getDay](); + m = date[self.getMonth]() + 1; + y = date[self.getFullYear](); + + output = format.replace(/[a-z]/gi, function(val) { + switch (val) { + case 'd': return d > 9 ? d : '0'+d; + case 'j': return d; + case 'D': return self.i18n(self.i18.daysShort[dw]); + case 'l': return self.i18n(self.i18.days[dw]); + case 'm': return m > 9 ? m : '0'+m; + case 'n': return m; + case 'M': return self.i18n(self.i18.monthsShort[m-1]); + case 'F': return self.i18n(self.i18.months[m-1]); + case 'Y': return y; + case 'y': return (''+y).substr(2); + case 'H': return h > 9 ? h : '0'+h; + case 'G': return h; + case 'g': return g; + case 'h': return g > 9 ? g : '0'+g; + case 'a': return h >= 12 ? 'pm' : 'am'; + case 'A': return h >= 12 ? 'PM' : 'AM'; + case 'i': return i > 9 ? i : '0'+i; + case 's': return s > 9 ? s : '0'+s; + } + return val; + }); + + return output; + }, + + /** + * Return localized date + * + * @param Object file object + * @return String + */ + formatDate : function(file, t) { + var self = this, + ts = t || file.ts, + i18 = self.i18, + date, format, output, d, dw, m, y, h, g, i, s; + + if (self.options.clientFormatDate && ts > 0) { + + date = new Date(ts*1000); + format = ts >= this.yesterday + ? this.fancyFormat + : this.dateFormat; + + output = self.date(format, date); + + return ts >= this.yesterday + ? output.replace('$1', this.i18n(ts >= this.today ? 'Today' : 'Yesterday')) + : output; + } else if (file.date) { + return file.date.replace(/([a-z]+)\s/i, function(a1, a2) { return self.i18n(a2)+' '; }); + } + + return self.i18n('dateUnknown'); + }, + + /** + * Return localized number string + * + * @param Number + * @return String + */ + toLocaleString : function(num) { + var v = new Number(num); + if (v) { + if (v.toLocaleString) { + return v.toLocaleString(); + } else { + return String(num).replace( /(\d)(?=(\d\d\d)+(?!\d))/g, '$1,'); + } + } + return num; + }, + + /** + * Return css class marks file permissions + * + * @param Object file + * @return String + */ + perms2class : function(o) { + var c = ''; + + if (!o.read && !o.write) { + c = 'elfinder-na'; + } else if (!o.read) { + c = 'elfinder-wo'; + } else if (!o.write) { + c = 'elfinder-ro'; + } + + if (o.type) { + c += ' elfinder-' + this.escape(o.type); + } + + return c; + }, + + /** + * Return localized string with file permissions + * + * @param Object file + * @return String + */ + formatPermissions : function(f) { + var p = []; + + f.read && p.push(this.i18n('read')); + f.write && p.push(this.i18n('write')); + + return p.length ? p.join(' '+this.i18n('and')+' ') : this.i18n('noaccess'); + }, + + /** + * Return formated file size + * + * @param Number file size + * @return String + */ + formatSize : function(s) { + var n = 1, u = 'b'; + + if (s == 'unknown') { + return this.i18n('unknown'); + } + + if (s > 1073741824) { + n = 1073741824; + u = 'GB'; + } else if (s > 1048576) { + n = 1048576; + u = 'MB'; + } else if (s > 1024) { + n = 1024; + u = 'KB'; + } + s = s/n; + return (s > 0 ? n >= 1048576 ? s.toFixed(2) : Math.round(s) : 0) +' '+u; + }, + + /** + * Return formated file mode by options.fileModeStyle + * + * @param String file mode + * @param String format style + * @return String + */ + formatFileMode : function(p, style) { + var i, o, s, b, sticy, suid, sgid, str, oct; + + if (!style) { + style = this.options.fileModeStyle.toLowerCase(); + } + p = $.trim(p); + if (p.match(/[rwxs-]{9}$/i)) { + str = p = p.substr(-9); + if (style == 'string') { + return str; + } + oct = ''; + s = 0; + for (i=0; i<7; i=i+3) { + o = p.substr(i, 3); + b = 0; + if (o.match(/[r]/i)) { + b += 4; + } + if (o.match(/[w]/i)) { + b += 2; + } + if (o.match(/[xs]/i)) { + if (o.match(/[xs]/)) { + b += 1; + } + if (o.match(/[s]/i)) { + if (i == 0) { + s += 4; + } else if (i == 3) { + s += 2; + } + } + } + oct += b.toString(8); + } + if (s) { + oct = s.toString(8) + oct; + } + } else { + p = parseInt(p, 8); + oct = p? p.toString(8) : ''; + if (!p || style == 'octal') { + return oct; + } + o = p.toString(8); + s = 0; + if (o.length > 3) { + o = o.substr(-4); + s = parseInt(o.substr(0, 1), 8); + o = o.substr(1); + } + sticy = ((s & 1) == 1); // not support + sgid = ((s & 2) == 2); + suid = ((s & 4) == 4); + str = ''; + for(i=0; i<3; i++) { + if ((parseInt(o.substr(i, 1), 8) & 4) == 4) { + str += 'r'; + } else { + str += '-'; + } + if ((parseInt(o.substr(i, 1), 8) & 2) == 2) { + str += 'w'; + } else { + str += '-'; + } + if ((parseInt(o.substr(i, 1), 8) & 1) == 1) { + str += ((i==0 && suid)||(i==1 && sgid))? 's' : 'x'; + } else { + str += '-'; + } + } + } + if (style == 'both') { + return str + ' (' + oct + ')'; + } else if (style == 'string') { + return str; + } else { + return oct; + } + }, + + /** + * Regist this.decodeRawString function + * + * @return void + */ + registRawStringDecoder : function(rawStringDecoder) { + if (typeof rawStringDecoder === 'function') { + this.decodeRawString = this.options.rawStringDecoder = rawStringDecoder; + } + }, + + /** + * Return boolean that uploadable MIME type into target folder + * + * @param String mime MIME type + * @param String target target folder hash + * @return Bool + */ + uploadMimeCheck : function(mime, target) { + target = target || this.cwd().hash; + var res = true, // default is allow + mimeChecker = this.option('uploadMime', target), + allow, + deny, + check = function(checker) { + var ret = false; + if (typeof checker === 'string' && checker.toLowerCase() === 'all') { + ret = true; + } else if (Array.isArray(checker) && checker.length) { + $.each(checker, function(i, v) { + v = v.toLowerCase(); + if (v === 'all' || mime.indexOf(v) === 0) { + ret = true; + return false; + } + }); + } + return ret; + }; + if (mime && $.isPlainObject(mimeChecker)) { + mime = mime.toLowerCase(); + allow = check(mimeChecker.allow); + deny = check(mimeChecker.deny); + if (mimeChecker.firstOrder === 'allow') { + res = false; // default is deny + if (! deny && allow === true) { // match only allow + res = true; + } + } else { + res = true; // default is allow + if (deny === true && ! allow) { // match only deny + res = false; + } + } + } + return res; + }, + + /** + * call chained sequence of async deferred functions + * + * @param Array tasks async functions + * @return Object jQuery.Deferred + */ + sequence : function(tasks) { + var l = tasks.length, + chain = function(task, idx) { + ++idx; + if (tasks[idx]) { + return chain(task.then(tasks[idx]), idx); + } else { + return task; + } + }; + if (l > 1) { + return chain(tasks[0](), 0); + } else { + return tasks[0](); + } + }, + + /** + * Reload contents of target URL for clear browser cache + * + * @param String url target URL + * @return Object jQuery.Deferred + */ + reloadContents : function(url) { + var dfd = $.Deferred(), + ifm; + try { + ifm = $(''; + } + } + } + link.remove(); + $(iframes) + .appendTo('body') + .ready(function() { + setTimeout(function() { + $(iframes).each(function() { + $('#' + $(this).attr('id')).remove(); + }); + }, 20000 + (10000 * i)); // give 20 sec + 10 sec for each file to be saved + }); + fm.trigger('download', {files : files}); + dfrd.resolve(); + }); + fileCnt = files.length; + urls = []; + for (i = 0; i < files.length; i++) { + fm.openUrl(files[i].hash, true, function(v) { + v && urls.push(v); + if (--fileCnt < 1) { + getUrlDfrd.resolve(urls); + } + }); + } + return dfrd; + } + }; + +}; + + +/* + * File: /js/commands/duplicate.js + */ + +/** + * @class elFinder command "duplicate" + * Create file/folder copy with suffix "copy Number" + * + * @type elFinder.command + * @author Dmitry (dio) Levashov + */ +elFinder.prototype.commands.duplicate = function() { + var fm = this.fm; + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length, + filter = function(files) { + var fres = true; + return $.grep(files, function(f) { + fres = fres && f.read && f.phash === fm.cwd().hash && ! fm.isRoot(f)? true : false; + return fres; + }); + }; + + return cnt && fm.cwd().write && filter(sel).length == cnt ? 0 : -1; + }; + + this.exec = function(hashes) { + var fm = this.fm, + files = this.files(hashes), + cnt = files.length, + dfrd = $.Deferred() + .fail(function(error) { + error && fm.error(error); + }), + args = []; + + if (! cnt) { + return dfrd.reject(); + } + + $.each(files, function(i, file) { + if (!file.read || !fm.file(file.phash).write) { + return !dfrd.reject(['errCopy', file.name, 'errPerm']); + } + }); + + if (dfrd.state() == 'rejected') { + return dfrd; + } + + return fm.request({ + data : {cmd : 'duplicate', targets : this.hashes(hashes)}, + notify : {type : 'copy', cnt : cnt}, + navigate : { + toast : { + inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdduplicate')])} + } + } + }); + + }; + +}; + + +/* + * File: /js/commands/edit.js + */ + +/** + * @class elFinder command "edit". + * Edit text file in dialog window + * + * @author Dmitry (dio) Levashov, dio@std42.ru + **/ +elFinder.prototype.commands.edit = function() { + var self = this, + fm = this.fm, + clsEditing = fm.res('class', 'editing'), + mimesSingle = [], + mimes = [], + allowAll = false, + rtrim = function(str){ + return str.replace(/\s+$/, ''); + }, + getEncSelect = function(heads) { + var sel = $(''), + hval; + if (heads) { + $.each(heads, function(i, head) { + hval = fm.escape(head.value); + sel.append(''); + }); + } + $.each(self.options.encodings, function(i, v) { + sel.append(''); + }); + return sel; + }, + getDlgWidth = function() { + var win = fm.options.dialogContained? fm.getUI() : $(window), + m, width; + if (typeof self.options.dialogWidth === 'string' && (m = self.options.dialogWidth.match(/(\d+)%/))) { + width = parseInt(win.width() * (m[1] / 100)); + } else { + width = parseInt(self.options.dialogWidth || 650); + } + return Math.min(width, win.width()); + }, + getDlgHeight = function() { + if (!self.options.dialogHeight) { + return void(0); + } + var win = fm.options.dialogContained? fm.getUI() : $(window), + m, height; + if (typeof self.options.dialogHeight === 'string' && (m = self.options.dialogHeight.match(/(\d+)%/))) { + height = parseInt(win.height() * (m[1] / 100)); + } else { + height = parseInt(self.options.dialogHeight || win.height()); + } + return Math.min(height, win.height()); + }, + + /** + * Return files acceptable to edit + * + * @param Array files hashes + * @return Array + **/ + filter = function(files) { + var cnt = files.length, + mime, ext, skip; + + if (cnt > 1) { + mime = files[0].mime; + ext = files[0].name.replace(/^.*(\.[^.]+)$/, '$1'); + } + return $.grep(files, function(file) { + var res; + if (skip || file.mime === 'directory') { + return false; + } + res = file.read + && (allowAll || fm.mimeIsText(file.mime) || $.inArray(file.mime, cnt === 1? mimesSingle : mimes) !== -1) + && (!self.onlyMimes.length || $.inArray(file.mime, self.onlyMimes) !== -1) + && (cnt === 1 || (file.mime === mime && file.name.substr(ext.length * -1) === ext)) + && (fm.uploadMimeCheck(file.mime, file.phash)? true : false) + && setEditors(file, cnt) + && Object.keys(editors).length; + if (!res) { + skip = true; + } + return res; + }); + }, + + fileSync = function(hash) { + var old = fm.file(hash), + f; + fm.request({ + cmd: 'info', + targets: [hash], + preventDefault: true + }).done(function(data) { + var changed; + if (data && data.files && data.files.length) { + f = data.files[0]; + if (old.ts != f.ts || old.size != f.size) { + changed = { changed: [ f ] }; + fm.updateCache(changed); + fm.change(changed); + } + } + }); + }, + + /** + * Open dialog with textarea to edit file + * + * @param String id dialog id + * @param Object file file object + * @param String content file content + * @return $.Deferred + **/ + dialog = function(id, file, content, encoding, editor, toasts) { + + var dfrd = $.Deferred(), + _loaded = false, + loaded = function() { + if (!_loaded) { + fm.toast({ + mode: 'warning', + msg: fm.i18n('nowLoading') + }); + return false; + } + return true; + }, + makeToasts = function() { + // make toast message + if (toasts && Array.isArray(toasts)) { + $.each(toasts, function() { + this.msg && fm.toast(this); + }); + } + }, + save = function() { + var encord = selEncoding? selEncoding.val():void(0), + saveDfd = $.Deferred().fail(function(err) { + dialogNode.show().find('button.elfinder-btncnt-0,button.elfinder-btncnt-1').hide(); + }), + conf, res, tm; + if (!loaded()) { + return saveDfd.resolve(); + } + if (ta.editor) { + ta.editor.save(ta[0], ta.editor.instance); + conf = ta.editor.confObj; + if (conf.info && (conf.info.schemeContent || conf.info.arrayBufferContent)) { + encord = 'scheme'; + } + } + res = getContent(); + setOld(res); + if (res.promise) { + tm = setTimeout(function() { + fm.notify({ + type : 'chkcontent', + cnt : 1, + hideCnt: true, + cancel : function() { + res.reject(); + } + }); + }, 100); + res.always(function() { + tm && clearTimeout(tm); + fm.notify({ type : 'chkcontent', cnt: -1 }); + }).done(function(data) { + dfrd.notifyWith(ta, [encord, ta.data('hash'), old, saveDfd]); + }).fail(function(err) { + saveDfd.reject(err); + }); + } else { + dfrd.notifyWith(ta, [encord, ta.data('hash'), old, saveDfd]); + } + return saveDfd; + }, + saveon = function() { + if (!loaded()) { return; } + save().fail(function(err) { + err && fm.error(err); + }); + }, + cancel = function() { + if (!self.options.confirmUnsavedBeforeClose) { + ta.elfinderdialog('close'); + } else { + var close = function() { + var conf; + dfrd.resolve(); + if (ta.editor) { + ta.editor.close(ta[0], ta.editor.instance); + conf = ta.editor.confObj; + if (conf.info && conf.info.syncInterval) { + fileSync(file.hash); + } + } + ta.elfinderdialog('destroy'); + }, + onlySaveAs = (typeof saveAsFile.name !== 'undefined'), + accept = onlySaveAs? { + label : 'btnSaveAs', + callback : function() { + requestAnimationFrame(saveAs); + } + } : { + label : 'btnSaveClose', + callback : function() { + save().done(function() { + close(); + }); + } + }; + changed().done(function(change) { + var msgs = ['confirmNotSave']; + var btnDiscard = { + label : 'btnDiscard', + callback : function() { + close(); + } + } + if (change) { + if (typeof change === 'string') { + msgs.unshift(change); + } + fm.confirm({ + title : self.title, + text : msgs, + accept : accept, + cancel : { + label : 'btnCancel', + callback : $.noop + }, + buttons : onlySaveAs? [btnDiscard] : [{ + label : 'btnSaveAs', + callback : function() { + ta.elfinderdialog('destroy'); + requestAnimationFrame(saveAs); + } + }, btnDiscard] + }); + } else { + close(); + } + }); + } + }, + savecl = function() { + if (!loaded()) { return; } + dialogNode.hide(); + save().done(function() { + _loaded = false; + dialogNode.show(); + cancel(); + }).fail(function(err) { + dialogNode.show(); + err && fm.error(err); + }); + }, + saveAs = function() { + if (!loaded()) { return; } + var prevOld = old, + phash = file.phash, + fail = function(err) { + dialogs.addClass(clsEditing).fadeIn(function() { + err && fm.error(err); + }); + old = prevOld; + fm.disable(); + }, + make = function() { + self.mime = saveAsFile.mime || file.mime; + self.prefix = (saveAsFile.name || file.name).replace(/ \d+(\.[^.]+)?$/, '$1'); + self.requestCmd = 'mkfile'; + self.nextAction = {}; + self.data = {target : phash}; + $.proxy(fm.res('mixin', 'make'), self)() + .done(function(data) { + var oldHash; + if (data.added && data.added.length) { + oldHash = ta.data('hash'); + ta.data('hash', data.added[0].hash); + save().done(function() { + _loaded = false; + dialogNode.show(); + cancel(); + dialogs.fadeIn(); + }).fail(function() { + fm.exec('rm', [data.added[0].hash], { forceRm: true, quiet: true }); + ta.data('hash', oldHash); + dialogNode.find('button.elfinder-btncnt-2').hide(); + fail(); + }); + } else { + fail(); + } + }) + .progress(function(err) { + if (err && err === 'errUploadMime') { + ta.trigger('saveAsFail'); + } + }) + .fail(fail) + .always(function() { + delete self.mime; + delete self.prefix; + delete self.nextAction; + delete self.data; + }); + fm.trigger('unselectfiles', { files: [ file.hash ] }); + }, + reqOpen = null, + reqInfo = null, + dialogs = fm.getUI().children('.' + self.dialogClass + ':visible'); + if (dialogNode.is(':hidden')) { + dialogs = dialogs.add(dialogNode); + } + dialogs.removeClass(clsEditing).fadeOut(); + + fm.enable(); + + if (fm.searchStatus.state < 2 && phash !== fm.cwd().hash) { + reqOpen = fm.exec('open', [phash], {thash: phash}); + } else if (!fm.file(phash)) { + reqInfo = fm.request({cmd: 'info', targets: [phash]}); + } + + $.when([reqOpen, reqInfo]).done(function() { + if (reqInfo) { + fm.one('infodone', function() { + fm.file(phash)? make() : fail('errFolderNotFound'); + }); + } else { + reqOpen? fm.one('cwdrender', make) : make(); + } + }).fail(fail); + }, + changed = function() { + var dfd = $.Deferred(), + res, tm; + if (!_loaded) { + return dfd.resolve(false); + } + ta.editor && ta.editor.save(ta[0], ta.editor.instance); + res = getContent(); + if (res && res.promise) { + tm = setTimeout(function() { + fm.notify({ + type : 'chkcontent', + cnt : 1, + hideCnt: true, + cancel : function() { + res.reject(); + } + }); + }, 100); + res.always(function() { + tm && clearTimeout(tm); + fm.notify({ type : 'chkcontent', cnt: -1 }); + }).done(function(d) { + dfd.resolve(old !== d); + }).fail(function(err) { + dfd.resolve(err || (old === undefined? false : true)); + }); + } else { + dfd.resolve(old !== res); + } + return dfd; + }, + opts = { + title : fm.escape(file.name), + width : getDlgWidth(), + height : getDlgHeight(), + buttons : {}, + cssClass : clsEditing, + maxWidth : 'window', + maxHeight : 'window', + allowMinimize : true, + allowMaximize : true, + openMaximized : editorMaximized() || (editor && editor.info && editor.info.openMaximized), + btnHoverFocus : false, + closeOnEscape : false, + propagationEvents : ['mousemove', 'mouseup', 'click'], + minimize : function() { + var conf; + if (ta.editor && dialogNode.closest('.ui-dialog').is(':hidden')) { + conf = ta.editor.confObj; + if (conf.info && conf.info.syncInterval) { + fileSync(file.hash); + } + } + }, + headerBtnCloseAction : self.options.confirmUnsavedBeforeClose ? function() { + cancel(); + } : undefined, + close : function() { + if (self.options.confirmUnsavedBeforeClose) { + return; + } + var close = function() { + var conf; + dfrd.resolve(); + if (ta.editor) { + ta.editor.close(ta[0], ta.editor.instance); + conf = ta.editor.confObj; + if (conf.info && conf.info.syncInterval) { + fileSync(file.hash); + } + } + ta.elfinderdialog('destroy'); + }, + onlySaveAs = (typeof saveAsFile.name !== 'undefined'), + accept = onlySaveAs? { + label : 'btnSaveAs', + callback : function() { + requestAnimationFrame(saveAs); + } + } : { + label : 'btnSaveClose', + callback : function() { + save().done(function() { + close(); + }); + } + }; + changed().done(function(change) { + var msgs = ['confirmNotSave']; + if (change) { + if (typeof change === 'string') { + msgs.unshift(change); + } + fm.confirm({ + title : self.title, + text : msgs, + accept : accept, + cancel : { + label : 'btnClose', + callback : close + }, + buttons : onlySaveAs? null : [{ + label : 'btnSaveAs', + callback : function() { + requestAnimationFrame(saveAs); + } + }] + }); + } else { + close(); + } + }); + }, + open : function() { + var loadRes, conf, interval; + ta.initEditArea.call(ta, id, file, content, fm); + if (ta.editor) { + loadRes = ta.editor.load(ta[0]) || null; + if (loadRes && loadRes.done) { + loadRes.always(function() { + _loaded = true; + }).done(function(instance) { + ta.editor.instance = instance; + ta.editor.focus(ta[0], ta.editor.instance); + setOld(getContent()); + requestAnimationFrame(function() { + dialogNode.trigger('resize'); + }); + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + return; + }).always(makeToasts); + } else { + _loaded = true; + if (loadRes && (typeof loadRes === 'string' || Array.isArray(loadRes))) { + fm.error(loadRes); + ta.elfinderdialog('destroy'); + return; + } + ta.editor.instance = loadRes; + ta.editor.focus(ta[0], ta.editor.instance); + setOld(getContent()); + requestAnimationFrame(function() { + dialogNode.trigger('resize'); + }); + makeToasts(); + } + conf = ta.editor.confObj; + if (conf.info && conf.info.syncInterval) { + if (interval = parseInt(conf.info.syncInterval)) { + setTimeout(function() { + autoSync(interval); + }, interval); + } + } + } else { + _loaded = true; + setOld(getContent()); + } + }, + resize : function(e, data) { + ta.editor && ta.editor.resize(ta[0], ta.editor.instance, e, data || {}); + } + }, + getContent = function() { + var res = ta.getContent.call(ta, ta[0]); + if (res === undefined || res === false || res === null) { + res = $.Deferred().reject(); + } + return res; + }, + setOld = function(res) { + if (res && res.promise) { + res.done(function(d) { + old = d; + }); + } else { + old = res; + } + }, + autoSync = function(interval) { + if (dialogNode.is(':visible')) { + fileSync(file.hash); + setTimeout(function() { + autoSync(interval); + }, interval); + } + }, + stateChange = function() { + if (selEncoding) { + changed().done(function(change) { + if (change) { + selEncoding.attr('title', fm.i18n('saveAsEncoding')).addClass('elfinder-edit-changed'); + } else { + selEncoding.attr('title', fm.i18n('openAsEncoding')).removeClass('elfinder-edit-changed'); + } + }); + } + }, + saveAsFile = {}, + ta, old, dialogNode, selEncoding, extEditor, maxW, syncInterval; + + if (editor) { + if (editor.html) { + ta = $(editor.html); + } + extEditor = { + init : editor.init || null, + load : editor.load, + getContent : editor.getContent || null, + save : editor.save, + beforeclose : typeof editor.beforeclose == 'function' ? editor.beforeclose : void 0, + close : typeof editor.close == 'function' ? editor.close : function() {}, + focus : typeof editor.focus == 'function' ? editor.focus : function() {}, + resize : typeof editor.resize == 'function' ? editor.resize : function() {}, + instance : null, + doSave : saveon, + doCancel : cancel, + doClose : savecl, + file : file, + fm : fm, + confObj : editor, + trigger : function(evName, data) { + fm.trigger('editEditor' + evName, Object.assign({}, editor.info || {}, data)); + } + }; + } + + if (!ta) { + if (!fm.mimeIsText(file.mime)) { + return dfrd.reject('errEditorNotFound'); + } + (function() { + ta = $('') + .on('input propertychange', stateChange); + + if (!editor || !editor.info || editor.info.useTextAreaEvent) { + ta.on('keydown', function(e) { + var code = e.keyCode, + value, start; + + e.stopPropagation(); + if (code == $.ui.keyCode.TAB) { + e.preventDefault(); + // insert tab on tab press + if (this.setSelectionRange) { + value = this.value; + start = this.selectionStart; + this.value = value.substr(0, start) + "\t" + value.substr(this.selectionEnd); + start += 1; + this.setSelectionRange(start, start); + } + } + + if (e.ctrlKey || e.metaKey) { + // close on ctrl+w/q + if (code == 'Q'.charCodeAt(0) || code == 'W'.charCodeAt(0)) { + e.preventDefault(); + cancel(); + } + if (code == 'S'.charCodeAt(0)) { + e.preventDefault(); + saveon(); + } + } + + }) + .on('mouseenter', function(){this.focus();}); + } + + ta.initEditArea = function(id, file, content) { + // ta.hide() for performance tune. Need ta.show() in `load()` if use textarea node. + ta.hide().val(content); + this._setupSelEncoding(content); + }; + })(); + } + + // extended function to setup selector of encoding for text editor + ta._setupSelEncoding = function(content) { + var heads = (encoding && encoding !== 'unknown')? [{value: encoding}] : [], + wfake = $('').hide(), + setSelW = function(init) { + init && wfake.appendTo(selEncoding.parent()); + wfake.empty().append($('').text(selEncoding.val())); + selEncoding.width(wfake.width()); + }; + if (content === '' || ! encoding || encoding !== 'UTF-8') { + heads.push({value: 'UTF-8'}); + } + selEncoding = getEncSelect(heads).on('touchstart', function(e) { + // for touch punch event handler + e.stopPropagation(); + }).on('change', function() { + // reload to change encoding if not edited + changed().done(function(change) { + if (! change && getContent() !== '') { + cancel(); + edit(file, selEncoding.val(), editor).fail(function(err) { err && fm.error(err); }); + } + }); + setSelW(); + }).on('mouseover', stateChange); + ta.parent().next().prepend($('
      ').append(selEncoding)); + setSelW(true); + }; + + ta.data('hash', file.hash); + + if (extEditor) { + ta.editor = extEditor; + + if (typeof extEditor.beforeclose === 'function') { + opts.beforeclose = function() { + return extEditor.beforeclose(ta[0], extEditor.instance); + }; + } + + if (typeof extEditor.init === 'function') { + ta.initEditArea = extEditor.init; + } + + if (typeof extEditor.getContent === 'function') { + ta.getContent = extEditor.getContent; + } + } + + if (! ta.initEditArea) { + ta.initEditArea = function() {}; + } + + if (! ta.getContent) { + ta.getContent = function() { + return rtrim(ta.val()); + }; + } + + if (!editor || !editor.info || !editor.info.preventGet) { + opts.buttons[fm.i18n('btnSave')] = saveon; + opts.buttons[fm.i18n('btnSaveClose')] = savecl; + opts.buttons[fm.i18n('btnSaveAs')] = saveAs; + opts.buttons[fm.i18n('btnCancel')] = cancel; + } + + if (editor && typeof editor.prepare === 'function') { + editor.prepare(ta, opts, file); + } + + dialogNode = self.fmDialog(ta, opts) + .attr('id', id) + .on('keydown keyup keypress', function(e) { + e.stopPropagation(); + }) + .css({ overflow: 'hidden', minHeight: '7em' }) + .addClass('elfinder-edit-editor') + .closest('.ui-dialog') + .on('changeType', function(e, data) { + if (data.extention && data.mime) { + var ext = data.extention, + mime = data.mime, + btnSet = $(this).children('.ui-dialog-buttonpane').children('.ui-dialog-buttonset'); + btnSet.children('.elfinder-btncnt-0,.elfinder-btncnt-1').hide(); + saveAsFile.name = fm.splitFileExtention(file.name)[0] + '.' + data.extention; + saveAsFile.mime = data.mime; + if (!data.keepEditor) { + btnSet.children('.elfinder-btncnt-2').trigger('click'); + } + } + }); + + // care to viewport scale change with mobile devices + maxW = (fm.options.dialogContained? fm.getUI() : $(window)).width(); + (dialogNode.width() > maxW) && dialogNode.width(maxW); + + return dfrd.promise(); + }, + + /** + * Get file content and + * open dialog with textarea to edit file content + * + * @param String file hash + * @return jQuery.Deferred + **/ + edit = function(file, convert, editor) { + var hash = file.hash, + opts = fm.options, + dfrd = $.Deferred(), + id = 'edit-'+fm.namespace+'-'+file.hash, + d = fm.getUI().find('#'+id), + conv = !convert? 0 : convert, + noContent = false, + req, error, res; + + + if (d.length) { + d.elfinderdialog('toTop'); + return dfrd.resolve(); + } + + if (!file.read || (!file.write && (!editor.info || !editor.info.converter))) { + error = ['errOpen', file.name, 'errPerm']; + return dfrd.reject(error); + } + + if (editor && editor.info) { + if (typeof editor.info.edit === 'function') { + res = editor.info.edit.call(fm, file, editor); + if (res.promise) { + res.done(function() { + dfrd.resolve(); + }).fail(function(error) { + dfrd.reject(error); + }); + } else { + res? dfrd.resolve() : dfrd.reject(); + } + return dfrd; + } + + noContent = editor.info.preventGet || editor.info.noContent; + if (editor.info.urlAsContent || noContent) { + req = $.Deferred(); + if (editor.info.urlAsContent) { + fm.url(hash, { async: true, onetime: true, temporary: true }).done(function(url) { + req.resolve({content: url}); + }); + } else { + req.resolve({}); + } + } else { + if (conv) { + file.encoding = conv; + fm.cache(file, 'change'); + } + req = fm.request({ + data : {cmd : 'get', target : hash, conv : conv, _t : file.ts}, + options : {type: 'get', cache : true}, + notify : {type : 'file', cnt : 1}, + preventDefault : true + }); + } + + req.done(function(data) { + var selEncoding, reg, m, res; + if (data.doconv) { + fm.confirm({ + title : self.title, + text : data.doconv === 'unknown'? 'confirmNonUTF8' : 'confirmConvUTF8', + accept : { + label : 'btnConv', + callback : function() { + dfrd = edit(file, selEncoding.val(), editor); + } + }, + cancel : { + label : 'btnCancel', + callback : function() { dfrd.reject(); } + }, + optionsCallback : function(options) { + options.create = function() { + var base = $('
      '), + head = {value: data.doconv}, + detected; + + if (data.doconv === 'unknown') { + head.caption = '-'; + } + selEncoding = getEncSelect([head]); + $(this).next().find('.ui-dialog-buttonset') + .prepend(base.append($('').append(selEncoding))); + }; + } + }); + } else { + if (!noContent && fm.mimeIsText(file.mime)) { + reg = new RegExp('^(data:'+file.mime.replace(/([.+])/g, '\\$1')+';base64,)', 'i'); + if (!editor.info.dataScheme) { + if (window.atob && (m = data.content.match(reg))) { + data.content = atob(data.content.substr(m[1].length)); + } + } else { + if (window.btoa && !data.content.match(reg)) { + data.content = 'data:'+file.mime+';base64,'+btoa(data.content); + } + } + } + dialog(id, file, data.content, data.encoding, editor, data.toasts) + .done(function(data) { + dfrd.resolve(data); + }) + .progress(function(encoding, newHash, data, saveDfd) { + var ta = this; + if (newHash) { + hash = newHash; + } + fm.request({ + options : {type : 'post'}, + data : { + cmd : 'put', + target : hash, + encoding : encoding || data.encoding, + content : data + }, + notify : {type : 'save', cnt : 1}, + syncOnFail : true, + preventFail : true, + navigate : { + target : 'changed', + toast : { + inbuffer : {msg: fm.i18n(['complete', fm.i18n('btnSave')])} + } + } + }) + .fail(function(error) { + dfrd.reject(error); + saveDfd.reject(); + }) + .done(function(data) { + requestAnimationFrame(function(){ + ta.trigger('focus'); + ta.editor && ta.editor.focus(ta[0], ta.editor.instance); + }); + saveDfd.resolve(); + }); + }) + .fail(function(error) { + dfrd.reject(error); + }); + } + }) + .fail(function(error) { + var err = fm.parseError(error); + err = Array.isArray(err)? err[0] : err; + if (file.encoding) { + file.encoding = ''; + fm.cache(file, 'change'); + } + (err !== 'errConvUTF8') && fm.sync(); + dfrd.reject(error); + }); + } + + return dfrd.promise(); + }, + + /** + * Current editors of selected files + * + * @type Object + */ + editors = {}, + + /** + * Fallback editor (Simple text editor) + * + * @type Object + */ + fallbackEditor = { + // Simple Text (basic textarea editor) + info : { + id : 'textarea', + name : 'TextArea', + useTextAreaEvent : true + }, + load : function(textarea) { + // trigger event 'editEditorPrepare' + this.trigger('Prepare', { + node: textarea, + editorObj: void(0), + instance: void(0), + opts: {} + }); + textarea.setSelectionRange && textarea.setSelectionRange(0, 0); + $(textarea).trigger('focus').show(); + }, + save : function(){} + }, + + /** + * Set current editors + * + * @param Object file object + * @param Number cnt count of selected items + * @return Void + */ + setEditors = function(file, cnt) { + var mimeMatch = function(fileMime, editorMimes){ + if (!editorMimes) { + return fm.mimeIsText(fileMime); + } else { + if (editorMimes[0] === '*' || $.inArray(fileMime, editorMimes) !== -1) { + return true; + } + var i, l; + l = editorMimes.length; + for (i = 0; i < l; i++) { + if (fileMime.indexOf(editorMimes[i]) === 0) { + return true; + } + } + return false; + } + }, + extMatch = function(fileName, editorExts){ + if (!editorExts || !editorExts.length) { + return true; + } + var ext = fileName.replace(/^.+\.([^.]+)|(.+)$/, '$1$2').toLowerCase(), + i, l; + l = editorExts.length; + for (i = 0; i < l; i++) { + if (ext === editorExts[i].toLowerCase()) { + return true; + } + } + return false; + }, + optEditors = self.options.editors || [], + cwdWrite = fm.cwd().write; + + stored = fm.storage('storedEditors') || {}; + editors = {}; + if (!optEditors.length) { + optEditors = [fallbackEditor]; + } + $.each(optEditors, function(i, editor) { + var name; + if ((cnt === 1 || !editor.info.single) + && ((!editor.info || !editor.info.converter)? file.write : cwdWrite) + && (file.size > 0 || (!editor.info.converter && editor.info.canMakeEmpty !== false && fm.mimesCanMakeEmpty[file.mime])) + && (!editor.info.maxSize || file.size <= editor.info.maxSize) + && mimeMatch(file.mime, editor.mimes || null) + && extMatch(file.name, editor.exts || null) + && typeof editor.load == 'function' + && typeof editor.save == 'function') { + + name = editor.info.name? editor.info.name : ('Editor ' + i); + editor.id = editor.info.id? editor.info.id : ('editor' + i), + editor.name = name; + editor.i18n = fm.i18n(name); + editors[editor.id] = editor; + } + }); + return Object.keys(editors).length? true : false; + }, + store = function(mime, editor) { + if (mime && editor) { + if (!$.isPlainObject(stored)) { + stored = {}; + } + stored[mime] = editor.id; + fm.storage('storedEditors', stored); + fm.trigger('selectfiles', {files : fm.selected()}); + } + }, + useStoredEditor = function() { + var d = fm.storage('useStoredEditor'); + return d? (d > 0) : self.options.useStoredEditor; + }, + editorMaximized = function() { + var d = fm.storage('editorMaximized'); + return d? (d > 0) : self.options.editorMaximized; + }, + getSubMenuRaw = function(files, callback) { + var subMenuRaw = []; + $.each(editors, function(id, ed) { + subMenuRaw.push( + { + label : fm.escape(ed.i18n), + icon : ed.info && ed.info.icon? ed.info.icon : 'edit', + options : { iconImg: ed.info && ed.info.iconImg? fm.baseUrl + ed.info.iconImg : void(0) }, + callback : function() { + store(files[0].mime, ed); + callback && callback.call(ed); + } + } + ); + }); + return subMenuRaw; + }, + getStoreId = function(name) { + // for compatibility to previous version + return name.toLowerCase().replace(/ +/g, ''); + }, + getStoredEditor = function(mime) { + var name = stored[mime]; + return name && Object.keys(editors).length? editors[getStoreId(name)] : void(0); + }, + infoRequest = function() { + + }, + stored; + + // make public method + this.getEncSelect = getEncSelect; + + this.shortcuts = [{ + pattern : 'ctrl+e' + }]; + + this.init = function() { + var self = this, + fm = this.fm, + opts = this.options, + cmdChecks = [], + ccData, dfd; + + this.onlyMimes = this.options.mimes || []; + + fm.one('open', function() { + // editors setup + if (opts.editors && Array.isArray(opts.editors)) { + fm.trigger('canMakeEmptyFile', {mimes: Object.keys(fm.storage('mkfileTextMimes') || {}).concat(opts.makeTextMimes || ['text/plain'])}); + $.each(opts.editors, function(i, editor) { + if (editor.info && editor.info.cmdCheck) { + cmdChecks.push(editor.info.cmdCheck); + } + }); + if (cmdChecks.length) { + if (fm.api >= 2.1030) { + dfd = fm.request({ + data : { + cmd: 'editor', + name: cmdChecks, + method: 'enabled' + }, + preventDefault : true + }).done(function(d) { + ccData = d; + }).fail(function() { + ccData = {}; + }); + } else { + ccData = {}; + dfd = $.Deferred().resolve(); + } + } else { + dfd = $.Deferred().resolve(); + } + + dfd.always(function() { + if (ccData) { + opts.editors = $.grep(opts.editors, function(e) { + if (e.info && e.info.cmdCheck) { + return ccData[e.info.cmdCheck]? true : false; + } else { + return true; + } + }); + } + $.each(opts.editors, function(i, editor) { + if (editor.setup && typeof editor.setup === 'function') { + editor.setup.call(editor, opts, fm); + } + if (!editor.disabled) { + if (editor.mimes && Array.isArray(editor.mimes)) { + mimesSingle = mimesSingle.concat(editor.mimes); + if (!editor.info || !editor.info.single) { + mimes = mimes.concat(editor.mimes); + } + } + if (!allowAll && editor.mimes && editor.mimes[0] === '*') { + allowAll = true; + } + if (!editor.info) { + editor.info = {}; + } + if (editor.info.integrate) { + fm.trigger('helpIntegration', Object.assign({cmd: 'edit'}, editor.info.integrate)); + } + if (editor.info.canMakeEmpty) { + fm.trigger('canMakeEmptyFile', {mimes: Array.isArray(editor.info.canMakeEmpty)? editor.info.canMakeEmpty : editor.mimes}); + } + } + }); + + mimesSingle = ($.uniqueSort || $.unique)(mimesSingle); + mimes = ($.uniqueSort || $.unique)(mimes); + + opts.editors = $.grep(opts.editors, function(e) { + return e.disabled? false : true; + }); + }); + } + }) + .bind('select', function() { + editors = null; + }) + .bind('contextmenucreate', function(e) { + var file, editor, + single = function(editor) { + var title = self.title; + fm.one('contextmenucreatedone', function() { + self.title = title; + }); + self.title = fm.escape(editor.i18n); + if (editor.info && editor.info.iconImg) { + self.contextmenuOpts = { + iconImg: fm.baseUrl + editor.info.iconImg + }; + } + delete self.variants; + }; + + self.contextmenuOpts = void(0); + if (e.data.type === 'files' && self.enabled()) { + file = fm.file(e.data.targets[0]); + if (setEditors(file, e.data.targets.length)) { + if (Object.keys(editors).length > 1) { + if (!useStoredEditor() || !(editor = getStoredEditor(file.mime))) { + delete self.extra; + self.variants = []; + $.each(editors, function(id, editor) { + self.variants.push([{ editor: editor }, editor.i18n, editor.info && editor.info.iconImg? fm.baseUrl + editor.info.iconImg : 'edit']); + }); + } else { + single(editor); + self.extra = { + icon: 'menu', + node: $('') + .attr({title: fm.i18n('select')}) + .on('click touchstart', function(e){ + if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) { + return; + } + var node = $(this); + e.stopPropagation(); + e.preventDefault(); + fm.trigger('contextmenu', { + raw: getSubMenuRaw(fm.selectedFiles(), function() { + var hashes = fm.selected(); + fm.exec('edit', hashes, {editor: this}); + fm.trigger('selectfiles', {files : hashes}); + }), + x: node.offset().left, + y: node.offset().top + }); + }) + }; + } + } else { + single(editors[Object.keys(editors)[0]]); + delete self.extra; + } + } + } + }) + .bind('canMakeEmptyFile', function(e) { + if (e.data && e.data.resetTexts) { + var defs = fm.arrayFlip(self.options.makeTextMimes || ['text/plain']), + hides = self.getMkfileHides(); + + $.each((fm.storage('mkfileTextMimes') || {}), function(mime, type) { + if (!defs[mime]) { + delete fm.mimesCanMakeEmpty[mime]; + delete hides[mime]; + } + }); + fm.storage('mkfileTextMimes', null); + if (Object.keys(hides).length) { + fm.storage('mkfileHides', hides); + } else { + fm.storage('mkfileHides', null); + } + } + }); + }; + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length; + + return cnt && filter(sel).length == cnt ? 0 : -1; + }; + + this.exec = function(select, opts) { + var fm = this.fm, + files = filter(this.files(select)), + hashes = $.map(files, function(f) { return f.hash; }), + list = [], + editor = opts && opts.editor? opts.editor : null, + node = $(opts && opts._currentNode? opts._currentNode : fm.cwdHash2Elm(hashes[0])), + getEditor = function() { + var dfd = $.Deferred(), + storedId; + + if (!editor && Object.keys(editors).length > 1) { + if (useStoredEditor() && (editor = getStoredEditor(files[0].mime))) { + return dfd.resolve(editor); + } + fm.trigger('contextmenu', { + raw: getSubMenuRaw(files, function() { + dfd.resolve(this); + }), + x: node.offset().left, + y: node.offset().top + 22, + opened: function() { + fm.one('closecontextmenu',function() { + requestAnimationFrame(function() { + if (dfd.state() === 'pending') { + dfd.reject(); + } + }); + }); + } + }); + + fm.trigger('selectfiles', {files : hashes}); + + return dfd; + } else { + Object.keys(editors).length > 1 && editor && store(files[0].mime, editor); + return dfd.resolve(editor? editor : (Object.keys(editors).length? editors[Object.keys(editors)[0]] : null)); + } + }, + dfrd = $.Deferred(), + file; + + if (editors === null) { + setEditors(files[0], hashes.length); + } + + if (!node.length) { + node = fm.getUI('cwd'); + } + + getEditor().done(function(editor) { + while ((file = files.shift())) { + list.push(edit(file, (file.encoding || void(0)), editor).fail(function(error) { + error && fm.error(error); + })); + } + + if (list.length) { + $.when.apply(null, list).done(function() { + dfrd.resolve(); + }).fail(function() { + dfrd.reject(); + }); + } else { + dfrd.reject(); + } + }).fail(function() { + dfrd.reject(); + }); + + return dfrd; + }; + + this.getMkfileHides = function() { + return fm.storage('mkfileHides') || fm.arrayFlip(self.options.mkfileHideMimes || []); + }; + +}; + + +/* + * File: /js/commands/empty.js + */ + +/** + * @class elFinder command "empty". + * Empty the folder + * + * @type elFinder.command + * @author Naoki Sawada + */ +elFinder.prototype.commands.empty = function() { + var self, fm, + selFiles = function(select) { + var sel = self.files(select); + if (!sel.length) { + sel = [ fm.cwd() ]; + } + return sel; + }; + + this.linkedCmds = ['rm']; + + this.init = function() { + // lazy assign to make possible to become superclass + self = this; + fm = this.fm; + }; + + this.getstate = function(select) { + var sel = selFiles(select), + cnt, + filter = function(files) { + var fres = true; + return $.grep(files, function(f) { + fres = fres && f.read && f.write && f.mime === 'directory' ? true : false; + return fres; + }); + }; + + cnt = sel.length; + return filter(sel).length == cnt ? 0 : -1; + }; + + this.exec = function(hashes) { + var dirs = selFiles(hashes), + cnt = dirs.length, + dfrd = $.Deferred() + .done(function() { + var data = {changed: {}}; + fm.toast({msg: fm.i18n(['"'+success.join('", ')+'"', 'complete', fm.i18n('cmdempty')])}); + $.each(dirs, function(i, dir) { + data.changed[dir.hash] = dir; + }); + fm.change(data); + }) + .always(function() { + var cwd = fm.cwd().hash; + fm.trigger('selectfiles', {files: $.map(dirs, function(d) { return cwd === d.phash? d.hash : null; })}); + }), + success = [], + done = function(res) { + if (typeof res === 'number') { + success.push(dirs[res].name); + delete dirs[res].dirs; + } else { + res && fm.error(res); + } + (--cnt < 1) && dfrd[success.length? 'resolve' : 'reject'](); + }; + + $.each(dirs, function(i, dir) { + var tm; + if (!(dir.write && dir.mime === 'directory')) { + done(['errEmpty', dir.name, 'errPerm']); + return null; + } + if (!fm.isCommandEnabled('rm', dir.hash)) { + done(['errCmdNoSupport', '"rm"']); + return null; + } + tm = setTimeout(function() { + fm.notify({type : 'search', cnt : 1, hideCnt : cnt > 1? false : true}); + }, fm.notifyDelay); + fm.request({ + data : {cmd : 'open', target : dir.hash}, + preventDefault : true, + asNotOpen : true + }).done(function(data) { + var targets = []; + tm && clearTimeout(tm); + if (fm.ui.notify.children('.elfinder-notify-search').length) { + fm.notify({type : 'search', cnt : -1, hideCnt : cnt > 1? false : true}); + } + if (data && data.files && data.files.length) { + if (data.files.length > fm.maxTargets) { + done(['errEmpty', dir.name, 'errMaxTargets', fm.maxTargets]); + } else { + fm.updateCache(data); + $.each(data.files, function(i, f) { + if (!f.write || f.locked) { + done(['errEmpty', dir.name, 'errRm', f.name, 'errPerm']); + targets = []; + return false; + } + targets.push(f.hash); + }); + if (targets.length) { + fm.exec('rm', targets, { _userAction : true, addTexts : [ fm.i18n('folderToEmpty', dir.name) ] }) + .fail(function(error) { + fm.trigger('unselectfiles', {files: fm.selected()}); + done(fm.parseError(error) || ''); + }) + .done(function() { done(i); }); + } + } + } else { + fm.toast({ mode: 'warning', msg: fm.i18n('filderIsEmpty', dir.name)}); + done(''); + } + }).fail(function(error) { + done(fm.parseError(error) || ''); + }); + }); + + return dfrd; + }; + +}; + + +/* + * File: /js/commands/extract.js + */ + +/** + * @class elFinder command "extract" + * Extract files from archive + * + * @author Dmitry (dio) Levashov + **/ +elFinder.prototype.commands.extract = function() { + var self = this, + fm = self.fm, + mimes = [], + filter = function(files) { + var fres = true; + return $.grep(files, function(file) { + fres = fres && file.read && $.inArray(file.mime, mimes) !== -1 ? true : false; + return fres; + }); + }; + + this.variants = []; + this.disableOnSearch = true; + + // Update mimes list on open/reload + fm.bind('open reload', function() { + mimes = fm.option('archivers')['extract'] || []; + if (fm.api > 2) { + self.variants = [[{makedir: true}, fm.i18n('cmdmkdir')], [{}, fm.i18n('btnCwd')]]; + } else { + self.variants = [[{}, fm.i18n('btnCwd')]]; + } + self.change(); + }); + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length, + cwdHash, cwdChk; + if (!cnt || filter(sel).length != cnt) { + return -1; + } else if (fm.searchStatus.state > 0) { + cwdHash = this.fm.cwd().hash; + $.each(sel, function(i, file) { + cwdChk = (file.phash === cwdHash); + return cwdChk; + }); + return cwdChk? 0 : -1; + } else { + return this.fm.cwd().write? 0 : -1; + } + }; + + this.exec = function(hashes, opts) { + var files = this.files(hashes), + dfrd = $.Deferred(), + cnt = files.length, + makedir = opts && opts.makedir ? 1 : 0, + i, error, + decision, + + overwriteAll = false, + omitAll = false, + mkdirAll = 0, + siblings = fm.files(files[0].phash), + + names = [], + map = {}; + + $.each(siblings, function(id, file) { + map[file.name] = file; + names.push(file.name); + }); + + var decide = function(decision) { + switch (decision) { + case 'overwrite_all' : + overwriteAll = true; + break; + case 'omit_all': + omitAll = true; + break; + } + }; + + var unpack = function(file) { + if (!(file.read && fm.file(file.phash).write)) { + error = ['errExtract', file.name, 'errPerm']; + fm.error(error); + dfrd.reject(error); + } else if ($.inArray(file.mime, mimes) === -1) { + error = ['errExtract', file.name, 'errNoArchive']; + fm.error(error); + dfrd.reject(error); + } else { + fm.request({ + data:{cmd:'extract', target:file.hash, makedir:makedir}, + notify:{type:'extract', cnt:1}, + syncOnFail:true, + navigate:{ + toast : makedir? { + incwd : {msg: fm.i18n(['complete', fm.i18n('cmdextract')]), action: {cmd: 'open', msg: 'cmdopen'}}, + inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdextract')]), action: {cmd: 'open', msg: 'cmdopen'}} + } : { + inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmdextract')])} + } + } + }) + .fail(function (error) { + if (dfrd.state() != 'rejected') { + dfrd.reject(error); + } + }) + .done(function () { + }); + } + }; + + var confirm = function(files, index) { + var file = files[index], + name = fm.splitFileExtention(file.name)[0], + existed = ($.inArray(name, names) >= 0), + next = function(){ + if((index+1) < cnt) { + confirm(files, index+1); + } else { + dfrd.resolve(); + } + }; + if (!makedir && existed && map[name].mime != 'directory') { + fm.confirm( + { + title : fm.i18n('ntfextract'), + text : ['errExists', name, 'confirmRepl'], + accept:{ + label : 'btnYes', + callback:function (all) { + decision = all ? 'overwrite_all' : 'overwrite'; + decide(decision); + if(!overwriteAll && !omitAll) { + if('overwrite' == decision) { + unpack(file); + } + if((index+1) < cnt) { + confirm(files, index+1); + } else { + dfrd.resolve(); + } + } else if(overwriteAll) { + for (i = index; i < cnt; i++) { + unpack(files[i]); + } + dfrd.resolve(); + } + } + }, + reject : { + label : 'btnNo', + callback:function (all) { + decision = all ? 'omit_all' : 'omit'; + decide(decision); + if(!overwriteAll && !omitAll && (index+1) < cnt) { + confirm(files, index+1); + } else if (omitAll) { + dfrd.resolve(); + } + } + }, + cancel : { + label : 'btnCancel', + callback:function () { + dfrd.resolve(); + } + }, + all : ((index+1) < cnt) + } + ); + } else if (!makedir) { + if (mkdirAll == 0) { + fm.confirm({ + title : fm.i18n('cmdextract'), + text : [fm.i18n('cmdextract')+' "'+file.name+'"', 'confirmRepl'], + accept:{ + label : 'btnYes', + callback:function (all) { + all && (mkdirAll = 1); + unpack(file); + next(); + } + }, + reject : { + label : 'btnNo', + callback:function (all) { + all && (mkdirAll = -1); + next(); + } + }, + cancel : { + label : 'btnCancel', + callback:function () { + dfrd.resolve(); + } + }, + all : ((index+1) < cnt) + }); + } else { + (mkdirAll > 0) && unpack(file); + next(); + } + } else { + unpack(file); + next(); + } + }; + + if (!(this.enabled() && cnt && mimes.length)) { + return dfrd.reject(); + } + + if(cnt > 0) { + confirm(files, 0); + } + + return dfrd; + }; + +}; + + +/* + * File: /js/commands/forward.js + */ + +/** + * @class elFinder command "forward" + * Open next visited folder + * + * @author Dmitry (dio) Levashov + **/ +(elFinder.prototype.commands.forward = function() { + this.alwaysEnabled = true; + this.updateOnSelect = true; + this.shortcuts = [{ + pattern : 'ctrl+right' + }]; + + this.getstate = function() { + return this.fm.history.canForward() ? 0 : -1; + }; + + this.exec = function() { + return this.fm.history.forward(); + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/fullscreen.js + */ + +/** + * @class elFinder command "fullscreen" + * elFinder node to full scrren mode + * + * @author Naoki Sawada + **/ + +elFinder.prototype.commands.fullscreen = function() { + var self = this, + fm = this.fm, + update = function(e, data) { + var full; + e.preventDefault(); + e.stopPropagation(); + if (data && data.fullscreen) { + full = (data.fullscreen === 'on'); + self.update(void(0), full); + self.title = fm.i18n(full ? 'reinstate' : 'cmdfullscreen'); + } + }; + + this.alwaysEnabled = true; + this.updateOnSelect = false; + this.syncTitleOnChange = true; + this.value = false; + + this.options = { + ui : 'fullscreenbutton' + }; + + this.getstate = function() { + return 0; + }; + + this.exec = function() { + var node = fm.getUI().get(0), + full = (node === fm.toggleFullscreen(node)); + self.title = fm.i18n(full ? 'reinstate' : 'cmdfullscreen'); + self.update(void(0), full); + return $.Deferred().resolve(); + }; + + fm.bind('init', function() { + fm.getUI().off('resize.' + fm.namespace, update).on('resize.' + fm.namespace, update); + }); +}; + + +/* + * File: /js/commands/getfile.js + */ + +/** + * @class elFinder command "getfile". + * Return selected files info into outer callback. + * For use elFinder with wysiwyg editors etc. + * + * @author Dmitry (dio) Levashov, dio@std42.ru + **/ +(elFinder.prototype.commands.getfile = function() { + var self = this, + fm = this.fm, + filter = function(files) { + var o = self.options, + fres = true; + + files = $.grep(files, function(file) { + fres = fres && (file.mime != 'directory' || o.folders) && file.read ? true : false; + return fres; + }); + + return o.multiple || files.length == 1 ? files : []; + }; + + this.alwaysEnabled = true; + this.callback = fm.options.getFileCallback; + this._disabled = typeof(this.callback) == 'function'; + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length; + + return this.callback && cnt && filter(sel).length == cnt ? 0 : -1; + }; + + this.exec = function(hashes) { + var fm = this.fm, + opts = this.options, + files = this.files(hashes), + cnt = files.length, + url = fm.option('url'), + tmb = fm.option('tmbUrl'), + dfrd = $.Deferred() + .done(function(data) { + var res, + done = function() { + if (opts.oncomplete == 'close') { + fm.hide(); + } else if (opts.oncomplete == 'destroy') { + fm.destroy(); + } + }, + fail = function(error) { + if (opts.onerror == 'close') { + fm.hide(); + } else if (opts.onerror == 'destroy') { + fm.destroy(); + } else { + error && fm.error(error); + } + }; + + fm.trigger('getfile', {files : data}); + + try { + res = self.callback(data, fm); + } catch(e) { + fail(['Error in `getFileCallback`.', e.message]); + return; + } + + if (typeof res === 'object' && typeof res.done === 'function') { + res.done(done).fail(fail); + } else { + done(); + } + }), + result = function(file) { + return opts.onlyURL + ? opts.multiple ? $.map(files, function(f) { return f.url; }) : files[0].url + : opts.multiple ? files : files[0]; + }, + req = [], + i, file, dim; + + for (i = 0; i < cnt; i++) { + file = files[i]; + if (file.mime == 'directory' && !opts.folders) { + return dfrd.reject(); + } + file.baseUrl = url; + if (file.url == '1') { + req.push(fm.request({ + data : {cmd : 'url', target : file.hash}, + notify : {type : 'url', cnt : 1, hideCnt : true}, + preventDefault : true + }) + .done(function(data) { + if (data.url) { + var rfile = fm.file(this.hash); + rfile.url = this.url = data.url; + } + }.bind(file))); + } else { + file.url = fm.url(file.hash); + } + if (! opts.onlyURL) { + if (opts.getPath) { + file.path = fm.path(file.hash); + if (file.path === '' && file.phash) { + // get parents + (function() { + var dfd = $.Deferred(); + req.push(dfd); + fm.path(file.hash, false, {}) + .done(function(path) { + file.path = path; + }) + .fail(function() { + file.path = ''; + }) + .always(function() { + dfd.resolve(); + }); + })(); + } + } + if (file.tmb && file.tmb != 1) { + file.tmb = tmb + file.tmb; + } + if (!file.width && !file.height) { + if (file.dim) { + dim = file.dim.split('x'); + file.width = dim[0]; + file.height = dim[1]; + } else if (opts.getImgSize && file.mime.indexOf('image') !== -1) { + req.push(fm.request({ + data : {cmd : 'dim', target : file.hash}, + notify : {type : 'dim', cnt : 1, hideCnt : true}, + preventDefault : true + }) + .done(function(data) { + if (data.dim) { + var dim = data.dim.split('x'); + var rfile = fm.file(this.hash); + rfile.width = this.width = dim[0]; + rfile.height = this.height = dim[1]; + } + }.bind(file))); + } + } + } + } + + if (req.length) { + $.when.apply(null, req).always(function() { + dfrd.resolve(result(files)); + }); + return dfrd; + } + + return dfrd.resolve(result(files)); + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/help.js + */ + +/** + * @class elFinder command "help" + * "About" dialog + * + * @author Dmitry (dio) Levashov + **/ +(elFinder.prototype.commands.help = function() { + var fm = this.fm, + self = this, + linktpl = '
      ', + linktpltgt = '', + atpl = '
      {author}
      {work}
      ', + url = /\{url\}/, + link = /\{link\}/, + author = /\{author\}/, + work = /\{work\}/, + r = 'replace', + prim = 'ui-priority-primary', + sec = 'ui-priority-secondary', + lic = 'elfinder-help-license', + tab = '
    60. {title}
    61. ', + html = ['
      ', + '
        '], + stpl = '
        {pattern}
        {descrip}
        ', + sep = '
        ', + selfUrl = $('base').length? fm.escape(document.location.href.replace(/#.*$/, '')) : '', + clTabActive = fm.res('class', 'tabsactive'), + + getTheme = function() { + var src; + if (fm.theme && fm.theme.author) { + src = atpl[r]('elfinder-help-team', 'elfinder-help-team elfinder-help-term-theme')[r](author, fm.i18n(fm.theme.author) + (fm.theme.email? ' <'+fm.theme.email+'>' : ''))[r](work, fm.i18n('theme') + ' ('+fm.i18n(fm.theme.name)+')'); + } else { + src = ''; + } + return src; + }, + + about = function() { + html.push('
        '); + html.push('

        elFinder

        '); + html.push('
        '+fm.i18n('webfm')+'
        '); + html.push('
        '+fm.i18n('ver')+': '+fm.version+'
        '); + html.push('
        '+fm.i18n('protocolver')+':
        '); + html.push('
        jQuery/jQuery UI: '+$().jquery+'/'+$.ui.version+'
        '); + + html.push(sep); + + html.push(linktpltgt[r](url, 'https://studio-42.github.io/elFinder/')[r](link, fm.i18n('homepage'))); + html.push(linktpltgt[r](url, 'https://github.com/Studio-42/elFinder/wiki')[r](link, fm.i18n('docs'))); + html.push(linktpltgt[r](url, 'https://github.com/Studio-42/elFinder')[r](link, fm.i18n('github'))); + //html.push(linktpltgt[r](url, 'http://twitter.com/elrte_elfinder')[r](link, fm.i18n('twitter'))); + + html.push(sep); + + html.push('
        '+fm.i18n('team')+'
        '); + + html.push(atpl[r](author, 'Dmitry "dio" Levashov <dio@std42.ru>')[r](work, fm.i18n('chiefdev'))); + html.push(atpl[r](author, 'Naoki Sawada (nao-pon)<hypweb+elfinder@gmail.com>')[r](work, fm.i18n('developer'))); + html.push(atpl[r](author, 'Troex Nevelin <troex@fury.scancode.ru>')[r](work, fm.i18n('maintainer'))); + html.push(atpl[r](author, 'Alexey Sukhotin <strogg@yandex.ru>')[r](work, fm.i18n('contributor'))); + + if (fm.i18[fm.lang].translator) { + $.each(fm.i18[fm.lang].translator.split(', '), function() { + html.push(atpl[r](author, $.trim(this))[r](work, fm.i18n('translator')+' ('+fm.i18[fm.lang].language+')')); + }); + } + + html.push(getTheme()); + + html.push(sep); + html.push('
        '+fm.i18n('icons')+': Pixelmixer, Fugue, Icons8
        '); + + html.push(sep); + html.push('
        Licence: 3-clauses BSD Licence
        '); + html.push('
        Copyright © 2009-2024, Studio 42 / nao-pon
        '); + html.push('
        „ …'+fm.i18n('dontforget')+' ”
        '); + html.push('
        '); + }, + shortcuts = function() { + var sh = fm.shortcuts(); + // shortcuts tab + html.push('
        '); + + if (sh.length) { + html.push('
        '); + $.each(sh, function(i, s) { + html.push(stpl.replace(/\{pattern\}/, s[0]).replace(/\{descrip\}/, s[1])); + }); + + html.push('
        '); + } else { + html.push('
        '+fm.i18n('shortcutsof')+'
        '); + } + + + html.push('
        '); + + }, + help = function() { + // help tab + html.push('
        '); + html.push('DON\'T PANIC'); + html.push('
        '); + // end help + }, + useInteg = false, + integrations = function() { + useInteg = true; + html.push('
        '); + }, + useDebug = false, + debug = function() { + useDebug = true; + // debug tab + html.push('
        '); + html.push('
          '); + html.push('
          '); + // end debug + }, + debugRender = function() { + var render = function(elm, obj) { + $.each(obj, function(k, v) { + elm.append($('
          ').text(k)); + if (typeof v === 'undefined') { + elm.append($('
          ').append($('').text('undfined'))); + } else if (typeof v === 'object' && !v) { + elm.append($('
          ').append($('').text('null'))); + } else if (typeof v === 'object' && ($.isPlainObject(v) || v.length)) { + elm.append( $('
          ').append(render($('
          '), v))); + } else { + elm.append($('
          ').append($('').text((v && typeof v === 'object')? '[]' : (v? v : '""')))); + } + }); + return elm; + }, + cnt = debugUL.children('li').length, + targetL, target, tabId, + info, lastUL, lastDIV; + + if (self.debug.options || self.debug.debug) { + if (cnt >= 5) { + lastUL = debugUL.children('li:last'); + lastDIV = debugDIV.children('div:last'); + if (lastDIV.is(':hidden')) { + lastUL.remove(); + lastDIV.remove(); + } else { + lastUL.prev().remove(); + lastDIV.prev().remove(); + } + } + + tabId = fm.namespace + '-help-debug-' + (+new Date()); + targetL = $('
        • ').html(''+self.debug.debug.cmd+'').prependTo(debugUL); + target = $('
          ').data('debug', self.debug); + + targetL.on('click.debugrender', function() { + var debug = target.data('debug'); + target.removeData('debug'); + if (debug) { + target.hide(); + if (debug.debug) { + info = $('
          ').append($('').text('debug'), render($('
          '), debug.debug)); + target.append(info); + } + if (debug.options) { + info = $('
          ').append($('').text('options'), render($('
          '), debug.options)); + target.append(info); + } + target.show(); + } + targetL.off('click.debugrender'); + }); + + debugUL.after(target); + + opened && debugDIV.tabs('refresh'); + } + }, + content = '', + opened, tabInteg, integDIV, tabDebug, debugDIV, debugUL; + + this.alwaysEnabled = true; + this.updateOnSelect = false; + this.state = -1; + + this.shortcuts = [{ + pattern : 'f1', + description : this.title + }]; + + fm.bind('load', function() { + var parts = self.options.view || ['about', 'shortcuts', 'help', 'integrations', 'debug'], + i, helpSource, tabBase, tabNav, tabs, delta; + + // remove 'preference' tab, it moved to command 'preference' + if ((i = $.inArray('preference', parts)) !== -1) { + parts.splice(i, 1); + } + + // debug tab require jQueryUI Tabs Widget + if (! $.fn.tabs) { + if ((i = $.inArray(parts, 'debug')) !== -1) { + parts.splice(i, 1); + } + } + + $.each(parts, function(i, title) { + html.push(tab[r](/\{id\}/g, title)[r](/\{title\}/, fm.i18n(title))); + }); + + html.push('
        '); + + $.inArray('about', parts) !== -1 && about(); + $.inArray('shortcuts', parts) !== -1 && shortcuts(); + if ($.inArray('help', parts) !== -1) { + helpSource = fm.i18nBaseUrl + 'help/%s.html.js'; + help(); + } + $.inArray('integrations', parts) !== -1 && integrations(); + $.inArray('debug', parts) !== -1 && debug(); + + html.push('
        '); + content = $(html.join('')); + + content.find('.ui-tabs-nav li') + .on('mouseenter mouseleave', function(e) { + $(this).toggleClass('ui-state-hover', e.type === 'mouseenter'); + }) + .on('focus blur', 'a', function(e) { + $(e.delegateTarget).toggleClass('ui-state-focus', e.type === 'focusin'); + }) + .children() + .on('click', function(e) { + var link = $(this); + + e.preventDefault(); + e.stopPropagation(); + + link.parent().addClass(clTabActive).siblings().removeClass(clTabActive); + content.children('.ui-tabs-panel').hide().filter(link.attr('href')).show(); + }) + .filter(':first').trigger('click'); + + if (useInteg) { + tabInteg = content.find('.elfinder-help-tab-integrations').hide(); + integDIV = content.find('#'+fm.namespace+'-help-integrations').hide().append($('
        ').html(fm.i18n('integrationWith'))); + fm.bind('helpIntegration', function(e) { + var ul = integDIV.children('ul:first'), + data, elm, cmdUL, cmdCls; + if (e.data) { + if ($.isPlainObject(e.data)) { + data = Object.assign({ + link: '', + title: '', + banner: '' + }, e.data); + if (data.title || data.link) { + if (!data.title) { + data.title = data.link; + } + if (data.link) { + elm = $('').attr('href', data.link).attr('target', '_blank').text(data.title); + } else { + elm = $('').text(data.title); + } + if (data.banner) { + elm = $('').append($('').attr(data.banner), elm); + } + } + } else { + elm = $(e.data); + elm.filter('a').each(function() { + var tgt = $(this); + if (!tgt.attr('target')) { + tgt.attr('target', '_blank');; + } + }); + } + if (elm) { + tabInteg.show(); + if (!ul.length) { + ul = $('
          ').appendTo(integDIV); + } + if (data && data.cmd) { + cmdCls = 'elfinder-help-integration-' + data.cmd; + cmdUL = ul.find('ul.' + cmdCls); + if (!cmdUL.length) { + cmdUL = $('
            '); + ul.append($('
          • ').append($('').html(fm.i18n('cmd'+data.cmd))).append(cmdUL)); + } + elm = cmdUL.append($('
          • ').append(elm)); + } else { + ul.append($('
          • ').append(elm)); + } + } + } + }).bind('themechange', function() { + content.find('div.elfinder-help-term-theme').replaceWith(getTheme()); + }); + } + + // debug + if (useDebug) { + tabDebug = content.find('.elfinder-help-tab-debug').hide(); + debugDIV = content.find('#'+fm.namespace+'-help-debug').children('div:first'); + debugUL = debugDIV.children('ul:first').on('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + }); + + self.debug = {}; + + fm.bind('backenddebug', function(e) { + // CAUTION: DO NOT TOUCH `e.data` + if (useDebug && e.data && e.data.debug) { + self.debug = { options : e.data.options, debug : Object.assign({ cmd : fm.currentReqCmd }, e.data.debug) }; + if (self.dialog) { + debugRender(); + } + } + }); + } + + content.find('#'+fm.namespace+'-help-about').find('.apiver').text(fm.api); + self.dialog = self.fmDialog(content, { + title : self.title, + width : 530, + maxWidth: 'window', + maxHeight: 'window', + autoOpen : false, + destroyOnClose : false, + close : function() { + if (useDebug) { + tabDebug.hide(); + debugDIV.tabs('destroy'); + } + opened = false; + } + }) + .on('click', function(e) { + e.stopPropagation(); + }) + .css({ + overflow: 'hidden' + }); + + tabBase = self.dialog.children('.ui-tabs'); + tabNav = tabBase.children('.ui-tabs-nav:first'); + tabs = tabBase.children('.ui-tabs-panel'); + delta = self.dialog.outerHeight(true) - self.dialog.height(); + self.dialog.closest('.ui-dialog').on('resize', function() { + tabs.height(self.dialog.height() - delta - tabNav.outerHeight(true) - 20); + }); + + if (helpSource) { + self.dialog.one('initContents', function() { + $.ajax({ + url: self.options.helpSource? self.options.helpSource : helpSource.replace('%s', fm.lang), + dataType: 'html' + }).done(function(source) { + $('#'+fm.namespace+'-help-help').html(source); + }).fail(function() { + $.ajax({ + url: helpSource.replace('%s', 'en'), + dataType: 'html' + }).done(function(source) { + $('#'+fm.namespace+'-help-help').html(source); + }); + }); + }); + } + + self.state = 0; + + fm.trigger('helpBuilded', self.dialog); + }).one('open', function() { + var debug = false; + fm.one('backenddebug', function() { + debug =true; + }).one('opendone', function() { + requestAnimationFrame(function() { + if (! debug && useDebug) { + useDebug = false; + tabDebug.hide(); + debugDIV.hide(); + debugUL.hide(); + } + }); + }); + }); + + this.getstate = function() { + return 0; + }; + + this.exec = function(sel, opts) { + var tab = opts? opts.tab : void(0), + debugShow = function() { + if (useDebug) { + debugDIV.tabs(); + debugUL.find('a:first').trigger('click'); + tabDebug.show(); + opened = true; + } + }; + debugShow(); + this.dialog.trigger('initContents').elfinderdialog('open').find((tab? '.elfinder-help-tab-'+tab : '.ui-tabs-nav li') + ' a:first').trigger('click'); + return $.Deferred().resolve(); + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/hidden.js + */ + +/** + * @class elFinder command "hidden" + * Always hidden command for uiCmdMap + * + * @author Naoki Sawada + **/ +elFinder.prototype.commands.hidden = function() { + this.hidden = true; + this.updateOnSelect = false; + this.getstate = function() { + return -1; + }; +}; + +/* + * File: /js/commands/hide.js + */ + +/** + * @class elFinder command "hide". + * folders/files to hide as personal setting. + * + * @type elFinder.command + * @author Naoki Sawada + */ +elFinder.prototype.commands.hide = function() { + + var self = this, + nameCache = {}, + hideData, hideCnt, cMenuType, sOrigin; + + this.syncTitleOnChange = true; + + this.shortcuts = [{ + pattern : 'ctrl+shift+dot', + description : this.fm.i18n('toggleHidden') + }]; + + this.init = function() { + var fm = this.fm; + + hideData = fm.storage('hide') || {items: {}}; + hideCnt = Object.keys(hideData.items).length; + + this.title = fm.i18n(hideData.show? 'hideHidden' : 'showHidden'); + self.update(void(0), self.title); + }; + + this.fm.bind('select contextmenucreate closecontextmenu', function(e, fm) { + var sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected(); + if (e.type === 'select' && e.data) { + sOrigin = e.data.origin; + } else if (e.type === 'contextmenucreate') { + cMenuType = e.data.type; + } + if (!sel.length || (((e.type !== 'contextmenucreate' && sOrigin !== 'navbar') || cMenuType === 'cwd') && sel[0] === fm.cwd().hash)) { + self.title = fm.i18n(hideData.show? 'hideHidden' : 'showHidden'); + } else { + self.title = fm.i18n('cmdhide'); + } + if (e.type !== 'closecontextmenu') { + self.update(cMenuType === 'cwd'? (hideCnt? 0 : -1) : void(0), self.title); + } else { + cMenuType = ''; + requestAnimationFrame(function() { + self.update(void(0), self.title); + }); + } + }); + + this.getstate = function(sel) { + return (this.fm.cookieEnabled && cMenuType !== 'cwd' && (sel || this.fm.selected()).length) || hideCnt? 0 : -1; + }; + + this.exec = function(hashes, opts) { + var fm = this.fm, + dfrd = $.Deferred() + .done(function() { + fm.trigger('hide', {items: items, opts: opts}); + }) + .fail(function(error) { + fm.error(error); + }), + o = opts || {}, + items = o.targets? o.targets : (hashes || fm.selected()), + added = [], + removed = [], + notifyto, files, res; + + hideData = fm.storage('hide') || {}; + if (!$.isPlainObject(hideData)) { + hideData = {}; + } + if (!$.isPlainObject(hideData.items)) { + hideData.items = {}; + } + if (opts._currentType === 'shortcut' || !items.length || (opts._currentType !== 'navbar' && sOrigin !=='navbar' && items[0] === fm.cwd().hash)) { + if (hideData.show) { + o.hide = true; + } else if (Object.keys(hideData.items).length) { + o.show = true; + } + } + if (o.reset) { + o.show = true; + hideCnt = 0; + } + if (o.show || o.hide) { + if (o.show) { + hideData.show = true; + } else { + delete hideData.show; + } + if (o.show) { + fm.storage('hide', o.reset? null : hideData); + self.title = fm.i18n('hideHidden'); + self.update(o.reset? -1 : void(0), self.title); + $.each(hideData.items, function(h) { + var f = fm.file(h, true); + if (f && (fm.searchStatus.state || !f.phash || fm.file(f.phash))) { + added.push(f); + } + }); + if (added.length) { + fm.updateCache({added: added}); + fm.add({added: added}); + } + if (o.reset) { + hideData = {items: {}}; + } + return dfrd.resolve(); + } + items = Object.keys(hideData.items); + } + + if (items.length) { + $.each(items, function(i, h) { + var f; + if (!hideData.items[h]) { + f = fm.file(h); + if (f) { + nameCache[h] = f.i18 || f.name; + } + hideData.items[h] = nameCache[h]? nameCache[h] : h; + } + }); + hideCnt = Object.keys(hideData.items).length; + files = this.files(items); + fm.storage('hide', hideData); + fm.remove({removed: items}); + if (hideData.show) { + this.exec(void(0), {hide: true}); + } + if (!o.hide) { + res = {}; + res.undo = { + cmd : 'hide', + callback : function() { + var nData = fm.storage('hide'); + if (nData) { + $.each(items, function(i, h) { + delete nData.items[h]; + }); + hideCnt = Object.keys(nData.items).length; + fm.storage('hide', nData); + fm.trigger('hide', {items: items, opts: {}}); + self.update(hideCnt? 0 : -1); + } + fm.updateCache({added: files}); + fm.add({added: files}); + } + }; + res.redo = { + cmd : 'hide', + callback : function() { + return fm.exec('hide', void(0), {targets: items}); + } + }; + } + } + + return dfrd.state() == 'rejected' ? dfrd : dfrd.resolve(res); + }; +}; + + +/* + * File: /js/commands/home.js + */ + +(elFinder.prototype.commands.home = function() { + this.title = 'Home'; + this.alwaysEnabled = true; + this.updateOnSelect = false; + this.shortcuts = [{ + pattern : 'ctrl+home ctrl+shift+up', + description : 'Home' + }]; + + this.getstate = function() { + var root = this.fm.root(), + cwd = this.fm.cwd().hash; + + return root && cwd && root != cwd ? 0: -1; + }; + + this.exec = function() { + return this.fm.exec('open', this.fm.root()); + }; + + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/info.js + */ + +/** + * @class elFinder command "info". + * Display dialog with file properties. + * + * @author Dmitry (dio) Levashov, dio@std42.ru + **/ +(elFinder.prototype.commands.info = function() { + var m = 'msg', + fm = this.fm, + spclass = 'elfinder-spinner', + btnclass = 'elfinder-info-button', + msg = { + calc : fm.i18n('calc'), + size : fm.i18n('size'), + unknown : fm.i18n('unknown'), + path : fm.i18n('path'), + aliasfor : fm.i18n('aliasfor'), + modify : fm.i18n('modify'), + perms : fm.i18n('perms'), + locked : fm.i18n('locked'), + dim : fm.i18n('dim'), + kind : fm.i18n('kind'), + files : fm.i18n('files'), + folders : fm.i18n('folders'), + roots : fm.i18n('volumeRoots'), + items : fm.i18n('items'), + yes : fm.i18n('yes'), + no : fm.i18n('no'), + link : fm.i18n('link'), + owner : fm.i18n('owner'), + group : fm.i18n('group'), + perm : fm.i18n('perm'), + getlink : fm.i18n('getLink') + }, + applyZWSP = function(str, remove) { + if (remove) { + return str.replace(/\u200B/g, ''); + } else { + return str.replace(/(\/|\\)/g, "$1\u200B"); + } + }; + + this.items = ['size', 'aliasfor', 'path', 'link', 'dim', 'modify', 'perms', 'locked', 'owner', 'group', 'perm']; + if (this.options.custom && Object.keys(this.options.custom).length) { + $.each(this.options.custom, function(name, details) { + details.label && this.items.push(details.label); + }); + } + + this.tpl = { + main : '
            {title}
            {content}
            ', + itemTitle : '{name}{kind}', + groupTitle : '{items}: {num}', + row : '{label} : {value}', + spinner : '{text} ' + }; + + this.alwaysEnabled = true; + this.updateOnSelect = false; + this.shortcuts = [{ + pattern : 'ctrl+i' + }]; + + this.init = function() { + $.each(msg, function(k, v) { + msg[k] = fm.i18n(v); + }); + }; + + this.getstate = function() { + return 0; + }; + + this.exec = function(hashes) { + var files = this.files(hashes); + if (! files.length) { + files = this.files([ this.fm.cwd().hash ]); + } + var self = this, + fm = this.fm, + o = this.options, + tpl = this.tpl, + row = tpl.row, + cnt = files.length, + content = [], + view = tpl.main, + l = '{label}', + v = '{value}', + reqs = [], + reqDfrd = null, + opts = { + title : fm.i18n('selectionInfo'), + width : 'auto', + close : function() { + $(this).elfinderdialog('destroy'); + if (reqDfrd && reqDfrd.state() === 'pending') { + reqDfrd.reject(); + } + $.grep(reqs, function(r) { + r && r.state() === 'pending' && r.reject(); + }); + } + }, + count = [], + replSpinner = function(msg, name, className) { + dialog.find('.'+spclass+'-'+name).parent().html(msg).addClass(className || ''); + }, + id = fm.namespace+'-info-'+$.map(files, function(f) { return f.hash; }).join('-'), + dialog = fm.getUI().find('#'+id), + customActions = [], + style = '', + hashClass = 'elfinder-font-mono elfinder-info-hash', + getHashAlgorisms = [], + ndialog = fm.ui.notify, + size, tmb, file, title, dcnt, rdcnt, path, hideItems, hashProg; + + if (ndialog.is(':hidden') && ndialog.children('.elfinder-notify').length) { + ndialog.elfinderdialog('open').height('auto'); + } + + if (!cnt) { + return $.Deferred().reject(); + } + + if (dialog.length) { + dialog.elfinderdialog('toTop'); + return $.Deferred().resolve(); + } + + hideItems = fm.storage('infohides') || fm.arrayFlip(o.hideItems, true); + + if (cnt === 1) { + file = files[0]; + + if (file.icon) { + style = ' '+fm.getIconStyle(file); + } + + view = view.replace('{dirclass}', file.csscls? fm.escape(file.csscls) : '').replace('{class}', fm.mime2class(file.mime)).replace('{style}', style); + title = tpl.itemTitle.replace('{name}', fm.escape(file.i18 || file.name)).replace('{kind}', ''+fm.mime2kind(file)+''); + + tmb = fm.tmb(file); + + if (!file.read) { + size = msg.unknown; + } else if (file.mime != 'directory' || file.alias) { + size = fm.formatSize(file.size); + } else { + size = tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'size'); + count.push(file.hash); + } + + !hideItems.size && content.push(row.replace(l, msg.size).replace(v, size)); + !hideItems.aleasfor && file.alias && content.push(row.replace(l, msg.aliasfor).replace(v, file.alias)); + if (!hideItems.path) { + if (path = fm.path(file.hash, true)) { + content.push(row.replace(l, msg.path).replace(v, applyZWSP(fm.escape(path))).replace('{class}', 'elfinder-info-path')); + } else { + content.push(row.replace(l, msg.path).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'path')).replace('{class}', 'elfinder-info-path')); + reqs.push(fm.path(file.hash, true, {notify: null}) + .fail(function() { + replSpinner(msg.unknown, 'path'); + }) + .done(function(path) { + replSpinner(applyZWSP(path), 'path'); + })); + } + } + if (!hideItems.link && file.read) { + var href, + name_esc = fm.escape(file.name); + if (file.url == '1') { + content.push(row.replace(l, msg.link).replace(v, '')); + } else { + if (file.url) { + href = file.url; + } else if (file.mime === 'directory') { + if (o.nullUrlDirLinkSelf && file.url === null) { + var loc = window.location; + href = loc.pathname + loc.search + '#elf_' + file.hash; + } else if (file.url !== '' && fm.option('url', (!fm.isRoot(file) && file.phash) || file.hash)) { + href = fm.url(file.hash); + } + } else { + href = fm.url(file.hash); + } + href && content.push(row.replace(l, msg.link).replace(v, ''+name_esc+'')); + } + } + + if (!hideItems.dim) { + if (file.dim) { // old api + content.push(row.replace(l, msg.dim).replace(v, file.dim)); + } else if (file.mime.indexOf('image') !== -1) { + if (file.width && file.height) { + content.push(row.replace(l, msg.dim).replace(v, file.width+'x'+file.height)); + } else if (file.size && file.size !== '0') { + content.push(row.replace(l, msg.dim).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'dim'))); + reqs.push(fm.request({ + data : {cmd : 'dim', target : file.hash}, + preventDefault : true + }) + .fail(function() { + replSpinner(msg.unknown, 'dim'); + }) + .done(function(data) { + replSpinner(data.dim || msg.unknown, 'dim'); + if (data.dim) { + var dim = data.dim.split('x'); + var rfile = fm.file(file.hash); + rfile.width = dim[0]; + rfile.height = dim[1]; + } + })); + } + } + } + + !hideItems.modify && content.push(row.replace(l, msg.modify).replace(v, fm.formatDate(file))); + !hideItems.perms && content.push(row.replace(l, msg.perms).replace(v, fm.formatPermissions(file))); + !hideItems.locked && content.push(row.replace(l, msg.locked).replace(v, file.locked ? msg.yes : msg.no)); + !hideItems.owner && file.owner && content.push(row.replace(l, msg.owner).replace(v, file.owner)); + !hideItems.group && file.group && content.push(row.replace(l, msg.group).replace(v, file.group)); + !hideItems.perm && file.perm && content.push(row.replace(l, msg.perm).replace(v, fm.formatFileMode(file.perm))); + + // Get MD5, SHA hashes + if (window.ArrayBuffer && (fm.options.cdns.sparkmd5 || fm.options.cdns.jssha) && file.mime !== 'directory' && file.size > 0 && (!o.showHashMaxsize || file.size <= o.showHashMaxsize)) { + getHashAlgorisms = []; + $.each(fm.storage('hashchekcer') || o.showHashAlgorisms, function(i, n) { + if (!file[n]) { + content.push(row.replace(l, fm.i18n(n)).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', n))); + getHashAlgorisms.push(n); + } else { + content.push(row.replace(l, fm.i18n(n)).replace(v, file[n]).replace('{class}', hashClass)); + } + }); + + if (getHashAlgorisms.length) { + hashProg = $('
            '); + reqs.push( + fm.getContentsHashes(file.hash, getHashAlgorisms, o.showHashOpts, { progressBar : hashProg }).progress(function(hashes) { + $.each(getHashAlgorisms, function(i, n) { + if (hashes[n]) { + replSpinner(hashes[n], n, hashClass); + } + }); + }).always(function() { + $.each(getHashAlgorisms, function(i, n) { + replSpinner(msg.unknown, n); + }); + }) + ); + } + } + + // Add custom info fields + if (o.custom) { + $.each(o.custom, function(name, details) { + if ( + !hideItems[details.label] + && + (!details.mimes || $.grep(details.mimes, function(m){return (file.mime === m || file.mime.indexOf(m+'/') === 0)? true : false;}).length) + && + (!details.hashRegex || file.hash.match(details.hashRegex)) + ) { + // Add to the content + content.push(row.replace(l, fm.i18n(details.label)).replace(v , details.tpl.replace('{id}', id))); + // Register the action + if (details.action && (typeof details.action == 'function')) { + customActions.push(details.action); + } + } + }); + } + } else { + view = view.replace('{class}', 'elfinder-cwd-icon-group'); + title = tpl.groupTitle.replace('{items}', msg.items).replace('{num}', cnt); + dcnt = $.grep(files, function(f) { return f.mime == 'directory' ? true : false ; }).length; + if (!dcnt) { + size = 0; + $.each(files, function(h, f) { + var s = parseInt(f.size); + + if (s >= 0 && size >= 0) { + size += s; + } else { + size = 'unknown'; + } + }); + content.push(row.replace(l, msg.kind).replace(v, msg.files)); + !hideItems.size && content.push(row.replace(l, msg.size).replace(v, fm.formatSize(size))); + } else { + rdcnt = $.grep(files, function(f) { return f.mime === 'directory' && (! f.phash || f.isroot)? true : false ; }).length; + dcnt -= rdcnt; + content.push(row.replace(l, msg.kind).replace(v, (rdcnt === cnt || dcnt === cnt)? msg[rdcnt? 'roots' : 'folders'] : $.map({roots: rdcnt, folders: dcnt, files: cnt - rdcnt - dcnt}, function(c, t) { return c? msg[t]+' '+c : null; }).join(', '))); + !hideItems.size && content.push(row.replace(l, msg.size).replace(v, tpl.spinner.replace('{text}', msg.calc).replace('{name}', 'size'))); + count = $.map(files, function(f) { return f.hash; }); + + } + } + + view = view.replace('{title}', title).replace('{content}', content.join('').replace(/{class}/g, '')); + + dialog = self.fmDialog(view, opts); + dialog.attr('id', id).one('mousedown', '.elfinder-info-path', function() { + $(this).html(applyZWSP($(this).html(), true)); + }); + + if (getHashAlgorisms.length) { + hashProg.appendTo(dialog.find('.'+spclass+'-'+getHashAlgorisms[0]).parent()); + } + + if (fm.UA.Mobile && $.fn.tooltip) { + dialog.children('.ui-dialog-content .elfinder-info-title').tooltip({ + classes: { + 'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow' + }, + tooltipClass: 'elfinder-ui-tooltip ui-widget-shadow', + track: true + }); + } + + if (file && file.url == '1') { + dialog.on('click', '.'+spclass+'-url', function(){ + $(this).parent().html(tpl.spinner.replace('{text}', fm.i18n('ntfurl')).replace('{name}', 'url')); + fm.request({ + data : {cmd : 'url', target : file.hash}, + preventDefault : true + }) + .fail(function() { + replSpinner(name_esc, 'url'); + }) + .done(function(data) { + if (data.url) { + replSpinner(''+name_esc+'' || name_esc, 'url'); + var rfile = fm.file(file.hash); + rfile.url = data.url; + } else { + replSpinner(name_esc, 'url'); + } + }); + }); + } + + // load thumbnail + if (tmb) { + $('') + .on('load', function() { dialog.find('.elfinder-cwd-icon').addClass(tmb.className).css('background-image', "url('"+tmb.url+"')"); }) + .attr('src', tmb.url); + } + + // send request to count total size + if (count.length) { + reqDfrd = fm.getSize(count).done(function(data) { + replSpinner(data.formated, 'size'); + }).fail(function() { + replSpinner(msg.unknown, 'size'); + }); + } + + // call custom actions + if (customActions.length) { + $.each(customActions, function(i, action) { + try { + action(file, fm, dialog); + } catch(e) { + fm.debug('error', e); + } + }); + } + + return $.Deferred().resolve(); + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/mkdir.js + */ + +/** + * @class elFinder command "mkdir" + * Create new folder + * + * @author Dmitry (dio) Levashov + **/ +elFinder.prototype.commands.mkdir = function() { + var fm = this.fm, + self = this, + curOrg; + + this.value = ''; + this.disableOnSearch = true; + this.updateOnSelect = false; + this.syncTitleOnChange = true; + this.mime = 'directory'; + this.prefix = 'untitled folder'; + this.exec = function(select, cOpts) { + var onCwd; + + if (select && select.length && cOpts && cOpts._currentType && cOpts._currentType === 'navbar') { + this.origin = cOpts._currentType; + this.data = { + target: select[0] + }; + } else { + onCwd = fm.cwd().hash === select[0]; + this.origin = curOrg && !onCwd? curOrg : 'cwd'; + delete this.data; + } + if (! select && ! this.options.intoNewFolderToolbtn) { + fm.getUI('cwd').trigger('unselectall'); + } + //this.move = (!onCwd && curOrg !== 'navbar' && fm.selected().length)? true : false; + this.move = this.value === fm.i18n('cmdmkdirin'); + return $.proxy(fm.res('mixin', 'make'), self)(); + }; + + this.shortcuts = [{ + pattern : 'ctrl+shift+n' + }]; + + this.init = function() { + if (this.options.intoNewFolderToolbtn) { + this.syncTitleOnChange = true; + } + }; + + fm.bind('select contextmenucreate closecontextmenu', function(e) { + var sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected(); + + self.className = 'mkdir'; + curOrg = e.data && sel.length? (e.data.origin || e.data.type || '') : ''; + if (!self.options.intoNewFolderToolbtn && curOrg === '') { + curOrg = 'cwd'; + } + if (sel.length && curOrg !== 'navbar' && curOrg !== 'cwd' && fm.cwd().hash !== sel[0]) { + self.title = fm.i18n('cmdmkdirin'); + self.className += ' elfinder-button-icon-mkdirin'; + } else { + self.title = fm.i18n('cmdmkdir'); + } + if (e.type !== 'closecontextmenu') { + self.update(void(0), self.title); + } else { + requestAnimationFrame(function() { + self.update(void(0), self.title); + }); + } + }); + + this.getstate = function(select) { + var cwd = fm.cwd(), + sel = (curOrg === 'navbar' || (select && select[0] !== cwd.hash))? this.files(select || fm.selected()) : [], + cnt = sel.length, + filter = function(files) { + var fres = true; + return $.grep(files, function(f) { + fres = fres && f.read && ! f.locked? true : false; + return fres; + }); + }; + + if (curOrg === 'navbar') { + return cnt && sel[0].write && sel[0].read? 0 : -1; + } else { + return cwd.write && (!cnt || filter(sel).length == cnt)? 0 : -1; + } + }; + +}; + + +/* + * File: /js/commands/mkfile.js + */ + +/** + * @class elFinder command "mkfile" + * Create new empty file + * + * @author Dmitry (dio) Levashov + **/ +elFinder.prototype.commands.mkfile = function() { + var self = this; + + this.disableOnSearch = true; + this.updateOnSelect = false; + this.mime = 'text/plain'; + this.prefix = 'untitled file.txt'; + this.variants = []; + + this.getTypeName = function(mime, type) { + var fm = self.fm, + name; + if (name = fm.messages['kind' + fm.kinds[mime]]) { + name = fm.i18n(['extentiontype', type.toUpperCase(), name]); + } else { + name = fm.i18n(['extentionfile', type.toUpperCase()]); + } + return name; + }; + + this.fm.bind('open reload canMakeEmptyFile', function() { + var fm = self.fm, + hides = fm.getCommand('edit').getMkfileHides(); + self.variants = []; + if (fm.mimesCanMakeEmpty) { + $.each(fm.mimesCanMakeEmpty, function(mime, type) { + type && !hides[mime] && fm.uploadMimeCheck(mime) && self.variants.push([mime, self.getTypeName(mime, type)]); + }); + } + self.change(); + }); + + this.getstate = function() { + return this.fm.cwd().write ? 0 : -1; + }; + + this.exec = function(_dum, mime) { + var fm = self.fm, + type, err; + if (type = fm.mimesCanMakeEmpty[mime]) { + if (fm.uploadMimeCheck(mime)) { + this.mime = mime; + this.prefix = fm.i18n(['untitled file', type]); + return $.proxy(fm.res('mixin', 'make'), self)(); + } + err = ['errMkfile', self.getTypeName(mime, type)]; + } + return $.Deferred().reject(err); + }; +}; + + +/* + * File: /js/commands/netmount.js + */ + +/** + * @class elFinder command "netmount" + * Mount network volume with user credentials. + * + * @author Dmitry (dio) Levashov + **/ +elFinder.prototype.commands.netmount = function() { + var self = this, + hasMenus = false, + content; + + this.alwaysEnabled = true; + this.updateOnSelect = false; + + this.drivers = []; + + this.handlers = { + load : function() { + var fm = self.fm; + if (fm.cookieEnabled) { + fm.one('open', function() { + self.drivers = fm.netDrivers; + if (self.drivers.length) { + $.each(self.drivers, function() { + var d = self.options[this]; + if (d) { + hasMenus = true; + if (d.integrateInfo) { + fm.trigger('helpIntegration', Object.assign({cmd: 'netmount'}, d.integrateInfo)); + } + } + }); + } + }); + } + } + }; + + this.getstate = function() { + return hasMenus ? 0 : -1; + }; + + this.exec = function() { + var fm = self.fm, + dfrd = $.Deferred(), + o = self.options, + create = function() { + var winFocus = function() { + inputs.protocol.trigger('change', 'winfocus'); + }, + inputs = { + protocol : $('') + .on('change', function(e, data){ + var protocol = this.value; + content.find('.elfinder-netmount-tr').hide(); + content.find('.elfinder-netmount-tr-'+protocol).show(); + dialogNode && dialogNode.children('.ui-dialog-buttonpane:first').find('button').show(); + if (typeof o[protocol].select == 'function') { + o[protocol].select(fm, e, data); + } + }) + .addClass('ui-corner-all') + }, + opts = { + title : fm.i18n('netMountDialogTitle'), + resizable : true, + modal : true, + destroyOnClose : false, + open : function() { + $(window).on('focus.'+fm.namespace, winFocus); + inputs.protocol.trigger('change'); + }, + close : function() { + dfrd.state() == 'pending' && dfrd.reject(); + $(window).off('focus.'+fm.namespace, winFocus); + }, + buttons : {} + }, + doMount = function() { + var protocol = inputs.protocol.val(), + data = {cmd : 'netmount', protocol: protocol}, + cur = o[protocol], + mnt2res; + $.each(content.find('input.elfinder-netmount-inputs-'+protocol), function(name, input) { + var val, elm; + elm = $(input); + if (elm.is(':radio,:checkbox')) { + if (elm.is(':checked')) { + val = $.trim(elm.val()); + } + } else { + val = $.trim(elm.val()); + } + if (val) { + data[input.name] = val; + } + }); + + if (!data.host) { + return fm.trigger('error', {error : 'errNetMountHostReq', opts : {modal: true}}); + } + + if (data.mnt2res) { + mnt2res = true; + } + + fm.request({data : data, notify : {type : 'netmount', cnt : 1, hideCnt : true}}) + .done(function(data) { + var pdir; + if (data.added && data.added.length) { + mnt2res && inputs.protocol.trigger('change', 'reset'); + if (data.added[0].phash) { + if (pdir = fm.file(data.added[0].phash)) { + if (! pdir.dirs) { + pdir.dirs = 1; + fm.change({ changed: [ pdir ] }); + } + } + } + fm.one('netmountdone', function() { + fm.exec('open', data.added[0].hash); + }); + } + dfrd.resolve(); + }) + .fail(function(error) { + if (cur.fail && typeof cur.fail == 'function') { + cur.fail(fm, fm.parseError(error)); + } + dfrd.reject(error); + }); + + self.dialog.elfinderdialog('close'); + }, + form = $('
            ').on('keydown', 'input', function(e) { + var comp = true, + next; + if (e.keyCode === $.ui.keyCode.ENTER) { + $.each(form.find('input:visible:not(.elfinder-input-optional)'), function() { + if ($(this).val() === '') { + comp = false; + next = $(this); + return false; + } + }); + if (comp) { + doMount(); + } else { + next.trigger('focus'); + } + } + }), + hidden = $('
            '), + dialog; + + content = $('
            ') + .append($('').append($(''+fm.i18n('protocol')+'')).append($('').append(inputs.protocol))); + + $.each(self.drivers, function(i, protocol) { + if (o[protocol]) { + inputs.protocol.append(''); + $.each(o[protocol].inputs, function(name, input) { + input.attr('name', name); + if (input.attr('type') != 'hidden') { + input.addClass('ui-corner-all elfinder-netmount-inputs-'+protocol); + content.append($('').addClass('elfinder-netmount-tr elfinder-netmount-tr-'+protocol).append($(''+fm.i18n(name)+'')).append($('').append(input))); + } else { + input.addClass('elfinder-netmount-inputs-'+protocol); + hidden.append(input); + } + }); + o[protocol].protocol = inputs.protocol; + } + }); + + content.append(hidden); + + content.find('.elfinder-netmount-tr').hide(); + content.find('.elfinder-netmount-tr-' + self.drivers[0]).show(); + + opts.buttons[fm.i18n('btnMount')] = doMount; + + opts.buttons[fm.i18n('btnCancel')] = function() { + self.dialog.elfinderdialog('close'); + }; + + content.find('select,input').addClass('elfinder-tabstop'); + + dialog = self.fmDialog(form.append(content), opts).ready(function() { + inputs.protocol.trigger('change'); + dialog.elfinderdialog('posInit'); + }); + dialogNode = dialog.closest('.ui-dialog'); + return dialog; + }, + dialogNode; + + if (!self.dialog) { + self.dialog = create(); + } else { + self.dialog.elfinderdialog('open'); + } + + return dfrd.promise(); + }; + + self.fm.bind('netmount', function(e) { + var d = e.data || null, + o = self.options, + done = function() { + if (o[d.protocol] && typeof o[d.protocol].done == 'function') { + o[d.protocol].done(self.fm, d); + content.find('select,input').addClass('elfinder-tabstop'); + self.dialog.elfinderdialog('tabstopsInit'); + } + }; + if (d && d.protocol) { + if (d.mode && d.mode === 'redirect') { + // To support of third-party cookie blocking (ITP) on CORS + // On iOS and iPadOS 13.4 and Safari 13.1 on macOS, the session cannot be continued when redirecting OAuth in CORS mode + self.fm.request({ + data : {cmd : 'netmount', protocol : d.protocol, host: d.host, user : 'init', pass : 'return', options: d.options}, + preventDefault : true + }).done(function(data) { + d = JSON.parse(data.body); + done(); + }); + } else { + done(); + } + } + }); + +}; + +elFinder.prototype.commands.netunmount = function() { + var self = this; + + this.alwaysEnabled = true; + this.updateOnSelect = false; + + this.drivers = []; + + this.handlers = { + load : function() { + this.drivers = this.fm.netDrivers; + } + }; + + this.getstate = function(sel) { + var fm = this.fm, + file; + return !!sel && this.drivers.length && !this._disabled && (file = fm.file(sel[0])) && file.netkey ? 0 : -1; + }; + + this.exec = function(hashes) { + var self = this, + fm = this.fm, + dfrd = $.Deferred() + .fail(function(error) { + error && fm.error(error); + }), + drive = fm.file(hashes[0]), + childrenRoots = function(hash) { + var roots = [], + work; + if (fm.leafRoots) { + work = []; + $.each(fm.leafRoots, function(phash, hashes) { + var parents = fm.parents(phash), + idx, deep; + if ((idx = $.inArray(hash, parents)) !== -1) { + idx = parents.length - idx; + $.each(hashes, function(i, h) { + work.push({i: idx, hash: h}); + }); + } + }); + if (work.length) { + work.sort(function(a, b) { return a.i < b.i; }); + $.each(work, function(i, o) { + roots.push(o.hash); + }); + } + } + return roots; + }; + + if (this._disabled) { + return dfrd.reject(); + } + + if (dfrd.state() == 'pending') { + fm.confirm({ + title : self.title, + text : fm.i18n('confirmUnmount', drive.name), + accept : { + label : 'btnUnmount', + callback : function() { + var target = drive.hash, + roots = childrenRoots(target), + requests = [], + removed = [], + doUmount = function() { + $.when(requests).done(function() { + fm.request({ + data : {cmd : 'netmount', protocol : 'netunmount', host: drive.netkey, user : target, pass : 'dum'}, + notify : {type : 'netunmount', cnt : 1, hideCnt : true}, + preventFail : true + }) + .fail(function(error) { + dfrd.reject(error); + }) + .done(function(data) { + drive.volumeid && delete fm.volumeExpires[drive.volumeid]; + dfrd.resolve(); + }); + }).fail(function(error) { + if (removed.length) { + fm.remove({ removed: removed }); + } + dfrd.reject(error); + }); + }; + + if (roots.length) { + fm.confirm({ + title : self.title, + text : (function() { + var msgs = ['unmountChildren']; + $.each(roots, function(i, hash) { + msgs.push([fm.file(hash).name]); + }); + return msgs; + })(), + accept : { + label : 'btnUnmount', + callback : function() { + $.each(roots, function(i, hash) { + var d = fm.file(hash); + if (d.netkey) { + requests.push(fm.request({ + data : {cmd : 'netmount', protocol : 'netunmount', host: d.netkey, user : d.hash, pass : 'dum'}, + notify : {type : 'netunmount', cnt : 1, hideCnt : true}, + preventDefault : true + }).done(function(data) { + if (data.removed) { + d.volumeid && delete fm.volumeExpires[d.volumeid]; + removed = removed.concat(data.removed); + } + })); + } + }); + doUmount(); + } + }, + cancel : { + label : 'btnCancel', + callback : function() { + dfrd.reject(); + } + } + }); + } else { + requests = null; + doUmount(); + } + } + }, + cancel : { + label : 'btnCancel', + callback : function() { dfrd.reject(); } + } + }); + } + + return dfrd; + }; + +}; + + +/* + * File: /js/commands/open.js + */ + +/** + * @class elFinder command "open" + * Enter folder or open files in new windows + * + * @author Dmitry (dio) Levashov + **/ +(elFinder.prototype.commands.open = function() { + var fm = this.fm, + self = this; + this.alwaysEnabled = true; + this.noChangeDirOnRemovedCwd = true; + + this._handlers = { + dblclick : function(e) { + var arg = e.data && e.data.file? [ e.data.file ]: void(0); + if (self.getstate(arg) === 0) { + e.preventDefault(); + fm.exec('open', arg); + } + }, + 'select enable disable reload' : function(e) { this.update(e.type == 'disable' ? -1 : void(0)); } + }; + + this.shortcuts = [{ + pattern : 'ctrl+down numpad_enter'+(fm.OS != 'mac' && ' enter') + }]; + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length, + filter = function(files) { + var fres = true; + return $.grep(files, function(file) { + fres = fres && file.mime == 'directory' || ! file.read ? false : true; + return fres; + }); + }; + + return cnt == 1 + ? (sel[0].read ? 0 : -1) + : (cnt && !fm.UA.Mobile) ? ($.grep(sel, function(file) { return file.mime == 'directory' || ! file.read ? false : true;}).length == cnt ? 0 : -1) : -1; + }; + + this.exec = function(hashes, cOpts) { + var dfrd = $.Deferred().fail(function(error) { error && fm.error(error); }), + files = this.files(hashes), + cnt = files.length, + thash = (typeof cOpts == 'object')? cOpts.thash : false, + opts = this.options, + into = opts.into || 'window', + file, url, s, w, imgW, imgH, winW, winH, reg, link, html5dl, inline, + selAct, cmd; + + if (!cnt && !thash) { + { + return dfrd.reject(); + } + } + + // open folder + if (thash || (cnt == 1 && (file = files[0]) && file.mime == 'directory')) { + if (!thash && file && !file.read) { + return dfrd.reject(['errOpen', file.name, 'errPerm']); + } else { + if (fm.keyState.ctrlKey && (fm.keyState.shiftKey || typeof fm.options.getFileCallback !== 'function')) { + if (fm.getCommand('opennew')) { + return fm.exec('opennew', [thash? thash : file.hash]); + } + } + + return fm.request({ + data : {cmd : 'open', target : thash || file.hash}, + notify : {type : 'open', cnt : 1, hideCnt : true}, + syncOnFail : true, + lazy : false + }); + } + } + + files = $.grep(files, function(file) { return file.mime != 'directory' ? true : false; }); + + // nothing to open or files and folders selected - do nothing + if (cnt != files.length) { + return dfrd.reject(); + } + + var doOpen = function() { + var openCB = function(url) { + var link = $('').hide().appendTo($('body')); + if (fm.UA.Mobile || !inline) { + if (html5dl) { + if (!inline) { + link.attr('download', file.name); + } else { + link.attr('target', '_blank'); + } + link.attr('href', url).get(0).click(); + } else { + wnd = window.open(url); + if (!wnd) { + return dfrd.reject('errPopup'); + } + } + } else { + getOnly = (typeof opts.method === 'string' && opts.method.toLowerCase() === 'get'); + if (!getOnly + && url.indexOf(fm.options.url) === 0 + && fm.customData + && Object.keys(fm.customData).length + // Since playback by POST request can not be done in Chrome, media allows GET request + && !file.mime.match(/^(?:video|audio)/) + ) { + // Send request as 'POST' method to hide custom data at location bar + url = ''; + } + if (into === 'window') { + // set window size for image if set + imgW = winW = Math.round(2 * screen.availWidth / 3); + imgH = winH = Math.round(2 * screen.availHeight / 3); + if (parseInt(file.width) && parseInt(file.height)) { + imgW = parseInt(file.width); + imgH = parseInt(file.height); + } else if (file.dim) { + s = file.dim.split('x'); + imgW = parseInt(s[0]); + imgH = parseInt(s[1]); + } + if (winW >= imgW && winH >= imgH) { + winW = imgW; + winH = imgH; + } else { + if ((imgW - winW) > (imgH - winH)) { + winH = Math.round(imgH * (winW / imgW)); + } else { + winW = Math.round(imgW * (winH / imgH)); + } + } + w = 'width='+winW+',height='+winH; + wnd = window.open(url, target, w + ',top=50,left=50,scrollbars=yes,resizable=yes,titlebar=no'); + } else { + if (into === 'tabs') { + target = file.hash; + } + wnd = window.open('about:blank', target); + } + + if (!wnd) { + return dfrd.reject('errPopup'); + } + + if (url === '') { + var form = document.createElement("form"); + form.action = fm.options.url; + form.method = 'POST'; + form.target = target; + form.style.display = 'none'; + var params = Object.assign({}, fm.customData, { + cmd: 'file', + target: file.hash, + _t: file.ts || parseInt(+new Date()/1000) + }); + $.each(params, function(key, val) + { + var input = document.createElement("input"); + input.name = key; + input.value = val; + form.appendChild(input); + }); + + document.body.appendChild(form); + form.submit(); + } else if (into !== 'window') { + wnd.location = url; + } + $(wnd).trigger('focus'); + } + link.remove(); + }, + wnd, target, getOnly; + + try { + reg = new RegExp(fm.option('dispInlineRegex'), 'i'); + } catch(e) { + reg = false; + } + + // open files + html5dl = (typeof $('').get(0).download === 'string'); + cnt = files.length; + while (cnt--) { + target = 'elf_open_window'; + file = files[cnt]; + + if (!file.read) { + return dfrd.reject(['errOpen', file.name, 'errPerm']); + } + + inline = (reg && file.mime.match(reg)); + fm.openUrl(file.hash, !inline, openCB); + } + return dfrd.resolve(hashes); + }; + + if (cnt > 1) { + fm.confirm({ + title: 'openMulti', + text : ['openMultiConfirm', cnt + ''], + accept : { + label : 'cmdopen', + callback : function() { doOpen(); } + }, + cancel : { + label : 'btnCancel', + callback : function() { + dfrd.reject(); + } + }, + buttons : (fm.getCommand('zipdl') && fm.isCommandEnabled('zipdl', fm.cwd().hash))? [ + { + label : 'cmddownload', + callback : function() { + fm.exec('download', hashes); + dfrd.reject(); + } + } + ] : [] + }); + } else { + selAct = fm.storage('selectAction') || opts.selectAction; + if (selAct) { + $.each(selAct.split('/'), function() { + var cmdName = this.valueOf(); + if (cmdName !== 'open' && (cmd = fm.getCommand(cmdName)) && cmd.enabled()) { + return false; + } + cmd = null; + }); + if (cmd) { + return fm.exec(cmd.name); + } + } + doOpen(); + } + + return dfrd; + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/opendir.js + */ + +/** + * @class elFinder command "opendir" + * Enter parent folder + * + * @author Naoki Sawada + **/ +elFinder.prototype.commands.opendir = function() { + this.alwaysEnabled = true; + + this.getstate = function() { + var sel = this.fm.selected(), + cnt = sel.length, + wz; + if (cnt !== 1) { + return -1; + } + wz = this.fm.getUI('workzone'); + return wz.hasClass('elfinder-search-result')? 0 : -1; + }; + + this.exec = function(hashes) { + var fm = this.fm, + dfrd = $.Deferred(), + files = this.files(hashes), + cnt = files.length, + hash, pcheck = null; + + if (!cnt || !files[0].phash) { + return dfrd.reject(); + } + + hash = files[0].phash; + fm.trigger('searchend', { noupdate: true }); + fm.request({ + data : {cmd : 'open', target : hash}, + notify : {type : 'open', cnt : 1, hideCnt : true}, + syncOnFail : false + }); + + return dfrd; + }; + +}; + + +/* + * File: /js/commands/opennew.js + */ + +/** + * @class elFinder command "opennew" + * Open folder in new window + * + * @author Naoki Sawada + **/ +elFinder.prototype.commands.opennew = function() { + var fm = this.fm; + + this.shortcuts = [{ + pattern : (typeof(fm.options.getFileCallback) === 'function'? 'shift+' : '') + 'ctrl+enter' + }]; + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length; + + return cnt === 1 + ? (sel[0].mime === 'directory' && sel[0].read? 0 : -1) + : -1; + }; + + this.exec = function(hashes) { + var dfrd = $.Deferred(), + files = this.files(hashes), + cnt = files.length, + opts = this.options, + file, loc, url, win; + + // open folder to new tab (window) + if (cnt === 1 && (file = files[0]) && file.mime === 'directory') { + loc = window.location; + if (opts.url) { + url = opts.url; + } else { + url = loc.pathname; + } + if (opts.useOriginQuery) { + if (!url.match(/\?/)) { + url += loc.search; + } else if (loc.search) { + url += '&' + loc.search.substr(1); + } + } + url += '#elf_' + file.hash; + win = window.open(url, '_blank'); + setTimeout(function() { + win.focus(); + }, 1000); + return dfrd.resolve(); + } else { + return dfrd.reject(); + } + }; +}; + + +/* + * File: /js/commands/paste.js + */ + +/** + * @class elFinder command "paste" + * Paste filesfrom clipboard into directory. + * If files pasted in its parent directory - files duplicates will created + * + * @author Dmitry (dio) Levashov + **/ +elFinder.prototype.commands.paste = function() { + this.updateOnSelect = false; + + this.handlers = { + changeclipboard : function() { this.update(); } + }; + + this.shortcuts = [{ + pattern : 'ctrl+v shift+insert' + }]; + + this.getstate = function(dst) { + if (this._disabled) { + return -1; + } + if (dst) { + if (Array.isArray(dst)) { + if (dst.length != 1) { + return -1; + } + dst = this.fm.file(dst[0]); + } + } else { + dst = this.fm.cwd(); + } + + return this.fm.clipboard().length && dst.mime == 'directory' && dst.write ? 0 : -1; + }; + + this.exec = function(select, cOpts) { + var self = this, + fm = self.fm, + opts = cOpts || {}, + dst = select ? this.files(select)[0] : fm.cwd(), + files = fm.clipboard(), + cnt = files.length, + cut = cnt ? files[0].cut : false, + cmd = opts._cmd? opts._cmd : (cut? 'move' : 'copy'), + error = 'err' + cmd.charAt(0).toUpperCase() + cmd.substr(1), + fpaste = [], + fcopy = [], + dfrd = $.Deferred() + .fail(function(error) { + error && fm.error(error); + }) + .always(function() { + fm.unlockfiles({files : $.map(files, function(f) { return f.hash; })}); + }), + copy = function(files) { + return files.length && fm._commands.duplicate + ? fm.exec('duplicate', files) + : $.Deferred().resolve(); + }, + paste = function(files) { + var dfrd = $.Deferred(), + existed = [], + hashes = {}, + intersect = function(files, names) { + var ret = [], + i = files.length; + + while (i--) { + $.inArray(files[i].name, names) !== -1 && ret.unshift(i); + } + return ret; + }, + confirm = function(ndx) { + var i = existed[ndx], + file = files[i], + last = ndx == existed.length-1; + + if (!file) { + return; + } + + fm.confirm({ + title : fm.i18n(cmd + 'Files'), + text : ['errExists', file.name, cmd === 'restore'? 'confirmRest' : 'confirmRepl'], + all : !last, + accept : { + label : 'btnYes', + callback : function(all) { + !last && !all + ? confirm(++ndx) + : paste(files); + } + }, + reject : { + label : 'btnNo', + callback : function(all) { + var i; + + if (all) { + i = existed.length; + while (ndx < i--) { + files[existed[i]].remove = true; + } + } else { + files[existed[ndx]].remove = true; + } + + !last && !all + ? confirm(++ndx) + : paste(files); + } + }, + cancel : { + label : 'btnCancel', + callback : function() { + dfrd.resolve(); + } + }, + buttons : [ + { + label : 'btnBackup', + callback : function(all) { + var i; + if (all) { + i = existed.length; + while (ndx < i--) { + files[existed[i]].rename = true; + } + } else { + files[existed[ndx]].rename = true; + } + !last && !all + ? confirm(++ndx) + : paste(files); + } + } + ] + }); + }, + valid = function(names) { + var exists = {}, existedArr; + if (names) { + if (Array.isArray(names)) { + if (names.length) { + if (typeof names[0] == 'string') { + // elFinder <= 2.1.6 command `is` results + existed = intersect(files, names); + } else { + $.each(names, function(i, v) { + exists[v.name] = v.hash; + }); + existed = intersect(files, $.map(exists, function(h, n) { return n; })); + $.each(files, function(i, file) { + if (exists[file.name]) { + hashes[exists[file.name]] = file.name; + } + }); + } + } + } else { + existedArr = []; + existed = $.map(names, function(n) { + if (typeof n === 'string') { + return n; + } else { + // support to >=2.1.11 plugin Normalizer, Sanitizer + existedArr = existedArr.concat(n); + return false; + } + }); + if (existedArr.length) { + existed = existed.concat(existedArr); + } + existed = intersect(files, existed); + hashes = names; + } + } + existed.length ? confirm(0) : paste(files); + }, + paste = function(selFiles) { + var renames = [], + files = $.grep(selFiles, function(file) { + if (file.rename) { + renames.push(file.name); + } + return !file.remove ? true : false; + }), + cnt = files.length, + groups = {}, + args = [], + targets, reqData; + + if (!cnt) { + return dfrd.resolve(); + } + + targets = $.map(files, function(f) { return f.hash; }); + + reqData = {cmd : 'paste', dst : dst.hash, targets : targets, cut : cut ? 1 : 0, renames : renames, hashes : hashes, suffix : fm.options.backupSuffix}; + if (fm.api < 2.1) { + reqData.src = files[0].phash; + } + + fm.request({ + data : reqData, + notify : {type : cmd, cnt : cnt}, + cancel : true, + navigate : { + toast : opts.noToast? {} : { + inbuffer : {msg: fm.i18n(['complete', fm.i18n('cmd' + cmd)]), action: { + cmd: 'open', + msg: 'cmdopendir', + data: [dst.hash], + done: 'select', + cwdNot: dst.hash + }} + } + } + }) + .done(function(data) { + var dsts = {}, + added = data.added && data.added.length? data.added : null; + if (cut && added) { + // undo/redo + $.each(files, function(i, f) { + var phash = f.phash, + srcHash = function(name) { + var hash; + $.each(added, function(i, f) { + if (f.name === name) { + hash = f.hash; + return false; + } + }); + return hash; + }, + shash = srcHash(f.name); + if (shash) { + if (dsts[phash]) { + dsts[phash].push(shash); + } else { + dsts[phash] = [ shash ]; + } + } + }); + if (Object.keys(dsts).length) { + data.undo = { + cmd : 'move', + callback : function() { + var reqs = []; + $.each(dsts, function(dst, targets) { + reqs.push(fm.request({ + data : {cmd : 'paste', dst : dst, targets : targets, cut : 1}, + notify : {type : 'undo', cnt : targets.length} + })); + }); + return $.when.apply(null, reqs); + } + }; + data.redo = { + cmd : 'move', + callback : function() { + return fm.request({ + data : reqData, + notify : {type : 'redo', cnt : cnt} + }); + } + }; + } + } + dfrd.resolve(data); + }) + .fail(function(flg) { + dfrd.reject(); + if (flg === 0) { + // canceling + fm.sync(); + } + }) + .always(function() { + fm.unlockfiles({files : files}); + }); + }, + internames; + + if (!fm.isCommandEnabled(self.name, dst.hash) || !files.length) { + return dfrd.resolve(); + } + + if (fm.oldAPI) { + paste(files); + } else { + + if (!fm.option('copyOverwrite', dst.hash)) { + paste(files); + } else { + internames = $.map(files, function(f) { return f.name; }); + dst.hash == fm.cwd().hash + ? valid($.map(fm.files(), function(file) { return file.phash == dst.hash ? {hash: file.hash, name: file.name} : null; })) + : fm.request({ + data : {cmd : 'ls', target : dst.hash, intersect : internames}, + notify : {type : 'prepare', cnt : 1, hideCnt : true}, + preventFail : true + }) + .always(function(data) { + valid(data.list); + }); + } + } + + return dfrd; + }, + parents, fparents, cutDfrd; + + + if (!cnt || !dst || dst.mime != 'directory') { + return dfrd.reject(); + } + + if (!dst.write) { + return dfrd.reject([error, files[0].name, 'errPerm']); + } + + parents = fm.parents(dst.hash); + + $.each(files, function(i, file) { + if (!file.read) { + return !dfrd.reject([error, file.name, 'errPerm']); + } + + if (cut && file.locked) { + return !dfrd.reject(['errLocked', file.name]); + } + + if ($.inArray(file.hash, parents) !== -1) { + return !dfrd.reject(['errCopyInItself', file.name]); + } + + if (file.mime && file.mime !== 'directory' && ! fm.uploadMimeCheck(file.mime, dst.hash)) { + return !dfrd.reject([error, file.name, 'errUploadMime']); + } + + fparents = fm.parents(file.hash); + fparents.pop(); + if ($.inArray(dst.hash, fparents) !== -1) { + + if ($.grep(fparents, function(h) { var d = fm.file(h); return d.phash == dst.hash && d.name == file.name ? true : false; }).length) { + return !dfrd.reject(['errReplByChild', file.name]); + } + } + + if (file.phash == dst.hash) { + fcopy.push(file.hash); + } else { + fpaste.push({ + hash : file.hash, + phash : file.phash, + name : file.name + }); + } + }); + + if (dfrd.state() === 'rejected') { + return dfrd; + } + + cutDfrd = $.Deferred(); + if (cut && self.options.moveConfirm) { + fm.confirm({ + title : 'moveFiles', + text : fm.i18n('confirmMove', dst.i18 || dst.name), + accept : { + label : 'btnYes', + callback : function() { + cutDfrd.resolve(); + } + }, + cancel : { + label : 'btnCancel', + callback : function() { + cutDfrd.reject(); + } + } + }); + } else { + cutDfrd.resolve(); + } + + cutDfrd.done(function() { + $.when( + copy(fcopy), + paste(fpaste) + ) + .done(function(cr, pr) { + dfrd.resolve(pr && pr.undo? pr : void(0)); + }) + .fail(function() { + dfrd.reject(); + }) + .always(function() { + cut && fm.clipboard([]); + }); + }).fail(function() { + dfrd.reject(); + }); + + return dfrd; + }; + +}; + + +/* + * File: /js/commands/places.js + */ + +/** + * @class elFinder command "places" + * Regist to Places + * + * @author Naoki Sawada + **/ +elFinder.prototype.commands.places = function() { + var self = this, + fm = this.fm, + filter = function(hashes) { + var fres = true; + return $.grep(self.files(hashes), function(f) { + fres = fres && f.mime == 'directory' ? true : false; + return fres; + }); + }, + places = null; + + this.getstate = function(select) { + var sel = this.hashes(select), + cnt = sel.length; + + return places && cnt && cnt == filter(sel).length ? 0 : -1; + }; + + this.exec = function(hashes) { + var files = this.files(hashes); + places.trigger('regist', [ files ]); + return $.Deferred().resolve(); + }; + + fm.one('load', function(){ + places = fm.ui.places; + }); + +}; + + +/* + * File: /js/commands/preference.js + */ + +/** + * @class elFinder command "preference" + * "Preference" dialog + * + * @author Naoki Sawada + **/ +elFinder.prototype.commands.preference = function() { + var self = this, + fm = this.fm, + r = 'replace', + tab = '
          • {title}
          • ', + base = $('
            '), + ul = $('
              '), + tabs = $('
              '), + sep = '
              ', + selfUrl = $('base').length? document.location.href.replace(/#.*$/, '') : '', + selectTab = function(tab) { + $('#'+fm.namespace+'-preference-tab-'+tab).trigger('mouseover').trigger('click'); + openTab = tab; + }, + clTabActive = fm.res('class', 'tabsactive'), + build = function() { + var cats = self.options.categories || { + 'language' : ['language'], + 'theme' : ['theme'], + 'toolbar' : ['toolbarPref'], + 'workspace' : ['iconSize','columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'useFullscreen', 'showHidden'], + 'dialog' : ['autoFocusDialog'], + 'selectionInfo' : ['infoItems', 'hashChecker'], + 'reset' : ['clearBrowserData'], + 'all' : true + }, + forms = self.options.prefs || ['language', 'theme', 'toolbarPref', 'iconSize', 'columnPref', 'selectAction', 'makefileTypes', 'useStoredEditor', 'editorMaximized', 'useFullscreen', 'showHidden', 'infoItems', 'hashChecker', 'autoFocusDialog', 'clearBrowserData']; + + if (!fm.cookieEnabled) { + delete cats.language; + } + + forms = fm.arrayFlip(forms, true); + + if (fm.options.getFileCallback) { + delete forms.selectAction; + } + if (!fm.UA.Fullscreen) { + delete forms.useFullscreen; + } + + forms.language && (forms.language = (function() { + var langSel = $('').on('change', function() { + var lang = $(this).val(); + fm.storage('lang', lang); + $('#'+fm.id).elfinder('reload'); + }), + optTags = [], + langs = self.options.langs || { + ar: 'العربية', + bg: 'Български', + ca: 'Català', + cs: 'Čeština', + da: 'Dansk', + de: 'Deutsch', + el: 'Ελληνικά', + en: 'English', + es: 'Español', + fa: 'فارسی', + fo: 'Føroyskt', + fr: 'Français', + fr_CA: 'Français (Canada)', + he: 'עברית', + hr: 'Hrvatski', + hu: 'Magyar', + id: 'Bahasa Indonesia', + it: 'Italiano', + ja: '日本語', + ko: '한국어', + nl: 'Nederlands', + no: 'Norsk', + pl: 'Polski', + pt_BR: 'Português', + ro: 'Română', + ru: 'Pусский', + si: 'සිංහල', + sk: 'Slovenčina', + sl: 'Slovenščina', + sr: 'Srpski', + sv: 'Svenska', + tr: 'Türkçe', + ug_CN: 'ئۇيغۇرچە', + uk: 'Український', + vi: 'Tiếng Việt', + zh_CN: '简体中文', + zh_TW: '正體中文' + }; + if (!fm.cookieEnabled) { + return $(); + } + $.each(langs, function(lang, name) { + optTags.push(''); + }); + return langSel.append(optTags.join('')).val(fm.lang); + })()); + + forms.theme && (forms.theme = (function() { + var cnt = fm.options.themes? Object.keys(fm.options.themes).length : 0; + if (cnt === 0 || (cnt === 1 && fm.options.themes.default)) { + return null; + } + var themeSel = $('').on('change', function() { + var theme = $(this).val(); + fm.changeTheme(theme).storage('theme', theme); + }), + optTags = [], + tpl = { + image: '', + link: '$2', + data: '
              $1
              $2
              ' + }, + items = ['image', 'description', 'author', 'email', 'license'], + render = function(key, data) { + }, + defBtn = $('').text(fm.i18n('default')).on('click', function(e) { + themeSel.val('default').trigger('change'); + }), + list = $('
              ').on('click', 'button', function() { + var val = $(this).data('themeid'); + themeSel.val(val).trigger('change'); + }); + + if (!fm.options.themes.default) { + themeSel.append(''); + } + $.each(fm.options.themes, function(id, val) { + var opt = $(''), + dsc = $('
              '+fm.i18n(id)+'
              '), + tm; + themeSel.append(opt); + list.append(dsc); + tm = setTimeout(function() { + dsc.find('span.elfinder-spinner').replaceWith(fm.i18n(['errRead', id])); + }, 10000); + fm.getTheme(id).always(function() { + tm && clearTimeout(tm); + }).done(function(data) { + var link, val = $(), dl = $('
              '); + link = data.link? tpl.link.replace(/\$1/g, data.link).replace(/\$3/g, fm.i18n('website')) : '$2'; + if (data.name) { + opt.html(fm.i18n(data.name)); + } + dsc.children('legend').html(link.replace(/\$2/g, fm.i18n(data.name) || id)); + $.each(items, function(i, key) { + var t = tpl[key] || tpl.data, + elm; + if (data[key]) { + elm = t.replace(/\$0/g, fm.escape(key)).replace(/\$1/g, fm.i18n(key)).replace(/\$2/g, fm.i18n(data[key])); + if (key === 'image' && data.link) { + elm = $(elm).on('click', function() { + themeSel.val(id).trigger('change'); + }).attr('title', fm.i18n('select')); + } + dl.append(elm); + } + }); + val = val.add(dl); + val = val.add($('
              ').append($('').data('themeid', id).html(fm.i18n('select')))); + dsc.find('span.elfinder-spinner').replaceWith(val); + }).fail(function() { + dsc.find('span.elfinder-spinner').replaceWith(fm.i18n(['errRead', id])); + }); + }); + return $('
              ').append(themeSel.val(fm.theme && fm.theme.id? fm.theme.id : 'default'), defBtn, list); + })()); + + forms.toolbarPref && (forms.toolbarPref = (function() { + var pnls = $.map(fm.options.uiOptions.toolbar, function(v) { + return $.isArray(v)? v : null; + }), + tags = [], + hides = fm.storage('toolbarhides') || {}; + $.each(pnls, function() { + var cmd = this, + name = fm.i18n('cmd'+cmd); + if (name === 'cmd'+cmd) { + name = fm.i18n(cmd); + } + tags.push(''); + }); + return $(tags.join(' ')).on('change', 'input', function() { + var v = $(this).val(), + o = $(this).is(':checked'); + if (!o && !hides[v]) { + hides[v] = true; + } else if (o && hides[v]) { + delete hides[v]; + } + fm.storage('toolbarhides', hides); + fm.trigger('toolbarpref'); + }); + })()); + + forms.iconSize && (forms.iconSize = (function() { + var max = fm.options.uiOptions.cwd.iconsView.sizeMax || 3, + size = fm.storage('iconsize') || fm.options.uiOptions.cwd.iconsView.size || 0, + sld = $('
              ').slider({ + classes: { + 'ui-slider-handle': 'elfinder-tabstop', + }, + value: size, + max: max, + slide: function(e, ui) { + fm.getUI('cwd').trigger('iconpref', {size: ui.value}); + }, + change: function(e, ui) { + fm.storage('iconsize', ui.value); + } + }); + fm.getUI('cwd').on('iconpref', function(e, data) { + sld.slider('option', 'value', data.size); + }); + return sld; + })()); + + forms.columnPref && (forms.columnPref = (function() { + var cols = fm.options.uiOptions.cwd.listView.columns, + tags = [], + hides = fm.storage('columnhides') || {}; + $.each(cols, function() { + var key = this, + name = fm.getColumnName(key); + tags.push(''); + }); + return $(tags.join(' ')).on('change', 'input', function() { + var v = $(this).val(), + o = $(this).is(':checked'); + if (!o && !hides[v]) { + hides[v] = true; + } else if (o && hides[v]) { + delete hides[v]; + } + fm.storage('columnhides', hides); + fm.trigger('columnpref', { repaint: true }); + }); + })()); + + forms.selectAction && (forms.selectAction = (function() { + var actSel = $('').on('change', function() { + var act = $(this).val(); + fm.storage('selectAction', act === 'default'? null : act); + }), + optTags = [], + acts = self.options.selectActions, + defAct = fm.getCommand('open').options.selectAction || 'open'; + + if ($.inArray(defAct, acts) === -1) { + acts.unshift(defAct); + } + $.each(acts, function(i, act) { + var names = $.map(act.split('/'), function(cmd) { + var name = fm.i18n('cmd'+cmd); + if (name === 'cmd'+cmd) { + name = fm.i18n(cmd); + } + return name; + }); + optTags.push(''); + }); + return actSel.append(optTags.join('')).val(fm.storage('selectAction') || defAct); + })()); + + forms.makefileTypes && (forms.makefileTypes = (function() { + var hides = fm.getCommand('edit').getMkfileHides(), + getTag = function() { + var tags = []; + // re-assign hides + hides = fm.getCommand('edit').getMkfileHides(); + $.each(fm.mimesCanMakeEmpty, function(mime, type) { + var name = fm.getCommand('mkfile').getTypeName(mime, type); + tags.push(''); + }); + return tags.join(' '); + }, + elm = $('
              ').on('change', 'input', function() { + var v = $(this).val(), + o = $(this).is(':checked'); + if (!o && !hides[v]) { + hides[v] = true; + } else if (o && hides[v]) { + delete hides[v]; + } + fm.storage('mkfileHides', hides); + fm.trigger('canMakeEmptyFile'); + }).append(getTag()), + add = $('
              ').append( + $('').on('keydown', function(e) { + (e.keyCode === $.ui.keyCode.ENTER) && $(this).next().trigger('click'); + }), + $('').html(fm.i18n('add')).on('click', function() { + var input = $(this).prev(), + val = input.val(), + uiToast = fm.getUI('toast'), + err = function() { + uiToast.appendTo(input.closest('.ui-dialog')); + fm.toast({ + msg: fm.i18n('errUsupportType'), + mode: 'warning', + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + } + }); + input.trigger('focus'); + return false; + }, + tmpMimes; + if (!val.match(/\//)) { + val = fm.arrayFlip(fm.mimeTypes)[val]; + if (!val) { + return err(); + } + input.val(val); + } + if (!fm.mimeIsText(val) || !fm.mimeTypes[val]) { + return err(); + } + fm.trigger('canMakeEmptyFile', {mimes: [val], unshift: true}); + tmpMimes = {}; + tmpMimes[val] = fm.mimeTypes[val]; + fm.storage('mkfileTextMimes', Object.assign(tmpMimes, fm.storage('mkfileTextMimes') || {})); + input.val(''); + uiToast.appendTo(input.closest('.ui-dialog')); + fm.toast({ + msg: fm.i18n(['complete', val + ' (' + tmpMimes[val] + ')']), + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + } + }); + }), + $('').html(fm.i18n('reset')).on('click', function() { + fm.one('canMakeEmptyFile', {done: function() { + elm.empty().append(getTag()); + }}); + fm.trigger('canMakeEmptyFile', {resetTexts: true}); + }) + ), + tm; + fm.bind('canMakeEmptyFile', {done: function(e) { + if (e.data && e.data.mimes && e.data.mimes.length) { + elm.empty().append(getTag()); + } + }}); + return $('
              ').append(elm, add); + })()); + + forms.useStoredEditor && (forms.useStoredEditor = $('').prop('checked', (function() { + var s = fm.storage('useStoredEditor'); + return s? (s > 0) : fm.options.commandsOptions.edit.useStoredEditor; + })()).on('change', function(e) { + fm.storage('useStoredEditor', $(this).is(':checked')? 1 : -1); + })); + + forms.editorMaximized && (forms.editorMaximized = $('').prop('checked', (function() { + var s = fm.storage('editorMaximized'); + return s? (s > 0) : fm.options.commandsOptions.edit.editorMaximized; + })()).on('change', function(e) { + fm.storage('editorMaximized', $(this).is(':checked')? 1 : -1); + })); + + forms.useFullscreen && (forms.useFullscreen = $('').prop('checked', (function() { + var s = fm.storage('useFullscreen'); + return s? (s > 0) : fm.options.commandsOptions.fullscreen.mode === 'screen'; + })()).on('change', function(e) { + fm.storage('useFullscreen', $(this).is(':checked')? 1 : -1); + })); + + if (forms.showHidden) { + (function() { + var setTitle = function() { + var s = fm.storage('hide'), + t = [], + v; + if (s && s.items) { + $.each(s.items, function(h, n) { + t.push(fm.escape(n)); + }); + } + elms.prop('disabled', !t.length)[t.length? 'removeClass' : 'addClass']('ui-state-disabled'); + v = t.length? t.join('\n') : ''; + forms.showHidden.attr('title',v); + useTooltip && forms.showHidden.tooltip('option', 'content', v.replace(/\n/g, '
              ')).tooltip('close'); + }, + chk = $('').prop('checked', (function() { + var s = fm.storage('hide'); + return s && s.show; + })()).on('change', function(e) { + var o = {}; + o[$(this).is(':checked')? 'show' : 'hide'] = true; + fm.exec('hide', void(0), o); + }), + btn = $('').append(fm.i18n('reset')).on('click', function() { + fm.exec('hide', void(0), {reset: true}); + $(this).parent().find('input:first').prop('checked', false); + setTitle(); + }), + elms = $().add(chk).add(btn), + useTooltip; + + forms.showHidden = $('
              ').append(chk, btn); + fm.bind('hide', function(e) { + var d = e.data; + if (!d.opts || (!d.opts.show && !d.opts.hide)) { + setTitle(); + } + }); + if (fm.UA.Mobile && $.fn.tooltip) { + useTooltip = true; + forms.showHidden.tooltip({ + classes: { + 'ui-tooltip': 'elfinder-ui-tooltip ui-widget-shadow' + }, + tooltipClass: 'elfinder-ui-tooltip ui-widget-shadow', + track: true + }).css('user-select', 'none'); + btn.css('user-select', 'none'); + } + setTitle(); + })(); + } + + forms.infoItems && (forms.infoItems = (function() { + var items = fm.getCommand('info').items, + tags = [], + hides = fm.storage('infohides') || fm.arrayFlip(fm.options.commandsOptions.info.hideItems, true); + $.each(items, function() { + var key = this, + name = fm.i18n(key); + tags.push(''); + }); + return $(tags.join(' ')).on('change', 'input', function() { + var v = $(this).val(), + o = $(this).is(':checked'); + if (!o && !hides[v]) { + hides[v] = true; + } else if (o && hides[v]) { + delete hides[v]; + } + fm.storage('infohides', hides); + fm.trigger('infopref', { repaint: true }); + }); + })()); + + forms.hashChecker && fm.hashCheckers.length && (forms.hashChecker = (function() { + var tags = [], + enabled = fm.arrayFlip(fm.storage('hashchekcer') || fm.options.commandsOptions.info.showHashAlgorisms, true); + $.each(fm.hashCheckers, function() { + var cmd = this, + name = fm.i18n(cmd); + tags.push(''); + }); + return $(tags.join(' ')).on('change', 'input', function() { + var v = $(this).val(), + o = $(this).is(':checked'); + if (o) { + enabled[v] = true; + } else if (enabled[v]) { + delete enabled[v]; + } + fm.storage('hashchekcer', $.grep(fm.hashCheckers, function(v) { + return enabled[v]; + })); + }); + })()); + + forms.autoFocusDialog && (forms.autoFocusDialog = $('').prop('checked', (function() { + var s = fm.storage('autoFocusDialog'); + return s? (s > 0) : fm.options.uiOptions.dialog.focusOnMouseOver; + })()).on('change', function(e) { + fm.storage('autoFocusDialog', $(this).is(':checked')? 1 : -1); + })); + + forms.clearBrowserData && (forms.clearBrowserData = $('').text(fm.i18n('reset')).button().on('click', function(e) { + e.preventDefault(); + fm.storage(); + $('#'+fm.id).elfinder('reload'); + })); + + $.each(cats, function(id, prefs) { + var dls, found; + if (prefs === true) { + found = 1; + } else if (prefs) { + dls = $(); + $.each(prefs, function(i, n) { + var f, title, chks = '', cbox; + if (f = forms[n]) { + found = 2; + title = fm.i18n(n); + cbox = $(f).filter('input[type="checkbox"]'); + if (!cbox.length) { + cbox = $(f).find('input[type="checkbox"]'); + } + if (cbox.length === 1) { + if (!cbox.attr('id')) { + cbox.attr('id', 'elfinder-preference-'+n+'-checkbox'); + } + title = ''; + } else if (cbox.length > 1) { + chks = ' elfinder-preference-checkboxes'; + } + dls = dls.add($('
              '+title+'
              ')).add($('
              ').append(f)); + } + }); + } + if (found) { + ul.append(tab[r](/\{id\}/g, id)[r](/\{title\}/, fm.i18n(id))[r](/\{class\}/, openTab === id? 'elfinder-focus' : '')); + if (found === 2) { + tabs.append( + $('
              ') + .hide() + .append($('
              ').append(dls)) + ); + } + } + }); + + ul.on('click', 'a', function(e) { + var t = $(e.target), + h = t.attr('href'); + e.preventDefault(); + e.stopPropagation(); + + ul.children().removeClass(clTabActive); + t.removeClass('ui-state-hover').parent().addClass(clTabActive); + + if (h.match(/all$/)) { + tabs.addClass('elfinder-preference-taball').children().show(); + } else { + tabs.removeClass('elfinder-preference-taball').children().hide(); + $(h).show(); + } + }).on('focus blur', 'a', function(e) { + $(this).parent().toggleClass('ui-state-focus', e.type === 'focusin'); + }).on('mouseenter mouseleave', 'li', function(e) { + $(this).toggleClass('ui-state-hover', e.type === 'mouseenter'); + }); + + tabs.find('a,input,select,button').addClass('elfinder-tabstop'); + base.append(ul, tabs); + + dialog = self.fmDialog(base, { + title : self.title, + width : self.options.width || 600, + height: self.options.height || 400, + maxWidth: 'window', + maxHeight: 'window', + autoOpen : false, + destroyOnClose : false, + allowMinimize : false, + open : function() { + openTab && selectTab(openTab); + openTab = null; + }, + resize : function() { + tabs.height(dialog.height() - ul.outerHeight(true) - (tabs.outerHeight(true) - tabs.height()) - 5); + } + }) + .on('click', function(e) { + e.stopPropagation(); + }) + .css({ + overflow: 'hidden' + }); + + dialog.closest('.ui-dialog') + .css({ + overflow: 'hidden' + }) + .addClass('elfinder-bg-translucent'); + + openTab = 'all'; + }, + dialog, openTab; + + this.shortcuts = [{ + pattern : 'ctrl+comma', + description : this.title + }]; + + this.alwaysEnabled = true; + + this.getstate = function() { + return 0; + }; + + this.exec = function(sel, cOpts) { + !dialog && build(); + if (cOpts) { + if (cOpts.tab) { + selectTab(cOpts.tab); + } else if (cOpts._currentType === 'cwd') { + selectTab('workspace'); + } + } + dialog.elfinderdialog('open'); + return $.Deferred().resolve(); + }; + +}; + +/* + * File: /js/commands/quicklook.js + */ + +/** + * @class elFinder command "quicklook" + * Fast preview for some files types + * + * @author Dmitry (dio) Levashov + **/ +(elFinder.prototype.commands.quicklook = function() { + var self = this, + fm = self.fm, + /** + * window closed state + * + * @type Number + **/ + closed = 0, + /** + * window animated state + * + * @type Number + **/ + animated = 1, + /** + * window opened state + * + * @type Number + **/ + opened = 2, + /** + * window docked state + * + * @type Number + **/ + docked = 3, + /** + * window docked and hidden state + * + * @type Number + **/ + dockedhidden = 4, + /** + * window state + * + * @type Number + **/ + state = closed, + /** + * Event name of update + * for fix conflicts with Prototype.JS + * + * `@see https://github.com/Studio-42/elFinder/pull/2346 + * @type String + **/ + evUpdate = Element.update? 'quicklookupdate' : 'update', + /** + * navbar icon class + * + * @type String + **/ + navicon = 'elfinder-quicklook-navbar-icon', + /** + * navbar "fullscreen" icon class + * + * @type String + **/ + fullscreen = 'elfinder-quicklook-fullscreen', + /** + * info wrapper class + * + * @type String + */ + infocls = 'elfinder-quicklook-info-wrapper', + /** + * Triger keydown/keypress event with left/right arrow key code + * + * @param Number left/right arrow key code + * @return void + **/ + navtrigger = function(code) { + $(document).trigger($.Event('keydown', { keyCode: code, ctrlKey : false, shiftKey : false, altKey : false, metaKey : false })); + }, + /** + * Return css for closed window + * + * @param jQuery file node in cwd + * @return void + **/ + closedCss = function(node) { + var elf = fm.getUI().offset(), + base = (function() { + var target = node.find('.elfinder-cwd-file-wrapper'); + return target.length? target : node; + })(), + baseOffset = base.offset() || { top: 0, left: 0 }; + return { + opacity : 0, + width : base.width(), + height : base.height() - 30, + top : baseOffset.top - elf.top, + left : baseOffset.left - elf.left + }; + }, + /** + * Return css for opened window + * + * @return void + **/ + openedCss = function() { + var contain = self.options.contain || fm.options.dialogContained, + win = contain? fm.getUI() : $(window), + elf = fm.getUI().offset(), + w = Math.min(width, win.width()-10), + h = Math.min(height, win.height()-80); + return { + opacity : 1, + width : w, + height : h, + top : parseInt((win.height() - h - 60) / 2 + (contain? 0 : win.scrollTop() - elf.top)), + left : parseInt((win.width() - w) / 2 + (contain? 0 : win.scrollLeft() - elf.left)) + }; + }, + + mediaNode = {}, + support = function(codec, name) { + var node = name || codec.substr(0, codec.indexOf('/')), + media = mediaNode[node]? mediaNode[node] : (mediaNode[node] = document.createElement(node)), + value = false; + + try { + value = media.canPlayType && media.canPlayType(codec); + } catch(e) {} + + return (value && value !== '' && value != 'no')? true : false; + }, + + platformWin = (window.navigator.platform.indexOf('Win') != -1), + + /** + * Opened window width (from config) + * + * @type Number + **/ + width, + /** + * Opened window height (from config) + * + * @type Number + **/ + height, + /** + * Previous style before docked + * + * @type String + **/ + prevStyle, + /** + * elFinder node + * + * @type jQuery + **/ + parent, + /** + * elFinder current directory node + * + * @type jQuery + **/ + cwd, + /** + * Current directory hash + * + * @type String + **/ + cwdHash, + dockEnabled = false, + navdrag = false, + navmove = false, + navtm = null, + leftKey = $.ui.keyCode.LEFT, + rightKey = $.ui.keyCode.RIGHT, + coverEv = 'mousemove touchstart ' + ('onwheel' in document? 'wheel' : 'onmousewheel' in document? 'mousewheel' : 'DOMMouseScroll'), + title = $(''), + icon = $('
              '), + info = $('
              '),//.hide(), + cover = $('
              '), + fsicon = $('
              ') + .on('click touchstart', function(e) { + if (navmove) { + return; + } + + var win = self.window, + full = win.hasClass(fullscreen), + $window = $(window), + resize = function() { self.preview.trigger('changesize'); }; + + e.stopPropagation(); + e.preventDefault(); + + if (full) { + navStyle = ''; + navShow(); + win.toggleClass(fullscreen) + .css(win.data('position')); + $window.trigger(self.resize).off(self.resize, resize); + navbar.off('mouseenter mouseleave'); + cover.off(coverEv); + } else { + win.toggleClass(fullscreen) + .data('position', { + left : win.css('left'), + top : win.css('top'), + width : win.width(), + height : win.height(), + display: 'block' + }) + .removeAttr('style'); + + $(window).on(self.resize, resize) + .trigger(self.resize); + + cover.on(coverEv, function(e) { + if (! navdrag) { + if (e.type === 'mousemove' || e.type === 'touchstart') { + navShow(); + navtm = setTimeout(function() { + if (fm.UA.Mobile || navbar.parent().find('.elfinder-quicklook-navbar:hover').length < 1) { + navbar.fadeOut('slow', function() { + cover.show(); + }); + } + }, 3000); + } + if (cover.is(':visible')) { + coverHide(); + cover.data('tm', setTimeout(function() { + cover.show(); + }, 3000)); + } + } + }).show().trigger('mousemove'); + + navbar.on('mouseenter mouseleave', function(e) { + if (! navdrag) { + if (e.type === 'mouseenter') { + navShow(); + } else { + cover.trigger('mousemove'); + } + } + }); + } + if (fm.zIndex) { + win.css('z-index', fm.zIndex + 1); + } + if (fm.UA.Mobile) { + navbar.attr('style', navStyle); + } else { + navbar.attr('style', navStyle).draggable(full ? 'destroy' : { + start: function() { + navdrag = true; + navmove = true; + cover.show(); + navShow(); + }, + stop: function() { + navdrag = false; + navStyle = self.navbar.attr('style'); + requestAnimationFrame(function() { + navmove = false; + }); + } + }); + } + $(this).toggleClass(navicon+'-fullscreen-off'); + var collection = win; + if (parent.is('.ui-resizable')) { + collection = collection.add(parent); + } + collection.resizable(full ? 'enable' : 'disable').removeClass('ui-state-disabled'); + + win.trigger('viewchange'); + } + ), + + updateOnSel = function() { + self.update(void(0), (function() { + var fm = self.fm, + files = fm.selectedFiles(), + cnt = files.length, + inDock = self.docked(), + getInfo = function() { + var ts = 0; + $.each(files, function(i, f) { + var t = parseInt(f.ts); + if (ts >= 0) { + if (t > ts) { + ts = t; + } + } else { + ts = 'unknown'; + } + }); + return { + hash : files[0].hash + '/' + (+new Date()), + name : fm.i18n('items') + ': ' + cnt, + mime : 'group', + size : spinner, + ts : ts, + files : $.map(files, function(f) { return f.hash; }), + getSize : true + }; + }; + if (! cnt) { + cnt = 1; + files = [fm.cwd()]; + } + return (cnt === 1)? files[0] : getInfo(); + })()); + }, + + navShow = function() { + if (self.window.hasClass(fullscreen)) { + navtm && clearTimeout(navtm); + navtm = null; + // if use `show()` it make infinite loop with old jQuery (jQuery/jQuery UI: 1.8.0/1.9.0) + // see #1478 https://github.com/Studio-42/elFinder/issues/1478 + navbar.stop(true, true).css('display', 'block'); + coverHide(); + } + }, + + coverHide = function() { + cover.data('tm') && clearTimeout(cover.data('tm')); + cover.removeData('tm'); + cover.hide(); + }, + + prev = $('
              ').on('click touchstart', function(e) { ! navmove && navtrigger(leftKey); return false; }), + next = $('
              ').on('click touchstart', function(e) { ! navmove && navtrigger(rightKey); return false; }), + navbar = $('
              ') + .append(prev) + .append(fsicon) + .append(next) + .append('
              ') + .append($('
              ').on('click touchstart', function(e) { ! navmove && self.window.trigger('close'); return false; })) + , + titleClose = $('').on('mousedown', function(e) { + e.stopPropagation(); + self.window.trigger('close'); + }), + titleDock = $('').on('mousedown', function(e) { + e.stopPropagation(); + if (! self.docked()) { + self.window.trigger('navdockin'); + } else { + self.window.trigger('navdockout'); + } + }), + spinner = '' + fm.i18n('calc') + '' + '', + navStyle = '', + init = true, + dockHeight, getSize, tm4cwd, dockedNode, selectTm; + + /** + * Any flags for each plugin + */ + this.flags = {}; + + this.cover = cover; + this.evUpdate = evUpdate; + (this.navbar = navbar)._show = navShow; + this.resize = 'resize.'+fm.namespace; + this.info = $('
              ').addClass(infocls) + .append(icon) + .append(info); + this.autoPlay = function() { + if (self.opened()) { + return !! self.options[self.docked()? 'dockAutoplay' : 'autoplay']; + } + return false; + }; + this.preview = $('
              ') + // clean info/icon + .on('change', function() { + navShow(); + navbar.attr('style', navStyle); + self.docked() && navbar.hide(); + self.preview.attr('style', '').removeClass('elfinder-overflow-auto'); + self.info.attr('style', '').hide(); + self.cover.removeClass('elfinder-quicklook-coverbg'); + icon.removeAttr('class').attr('style', ''); + info.html(''); + }) + // update info/icon + .on(evUpdate, function(e) { + var preview = self.preview, + file = e.file, + tpl = '
              {value}
              ', + update = function() { + var win = self.window.css('overflow', 'hidden'); + name = fm.escape(file.i18 || file.name); + !file.read && e.stopImmediatePropagation(); + self.window.data('hash', file.hash); + self.preview.off('changesize').trigger('change').children().remove(); + title.html(name); + + prev.css('visibility', ''); + next.css('visibility', ''); + if (file.hash === fm.cwdId2Hash(cwd.find('[id]:not(.elfinder-cwd-parent):first').attr('id'))) { + prev.css('visibility', 'hidden'); + } + if (file.hash === fm.cwdId2Hash(cwd.find('[id]:last').attr('id'))) { + next.css('visibility', 'hidden'); + } + + if (file.mime === 'directory') { + getSizeHashes = [ file.hash ]; + } else if (file.mime === 'group' && file.getSize) { + getSizeHashes = file.files; + } + + info.html( + tpl.replace(/\{value\}/, name) + + tpl.replace(/\{value\}/, fm.mime2kind(file)) + + tpl.replace(/\{value\}/, getSizeHashes.length ? spinner : fm.formatSize(file.size)) + + tpl.replace(/\{value\}/, fm.i18n('modify')+': '+ fm.formatDate(file)) + ); + + if (getSizeHashes.length) { + getSize = fm.getSize(getSizeHashes).done(function(data) { + info.find('span.elfinder-spinner').parent().html(data.formated); + }).fail(function() { + info.find('span.elfinder-spinner').parent().html(fm.i18n('unknown')); + }).always(function() { + getSize = null; + }); + getSize._hash = file.hash; + } + + icon.addClass('elfinder-cwd-icon ui-corner-all '+fm.mime2class(file.mime)); + + if (file.icon) { + icon.css(fm.getIconStyle(file, true)); + } + + self.info.attr('class', infocls); + if (file.csscls) { + self.info.addClass(file.csscls); + } + + if (file.read && (tmb = fm.tmb(file))) { + $('') + .hide() + .appendTo(self.preview) + .on('load', function() { + icon.addClass(tmb.className).css('background-image', "url('"+tmb.url+"')"); + $(this).remove(); + }) + .attr('src', tmb.url); + } + self.info.delay(100).fadeIn(10); + if (self.window.hasClass(fullscreen)) { + cover.trigger('mousemove'); + } + win.css('overflow', ''); + }, + tmb, name, getSizeHashes = []; + + if (file && ! Object.keys(file).length) { + file = fm.cwd(); + } + if (file && getSize && getSize.state() === 'pending' && getSize._hash !== file.hash) { + getSize.reject(); + } + if (file && (e.forceUpdate || self.window.data('hash') !== file.hash)) { + update(); + } else { + e.stopImmediatePropagation(); + } + }); + + this.window = $('
              ') + .hide() + .addClass(fm.UA.Touch? 'elfinder-touch' : '') + .on('click', function(e) { + var win = this; + e.stopPropagation(); + if (state === opened) { + requestAnimationFrame(function() { + state === opened && fm.toFront(win); + }); + } + }) + .append( + $('
              ') + .append( + $('').append( + titleClose, titleDock + ), + title + ), + this.preview, + self.info.hide(), + cover.hide(), + navbar + ) + .draggable({handle : 'div.elfinder-quicklook-titlebar'}) + .on('open', function(e, clcss) { + var win = self.window, + file = self.value, + node = fm.getUI('cwd'), + open = function(status) { + state = status; + self.update(1, self.value); + self.change(); + win.trigger('resize.' + fm.namespace); + }; + + if (!init && state === closed) { + if (file && file.hash !== cwdHash) { + node = fm.cwdHash2Elm(file.hash.split('/', 2)[0]); + } + navStyle = ''; + navbar.attr('style', ''); + state = animated; + node.trigger('scrolltoview'); + coverHide(); + win.css(clcss || closedCss(node)) + .show() + .animate(openedCss(), 550, function() { + open(opened); + navShow(); + }); + fm.toFront(win); + } else if (state === dockedhidden) { + fm.getUI('navdock').data('addNode')(dockedNode); + open(docked); + self.preview.trigger('changesize'); + fm.storage('previewDocked', '1'); + if (fm.getUI('navdock').width() === 0) { + win.trigger('navdockout'); + } + } + }) + .on('close', function(e, dfd) { + var win = self.window, + preview = self.preview.trigger('change'), + file = self.value, + hash = (win.data('hash') || '').split('/', 2)[0], + close = function(status, winhide) { + state = status; + winhide && fm.toHide(win); + preview.children().remove(); + self.update(0, self.value); + win.data('hash', ''); + dfd && dfd.resolve(); + }, + node; + + if (self.opened()) { + getSize && getSize.state() === 'pending' && getSize.reject(); + if (! self.docked()) { + state = animated; + win.hasClass(fullscreen) && fsicon.click(); + (hash && (node = cwd.find('#'+hash)).length) + ? win.animate(closedCss(node), 500, function() { + preview.off('changesize'); + close(closed, true); + }) + : close(closed, true); + } else { + dockedNode = fm.getUI('navdock').data('removeNode')(self.window.attr('id'), 'detach'); + close(dockedhidden); + fm.storage('previewDocked', '2'); + } + } + }) + .on('navdockin', function(e, data) { + var w = self.window, + box = fm.getUI('navdock'), + height = dockHeight || box.width(), + opts = data || {}; + + if (init) { + opts.init = true; + } + state = docked; + prevStyle = w.attr('style'); + w.toggleClass('ui-front').removeClass('ui-widget').draggable('disable').resizable('disable').removeAttr('style').css({ + width: '100%', + height: height, + boxSizing: 'border-box', + paddingBottom: 0, + zIndex: 'unset' + }); + navbar.hide(); + titleDock.toggleClass('ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize'); + + fm.toHide(w, true); + box.data('addNode')(w, opts); + + self.preview.trigger('changesize'); + + fm.storage('previewDocked', '1'); + }) + .on('navdockout', function(e) { + var w = self.window, + box = fm.getUI('navdock'), + dfd = $.Deferred(), + clcss = closedCss(self.preview); + + dockHeight = w.outerHeight(); + box.data('removeNode')(w.attr('id'), fm.getUI()); + w.toggleClass('ui-front').addClass('ui-widget').draggable('enable').resizable('enable').attr('style', prevStyle); + titleDock.toggleClass('ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize'); + + state = closed; + w.trigger('open', clcss); + + fm.storage('previewDocked', '0'); + }) + .on('resize.' + fm.namespace, function() { + self.preview.trigger('changesize'); + }); + + /** + * This command cannot be disable by backend + * + * @type Boolean + **/ + this.alwaysEnabled = true; + + /** + * Selected file + * + * @type Object + **/ + this.value = null; + + this.handlers = { + // save selected file + select : function(e, d) { + selectTm && cancelAnimationFrame(selectTm); + if (! e.data || ! e.data.selected || ! e.data.selected.length) { + selectTm = requestAnimationFrame(function() { + self.opened() && updateOnSel(); + }); + } else { + self.opened() && updateOnSel(); + } + }, + error : function() { self.window.is(':visible') && self.window.trigger('close'); }, + 'searchshow searchhide' : function() { this.opened() && this.window.trigger('close'); }, + navbarshow : function() { + requestAnimationFrame(function() { + self.docked() && self.preview.trigger('changesize'); + }); + }, + destroy : function() { self.window.remove(); } + }; + + this.shortcuts = [{ + pattern : 'space' + }]; + + this.support = { + audio : { + ogg : support('audio/ogg;'), + webm: support('audio/webm;'), + mp3 : support('audio/mpeg;'), + wav : support('audio/wav;'), + m4a : support('audio/mp4;') || support('audio/x-m4a;') || support('audio/aac;'), + flac: support('audio/flac;'), + amr : support('audio/amr;') + }, + video : { + ogg : support('video/ogg;'), + webm : support('video/webm;'), + mp4 : support('video/mp4;'), + mkv : support('video/x-matroska;') || support('video/webm;'), + '3gp': support('video/3gpp;') || support('video/mp4;'), // try as mp4 + m3u8 : support('application/x-mpegURL', 'video') || support('application/vnd.apple.mpegURL', 'video'), + mpd : support('application/dash+xml', 'video') + } + }; + // for GC + mediaNode = {}; + + /** + * Return true if quickLoock window is hiddenReturn true if quickLoock window is visible and not animated + * + * @return Boolean + **/ + this.closed = function() { + return (state == closed || state == dockedhidden); + }; + + /** + * Return true if quickLoock window is visible and not animated + * + * @return Boolean + **/ + this.opened = function() { + return state == opened || state == docked; + }; + + /** + * Return true if quickLoock window is in NavDock + * + * @return Boolean + **/ + this.docked = function() { + return state == docked; + }; + + /** + * Adds an integration into help dialog. + * + * @param Object opts options + */ + this.addIntegration = function(opts) { + requestAnimationFrame(function() { + fm.trigger('helpIntegration', Object.assign({cmd: 'quicklook'}, opts)); + }); + }; + + /** + * Init command. + * Add default plugins and init other plugins + * + * @return Object + **/ + this.init = function() { + var o = this.options, + win = this.window, + preview = this.preview, + i, p, cwdDispInlineRegex; + + width = o.width > 0 ? parseInt(o.width) : 450; + height = o.height > 0 ? parseInt(o.height) : 300; + if (o.dockHeight !== 'auto') { + dockHeight = parseInt(o.dockHeight); + if (! dockHeight) { + dockHeight = void(0); + } + } + + fm.one('load', function() { + + dockEnabled = fm.getUI('navdock').data('dockEnabled'); + + ! dockEnabled && titleDock.hide(); + + parent = fm.getUI(); + cwd = fm.getUI('cwd'); + + if (fm.zIndex) { + win.css('z-index', fm.zIndex + 1); + } + + win.appendTo(parent); + + // close window on escape + $(document).on('keydown.'+fm.namespace, function(e) { + e.keyCode == $.ui.keyCode.ESCAPE && self.opened() && ! self.docked() && win.hasClass('elfinder-frontmost') && win.trigger('close'); + }); + + win.resizable({ + handles : 'se', + minWidth : 350, + minHeight : 120, + resize : function() { + // use another event to avoid recursion in fullscreen mode + // may be there is clever solution, but i cant find it :( + preview.trigger('changesize'); + } + }); + + self.change(function() { + if (self.opened()) { + if (self.value) { + if (self.value.tmb && self.value.tmb == 1) { + // try re-get file object + self.value = Object.assign({}, fm.file(self.value.hash)); + } + preview.trigger($.Event(evUpdate, {file : self.value})); + } + } + }); + + preview.on(evUpdate, function(e) { + var file, hash, serach; + + if (file = e.file) { + hash = file.hash; + serach = (fm.searchStatus.mixed && fm.searchStatus.state > 1); + + if (file.mime !== 'directory') { + if (parseInt(file.size) || file.mime.match(o.mimeRegexNotEmptyCheck)) { + // set current dispInlineRegex + self.dispInlineRegex = cwdDispInlineRegex; + if (serach || fm.optionsByHashes[hash]) { + try { + self.dispInlineRegex = new RegExp(fm.option('dispInlineRegex', hash), 'i'); + } catch(e) { + try { + self.dispInlineRegex = new RegExp(!fm.isRoot(file)? fm.option('dispInlineRegex', file.phash) : fm.options.dispInlineRegex, 'i'); + } catch(e) { + self.dispInlineRegex = /^$/; + } + } + } + } else { + // do not preview of file that size = 0 + e.stopImmediatePropagation(); + } + } else { + self.dispInlineRegex = /^$/; + } + + self.info.show(); + } else { + e.stopImmediatePropagation(); + } + }); + + $.each(fm.commands.quicklook.plugins || [], function(i, plugin) { + if (typeof(plugin) == 'function') { + new plugin(self); + } + }); + }).one('open', function() { + var dock = Number(fm.storage('previewDocked') || o.docked), + win; + if (dockEnabled && dock >= 1) { + win = self.window; + self.exec(); + win.trigger('navdockin', { init : true }); + if (dock === 2) { + win.trigger('close'); + } else { + self.update(void(0), fm.cwd()); + self.change(); + } + } + init = false; + }).bind('open', function() { + cwdHash = fm.cwd().hash; + self.value = fm.cwd(); + // set current volume dispInlineRegex + try { + cwdDispInlineRegex = new RegExp(fm.option('dispInlineRegex'), 'i'); + } catch(e) { + cwdDispInlineRegex = /^$/; + } + }).bind('change', function(e) { + if (e.data && e.data.changed && self.opened()) { + $.each(e.data.changed, function() { + if (self.window.data('hash') === this.hash) { + self.window.data('hash', null); + self.preview.trigger(evUpdate); + return false; + } + }); + } + }).bind('navdockresizestart navdockresizestop', function(e) { + cover[e.type === 'navdockresizestart'? 'show' : 'hide'](); + }); + }; + + this.getstate = function() { + return self.opened()? 1 : 0; + }; + + this.exec = function() { + self.closed() && updateOnSel(); + self.enabled() && self.window.trigger(self.opened() ? 'close' : 'open'); + return $.Deferred().resolve(); + }; + + this.hideinfo = function() { + this.info.stop(true, true).hide(); + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/quicklook.plugins.js + */ + +elFinder.prototype.commands.quicklook.plugins = [ + + /** + * Images preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'], + getDimSize = ql.fm.returnBytes((ql.options.getDimThreshold || 0)), + preview = ql.preview, + WebP, flipMime; + + // webp support + WebP = new Image(); + WebP.onload = WebP.onerror = function() { + if (WebP.height == 2) { + mimes.push('image/webp'); + } + }; + WebP.src='data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA'; + + // what kind of images we can display + $.each(navigator.mimeTypes, function(i, o) { + var mime = o.type; + + if (mime.indexOf('image/') === 0 && $.inArray(mime, mimes)) { + mimes.push(mime); + } + }); + + preview.on(ql.evUpdate, function(e) { + var fm = ql.fm, + file = e.file, + showed = false, + dimreq = null, + setdim = function(dim) { + var rfile = fm.file(file.hash); + rfile.width = dim[0]; + rfile.height = dim[1]; + }, + show = function() { + var elm, varelm, memSize, width, height, prop; + + dimreq && dimreq.state && dimreq.state() === 'pending' && dimreq.reject(); + if (showed) { + return; + } + showed = true; + + elm = img.get(0); + memSize = file.width && file.height? {w: file.width, h: file.height} : (elm.naturalWidth? null : {w: img.width(), h: img.height()}); + + memSize && img.removeAttr('width').removeAttr('height'); + + width = file.width || elm.naturalWidth || elm.width || img.width(); + height = file.height || elm.naturalHeight || elm.height || img.height(); + if (!file.width || !file.height) { + setdim([width, height]); + } + + memSize && img.width(memSize.w).height(memSize.h); + + prop = (width/height).toFixed(2); + preview.on('changesize', function() { + var pw = parseInt(preview.width()), + ph = parseInt(preview.height()), + w, h; + + if (prop < (pw/ph).toFixed(2)) { + h = ph; + w = Math.floor(h * prop); + } else { + w = pw; + h = Math.floor(w/prop); + } + img.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0); + + }) + .trigger('changesize'); + + //show image + img.fadeIn(100); + }, + hideInfo = function() { + loading.remove(); + // hide info/icon + ql.hideinfo(); + }, + url, img, loading, prog, m, opDfd; + + if (!flipMime) { + flipMime = fm.arrayFlip(mimes); + } + if (flipMime[file.mime] && ql.dispInlineRegex.test(file.mime)) { + // this is our file - stop event propagation + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + img = $('') + .hide() + .appendTo(preview) + .on('load', function() { + hideInfo(); + show(); + }) + .on('error', function() { + loading.remove(); + }); + opDfd = fm.openUrl(file.hash, false, function(url) { + img.attr('src', url); + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + + if (file.width && file.height) { + show(); + } else if (file.size > getDimSize) { + dimreq = fm.request({ + data : {cmd : 'dim', target : file.hash}, + preventDefault : true + }) + .done(function(data) { + if (data.dim) { + var dim = data.dim.split('x'); + file.width = dim[0]; + file.height = dim[1]; + setdim(dim); + show(); + } + }); + } + } + + }); + }, + + /** + * TIFF image preview + * + * @param object ql elFinder.commands.quicklook + */ + function(ql) { + var fm = ql.fm, + mime = 'image/tiff', + preview = ql.preview; + if (window.Worker && window.Uint8Array) { + preview.on(ql.evUpdate, function(e) { + var file = e.file, + err = function(e) { + wk && wk.terminate(); + loading.remove(); + fm.debug('error', e); + }, + setdim = function(dim) { + var rfile = fm.file(file.hash); + rfile.width = dim[0]; + rfile.height = dim[1]; + }, + loading, prog, url, base, wk, opDfd; + if (file.mime === mime) { + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + // stop loading on change file if not loaded yet + preview.one('change', function() { + wk && wk.terminate(); + loading.remove(); + }); + + opDfd = fm.getContents(file.hash, 'arraybuffer', { progressBar: prog }).done(function(data) { + if (data) { + base = $('
              ').css({width:'100%',height:'100%'}).hide().appendTo(preview); + try { + wk = fm.getWorker(); + wk.onmessage = function(res) { + var data = res.data, + cv, co, id, prop; + wk && wk.terminate(); + cv = document.createElement('canvas'); + co = cv.getContext('2d'); + cv.width = data.width; + cv.height = data.height; + id = co.createImageData(data.width, data.height); + (id).data.set(new Uint8Array(data.image)); + co.putImageData(id, 0, 0); + base.append(cv).show(); + loading.remove(); + prop = (data.width/data.height).toFixed(2); + preview.on('changesize', function() { + var pw = parseInt(preview.width()), + ph = parseInt(preview.height()), + w, h; + if (prop < (pw/ph).toFixed(2)) { + h = ph; + w = Math.floor(h * prop); + } else { + w = pw; + h = Math.floor(w/prop); + } + $(cv).width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0); + }).trigger('changesize'); + if (!file.width || !file.height) { + setdim([data.width, data.height]); + } + ql.hideinfo(); + }; + wk.onerror = err; + wk.postMessage({ + scripts: [fm.options.cdns.tiff, fm.getWorkerUrl('quicklook.tiff.js')], + data: { data: data } + }); + } catch(e) { + err(e); + } + } else { + err(); + } + }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + }); + } + }, + + /** + * PSD(Adobe Photoshop data) preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = fm.arrayFlip(['image/vnd.adobe.photoshop', 'image/x-photoshop']), + preview = ql.preview, + load = function(url, img, loading) { + try { + fm.replaceXhrSend(); + PSD.fromURL(url).then(function(psd) { + var prop; + img.attr('src', psd.image.toBase64()); + requestAnimationFrame(function() { + prop = (img.width()/img.height()).toFixed(2); + preview.on('changesize', function() { + var pw = parseInt(preview.width()), + ph = parseInt(preview.height()), + w, h; + + if (prop < (pw/ph).toFixed(2)) { + h = ph; + w = Math.floor(h * prop); + } else { + w = pw; + h = Math.floor(w/prop); + } + img.width(w).height(h).css('margin-top', h < ph ? Math.floor((ph - h)/2) : 0); + }).trigger('changesize'); + + loading.remove(); + // hide info/icon + ql.hideinfo(); + //show image + img.fadeIn(100); + }); + }, function() { + loading.remove(); + img.remove(); + }); + fm.restoreXhrSend(); + } catch(e) { + fm.restoreXhrSend(); + loading.remove(); + img.remove(); + } + }, + PSD; + + preview.on(ql.evUpdate, function(e) { + var file = e.file, + url, img, loading, prog, m, + _define, _require, opDfd; + + if (mimes[file.mime] && fm.options.cdns.psd && ! fm.UA.ltIE10 && ql.dispInlineRegex.test(file.mime)) { + // this is our file - stop event propagation + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + opDfd = fm.openUrl(file.hash, 'sameorigin', function(url) { + if (url) { + img = $('').hide().appendTo(preview); + if (PSD) { + load(url, img, loading); + } else { + _define = window.define; + _require = window.require; + window.require = null; + window.define = null; + fm.loadScript( + [ fm.options.cdns.psd ], + function() { + PSD = require('psd'); + _define? (window.define = _define) : (delete window.define); + _require? (window.require = _require) : (delete window.require); + load(url, img, loading); + } + ); + } + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + }); + }, + + /** + * HTML preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = fm.arrayFlip(['text/html', 'application/xhtml+xml']), + preview = ql.preview; + + preview.on(ql.evUpdate, function(e) { + var file = e.file, jqxhr, loading, prog; + + if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) { + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + // stop loading on change file if not loaded yet + preview.one('change', function() { + jqxhr.state() == 'pending' && jqxhr.reject(); + }).addClass('elfinder-overflow-auto'); + + jqxhr = fm.request({ + data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts}, + options : {type: 'get', cache : true}, + preventDefault : true, + progressBar : prog + }) + .done(function(data) { + ql.hideinfo(); + var doc = $('').appendTo(preview)[0].contentWindow.document; + doc.open(); + doc.write(data.content); + doc.close(); + }) + .always(function() { + loading.remove(); + }); + } + }); + }, + + /** + * MarkDown preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = fm.arrayFlip(['text/x-markdown']), + preview = ql.preview, + marked = null, + show = function(data, loading) { + ql.hideinfo(); + var doc = $('').appendTo(preview)[0].contentWindow.document; + doc.open(); + doc.write((marked.parse || marked)(data.content)); + doc.close(); + loading.remove(); + }, + error = function(loading) { + marked = false; + loading.remove(); + }; + + preview.on(ql.evUpdate, function(e) { + var file = e.file, jqxhr, loading, prog; + + if (mimes[file.mime] && fm.options.cdns.marked && marked !== false && ql.dispInlineRegex.test(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax)) { + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + // stop loading on change file if not loaded yet + preview.one('change', function() { + jqxhr.state() == 'pending' && jqxhr.reject(); + }).addClass('elfinder-overflow-auto'); + + jqxhr = fm.request({ + data : {cmd : 'get', target : file.hash, conv : 1, _t : file.ts}, + options : {type: 'get', cache : true}, + preventDefault : true, + progressBar : prog + }) + .done(function(data) { + if (marked || window.marked) { + if (!marked) { + marked = window.marked; + } + show(data, loading); + } else { + fm.loadScript([fm.options.cdns.marked], + function(res) { + marked = res || window.marked || false; + delete window.marked; + if (marked) { + show(data, loading); + } else { + error(loading); + } + }, + { + tryRequire: true, + error: function() { + error(loading); + } + } + ); + } + }) + .fail(function() { + error(loading); + }); + } + }); + }, + + /** + * PDF/ODT/ODS/ODP preview with ViewerJS + * + * @param elFinder.commands.quicklook + */ + function(ql) { + if (ql.options.viewerjs) { + var fm = ql.fm, + preview = ql.preview, + opts = ql.options.viewerjs, + mimes = opts.url? fm.arrayFlip(opts.mimes || []) : [], + win = ql.window, + navi = ql.navbar, + setNavi = function() { + navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '30px' : ''); + }; + + if (opts.url) { + preview.on('update', function(e) { + var file = e.file, node, loading, prog, opDfd; + + if (mimes[file.mime] && (file.mime !== 'application/pdf' || !opts.pdfNative || !ql.flags.pdfNative)) { + e.stopImmediatePropagation(); + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + opDfd = fm.openUrl(file.hash, 'sameorigin', function(url) { + if (url) { + node = $('') + .css('background-color', 'transparent') + .on('load', function() { + ql.hideinfo(); + loading.remove(); + node.css('background-color', '#fff'); + }) + .on('error', function() { + loading.remove(); + node.remove(); + }) + .appendTo(preview) + .attr('src', opts.url + '#' + url); + + win.on('viewchange.viewerjs', setNavi); + setNavi(); + + preview.one('change', function() { + win.off('viewchange.viewerjs'); + loading.remove(); + node.off('load').remove(); + }); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + }); + } + } + }, + + /** + * PDF preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mime = 'application/pdf', + preview = ql.preview, + active = false, + urlhash = '', + firefox, toolbar; + + if ((fm.UA.Safari && fm.OS === 'mac' && !fm.UA.iOS) || fm.UA.IE || fm.UA.Firefox) { + active = true; + } else { + $.each(navigator.plugins, function(i, plugins) { + $.each(plugins, function(i, plugin) { + if (plugin.type === mime) { + return !(active = true); + } + }); + }); + } + + ql.flags.pdfNative = active; + if (active) { + if (typeof ql.options.pdfToolbar !== 'undefined' && !ql.options.pdfToolbar) { + urlhash = '#toolbar=0'; + } + preview.on(ql.evUpdate, function(e) { + var file = e.file, + opDfd; + + if (active && file.mime === mime && ql.dispInlineRegex.test(file.mime)) { + e.stopImmediatePropagation(); + opDfd = fm.openUrl(file.hash, false, function(url) { + if (url) { + ql.hideinfo(); + ql.cover.addClass('elfinder-quicklook-coverbg'); + $('') + .on('error', function(e) { + active = false; + ql.update(void(0), fm.cwd()); + ql.update(void(0), file); + }) + .appendTo(preview); + } + }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + + }); + } + }, + + /** + * Flash preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mime = 'application/x-shockwave-flash', + preview = ql.preview, + active = false; + + $.each(navigator.plugins, function(i, plugins) { + $.each(plugins, function(i, plugin) { + if (plugin.type === mime) { + return !(active = true); + } + }); + }); + + active && preview.on(ql.evUpdate, function(e) { + var file = e.file, + node, opDfd; + + if (file.mime === mime && ql.dispInlineRegex.test(file.mime)) { + e.stopImmediatePropagation(); + opDfd = fm.openUrl(file.hash, false, function(url) { + if (url) { + ql.hideinfo(); + node = $('') + .appendTo(preview); + } + }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + }); + }, + + /** + * HTML5 audio preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + preview = ql.preview, + mimes = { + 'audio/mpeg' : 'mp3', + 'audio/mpeg3' : 'mp3', + 'audio/mp3' : 'mp3', + 'audio/x-mpeg3' : 'mp3', + 'audio/x-mp3' : 'mp3', + 'audio/x-wav' : 'wav', + 'audio/wav' : 'wav', + 'audio/x-m4a' : 'm4a', + 'audio/aac' : 'm4a', + 'audio/mp4' : 'm4a', + 'audio/x-mp4' : 'm4a', + 'audio/ogg' : 'ogg', + 'audio/webm' : 'webm', + 'audio/flac' : 'flac', + 'audio/x-flac' : 'flac', + 'audio/amr' : 'amr' + }, + node, curHash, + win = ql.window, + navi = ql.navbar, + AMR, autoplay, + controlsList = typeof ql.options.mediaControlsList === 'string' && ql.options.mediaControlsList? ' controlsList="' + fm.escape(ql.options.mediaControlsList) + '"' : '', + setNavi = function() { + navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : ''); + }, + getNode = function(src, hash) { + return $('') + .on('change', function(e) { + // Firefox fire change event on seek or volume change + e.stopPropagation(); + }) + .on('error', function(e) { + node && node.data('hash') === hash && reset(); + }) + .data('hash', hash) + .appendTo(preview); + }, + amrToWavUrl = function(hash) { + var dfd = $.Deferred(), + loader = $.Deferred().done(function() { + var opDfd; + opDfd = fm.getContents(hash, 'arraybuffer', { progressBar: prog }).done(function(data) { + try { + var buffer = AMR.toWAV(new Uint8Array(data)); + if (buffer) { + dfd.resolve(URL.createObjectURL(new Blob([buffer], { type: 'audio/x-wav' }))); + } else { + dfd.reject(); + } + } catch(e) { + dfd.reject(); + } + }).fail(function() { + dfd.reject(); + }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + }).fail(function() { + AMR = false; + dfd.reject(); + }), + _AMR; + if (window.TextEncoder && window.URL && URL.createObjectURL && typeof AMR === 'undefined') { + // previous window.AMR + _AMR = window.AMR; + delete window.AMR; + fm.loadScript( + [ fm.options.cdns.amr ], + function() { + AMR = window.AMR? window.AMR : false; + // restore previous window.AMR + window.AMR = _AMR; + loader[AMR? 'resolve':'reject'](); + }, + { + error: function() { + loader.reject(); + } + } + ); + } else { + loader[AMR? 'resolve':'reject'](); + } + return dfd; + }, + play = function(player) { + var hash = node.data('hash'), + playPromise; + autoplay && (playPromise = player.play()); + // uses "playPromise['catch']" instead "playPromise.catch" to support Old IE + if (playPromise && playPromise['catch']) { + playPromise['catch'](function(e) { + if (!player.paused) { + node && node.data('hash') === hash && reset(); + } + }); + } + }, + reset = function() { + if (node && node.parent().length) { + var elm = node[0], + url = node.children('source').attr('src'); + win.off('viewchange.audio'); + try { + elm.pause(); + node.empty(); + if (url.match(/^blob:/)) { + URL.revokeObjectURL(url); + } + elm.src = ''; + elm.load(); + } catch(e) {} + node.remove(); + node = null; + } + }, + loading, prog; + + preview.on(ql.evUpdate, function(e) { + var file = e.file, + type = mimes[file.mime], + html5, opDfd; + + if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime) && ((html5 = ql.support.audio[type]) || (type === 'amr'))) { + autoplay = ql.autoPlay(); + curHash = file.hash; + if (!html5) { + if (fm.options.cdns.amr && type === 'amr' && AMR !== false) { + e.stopImmediatePropagation(); + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + node = getNode('', curHash); + amrToWavUrl(file.hash).done(function(url) { + loading.remove(); + if (curHash === file.hash) { + var elm = node[0]; + try { + node.children('source').attr('src', url); + elm.pause(); + elm.load(); + play(elm); + win.on('viewchange.audio', setNavi); + setNavi(); + } catch(e) { + URL.revokeObjectURL(url); + node.remove(); + } + } else { + URL.revokeObjectURL(url); + } + }).fail(function() { + node.remove(); + }); + } + } else { + e.stopImmediatePropagation(); + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + opDfd = fm.openUrl(curHash, false, function(url) { + loading.remove(); + if (url) { + node = getNode(url, curHash); + play(node[0]); + win.on('viewchange.audio', setNavi); + setNavi(); + } else { + node.remove(); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + } + }).one('change', reset); + }, + + /** + * HTML5 video preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + preview = ql.preview, + mimes = { + 'video/mp4' : 'mp4', + 'video/x-m4v' : 'mp4', + 'video/quicktime' : 'mp4', + 'video/mpeg' : 'mpeg', + 'video/ogg' : 'ogg', + 'application/ogg' : 'ogg', + 'video/webm' : 'webm', + 'video/x-matroska': 'mkv', + 'video/3gpp' : '3gp', + 'application/vnd.apple.mpegurl' : 'm3u8', + 'application/x-mpegurl' : 'm3u8', + 'application/dash+xml' : 'mpd', + 'video/x-flv' : 'flv', + 'video/x-msvideo' : 'avi' + }, + node, + win = ql.window, + navi = ql.navbar, + cHls, cDash, pDash, cFlv, cVideojs, autoplay, tm, loading, prog, + controlsList = typeof ql.options.mediaControlsList === 'string' && ql.options.mediaControlsList? ' controlsList="' + fm.escape(ql.options.mediaControlsList) + '"' : '', + setNavi = function() { + if (fm.UA.iOS) { + if (win.hasClass('elfinder-quicklook-fullscreen')) { + preview.css('height', '-webkit-calc(100% - 50px)'); + navi._show(); + } else { + preview.css('height', ''); + } + } else { + navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : ''); + } + }, + render = function(file, opts) { + var errTm = function(e) { + if (err > 1) { + tm && clearTimeout(tm); + tm = setTimeout(function() { + !canPlay && reset(true); + }, 800); + } + }, + err = 0, + cssClass = '', + canPlay; + //reset(); + pDash = null; + opts = opts || {}; + if (opts.cssClass) { + cssClass = ' ' + opts.cssClass; + } + ql.hideinfo(); + node = $('') + .on('change', function(e) { + // Firefox fire change event on seek or volume change + e.stopPropagation(); + }) + .on('timeupdate progress', errTm) + .on('canplay', function() { + canPlay = true; + }) + .data('hash', file.hash); + // can not handling error event with jQuery `on` event handler + node[0].addEventListener('error', function(e) { + if (opts.src && fm.convAbsUrl(opts.src) === fm.convAbsUrl(e.target.src)) { + ++err; + errTm(); + } + }, true); + + if (opts.src) { + node.append(''); + } + + node.appendTo(preview); + + win.on('viewchange.video', setNavi); + setNavi(); + }, + loadHls = function(file) { + var hls, opDfd; + opDfd = fm.openUrl(file.hash, false, function(url) { + loading.remove(); + if (url) { + render(file); + hls = new cHls(); + hls.loadSource(url); + hls.attachMedia(node[0]); + if (autoplay) { + hls.on(cHls.Events.MANIFEST_PARSED, function() { + play(node[0]); + }); + } + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + }, + loadDash = function(file) { + var opDfd; + opDfd = fm.openUrl(file.hash, false, function(url) { + var debug; + loading.remove(); + if (url) { + render(file); + pDash = window.dashjs.MediaPlayer().create(); + debug = pDash.getDebug(); + if (debug.setLogLevel) { + debug.setLogLevel(dashjs.Debug.LOG_LEVEL_FATAL); + } else if (debug.setLogToBrowserConsole) { + debug.setLogToBrowserConsole(false); + } + pDash.initialize(node[0], url, autoplay); + pDash.on('error', function(e) { + reset(true); + }); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + }, + loadFlv = function(file) { + var opDfd + if (!cFlv.isSupported()) { + cFlv = false; + return; + } + opDfd = fm.openUrl(file.hash, false, function(url) { + loading.remove(); + if (url) { + var player = cFlv.createPlayer({ + type: 'flv', + url: url + }); + render(file); + player.on(cFlv.Events.ERROR, function() { + player.destroy(); + reset(true); + }); + player.attachMediaElement(node[0]); + player.load(); + play(player); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + }, + loadVideojs = function(file) { + var opDfd; + opDfd = fm.openUrl(file.hash, false, function(url) { + loading.remove(); + if (url) { + render(file, { + src: url, + cssClass: 'video-js' + }); + node[0].src = url; + cVideojs(node[0], { + autoplay: true + }); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + }, + play = function(player) { + var hash = node.data('hash'), + playPromise; + autoplay && (playPromise = player.play()); + // uses "playPromise['catch']" instead "playPromise.catch" to support Old IE + if (playPromise && playPromise['catch']) { + playPromise['catch'](function(e) { + if (!player.paused) { + node && node.data('hash') === hash && reset(true); + } + }); + } + }, + reset = function(showInfo) { + tm && clearTimeout(tm); + if (node && node.parent().length) { + var elm = node[0]; + win.off('viewchange.video'); + pDash && pDash.reset(); + try { + elm.pause(); + node.empty(); + elm.src = ''; + elm.load(); + } catch(e) {} + node.remove(); + node = null; + } + showInfo && ql.info.show(); + }; + + preview.on(ql.evUpdate, function(e) { + var file = e.file, + mime = file.mime.toLowerCase(), + type = mimes[mime], + stock, playPromise, opDfd; + + if (mimes[mime] && ql.dispInlineRegex.test(file.mime) /*&& (((type === 'm3u8' || (type === 'mpd' && !fm.UA.iOS) || type === 'flv') && !fm.UA.ltIE10) || ql.support.video[type])*/) { + autoplay = ql.autoPlay(); + loading = $('
              '+fm.i18n('nowLoading')+'
              '); + prog = $('
              ').appendTo(loading); + if (ql.support.video[type] && (type !== 'm3u8' || fm.UA.Safari)) { + e.stopImmediatePropagation(); + loading.appendTo(ql.info.find('.elfinder-quicklook-info')); + opDfd = fm.openUrl(file.hash, false, function(url) { + loading.remove(); + if (url) { + render(file, { src: url }); + play(node[0]); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } else { + if (cHls !== false && fm.options.cdns.hls && type === 'm3u8') { + e.stopImmediatePropagation(); + loading.appendTo(ql.info.find('.elfinder-quicklook-info')); + if (cHls) { + loadHls(file); + } else { + stock = window.Hls; + delete window.Hls; + fm.loadScript( + [ fm.options.cdns.hls ], + function(res) { + cHls = res || window.Hls || false; + window.Hls = stock; + cHls && loadHls(file); + }, + { + tryRequire: true, + error : function() { + cHls = false; + } + } + ); + } + } else if (cDash !== false && fm.options.cdns.dash && type === 'mpd') { + e.stopImmediatePropagation(); + loading.appendTo(ql.info.find('.elfinder-quicklook-info')); + if (cDash) { + loadDash(file); + } else { + fm.loadScript( + [ fm.options.cdns.dash ], + function() { + // dashjs require window.dashjs in global scope + cDash = window.dashjs? true : false; + cDash && loadDash(file); + }, + { + tryRequire: true, + error : function() { + cDash = false; + } + } + ); + } + } else if (cFlv !== false && fm.options.cdns.flv && type === 'flv') { + e.stopImmediatePropagation(); + loading.appendTo(ql.info.find('.elfinder-quicklook-info')); + if (cFlv) { + loadFlv(file); + } else { + stock = window.flvjs; + delete window.flvjs; + fm.loadScript( + [ fm.options.cdns.flv ], + function(res) { + cFlv = res || window.flvjs || false; + window.flvjs = stock; + cFlv && loadFlv(file); + }, + { + tryRequire: true, + error : function() { + cFlv = false; + } + } + ); + } + } else if (fm.options.cdns.videojs) { + e.stopImmediatePropagation(); + loading.appendTo(ql.info.find('.elfinder-quicklook-info')); + if (cVideojs) { + loadVideojs(file); + } else { + fm.loadScript( + [ fm.options.cdns.videojs + '/video.min.js' ], + function(res) { + cVideojs = res || window.videojs || false; + //window.flvjs = stock; + cVideojs && loadVideojs(file); + }, + { + tryRequire: true, + error : function() { + cVideojs = false; + } + } + ).loadCss([fm.options.cdns.videojs + '/video-js.min.css']); + } + } + } + } + }).one('change', reset); + }, + + /** + * Audio/video preview plugin using browser plugins + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var preview = ql.preview, + mimes = [], + node, + win = ql.window, + navi = ql.navbar; + + $.each(navigator.plugins, function(i, plugins) { + $.each(plugins, function(i, plugin) { + (plugin.type.indexOf('audio/') === 0 || plugin.type.indexOf('video/') === 0) && mimes.push(plugin.type); + }); + }); + mimes = ql.fm.arrayFlip(mimes); + + preview.on(ql.evUpdate, function(e) { + var file = e.file, + mime = file.mime, + video, opDfd, loading, prog, + setNavi = function() { + navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? '50px' : ''); + }; + + if (mimes[file.mime] && ql.dispInlineRegex.test(file.mime)) { + e.stopImmediatePropagation(); + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + opDfd = ql.fm.openUrl(file.hash, false, function(url) { + loading.remove(); + if (url) { + (video = mime.indexOf('video/') === 0) && ql.hideinfo(); + node = $('') + .appendTo(preview); + + win.on('viewchange.embed', setNavi); + setNavi(); + } + }, { progressBar: prog }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + }).one('change', function() { + if (node && node.parent().length) { + win.off('viewchange.embed'); + node.remove(); + node= null; + } + }); + + }, + + /** + * Archive(zip|gzip|tar|bz2) preview plugin using https://github.com/imaya/zlib.js + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = fm.arrayFlip(['application/zip', 'application/x-gzip', 'application/x-tar', 'application/x-bzip2']), + preview = ql.preview, + sizeMax = fm.returnBytes(ql.options.unzipMaxSize || 0), + Zlib = (fm.options.cdns.zlibUnzip && fm.options.cdns.zlibGunzip)? true : false, + bzip2 = fm.options.cdns.bzip2? true : false; + + if (window.Worker && window.Uint8Array && window.DataView) { + preview.on(ql.evUpdate, function(e) { + var file = e.file, + isTar = (file.mime === 'application/x-tar'), + isBzip2 = (file.mime === 'application/x-bzip2'), + isZlib = (file.mime === 'application/zip' || file.mime === 'application/x-gzip'); + if (mimes[file.mime] && (!sizeMax || file.size <= sizeMax) && ( + isTar + || (isBzip2 && bzip2) + || (isZlib && Zlib) + )) { + var jqxhr, wk, loading, prog, url, + req = function() { + jqxhr = fm.getContents(file.hash, 'arraybuffer', { progressBar: prog }) + .fail(function() { + loading.remove(); + }) + .done(function(data) { + var unzip, filenames, + err = function(e) { + wk && wk.terminate(); + loading.remove(); + if (isZlib) { + Zlib = false; + } else if (isBzip2) { + bzip2 = false; + } + fm.debug('error', e); + }; + try { + wk = fm.getWorker(); + wk.onmessage = function(res) { + wk && wk.terminate(); + loading.remove(); + if (!res.data || res.data.error) { + new Error(res.data && res.data.error? res.data.error : ''); + } else { + makeList(res.data.files); + } + }; + wk.onerror = err; + if (file.mime === 'application/x-tar') { + wk.postMessage({ + scripts: [fm.getWorkerUrl('quicklook.unzip.js')], + data: { type: 'tar', bin: data } + }); + } else if (file.mime === 'application/zip') { + wk.postMessage({ + scripts: [fm.options.cdns.zlibUnzip, fm.getWorkerUrl('quicklook.unzip.js')], + data: { type: 'zip', bin: data } + }); + } else if (file.mime === 'application/x-gzip') { + wk.postMessage({ + scripts: [fm.options.cdns.zlibGunzip, fm.getWorkerUrl('quicklook.unzip.js')], + data: { type: 'gzip', bin: data } + }); + + } else if (file.mime === 'application/x-bzip2') { + wk.postMessage({ + scripts: [fm.options.cdns.bzip2, fm.getWorkerUrl('quicklook.unzip.js')], + data: { type: 'bzip2', bin: data } + }); + } + } catch (e) { + err(e); + } + }); + }, + makeList = function(filenames) { + var header, list, doc, tsize = 0; + if (filenames && filenames.length) { + filenames = $.map(filenames, function(str) { + return fm.decodeRawString(str); + }); + filenames.sort(); + list = fm.escape(filenames.join("\n").replace(/\{formatSize\((\d+)\)\}/g, function(m, s) { + tsize += parseInt(s); + return fm.formatSize(s); + })); + header = ''+fm.escape(file.mime)+' ('+fm.formatSize(file.size)+' / '+fm.formatSize(tsize)+')'+'
              '; + doc = $('
              '+header+'
              '+list+'
              ') + .on('touchstart', function(e) { + if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) { + e.originalEvent._preventSwipeX = true; + } + }) + .appendTo(preview); + ql.hideinfo(); + } + loading.remove(); + }; + + // this is our file - stop event propagation + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + // stop loading on change file if not loaded yet + preview.one('change', function() { + jqxhr.state() === 'pending' && jqxhr.reject(); + wk && wk.terminate(); + loading.remove(); + }); + + req(); + } + }); + } + }, + + /** + * RAR Archive preview plugin using https://github.com/43081j/rar.js + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = fm.arrayFlip(['application/x-rar']), + preview = ql.preview, + RAR; + + if (window.DataView) { + preview.on(ql.evUpdate, function(e) { + var file = e.file; + if (mimes[file.mime] && fm.options.cdns.rar && RAR !== false) { + var loading, prog, url, archive, abort, + getList = function(url) { + if (abort) { + loading.remove(); + return; + } + try { + archive = RAR({ + file: url, + type: 2, + xhrHeaders: fm.customHeaders, + xhrFields: fm.xhrFields + }, function(err) { + loading.remove(); + var filenames = [], + header, doc; + if (abort || err) { + // An error occurred (not a rar, read error, etc) + err && fm.debug('error', err); + return; + } + $.each(archive.entries, function() { + filenames.push(this.path + (this.size? ' (' + fm.formatSize(this.size) + ')' : '')); + }); + if (filenames.length) { + filenames = $.map(filenames, function(str) { + return fm.decodeRawString(str); + }); + filenames.sort(); + header = ''+fm.escape(file.mime)+' ('+fm.formatSize(file.size)+')'+'
              '; + doc = $('
              '+header+'
              '+fm.escape(filenames.join("\n"))+'
              ') + .on('touchstart', function(e) { + if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) { + e.originalEvent._preventSwipeX = true; + } + }) + .appendTo(preview); + ql.hideinfo(); + } + }); + } catch(e) { + loading.remove(); + } + }, + error = function() { + RAR = false; + loading.remove(); + }, + _RAR, opDfd; + + // this is our file - stop event propagation + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + // stop loading on change file if not loaded yet + preview.one('change', function() { + archive && (archive.abort = true); + loading.remove(); + abort = true; + }); + + opDfd = fm.openUrl(file.hash, 'sameorigin', function(url) { + if (url) { + if (RAR) { + getList(url); + } else { + if (window.RarArchive) { + _RAR = window.RarArchive; + delete window.RarArchive; + } + fm.loadScript( + [ fm.options.cdns.rar ], + function() { + if (fm.hasRequire) { + require(['rar'], function(RarArchive) { + RAR = RarArchive; + getList(url); + }, error); + } else { + if (RAR = window.RarArchive) { + if (_RAR) { + window.RarArchive = _RAR; + } else { + delete window.RarArchive; + } + getList(url); + } else { + error(); + } + } + }, + { + tryRequire: true, + error : error + } + ); + } + } + }, { progressBar: prog, temporary: true }); + // stop loading on change file if not loaded yet + preview.one('change', function() { + opDfd && opDfd.state && opDfd.state() === 'pending' && opDfd.reject(); + }); + } + }); + } + }, + + /** + * CAD-Files and 3D-Models online viewer on sharecad.org + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = fm.arrayFlip(ql.options.sharecadMimes || []), + preview = ql.preview, + win = ql.window, + node; + + if (ql.options.sharecadMimes.length) { + ql.addIntegration({ + title: 'ShareCAD.org CAD and 3D-Models viewer', + link: 'https://sharecad.org/DWGOnlinePlugin' + }); + } + + preview.on(ql.evUpdate, function(e) { + var file = e.file; + if (mimes[file.mime.toLowerCase()] && fm.option('onetimeUrl', file.hash)) { + var win = ql.window, + loading, prog, url; + + e.stopImmediatePropagation(); + if (file.url == '1') { + preview.hide(); + $('
              ').appendTo(ql.info.find('.elfinder-quicklook-info')) + .on('click', function() { + var self = $(this); + self.html(''); + fm.request({ + data : {cmd : 'url', target : file.hash}, + preventDefault : true, + progressBar : prog + }) + .always(function() { + self.html(''); + }) + .done(function(data) { + var rfile = fm.file(file.hash); + file.url = rfile.url = data.url || ''; + if (file.url) { + preview.trigger({ + type: ql.evUpdate, + file: file, + forceUpdate: true + }); + } + }); + }); + } + if (file.url !== '' && file.url != '1') { + preview.one('change', function() { + loading.remove(); + node.off('load').remove(); + node = null; + }).addClass('elfinder-overflow-auto'); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + url = fm.convAbsUrl(fm.url(file.hash)); + node = $('') + .css('background-color', 'transparent') + .appendTo(preview) + .on('load', function() { + ql.hideinfo(); + loading.remove(); + ql.preview.after(ql.info); + $(this).css('background-color', '#fff').show(); + }) + .on('error', function() { + loading.remove(); + ql.preview.after(ql.info); + }) + .attr('src', '//sharecad.org/cadframe/load?url=' + encodeURIComponent(url)); + + ql.info.after(ql.preview); + } + } + + }); + }, + + /** + * KML preview with GoogleMaps API + * + * @param elFinder.commands.quicklook + */ + function(ql) { + var fm = ql.fm, + mimes = { + 'application/vnd.google-earth.kml+xml' : true, + 'application/vnd.google-earth.kmz' : true + }, + preview = ql.preview, + gMaps, loadMap, wGmfail, fail, mapScr; + + if (ql.options.googleMapsApiKey) { + ql.addIntegration({ + title: 'Google Maps', + link: 'https://www.google.com/intl/' + fm.lang.replace('_', '-') + '/help/terms_maps.html' + }); + gMaps = (window.google && google.maps); + // start load maps + loadMap = function(file, node, prog) { + var mapsOpts = ql.options.googleMapsOpts.maps; + fm.forExternalUrl(file.hash, { progressBar: prog }).done(function(url) { + if (url) { + try { + new gMaps.KmlLayer(url, Object.assign({ + map: new gMaps.Map(node.get(0), mapsOpts) + }, ql.options.googleMapsOpts.kml)); + ql.hideinfo(); + } catch(e) { + fail(); + } + } else { + fail(); + } + }); + }; + // keep stored error handler if exists + wGmfail = window.gm_authFailure; + // on error function + fail = function() { + mapScr = null; + }; + // API script url + mapScr = 'https://maps.googleapis.com/maps/api/js?key=' + ql.options.googleMapsApiKey; + // error handler + window.gm_authFailure = function() { + fail(); + wGmfail && wGmfail(); + }; + + preview.on(ql.evUpdate, function(e) { + var file = e.file; + if (mapScr && mimes[file.mime.toLowerCase()]) { + var win = ql.window, + getLink = (file.url == '1' && !fm.option('onetimeUrl', file.hash)), + loading, prog, url, node; + + e.stopImmediatePropagation(); + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + if (getLink) { + preview.hide(); + $('
              ').appendTo(ql.info.find('.elfinder-quicklook-info')) + .on('click', function() { + var self = $(this); + self.html(''); + fm.request({ + data : {cmd : 'url', target : file.hash}, + preventDefault : true, + progressBar : prog + }) + .always(function() { + loading.remove(); + self.html(''); + }) + .done(function(data) { + var rfile = fm.file(file.hash); + file.url = rfile.url = data.url || ''; + if (file.url) { + preview.trigger({ + type: ql.evUpdate, + file: file, + forceUpdate: true + }); + } + }); + }); + } + if (file.url !== '' && !getLink) { + node = $('
              ').appendTo(preview); + preview.one('change', function() { + node.remove(); + node = null; + }); + if (!gMaps) { + fm.loadScript([mapScr], function() { + gMaps = window.google && google.maps; + gMaps && loadMap(file, node, prog); + }); + } else { + loadMap(file, node, prog); + } + } + } + }); + } + }, + + /** + * Any supported files preview plugin using (Google docs | MS Office) online viewer + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + var fm = ql.fm, + mimes = Object.assign(fm.arrayFlip(ql.options.googleDocsMimes || [], 'g'), fm.arrayFlip(ql.options.officeOnlineMimes || [], 'm')), + preview = ql.preview, + win = ql.window, + navi = ql.navbar, + urls = { + g: 'docs.google.com/gview?embedded=true&url=', + m: 'view.officeapps.live.com/op/embed.aspx?wdStartOn=0&src=' + }, + navBottom = { + g: '56px', + m: '24px' + }, + mLimits = { + xls : 5242880, // 5MB + xlsb : 5242880, + xlsx : 5242880, + xlsm : 5242880, + other: 10485760 // 10MB + }, + node, enable; + + if (ql.options.googleDocsMimes.length) { + enable = true; + ql.addIntegration({ + title: 'Google Docs Viewer', + link: 'https://docs.google.com/' + }); + } + if (ql.options.officeOnlineMimes.length) { + enable = true; + ql.addIntegration({ + title: 'MS Online Doc Viewer', + link: 'https://products.office.com/office-online/view-office-documents-online' + }); + } + + if (enable) { + preview.on(ql.evUpdate, function(e) { + var file = e.file, + type, dfd; + // 25MB is maximum filesize of Google Docs prevew + if (file.size <= 26214400 && (type = mimes[file.mime])) { + var win = ql.window, + setNavi = function() { + navi.css('bottom', win.hasClass('elfinder-quicklook-fullscreen')? navBottom[type] : ''); + }, + ext = fm.mimeTypes[file.mime], + getLink = (file.url == '1' && !fm.option('onetimeUrl', file.hash)), + loading, prog, url, tm; + + if (type === 'm') { + if ((mLimits[ext] && file.size > mLimits[ext]) || file.size > mLimits.other) { + type = 'g'; + } + } + if (getLink) { + preview.hide(); + $('
              ').appendTo(ql.info.find('.elfinder-quicklook-info')) + .on('click', function() { + var self = $(this); + self.html(''); + fm.request({ + data : {cmd : 'url', target : file.hash}, + preventDefault : true + }) + .always(function() { + self.html(''); + }) + .done(function(data) { + var rfile = fm.file(file.hash); + file.url = rfile.url = data.url || ''; + if (file.url) { + preview.trigger({ + type: ql.evUpdate, + file: file, + forceUpdate: true + }); + } + }); + }); + } + if (file.url !== '' && !getLink) { + e.stopImmediatePropagation(); + preview.one('change', function() { + dfd && dfd.status && dfd.status() === 'pending' && dfd.reject(); + win.off('viewchange.googledocs'); + loading.remove(); + node.off('load').remove(); + node = null; + }).addClass('elfinder-overflow-auto'); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + node = $('') + .css('background-color', 'transparent') + .appendTo(preview); + + dfd = fm.forExternalUrl(file.hash, { progressBar: prog }).done(function(url) { + var load = function() { + try { + if (node && (!node.attr('src') || node.get(0).contentWindow.document/*maybe HTTP 204*/)) { + node.attr('src', 'https://' + urls[type] + encodeURIComponent(url)); + // Retry because Google Docs viewer sometimes returns HTTP 204 + tm = setTimeout(load, 2000); + } + } catch(e) {} + }; + if (url) { + if (file.ts) { + url += (url.match(/\?/)? '&' : '?') + '_t=' + file.ts; + } + node.on('load', function() { + tm && clearTimeout(tm); + ql.hideinfo(); + loading.remove(); + ql.preview.after(ql.info); + $(this).css('background-color', '#fff').show(); + }) + .on('error', function() { + tm && clearTimeout(tm); + loading.remove(); + ql.preview.after(ql.info); + }); + load(); + } else { + loading.remove(); + node.remove(); + } + }); + + win.on('viewchange.googledocs', setNavi); + setNavi(); + ql.info.after(ql.preview); + } + } + + }); + } + }, + + /** + * Texts preview plugin + * + * @param elFinder.commands.quicklook + **/ + function(ql) { + "use strict"; + var fm = ql.fm, + preview = ql.preview, + textLines = parseInt(ql.options.textInitialLines) || 150, + prettifyLines = parseInt(ql.options.prettifyMaxLines) || 500, + PR, _PR, + error = function() { + prettify = function() { return false; }; + _PR && (window.PR = _PR); + PR = false; + }, + prettify = function(node) { + if (fm.options.cdns.prettify) { + prettify = function(node) { + setTimeout(function() { + PRcheck(node); + }, 100); + return 'pending'; + }; + if (window.PR) { + _PR = window.PR; + } + fm.loadScript([fm.options.cdns.prettify + (fm.options.cdns.prettify.match(/\?/)? '&' : '?') + 'autorun=false'], function(wPR) { + PR = wPR || window.PR; + if (typeof PR === 'object') { + prettify = function() { return true; }; + if (_PR) { + window.PR = _PR; + } else { + delete window.PR; + } + exec(node); + } else { + error(); + } + }, { + tryRequire: true, + error : error + }); + } else { + error(); + } + }, + exec = function(node) { + if (node && !node.hasClass('prettyprinted')) { + node.css('cursor', 'wait'); + requestAnimationFrame(function() { + PR.prettyPrint && PR.prettyPrint(null, node.get(0)); + node.css('cursor', ''); + }); + } + }, + PRcheck = function(node) { + var status = prettify(node); + if (status === true) { + exec(node); + } + }; + + preview.on(ql.evUpdate, function(e) { + var file = e.file, + mime = file.mime, + jqxhr, loading, prog, encSelect; + + if (fm.mimeIsText(file.mime) && (!ql.options.getSizeMax || file.size <= ql.options.getSizeMax) && PR !== false) { + e.stopImmediatePropagation(); + + loading = $('
              '+fm.i18n('nowLoading')+'
              ').appendTo(ql.info.find('.elfinder-quicklook-info')); + prog = $('
              ').appendTo(loading); + + // stop loading on change file if not loadin yet + preview.one('change', function() { + jqxhr.state() == 'pending' && jqxhr.reject(); + encSelect && encSelect.remove(); + }); + + jqxhr = fm.request({ + data : {cmd : 'get', target : file.hash, conv : (file.encoding || 1), _t : file.ts}, + options : {type: 'get', cache : true}, + preventDefault : true, + progressBar : prog + }) + .done(function(data) { + var reg = new RegExp('^(data:'+file.mime.replace(/([.+])/g, '\\$1')+';base64,)', 'i'), + text = data.content, + part, more, node, lines, m; + if (typeof text !== 'string') { + return; + } + ql.hideinfo(); + if (window.atob && (m = text.match(reg))) { + text = atob(text.substr(m[1].length)); + } + + lines = text.match(/([^\r\n]{1,100}[\r\n]*)/g); + more = lines.length - textLines; + if (more > 10) { + part = lines.splice(0, textLines).join(''); + } else { + more = 0; + } + + node = $('
              '); + + if (more) { + node.append($('

              ' + fm.i18n('linesLeft', fm.toLocaleString(more)) + '
              ') + .on('click', function() { + var top = node.scrollTop(); + $(this).remove(); + node.children('pre').removeClass('prettyprinted').text(text).scrollTop(top); + if (lines.length <= prettifyLines) { + PRcheck(node); + } + }) + ); + } + node.children('pre').text(part || text); + + node.on('touchstart', function(e) { + if ($(this)['scroll' + (fm.direction === 'ltr'? 'Right' : 'Left')]() > 5) { + e.originalEvent._preventSwipeX = true; + } + }).appendTo(preview); + + // make toast message + if (data.toasts && Array.isArray(data.toasts)) { + $.each(data.toasts, function() { + this.msg && fm.toast(this); + }); + } + + PRcheck(node); + }) + .always(function(data) { + var cmdEdit, sel, head; + if (cmdEdit = fm.getCommand('edit')) { + head = []; + if (data && data.encoding) { + head.push({value: data.encoding}); + } + head.push({value: 'UTF-8'}); + sel = cmdEdit.getEncSelect(head); + sel.on('change', function() { + file.encoding = sel.val(); + fm.cache(file, 'change'); + preview.trigger({ + type: ql.evUpdate, + file: file, + forceUpdate: true + }); + }); + encSelect = $('
              ').append(sel); + ql.window.append(encSelect); + } + loading.remove(); + }); + } + }); + } +]; + + +/* + * File: /js/commands/reload.js + */ + +/** + * @class elFinder command "reload" + * Sync files and folders + * + * @author Dmitry (dio) Levashov + **/ +(elFinder.prototype.commands.reload = function() { + "use strict"; + var self = this, + search = false; + + this.alwaysEnabled = true; + this.updateOnSelect = true; + + this.shortcuts = [{ + pattern : 'ctrl+shift+r f5' + }]; + + this.getstate = function() { + return 0; + }; + + this.init = function() { + this.fm.bind('search searchend', function() { + search = this.type == 'search'; + }); + }; + + this.fm.bind('contextmenu', function(){ + var fm = self.fm; + if (fm.options.sync >= 1000) { + self.extra = { + icon: 'accept', + node: $('') + .attr({title: fm.i18n('autoSync')}) + .on('click touchstart', function(e){ + if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) { + return; + } + e.stopPropagation(); + e.preventDefault(); + $(this).parent() + .toggleClass('ui-state-disabled', fm.options.syncStart) + .parent().removeClass('ui-state-hover'); + fm.options.syncStart = !fm.options.syncStart; + fm.autoSync(fm.options.syncStart? null : 'stop'); + }).on('ready', function(){ + $(this).parent().toggleClass('ui-state-disabled', !fm.options.syncStart).css('pointer-events', 'auto'); + }) + }; + } + }); + + this.exec = function() { + var fm = this.fm; + if (!search) { + var dfrd = fm.sync(), + timeout = setTimeout(function() { + fm.notify({type : 'reload', cnt : 1, hideCnt : true}); + dfrd.always(function() { fm.notify({type : 'reload', cnt : -1}); }); + }, fm.notifyDelay); + + return dfrd.always(function() { + clearTimeout(timeout); + fm.trigger('reload'); + }); + } else { + $('div.elfinder-toolbar > div.'+fm.res('class', 'searchbtn') + ' > span.ui-icon-search').click(); + } + }; + +}).prototype = { forceLoad : true }; // this is required command + + +/* + * File: /js/commands/rename.js + */ + +/** + * @class elFinder command "rename". + * Rename selected file. + * + * @author Dmitry (dio) Levashov, dio@std42.ru + * @author Naoki Sawada + **/ +elFinder.prototype.commands.rename = function() { + "use strict"; + + // set alwaysEnabled to allow root rename on client size + if (this.fm.options.enableRootRename !== false) { + this.alwaysEnabled = true; + } + + this.syncTitleOnChange = true; + + var self = this, + fm = self.fm, + enableRootRename = fm.options.enableRootRename !== false, + request = function(dfrd, targtes, file, name) { + var sel = targtes? [file.hash].concat(targtes) : [file.hash], + cnt = sel.length, + data = {}, rootNames; + + fm.lockfiles({files : sel}); + + if (fm.isRoot(file) && !file.netkey && enableRootRename) { + if (!(rootNames = fm.storage('rootNames'))) { + rootNames = {}; + } + if (name === '') { + if (rootNames[file.hash]) { + file.name = file._name; + file.i18 = file._i18; + delete rootNames[file.hash]; + delete file._name; + delete file._i18; + } else { + dfrd && dfrd.reject(); + fm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel}); + return; + } + } else { + if (typeof file._name === 'undefined') { + file._name = file.name; + file._i18 = file.i18; + } + file.name = rootNames[file.hash] = name; + delete file.i18; + } + fm.storage('rootNames', rootNames); + data = { changed: [file] }; + fm.updateCache(data); + fm.change(data); + dfrd && dfrd.resolve(data); + fm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel}); + return; + } + + data = { + cmd : 'rename', + name : name, + target : file.hash + }; + + if (cnt > 1) { + data['targets'] = targtes; + if (name.match(/\*/)) { + data['q'] = name; + } + } + + fm.request({ + data : data, + notify : {type : 'rename', cnt : cnt}, + navigate : {} + }) + .fail(function(error) { + var err = fm.parseError(error); + dfrd && dfrd.reject(); + if (! err || ! Array.isArray(err) || err[0] !== 'errRename') { + fm.sync(); + } + }) + .done(function(data) { + var cwdHash; + if (data.added && data.added.length && cnt === 1) { + data.undo = { + cmd : 'rename', + callback : function() { + return fm.request({ + data : {cmd : 'rename', target : data.added[0].hash, name : file.name}, + notify : {type : 'undo', cnt : 1} + }); + } + }; + data.redo = { + cmd : 'rename', + callback : function() { + return fm.request({ + data : {cmd : 'rename', target : file.hash, name : name}, + notify : {type : 'rename', cnt : 1} + }); + } + }; + } + dfrd && dfrd.resolve(data); + if (!(cwdHash = fm.cwd().hash) || cwdHash === file.hash) { + fm.exec('open', $.map(data.added, function(f) { + return (f.mime === 'directory')? f.hash : null; + })[0]); + } + }) + .always(function() { + fm.unlockfiles({files : sel}).trigger('selectfiles', {files : sel}); + } + ); + }, + getHint = function(name, target) { + var sel = target || fm.selected(), + splits = fm.splitFileExtention(name), + f1 = fm.file(sel[0]), + f2 = fm.file(sel[1]), + ext, hint, add; + + ext = splits[1]? ('.' + splits[1]) : ''; + if (splits[1] && splits[0] === '*') { + // change extention + hint = '"' + fm.splitFileExtention(f1.name)[0] + ext + '", '; + hint += '"' + fm.splitFileExtention(f2.name)[0] + ext + '"'; + } else if (splits[0].length > 1) { + if (splits[0].substr(-1) === '*') { + // add prefix + add = splits[0].substr(0, splits[0].length - 1); + hint = '"' + add + f1.name+'", '; + hint += '"' + add + f2.name+'"'; + } else if (splits[0].substr(0, 1) === '*') { + // add suffix + add = splits[0].substr(1); + hint = '"'+fm.splitFileExtention(f1.name)[0] + add + ext + '", '; + hint += '"'+fm.splitFileExtention(f2.name)[0] + add + ext + '"'; + } + } + if (!hint) { + hint = '"'+splits[0] + '1' + ext + '", "' + splits[0] + '2' + ext + '"'; + } + if (sel.length > 2) { + hint += ' ...'; + } + return hint; + }, + batchRename = function() { + var sel = fm.selected(), + tplr = '', + mkChk = function(node, label) { + return $('').prepend(node); + }, + name = $(''), + num = $(tplr), + prefix = $(tplr), + suffix = $(tplr), + extention = $(tplr), + checks = $('
              ').append( + mkChk(num, 'plusNumber'), + mkChk(prefix, 'asPrefix'), + mkChk(suffix, 'asSuffix'), + mkChk(extention, 'changeExtention') + ), + preview = $('
              '), + node = $('
              ').append( + $('
              ').append(name), + $('
              ').append(checks), + preview + ), + opts = { + title : fm.i18n('batchRename'), + modal : true, + destroyOnClose : true, + width: Math.min(380, fm.getUI().width() - 20), + buttons : {}, + open : function() { + name.on('input', mkPrev).trigger('focus'); + } + }, + getName = function() { + var vName = name.val(), + ext = fm.splitFileExtention(fm.file(sel[0]).name)[1]; + if (vName !== '' || num.is(':checked')) { + if (prefix.is(':checked')) { + vName += '*'; + } else if (suffix.is(':checked')) { + vName = '*' + vName + '.' + ext; + } else if (extention.is(':checked')) { + vName = '*.' + vName; + } else if (ext) { + vName += '.' + ext; + } + } + return vName; + }, + mkPrev = function() { + var vName = getName(); + if (vName !== '') { + preview.html(fm.i18n(['renameMultiple', sel.length, getHint(vName)])); + } else { + preview.empty(); + } + }, + radios = checks.find('input:radio').on('change', mkPrev), + dialog; + + opts.buttons[fm.i18n('btnApply')] = function() { + var vName = getName(), + file, targets; + if (vName !== '') { + dialog.elfinderdialog('close'); + targets = sel; + file = fm.file(targets.shift()); + request(void(0), targets, file, vName); + } + }; + opts.buttons[fm.i18n('btnCancel')] = function() { + dialog.elfinderdialog('close'); + }; + if ($.fn.checkboxradio) { + radios.checkboxradio({ + create: function(e, ui) { + if (this === num.get(0)) { + num.prop('checked', true).change(); + } + } + }); + } else { + checks.buttonset({ + create: function(e, ui) { + num.prop('checked', true).change(); + } + }); + } + dialog = self.fmDialog(node, opts); + }; + + this.noChangeDirOnRemovedCwd = true; + + this.shortcuts = [{ + pattern : 'f2' + (fm.OS == 'mac' ? ' enter' : '') + }, { + pattern : 'shift+f2', + description : 'batchRename', + callback : function() { + fm.selected().length > 1 && batchRename(); + } + }]; + + this.getstate = function(select) { + var sel = this.files(select), + cnt = sel.length, + phash, ext, mime, brk, state, isRoot; + + if (!cnt) { + return -1; + } + + if (cnt > 1 && sel[0].phash) { + phash = sel[0].phash; + ext = fm.splitFileExtention(sel[0].name)[1].toLowerCase(); + mime = sel[0].mime; + } + if (cnt === 1) { + isRoot = fm.isRoot(sel[0]); + } + + state = (cnt === 1 && ((enableRootRename && fm.cookieEnabled && isRoot) || !sel[0].locked) || (fm.api > 2.1030 && cnt === $.grep(sel, function(f) { + if (!brk && !f.locked && f.phash === phash && !fm.isRoot(f) && (mime === f.mime || ext === fm.splitFileExtention(f.name)[1].toLowerCase())) { + return true; + } else { + brk && (brk = true); + return false; + } + }).length)) ? 0 : -1; + + // because alwaysEnabled = true, it need check disabled on connector + if (!isRoot && state === 0 && fm.option('disabledFlip', sel[0].hash)['rename']) { + state = -1; + } + + if (state !== -1 && cnt > 1) { + self.extra = { + icon: 'preference', + node: $('') + .attr({title: fm.i18n('batchRename')}) + .on('click touchstart', function(e){ + if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) { + return; + } + e.stopPropagation(); + e.preventDefault(); + fm.getUI().trigger('click'); // to close the context menu immediately + batchRename(); + }) + }; + } else { + delete self.extra; + } + + return state; + }; + + this.exec = function(hashes, cOpts) { + var cwd = fm.getUI('cwd'), + sel = hashes || (fm.selected().length? fm.selected() : false) || [fm.cwd().hash], + cnt = sel.length, + file = fm.file(sel.shift()), + filename = '.elfinder-cwd-filename', + opts = cOpts || {}, + incwd = (fm.cwd().hash == file.hash), + type = (opts._currentType === 'navbar' || opts._currentType === 'files')? opts._currentType : (incwd? 'navbar' : 'files'), + navbar = (type !== 'files'), + target = fm[navbar? 'navHash2Elm' : 'cwdHash2Elm'](file.hash), + tarea = (!navbar && fm.storage('view') != 'list'), + split = function(name) { + var ext = fm.splitFileExtention(name)[1]; + return [name.substr(0, name.length - ext.length - 1), ext]; + }, + unselect = function() { + requestAnimationFrame(function() { + input && input.trigger('blur'); + }); + }, + rest = function(){ + if (!overlay.is(':hidden')) { + overlay.elfinderoverlay('hide').off('click close', cancel); + } + pnode.removeClass('ui-front') + .css('position', '') + .off('unselect.'+fm.namespace, unselect); + if (tarea) { + node && node.css('max-height', ''); + } else if (!navbar) { + pnode.css('width', '') + .parent('td').css('overflow', ''); + } + }, colwidth, + dfrd = $.Deferred() + .fail(function(error) { + var parent = input.parent(), + name = fm.escape(file.i18 || file.name); + + input.off(); + if (tarea) { + name = name.replace(/([_.])/g, '​$1'); + } + requestAnimationFrame(function() { + if (navbar) { + input.replaceWith(name); + } else { + if (parent.length) { + input.remove(); + parent.html(name); + } else { + target.find(filename).html(name); + } + } + }); + error && fm.error(error); + }) + .always(function() { + rest(); + fm.unbind('resize', resize); + fm.enable(); + }), + blur = function(e) { + var name = $.trim(input.val()), + splits = fm.splitFileExtention(name), + valid = true, + req = function() { + input.off(); + rest(); + if (navbar) { + input.replaceWith(fm.escape(name)); + } else { + node.html(fm.escape(name)); + } + request(dfrd, sel, file, name); + }; + + if (!overlay.is(':hidden')) { + pnode.css('z-index', ''); + } + if (name === '') { + if (!fm.isRoot(file)) { + return cancel(); + } + if (navbar) { + input.replaceWith(fm.escape(file.name)); + } else { + node.html(fm.escape(file.name)); + } + } + if (!inError && pnode.length) { + + input.off('blur'); + + if (cnt === 1 && name === file.name) { + return dfrd.reject(); + } + if (fm.options.validName && fm.options.validName.test) { + try { + valid = fm.options.validName.test(name); + } catch(e) { + valid = false; + } + } + if (name === '.' || name === '..' || !valid) { + inError = true; + fm.error(file.mime === 'directory'? 'errInvDirname' : 'errInvName', {modal: true, close: function(){setTimeout(select, 120);}}); + return false; + } + if (cnt === 1 && fm.fileByName(name, file.phash)) { + inError = true; + fm.error(['errExists', name], {modal: true, close: function(){setTimeout(select, 120);}}); + return false; + } + + if (cnt === 1) { + req(); + } else { + fm.confirm({ + title : 'cmdrename', + text : ['renameMultiple', cnt, getHint(name, [file.hash].concat(sel))], + accept : { + label : 'btnYes', + callback : req + }, + cancel : { + label : 'btnCancel', + callback : function() { + setTimeout(function() { + inError = true; + select(); + }, 120); + } + } + }); + setTimeout(function() { + fm.trigger('unselectfiles', {files: fm.selected()}) + .trigger('selectfiles', {files : [file.hash].concat(sel)}); + }, 120); + } + } + }, + input = $(tarea? '' : '') + .on('keyup text', function(){ + if (tarea) { + this.style.height = '1px'; + this.style.height = this.scrollHeight + 'px'; + } else if (colwidth) { + this.style.width = colwidth + 'px'; + if (this.scrollWidth > colwidth) { + this.style.width = this.scrollWidth + 10 + 'px'; + } + } + }) + .on('keydown', function(e) { + e.stopImmediatePropagation(); + if (e.keyCode == $.ui.keyCode.ESCAPE) { + dfrd.reject(); + } else if (e.keyCode == $.ui.keyCode.ENTER) { + e.preventDefault(); + input.trigger('blur'); + } + }) + .on('mousedown click dblclick', function(e) { + e.stopPropagation(); + if (e.type === 'dblclick') { + e.preventDefault(); + } + }) + .on('blur', blur) + .on('dragenter dragleave dragover drop', function(e) { + // stop bubbling to prevent upload with native drop event + e.stopPropagation(); + }), + select = function() { + var name = fm.splitFileExtention(input.val())[0]; + if (!inError && fm.UA.Mobile && !fm.UA.iOS) { // since iOS has a bug? (z-index not effect) so disable it + overlay.on('click close', cancel).elfinderoverlay('show'); + pnode.css('z-index', overlay.css('z-index') + 1); + } + ! fm.enabled() && fm.enable(); + if (inError) { + inError = false; + input.on('blur', blur); + } + input.trigger('focus').trigger('select'); + input[0].setSelectionRange && input[0].setSelectionRange(0, name.length); + }, + node = navbar? target.contents().filter(function(){ return this.nodeType==3 && $(this).parent().attr('id') === fm.navHash2Id(file.hash); }) + : target.find(filename), + pnode = node.parent(), + overlay = fm.getUI('overlay'), + cancel = function(e) { + if (!overlay.is(':hidden')) { + pnode.css('z-index', ''); + } + if (! inError) { + dfrd.reject(); + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + } + }, + resize = function() { + target.trigger('scrolltoview', {blink : false}); + }, + inError = false; + + pnode.addClass('ui-front') + .css('position', 'relative') + .on('unselect.'+fm.namespace, unselect); + fm.bind('resize', resize); + if (navbar) { + node.replaceWith(input.val(file.name)); + } else { + if (tarea) { + node.css('max-height', 'none'); + } else if (!navbar) { + colwidth = pnode.width(); + pnode.width(colwidth - 15) + .parent('td').css('overflow', 'visible'); + } + node.empty().append(input.val(file.name)); + } + + if (cnt > 1 && fm.api <= 2.1030) { + return dfrd.reject(); + } + + if (!file || !node.length) { + return dfrd.reject('errCmdParams', this.title); + } + + if (file.locked && (!fm.isRoot(file) || !enableRootRename)) { + return dfrd.reject(['errLocked', file.name]); + } + + fm.one('select', function() { + input.parent().length && file && $.inArray(file.hash, fm.selected()) === -1 && input.trigger('blur'); + }); + + input.trigger('keyup'); + + select(); + + return dfrd; + }; + + fm.bind('select contextmenucreate closecontextmenu', function(e) { + var sel = (e.data? (e.data.selected || e.data.targets) : null) || fm.selected(), + file; + if (sel && sel.length === 1 && (file = fm.file(sel[0])) && fm.isRoot(file)) { + self.title = fm.i18n('kindAlias') + ' (' + fm.i18n('preference') + ')'; + } else { + self.title = fm.i18n('cmdrename'); + } + if (e.type !== 'closecontextmenu') { + self.update(void(0), self.title); + } else { + requestAnimationFrame(function() { + self.update(void(0), self.title); + }); + } + }).remove(function(e) { + var rootNames; + if (e.data && e.data.removed && (rootNames = fm.storage('rootNames'))) { + $.each(e.data.removed, function(i, h) { + if (rootNames[h]) { + delete rootNames[h]; + } + }); + fm.storage('rootNames', rootNames); + } + }); +}; + + +/* + * File: /js/commands/resize.js + */ + +/** + * @class elFinder command "resize" + * Open dialog to resize image + * + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + * @author Naoki Sawada + * @author Sergio Jovani + **/ +elFinder.prototype.commands.resize = function() { + "use strict"; + var fm = this.fm, + losslessRotate = 0, + getBounceBox = function(w, h, theta) { + var srcPts = [ + {x: w/2, y: h/2}, + {x: -w/2, y: h/2}, + {x: -w/2, y: -h/2}, + {x: w/2, y: -h/2} + ], + dstPts = [], + min = {x: Number.MAX_VALUE, y: Number.MAX_VALUE}, + max = {x: Number.MIN_VALUE, y: Number.MIN_VALUE}; + $.each(srcPts, function(i, srcPt){ + dstPts.push({ + x: srcPt.x * Math.cos(theta) - srcPt.y * Math.sin(theta), + y: srcPt.x * Math.sin(theta) + srcPt.y * Math.cos(theta) + }); + }); + $.each(dstPts, function(i, pt) { + min.x = Math.min(min.x, pt.x); + min.y = Math.min(min.y, pt.y); + max.x = Math.max(max.x, pt.x); + max.y = Math.max(max.y, pt.y); + }); + return { + width: max.x - min.x, height: max.y - min.y + }; + }; + + this.updateOnSelect = false; + + this.getstate = function() { + var sel = fm.selectedFiles(); + return sel.length == 1 && sel[0].read && sel[0].write && sel[0].mime.indexOf('image/') !== -1 ? 0 : -1; + }; + + this.resizeRequest = function(data, f, dfrd) { + var file = f || fm.file(data.target), + tmb = file? file.tmb : null, + enabled = fm.isCommandEnabled('resize', data.target); + + if (enabled && (! file || (file && file.read && file.write && file.mime.indexOf('image/') !== -1 ))) { + return fm.request({ + data : Object.assign(data, { + cmd : 'resize' + }), + notify : {type : 'resize', cnt : 1} + }) + .fail(function(error) { + if (dfrd) { + dfrd.reject(error); + } + }) + .done(function() { + if (data.quality) { + fm.storage('jpgQuality', data.quality === fm.option('jpgQuality')? null : data.quality); + } + dfrd && dfrd.resolve(); + }); + } else { + var error; + + if (file) { + if (file.mime.indexOf('image/') === -1) { + error = ['errResize', file.name, 'errUsupportType']; + } else { + error = ['errResize', file.name, 'errPerm']; + } + } else { + error = ['errResize', data.target, 'errPerm']; + } + + if (dfrd) { + dfrd.reject(error); + } else { + fm.error(error); + } + return $.Deferred().reject(error); + } + }; + + this.exec = function(hashes) { + var self = this, + files = this.files(hashes), + dfrd = $.Deferred(), + api2 = (fm.api > 1), + options = this.options, + dialogWidth = 650, + fmnode = fm.getUI(), + ctrgrup = $().controlgroup? 'controlgroup' : 'buttonset', + grid8Def = typeof options.grid8px === 'undefined' || options.grid8px !== 'disable'? true : false, + presetSize = Array.isArray(options.presetSize)? options.presetSize : [], + clactive = 'elfinder-dialog-active', + clsediting = fm.res('class', 'editing'), + open = function(file, id, src) { + var isJpeg = (file.mime === 'image/jpeg'), + dialog = $('
              '), + input = '', + row = '
              ', + label = '
              ', + changeTm = null, + operate = false, + opStart = function() { operate = true; }, + opStop = function() { + if (operate) { + operate = false; + control.trigger('change'); + } + }, + control = $('
              ') + .on('focus', 'input[type=text],input[type=number]', function() { + $(this).trigger('select'); + }) + .on('change', function() { + changeTm && cancelAnimationFrame(changeTm); + changeTm = requestAnimationFrame(function() { + var panel, quty, canvas, ctx, img, sx, sy, sw, sh, deg, theta, bb; + if (sizeImg && ! operate && (canvas = sizeImg.data('canvas'))) { + panel = control.children('div.elfinder-resize-control-panel:visible'); + quty = panel.find('input.elfinder-resize-quality'); + if (quty.is(':visible')) { + ctx = sizeImg.data('ctx'); + img = sizeImg.get(0); + if (panel.hasClass('elfinder-resize-uiresize')) { + // resize + sw = canvas.width = width.val(); + sh = canvas.height = height.val(); + ctx.drawImage(img, 0, 0, sw, sh); + } else if (panel.hasClass('elfinder-resize-uicrop')) { + // crop + sx = pointX.val(); + sy = pointY.val(); + sw = offsetX.val(); + sh = offsetY.val(); + canvas.width = sw; + canvas.height = sh; + ctx.drawImage(img, sx, sy, sw, sh, 0, 0, sw, sh); + } else { + // rotate + deg = degree.val(); + theta = (degree.val() * Math.PI) / 180; + bb = getBounceBox(owidth, oheight, theta); + sw = canvas.width = bb.width; + sh = canvas.height = bb.height; + ctx.save(); + if (deg % 90 !== 0) { + ctx.fillStyle = bg.val() || '#FFF'; + ctx.fillRect(0, 0, sw, sh); + } + ctx.translate(sw / 2, sh / 2); + ctx.rotate(theta); + ctx.drawImage(img, -img.width/2, -img.height/2, owidth, oheight); + ctx.restore(); + } + canvas.toBlob(function(blob) { + if (blob) { + size1 = blob.size; + quty.next('span').text(' (' + fm.formatSize(blob.size) + ')'); + } + }, 'image/jpeg', Math.max(Math.min(quty.val(), 100), 1) / 100); + } + } + }); + }) + .on('mouseup', 'input', function(e) { + $(e.target).trigger('change'); + }), + preview = $('
              ') + .on('touchmove', function(e) { + if ($(e.target).hasClass('touch-punch')) { + e.stopPropagation(); + e.preventDefault(); + } + }), + spinner = $('
              '+fm.i18n('ntfloadimg')+'
              '), + rhandle = $('
              '), + rhandlec = $('
              '), + uiresize = $('
              '), + uicrop = $('
              '), + uirotate = $('
              '), + uideg270 = $('').attr('title',fm.i18n('rotate-cw')).append($('')), + uideg90 = $('').attr('title',fm.i18n('rotate-ccw')).append($('')), + uiprop = $(''), + reset = $('') + .on('mouseenter mouseleave', function(e) { + $(this).toggleClass('ui-state-hover', e.type == 'mouseenter'); + }).on('click', function() { + fm.exec('open', check).done(function() { + fm.one('opendone', function() { + fm.trigger('selectfiles', {files : $.map(data.added, function(f) {return f.hash;})}); + }); + }); + }) + ); + } else { + fm.trigger('selectfiles', {files : $.map(data.added, function(f) {return f.hash;})}); + } + fm.toast({msg: fm.i18n(['complete', fm.i18n('cmdupload')]), extNode: node}); + } + } + }) + .progress(function() { + dfrd.notifyWith(this, Array.from(arguments)); + }); + }, + upload = function(data) { + dialog.elfinderdialog('close'); + if (targets) { + data.target = targets[0]; + } + fmUpload(data); + }, + getSelector = function() { + var hash = targetDir.hash, + dirs = $.map(fm.files(hash), function(f) { + return (f.mime === 'directory' && f.write)? f : null; + }); + + if (! dirs.length) { + return $(); + } + + return $('
              ') + .on('click', function(e) { + e.stopPropagation(); + e.preventDefault(); + dirs = fm.sortFiles(dirs); + var $this = $(this), + cwd = fm.cwd(), + base = dialog.closest('div.ui-dialog'), + getRaw = function(f, icon) { + return { + label : fm.escape(f.i18 || f.name), + icon : icon, + remain : false, + callback : function() { + var title = base.children('.ui-dialog-titlebar:first').find('span.elfinder-upload-target'); + targets = [ f.hash ]; + title.html(' - ' + fm.escape(f.i18 || f.name)); + $this.trigger('focus'); + }, + options : { + className : (targets && targets.length && f.hash === targets[0])? 'ui-state-active' : '', + iconClass : f.csscls || '', + iconImg : f.icon || '' + } + }; + }, + raw = [ getRaw(targetDir, 'opendir'), '|' ]; + $.each(dirs, function(i, f) { + raw.push(getRaw(f, 'dir')); + }); + $this.trigger('blur'); + fm.trigger('contextmenu', { + raw: raw, + x: e.pageX || $(this).offset().left, + y: e.pageY || $(this).offset().top, + prevNode: base, + fitHeight: true + }); + }).append(''); + }, + inputButton = function(type, caption) { + var button, + input = $('') + .on('click', function() { + // for IE's bug + if (fm.UA.IE) { + setTimeout(function() { + form.css('display', 'none').css('position', 'relative'); + requestAnimationFrame(function() { + form.css('display', '').css('position', ''); + }); + }, 100); + } + }) + .on('change', function() { + upload({input : input.get(0), type : 'files'}); + }) + .on('dragover', function(e) { + e.originalEvent.dataTransfer.dropEffect = 'copy'; + }), + form = $('
              ').append(input).on('click', function(e) { + e.stopPropagation(); + }); + + return $('
              '+fm.i18n(caption)+'
              ') + .append(form) + .on('click', function(e) { + e.stopPropagation(); + e.preventDefault(); + input.trigger('click'); + }) + .on('mouseenter mouseleave', function(e) { + $(this).toggleClass(hover, e.type === 'mouseenter'); + }); + }, + dfrd = $.Deferred(), + dialog, dropbox, pastebox, dropUpload, paste, dirs, spinner, uidialog; + + dropUpload = function(e) { + e.stopPropagation(); + e.preventDefault(); + var file = false, + type = '', + elfFrom = null, + mycwd = '', + data = null, + target = e._target || null, + trf = e.dataTransfer || null, + kind = '', + idx, errors; + + if (trf) { + if (trf.types && trf.types.length) { + if ((idx = $.inArray('application/x-moz-file', trf.types)) !== -1) { + kind = 'file'; + } else if ((idx = $.inArray('Files', trf.types)) !== -1) { + kind = 'file'; + } + } + else if (trf.items && trf.items.length && trf.items[0].kind) { + kind = trf.items[0].kind; + } + + try { + elfFrom = trf.getData('elfinderfrom'); + if (elfFrom) { + mycwd = window.location.href + fm.cwd().hash; + if ((!target && elfFrom === mycwd) || target === mycwd) { + dfrd.reject(); + return; + } + } + } catch(e) {} + + if (kind === 'file' && (trf.items[idx].getAsEntry || trf.items[idx].webkitGetAsEntry || trf.items[idx].getAsFile)) { + file = trf; + type = 'data'; + } else if (kind !== 'string' && trf.files && trf.files.length && $.inArray('Text', trf.types) === -1) { + file = trf.files; + type = 'files'; + } else { + try { + if ((data = trf.getData('text/html')) && data.match(/<(?:img|a)/i)) { + file = [ data ]; + type = 'html'; + } + } catch(e) {} + if (! file) { + if (data = trf.getData('text')) { + file = [ data ]; + type = 'text'; + } else if (trf && trf.files) { + // maybe folder uploading but this UA dose not support it + kind = 'file'; + } + } + } + } + if (file) { + fmUpload({files : file, type : type, target : target, dropEvt : e}); + } else { + errors = ['errUploadNoFiles']; + if (kind === 'file') { + errors.push('errFolderUpload'); + } + fm.error(errors); + dfrd.reject(); + } + }; + + if (!targets && data) { + if (data.input || data.files) { + data.type = 'files'; + fmUpload(data); + } else if (data.dropEvt) { + dropUpload(data.dropEvt); + } + return dfrd; + } + + paste = function(ev) { + var e = ev.originalEvent || ev; + var files = [], items = []; + var file; + if (e.clipboardData) { + if (e.clipboardData.items && e.clipboardData.items.length){ + items = e.clipboardData.items; + for (var i=0; i < items.length; i++) { + if (e.clipboardData.items[i].kind == 'file') { + file = e.clipboardData.items[i].getAsFile(); + files.push(file); + } + } + } else if (e.clipboardData.files && e.clipboardData.files.length) { + files = e.clipboardData.files; + } + if (files.length) { + upload({files : files, type : 'files', clipdata : true}); + return; + } + } + var my = e.target || e.srcElement; + requestAnimationFrame(function() { + var type = 'text', + src; + if (my.innerHTML) { + $(my).find('img').each(function(i, v){ + if (v.src.match(/^webkit-fake-url:\/\//)) { + // For Safari's bug. + // ref. https://bugs.webkit.org/show_bug.cgi?id=49141 + // https://dev.ckeditor.com/ticket/13029 + $(v).remove(); + } + }); + + if ($(my).find('a,img').length) { + type = 'html'; + } + src = my.innerHTML; + my.innerHTML = ''; + upload({files : [ src ], type : type}); + } + }); + }; + + dialog = $('
              ') + .append(inputButton('multiple', 'selectForUpload')); + + if (! fm.UA.Mobile && (function(input) { + return (typeof input.webkitdirectory !== 'undefined' || typeof input.directory !== 'undefined');})(document.createElement('input'))) { + dialog.append(inputButton('multiple webkitdirectory directory', 'selectFolder')); + } + + if (targetDir.dirs) { + + if (targetDir.hash === cwdHash || fm.navHash2Elm(targetDir.hash).hasClass('elfinder-subtree-loaded')) { + getSelector().appendTo(dialog); + } else { + spinner = $('
              ') + .append('') + .appendTo(dialog); + fm.request({cmd : 'tree', target : targetDir.hash}) + .done(function() { + fm.one('treedone', function() { + spinner.replaceWith(getSelector()); + uidialog.elfinderdialog('tabstopsInit'); + }); + }) + .fail(function() { + spinner.remove(); + }); + } + } + + if (fm.dragUpload) { + dropbox = $('
              ') + .on('paste', function(e){ + paste(e); + }) + .on('mousedown click', function(){ + $(this).trigger('focus'); + }) + .on('focus', function(){ + this.innerHTML = ''; + }) + .on('mouseover', function(){ + $(this).addClass(hover); + }) + .on('mouseout', function(){ + $(this).removeClass(hover); + }) + .on('dragenter', function(e) { + e.stopPropagation(); + e.preventDefault(); + $(this).addClass(hover); + }) + .on('dragleave', function(e) { + e.stopPropagation(); + e.preventDefault(); + $(this).removeClass(hover); + }) + .on('dragover', function(e) { + e.stopPropagation(); + e.preventDefault(); + e.originalEvent.dataTransfer.dropEffect = 'copy'; + $(this).addClass(hover); + }) + .on('drop', function(e) { + dialog.elfinderdialog('close'); + targets && (e.originalEvent._target = targets[0]); + dropUpload(e.originalEvent); + }) + .prependTo(dialog) + .after('
              '+fm.i18n('or')+'
              ')[0]; + + } else { + pastebox = $('
              '+fm.i18n('dropFilesBrowser')+'
              ') + .on('paste drop', function(e){ + paste(e); + }) + .on('mousedown click', function(){ + $(this).trigger('focus'); + }) + .on('focus', function(){ + this.innerHTML = ''; + }) + .on('dragenter mouseover', function(){ + $(this).addClass(hover); + }) + .on('dragleave mouseout', function(){ + $(this).removeClass(hover); + }) + .prependTo(dialog) + .after('
              '+fm.i18n('or')+'
              ')[0]; + + } + + uidialog = this.fmDialog(dialog, { + title : this.title + '' + (targetDir? ' - ' + fm.escape(targetDir.i18 || targetDir.name) : '') + '', + modal : true, + resizable : false, + destroyOnClose : true, + propagationEvents : ['mousemove', 'mouseup', 'click'], + close : function() { + var cm = fm.getUI('contextmenu'); + if (cm.is(':visible')) { + cm.click(); + } + } + }); + + return dfrd; + }; + +}; + + +/* + * File: /js/commands/view.js + */ + +/** + * @class elFinder command "view" + * Change current directory view (icons/list) + * + * @author Dmitry (dio) Levashov + **/ +elFinder.prototype.commands.view = function() { + "use strict"; + var self = this, + fm = this.fm, + subMenuRaw; + this.value = fm.viewType; + this.alwaysEnabled = true; + this.updateOnSelect = false; + + this.options = { ui : 'viewbutton'}; + + this.getstate = function() { + return 0; + }; + + this.extra = { + icon: 'menu', + node: $('') + .attr({title: fm.i18n('viewtype')}) + .on('click touchstart', function(e){ + if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) { + return; + } + var node = $(this); + e.stopPropagation(); + e.preventDefault(); + fm.trigger('contextmenu', { + raw: getSubMenuRaw(), + x: node.offset().left, + y: node.offset().top + }); + }) + }; + + this.exec = function() { + var self = this, + value = this.value == 'list' ? 'icons' : 'list'; + + fm.storage('view', value); + return fm.lazy(function() { + fm.viewchange(); + self.update(void(0), value); + this.resolve(); + }); + }; + + fm.bind('init', function() { + subMenuRaw = (function() { + var cwd = fm.getUI('cwd'), + raws = [], + sizeNames = fm.options.uiOptions.cwd.iconsView.sizeNames, + max = fm.options.uiOptions.cwd.iconsView.sizeMax, + i, size; + for (i = 0; i <= max; i++) { + raws.push( + { + label : fm.i18n(sizeNames[i] || ('Size-' + i + ' icons')), + icon : 'view', + callback : (function(s) { + return function() { + cwd.trigger('iconpref', {size: s}); + fm.storage('iconsize', s); + if (self.value === 'list') { + self.exec(); + } + }; + })(i) + } + ); + } + raws.push('|'); + raws.push( + { + label : fm.i18n('viewlist'), + icon : 'view-list', + callback : function() { + if (self.value !== 'list') { + self.exec(); + } + } + } + ); + return raws; + })(); + }).bind('contextmenucreate', function() { + self.extra = { + icon: 'menu', + node: $('') + .attr({title: fm.i18n('cmdview')}) + .on('click touchstart', function(e){ + if (e.type === 'touchstart' && e.originalEvent.touches.length > 1) { + return; + } + var node = $(this), + raw = subMenuRaw.concat(), + idx, i; + if (self.value === 'list') { + idx = subMenuRaw.length - 1; + } else { + idx = parseInt(fm.storage('iconsize') || 0); + } + for (i = 0; i < subMenuRaw.length; i++) { + if (subMenuRaw[i] !== '|') { + subMenuRaw[i].options = (i === idx? {'className': 'ui-state-active'} : void(0)) + ; + } + } + e.stopPropagation(); + e.preventDefault(); + fm.trigger('contextmenu', { + raw: subMenuRaw, + x: node.offset().left, + y: node.offset().top + }); + }) + }; + }); + +}; + +return elFinder; +})); \ No newline at end of file diff --git a/lib/redactor/elfinder/js/elfinder.min.js b/lib/redactor/elfinder/js/elfinder.min.js new file mode 100644 index 0000000..b0c6b56 --- /dev/null +++ b/lib/redactor/elfinder/js/elfinder.min.js @@ -0,0 +1,26 @@ +/*! + * elFinder - file manager for web + * Version 2.1.66 (2025-08-28) + * http://elfinder.org + * + * Copyright 2009-2025, Studio 42 + * Licensed under a 3-clauses BSD license + */ +!function(e,t){if("function"==typeof define&&define.amd)define(["jquery","jquery-ui"],t);else if("undefined"!=typeof exports){var n,i;try{n=require("jquery"),i=require("jquery-ui")}catch(a){}module.exports=t(n,i)}else t(e.jQuery,e.jQuery.ui,!0)}(this,function(e,t,n){n=n||!1;var i=function(t,n,a){var o,r,s,l,c,d,p,u=this,h=[],f=["button","tooltip"],m=e(t),g=e.extend(!0,{},e._data(m.get(0),"events")),v=e("
              ").append(m.contents()).attr("class",m.attr("class")||"").attr("style",m.attr("style")||""),b=m.attr("id")||m.attr("id","elfauto"+e(".elfinder").length).attr("id"),y="elfinder-"+b,w="mousedown."+y,x="keydown."+y,k="keypress."+y,C="keyup."+y,z=!1,T=!1,A=["enable","disable","load","open","reload","select","add","remove","change","dblclick","getfile","lockfiles","unlockfiles","selectfiles","unselectfiles","dragstart","dragstop","search","searchend","viewchange"],j="",O={path:"",url:"",tmbUrl:"",disabled:[],separator:"/",archives:[],extract:[],copyOverwrite:!0,uploadOverwrite:!0,uploadMaxSize:0,jpgQuality:100,tmbCrop:!1,tmbReqCustomData:!1,tmb:!1},S={},I={},M={},F={},E=[],D={},U={},P=[],R={},q=[],H=[],_=new u.command(u),N="auto",L=400,W=null,B="sounds/",$="",V=!1,K=e(document.createElement("audio")).hide().appendTo("body")[0],X=0,J="",G=null,Y=function(t){var n,i,a,o,r,s,l,c,d={},p={};u.api>=2.1?(u.commandMap=t.options.uiCmdMap&&Object.keys(t.options.uiCmdMap).length?t.options.uiCmdMap:{},J!==JSON.stringify(u.commandMap)&&(J=JSON.stringify(u.commandMap))):u.options.sync=0,t.init?(I={},F={}):(s=j,n="elfinder-subtree-loaded "+u.res("class","navexpand"),r=u.res("class","navcollapse"),i=Object.keys(I),a=function(e){if(!I[e])return!0;var t="directory"===I[e].mime,i=I[e].phash;!(!t||d[i]||!p[i]&&u.navHash2Elm(I[e].hash).is(":hidden")&&u.navHash2Elm(i).next(".elfinder-navbar-subtree").children().length>100)||!t&&i===j||R[e]?t&&(p[i]=!0):(t&&!d[i]&&(d[i]=!0,u.navHash2Elm(i).removeClass(n).next(".elfinder-navbar-subtree").empty()),ee(I[e]))},o=function(){i.length&&(G&&G._abort(),G=u.asyncJob(a,i,{interval:20,numPerOnce:100}).done(function(){var t=u.storage("hide")||{items:{}};Object.keys(M).length&&e.each(M,function(e){t.items[e]||delete M[e]})}))},u.trigger("filesgc").one("filesgc",function(){i=[]}),u.one("opendone",function(){s!==j&&(m.data("lazycnt")?u.one("lazydone",o):o())})),u.sorters={},j=t.cwd.hash,Q(t.files),I[j]?(c=u.diff([t.cwd],!0),c.changed.length&&(Q(c.changed,"change"),u.change({changed:c.changed}))):Q([t.cwd]),t.changed&&t.changed.length&&Q(t.changed,"change"),l=JSON.stringify(u.sorters),$!==l&&(u.trigger("sorterupdate"),$=l),u.lastDir(j),u.autoSync()},Q=function(t,n){var i,a,o,r,s,n=n||"files",l=["sizeInfo","encoding"],c={name:!0,perm:!0,date:!0,size:!0,kind:!0},d=!u.sorters._checked&&"files"===n,p=t.length,h=function(t){var n=t||{},i=[];e.each(u.sortRules,function(e){(c[e]||"undefined"!=typeof n[e]||"mode"===e&&"undefined"!=typeof n.perm)&&i.push(e)}),u.sorters=u.arrayFlip(i,!0),u.sorters._checked=!0},f={},m=u.storage("hide")||{},g=m.items||{};for(a=0;a-1&&o.splice(r,1));return n=null,this},this.trigger=function(t,n,i){var a,o,r,s,l=t.toLowerCase(),c="object"==typeof n,d=D[l]||[],p=[];if(this.debug("event-"+l,n),c&&"undefined"!=typeof i||(i=!0),o=d.length){for(s=e.Event(l),n&&(n._getEvent=function(){return s}),i&&(s.data=n),a=0;a script").each(function(){if(this.src&&this.src.match(/js\/elfinder(?:-[a-z0-9_-]+)?\.(?:min|full)\.js(?:$|\?)/i))return t=e(this),!1}),t&&(i=t.attr("src").replace(/js\/[^\/]+$/,""),i.match(/^(https?\/\/|\/)/)||(n=e("head > base[href]").attr("href"))&&(i=n.replace(/\/$/,"")+"/"+i)),""!==i?u.options.baseUrl=i:(u.options.baseUrl||(u.options.baseUrl="./"),i=u.options.baseUrl),i)}(),this.i18nBaseUrl=(this.options.i18nBaseUrl||this.baseUrl+"js/i18n").replace(/\/$/,"")+"/",this.workerBaseUrl=(this.options.workerBaseUrl||this.baseUrl+"js/worker").replace(/\/$/,"")+"/",this.options.maxErrorDialogs=Math.max(1,parseInt(this.options.maxErrorDialogs||5)),O.dispInlineRegex=this.options.dispInlineRegex,this.options.cssAutoLoad&&!function(){var t=u.baseUrl,n=e('head > link[href$="css/elfinder.min.css"],link[href$="css/elfinder.full.css"]:first').length,i=function(){m.data("cssautoloadHide")&&(m.data("cssautoloadHide").remove(),m.removeData("cssautoloadHide"))},a=function(){u.cssloaded||(i(),u.cssloaded=!0,u.trigger("cssloaded"))};n||(u.cssloaded=null),Array.isArray(u.options.cssAutoLoad)&&(u.options.themes["default"]?u.cssloaded===!0?u.loadCss(u.options.cssAutoLoad):u.bind("cssloaded",function(){u.loadCss(u.options.cssAutoLoad)}):(u.options.themes=Object.assign({"default":{name:"default",cssurls:u.options.cssAutoLoad}},u.options.themes),u.options.theme||(u.options.theme="default"))),null===u.cssloaded&&(m.addClass("elfinder").data("cssautoloadHide",e("")),e("head").append(m.data("cssautoloadHide")),u.options.themes["default"]||(u.options.themes=Object.assign({"default":{name:"default",cssurls:"css/theme.css",author:"elFinder Project",license:"3-clauses BSD"}},u.options.themes),u.options.theme||(u.options.theme="default")),requestAnimationFrame(function(){"hidden"===m.css("visibility")?u.loadCss([t+"css/elfinder.min.css"],{dfd:e.Deferred().done(function(){a()}).fail(function(){i(),u.cssloaded||(u.cssloaded=!1,u.bind("init",function(){u.cssloaded||u.error(["errRead","CSS (elfinder.min)"])}))})}):a()}))}(),function(){var e,t=u.options.themes,n=Object.keys(t||{});n.length&&(e=u.storage("theme")||u.options.theme,t[e]||(e=n[0]),u.cssloaded?u.changeTheme(e):u.bind("cssloaded",function(){u.changeTheme(e)}))}(),this.optionProperties={icon:void 0,csscls:void 0,tmbUrl:void 0,uiCmdMap:{},netkey:void 0,disabled:[]},re||this.options.enableAlways||2!==e("body").children().length||(this.options.enableAlways=!0),this.options.debug===!0?this.options.debug="all":Array.isArray(this.options.debug)?!function(){var t={};e.each(u.options.debug,function(){t[this]=!0}),u.options.debug=t}():this.options.debug=!1,this.noConflicts={},this.noConflict=function(){e.each(f,function(t,n){e.fn[n]&&"function"==typeof e.fn[n].noConflict&&(u.noConflicts[n]=e.fn[n].noConflict())})},this.noConflict(),this.isCORS=!1,function(){if("undefined"!=typeof u.options.cors&&null!==u.options.cors)u.isCORS=!!u.options.cors;else{var t,i=document.createElement("a"),a=window.location.protocol,o=function(e){return e=e&&":"!==e?e:a,"https:"===e?/\:443$/:/\:80$/},r=window.location.host.replace(o(a),"");i.href=n.url,n.urlUpload&&n.urlUpload!==n.url&&(t=document.createElement("a"),t.href=n.urlUpload),(r!==i.host.replace(o(i.protocol),"")||":"!==i.protocol&&""!==i.protocol&&a!==i.protocol||t&&(r!==t.host.replace(o(t.protocol),"")||":"!==t.protocol&&""!==t.protocol&&a!==t.protocol))&&(u.isCORS=!0)}u.isCORS&&(e.isPlainObject(u.options.customHeaders)||(u.options.customHeaders={}),e.isPlainObject(u.options.xhrFields)||(u.options.xhrFields={}),u.options.requestType="post",u.options.customHeaders["X-Requested-With"]="XMLHttpRequest",u.options.xhrFields.withCredentials=!0)}(),this.requestType=/^(get|post)$/i.test(this.options.requestType)?this.options.requestType.toLowerCase():"get",s=Math.max(parseInt(this.options.requestMaxConn),1),this.optsCustomData=e.isPlainObject(this.options.customData)?this.options.customData:{},this.customData=Object.assign({},this.optsCustomData),this.prevCustomData=null,this.customHeaders=e.isPlainObject(this.options.customHeaders)?this.options.customHeaders:{},this.xhrFields=e.isPlainObject(this.options.xhrFields)?this.options.xhrFields:{},this.replaceXhrSend=function(){p||(p=XMLHttpRequest.prototype.send),XMLHttpRequest.prototype.send=function(){var t=this;return u.customHeaders&&e.each(u.customHeaders,function(e){t.setRequestHeader(e,this)}),u.xhrFields&&e.each(u.xhrFields,function(e){e in t&&(t[e]=this)}),p.apply(this,arguments)}},this.restoreXhrSend=function(){p&&(XMLHttpRequest.prototype.send=p)},this.abortCmdsOnOpen=this.options.abortCmdsOnOpen||["tmb","parents"],this.navPrefix="nav"+(i.prototype.uniqueid?i.prototype.uniqueid:"")+"-",this.cwdPrefix=i.prototype.uniqueid?"cwd"+i.prototype.uniqueid+"-":"",++i.prototype.uniqueid,this.uploadURL=n.urlUpload||n.url,this.namespace=y,this.today=new Date(oe.getFullYear(),oe.getMonth(),oe.getDate()).getTime()/1e3,this.yesterday=this.today-86400,l=this.options.UTCDate?"UTC":"",this.getHours="get"+l+"Hours",this.getMinutes="get"+l+"Minutes",this.getSeconds="get"+l+"Seconds",this.getDate="get"+l+"Date",this.getDay="get"+l+"Day",this.getMonth="get"+l+"Month",this.getFullYear="get"+l+"FullYear",this.zIndex,this.searchStatus={state:0,query:"",target:"",mime:"",mixed:!1,ininc:!1},this.lang=this.storage("lang")||this.options.lang,"jp"===this.lang&&(this.lang=this.options.lang="ja"),this.viewType=this.storage("view")||this.options.defaultView||"icons",this.sortType=this.storage("sortType")||this.options.sortType||"name",this.sortOrder=this.storage("sortOrder")||this.options.sortOrder||"asc",this.sortStickFolders=this.storage("sortStickFolders"),null===this.sortStickFolders?this.sortStickFolders=!!this.options.sortStickFolders:this.sortStickFolders=!!this.sortStickFolders,this.sortAlsoTreeview=this.storage("sortAlsoTreeview"),null===this.sortAlsoTreeview||null===this.options.sortAlsoTreeview?this.sortAlsoTreeview=!!this.options.sortAlsoTreeview:this.sortAlsoTreeview=!!this.sortAlsoTreeview,this.sortRules=e.extend(!0,{},this._sortRules,this.options.sortRules),e.each(this.sortRules,function(e,t){"function"!=typeof t&&delete u.sortRules[e]}),this.compare=e.proxy(this.compare,this),this.notifyDelay=this.options.notifyDelay>0?parseInt(this.options.notifyDelay):500,this.draggingUiHelper=null,this.droppable={greedy:!0,tolerance:"pointer",accept:".elfinder-cwd-file-wrapper,.elfinder-navbar-dir,.elfinder-cwd-file,.elfinder-cwd-filename",hoverClass:this.res("class","adroppable"),classes:{"ui-droppable-hover":this.res("class","adroppable")},autoDisable:!0,drop:function(t,n){var i,a,o,r=e(this),s=e.grep(n.helper.data("files")||[],function(e){return!!e}),l=[],c=[],d=[],p=n.helper.hasClass("elfinder-drag-helper-plus"),h="class";if("undefined"==typeof t.button||n.helper.data("namespace")!==y||!u.insideWorkzone(t.pageX,t.pageY))return!1;for(a=r.hasClass(u.res(h,"cwdfile"))?u.cwdId2Hash(r.attr("id")):r.hasClass(u.res(h,"navdir"))?u.navId2Hash(r.attr("id")):j,i=s.length;i--;)o=s[i],o!=a&&I[o].phash!=a?l.push(o):(p&&o!==a&&I[a].write?c:d).push(o);return!d.length&&(n.helper.data("droped",!0),c.length&&(n.helper.hide(),u.exec("duplicate",c,{_userAction:!0})),void(l.length&&(n.helper.hide(),u.clipboard(l,!p),u.exec("paste",a,{_userAction:!0},a).always(function(){u.clipboard([]),u.trigger("unlockfiles",{files:s})}),u.trigger("drop",{files:s}))))}},this.enabled=function(){return z&&this.visible()},this.visible=function(){return m[0].elfinder&&m.is(":visible")},this.isRoot=function(e){return!(!e.isroot&&e.phash)},this.root=function(t,n){t=t||j;var i,a;if(!n&&(e.each(u.roots,function(e,n){if(0===t.indexOf(e))return i=n,!1}),i))return i;for(i=I[t];i&&i.phash&&(n||!i.isroot);)i=I[i.phash];if(i)return i.hash;for(;a in I&&I.hasOwnProperty(a);)if(i=I[a],"directory"===i.mime&&!i.phash&&i.read)return i.hash;return""},this.cwd=function(){return I[j]||{}},this.option=function(t,n){var i,a;return n=n||j,u.optionsByHashes[n]&&"undefined"!=typeof u.optionsByHashes[n][t]?u.optionsByHashes[n][t]:!u.hasVolOptions||j===n||(a=u.file(n))&&a.phash===j?S[t]||"":(i="",e.each(u.volOptions,function(e,a){if(0===n.indexOf(e))return i=a[t]||"",!1}),i)},this.getDisabledCmds=function(t,n){var i={hidden:!0};return Array.isArray(t)||(t=[t]),e.each(t,function(e,t){var n=u.option("disabledFlip",t);n&&Object.assign(i,n)}),n?i:Object.keys(i)},this.file=function(e,t){return e?I[e]||(t?M[e]:void 0):void 0},this.files=function(t){var n={};return t?F[t]?(e.each(F[t],function(e){I[e]?n[e]=I[e]:delete F[t][e]}),Object.assign({},n)):{}:Object.assign({},I)},this.parents=function(e){for(var t,n=[];e&&(t=this.file(e));)n.unshift(t.hash),e=t.phash;return n},this.path2array=function(e,t){for(var n,i=[];e;){if(!(n=I[e])||!n.hash){i=[];break}i.unshift(t&&n.i18?n.i18:n.name),e=n.isroot?null:n.phash}return i},this.path=function(t,n,i){var a=I[t]&&I[t].path?I[t].path:this.path2array(t,n).join(S.separator);if(i&&I[t]){i=Object.assign({notify:{type:"parents",cnt:1,hideCnt:!0}},i);var o,r=e.Deferred(),s=i.notify,l=!1,c=function(){u.request({data:{cmd:"parents",target:I[t].phash},notify:s,preventFail:!0}).done(d).fail(function(){r.reject()})},d=function(){u.one("parentsdone",function(){a=u.path(t,n),""===a&&l?(l=!1,c()):(s&&(clearTimeout(o),s.cnt=-parseInt(s.cnt||0),u.notify(s)),r.resolve(a))})};return a?r.resolve(a):(u.ui.tree?(s&&(o=setTimeout(function(){u.notify(s)},u.notifyDelay)),l=!0,d(!0)):c(),r)}return a},this.url=function(t,n){var i,a=I[t],o=n||{},r=o.async||!1,s=o.temporary||!1,l=o.onetime&&u.option("onetimeUrl",t)||!1,c=o.absurl||!1,d=r||l?e.Deferred():null,p=function(e){return e&&c&&(e=u.convAbsUrl(e)),e},h=function(n){if(n)return p(n);if(a.url)return p(a.url);if("undefined"==typeof i&&(i=f()),i)return p(i+e.map(u.path2array(t),function(e){return encodeURIComponent(e)}).slice(1).join("/"));var o=Object.assign({},u.customData,{cmd:"file",target:a.hash});return u.oldAPI&&(o.cmd="open",o.current=a.phash),p(u.options.url+(u.options.url.indexOf("?")===-1?"?":"&")+e.param(o,!0))},f=function(){return u.option("url",!u.isRoot(a)&&a.phash||a.hash)};if(!a||!a.read)return r?d.resolve(""):"";if(!l||a.url&&"1"!=a.url||(i=f()))if("1"==a.url||s&&!a.url&&!(i=f()))this.request({data:{cmd:"url",target:t,options:{temporary:s?1:0}},preventDefault:!0,options:{async:r},notify:r?{type:s?"file":"url",cnt:1,hideCnt:!0}:{},progressBar:o.progressBar}).done(function(e){a.url=e.url||""}).fail(function(){a.url=""}).always(function(){var e;return a.url&&s&&(e=a.url,a.url="1"),r?void d.resolve(h(e)):h(e)});else{if(!r)return h();d.resolve(h())}else r=!0,this.request({data:{cmd:"url",target:t,options:{onetime:1}},preventDefault:!0,options:{async:r},notify:{type:"file",cnt:1,hideCnt:!0},progressBar:o.progressBar}).done(function(e){d.resolve(p(e.url||""))}).fail(function(){d.resolve("")});return r?d:void 0},this.forExternalUrl=function(e,t){var n=u.option("onetimeUrl",e),i={async:!0,absurl:!0};return i[n?"onetime":"temporary"]=!0,u.url(e,Object.assign({},t,i))},this.openUrl=function(t,n,i,a){var o=I[t],r="",s=(a||{}).onetimeSize||5242880;return o&&o.read?n&&"sameorigin"!==n||(o.url?1!=o.url&&(r=o.url):S.url&&0===o.hash.indexOf(u.cwd().volumeid)&&(r=S.url+e.map(this.path2array(t),function(e){return encodeURIComponent(e)}).slice(1).join("/")),n&&!this.isSameOrigin(r)||!r)?i&&this.hasParrotHeaders()?(a?delete a.onetimeSize:a={},!a.onetime&&!a.temporary&&o.size>s&&(o.mime.match(/^video|audio/)?a.temporary=!0:a.onetime=!0),a.onetime||a.temporary?this.url(o.hash,Object.assign({async:!0},a)).done(function(e){i(e)}).fail(function(){i("")}):this.getContents(t,"blob",a).done(function(e){r=(window.URL||window.webkitURL).createObjectURL(e),i(r)}).fail(function(){i("")})):(r=this.options.url,r=r+(r.indexOf("?")===-1?"?":"&")+(this.oldAPI?"cmd=open¤t="+o.phash:"cmd=file")+"&target="+o.hash+"&_t="+(o.ts||parseInt(+new Date/1e3)),n===!0&&(r+="&download=1"),e.each(this.customData,function(e,t){r+="&"+encodeURIComponent(e)+"="+encodeURIComponent(t)}),i?void i(r):r):(r+=(r.match(/\?/)?"&":"?")+"_".repeat((r.match(/[\?&](_+)t=/g)||["&t="]).sort().shift().match(/[\?&](_*)t=/)[1].length+1)+"t="+(o.ts||parseInt(+new Date/1e3)),i?void i(r):r):""},this.tmb=function(t){var n,i,a="elfinder-cwd-bgurl",o="",r={},s=0;return!(!e.isPlainObject(t)||(u.searchStatus.state&&0!==t.hash.indexOf(u.cwd().volumeid)?(n=u.option("tmbUrl",t.hash),i=u.option("tmbCrop",t.hash)):(n=S.tmbUrl,i=S.tmbCrop),i&&(a+=" elfinder-cwd-bgurl-crop"),"self"===n&&0===t.mime.indexOf("image/")?(o=u.openUrl(t.hash),a+=" elfinder-cwd-bgself"):(u.oldAPI||n)&&t&&t.tmb&&1!=t.tmb?o=n+t.tmb:u.newAPI&&t&&t.tmb&&1!=t.tmb&&(o=t.tmb),!o))&&("self"!==n&&(t.ts&&(r._t=t.ts),S.tmbReqCustomData&&Object.keys(this.customData).length&&(r=Object.assign(r,this.customData)),Object.keys(r).length&&(o+=o.match(/\?/)?"&":"?",e.each(r,function(e,t){o+=(0===s++?"":"&")+encodeURIComponent(e)+"="+encodeURIComponent(t)}))),{url:o,className:a})},this.selected=function(){return E.slice(0)},this.selectedFiles=function(){return e.map(E,function(e){return I[e]?Object.assign({},I[e]):null})},this.fileByName=function(e,t){var n;for(n in I)if(I.hasOwnProperty(n)&&I[n].phash==t&&I[n].name==e)return I[n]},this.validResponse=function(e,t){return t.error||this.rules[this.rules[e]?e:"defaults"](t)},this.returnBytes=function(e){var t;return isNaN(e)?(e||(e=""),e=e.replace(/b$/i,""),t=e.charAt(e.length-1).toLowerCase(),e=e.replace(/[tgmk]$/i,""),"t"==t?e=1024*e*1024*1024*1024:"g"==t?e=1024*e*1024*1024:"m"==t?e=1024*e*1024:"k"==t&&(e=1024*e),e=isNaN(e)?0:parseInt(e)):(e=parseInt(e),e<1&&(e=0)),e},this.request=function(t){var n,i,a,o,r=this,l=this.options,c=e.Deferred(),d=(+new Date).toString(16)+Math.floor(1e3*Math.random()).toString(16),p=Object.assign({},r.customData,{mimes:l.onlyMimes},t.data||t),u=p.cmd,h="binary"===(t.options||{}).dataType,f=!t.asNotOpen&&"open"===u,m=1===p.tree,g=!(h||t.preventDefault||t.preventFail),v=!(h||t.preventDefault||t.preventDone),b=t.progressVal||20,y=null,w=!1,x=t.progressBar?{}:t.notify?Object.assign({progress:b*t.notify.cnt},t.notify):{},k=!!t.cancel,C=h||!!t.raw,z=t.syncOnFail,T=!!t.lazy,A=t.prepare,I=t.navigate,M=(t.options||{}).cache,F=Object.assign({url:l.url,async:!0,type:this.requestType,dataType:"json",cache:r.api>=2.1029,data:p,headers:this.customHeaders,xhrFields:this.xhrFields,progress:function(e){var n=e.loaded/e.total*100;if(y&&clearTimeout(y),t.progressBar)try{t.progressBar.width(n+"%")}catch(e){}else w&&x.type&&(n*=x.cnt,b=500)n=["errResponse","errServerError","HTTP error "+e.status];else{if(414==e.status&&"get"===F.type)return F.type="post",r.abortXHR(e),void(c.xhr=e=r.transport.send(F).fail(n).done(U));n=e.quiet?"":["errConnect","HTTP error "+e.status]}}r.trigger(u+"done"),c.reject({error:n},e,t)},U=function(t){if(r.currentReqCmd=u,t.debug&&r.responseDebug(t),r.setCustomHeaderByXhr(i),C)return r.abortXHR(i),t&&t.debug&&r.debug("backend-debug",t),c.resolve(t);if(!t)return c.reject({error:["errResponse","errDataEmpty"]},i,t);if(!e.isPlainObject(t))return c.reject({error:["errResponse","errDataNotJSON"]},i,t);if(t.error)return f&&e.each(r.leafRoots,function(t,n){r.leafRoots[t]=e.grep(n,function(e){return e!==p.target})}),c.reject({error:t.error},i,t);var n=function(){var n,a=function(n){r.leafRoots[p.target]&&t[n]&&e.each(r.leafRoots[p.target],function(e,i){var a;(a=r.file(i))&&t[n].push(a)})},o=function(){r.textMimes={},e.each(r.res("mimes","text"),function(){r.textMimes[this.toLowerCase()]=!0})};return f&&!m?a("files"):"tree"===u&&a("tree"),t=r.normalize(t),r.validResponse(u,t)?(f&&(r.api||(r.api=t.api||1,"2.0"==r.api&&"undefined"!=typeof t.options.uploadMaxSize&&(r.api="2.1"),r.newAPI=r.api>=2,r.oldAPI=!r.newAPI),t.textMimes&&Array.isArray(t.textMimes)&&(r.resources.mimes.text=t.textMimes,o()),!r.textMimes&&o(),t.options&&(S=Object.assign({},O,t.options)),t.netDrivers&&(r.netDrivers=t.netDrivers),t.maxTargets&&(r.maxTargets=t.maxTargets),p.init&&(r.uplMaxSize=r.returnBytes(t.uplMaxSize),r.uplMaxFile=t.uplMaxFile?Math.min(parseInt(t.uplMaxFile),50):20)),"function"==typeof A&&A(t),I&&(n=I.target||"added",t[n]&&t[n].length&&r.one(u+"done",function(){var i=t[n],a=r.findCwdNodes(i),o=function(){var t=r.cwd().hash;return e.map(i,function(e){return e.phash&&t===e.phash?e.hash:null})},s=o(),l=function(t){var n,i,a,l=void 0,c=t.action?t.action.data:void 0;return(c||s.length)&&t.action&&(i=t.action.msg)&&(n=t.action.cmd)&&(!t.action.cwdNot||t.action.cwdNot!==r.cwd().hash)&&(a=t.action.done,c=t.action.data,l=e("
              ").append(e('").on("mouseenter mouseleave",function(t){e(this).toggleClass("ui-state-hover","mouseenter"==t.type)}).on("click",function(){r.exec(n,c||s,{_userAction:!0,_currentType:"toast",_currentNode:e(this)}),a&&r.one(n+"done",function(){"function"==typeof a?a():"select"===a&&r.trigger("selectfiles",{files:o()})})}))),delete t.action,t.extNode=l,t};I.toast||(I.toast={}),!I.noselect&&r.trigger("selectfiles",{files:r.searchStatus.state>1?e.map(i,function(e){return e.hash}):s}),a.length?(I.noscroll||(a.first().trigger("scrolltoview",{blink:!1}),r.resources.blink(a,"lookme")),e.isPlainObject(I.toast.incwd)&&r.toast(l(I.toast.incwd))):e.isPlainObject(I.toast.inbuffer)&&r.toast(l(I.toast.inbuffer))})),c.resolve(t),void(t.debug&&r.debug("backend-debug",t))):c.reject({error:t.norError||"errResponse"},i,t)};r.abortXHR(i),T?r.lazy(n):n()},P=function(e){i&&"pending"===i.state()&&(r.abortXHR(i,{quiet:!0,abort:!0}),(!e||"unload"!==e.type&&"destroy"!==e.type)&&r.autoSync())},R=function(e){if(r.trigger(u+"done"),"autosync"==e.type){if("stop"!=e.data.action)return}else if(!("unload"==e.type||"destroy"==e.type||"openxhrabort"==e.type||e.data.added&&e.data.added.length))return;P(e)},_=function(t){var n=function(){z=!1,c.reject()};if(t&&"cmd"===t)return u;if(f){if(ie&&"pending"===ie.state()){if(ie._target===p.target)return c.reject("openabort");ie.xhr?ie.xhr.queueAbort():ie.reject("openabort")}ie=c,ie._target=p.target}if(c.always(function(){delete F.headers["X-elFinderReqid"],f&&(ie=null)}).fail(function(t,n,i){var a,s;f&&"openabort"===t&&(t="",z=!1),a={cmd:u,err:t,xhr:n,rc:i},0===t&&ne.length&&(ne=e.grep(ne,function(e){return e("cmd")!==u})),r.trigger("requestError",a),a._getEvent&&a._getEvent().isDefaultPrevented()&&(g=!1,z=!1,t&&(t.error="")),P(),f&&(o=r.file(p.target),o&&o.volumeid&&r.isRoot(o)&&delete r.volumeExpires[o.volumeid]),r.trigger(u+"fail",i),s="object"==typeof t?t.error:t,s&&(g?r.error(s):r.debug("error",r.i18n(s))),z&&r.sync()}),!u)return z=!1,c.reject({error:"errCmdReq"});if(r.maxTargets&&p.targets&&p.targets.length>r.maxTargets)return z=!1,c.reject({error:["errMaxTargets",r.maxTargets]});if(v&&c.done(E),f){for(;a=q.pop();)a.queueAbort();if(j!==p.target)for(;a=H.pop();)a.queueAbort()}return e.inArray(u,(r.cmdsToAdd+" autosync").split(" "))!==-1&&("autosync"!==u&&(r.autoSync("stop"),c.always(function(){r.autoSync()})),r.trigger("openxhrabort")),delete F.preventFail,r.api>=2.1029&&(M?F.headers["X-elFinderReqid"]=d:Object.assign(F.data,{reqid:d})),c.syncOnFail=function(e){z=!!e},te++,c.xhr=i=r.transport.send(F).always(function(){F._xhr&&"undefined"!=typeof F._xhr.responseURL&&(i.responseURL=F._xhr.responseURL||""),--te,ne.length&&ne.shift()()}).fail(D).done(U),r.api>=2.1029&&(i._requestId=d),f||p.compare&&"info"===u?(i.queueAbort=n,q.unshift(i),p.compare&&r.bind(r.cmdsToAdd+" autosync openxhrabort",R),c.always(function(){var t=e.inArray(i,q);p.compare&&r.unbind(r.cmdsToAdd+" autosync openxhrabort",R),t!==-1&&q.splice(t,1)})):e.inArray(u,r.abortCmdsOnOpen)!==-1&&(i.queueAbort=n,H.unshift(i),c.always(function(){var t=e.inArray(i,H);t!==-1&&H.splice(t,1)})),r.bind("unload destroy",R),c.always(function(){r.unbind("unload destroy",R)}),c},N=function(){return x.type&&x.cnt&&(k&&(x.cancel=c,t.eachCancel&&(x.id=+new Date)),n=setTimeout(function(){y=setTimeout(L,1e3),r.notify(x),w=!0,c.always(function(){x.cnt=-(parseInt(x.cnt)||0),r.notify(x),w=!1})},r.notifyDelay),c.always(function(){clearTimeout(n)})),te=2&&(j!==this.root()&&d.push(this.request({data:{cmd:"parents",target:j},preventDefault:!0})),e.each(p(),function(e,t){d.push(o.request({data:{cmd:t.cmd,target:t.target},preventDefault:!0}))})),e.when.apply(e,d).fail(function(t,i){a=i&&200!=i.status,n&&e.inArray("errOpen",t)===-1?l.reject(t&&0!=i.status?t:void 0):(l.reject(t),o.parseError(t)&&o.request({data:{cmd:"open",target:o.lastDir("")||o.root(),tree:1,init:1},notify:{type:"open",cnt:1,hideCnt:!0}}))}).done(function(n){var a,r,d;if(n.cwd.compare&&s===n.cwd.compare)return l.reject();if(a={tree:[]},r=arguments.length,r>1)for(d=1;d=0}));var p=o.diff(n.files.concat(a&&a.tree?a.tree:[]),t);return p.added.push(n.cwd),o.updateCache(p),p.removed.length&&o.remove(p),p.added.length&&o.add(p),p.changed.length&&o.change(p),l.resolve(p)}).always(function(){o.syncStopper=!1,o.autoSync()}),l},this.upload=function(e){return this.transport.upload(e,this)},this.shortcut=function(t){var n,i,a,o,r;if(this.options.allowShortcuts&&t.pattern&&"function"==typeof t.callback)for(n=t.pattern.toUpperCase().split(/\s+/),o=0;o0?a:a.charCodeAt(0):a>0?a:e.ui.keyCode[a],a&&!U[i]&&(U[i]={keyCode:a,altKey:e.inArray("ALT",r)!=-1,ctrlKey:e.inArray("CTRL",r)!=-1,shiftKey:e.inArray("SHIFT",r)!=-1,type:t.type||"keydown",callback:t.callback,description:t.description,pattern:i});return this},this.shortcuts=function(){var t=[];return e.each(U,function(e,n){t.push([n.pattern,u.i18n(n.description)])}),t},this.clipboard=function(t,n){var i=function(){return e.map(P,function(e){return e.hash})};return void 0!==t&&(P.length&&this.trigger("unlockfiles",{files:i()}),R={},P=e.map(t||[],function(e){var t=I[e];return t?(R[e]=!0,{hash:e,phash:t.phash,name:t.name,mime:t.mime,read:t.read,locked:t.locked,cut:!!n}):null}),this.trigger("changeclipboard",{clipboard:P.slice(0,P.length)}),n&&this.trigger("lockfiles",{files:i()})),P.slice(0,P.length)},this.isCommandEnabled=function(e,t){var n,i,a=u.cwd().volumeid||"";return!t&&u.searchStatus.state>1&&u.selected().length&&(t=u.selected()[0]),n=!t||a&&0===t.indexOf(a)?S.disabledFlip:u.option("disabledFlip",t),i=this._commands[e],!!i&&(i.alwaysEnabled||!n[e])},this.exec=function(t,n,i,a){var o,r;return!a&&this.commandMap[t]&&"hidden"!==this.commandMap[t]&&(t=this.commandMap[t]),"open"===t&&((this.searchStatus.state||this.searchStatus.ininc)&&this.trigger("searchend",{noupdate:!0}),this.autoSync("stop")),!a&&n&&(e.isArray(n)?n.length&&(a=n[0]):a=n),o=this._commands[t]&&this.isCommandEnabled(t,a)?this._commands[t].exec(n,i):e.Deferred().reject("errUnknownCmd"),r=typeof o,"object"===r&&o.promise||(u.debug("warning",'"cmd.exec()" should be returned "$.Deferred" but cmd "'+t+'" returned "'+r+'"'),o=e.Deferred().resolve()),this.trigger("exec",{dfrd:o,cmd:t,files:n,opts:i,dstHash:a}),o},this.dialog=function(t,n){var i=e("
              ").append(t).appendTo(m).elfinderdialog(n,u),a=i.closest(".ui-dialog"),o=function(){!i.data("draged")&&i.is(":visible")&&i.elfinderdialog("posInit")};return a.length&&(u.bind("resize",o),a.on("remove",function(){u.unbind("resize",o)})),i},this.toast=function(t){return e('
              ').appendTo(this.ui.toast).elfindertoast(t||{},this)},this.getUI=function(t){return t?this.ui[t]||e():m},this.getCommand=function(e){return void 0===e?this._commands:this._commands[e]},this.resize=function(t,n){var i,a=function(){for(var e=m.outerHeight(!0)-m.innerHeight(),t=m;t.get(0)!==W.get(0)&&(t=t.parent(),e+=t.outerHeight(!0)-t.innerHeight(),t.parent().length););return e},o=!m.hasClass("ui-resizable"),r=m.data("resizeSize")||{w:0,h:0},s={};W&&W.data("resizeTm")&&clearTimeout(W.data("resizeTm")),u.options.noResizeBySelf||("string"==typeof n&&(i=n.match(/^([0-9.]+)%$/))&&(W&&W.length||(W=e(window)),W.data("marginToMyNode")||W.data("marginToMyNode",a()),W.data("fitToBaseFunc")||W.data("fitToBaseFunc",function(e){var t=W.data("resizeTm");e.preventDefault(),e.stopPropagation(),t&&cancelAnimationFrame(t),m.hasClass("elfinder-fullscreen")||u.UA.Mobile&&W.data("rotated")===u.UA.Rotated||(W.data("rotated",u.UA.Rotated),W.data("resizeTm",requestAnimationFrame(function(){u.restoreSize()})))}),"undefined"==typeof W.data("rotated")&&W.data("rotated",u.UA.Rotated),n=W.height()*(i[1]/100)-W.data("marginToMyNode"),W.off("resize."+u.namespace,W.data("fitToBaseFunc")),o&&W.on("resize."+u.namespace,W.data("fitToBaseFunc"))),m.css({width:t,height:parseInt(n)})),s.w=Math.round(m.width()),s.h=Math.round(m.height()),m.data("resizeSize",s),s.w===r.w&&s.h===r.h||(m.trigger("resize"),this.trigger("resize",{width:s.w,height:s.h}))},this.restoreSize=function(){this.resize(N,L)},this.show=function(){m.show(),this.enable().trigger("show")},this.hide=function(){this.options.enableAlways&&(T=z,z=!1),this.disable(),this.trigger("hide"),m.hide()},this.lazy=function(t,n,i){var a=function(e){var t,n=m.data("lazycnt");e?(t=!m.data("lazyrepaint")&&i.repaint,n?m.data("lazycnt",++n):m.data("lazycnt",1).addClass("elfinder-processing"),t&&m.data("lazyrepaint",!0).css("display")):n&&n>1?m.data("lazycnt",--n):(t=m.data("lazyrepaint"),m.data("lazycnt",0).removeData("lazyrepaint").removeClass("elfinder-processing"),t&&m.css("display"),u.trigger("lazydone"))},o=e.Deferred(),r=function(){o.resolve(t.call(o)),a(!1)};return n=n||0,i=i||{},a(!0),n?setTimeout(r,n):requestAnimationFrame(r),o},this.destroy=function(){m&&m[0].elfinder&&(m.hasClass("elfinder-fullscreen")&&u.toggleFullscreen(m),this.options.syncStart=!1,this.autoSync("forcestop"),this.trigger("destroy").disable(),P=[],E=[],D={},U={},e(window).off("."+y),e(document).off("."+y),u.trigger=function(){},e(K).remove(),m.off().removeData().empty().append(v.contents()).attr("class",v.attr("class")).attr("style",v.attr("style")),delete m[0].elfinder,e.each(g,function(t,n){e.each(n,function(e,t){m.on(t.type+(t.namespace?"."+t.namespace:""),t.selector,t.handler)})}))},this.autoSync=function(t){var n;if(u.options.sync>=1e3){if(r&&(clearTimeout(r),r=null,u.trigger("autosync",{action:"stop"})),"stop"===t?++X:X=Math.max(0,--X),X||"forcestop"===t||!u.options.syncStart)return;n=function(t){var i;S.syncMinMs&&(t||r)&&(t&&u.trigger("autosync",{action:"start"}),i=Math.max(u.options.sync,S.syncMinMs),r&&clearTimeout(r),r=setTimeout(function(){var t,a=!0,o=j;S.syncChkAsTs&&I[o]&&(t=I[o].ts)?u.request({data:{cmd:"info",targets:[o],compare:t,reload:1},preventDefault:!0}).done(function(e){var i;a=!0,e.compare&&(i=e.compare,i==t&&(a=!1)),a?u.sync(o).always(function(){i&&(I[o].ts=i),n()}):n()}).fail(function(t,a){var o=u.parseError(t);o&&0!=a.status?(u.error(o),Array.isArray(o)&&e.inArray("errOpen",o)!==-1&&u.request({data:{cmd:"open",target:u.lastDir("")||u.root(),tree:1,init:1},notify:{type:"open",cnt:1,hideCnt:!0}})):r=setTimeout(function(){n()},i)}):u.sync(j,!0).always(function(){n()})},i))},n(!0)}},this.insideWorkzone=function(e,t,n){var i=this.getUI("workzone").data("rectangle");return n=n||1,!(ei.left+i.width+n||ti.top+i.height+n)},this.toFront=function(t){var n=m.children(".ui-front").removeClass("elfinder-frontmost"),i=n.last();n.css("z-index",""),e(t).addClass("ui-front elfinder-frontmost").css("z-index",i.css("z-index")+1)},this.toHide=function(t,n){var i,a=e(t);!n&&a.hide(),a.hasClass("elfinder-frontmost")&&(a.removeClass("elfinder-frontmost"),i=m.children(".ui-front:visible:not(.elfinder-frontmost)").last(),i.length&&requestAnimationFrame(function(){m.children(".elfinder-frontmost:visible").length||(u.toFront(i),i.trigger("frontmost"))}))},this.getMaximizeCss=function(){return{width:"100%",height:"100%",margin:0,top:0,left:0,display:"block",position:"fixed",zIndex:Math.max(u.zIndex?u.zIndex+1:0,1e3),maxWidth:"",maxHeight:""}},function(){re&&u.UA.Fullscreen&&(u.UA.Fullscreen=!1,se&&"undefined"!=typeof se.attr("allowfullscreen")&&(u.UA.Fullscreen=!0));var t,n,i,a,o="elfinder-fullscreen",r="elfinder-fullscreen-native",s=function(){var t=0,n=0;e.each(m.children(".ui-dialog,.ui-draggable"),function(i,a){var o=e(a),r=o.position();r.top<0&&(o.css("top",t),t+=20),r.left<0&&(o.css("left",n),n+=20)})},l=function(){var i=u.storage("useFullscreen");a=u.UA.Fullscreen&&(i?i>0:"screen"===u.options.commandsOptions.fullscreen.mode)?{fullElm:function(){return document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||null},exitFull:function(){return document.exitFullscreen?document.exitFullscreen():document.webkitExitFullscreen?document.webkitExitFullscreen():document.mozCancelFullScreen?document.mozCancelFullScreen():document.msExitFullscreen?document.msExitFullscreen():void 0},toFull:function(e){return e.requestFullscreen?e.requestFullscreen():e.webkitRequestFullscreen?e.webkitRequestFullscreen():e.mozRequestFullScreen?e.mozRequestFullScreen():!!e.msRequestFullscreen&&e.msRequestFullscreen()}}:{fullElm:function(){var e;return m.hasClass(o)?m.get(0):(e=m.find("."+o),e.length?e.get(0):null)},exitFull:function(){var i;e(window).off("resize."+y,d),void 0!==n&&e("body").css("overflow",n),n=void 0,t&&(i=t.elm,c(i),e(i).trigger("resize",{fullscreen:"off"})),e(window).trigger("resize")},toFull:function(t){return n=e("body").css("overflow")||"",e("body").css("overflow","hidden"),e(t).css(u.getMaximizeCss()).addClass(o).trigger("resize",{fullscreen:"on"}),s(),e(window).on("resize."+y,d).trigger("resize"),!0}}},c=function(n){t&&t.elm==n&&(e(n).removeClass(o+" "+r).attr("style",t.style),t=null)},d=function(t){var n;t.target===window&&(i&&cancelAnimationFrame(i),i=requestAnimationFrame(function(){(n=a.fullElm())&&e(n).trigger("resize",{fullscreen:"on"})}))};l(),e(document).on("fullscreenchange."+y+" webkitfullscreenchange."+y+" mozfullscreenchange."+y+" MSFullscreenChange."+y,function(n){if(u.UA.Fullscreen){var l=a.fullElm(),p=e(window);i&&cancelAnimationFrame(i),null===l?(p.off("resize."+y,d),t&&(l=t.elm,c(l),e(l).trigger("resize",{fullscreen:"off"}))):(e(l).addClass(o+" "+r).attr("style","width:100%; height:100%; margin:0; padding:0;").trigger("resize",{fullscreen:"on"}),p.on("resize."+y,d),s()),p.trigger("resize")}}),u.toggleFullscreen=function(n,i){var o=e(n).get(0),r=null;if(r=a.fullElm()){if(r==o){if(i===!0)return r}else if(i===!1)return r;return a.exitFull(),null}return i===!1?null:(l(),t={elm:o,style:e(o).attr("style")},a.toFull(o)!==!1?o:(t=null,null))}}(),function(){var t,n="elfinder-maximized",i=function(e){if(e.target===window&&e.data&&e.data.elm){var n=e.data.elm;t&&cancelAnimationFrame(t),t=requestAnimationFrame(function(){n.trigger("resize",{maximize:"on"})})}},a=function(t){e(window).off("resize."+y,i),e("body").css("overflow",t.data("bodyOvf")),t.removeClass(n).attr("style",t.data("orgStyle")).removeData("bodyOvf").removeData("orgStyle"),t.trigger("resize",{maximize:"off"})},o=function(t){t.data("bodyOvf",e("body").css("overflow")||"").data("orgStyle",t.attr("style")).addClass(n).css(u.getMaximizeCss()),e("body").css("overflow","hidden"),e(window).on("resize."+y,{elm:t},i),t.trigger("resize",{maximize:"on"})};u.toggleMaximize=function(t,i){var r=e(t),s=r.hasClass(n);if(s){if(i===!0)return;a(r)}else{if(i===!1)return;o(r)}}}(),Object.assign(e.ui.keyCode,{F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,DIG0:48,DIG1:49,DIG2:50,DIG3:51,DIG4:52,DIG5:53,DIG6:54,DIG7:55,DIG8:56,DIG9:57,NUM0:96,NUM1:97,NUM2:98,NUM3:99,NUM4:100,NUM5:101,NUM6:102,NUM7:103,NUM8:104,NUM9:105,CONTEXTMENU:93,DOT:190}),this.dragUpload=!1,this.xhrUpload=("undefined"!=typeof XMLHttpRequestUpload||"undefined"!=typeof XMLHttpRequestEventTarget)&&"undefined"!=typeof File&&"undefined"!=typeof FormData,this.transport={},"object"==typeof this.options.transport&&(this.transport=this.options.transport,"function"==typeof this.transport.init&&this.transport.init(this)),"function"!=typeof this.transport.send&&(this.transport.send=function(t){return u.UA.IE||(t._xhr=new XMLHttpRequest,t.xhr=function(){return t.progress&&t._xhr.addEventListener("progress",t.progress),t._xhr}),e.ajax(t)}),"iframe"==this.transport.upload?this.transport.upload=e.proxy(this.uploads.iframe,this):"function"==typeof this.transport.upload?this.dragUpload=!!this.options.dragUploadAllow:this.xhrUpload&&this.options.dragUploadAllow?(this.transport.upload=e.proxy(this.uploads.xhr,this),this.dragUpload=!0):this.transport.upload=e.proxy(this.uploads.iframe,this),this.decodeRawString=function(e){var t=function(e){var t,n,i;for(t=0,n=e.length,i=[];t=55296&&a<=56319?o.push((1023&a)+64<<10|1023&e[++n]):o.push(a);return o},i=function(e){var t,n,i,a,o=String.fromCharCode;for(t=0,n=e.length,a="";i=e[t],t=194?o((31&i)<<6|63&e[++t]):i<=239&&i>=224?o((15&i)<<12|(63&e[++t])<<6|63&e[++t]):i<=247&&i>=240?o(55296|((7&i)<<8|(63&e[++t])<<2|e[++t]>>>4&3)-64,56320|(15&e[t++])<<6|63&e[t]):o(65533);return a};return i(n(e))},this.getContents=function(t,n,i){var a,o,r=this,s=e.Deferred(),l=n||"arraybuffer";return s.fail(function(){o&&"pending"===o.state()&&o.reject()}),a=r.openUrl(t),r.isSameOrigin(a)||(a=r.openUrl(t,!0)),o=r.request(Object.assign({data:{cmd:"get"},options:{url:a,type:"get",cache:!0,dataType:"binary",responseType:l,processData:!1},notify:{type:"file",cnt:1,hideCnt:!0},cancel:!0},i||{})).fail(function(){s.reject()}).done(function(e){s.resolve(e)}),s},this.getBinaryByUrl=function(t,n,i){var a,o=this,r=e.Deferred();return r.fail(function(){a&&"pending"===a.state()&&a.reject()}),a=o.request(Object.assign({data:{cmd:"get"},options:Object.assign({type:"get",cache:!0,dataType:"binary",responseType:"blob",processData:!1},t)},i||{})).fail(function(){r.reject()}).done(function(e){n&&n(e),r.resolve(e)}),r},this.getMimetype=function(e,t){var n,i,a=t;return i=(e+"").match(/\.([^.]+)$/),i&&(n=i[1])&&(o||(o=u.arrayFlip(u.mimeTypes)),(a=o[n.toLowerCase()])||(a=t)),a},u.hashCheckers=[],function(t){var n={};window.Worker&&window.ArrayBuffer&&(t.options.cdns.sparkmd5&&(n.SparkMD5=!0,t.hashCheckers.push("md5")),t.options.cdns.jssha&&(n.jsSHA=!0,t.hashCheckers=t.hashCheckers.concat(["sha1","sha224","sha256","sha384","sha512","sha3-224","sha3-256","sha3-384","sha3-512","shake128","shake256"]))),t.getContentsHashes=function(i,a,o,r){var s,l=e.Deferred(),c=t.arrayFlip(a||["md5"],!0),d=[],p={},u=o?o:{shake128len:256,shake256len:512};return l.fail(function(){s&&s.reject()}),Object.keys(n).length?s=t.getContents(i,"arraybuffer",r).done(function(a){c.md5&&n.SparkMD5&&d.push(function(){var o=e.Deferred();try{var r=t.getWorker();o.fail(function(){r&&r.terminate()}),r.onmessage=function(e){if(r&&r.terminate(),e.data.hash){var n;p.md5=e.data.hash,(n=t.file(i))&&(n.md5=p.md5)}else e.data.error&&(p.md5=e.data.error);l.notify(p),o.resolve()},r.onerror=function(e){o.reject()},r.postMessage({scripts:[t.options.cdns.sparkmd5,t.getWorkerUrl("calcfilehash.js")],data:{type:"md5",bin:a}}),l.fail(function(){o.reject()})}catch(s){o.reject(),delete n.SparkMD5}return o}()),n.jsSHA&&e.each(["1","224","256","384","512","3-224","3-256","3-384","3-512","ke128","ke256"],function(o,r){c["sha"+r]&&d.push(function(){var o=e.Deferred();try{var s=t.getWorker();o.fail(function(){s&&s.terminate()}),s.onmessage=function(e){if(s&&s.terminate(),e.data.hash){var n;p["sha"+r]=e.data.hash,(n=t.file(i))&&(n["sha"+r]=p["sha"+r])}else e.data.error&&(p["sha"+r]=e.data.error);l.notify(p),o.resolve()},s.onerror=function(e){o.reject()},s.postMessage({scripts:[t.options.cdns.jssha,t.getWorkerUrl("calcfilehash.js")],data:{type:r,bin:a,hashOpts:u}}),l.fail(function(){o.reject()})}catch(c){o.reject(),delete n.jsSHA}return o}())}),d.length?e.when.apply(null,d).always(function(){l.resolve(p)}):l.reject()}).fail(function(){l.reject()}):l.reject(),l}}(this),this.parseError=function(t){var n=t;return e.isPlainObject(n)&&(n=n.error),n},this.error=function(){var e,t=arguments[0],n=arguments[1]||null;return 1==arguments.length&&"function"==typeof t?u.bind("error",t):(e=this.parseError(t),e!==!0&&e?u.trigger("error",{error:e,opts:n}):this)},e.each(A,function(t,n){u[n]=function(){var t=arguments[0];return 1==arguments.length&&"function"==typeof t?u.bind(n,t):u.trigger(n,e.isPlainObject(t)?t:{})}}),this.enable(function(){!z&&u.api&&u.visible()&&u.ui.overlay.is(":hidden")&&!m.children(".elfinder-dialog."+u.res("class","editing")+":visible").length&&(z=!0,document.activeElement&&document.activeElement.blur(),m.removeClass("elfinder-disabled"))}).disable(function(){T=z,z=!1,m.addClass("elfinder-disabled")}).open(function(){E=[]}).select(function(t){var n=0,i=[];E=e.grep(t.data.selected||t.data.value||[],function(e){return i.length||u.maxTargets&&++n>u.maxTargets?(i.push(e),!1):!!I[e]}),i.length&&(u.trigger("unselectfiles",{files:i,inselect:!0}),u.toast({mode:"warning",msg:u.i18n(["errMaxTargets",u.maxTargets])}))}).error(function(t){var n,i,a={cssClass:"elfinder-dialog-error",title:u.i18n("error"),resizable:!1,destroyOnClose:!0,buttons:{}},o=u.getUI(),r=o.children(".elfinder-dialog-error").length;r
              '+u.i18n(t.data.error),a)):(n=o.children(".elfinder-dialog-error:last").children(".ui-dialog-content:first"),i=n.children(".elfinder-error-counter"),i.length?i.data("cnt",parseInt(i.data("cnt"))+1).html(u.i18n(["moreErrors",i.data("cnt")])):(i=e(''+u.i18n(["moreErrors",1])+"").data("cnt",1),n.append("
              ",i)))}).bind("tmb",function(t){e.each(t.data.images||[],function(e,t){I[e]&&(I[e].tmb=t)})}).bind("searchstart",function(e){Object.assign(u.searchStatus,e.data),u.searchStatus.state=1}).bind("search",function(e){u.searchStatus.state=2}).bind("searchend",function(){u.searchStatus.state=0,u.searchStatus.ininc=!1,u.searchStatus.mixed=!1}).bind("canMakeEmptyFile",function(t){var n=t.data,i={};n&&Array.isArray(n.mimes)&&(n.unshift||(i=u.mimesCanMakeEmpty),e.each(n.mimes,function(){i[this]||(i[this]=u.mimeTypes[this])}),n.unshift&&(u.mimesCanMakeEmpty=Object.assign(i,u.mimesCanMakeEmpty)))}).bind("themechange",function(){requestAnimationFrame(function(){u.trigger("uiresize")})}),!0===this.options.sound&&this.bind("playsound",function(t){var n=K.canPlayType&&K.canPlayType('audio/wav; codecs="1"'),i=t.data&&t.data.soundFile;n&&i&&""!=n&&"no"!=n&&e(K).html('')[0].play()}),e.each(this.options.handlers,function(e,t){u.bind(e,t)}),this.history=new this.history(this),this.roots={},this.leafRoots={},this.volumeExpires={},this._commands={},Array.isArray(this.options.commands)||(this.options.commands=[]),e.inArray("*",this.options.commands)!==-1&&(this.options.commands=Object.keys(this.commands)),this.commandMap={},this.volOptions={},this.hasVolOptions=!1,this.trashes={},this.optionsByHashes={},this.uiAutoHide=[],this.one("open",function(){u.uiAutoHide.length&&setTimeout(function(){u.trigger("uiautohide")},500)}),this.bind("uiautohide",function(){u.uiAutoHide.length&&u.uiAutoHide.shift()()}),this.options.width&&(N=this.options.width),this.options.height&&(L=this.options.height),this.options.heightBase&&(W=e(this.options.heightBase)),B=this.options.soundPath?this.options.soundPath.replace(/\/+$/,"")+"/":this.baseUrl+B,this.options.parrotHeaders&&Array.isArray(this.options.parrotHeaders)&&this.options.parrotHeaders.length?(this.parrotHeaders=this.options.parrotHeaders,e.each(this.parrotHeaders,function(e,t){var n=u.sessionStorage("core-ph:"+t);n&&(u.customHeaders[t]=n)})):this.parrotHeaders=[],u.one("opendone",function(){var t;e(document).on("click."+y,function(t){z&&!u.options.enableAlways&&!e(t.target).closest(m).length&&u.disable()}).on(x+" "+k+" "+C+" "+w,ae),u.options.useBrowserHistory&&e(window).on("popstate."+y,function(t){var n,i,a=t.originalEvent.state||{},o=!!a.thash,r=m.find(".elfinder-frontmost:visible"),s=m.find(".elfinder-navbar-dir,.elfinder-cwd-filename").find("input,textarea");o||(a={thash:u.cwd().hash},e("html,body").animate({scrollTop:m.offset().top})),r.length||s.length?(history.pushState(a,null,location.pathname+location.search+"#elf_"+a.thash),r.length?r.hasClass(u.res("class","preventback"))||(r.hasClass("elfinder-contextmenu")?e(document).trigger(e.Event("keydown",{keyCode:e.ui.keyCode.ESCAPE,ctrlKey:!1,shiftKey:!1,altKey:!1,metaKey:!1})):r.hasClass("elfinder-dialog")?r.elfinderdialog("close"):r.trigger("close")):s.trigger(e.Event("keydown",{keyCode:e.ui.keyCode.ESCAPE,ctrlKey:!1,shiftKey:!1,altKey:!1,metaKey:!1}))):o?!e.isEmptyObject(u.files())&&u.request({data:{cmd:"open",target:a.thash,onhistory:1},notify:{type:"open",cnt:1,hideCnt:!0},syncOnFail:!0}):(n=function(){i.trigger("click")},u.one("open",n,!0),i=u.toast({msg:u.i18n("pressAgainToExit"),onHidden:function(){u.unbind("open",n),history.pushState(a,null,location.pathname+location.search+"#elf_"+a.thash)}}))}),e(window).on("resize."+y,function(e){e.target===this&&(t&&cancelAnimationFrame(t),t=requestAnimationFrame(function(){var e=m.data("resizeSize")||{w:0,h:0},t={w:Math.round(m.width()),h:Math.round(m.height())};m.data("resizeSize",t),t.w===e.w&&t.h===e.h||(m.trigger("resize"),u.trigger("resize",{width:t.w,height:t.h}))}))}).on("beforeunload."+y,function(t){var n,i;if(!u.pauseUnloadCheck()){if(m.is(":visible")&&(u.ui.notify.children().length&&e.inArray("hasNotifyDialog",u.options.windowCloseConfirm)!==-1?n=u.i18n("ntfsmth"):m.find("."+u.res("class","editing")).length&&e.inArray("editingFile",u.options.windowCloseConfirm)!==-1?n=u.i18n("editingFile"):(i=Object.keys(u.selected()).length)&&e.inArray("hasSelectedItem",u.options.windowCloseConfirm)!==-1?n=u.i18n("hasSelected",""+i):(i=Object.keys(u.clipboard()).length)&&e.inArray("hasClipboardData",u.options.windowCloseConfirm)!==-1&&(n=u.i18n("hasClipboard",""+i)),n))return t.returnValue=n,n;u.trigger("unload")}}),e(window).on("message."+y,function(e){var t,n,i=e.originalEvent||null;if(i&&(0===u.convAbsUrl(u.options.url).indexOf(i.origin)||0===u.convAbsUrl(u.uploadURL).indexOf(i.origin)))try{try{if("string"!=typeof i.data)return;if(t=JSON.parse(i.data),"io.studio-42.github"!==t.type)return;n=t.data||null}catch(a){return}n&&(n.error?(t.bind&&u.trigger(t.bind+"fail",n),u.error(n.error)):(n.warning&&u.error(n.warning),u.updateCache(n),n.removed&&n.removed.length&&u.remove(n),n.added&&n.added.length&&u.add(n),n.changed&&n.changed.length&&u.change(n),t.bind&&(u.trigger(t.bind,n),u.trigger(t.bind+"done")),n.sync&&u.sync()))}catch(e){u.sync()}}),u.options.enableAlways?(e(window).on("focus."+y,function(e){e.target===this&&u.enable()}),re&&e(window.top).on("focus."+y,function(){!u.enable()||se&&!se.is(":visible")||requestAnimationFrame(function(){e(window).trigger("focus")})})):re&&e(window).on("blur."+y,function(e){z&&e.target===this&&u.disable()}),re&&m.on("click",function(t){e(window).trigger("focus")}),u.options.enableByMouseOver&&m.on("mouseenter touchstart",function(t){re&&e(window).trigger("focus"),!u.enabled()&&u.enable()}),e(window).on("visibilitychange."+y,function(e){var t=document.hidden||document.webkitHidden||document.msHidden;u.options.syncStart&&u.autoSync(t?"stop":void 0)})}),m[0].elfinder=this,h.push(function(){var t=u.lang,n=u.i18nBaseUrl+"elfinder."+t+".js",i=e.Deferred().done(function(){u.i18[t]&&(u.lang=t),u.trigger("i18load"),c="en"===u.lang?u.i18.en:e.extend(!0,{},u.i18.en,u.i18[u.lang])});return u.i18[t]?i.resolve():(u.lang="en",u.hasRequire?require([n],function(){i.resolve()},function(){i.resolve()}):u.loadScript([n],function(){i.resolve()},{loadType:"tag",error:function(){i.resolve()}})),i}()),d=function(){var t;return u.messages=c.messages,e.fn.selectable&&e.fn.draggable&&e.fn.droppable&&e.fn.resizable&&e.fn.button&&e.fn.slider?m.length?u.options.url?(t=Object.assign({name:u.i18n("name"),perm:u.i18n("perms"),date:u.i18n("modify"),size:u.i18n("size"),kind:u.i18n("kind"),modestr:u.i18n("mode"),modeoct:u.i18n("mode"),modeboth:u.i18n("mode")},u.options.uiOptions.cwd.listView.columnsCustomName),u.getColumnName=function(e){var n=t[e]||u.i18n(e);return"function"==typeof n?n():n},u.direction=c.direction,u.dateFormat=u.options.dateFormat||c.dateFormat,u.fancyFormat=u.options.fancyDateFormat||c.fancyDateFormat,u.nonameDateFormat=(u.options.nonameDateFormat||c.nonameDateFormat).replace(/[\/\\]/g,"_"),u.cssClass="ui-helper-reset ui-helper-clearfix ui-widget ui-widget-content ui-corner-all elfinder elfinder-"+("rtl"==u.direction?"rtl":"ltr")+(u.UA.Touch?" elfinder-touch"+(u.options.resizable?" touch-punch":""):"")+(u.UA.Mobile?" elfinder-mobile":"")+(u.UA.iOS?" elfinder-ios":"")+" "+u.options.cssClass,m.addClass(u.cssClass).on(w,function(){!z&&u.enable()}),function(){var t,n,i,a,o,r=x+"draggable keyup."+y+"draggable";u.draggable={appendTo:m,addClasses:!1,distance:4,revert:!0,refreshPositions:!1,cursor:"crosshair",cursorAt:{left:50,top:47},scroll:!1,start:function(r,s){var l,c,d=s.helper,p=e.grep(d.data("files")||[],function(e){return!!e&&(R[e]=!0,!0)}),h=!1;for(o=m.attr("style"),m.width(m.width()).height(m.height()),t="ltr"===u.direction,n=u.getUI("workzone").data("rectangle"),i=n.top+n.height,a=i-u.getUI("navdock").outerHeight(!0),u.draggingUiHelper=d,l=p.length;l--;)if(c=p[l],I[c].locked){h=!0,d.data("locked",!0);break}!h&&u.trigger("lockfiles",{files:p}),d.data("autoScrTm",setInterval(function(){d.data("autoScr")&&u.autoScroll[d.data("autoScr")](d.data("autoScrVal"))},50))},drag:function(o,r){var s,l,c,d=r.helper;((l=n.top>o.pageY)||ao.pageX?(t?"navbar":"cwd")+(l?"Up":"Down"):(t?"cwd":"navbar")+(l?"Up":"Down"),l||("cwd"===s.substr(0,3)?i0?(e(this).draggable("option",{refreshPositions:!0,elfRefresh:!0}),d.data("refreshPositions",-1)):(e(this).draggable("option",{refreshPositions:!1,elfRefresh:!1}),d.data("refreshPositions",null)))},stop:function(t,n){var i,a=n.helper;e(document).off(r),e(this).elfUiWidgetInstance("draggable")&&e(this).draggable("option",{refreshPositions:!1}),u.draggingUiHelper=null,u.trigger("focus").trigger("dragstop"),a.data("droped")||(i=e.grep(a.data("files")||[],function(e){return!!e}),u.trigger("unlockfiles",{files:i}),u.trigger("selectfiles",{files:u.selected()})),u.enable(),m.attr("style",o),a.data("autoScrTm")&&clearInterval(a.data("autoScrTm"))},helper:function(t,n){var i,a,o,s=this.id?e(this):e(this).parents("[id]:first"),l=e('
              '),c=function(t){var n,i=t.mime,a=u.tmb(t);return n='
              ',a?n=e(n).addClass(a.className).css("background-image","url('"+a.url+"')").get(0).outerHTML:t.icon&&(n=e(n).css(u.getIconStyle(t,!0)).get(0).outerHTML),t.csscls&&(n='
              '+n+"
              "),n};return u.draggingUiHelper&&u.draggingUiHelper.stop(!0,!0),u.trigger("dragstart",{target:s[0],originalEvent:t},!0),i=s.hasClass(u.res("class","cwdfile"))?u.selected():[u.navId2Hash(s.attr("id"))],l.append(c(I[i[0]])).data("files",i).data("locked",!1).data("droped",!1).data("namespace",y).data("dropover",0),(a=i.length)>1&&l.append(c(I[i[a-1]])+''+a+""),e(document).on(r,function(e){if(u._commands.copy){var t=e.shiftKey||e.ctrlKey||e.metaKey;o!==t&&(o=t,l.is(":visible")&&l.data("dropover")&&!l.data("droped")&&(l.toggleClass("elfinder-drag-helper-plus",!!l.data("locked")||o),u.trigger(o?"unlockfiles":"lockfiles",{files:i,helper:l})))}}),l}}}(),u.commands.getfile&&("function"==typeof u.options.getFileCallback?(u.bind("dblclick",function(e){e.preventDefault(),u.exec("getfile").fail(function(){u.exec("open",e.data&&e.data.file?[e.data.file]:void 0)})}),u.shortcut({pattern:"enter",description:u.i18n("cmdgetfile"),callback:function(){u.exec("getfile").fail(function(){u.exec("mac"==u.OS?"rename":"open")})}}).shortcut({pattern:"ctrl+enter",description:u.i18n("mac"==u.OS?"cmdrename":"cmdopen"),callback:function(){u.exec("mac"==u.OS?"rename":"open")}})):u.options.getFileCallback=null),e.each(u.commands,function(t,n){var i,a,o=Object.assign({},n.prototype);if("function"==typeof n&&!u._commands[t]&&(n.prototype.forceLoad||e.inArray(t,u.options.commands)!==-1)){if(i=n.prototype.extendsCmd||""){if("function"!=typeof u.commands[i])return!0;n.prototype=Object.assign({},_,new u.commands[i],n.prototype)}else n.prototype=Object.assign({},_,n.prototype);u._commands[t]=new n,n.prototype=o,a=u.options.commandsOptions[t]||{},i&&u.options.commandsOptions[i]&&(a=e.extend(!0,{},u.options.commandsOptions[i],a)),u._commands[t].setup(t,a),u._commands[t].linkedCmds.length&&e.each(u._commands[t].linkedCmds,function(e,t){var n=u.commands[t];"function"!=typeof n||u._commands[t]||(n.prototype=_,u._commands[t]=new n,u._commands[t].setup(t,u.options.commandsOptions[t]||{}))})}}),u.ui={workzone:e("
              ").appendTo(m).elfinderworkzone(u),navbar:e("
              ").appendTo(m).elfindernavbar(u,u.options.uiOptions.navbar||{}),navdock:e("
              ").appendTo(m).elfindernavdock(u,u.options.uiOptions.navdock||{}),contextmenu:e("
              ").appendTo(m).elfindercontextmenu(u),overlay:e("
              ").appendTo(m).elfinderoverlay({show:function(){u.disable()},hide:function(){T&&u.enable()}}),cwd:e("
              ").appendTo(m).elfindercwd(u,u.options.uiOptions.cwd||{}),notify:u.dialog("",{cssClass:"elfinder-dialog-notify"+(u.options.notifyDialog.canClose?"":" elfinder-titlebar-button-hide"),position:u.options.notifyDialog.position,absolute:!0,resizable:!1,autoOpen:!1,allowMinimize:!0,closeOnEscape:!!u.options.notifyDialog.canClose,title:" ",width:u.options.notifyDialog.width?parseInt(u.options.notifyDialog.width):null,minHeight:null,minimize:function(){u.ui.notify.trigger("minimize")}}),statusbar:e('
              ').hide().appendTo(m),toast:e('
              ').appendTo(m),bottomtray:e('
              ').appendTo(m),progressbar:e('
              ').appendTo(m)},u.trigger("uiready"),e.each(u.options.ui||[],function(t,n){var i="elfinder"+n,a=u.options.uiOptions[n]||{};!u.ui[n]&&e.fn[i]&&(u.ui[n]=e("<"+(a.tag||"div")+"/>").appendTo(m),u.ui[n][i](u,a))}),u.ui.progressbar.appendTo(u.ui.workzone),u.ui.notify.prev(".ui-dialog-titlebar").append('
              '),u.resize(N,L),u.options.resizable&&(m.resizable({resize:function(e,t){u.resize(t.size.width,t.size.height)},handles:"se",minWidth:300,minHeight:200}),u.UA.Touch&&m.addClass("touch-punch")),function(){var e=u.getUI("navbar"),t=u.getUI("cwd").parent();u.autoScroll={navbarUp:function(t){e.scrollTop(Math.max(0,e.scrollTop()-t))},navbarDown:function(t){e.scrollTop(e.scrollTop()+t)},cwdUp:function(e){t.scrollTop(Math.max(0,t.scrollTop()-e))},cwdDown:function(e){t.scrollTop(t.scrollTop()+e)}}}(),u.UA.Touch&&!function(){var e,t,n,i,a,o,r,s,l,c=u.getUI("navbar"),d=u.getUI("toolbar"),p="touchmove.stopscroll",h=function(e){ +var n=e.originalEvent.touches||[{}],i=n[0].pageY||null;(!t||i1||("touchstart"===s.type?(n=m.offset(),i=m.width(),c&&(e=!1,c.is(":hidden")?(l||(l=Math.max(50,i/10)),(A?z-n.left:i+n.left-z)n.left+i-o,y?(l=Math.max(50,i/10),e=z):e=!1)),d&&(t=!1,s.originalEvent._preventSwipeY||(r=d.height(),a=n.top,T-a<(d.is(":hidden")?v:r+30)&&(t=T,m.on(p,d.is(":hidden")?f:h))))):(c&&e!==!1&&(b=(A?e>z:e.6*o||w>("navhide"===b?o/3:45)&&("navshow"===b||(A?zn.left+i-20)))&&(u.getUI("navbar").trigger(b,{handleW:l}),e=!1)),d&&t!==!1&&(x=d.offset().top,Math.abs(t-T)>Math.min(45,r/3)&&(k=t>T?"slideUp":"slideDown",("slideDown"===k||x+20>T)&&(d.is("slideDown"===k?":hidden":":visible")&&d.stop(!0,!0).trigger("toggle",{duration:100,handleH:v}),t=!1)))))})}(),u.dragUpload&&!function(){var t,n,i=function(t){return"TEXTAREA"!==t.target.nodeName&&"INPUT"!==t.target.nodeName&&0===e(t.target).closest("div.ui-dialog-content").length},a="native-drag-enter",o="native-drag-disable",r="class",s=u.res(r,"navdir"),l=(u.res(r,"droppable"),u.res(r,"adroppable"),u.res(r,"navarrow"),u.res(r,"adroppable")),c=u.getUI("workzone"),d="ltr"===u.direction,p=function(){n&&cancelAnimationFrame(n),n=null};m.on("dragenter",function(e){p(),i(e)&&(e.preventDefault(),e.stopPropagation(),t=c.data("rectangle"))}).on("dragleave",function(e){p(),i(e)&&(e.preventDefault(),e.stopPropagation())}).on("dragover",function(e){var a;i(e)?(e.preventDefault(),e.stopPropagation(),e.originalEvent.dataTransfer.dropEffect="none",n||(n=requestAnimationFrame(function(){var i,o=t.top+t.height,r=o-u.getUI("navdock").outerHeight(!0);((a=e.pageYr)&&(i=t.cwdEdge>e.pageX?(d?"navbar":"cwd")+(a?"Up":"Down"):(d?"cwd":"navbar")+(a?"Up":"Down"),a||"cwd"===i.substr(0,3)&&(o=11,IE:document.uniqueID,Firefox:window.sidebar,Opera:window.opera,Webkit:e,Chrome:t,Edge:!(!t||!window.msCredentials),Safari:e&&!window.chrome,Mobile:"undefined"!=typeof window.orientation,Touch:"undefined"!=typeof window.ontouchstart,iOS:navigator.platform.match(/^iP(?:[ao]d|hone)/),Mac:navigator.platform.match(/^Mac/),Fullscreen:"undefined"!=typeof(document.exitFullscreen||document.webkitExitFullscreen||document.mozCancelFullScreen||document.msExitFullscreen),Angle:0,Rotated:!1,CSS:function(){var e,t=document.createElement("a").style,n=document.createElement("p").style;return e="position:sticky;position:-webkit-sticky;",e+="width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:max-content;",t.cssText=e,{positionSticky:t.position.indexOf("sticky")!==-1,widthMaxContent:t.width.indexOf("max-content")!==-1,flex:"undefined"!=typeof n.flex}}()};return n}(),cookieEnabled:window.navigator.cookieEnabled,hasRequire:"function"==typeof define&&define.amd,currentReqCmd:"",keyState:{},i18:{en:{translator:"",language:"English",direction:"ltr",dateFormat:"d.m.Y H:i",fancyDateFormat:"$1 H:i",nonameDateFormat:"ymd-His",messages:{}},months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["msJan","msFeb","msMar","msApr","msMay","msJun","msJul","msAug","msSep","msOct","msNov","msDec"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},kinds:{unknown:"Unknown",directory:"Folder",group:"Selects",symlink:"Alias","symlink-broken":"AliasBroken","application/x-empty":"TextPlain","application/postscript":"Postscript","application/vnd.ms-office":"MsOffice","application/msword":"MsWord","application/vnd.ms-word":"MsWord","application/vnd.openxmlformats-officedocument.wordprocessingml.document":"MsWord","application/vnd.ms-word.document.macroEnabled.12":"MsWord","application/vnd.openxmlformats-officedocument.wordprocessingml.template":"MsWord","application/vnd.ms-word.template.macroEnabled.12":"MsWord","application/vnd.ms-excel":"MsExcel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":"MsExcel","application/vnd.ms-excel.sheet.macroEnabled.12":"MsExcel","application/vnd.openxmlformats-officedocument.spreadsheetml.template":"MsExcel","application/vnd.ms-excel.template.macroEnabled.12":"MsExcel","application/vnd.ms-excel.sheet.binary.macroEnabled.12":"MsExcel","application/vnd.ms-excel.addin.macroEnabled.12":"MsExcel","application/vnd.ms-powerpoint":"MsPP","application/vnd.openxmlformats-officedocument.presentationml.presentation":"MsPP","application/vnd.ms-powerpoint.presentation.macroEnabled.12":"MsPP","application/vnd.openxmlformats-officedocument.presentationml.slideshow":"MsPP","application/vnd.ms-powerpoint.slideshow.macroEnabled.12":"MsPP","application/vnd.openxmlformats-officedocument.presentationml.template":"MsPP","application/vnd.ms-powerpoint.template.macroEnabled.12":"MsPP","application/vnd.ms-powerpoint.addin.macroEnabled.12":"MsPP","application/vnd.openxmlformats-officedocument.presentationml.slide":"MsPP","application/vnd.ms-powerpoint.slide.macroEnabled.12":"MsPP","application/pdf":"PDF","application/xml":"XML","application/vnd.oasis.opendocument.text":"OO","application/vnd.oasis.opendocument.text-template":"OO","application/vnd.oasis.opendocument.text-web":"OO","application/vnd.oasis.opendocument.text-master":"OO","application/vnd.oasis.opendocument.graphics":"OO","application/vnd.oasis.opendocument.graphics-template":"OO","application/vnd.oasis.opendocument.presentation":"OO","application/vnd.oasis.opendocument.presentation-template":"OO","application/vnd.oasis.opendocument.spreadsheet":"OO","application/vnd.oasis.opendocument.spreadsheet-template":"OO","application/vnd.oasis.opendocument.chart":"OO","application/vnd.oasis.opendocument.formula":"OO","application/vnd.oasis.opendocument.database":"OO","application/vnd.oasis.opendocument.image":"OO","application/vnd.openofficeorg.extension":"OO","application/x-shockwave-flash":"AppFlash","application/flash-video":"Flash video","application/x-bittorrent":"Torrent","application/javascript":"JS","application/rtf":"RTF","application/rtfd":"RTF","application/x-font-ttf":"TTF","application/x-font-otf":"OTF","application/x-rpm":"RPM","application/x-web-config":"TextPlain","application/xhtml+xml":"HTML","application/docbook+xml":"DOCBOOK","application/x-awk":"AWK","application/x-gzip":"GZIP","application/x-bzip2":"BZIP","application/x-xz":"XZ","application/zip":"ZIP","application/x-zip":"ZIP","application/x-rar":"RAR","application/x-tar":"TAR","application/x-7z-compressed":"7z","application/x-jar":"JAR","text/plain":"TextPlain","text/x-php":"PHP","text/html":"HTML","text/javascript":"JS","text/css":"CSS","text/rtf":"RTF","text/rtfd":"RTF","text/x-c":"C","text/x-csrc":"C","text/x-chdr":"CHeader","text/x-c++":"CPP","text/x-c++src":"CPP","text/x-c++hdr":"CPPHeader","text/x-shellscript":"Shell","application/x-csh":"Shell","text/x-python":"Python","text/x-java":"Java","text/x-java-source":"Java","text/x-ruby":"Ruby","text/x-perl":"Perl","text/x-sql":"SQL","text/xml":"XML","text/x-comma-separated-values":"CSV","text/x-markdown":"Markdown","image/x-ms-bmp":"BMP","image/jpeg":"JPEG","image/gif":"GIF","image/png":"PNG","image/tiff":"TIFF","image/x-targa":"TGA","image/vnd.adobe.photoshop":"PSD","image/xbm":"XBITMAP","image/pxm":"PXM","image/webp":"WEBP","application/vnd.ms-fontobject":"EOT","font/sfnt":"SFNT","application/font-sfnt":"SFNT","font/ttf":"TTF","font/opentype":"OTF","font/otf":"OTF","application/x-font-opentype":"OTF","font/woff":"WOFF","application/font-woff":"WOFF","font/woff2":"WOFF2","application/font-woff2":"WOFF2","audio/mpeg":"AudioMPEG","audio/midi":"AudioMIDI","audio/ogg":"AudioOGG","audio/mp4":"AudioMPEG4","audio/x-m4a":"AudioMPEG4","audio/wav":"AudioWAV","audio/x-mp3-playlist":"AudioPlaylist","video/x-dv":"VideoDV","video/mp4":"VideoMPEG4","video/mpeg":"VideoMPEG","video/x-msvideo":"VideoAVI","video/quicktime":"VideoMOV","video/x-ms-wmv":"VideoWM","video/x-flv":"VideoFlash","video/x-matroska":"VideoMKV","video/ogg":"VideoOGG"},mimeTypes:{},rules:{defaults:function(e){return!(!e||e.added&&!Array.isArray(e.added)||e.removed&&!Array.isArray(e.removed)||e.changed&&!Array.isArray(e.changed))},open:function(t){return t&&t.cwd&&t.files&&e.isPlainObject(t.cwd)&&Array.isArray(t.files)},tree:function(e){return e&&e.tree&&Array.isArray(e.tree)},parents:function(e){return e&&e.tree&&Array.isArray(e.tree)},tmb:function(t){return t&&t.images&&(e.isPlainObject(t.images)||Array.isArray(t.images))},upload:function(t){return t&&(e.isPlainObject(t.added)||Array.isArray(t.added))},search:function(e){return e&&e.files&&Array.isArray(e.files)}},commands:{},cmdsToAdd:"archive duplicate extract mkdir mkfile paste rm upload",parseUploadData:function(t){var n,i=this;if(!e.trim(t))return{error:["errResponse","errDataEmpty"]};try{n=JSON.parse(t)}catch(a){return{error:["errResponse","errDataNotJSON"]}}return n=i.normalize(n),i.validResponse("upload",n)?(n.removed=e.merge(n.removed||[],e.map(n.added||[],function(e){return i.file(e.hash)?e.hash:null})),n):{error:n.norError||["errResponse"]}},iframeCnt:0,uploads:{xhrUploading:!1,failSyncTm:null,chunkfailReq:{},checkExists:function(t,n,i,a){var o,r=e.Deferred(),s=[],l={},c=function(){for(var e=t.length;--e>-1;)t[e]._remove=!0},d=function(){r.resolve(s,l)},p=function(){var r=[],p=[],u=n!==i.cwd().hash?i.path(n,!0)+i.option("separator",n):"",h=function(e){var n=e==p.length-1,o={cssClass:"elfinder-confirm-upload",title:i.i18n("cmdupload"),text:["errExists",u+p[e].name,"confirmRepl"],all:!n,accept:{label:"btnYes",callback:function(t){n||t?d():h(++e)}},reject:{label:"btnNo",callback:function(i){var a;if(i)for(a=p.length;e0&&delete o.reject,i.confirm(o)};return i.file(n).read?(o=e.map(t,function(e,t){return!e.name||i.UA.iOS&&"image.jpg"===e.name?null:{i:t,name:e.name}}),void i.request({data:{cmd:"ls",target:n,intersect:e.map(o,function(e){return e.name})},notify:{type:"preupload",cnt:1,hideCnt:!0},preventDefault:!0}).done(function(t){var a,s;t&&(t.error?c():i.options.overwriteUploadConfirm&&i.option("uploadOverwrite",n)&&t.list&&(Array.isArray(t.list)?r=t.list||[]:(a=[],r=e.map(t.list,function(e){return"string"==typeof e?e:(a=a.concat(e),!1)}),a.length&&(r=r.concat(a)),l=t.list),p=e.grep(o,function(t){return e.inArray(t.name,r)!==-1}),p.length&&r.length&&n==i.cwd().hash&&(s=e.map(i.files(n),function(e){return e.name}),e.grep(r,function(t){return e.inArray(t,s)===-1}).length&&i.sync()))),p.length>0?h(0):d()}).fail(function(e){c(),d(),e&&i.error(e)})):void d()};return i.api>=2.1&&"object"==typeof t[0]?p():d(),r},checkFile:function(t,n,i){if(t.checked||"files"==t.type)return t.files;if("data"==t.type){var a,o,r=e.Deferred(),s=e.Deferred(),l=[],c=[],d=0,p=[],u=!1,h=function(e){return Array.prototype.slice.call(e||[],0)},f=function(e){var t,i,a=n.options.folderUploadExclude[n.OS]||null,o=e.length,r=function(){--d<1&&"pending"===s.state()&&s.resolve()},m=function(e){a&&e.name.match(a)||(c.push(t.fullPath||""),l.push(e)),r()},i=function(e){var t=[],n=function(){e.readEntries(function(e){if(u||!e.length){for(var i=0;i=2.1&&(d++,p.push(t.fullPath),i(t.createReader())))}return r(),s};return a=e.map(t.files.items,function(e){return"file"===e.kind?(e.getAsEntry?e.getAsEntry():e.webkitGetAsEntry())||e.getAsFile():null}),e.each(a,function(e,t){if(t.isDirectory)return o=!0,!1}),a.length>0?(n.uploads.checkExists(a,i,n,o).done(function(o,s){var d=[];n.options.overwriteUploadConfirm&&n.option("uploadOverwrite",i)&&(null===o&&(t.overwrite=0,o=[]),a=e.grep(a,function(t){var a,r,l,c;return t.isDirectory&&o.length&&(a=e.inArray(t.name,o),a!==-1&&(o.splice(a,1),r=n.uniqueName(t.name+n.options.backupSuffix,null,""),e.each(s,function(e,n){if(t.name==n)return l=e,!1}),l||(l=n.fileByName(t.name,i).hash),n.lockfiles({files:[l]}),c=n.request({data:{cmd:"rename",target:l,name:r},notify:{type:"rename",cnt:1}}).fail(function(){t._remove=!0,n.sync()}).always(function(){n.unlockfiles({files:[l]})}),d.push(c))),!t._remove})),e.when.apply(e,d).done(function(){var e,t,i=+new Date;a.length>0?(t=n.escape(a[0].name),a.length>1&&(t+=" ... "+a.length+n.i18n("items")),e=setTimeout(function(){n.notify({type:"readdir",id:i,cnt:1,hideCnt:!0,msg:n.i18n("ntfreaddir")+" ("+t+")",cancel:function(){u=!0}})},n.options.notifyDelay),f(a).done(function(){e&&clearTimeout(e),n.notify({type:"readdir",id:i,cnt:-1}),u?r.reject():r.resolve([l,c,o,s,p])}).fail(function(){r.reject()})):r.reject()})}),r.promise()):r.reject()}var m=[],g=[],v=t.files[0];if("html"==t.type){var b,y=e("").append(e.parseHTML(v.replace(/ src=/gi," _elfsrc=")));e("img[_elfsrc]",y).each(function(){var n,i,a=e(this),o=a.closest("a");o&&o.attr("href")&&o.attr("href").match(/\.(?:jpe?g|gif|bmp|png)/i)&&(i=o.attr("href")),n=a.attr("_elfsrc"),n&&(i?(e.inArray(i,m)==-1&&m.push(i),e.inArray(n,g)==-1&&g.push(n)):e.inArray(n,m)==-1&&m.push(n)),1===m.length&&m[0].match(/^data:image\/png/)&&(t.clipdata=!0)}),b=e("a[href]",y),b.each(function(){var t,n,i=function(e){var t=document.createElement("a");return t.href=e,t};(t=e(this).text())&&(n=i(e(this).attr("href")),n.href&&n.href.match(/^(?:ht|f)tp/i)&&(1===b.length||!n.pathname.match(/(?:\.html?|\/[^\/.]*)$/i)||e.trim(t).match(/\.[a-z0-9-]{1,10}$/i))&&e.inArray(n.href,m)==-1&&e.inArray(n.href,g)==-1&&m.push(n.href))})}else{var w,x,k;for(w=/((?:ht|f)tps?:\/\/[-_.!~*\'()a-z0-9;\/?:\@&=+\$,%#\*\[\]]+)/gi;x=w.exec(v);)k=x[1].replace(/&/g,"&"),e.inArray(k,m)==-1&&m.push(k)}return m},xhr:function(t,n){var i=n?n:this,a=i.getUI(),o=new XMLHttpRequest,r=null,s=null,l=null,c=t.checked,d=t.isDataType||"data"==t.type,p=t.target||i.cwd().hash,u=t.dropEvt||null,h=t.extraData||null,f=i.option("uploadMaxConn",p)!=-1,m=Math.min(5,Math.max(1,i.option("uploadMaxConn",p))),g=1e4,v=30,b=0,y=function(t){var n=e.Deferred();return t.promise?t.always(function(e){n.resolve(Array.isArray(e)&&e.length?d?e[0][0]:e[0]:{})}):n.resolve(t.length?d?t[0][0]:t[0]:{}),n},w=e.Deferred().fail(function(e){var t,a=i.parseError(e);"userabort"===a&&(t=!0,a=void 0),k&&(i.uploads.xhrUploading||t)?y(k).done(function(e){t||H(a,e),e._cid?i.uploads.chunkfailReq[e._cid]||(i.uploads.chunkfailReq[e._cid]=!0,setTimeout(function(){n.request({data:{cmd:"upload",target:p,chunk:e._chunk,cid:e._cid,upload:["chunkfail"],mimes:"chunkfail"},options:{type:"post",url:i.uploadURL},preventDefault:!0}).always(function(){delete i.uploads.chunkfailReq[e._chunk]})},1e3)):(i.uploads.failSyncTm&&clearTimeout(i.uploads.failSyncTm),i.uploads.failSyncTm=setTimeout(function(){i.sync(p)},1e3))}):H(a),!t&&i.sync(),i.uploads.xhrUploading=!1,k=null}).done(function(t){i.uploads.xhrUploading=!1,k=null,t&&(i.currentReqCmd="upload",t.warning&&H(t.warning),i.updateCache(t),t.removed&&t.removed.length&&i.remove(t),t.added&&t.added.length&&i.add(t),t.changed&&t.changed.length&&i.change(t),i.trigger("upload",t,!1),i.trigger("uploaddone"),t.toasts&&Array.isArray(t.toasts)&&e.each(t.toasts,function(){this.msg&&i.toast(this)}),t.sync&&i.sync(),t.debug&&(i.responseDebug(t),n.debug("backend-debug",t)))}).always(function(){i.abortXHR(o),a.off("uploadabort",D),e(window).off("unload",D),r&&clearTimeout(r),s&&clearTimeout(s),l&&clearTimeout(l),c&&!t.multiupload&&E()&&i.notify({type:"upload",cnt:-C,progress:0,size:0}),s&&M&&i.notify({type:"chunkmerge",cnt:-C}),B&&S.children(".elfinder-notify-chunkmerge").length&&i.notify({type:"chunkmerge",cnt:-1})}),x=new FormData,k=t.input?t.input.files:i.uploads.checkFile(t,i,p),C=t.checked&&d?k[0].length:k.length,z=!1,T=0,A=0,j=0,O=!1,S=i.ui.notify,I=!0,M=!1,F=!1,E=function(){return!O&&($=S.children(".elfinder-notify-upload")).length&&(O=!0),O},D=function(e,t){F=!0,i.abortXHR(o,{quiet:!0,abort:!0}),w.reject(t),E()&&i.notify({type:"upload",cnt:$.data("cnt")*-1,progress:0,size:0})},U=function(e,t){$.children(".elfinder-notify-cancel")[e?"show":"hide"](),I=e},P=function(e){return e||(e=j),setTimeout(function(){O=!0,i.notify({type:"upload",cnt:C,progress:T-A,size:e,cancel:function(){a.trigger("uploadabort","userabort")}}),$=S.children(".elfinder-notify-upload"),A=T,t.multiupload?I&&U(!0):U(I&&T=2.1029&&(e=(+new Date).toString(16)+Math.floor(1e3*Math.random()).toString(16),"function"==typeof x["delete"]&&x["delete"]("reqid"),x.append("reqid",e),o._requestId=e),o.send(x))},g)):a.trigger("uploadabort",["errAbort","errTimeout"])},q=function(){O&&w.notifyWith($,[{cnt:$.data("cnt"),progress:$.data("progress"),total:$.data("total")}])},H=function(e,t,n){e&&i.trigger("xhruploadfail",{error:e,file:t}),n?e&&(N=i.options.maxErrorDialogs&&(_=_.concat("moreErrors",N-i.options.maxErrorDialogs)),i.error(_)),_=[],N=0)},_=[],N=0,L=t.renames||null,W=t.hashes||null,B=!1,$=e();if(a.one("uploadabort",D),e(window).one("unload."+n.namespace,D),!B&&(A=T),!d&&!C)return w.reject(["errUploadNoFiles"]);o.addEventListener("error",function(){0==o.status?F?w.reject():!d&&t.files&&e.grep(t.files,function(e){return!e.type&&e.size===(i.UA.Safari?1802:0)}).length?w.reject(["errAbort","errFolderUpload"]):t.input&&e.grep(t.input.files,function(e){return!e.type&&e.size===(i.UA.Safari?1802:0)}).length?w.reject(["errUploadNoFiles"]):R():a.trigger("uploadabort","errConnect")},!1),o.addEventListener("load",function(e){var n,s,c=o.status,p=0,u="";if(i.setCustomHeaderByXhr(o),c>=400?u=c>500?"errResponse":["errResponse","errServerError"]:o.responseText||(u=["errResponse","errDataEmpty"]),u&&(a.trigger("uploadabort"),y(k||{}).done(function(e){return w.reject(e._cid?null:u)})),T=j,E()&&(p=T-A)&&(i.notify({type:"upload",cnt:0,progress:p,size:0}),q()),n=i.parseUploadData(o.responseText),n._chunkmerged){x=new FormData;var h=[{_chunkmerged:n._chunkmerged,_name:n._name,_mtime:n._mtime}];return B=!0,a.off("uploadabort",D),l=setTimeout(function(){i.notify({type:"chunkmerge",cnt:1})},i.options.notifyDelay),void(d?V(h,k[1]):V(h))}n._multiupload=!!t.multiupload,n.error?(s={cmd:"upload",err:n,xhr:o,rc:o.status},i.trigger("uploadfail",n),i.trigger("requestError",s),s._getEvent&&s._getEvent().isDefaultPrevented()&&(n.error=""),n._chunkfailure||n._multiupload?(F=!0,i.uploads.xhrUploading=!1,r&&clearTimeout(r),$.length?(i.notify({type:"upload",cnt:-C,progress:0,size:0}),w.reject(n)):w.reject()):w.reject(n)):w.resolve(n)},!1),o.upload.addEventListener("loadstart",function(e){!B&&e.lengthComputable&&(T=e.loaded,b&&(T=0),j=e.total,T||(T=parseInt(.05*j)),E()&&(i.notify({type:"upload",cnt:0,progress:T-A,size:t.multiupload?0:j}),A=T,q()))},!1),o.upload.addEventListener("progress",function(e){var n;e.lengthComputable&&!B&&o.readyState<2&&(T=e.loaded,!t.checked&&T>0&&!r&&(r=P(o._totalSize-T)),j||(j=e.total,T||(T=parseInt(.05*j))),n=T-A,E()&&n/e.total>=.05&&(i.notify({type:"upload",cnt:0,progress:n,size:0}),A=T,q()),!M&&T>=j&&!z&&(M=!0,s=setTimeout(function(){i.notify({type:"chunkmerge",cnt:C})},i.options.notifyDelay)),I&&!t.multiupload&&T>=j&&E()&&U(!1))},!1);var V=function(a,s){var l,g,v,b,y,k,T,A,j,O,S,M,D,R,q,N=0,B=1,$=[],V=0,K=C,X=0,J=[],G=(new Date).getTime().toString().substr(-9),Y=Math.min((n.uplMaxSize?n.uplMaxSize:2097152)-8190,n.options.uploadMaxChunkSize),Q=!f&&"",Z=function(a,o){var s,l,c,h=[],f=0;if(!F){for(;a.length&&h.length=2.1&&("slice"in j?Q="slice":"mozSlice"in j?Q="mozSlice":"webkitSlice"in j&&(Q="webkitSlice")))}catch(te){C--,K--;continue}if(l&&g>l||!Q&&n.uplMaxSize&&g>n.uplMaxSize)H(["errUploadFile",j.name,"errUploadFileSize"],j,!0),C--,K--;else if(!j.type||i.uploadMimeCheck(j.type,p))if(Q&&g>Y){for(k=0,T=Y,A=-1,K=Math.floor((g-1)/Y),v=j.lastModified?Math.round(j.lastModified/1e3):0,b=t.clipdata?n.date(n.nonameDateFormat)+".png":j.name,X+=g,J[G]=0;kn.uplMaxSize||B>n.uplMaxFile)&&(N=0,B=1,V++),"undefined"==typeof $[V]&&($[V]=[],d&&($[V][0]=[],$[V][1]=[])),d?($[V][0].push(j),$[V][1].push(s[y])):$[V].push(j),N+=g,X+=g,B++;else H(["errUploadFile",j.name,"errUploadMime","("+j.type+")"],j,!0),C--,K--}if(_.length&&H(),0==$.length)return t.checked=!0,!1;if($.length>1)return r=P(X),S=[],M=0,D=$.length,R=[],ee(),!0;d?(a=$[0][0],s=$[0][1]):a=$[0]}return c||(n.UA.Safari&&t.files?o._totalSize=X:r=P(X)),c=!0,a.length||w.reject(["errUploadNoFiles"]),o.open("POST",i.uploadURL,!0),n.customHeaders&&e.each(n.customHeaders,function(e){o.setRequestHeader(e,this)}),n.xhrFields&&e.each(n.xhrFields,function(e){e in o&&(o[e]=this)}),i.api>=2.1029&&(q=(+new Date).toString(16)+Math.floor(1e3*Math.random()).toString(16),x.append("reqid",q),o._requestId=q),x.append("cmd","upload"),x.append(i.newAPI?"target":"current",p),L&&L.length&&(e.each(L,function(e,t){x.append("renames[]",t)}),x.append("suffix",n.options.backupSuffix)),W&&e.each(W,function(e,t){x.append("hashes["+e+"]",t)}),e.each(i.customData,function(e,t){x.append(e,t)}),e.each(i.options.onlyMimes,function(e,t){x.append("mimes[]",t)}),e.each(a,function(e,i){var a,o;i._chunkmerged?(x.append("chunk",i._chunkmerged),x.append("upload[]",i._name),x.append("mtime[]",i._mtime),t.clipdata&&x.append("overwrite",0),z=!0):(i._chunkfail?(x.append("upload[]","chunkfail"),x.append("mimes","chunkfail")):(t.clipdata?i._chunk||(t.overwrite=0,a=n.date(n.nonameDateFormat)+".png"):i.name&&(a=i.name,n.UA.iOS&&(a.match(/^image\.jpe?g$/i)?(t.overwrite=0,a=n.date(n.nonameDateFormat)+".jpg"):a.match(/^capturedvideo\.mov$/i)&&(t.overwrite=0,a=n.date(n.nonameDateFormat)+".mov")),o=(i.webkitRelativePath||i.relativePath||i._relativePath||"").replace(/[^\/]+$/,""),a=o+a),a?x.append("upload[]",i,a):x.append("upload[]",i)),i._chunk?(x.append("chunk",i._chunk),x.append("cid",i._cid),x.append("range",i._range),x.append("mtime[]",i._mtime),z=!0):x.append("mtime[]",i.lastModified?Math.round(i.lastModified/1e3):0))}),d&&e.each(s,function(e,t){x.append("upload_path[]",t)}),0===t.overwrite&&x.append("overwrite",0),u&&x.append("dropWith",parseInt((u.altKey?"1":"0")+(u.ctrlKey?"1":"0")+(u.metaKey?"1":"0")+(u.shiftKey?"1":"0"),2)),h&&e.each(h,function(e,t){x.append(e,t)}),o.send(x),!0};if(d)c?V(k[0],k[1]):k.done(function(t){if(L=[],C=t[0].length){if(t[4]&&t[4].length)return void n.request({data:{cmd:"mkdir",target:p,dirs:t[4]},notify:{type:"mkdir",cnt:t[4].length},preventFail:!0}).fail(function(e){e=e||["errUnknown"],"errCmdParams"===e[0]?m=1:(m=0,w.reject(e))}).done(function(n){var i=!1;n.hashes||(n.hashes={}),t[1]=e.map(t[1],function(e,a){return t[0][a]._relativePath=e.replace(/^\//,""),e=e.replace(/\/[^\/]*$/,""),""===e?p:n.hashes[e]?n.hashes[e]:(i=!0,t[0][a]._remove=!0,null)}),i&&(t[0]=e.grep(t[0],function(e){return!e._remove}))}).always(function(e){m&&(L=t[2],W=t[3],V(t[0],t[1]))});t[1]=e.map(t[1],function(){return p}),L=t[2],W=t[3],V(t[0],t[1])}else w.reject(["errUploadNoFiles"])}).fail(function(){w.reject()});else if(k.length>0)if(t.clipdata||null!=L)V(k)||w.reject();else{var K=[],X=[],J=n.options.folderUploadExclude[n.OS]||null;e.each(k,function(t,n){var i,a,o=n.webkitRelativePath||n.relativePath||"";return!!o&&(J&&n.name.match(J)?(n._remove=!0,o=void 0):(o="/"+o.replace(/\/[^\/]*$/,"").replace(/^\//,""),o&&e.inArray(o,K)===-1&&(K.push(o),i=o.substr(1).indexOf("/"),i!==-1&&(a=o.substr(0,i+1))&&e.inArray(a,K)===-1&&K.unshift(a))),void X.push(o))}),L=[],W={},K.length?!function(){var t=e.map(K,function(e){return e.substr(1).indexOf("/")===-1?{name:e.substr(1)}:null}),i=[];n.uploads.checkExists(t,p,n,!0).done(function(a,o){var r,s,l,c=[];n.options.overwriteUploadConfirm&&n.option("uploadOverwrite",p)&&(i=e.map(t,function(e){return e._remove?e.name:null}),t=e.grep(t,function(e){return!e._remove})),i.length&&e.each(X.concat(),function(t,n){0===e.inArray(n,i)&&(k[t]._remove=!0,X[t]=void 0)}),k=e.grep(k,function(e){return!e._remove}),X=e.grep(X,function(e){return void 0!==e}),t.length?(r=e.Deferred(),a.length?e.each(a,function(t,i){s=n.uniqueName(i+n.options.backupSuffix,null,""),e.each(o,function(e,t){if(a[0]==t)return l=e,!1}),l||(l=n.fileByName(a[0],p).hash),n.lockfiles({files:[l]}),c.push(n.request({data:{cmd:"rename",target:l,name:s},notify:{type:"rename",cnt:1}}).fail(function(e){w.reject(e),n.sync()}).always(function(){n.unlockfiles({files:[l]})}))}):c.push(null),e.when.apply(e,c).done(function(){n.request({data:{cmd:"mkdir",target:p,dirs:K},notify:{type:"mkdir",cnt:K.length},preventFail:!0}).fail(function(e){e=e||["errUnknown"],"errCmdParams"===e[0]?m=1:(m=0,w.reject(e))}).done(function(t){var n=!1;t.hashes||(t.hashes={}),X=e.map(X.concat(),function(e,i){return"/"===e?p:t.hashes[e]?t.hashes[e]:(n=!0,k[i]._remove=!0,null)}),n&&(k=e.grep(k,function(e){return!e._remove}))}).always(function(e){m&&(d=!0,V(k,X)||w.reject())})})):w.reject()})}():n.uploads.checkExists(k,p,n).done(function(i,a){n.options.overwriteUploadConfirm&&n.option("uploadOverwrite",p)&&(W=a,null===i?t.overwrite=0:L=i,k=e.grep(k,function(e){return!e._remove})),C=k.length,C>0?V(k)||w.reject():w.reject()})}else w.reject();return w},iframe:function(t,n){var i,a,o,r,s=n?n:this,l=!!t.input&&t.input,c=!l&&s.uploads.checkFile(t,s),d=e.Deferred().fail(function(e){e&&s.error(e)}),p="iframe-"+n.namespace+ ++s.iframeCnt,u=e('
              '),h=this.UA.IE,f=function(){r&&clearTimeout(r),o&&clearTimeout(o),a&&s.notify({type:"upload",cnt:-i}),setTimeout(function(){h&&e('').appendTo(u),u.remove(),m.remove()},100)},m=e('').on("load",function(){m.off("load").on("load",function(){ +f(),d.resolve()}),o=setTimeout(function(){a=!0,s.notify({type:"upload",cnt:i})},s.options.notifyDelay),s.options.iframeTimeout>0&&(r=setTimeout(function(){f(),d.reject(["errConnect","errTimeout"])},s.options.iframeTimeout)),u.submit()}),g=t.target||s.cwd().hash,v=[],b=[],y=[],w={};if(c&&c.length)e.each(c,function(e,t){u.append('')}),i=1;else{if(!(l&&e(l).is(":file")&&e(l).val()))return d.reject();n.options.overwriteUploadConfirm&&n.option("uploadOverwrite",g)&&(v=l.files?l.files:[{name:e(l).val().replace(/^(?:.+[\\\/])?([^\\\/]+)$/,"$1")}],b.push(s.uploads.checkExists(v,g,s).done(function(n,a){w=a,null===n?t.overwrite=0:(y=n,i=e.grep(v,function(e){return!e._remove}).length,i!=v.length&&(i=0))}))),i=l.files?l.files.length:1,u.append(l)}return e.when.apply(e,b).done(function(){return i<1?d.reject():(u.append('').append('').append('').append(e(l).attr("name","upload[]")),y.length>0&&(e.each(y,function(e,t){u.append('')}),u.append('')),w&&e.each(y,function(e,t){u.append('')}),0===t.overwrite&&u.append(''),e.each(s.options.onlyMimes||[],function(e,t){u.append('')}),e.each(s.customData,function(e,t){u.append('')}),u.appendTo("body"),void m.appendTo("body"))}),d}},one:function(e,t,n){var i=this,a=e.toLowerCase(),o=function(e,n){return i.toUnbindEvents[a]||(i.toUnbindEvents[a]=[]),i.toUnbindEvents[a].push({type:a,callback:o}),(t.done?t.done:t).apply(this,arguments)};return t.done&&(o={done:o}),this.bind(a,o,n)},localStorage:function(t,n){var i,a,o,r,s,l=this,c=window.localStorage,d="elfinder-"+(t||"")+this.id,p=window.location.pathname+"-elfinder-",u=this.id,h=[];if("undefined"==typeof t)return r=p.length,s=u.length*-1,e.each(c,function(e){e.substr(0,r)===p&&e.substr(s)===u&&h.push(e)}),e.each(h,function(e,t){c.removeItem(t)}),!0;if(t=p+t+u,null===n)return c.removeItem(t);if(void 0===n&&!(i=c.getItem(t))&&(a=c.getItem(d))&&(n=a,c.removeItem(d)),void 0!==n){o=typeof n,"string"!==o&&"number"!==o&&(n=JSON.stringify(n));try{c.setItem(t,n)}catch(f){try{c.clear(),c.setItem(t,n)}catch(f){l.debug("error",f.toString())}}i=c.getItem(t)}if(i&&("{"===i.substr(0,1)||"["===i.substr(0,1)))try{return JSON.parse(i)}catch(f){}return i},sessionStorage:function(e,t){var n,i,a,o=this;try{n=window.sessionStorage}catch(r){}if(n){if(null===t)return n.removeItem(e);if(void 0!==t){a=typeof t,"string"!==a&&"number"!==a&&(t=JSON.stringify(t));try{n.setItem(e,t)}catch(r){try{n.clear(),n.setItem(e,t)}catch(r){o.debug("error",r.toString())}}}if(i=n.getItem(e),i&&("{"===i.substr(0,1)||"["===i.substr(0,1)))try{return JSON.parse(i)}catch(r){}return i}},cookie:function(t,n){var i,a,o,r,s,l;if(t="elfinder-"+t+this.id,void 0===n){if(this.cookieEnabled&&document.cookie&&""!=document.cookie)for(o=document.cookie.split(";"),t+="=",r=0;r"),escape:function(e){return this._node.text(e).html().replace(/"/g,""").replace(/'/g,"'")},normalize:function(t){var n,i,a,o,r,s=this,l=function(){var e,t;return(t=s.options.fileFilter)&&("function"==typeof t?e=function(e){return t.call(s,e)}:t instanceof RegExp&&(e=function(e){return t.test(e.name)})),e?e:null}(),c=function(t){var n;t.uiCmdMap&&(e.isPlainObject(t.uiCmdMap)&&Object.keys(t.uiCmdMap).length?(t.disabledFlip||(t.disabledFlip={}),n=t.disabledFlip,e.each(t.uiCmdMap,function(e,i){"hidden"!==i||n[e]||(t.disabled.push(e),t.disabledFlip[e]=!0)})):delete t.uiCmdMap)},d=function(t){var n=function(e){var t=typeof e;return"object"===t&&Array.isArray(e)&&(t="array"),t};return e.each(s.optionProperties,function(e,i){void 0!==i&&t[e]&&n(t[e])!==n(i)&&(t[e]=i)}),t.disabled?(t.disabledFlip=s.arrayFlip(t.disabled,!0),e.each(s.options.disabledCmdsRels,function(n,i){var a,o;t.disabledFlip[n]?o=!0:(a=n.match(/^([^&]+)&([^=]+)=(.*)$/))&&t.disabledFlip[a[1]]&&t[a[2]]==a[3]&&(o=!0),o&&e.each(i,function(e,n){t.disabledFlip[n]||(t.disabledFlip[n]=!0,t.disabled.push(n))})})):t.disabledFlip={},t},p=function(t,r,p){var u,h,m,g,v=!r||t,b=!!r&&null;if(t&&t.hash&&t.name&&t.mime){if("application/x-empty"===t.mime&&(t.mime="text/plain"),m=s.isRoot(t),m&&!t.volumeid&&s.debug("warning","The volume root statuses requires `volumeid` property."),m||"directory"===t.mime){if(t.phash){if(t.phash===t.hash)return f=f.concat(['Parent folder of "$1" is itself.',t.name]),b;if(m&&t.volumeid&&0===t.phash.indexOf(t.volumeid))return f=f.concat(['Parent folder of "$1" is inner itself.',t.name]),b}t.volumeid&&(u=t.volumeid,m&&(t.phash&&(s.leafRoots[t.phash]?e.inArray(t.hash,s.leafRoots[t.phash])===-1&&s.leafRoots[t.phash].push(t.hash):s.leafRoots[t.phash]=[t.hash]),s.hasVolOptions=!0,s.volOptions[u]||(s.volOptions[u]={dispInlineRegex:s.options.dispInlineRegex}),h=s.volOptions[u],t.options&&Object.assign(h,t.options),t.disabled&&(h.disabled=t.disabled,h.disabledFlip=s.arrayFlip(t.disabled,!0)),t.tmbUrl&&(h.tmbUrl=t.tmbUrl),h.url&&"/"!==h.url.substr(-1)&&(h.url+="/"),c(h),h.trashHash&&(s.trashes[h.trashHash]===!1?delete h.trashHash:s.trashes[h.trashHash]=t.hash),e.each(s.optionProperties,function(e){h[e]&&(t[e]=h[e])}),"cwd"!==p&&(s.roots[u]=t.hash),t.expires&&(s.volumeExpires[u]=t.expires)),o!==u&&(o=u,a=s.option("i18nFolderName",u))),m&&!t.i18&&(n="volume_"+t.name,i=s.i18n(!1,n),n!==i&&(t.i18=i)),a&&!t.i18&&(n="folder_"+t.name,i=s.i18n(!1,n),n!==i&&(t.i18=i)),m&&s.options.enableRootRename!==!1&&(g=s.storage("rootNames"))&&(g[t.hash]&&(t._name=t.name,t._i18=t.i18,t.name=g[t.hash]=g[t.hash],delete t.i18),s.storage("rootNames",g)),s.trashes[t.hash]&&(t.locked=!0)}else{if(l)try{if(!l(t))return b}catch(y){s.debug(y)}0==t.size&&(t.mime=s.getMimetype(t.name,t.mime))}return t.options&&(s.optionsByHashes[t.hash]=d(t.options)),delete t.options,v}return b},u=function(t){var n=[];return e.each(s.files(),function(i,a){e.each(s.parents(i),function(a,o){if(e.inArray(o,t)!==-1&&e.inArray(i,t)===-1)return n.push(i),!1})}),n},h=function(n,i){e.each(n,function(n,a){var o,r;s.leafRoots[a.hash]&&s.applyLeafRootStats(a),"change"!==i&&a.phash&&s.isRoot(a)&&(o=s.file(a.phash))&&(s.applyLeafRootStats(o),t.changed?(e.each(t.changed,function(e,n){if(n.hash===o.hash)return t.changed[e]=o,r=!0,!1}),r||t.changed.push(o)):t.changed=[o])})},f=[];if(t.customData&&(!s.prevCustomData||JSON.stringify(t.customData)!==JSON.stringify(s.prevCustomData))){s.prevCustomData=t.customData;try{r=JSON.parse(t.customData),e.isPlainObject(r)&&(s.prevCustomData=r,e.each(Object.keys(r),function(e,t){null===r[t]&&(delete r[t],delete s.optsCustomData[t])}),s.customData=Object.assign({},s.optsCustomData,r))}catch(m){}}return t.options&&d(t.options),t.cwd&&(t.cwd.volumeid&&t.options&&Object.keys(t.options).length&&s.isRoot(t.cwd)&&(s.hasVolOptions=!0,s.volOptions[t.cwd.volumeid]=t.options),t.cwd=p(t.cwd,!0,"cwd")),t.files&&(t.files=e.grep(t.files,p)),t.tree&&(t.tree=e.grep(t.tree,p)),t.added&&(t.added=e.grep(t.added,p)),t.changed&&(t.changed=e.grep(t.changed,p)),t.removed&&t.removed.length&&2===s.searchStatus.state&&(t.removed=t.removed.concat(u(t.removed))),t.api&&(t.init=!0),Object.keys(s.leafRoots).length&&(t.files&&h(t.files),t.tree&&h(t.tree),t.added&&h(t.added),t.changed&&h(t.changed,"change")),t.cwd&&t.cwd.options&&t.options&&Object.assign(t.options,d(t.cwd.options)),t.options&&t.options.url&&"/"!==t.options.url.substr(-1)&&(t.options.url+="/"),f.length&&(t.norError=["errResponse"].concat(f)),t},setSort:function(e,t,n,i){this.storage("sortType",this.sortType=this.sortRules[e]?e:"name"),this.storage("sortOrder",this.sortOrder=/asc|desc/.test(t)?t:"asc"),this.storage("sortStickFolders",(this.sortStickFolders=!!n)?1:""),this.storage("sortAlsoTreeview",(this.sortAlsoTreeview=!!i)?1:""),this.trigger("sortchange")},_sortRules:{name:function(e,t){return i.prototype.naturalCompare(e.i18||e.name,t.i18||t.name)},size:function(e,t){var n=parseInt(e.size)||0,i=parseInt(t.size)||0;return n===i?0:n>i?1:-1},kind:function(e,t){return i.prototype.naturalCompare(e.mime,t.mime)},date:function(e,t){var n=e.ts||e.date||0,i=t.ts||t.date||0;return n===i?0:n>i?1:-1},perm:function(e,t){var n=function(e){return(e.write?2:0)+(e.read?1:0)},i=n(e),a=n(t);return i===a?0:i>a?1:-1},mode:function(e,t){var n=e.mode||e.perm||"",a=t.mode||t.perm||"";return i.prototype.naturalCompare(n,a)},owner:function(e,t){var n=e.owner||"",a=t.owner||"";return i.prototype.naturalCompare(n,a)},group:function(e,t){var n=e.group||"",a=t.group||"";return i.prototype.naturalCompare(n,a)}},sorters:{},naturalCompare:function(e,t){var n=i.prototype.naturalCompare;return"undefined"==typeof n.loc&&(n.loc=navigator.userLanguage||navigator.browserLanguage||navigator.language||"en-US"),"undefined"==typeof n.sort&&("11".localeCompare("2",n.loc,{numeric:!0})>0?window.Intl&&window.Intl.Collator?n.sort=new Intl.Collator(n.loc,{numeric:!0}).compare:n.sort=function(e,t){return e.localeCompare(t,n.loc,{numeric:!0})}:(n.sort=function(e,t){var i,a,o=/(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,r=/(^[ ]*|[ ]*$)/g,s=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,l=/^0x[0-9a-f]+$/i,c=/^0/,d=/^[\x01\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]/,p=function(e){return n.sort.insensitive&&(""+e).toLowerCase()||""+e},u=p(e).replace(r,"").replace(/^_/,"")||"",h=p(t).replace(r,"").replace(/^_/,"")||"",f=u.replace(o,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0"),m=h.replace(o,"\0$1\0").replace(/\0$/,"").replace(/^\0/,"").split("\0"),g=parseInt(u.match(l))||1!=f.length&&u.match(s)&&Date.parse(u),v=parseInt(h.match(l))||g&&h.match(s)&&Date.parse(h)||null,b=0;if(v){if(gv)return 1}for(var y=0,w=Math.max(f.length,m.length);ya)return 1}return 0},n.sort.insensitive=!0)),n.sort(e,t)},compare:function(e,t){var n,i=this,a=i.sortType,o="asc"==i.sortOrder,r=i.sortStickFolders,s=i.sortRules,l=s[a],c="directory"==e.mime,d="directory"==t.mime;if(r){if(c&&!d)return-1;if(!c&&d)return 1}return n=o?l(e,t):l(t,e),"name"!==a&&0===n?n=o?s.name(e,t):s.name(t,e):n},sortFiles:function(e){return e.sort(this.compare)},notify:function(t){var n,i,a,o=this,r=t.type,s=t.id?"elfinder-notify-"+t.id:"",l=this.i18n("undefined"!=typeof t.msg?t.msg:this.messages["ntf"+r]?"ntf"+r:"ntfsmth"),c=this.arrayFlip(this.options.notifyDialog.hiddens||[]),d=this.ui.notify,p=d.closest(".ui-dialog"),u=d.children(".elfinder-notify-"+r+(s?"."+s:"")),h=u.children("div.elfinder-notify-cancel").children("button"),f='
              {msg}
              ',m=t.cnt+0,g="undefined"!=typeof t.size?parseInt(t.size):null,v="undefined"!=typeof t.progress&&t.progress>=0?t.progress:null,b=t.fakeinterval||200,y=t.cancel,w="ui-state-hover",x=function(){var t=u.find(".elfinder-notify-progress"),n=function(){u.remove(),d.children(p.data("minimized")?void 0:":visible").length||(p.data("minimized")?p.data("minimized").hide():d.elfinderdialog("close")),C()};u._esc&&e(document).off("keydown",u._esc),u.data("cur")<100?t.animate({width:"100%"},50,function(){requestAnimationFrame(function(){n()})}):n()},k=function(e){var t;u.length&&(t=u.data("cur")+1,t<=98&&(u.find(".elfinder-notify-progress").width(t+"%"),u.data("cur",t),C(),setTimeout(function(){e*=1.05,k(e)},e)))},C=function(){var t,n=0,i=0,a=d.children(".elfinder-notify");a.length?(a.each(function(){n++,i+=Math.min(e(this).data("cur"),100)}),t=n?Math.floor(i/(100*n)*100)+"%":0,o.ui.progressbar.width(t),p.data("minimized")&&(p.data("minimized").title(t),p.data("minimized").dialog().children(".ui-dialog-titlebar").children(".elfinder-ui-progressbar").width(t))):(o.ui.progressbar.width(0),p.data("minimized")&&p.data("minimized").hide())};return r?(u.length?"undefined"!=typeof t.msg&&u.children("span.elfinder-notify-msg").html(l):(u=e(f.replace(/\{type\}/g,r).replace(/\{msg\}/g,l)),c[r]?u.hide():d.on("minimize",function(e){p.data("minimized")&&C()}),u.appendTo(d).data("cnt",0),null!=v?u.data({progress:0,total:0,cur:0}):(u.data({cur:0}),k(b)),y&&(h=e('').on("mouseenter mouseleave",function(t){e(this).toggleClass(w,"mouseenter"===t.type)}),u.children("div.elfinder-notify-cancel").append(h)),d.trigger("resize")),n=m+parseInt(u.data("cnt")),n>0?(y&&h.length&&("function"==typeof y||"object"==typeof y&&y.promise)&&(u._esc=function(t){"keydown"==t.type&&t.keyCode!=e.ui.keyCode.ESCAPE||(t.preventDefault(),t.stopPropagation(),x(),y.promise?y.reject(0):y(t))},h.on("click",function(e){u._esc(e)}),e(document).on("keydown."+this.namespace,u._esc)),!t.hideCnt&&u.children(".elfinder-notify-cnt").text("("+n+")"),m>0&&d.is(":hidden")&&!c[r]&&(p.data("minimized")?p.data("minimized").show():d.elfinderdialog("open",this).height("auto")),u.data("cnt",n),null!=v&&(i=u.data("total"))>=0&&(a=u.data("progress"))>=0&&(i+=null!=g?g:m,a+=v,null==g&&m<0&&(a+=100*m),u.data({progress:a,total:i}),null!=g&&(a*=100,i=Math.max(1,i)),v=Math.min(parseInt(a/i),100),u.find(".elfinder-notify-progress").animate({width:(v<100?v:100)+"%"},20,function(){u.data("cur",v),C()}))):x(),this):this},confirm:function(t){var n,i,a=this,o=!1,r={cssClass:"elfinder-dialog-confirm",modal:!0,resizable:!1,title:this.i18n(t.title||"confirmReq"),buttons:{},close:function(){!o&&t.cancel.callback(),e(this).elfinderdialog("destroy")}},s=this.i18n("apllyAll");return t.cssClass&&(r.cssClass+=" "+t.cssClass),r.buttons[this.i18n(t.accept.label)]=function(){t.accept.callback(!(!n||!n.prop("checked"))),o=!0,e(this).elfinderdialog("close")},r.buttons[this.i18n(t.accept.label)]._cssClass="elfinder-confirm-accept",t.reject&&(r.buttons[this.i18n(t.reject.label)]=function(){t.reject.callback(!(!n||!n.prop("checked"))),o=!0,e(this).elfinderdialog("close")},r.buttons[this.i18n(t.reject.label)]._cssClass="elfinder-confirm-reject"),t.buttons&&t.buttons.length>0&&(i=1,e.each(t.buttons,function(t,s){r.buttons[a.i18n(s.label)]=function(){s.callback(!(!n||!n.prop("checked"))),o=!0,e(this).elfinderdialog("close")},r.buttons[a.i18n(s.label)]._cssClass="elfinder-confirm-extbtn"+i++,s.cssClass&&(r.buttons[a.i18n(s.label)]._cssClass+=" "+s.cssClass)})),r.buttons[this.i18n(t.cancel.label)]=function(){e(this).elfinderdialog("close")},r.buttons[this.i18n(t.cancel.label)]._cssClass="elfinder-confirm-cancel",t.all&&(r.create=function(){var t=e('
              ');n=e(''),e(this).next().find(".ui-dialog-buttonset").prepend(t.append(e("").prepend(n)))}),t.optionsCallback&&"function"==typeof t.optionsCallback&&t.optionsCallback(r),this.dialog(''+this.i18n(t.text),r)},uniqueName:function(e,t,n){var i,a,o=0,r="";if(e=this.i18n(!1,e),t=t||this.cwd().hash,n="undefined"==typeof n?" ":n,(i=e.match(/^(.+)(\.[^.]+)$/))&&(r=i[2],e=i[1]),a=e+r,!this.fileByName(a,t))return a;for(;o<1e4;)if(a=e+n+ ++o+r,!this.fileByName(a,t))return a;return e+Math.random()+r},i18n:function(){var t,n,i,a,o,r=this,s=this.messages,l=[],c=[],d=function(e){var t;return 0===e.indexOf("#")&&(t=r.file(e.substr(1)))?t.name:e},p=0;for(arguments.length&&arguments[0]===!1&&(a=function(e){return e},p=1),t=p;t0&&l[n]&&c.push(n),i=a?a(l[n]):r.escape(l[n]),o&&(i=''+i+""),i})):i=i.get(0).outerHTML,l[t]=i);return e.grep(l,function(t,n){return e.inArray(n,c)===-1}).join("
              ")},getIconStyle:function(t,n){var i=this,a={background:"url('{url}') 0 0 no-repeat","background-size":"contain"},o="",r={},s=0;return t.icon&&(o='style="',e.each(a,function(e,a){0===s++&&(a=a.replace("{url}",i.escape(t.icon))),n?r[e]=a:o+=e+":"+a+";"}),o+='"'),n?r:o},mime2class:function(e){var t="elfinder-cwd-icon-",n=e.toLowerCase(),i=this.textMimes[n];return n=n.split("/"),i?n[0]+=" "+t+"text":n[1]&&n[1].match(/\+xml$/)&&(n[0]+=" "+t+"xml"),t+n[0]+(n[1]?" "+t+n[1].replace(/(\.|\+)/g,"-"):"")},mime2kind:function(e){var t,n="object"==typeof e,i=n?e.mime:e;return n&&e.alias&&"symlink-broken"!=i?t="Alias":this.kinds[i]?t=!n||"directory"!==i||e.phash&&!e.isroot?this.kinds[i]:"Root":this.mimeTypes[i]&&(t=this.mimeTypes[i].toUpperCase(),this.messages["kind"+t]||(t=null)),t||(t=0===i.indexOf("text")?"Text":0===i.indexOf("image")?"Image":0===i.indexOf("audio")?"Audio":0===i.indexOf("video")?"Video":0===i.indexOf("application")?"App":0===i.indexOf("font")?"Font":i),this.messages["kind"+t]?this.i18n("kind"+t):i},mimeIsText:function(e){return!!(this.textMimes[e.toLowerCase()]||0===e.indexOf("text/")&&"rtf"!==e.substr(5,3)||e.match(/^application\/.+\+xml$/))},date:function(e,t){var n,i,a,o,r,s,l,c,d,p=this;return t||(t=new Date),s=t[p.getHours](),l=s>12?s-12:s,c=t[p.getMinutes](),d=t[p.getSeconds](),i=t[p.getDate](),a=t[p.getDay](),o=t[p.getMonth]()+1,r=t[p.getFullYear](),n=e.replace(/[a-z]/gi,function(e){switch(e){case"d":return i>9?i:"0"+i;case"j":return i;case"D":return p.i18n(p.i18.daysShort[a]);case"l":return p.i18n(p.i18.days[a]);case"m":return o>9?o:"0"+o;case"n":return o;case"M":return p.i18n(p.i18.monthsShort[o-1]);case"F":return p.i18n(p.i18.months[o-1]);case"Y":return r;case"y":return(""+r).substr(2);case"H":return s>9?s:"0"+s;case"G":return s;case"g":return l;case"h":return l>9?l:"0"+l;case"a":return s>=12?"pm":"am";case"A":return s>=12?"PM":"AM";case"i":return c>9?c:"0"+c;case"s":return d>9?d:"0"+d}return e})},formatDate:function(e,t){var n,i,a,o=this,r=t||e.ts;o.i18;return o.options.clientFormatDate&&r>0?(n=new Date(1e3*r),i=r>=this.yesterday?this.fancyFormat:this.dateFormat,a=o.date(i,n),r>=this.yesterday?a.replace("$1",this.i18n(r>=this.today?"Today":"Yesterday")):a):e.date?e.date.replace(/([a-z]+)\s/i,function(e,t){return o.i18n(t)+" "}):o.i18n("dateUnknown")},toLocaleString:function(e){var t=new Number(e);return t?t.toLocaleString?t.toLocaleString():String(e).replace(/(\d)(?=(\d\d\d)+(?!\d))/g,"$1,"):e},perms2class:function(e){var t="";return e.read||e.write?e.read?e.write||(t="elfinder-ro"):t="elfinder-wo":t="elfinder-na",e.type&&(t+=" elfinder-"+this.escape(e.type)),t},formatPermissions:function(e){var t=[];return e.read&&t.push(this.i18n("read")),e.write&&t.push(this.i18n("write")),t.length?t.join(" "+this.i18n("and")+" "):this.i18n("noaccess")},formatSize:function(e){var t=1,n="b";return"unknown"==e?this.i18n("unknown"):(e>1073741824?(t=1073741824,n="GB"):e>1048576?(t=1048576,n="MB"):e>1024&&(t=1024,n="KB"),e/=t,(e>0?t>=1048576?e.toFixed(2):Math.round(e):0)+" "+n)},formatFileMode:function(t,n){var i,a,o,r,s,l,c,d,p;if(n||(n=this.options.fileModeStyle.toLowerCase()),t=e.trim(t),t.match(/[rwxs-]{9}$/i)){if(d=t=t.substr(-9),"string"==n)return d;for(p="",o=0,i=0;i<7;i+=3)a=t.substr(i,3),r=0,a.match(/[r]/i)&&(r+=4),a.match(/[w]/i)&&(r+=2),a.match(/[xs]/i)&&(a.match(/[xs]/)&&(r+=1),a.match(/[s]/i)&&(0==i?o+=4:3==i&&(o+=2))),p+=r.toString(8);o&&(p=o.toString(8)+p)}else{if(t=parseInt(t,8),p=t?t.toString(8):"",!t||"octal"==n)return p;for(a=t.toString(8),o=0,a.length>3&&(a=a.substr(-4),o=parseInt(a.substr(0,1),8),a=a.substr(1)),s=1==(1&o),c=2==(2&o),l=4==(4&o),d="",i=0;i<3;i++)d+=4==(4&parseInt(a.substr(i,1),8))?"r":"-",d+=2==(2&parseInt(a.substr(i,1),8))?"w":"-",d+=1==(1&parseInt(a.substr(i,1),8))?0==i&&l||1==i&&c?"s":"x":"-"}return"both"==n?d+" ("+p+")":"string"==n?d:p},registRawStringDecoder:function(e){"function"==typeof e&&(this.decodeRawString=this.options.rawStringDecoder=e)},uploadMimeCheck:function(t,n){n=n||this.cwd().hash;var i,a,o=!0,r=this.option("uploadMime",n),s=function(n){var i=!1;return"string"==typeof n&&"all"===n.toLowerCase()?i=!0:Array.isArray(n)&&n.length&&e.each(n,function(e,n){if(n=n.toLowerCase(),"all"===n||0===t.indexOf(n))return i=!0,!1}),i};return t&&e.isPlainObject(r)&&(t=t.toLowerCase(),i=s(r.allow),a=s(r.deny),"allow"===r.firstOrder?(o=!1,a||i!==!0||(o=!0)):(o=!0,a!==!0||i||(o=!1))),o},sequence:function(e){var t=e.length,n=function(t,i){return++i,e[i]?n(t.then(e[i]),i):t};return t>1?n(e[0](),0):e[0]()},reloadContents:function(t){var n,i=e.Deferred();try{n=e('';d.remove(),e(x).appendTo("body").ready(function(){setTimeout(function(){e(x).each(function(){e("#"+e(this).attr("id")).remove()})},2e4+1e4*i)}),b.trigger("download",{files:y}),w.resolve()}),u=y.length,g=[],i=0;i');return t&&e.each(t,function(e,t){a=i.escape(t.value),o.append('")}),e.each(n.options.encodings,function(e,t){o.append('")}),o},d=function(){var t,a,o=i.options.dialogContained?i.getUI():e(window);return a="string"==typeof n.options.dialogWidth&&(t=n.options.dialogWidth.match(/(\d+)%/))?parseInt(o.width()*(t[1]/100)):parseInt(n.options.dialogWidth||650),Math.min(a,o.width())},p=function(){if(n.options.dialogHeight){var t,a,o=i.options.dialogContained?i.getUI():e(window);return a="string"==typeof n.options.dialogHeight&&(t=n.options.dialogHeight.match(/(\d+)%/))?parseInt(o.height()*(t[1]/100)):parseInt(n.options.dialogHeight||o.height()),Math.min(a,o.height())}},u=function(t){var a,l,c,d=t.length;return d>1&&(a=t[0].mime,l=t[0].name.replace(/^.*(\.[^.]+)$/,"$1")),e.grep(t,function(t){var p;return!c&&"directory"!==t.mime&&(p=t.read&&(s||i.mimeIsText(t.mime)||e.inArray(t.mime,1===d?o:r)!==-1)&&(!n.onlyMimes.length||e.inArray(t.mime,n.onlyMimes)!==-1)&&(1===d||t.mime===a&&t.name.substr(l.length*-1)===l)&&!!i.uploadMimeCheck(t.mime,t.phash)&&b(t,d)&&Object.keys(g).length,p||(c=!0),p)})},h=function(e){var t,n=i.file(e);i.request({cmd:"info",targets:[e],preventDefault:!0}).done(function(e){var a;e&&e.files&&e.files.length&&(t=e.files[0],n.ts==t.ts&&n.size==t.size||(a={changed:[t]},i.updateCache(a),i.change(a)))})},f=function(t,o,r,s,u,f){var g,v,b,y,w,k,C=e.Deferred(),z=!1,T=function(){return!!z||(i.toast({mode:"warning",msg:i.i18n("nowLoading")}),!1)},A=function(){f&&Array.isArray(f)&&e.each(f,function(){this.msg&&i.toast(this)})},j=function(){var t,n,a,o=y?y.val():void 0,r=e.Deferred().fail(function(e){b.show().find("button.elfinder-btncnt-0,button.elfinder-btncnt-1").hide()});return T()?(g.editor&&(g.editor.save(g[0],g.editor.instance),t=g.editor.confObj,t.info&&(t.info.schemeContent||t.info.arrayBufferContent)&&(o="scheme")),n=D(),U(n),n.promise?(a=setTimeout(function(){i.notify({type:"chkcontent",cnt:1,hideCnt:!0,cancel:function(){n.reject()}})},100),n.always(function(){a&&clearTimeout(a),i.notify({type:"chkcontent",cnt:-1})}).done(function(e){C.notifyWith(g,[o,g.data("hash"),v,r])}).fail(function(e){r.reject(e)})):C.notifyWith(g,[o,g.data("hash"),v,r]),r):r.resolve()},O=function(){T()&&j().fail(function(e){e&&i.error(e)})},S=function(){if(n.options.confirmUnsavedBeforeClose){var t=function(){var e;C.resolve(),g.editor&&(g.editor.close(g[0],g.editor.instance),e=g.editor.confObj,e.info&&e.info.syncInterval&&h(o.hash)),g.elfinderdialog("destroy")},a="undefined"!=typeof q.name,r=a?{label:"btnSaveAs",callback:function(){requestAnimationFrame(M)}}:{label:"btnSaveClose",callback:function(){j().done(function(){t()})}};F().done(function(o){var s=["confirmNotSave"],l={label:"btnDiscard",callback:function(){t()}};o?("string"==typeof o&&s.unshift(o),i.confirm({title:n.title,text:s,accept:r,cancel:{label:"btnCancel",callback:e.noop},buttons:a?[l]:[{label:"btnSaveAs",callback:function(){g.elfinderdialog("destroy"),requestAnimationFrame(M)}},l]})):t()})}else g.elfinderdialog("close")},I=function(){T()&&(b.hide(),j().done(function(){z=!1,b.show(),S()}).fail(function(e){b.show(),e&&i.error(e)}))},M=function(){if(T()){var t=v,r=o.phash,s=function(e){p.addClass(a).fadeIn(function(){e&&i.error(e)}),v=t,i.disable()},l=function(){n.mime=q.mime||o.mime,n.prefix=(q.name||o.name).replace(/ \d+(\.[^.]+)?$/,"$1"),n.requestCmd="mkfile",n.nextAction={},n.data={target:r},e.proxy(i.res("mixin","make"),n)().done(function(e){var t;e.added&&e.added.length?(t=g.data("hash"),g.data("hash",e.added[0].hash),j().done(function(){z=!1,b.show(),S(),p.fadeIn()}).fail(function(){i.exec("rm",[e.added[0].hash],{forceRm:!0,quiet:!0}),g.data("hash",t),b.find("button.elfinder-btncnt-2").hide(),s()})):s()}).progress(function(e){e&&"errUploadMime"===e&&g.trigger("saveAsFail")}).fail(s).always(function(){delete n.mime,delete n.prefix,delete n.nextAction,delete n.data}),i.trigger("unselectfiles",{files:[o.hash]})},c=null,d=null,p=i.getUI().children("."+n.dialogClass+":visible");b.is(":hidden")&&(p=p.add(b)),p.removeClass(a).fadeOut(),i.enable(),i.searchStatus.state<2&&r!==i.cwd().hash?c=i.exec("open",[r],{thash:r}):i.file(r)||(d=i.request({cmd:"info",targets:[r]})),e.when([c,d]).done(function(){d?i.one("infodone",function(){i.file(r)?l():s("errFolderNotFound")}):c?i.one("cwdrender",l):l()}).fail(s)}},F=function(){var t,n,a=e.Deferred();return z?(g.editor&&g.editor.save(g[0],g.editor.instance),t=D(),t&&t.promise?(n=setTimeout(function(){i.notify({type:"chkcontent",cnt:1,hideCnt:!0,cancel:function(){t.reject()}})},100),t.always(function(){n&&clearTimeout(n),i.notify({type:"chkcontent",cnt:-1})}).done(function(e){a.resolve(v!==e)}).fail(function(e){a.resolve(e||void 0!==v)})):a.resolve(v!==t),a):a.resolve(!1)},E={title:i.escape(o.name),width:d(),height:p(),buttons:{},cssClass:a,maxWidth:"window",maxHeight:"window",allowMinimize:!0,allowMaximize:!0,openMaximized:x()||u&&u.info&&u.info.openMaximized,btnHoverFocus:!1,closeOnEscape:!1,propagationEvents:["mousemove","mouseup","click"],minimize:function(){var e;g.editor&&b.closest(".ui-dialog").is(":hidden")&&(e=g.editor.confObj,e.info&&e.info.syncInterval&&h(o.hash))},headerBtnCloseAction:n.options.confirmUnsavedBeforeClose?function(){S()}:void 0,close:function(){if(!n.options.confirmUnsavedBeforeClose){var e=function(){var e;C.resolve(),g.editor&&(g.editor.close(g[0],g.editor.instance),e=g.editor.confObj,e.info&&e.info.syncInterval&&h(o.hash)),g.elfinderdialog("destroy")},t="undefined"!=typeof q.name,a=t?{label:"btnSaveAs",callback:function(){requestAnimationFrame(M)}}:{label:"btnSaveClose",callback:function(){j().done(function(){e()})}};F().done(function(o){var r=["confirmNotSave"];o?("string"==typeof o&&r.unshift(o),i.confirm({title:n.title,text:r,accept:a,cancel:{label:"btnClose",callback:e},buttons:t?null:[{label:"btnSaveAs",callback:function(){requestAnimationFrame(M)}}]})):e()})}},open:function(){var e,n,a;if(g.initEditArea.call(g,t,o,r,i),g.editor){if(e=g.editor.load(g[0])||null,e&&e.done)e.always(function(){z=!0}).done(function(e){g.editor.instance=e,g.editor.focus(g[0],g.editor.instance),U(D()),requestAnimationFrame(function(){b.trigger("resize")})}).fail(function(e){e&&i.error(e),g.elfinderdialog("destroy")}).always(A);else{if(z=!0,e&&("string"==typeof e||Array.isArray(e)))return i.error(e),void g.elfinderdialog("destroy");g.editor.instance=e,g.editor.focus(g[0],g.editor.instance),U(D()),requestAnimationFrame(function(){b.trigger("resize")}),A()}n=g.editor.confObj,n.info&&n.info.syncInterval&&(a=parseInt(n.info.syncInterval))&&setTimeout(function(){P(a)},a)}else z=!0,U(D())},resize:function(e,t){g.editor&&g.editor.resize(g[0],g.editor.instance,e,t||{})}},D=function(){var t=g.getContent.call(g,g[0]);return void 0!==t&&t!==!1&&null!==t||(t=e.Deferred().reject()),t},U=function(e){e&&e.promise?e.done(function(e){v=e}):v=e},P=function(e){b.is(":visible")&&(h(o.hash),setTimeout(function(){P(e)},e))},R=function(){y&&F().done(function(e){e?y.attr("title",i.i18n("saveAsEncoding")).addClass("elfinder-edit-changed"):y.attr("title",i.i18n("openAsEncoding")).removeClass("elfinder-edit-changed")})},q={};if(u&&(u.html&&(g=e(u.html)),w={init:u.init||null,load:u.load,getContent:u.getContent||null,save:u.save,beforeclose:"function"==typeof u.beforeclose?u.beforeclose:void 0,close:"function"==typeof u.close?u.close:function(){},focus:"function"==typeof u.focus?u.focus:function(){},resize:"function"==typeof u.resize?u.resize:function(){},instance:null,doSave:O,doCancel:S,doClose:I,file:o,fm:i,confObj:u,trigger:function(e,t){i.trigger("editEditor"+e,Object.assign({},u.info||{},t))}}),!g){if(!i.mimeIsText(o.mime))return C.reject("errEditorNotFound");!function(){g=e('').on("input propertychange",R),u&&u.info&&!u.info.useTextAreaEvent||g.on("keydown",function(t){var n,i,a=t.keyCode;t.stopPropagation(),a==e.ui.keyCode.TAB&&(t.preventDefault(),this.setSelectionRange&&(n=this.value,i=this.selectionStart,this.value=n.substr(0,i)+"\t"+n.substr(this.selectionEnd),i+=1,this.setSelectionRange(i,i))),(t.ctrlKey||t.metaKey)&&(a!="Q".charCodeAt(0)&&a!="W".charCodeAt(0)||(t.preventDefault(),S()),a=="S".charCodeAt(0)&&(t.preventDefault(),O()))}).on("mouseenter",function(){this.focus()}),g.initEditArea=function(e,t,n){g.hide().val(n),this._setupSelEncoding(n)}}()}return g._setupSelEncoding=function(t){var n=s&&"unknown"!==s?[{value:s}]:[],a=e("").hide(),r=function(t){t&&a.appendTo(y.parent()),a.empty().append(e("").text(y.val())),y.width(a.width())};""!==t&&s&&"UTF-8"===s||n.push({value:"UTF-8"}),y=c(n).on("touchstart",function(e){e.stopPropagation()}).on("change",function(){F().done(function(e){e||""===D()||(S(),m(o,y.val(),u).fail(function(e){e&&i.error(e)}))}),r()}).on("mouseover",R),g.parent().next().prepend(e('
              ').append(y)),r(!0)},g.data("hash",o.hash),w&&(g.editor=w,"function"==typeof w.beforeclose&&(E.beforeclose=function(){return w.beforeclose(g[0],w.instance)}),"function"==typeof w.init&&(g.initEditArea=w.init),"function"==typeof w.getContent&&(g.getContent=w.getContent)),g.initEditArea||(g.initEditArea=function(){}),g.getContent||(g.getContent=function(){return l(g.val())}),u&&u.info&&u.info.preventGet||(E.buttons[i.i18n("btnSave")]=O,E.buttons[i.i18n("btnSaveClose")]=I,E.buttons[i.i18n("btnSaveAs")]=M,E.buttons[i.i18n("btnCancel")]=S),u&&"function"==typeof u.prepare&&u.prepare(g,E,o),b=n.fmDialog(g,E).attr("id",t).on("keydown keyup keypress",function(e){e.stopPropagation()}).css({overflow:"hidden",minHeight:"7em"}).addClass("elfinder-edit-editor").closest(".ui-dialog").on("changeType",function(t,n){if(n.extention&&n.mime){var a=(n.extention,n.mime,e(this).children(".ui-dialog-buttonpane").children(".ui-dialog-buttonset"));a.children(".elfinder-btncnt-0,.elfinder-btncnt-1").hide(),q.name=i.splitFileExtention(o.name)[0]+"."+n.extention,q.mime=n.mime,n.keepEditor||a.children(".elfinder-btncnt-2").trigger("click")}}),k=(i.options.dialogContained?i.getUI():e(window)).width(),b.width()>k&&b.width(k),C.promise()},m=function(t,a,o){var r,s,l,d=t.hash,p=(i.options,e.Deferred()),u="edit-"+i.namespace+"-"+t.hash,h=i.getUI().find("#"+u),g=a?a:0,v=!1;if(h.length)return h.elfinderdialog("toTop"),p.resolve();if(!(t.read&&(t.write||o.info&&o.info.converter)))return s=["errOpen",t.name,"errPerm"],p.reject(s);if(o&&o.info){if("function"==typeof o.info.edit)return l=o.info.edit.call(i,t,o),l.promise?l.done(function(){p.resolve()}).fail(function(e){p.reject(e)}):l?p.resolve():p.reject(),p;v=o.info.preventGet||o.info.noContent,o.info.urlAsContent||v?(r=e.Deferred(),o.info.urlAsContent?i.url(d,{async:!0,onetime:!0,temporary:!0}).done(function(e){r.resolve({content:e})}):r.resolve({})):(g&&(t.encoding=g,i.cache(t,"change")),r=i.request({data:{cmd:"get",target:d,conv:g,_t:t.ts},options:{type:"get",cache:!0},notify:{type:"file",cnt:1},preventDefault:!0})),r.done(function(a){var r,s,l;a.doconv?i.confirm({title:n.title,text:"unknown"===a.doconv?"confirmNonUTF8":"confirmConvUTF8",accept:{label:"btnConv",callback:function(){p=m(t,r.val(),o)}},cancel:{label:"btnCancel",callback:function(){p.reject()}},optionsCallback:function(t){t.create=function(){var t=e('
              '),n={value:a.doconv};"unknown"===a.doconv&&(n.caption="-"),r=c([n]),e(this).next().find(".ui-dialog-buttonset").prepend(t.append(e("").append(r)))}}}):(!v&&i.mimeIsText(t.mime)&&(s=new RegExp("^(data:"+t.mime.replace(/([.+])/g,"\\$1")+";base64,)","i"),o.info.dataScheme?window.btoa&&!a.content.match(s)&&(a.content="data:"+t.mime+";base64,"+btoa(a.content)):window.atob&&(l=a.content.match(s))&&(a.content=atob(a.content.substr(l[1].length)))),f(u,t,a.content,a.encoding,o,a.toasts).done(function(e){p.resolve(e)}).progress(function(e,t,n,a){var o=this;t&&(d=t),i.request({options:{type:"post"},data:{cmd:"put",target:d,encoding:e||n.encoding,content:n},notify:{type:"save",cnt:1},syncOnFail:!0,preventFail:!0,navigate:{target:"changed",toast:{inbuffer:{msg:i.i18n(["complete",i.i18n("btnSave")])}}}}).fail(function(e){p.reject(e),a.reject()}).done(function(e){requestAnimationFrame(function(){o.trigger("focus"),o.editor&&o.editor.focus(o[0],o.editor.instance)}),a.resolve()})}).fail(function(e){p.reject(e)}))}).fail(function(e){var n=i.parseError(e);n=Array.isArray(n)?n[0]:n,t.encoding&&(t.encoding="",i.cache(t,"change")),"errConvUTF8"!==n&&i.sync(),p.reject(e)})}return p.promise()},g={},v={info:{id:"textarea",name:"TextArea",useTextAreaEvent:!0},load:function(t){this.trigger("Prepare",{node:t,editorObj:void 0,instance:void 0,opts:{}}),t.setSelectionRange&&t.setSelectionRange(0,0),e(t).trigger("focus").show()},save:function(){}},b=function(a,o){var r=function(t,n){if(n){if("*"===n[0]||e.inArray(t,n)!==-1)return!0;var a,o;for(o=n.length,a=0;a0||!t.info.converter&&t.info.canMakeEmpty!==!1&&i.mimesCanMakeEmpty[a.mime])&&(!t.info.maxSize||a.size<=t.info.maxSize)&&r(a.mime,t.mimes||null)&&s(a.name,t.exts||null)&&"function"==typeof t.load&&"function"==typeof t.save&&(n=t.info.name?t.info.name:"Editor "+e,t.id=t.info.id?t.info.id:"editor"+e,t.name=n,t.i18n=i.i18n(n),g[t.id]=t)}),!!Object.keys(g).length},y=function(n,a){n&&a&&(e.isPlainObject(t)||(t={}),t[n]=a.id,i.storage("storedEditors",t),i.trigger("selectfiles",{files:i.selected()}))},w=function(){var e=i.storage("useStoredEditor");return e?e>0:n.options.useStoredEditor},x=function(){var e=i.storage("editorMaximized");return e?e>0:n.options.editorMaximized},k=function(t,n){var a=[];return e.each(g,function(e,o){a.push({label:i.escape(o.i18n),icon:o.info&&o.info.icon?o.info.icon:"edit",options:{iconImg:o.info&&o.info.iconImg?i.baseUrl+o.info.iconImg:void 0},callback:function(){y(t[0].mime,o),n&&n.call(o)}})}),a},C=function(e){return e.toLowerCase().replace(/ +/g,"")},z=function(e){var n=t[e];return n&&Object.keys(g).length?g[C(n)]:void 0};this.getEncSelect=c,this.shortcuts=[{pattern:"ctrl+e"}],this.init=function(){var t,n,i=this,a=this.fm,l=this.options,c=[];this.onlyMimes=this.options.mimes||[],a.one("open",function(){l.editors&&Array.isArray(l.editors)&&(a.trigger("canMakeEmptyFile",{mimes:Object.keys(a.storage("mkfileTextMimes")||{}).concat(l.makeTextMimes||["text/plain"])}),e.each(l.editors,function(e,t){t.info&&t.info.cmdCheck&&c.push(t.info.cmdCheck)}),c.length?a.api>=2.103?n=a.request({data:{cmd:"editor",name:c,method:"enabled"},preventDefault:!0}).done(function(e){t=e}).fail(function(){t={}}):(t={},n=e.Deferred().resolve()):n=e.Deferred().resolve(),n.always(function(){t&&(l.editors=e.grep(l.editors,function(e){return!e.info||!e.info.cmdCheck||!!t[e.info.cmdCheck]})),e.each(l.editors,function(e,t){t.setup&&"function"==typeof t.setup&&t.setup.call(t,l,a),t.disabled||(t.mimes&&Array.isArray(t.mimes)&&(o=o.concat(t.mimes),t.info&&t.info.single||(r=r.concat(t.mimes))),!s&&t.mimes&&"*"===t.mimes[0]&&(s=!0),t.info||(t.info={}),t.info.integrate&&a.trigger("helpIntegration",Object.assign({cmd:"edit"},t.info.integrate)),t.info.canMakeEmpty&&a.trigger("canMakeEmptyFile",{mimes:Array.isArray(t.info.canMakeEmpty)?t.info.canMakeEmpty:t.mimes}))}),o=(e.uniqueSort||e.unique)(o),r=(e.uniqueSort||e.unique)(r),l.editors=e.grep(l.editors,function(e){return!e.disabled})}))}).bind("select",function(){g=null}).bind("contextmenucreate",function(t){var n,o,r=function(e){var t=i.title;a.one("contextmenucreatedone",function(){i.title=t}),i.title=a.escape(e.i18n),e.info&&e.info.iconImg&&(i.contextmenuOpts={iconImg:a.baseUrl+e.info.iconImg}),delete i.variants};i.contextmenuOpts=void 0,"files"===t.data.type&&i.enabled()&&(n=a.file(t.data.targets[0]),b(n,t.data.targets.length)&&(Object.keys(g).length>1?w()&&(o=z(n.mime))?(r(o),i.extra={icon:"menu",node:e("").attr({title:a.i18n("select")}).on("click touchstart",function(t){if(!("touchstart"===t.type&&t.originalEvent.touches.length>1)){var n=e(this);t.stopPropagation(),t.preventDefault(),a.trigger("contextmenu",{raw:k(a.selectedFiles(),function(){var e=a.selected();a.exec("edit",e,{editor:this}),a.trigger("selectfiles",{files:e})}),x:n.offset().left,y:n.offset().top})}})}):(delete i.extra,i.variants=[],e.each(g,function(e,t){i.variants.push([{editor:t},t.i18n,t.info&&t.info.iconImg?a.baseUrl+t.info.iconImg:"edit"])})):(r(g[Object.keys(g)[0]]),delete i.extra)))}).bind("canMakeEmptyFile",function(t){if(t.data&&t.data.resetTexts){var n=a.arrayFlip(i.options.makeTextMimes||["text/plain"]),o=i.getMkfileHides();e.each(a.storage("mkfileTextMimes")||{},function(e,t){n[e]||(delete a.mimesCanMakeEmpty[e],delete o[e])}),a.storage("mkfileTextMimes",null),Object.keys(o).length?a.storage("mkfileHides",o):a.storage("mkfileHides",null)}})},this.getstate=function(e){var t=this.files(e),n=t.length;return n&&u(t).length==n?0:-1},this.exec=function(t,n){var i,a=this.fm,o=u(this.files(t)),r=e.map(o,function(e){return e.hash}),s=[],l=n&&n.editor?n.editor:null,c=e(n&&n._currentNode?n._currentNode:a.cwdHash2Elm(r[0])),d=function(){var t=e.Deferred();return!l&&Object.keys(g).length>1?w()&&(l=z(o[0].mime))?t.resolve(l):(a.trigger("contextmenu",{raw:k(o,function(){t.resolve(this)}),x:c.offset().left,y:c.offset().top+22,opened:function(){a.one("closecontextmenu",function(){requestAnimationFrame(function(){"pending"===t.state()&&t.reject()})})}}),a.trigger("selectfiles",{files:r}),t):(Object.keys(g).length>1&&l&&y(o[0].mime,l),t.resolve(l?l:Object.keys(g).length?g[Object.keys(g)[0]]:null))},p=e.Deferred();return null===g&&b(o[0],r.length),c.length||(c=a.getUI("cwd")),d().done(function(t){for(;i=o.shift();)s.push(m(i,i.encoding||void 0,t).fail(function(e){e&&a.error(e)}));s.length?e.when.apply(null,s).done(function(){p.resolve()}).fail(function(){p.reject()}):p.reject()}).fail(function(){p.reject()}),p},this.getMkfileHides=function(){return i.storage("mkfileHides")||i.arrayFlip(n.options.mkfileHideMimes||[])}},i.prototype.commands.empty=function(){var t,n,i=function(e){var i=t.files(e);return i.length||(i=[n.cwd()]),i};this.linkedCmds=["rm"],this.init=function(){t=this,n=this.fm},this.getstate=function(t){var n,a=i(t),o=function(t){var n=!0;return e.grep(t,function(e){return n=!!(n&&e.read&&e.write&&"directory"===e.mime)})};return n=a.length,o(a).length==n?0:-1},this.exec=function(t){var a=i(t),o=a.length,r=e.Deferred().done(function(){var t={changed:{}};n.toast({msg:n.i18n(['"'+s.join('", ')+'"',"complete",n.i18n("cmdempty")])}),e.each(a,function(e,n){t.changed[n.hash]=n}),n.change(t)}).always(function(){var t=n.cwd().hash;n.trigger("selectfiles",{files:e.map(a,function(e){return t===e.phash?e.hash:null})})}),s=[],l=function(e){"number"==typeof e?(s.push(a[e].name),delete a[e].dirs):e&&n.error(e),--o<1&&r[s.length?"resolve":"reject"]()};return e.each(a,function(t,i){var a;return i.write&&"directory"===i.mime?n.isCommandEnabled("rm",i.hash)?(a=setTimeout(function(){n.notify({type:"search",cnt:1,hideCnt:!(o>1)})},n.notifyDelay),void n.request({data:{cmd:"open",target:i.hash},preventDefault:!0,asNotOpen:!0}).done(function(r){var s=[];a&&clearTimeout(a),n.ui.notify.children(".elfinder-notify-search").length&&n.notify({type:"search",cnt:-1,hideCnt:!(o>1)}),r&&r.files&&r.files.length?r.files.length>n.maxTargets?l(["errEmpty",i.name,"errMaxTargets",n.maxTargets]):(n.updateCache(r),e.each(r.files,function(e,t){return!t.write||t.locked?(l(["errEmpty",i.name,"errRm",t.name,"errPerm"]),s=[],!1):void s.push(t.hash)}),s.length&&n.exec("rm",s,{_userAction:!0,addTexts:[n.i18n("folderToEmpty",i.name)]}).fail(function(e){n.trigger("unselectfiles",{files:n.selected()}),l(n.parseError(e)||"")}).done(function(){l(t)})):(n.toast({mode:"warning",msg:n.i18n("filderIsEmpty",i.name)}),l(""))}).fail(function(e){l(n.parseError(e)||"")})):(l(["errCmdNoSupport",'"rm"']),null):(l(["errEmpty",i.name,"errPerm"]),null)}),r}},i.prototype.commands.extract=function(){var t=this,n=t.fm,i=[],a=function(t){var n=!0;return e.grep(t,function(t){return n=!(!n||!t.read||e.inArray(t.mime,i)===-1)})};this.variants=[],this.disableOnSearch=!0,n.bind("open reload",function(){i=n.option("archivers").extract||[],n.api>2?t.variants=[[{makedir:!0},n.i18n("cmdmkdir")],[{},n.i18n("btnCwd")]]:t.variants=[[{},n.i18n("btnCwd")]],t.change()}),this.getstate=function(t){var i,o,r=this.files(t),s=r.length;return s&&a(r).length==s?n.searchStatus.state>0?(i=this.fm.cwd().hash,e.each(r,function(e,t){return o=t.phash===i}),o?0:-1):this.fm.cwd().write?0:-1:-1},this.exec=function(t,a){var o,r,s,l=this.files(t),c=e.Deferred(),d=l.length,p=a&&a.makedir?1:0,u=!1,h=!1,f=0,m=n.files(l[0].phash),g=[],v={};e.each(m,function(e,t){v[t.name]=t,g.push(t.name)});var b=function(e){switch(e){case"overwrite_all":u=!0;break;case"omit_all":h=!0}},y=function(t){t.read&&n.file(t.phash).write?e.inArray(t.mime,i)===-1?(r=["errExtract",t.name,"errNoArchive"],n.error(r),c.reject(r)):n.request({data:{cmd:"extract",target:t.hash,makedir:p},notify:{type:"extract",cnt:1},syncOnFail:!0,navigate:{toast:p?{incwd:{msg:n.i18n(["complete",n.i18n("cmdextract")]),action:{cmd:"open",msg:"cmdopen"}},inbuffer:{msg:n.i18n(["complete",n.i18n("cmdextract")]),action:{cmd:"open",msg:"cmdopen"}}}:{inbuffer:{msg:n.i18n(["complete",n.i18n("cmdextract")])}}}}).fail(function(e){"rejected"!=c.state()&&c.reject(e)}).done(function(){}):(r=["errExtract",t.name,"errPerm"],n.error(r),c.reject(r))},w=function(t,i){var a=t[i],r=n.splitFileExtention(a.name)[0],l=e.inArray(r,g)>=0,m=function(){i+10&&y(a),m())};return this.enabled()&&d&&i.length?(d>0&&w(l,0),c):c.reject()}},(i.prototype.commands.forward=function(){this.alwaysEnabled=!0,this.updateOnSelect=!0,this.shortcuts=[{pattern:"ctrl+right"}],this.getstate=function(){return this.fm.history.canForward()?0:-1},this.exec=function(){return this.fm.history.forward()}}).prototype={forceLoad:!0},i.prototype.commands.fullscreen=function(){var t=this,n=this.fm,i=function(e,i){var a;e.preventDefault(),e.stopPropagation(),i&&i.fullscreen&&(a="on"===i.fullscreen,t.update(void 0,a),t.title=n.i18n(a?"reinstate":"cmdfullscreen"))};this.alwaysEnabled=!0,this.updateOnSelect=!1,this.syncTitleOnChange=!0,this.value=!1,this.options={ui:"fullscreenbutton"},this.getstate=function(){return 0},this.exec=function(){var i=n.getUI().get(0),a=i===n.toggleFullscreen(i);return t.title=n.i18n(a?"reinstate":"cmdfullscreen"),t.update(void 0,a),e.Deferred().resolve()},n.bind("init",function(){n.getUI().off("resize."+n.namespace,i).on("resize."+n.namespace,i)})},(i.prototype.commands.getfile=function(){var t=this,n=this.fm,i=function(n){var i=t.options,a=!0;return n=e.grep(n,function(e){return a=!(!a||"directory"==e.mime&&!i.folders||!e.read)}),i.multiple||1==n.length?n:[]};this.alwaysEnabled=!0,this.callback=n.options.getFileCallback,this._disabled="function"==typeof this.callback,this.getstate=function(e){var t=this.files(e),n=t.length;return this.callback&&n&&i(t).length==n?0:-1},this.exec=function(n){var i,a,o,r=this.fm,s=this.options,l=this.files(n),c=l.length,d=r.option("url"),p=r.option("tmbUrl"),u=e.Deferred().done(function(e){var n,i=function(){"close"==s.oncomplete?r.hide():"destroy"==s.oncomplete&&r.destroy()},a=function(e){"close"==s.onerror?r.hide():"destroy"==s.onerror?r.destroy():e&&r.error(e)};r.trigger("getfile",{files:e});try{n=t.callback(e,r)}catch(o){return void a(["Error in `getFileCallback`.",o.message])}"object"==typeof n&&"function"==typeof n.done?n.done(i).fail(a):i()}),h=function(t){return s.onlyURL?s.multiple?e.map(l,function(e){return e.url}):l[0].url:s.multiple?l:l[0]},f=[];for(i=0;i {link}
              ',d='
              {author}
              {work}
              ',p=/\{url\}/,u=/\{link\}/,h=/\{author\}/,f=/\{work\}/,m="replace",g="ui-priority-primary",v="ui-priority-secondary",b="elfinder-help-license",y='
            • {title}
            • ',w=['
              ','
                '],x='
                {pattern}
                {descrip}
                ',k='
                ',C=e("base").length?s.escape(document.location.href.replace(/#.*$/,"")):"",z=s.res("class","tabsactive"),T=function(){var e;return e=s.theme&&s.theme.author?d[m]("elfinder-help-team","elfinder-help-team elfinder-help-term-theme")[m](h,s.i18n(s.theme.author)+(s.theme.email?" <"+s.theme.email+">":""))[m](f,s.i18n("theme")+" ("+s.i18n(s.theme.name)+")"):''},A=function(){w.push('
                '),w.push("

                elFinder

                "),w.push('
                '+s.i18n("webfm")+"
                "),w.push('
                '+s.i18n("ver")+": "+s.version+"
                "),w.push('
                '+s.i18n("protocolver")+':
                '),w.push('
                jQuery/jQuery UI: '+e().jquery+"/"+e.ui.version+"
                "),w.push(k),w.push(c[m](p,"https://studio-42.github.io/elFinder/")[m](u,s.i18n("homepage"))),w.push(c[m](p,"https://github.com/Studio-42/elFinder/wiki")[m](u,s.i18n("docs"))),w.push(c[m](p,"https://github.com/Studio-42/elFinder")[m](u,s.i18n("github"))),w.push(k),w.push('
                '+s.i18n("team")+"
                "),w.push(d[m](h,'Dmitry "dio" Levashov <dio@std42.ru>')[m](f,s.i18n("chiefdev"))),w.push(d[m](h,"Naoki Sawada (nao-pon)<hypweb+elfinder@gmail.com>")[m](f,s.i18n("developer"))),w.push(d[m](h,"Troex Nevelin <troex@fury.scancode.ru>")[m](f,s.i18n("maintainer"))),w.push(d[m](h,"Alexey Sukhotin <strogg@yandex.ru>")[m](f,s.i18n("contributor"))),s.i18[s.lang].translator&&e.each(s.i18[s.lang].translator.split(", "),function(){w.push(d[m](h,e.trim(this))[m](f,s.i18n("translator")+" ("+s.i18[s.lang].language+")"))}),w.push(T()),w.push(k),w.push('
                '+s.i18n("icons")+': Pixelmixer, Fugue, Icons8
                '),w.push(k),w.push('
                Licence: 3-clauses BSD Licence
                '),w.push('
                Copyright © 2009-2024, Studio 42 / nao-pon
                '), +w.push('
                „ …'+s.i18n("dontforget")+" ”
                "),w.push("
                ")},j=function(){var t=s.shortcuts();w.push('
                '),t.length?(w.push('
                '),e.each(t,function(e,t){w.push(x.replace(/\{pattern\}/,t[0]).replace(/\{descrip\}/,t[1]))}),w.push("
                ")):w.push('
                '+s.i18n("shortcutsof")+"
                "),w.push("
                ")},O=function(){w.push('
                '),w.push('DON\'T PANIC'),w.push("
                ")},S=!1,I=function(){S=!0,w.push('
                ')},M=!1,F=function(){M=!0,w.push('
                '),w.push('
                  '),w.push("
                  ")},E=function(){var n,i,a,c,d,p,u=function(t,n){return e.each(n,function(n,i){t.append(e("
                  ").text(n)),"undefined"==typeof i?t.append(e("
                  ").append(e("").text("undfined"))):"object"!=typeof i||i?"object"==typeof i&&(e.isPlainObject(i)||i.length)?t.append(e("
                  ").append(u(e("
                  "),i))):t.append(e("
                  ").append(e("").text(i&&"object"==typeof i?"[]":i?i:'""'))):t.append(e("
                  ").append(e("").text("null")))}),t},h=r.children("li").length;(l.debug.options||l.debug.debug)&&(h>=5&&(d=r.children("li:last"),p=o.children("div:last"),p.is(":hidden")?(d.remove(),p.remove()):(d.prev().remove(),p.prev().remove())),a=s.namespace+"-help-debug-"+ +new Date,n=e("
                • ").html(''+l.debug.debug.cmd+"").prependTo(r),i=e('
                  ').data("debug",l.debug),n.on("click.debugrender",function(){var t=i.data("debug");i.removeData("debug"),t&&(i.hide(),t.debug&&(c=e("
                  ").append(e("").text("debug"),u(e("
                  "),t.debug)),i.append(c)),t.options&&(c=e("
                  ").append(e("").text("options"),u(e("
                  "),t.options)),i.append(c)),i.show()),n.off("click.debugrender")}),r.after(i),t&&o.tabs("refresh"))},D="";this.alwaysEnabled=!0,this.updateOnSelect=!1,this.state=-1,this.shortcuts=[{pattern:"f1",description:this.title}],s.bind("load",function(){var c,d,p,u,h,f,g=l.options.view||["about","shortcuts","help","integrations","debug"];(c=e.inArray("preference",g))!==-1&&g.splice(c,1),e.fn.tabs||(c=e.inArray(g,"debug"))!==-1&&g.splice(c,1),e.each(g,function(e,t){w.push(y[m](/\{id\}/g,t)[m](/\{title\}/,s.i18n(t)))}),w.push("
                "),e.inArray("about",g)!==-1&&A(),e.inArray("shortcuts",g)!==-1&&j(),e.inArray("help",g)!==-1&&(d=s.i18nBaseUrl+"help/%s.html.js",O()),e.inArray("integrations",g)!==-1&&I(),e.inArray("debug",g)!==-1&&F(),w.push("
                "),D=e(w.join("")),D.find(".ui-tabs-nav li").on("mouseenter mouseleave",function(t){e(this).toggleClass("ui-state-hover","mouseenter"===t.type)}).on("focus blur","a",function(t){e(t.delegateTarget).toggleClass("ui-state-focus","focusin"===t.type)}).children().on("click",function(t){var n=e(this);t.preventDefault(),t.stopPropagation(),n.parent().addClass(z).siblings().removeClass(z),D.children(".ui-tabs-panel").hide().filter(n.attr("href")).show()}).filter(":first").trigger("click"),S&&(n=D.find(".elfinder-help-tab-integrations").hide(),i=D.find("#"+s.namespace+"-help-integrations").hide().append(e('
                ').html(s.i18n("integrationWith"))),s.bind("helpIntegration",function(t){var a,o,r,l,c=i.children("ul:first");t.data&&(e.isPlainObject(t.data)?(a=Object.assign({link:"",title:"",banner:""},t.data),(a.title||a.link)&&(a.title||(a.title=a.link),o=a.link?e("").attr("href",a.link).attr("target","_blank").text(a.title):e("").text(a.title),a.banner&&(o=e("").append(e("").attr(a.banner),o)))):(o=e(t.data),o.filter("a").each(function(){var t=e(this);t.attr("target")||t.attr("target","_blank")})),o&&(n.show(),c.length||(c=e('
                  ').appendTo(i)),a&&a.cmd?(l="elfinder-help-integration-"+a.cmd,r=c.find("ul."+l),r.length||(r=e('
                    '),c.append(e("
                  • ").append(e("").html(s.i18n("cmd"+a.cmd))).append(r))),o=r.append(e("
                  • ").append(o))):c.append(e("
                  • ").append(o))))}).bind("themechange",function(){D.find("div.elfinder-help-term-theme").replaceWith(T())})),M&&(a=D.find(".elfinder-help-tab-debug").hide(),o=D.find("#"+s.namespace+"-help-debug").children("div:first"),r=o.children("ul:first").on("click",function(e){e.preventDefault(),e.stopPropagation()}),l.debug={},s.bind("backenddebug",function(e){M&&e.data&&e.data.debug&&(l.debug={options:e.data.options,debug:Object.assign({cmd:s.currentReqCmd},e.data.debug)},l.dialog&&E())})),D.find("#"+s.namespace+"-help-about").find(".apiver").text(s.api),l.dialog=l.fmDialog(D,{title:l.title,width:530,maxWidth:"window",maxHeight:"window",autoOpen:!1,destroyOnClose:!1,close:function(){M&&(a.hide(),o.tabs("destroy")),t=!1}}).on("click",function(e){e.stopPropagation()}).css({overflow:"hidden"}),p=l.dialog.children(".ui-tabs"),u=p.children(".ui-tabs-nav:first"),h=p.children(".ui-tabs-panel"),f=l.dialog.outerHeight(!0)-l.dialog.height(),l.dialog.closest(".ui-dialog").on("resize",function(){h.height(l.dialog.height()-f-u.outerHeight(!0)-20)}),d&&l.dialog.one("initContents",function(){e.ajax({url:l.options.helpSource?l.options.helpSource:d.replace("%s",s.lang),dataType:"html"}).done(function(t){e("#"+s.namespace+"-help-help").html(t)}).fail(function(){e.ajax({url:d.replace("%s","en"),dataType:"html"}).done(function(t){e("#"+s.namespace+"-help-help").html(t)})})}),l.state=0,s.trigger("helpBuilded",l.dialog)}).one("open",function(){var e=!1;s.one("backenddebug",function(){e=!0}).one("opendone",function(){requestAnimationFrame(function(){!e&&M&&(M=!1,a.hide(),o.hide(),r.hide())})})}),this.getstate=function(){return 0},this.exec=function(n,i){var s=i?i.tab:void 0,l=function(){M&&(o.tabs(),r.find("a:first").trigger("click"),a.show(),t=!0)};return l(),this.dialog.trigger("initContents").elfinderdialog("open").find((s?".elfinder-help-tab-"+s:".ui-tabs-nav li")+" a:first").trigger("click"),e.Deferred().resolve()}}).prototype={forceLoad:!0},i.prototype.commands.hidden=function(){this.hidden=!0,this.updateOnSelect=!1,this.getstate=function(){return-1}},i.prototype.commands.hide=function(){var t,n,i,a,o=this,r={};this.syncTitleOnChange=!0,this.shortcuts=[{pattern:"ctrl+shift+dot",description:this.fm.i18n("toggleHidden")}],this.init=function(){var e=this.fm;t=e.storage("hide")||{items:{}},n=Object.keys(t.items).length,this.title=e.i18n(t.show?"hideHidden":"showHidden"),o.update(void 0,o.title)},this.fm.bind("select contextmenucreate closecontextmenu",function(e,r){var s=(e.data?e.data.selected||e.data.targets:null)||r.selected();"select"===e.type&&e.data?a=e.data.origin:"contextmenucreate"===e.type&&(i=e.data.type),!s.length||("contextmenucreate"!==e.type&&"navbar"!==a||"cwd"===i)&&s[0]===r.cwd().hash?o.title=r.i18n(t.show?"hideHidden":"showHidden"):o.title=r.i18n("cmdhide"),"closecontextmenu"!==e.type?o.update("cwd"===i?n?0:-1:void 0,o.title):(i="",requestAnimationFrame(function(){o.update(void 0,o.title)}))}),this.getstate=function(e){return this.fm.cookieEnabled&&"cwd"!==i&&(e||this.fm.selected()).length||n?0:-1},this.exec=function(i,s){var l,c,d=this.fm,p=e.Deferred().done(function(){d.trigger("hide",{items:h,opts:s})}).fail(function(e){d.error(e)}),u=s||{},h=u.targets?u.targets:i||d.selected(),f=[];if(t=d.storage("hide")||{},e.isPlainObject(t)||(t={}),e.isPlainObject(t.items)||(t.items={}),("shortcut"===s._currentType||!h.length||"navbar"!==s._currentType&&"navbar"!==a&&h[0]===d.cwd().hash)&&(t.show?u.hide=!0:Object.keys(t.items).length&&(u.show=!0)),u.reset&&(u.show=!0,n=0),u.show||u.hide){if(u.show?t.show=!0:delete t.show,u.show)return d.storage("hide",u.reset?null:t),o.title=d.i18n("hideHidden"),o.update(u.reset?-1:void 0,o.title),e.each(t.items,function(e){var t=d.file(e,!0);t&&(d.searchStatus.state||!t.phash||d.file(t.phash))&&f.push(t)}),f.length&&(d.updateCache({added:f}),d.add({added:f})),u.reset&&(t={items:{}}),p.resolve();h=Object.keys(t.items)}return h.length&&(e.each(h,function(e,n){var i;t.items[n]||(i=d.file(n),i&&(r[n]=i.i18||i.name),t.items[n]=r[n]?r[n]:n)}),n=Object.keys(t.items).length,l=this.files(h),d.storage("hide",t),d.remove({removed:h}),t.show&&this.exec(void 0,{hide:!0}),u.hide||(c={},c.undo={cmd:"hide",callback:function(){var t=d.storage("hide");t&&(e.each(h,function(e,n){delete t.items[n]}),n=Object.keys(t.items).length,d.storage("hide",t),d.trigger("hide",{items:h,opts:{}}),o.update(n?0:-1)),d.updateCache({added:l}),d.add({added:l})}},c.redo={cmd:"hide",callback:function(){return d.exec("hide",void 0,{targets:h})}})),"rejected"==p.state()?p:p.resolve(c)}},(i.prototype.commands.home=function(){this.title="Home",this.alwaysEnabled=!0,this.updateOnSelect=!1,this.shortcuts=[{pattern:"ctrl+home ctrl+shift+up",description:"Home"}],this.getstate=function(){var e=this.fm.root(),t=this.fm.cwd().hash;return e&&t&&e!=t?0:-1},this.exec=function(){return this.fm.exec("open",this.fm.root())}}).prototype={forceLoad:!0},(i.prototype.commands.info=function(){var t=this.fm,n="elfinder-spinner",i="elfinder-info-button",a={calc:t.i18n("calc"),size:t.i18n("size"),unknown:t.i18n("unknown"),path:t.i18n("path"),aliasfor:t.i18n("aliasfor"),modify:t.i18n("modify"),perms:t.i18n("perms"),locked:t.i18n("locked"),dim:t.i18n("dim"),kind:t.i18n("kind"),files:t.i18n("files"),folders:t.i18n("folders"),roots:t.i18n("volumeRoots"),items:t.i18n("items"),yes:t.i18n("yes"),no:t.i18n("no"),link:t.i18n("link"),owner:t.i18n("owner"),group:t.i18n("group"),perm:t.i18n("perm"),getlink:t.i18n("getLink")},o=function(e,t){return t?e.replace(/\u200B/g,""):e.replace(/(\/|\\)/g,"$1​")};this.items=["size","aliasfor","path","link","dim","modify","perms","locked","owner","group","perm"],this.options.custom&&Object.keys(this.options.custom).length&&e.each(this.options.custom,function(e,t){t.label&&this.items.push(t.label)}),this.tpl={main:'
                    {title}
                    {content}
                    ',itemTitle:'{name}{kind}',groupTitle:"{items}: {num}",row:'{label} : {value}',spinner:'{text} '},this.alwaysEnabled=!0,this.updateOnSelect=!1,this.shortcuts=[{pattern:"ctrl+i"}],this.init=function(){e.each(a,function(e,n){a[e]=t.i18n(n)})},this.getstate=function(){return 0},this.exec=function(t){var r=this.files(t);r.length||(r=this.files([this.fm.cwd().hash]));var s,l,c,d,p,u,h,f,m,g=this,v=this.fm,b=this.options,y=this.tpl,w=y.row,x=r.length,k=[],C=y.main,z="{label}",T="{value}",A=[],j=null,O={title:v.i18n("selectionInfo"),width:"auto",close:function(){e(this).elfinderdialog("destroy"),j&&"pending"===j.state()&&j.reject(),e.grep(A,function(e){e&&"pending"===e.state()&&e.reject()})}},S=[],I=function(e,t,i){F.find("."+n+"-"+t).parent().html(e).addClass(i||"")},M=v.namespace+"-info-"+e.map(r,function(e){return e.hash}).join("-"),F=v.getUI().find("#"+M),E=[],D="",U="elfinder-font-mono elfinder-info-hash",P=[],R=v.ui.notify;if(R.is(":hidden")&&R.children(".elfinder-notify").length&&R.elfinderdialog("open").height("auto"),!x)return e.Deferred().reject();if(F.length)return F.elfinderdialog("toTop"),e.Deferred().resolve();if(f=v.storage("infohides")||v.arrayFlip(b.hideItems,!0),1===x){if(c=r[0],c.icon&&(D=" "+v.getIconStyle(c)),C=C.replace("{dirclass}",c.csscls?v.escape(c.csscls):"").replace("{class}",v.mime2class(c.mime)).replace("{style}",D),d=y.itemTitle.replace("{name}",v.escape(c.i18||c.name)).replace("{kind}",''+v.mime2kind(c)+""),l=v.tmb(c),c.read?"directory"!=c.mime||c.alias?s=v.formatSize(c.size):(s=y.spinner.replace("{text}",a.calc).replace("{name}","size"),S.push(c.hash)):s=a.unknown,!f.size&&k.push(w.replace(z,a.size).replace(T,s)),!f.aleasfor&&c.alias&&k.push(w.replace(z,a.aliasfor).replace(T,c.alias)),f.path||((h=v.path(c.hash,!0))?k.push(w.replace(z,a.path).replace(T,o(v.escape(h))).replace("{class}","elfinder-info-path")):(k.push(w.replace(z,a.path).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}","path")).replace("{class}","elfinder-info-path")),A.push(v.path(c.hash,!0,{notify:null}).fail(function(){I(a.unknown,"path")}).done(function(e){I(o(e),"path")})))),!f.link&&c.read){var q,H=v.escape(c.name);if("1"==c.url)k.push(w.replace(z,a.link).replace(T,'"));else{if(c.url)q=c.url;else if("directory"===c.mime)if(b.nullUrlDirLinkSelf&&null===c.url){var _=window.location;q=_.pathname+_.search+"#elf_"+c.hash}else""!==c.url&&v.option("url",!v.isRoot(c)&&c.phash||c.hash)&&(q=v.url(c.hash));else q=v.url(c.hash);q&&k.push(w.replace(z,a.link).replace(T,''+H+""))}}f.dim||(c.dim?k.push(w.replace(z,a.dim).replace(T,c.dim)):c.mime.indexOf("image")!==-1&&(c.width&&c.height?k.push(w.replace(z,a.dim).replace(T,c.width+"x"+c.height)):c.size&&"0"!==c.size&&(k.push(w.replace(z,a.dim).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}","dim"))),A.push(v.request({data:{cmd:"dim",target:c.hash},preventDefault:!0}).fail(function(){I(a.unknown,"dim")}).done(function(e){if(I(e.dim||a.unknown,"dim"),e.dim){var t=e.dim.split("x"),n=v.file(c.hash);n.width=t[0],n.height=t[1]}}))))),!f.modify&&k.push(w.replace(z,a.modify).replace(T,v.formatDate(c))),!f.perms&&k.push(w.replace(z,a.perms).replace(T,v.formatPermissions(c))),!f.locked&&k.push(w.replace(z,a.locked).replace(T,c.locked?a.yes:a.no)),!f.owner&&c.owner&&k.push(w.replace(z,a.owner).replace(T,c.owner)),!f.group&&c.group&&k.push(w.replace(z,a.group).replace(T,c.group)),!f.perm&&c.perm&&k.push(w.replace(z,a.perm).replace(T,v.formatFileMode(c.perm))),window.ArrayBuffer&&(v.options.cdns.sparkmd5||v.options.cdns.jssha)&&"directory"!==c.mime&&c.size>0&&(!b.showHashMaxsize||c.size<=b.showHashMaxsize)&&(P=[],e.each(v.storage("hashchekcer")||b.showHashAlgorisms,function(e,t){c[t]?k.push(w.replace(z,v.i18n(t)).replace(T,c[t]).replace("{class}",U)):(k.push(w.replace(z,v.i18n(t)).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}",t))),P.push(t))}),P.length&&(m=e('
                    '),A.push(v.getContentsHashes(c.hash,P,b.showHashOpts,{progressBar:m}).progress(function(t){e.each(P,function(e,n){t[n]&&I(t[n],n,U)})}).always(function(){e.each(P,function(e,t){I(a.unknown,t)})})))),b.custom&&e.each(b.custom,function(t,n){f[n.label]||n.mimes&&!e.grep(n.mimes,function(e){return c.mime===e||0===c.mime.indexOf(e+"/")}).length||n.hashRegex&&!c.hash.match(n.hashRegex)||(k.push(w.replace(z,v.i18n(n.label)).replace(T,n.tpl.replace("{id}",M))),n.action&&"function"==typeof n.action&&E.push(n.action))})}else C=C.replace("{class}","elfinder-cwd-icon-group"),d=y.groupTitle.replace("{items}",a.items).replace("{num}",x),p=e.grep(r,function(e){return"directory"==e.mime}).length,p?(u=e.grep(r,function(e){return!("directory"!==e.mime||e.phash&&!e.isroot)}).length,p-=u,k.push(w.replace(z,a.kind).replace(T,u===x||p===x?a[u?"roots":"folders"]:e.map({roots:u,folders:p,files:x-u-p},function(e,t){return e?a[t]+" "+e:null}).join(", "))),!f.size&&k.push(w.replace(z,a.size).replace(T,y.spinner.replace("{text}",a.calc).replace("{name}","size"))),S=e.map(r,function(e){return e.hash})):(s=0,e.each(r,function(e,t){var n=parseInt(t.size);n>=0&&s>=0?s+=n:s="unknown"}),k.push(w.replace(z,a.kind).replace(T,a.files)),!f.size&&k.push(w.replace(z,a.size).replace(T,v.formatSize(s))));return C=C.replace("{title}",d).replace("{content}",k.join("").replace(/{class}/g,"")),F=g.fmDialog(C,O),F.attr("id",M).one("mousedown",".elfinder-info-path",function(){e(this).html(o(e(this).html(),!0))}),P.length&&m.appendTo(F.find("."+n+"-"+P[0]).parent()),v.UA.Mobile&&e.fn.tooltip&&F.children(".ui-dialog-content .elfinder-info-title").tooltip({classes:{"ui-tooltip":"elfinder-ui-tooltip ui-widget-shadow"},tooltipClass:"elfinder-ui-tooltip ui-widget-shadow",track:!0}),c&&"1"==c.url&&F.on("click","."+n+"-url",function(){e(this).parent().html(y.spinner.replace("{text}",v.i18n("ntfurl")).replace("{name}","url")),v.request({data:{cmd:"url",target:c.hash},preventDefault:!0}).fail(function(){I(H,"url")}).done(function(e){if(e.url){I(''+H+""||H,"url");var t=v.file(c.hash);t.url=e.url}else I(H,"url")})}),l&&e("").on("load",function(){F.find(".elfinder-cwd-icon").addClass(l.className).css("background-image","url('"+l.url+"')")}).attr("src",l.url),S.length&&(j=v.getSize(S).done(function(e){I(e.formated,"size")}).fail(function(){I(a.unknown,"size")})),E.length&&e.each(E,function(e,t){try{t(c,v,F)}catch(n){v.debug("error",n)}}),e.Deferred().resolve()}}).prototype={forceLoad:!0},i.prototype.commands.mkdir=function(){var t,n=this.fm,i=this;this.value="",this.disableOnSearch=!0,this.updateOnSelect=!1,this.syncTitleOnChange=!0,this.mime="directory",this.prefix="untitled folder",this.exec=function(a,o){var r;return a&&a.length&&o&&o._currentType&&"navbar"===o._currentType?(this.origin=o._currentType,this.data={target:a[0]}):(r=n.cwd().hash===a[0],this.origin=t&&!r?t:"cwd",delete this.data),a||this.options.intoNewFolderToolbtn||n.getUI("cwd").trigger("unselectall"),this.move=this.value===n.i18n("cmdmkdirin"),e.proxy(n.res("mixin","make"),i)()},this.shortcuts=[{pattern:"ctrl+shift+n"}],this.init=function(){this.options.intoNewFolderToolbtn&&(this.syncTitleOnChange=!0)},n.bind("select contextmenucreate closecontextmenu",function(e){var a=(e.data?e.data.selected||e.data.targets:null)||n.selected();i.className="mkdir",t=e.data&&a.length?e.data.origin||e.data.type||"":"",i.options.intoNewFolderToolbtn||""!==t||(t="cwd"),a.length&&"navbar"!==t&&"cwd"!==t&&n.cwd().hash!==a[0]?(i.title=n.i18n("cmdmkdirin"),i.className+=" elfinder-button-icon-mkdirin"):i.title=n.i18n("cmdmkdir"),"closecontextmenu"!==e.type?i.update(void 0,i.title):requestAnimationFrame(function(){i.update(void 0,i.title)})}),this.getstate=function(i){var a=n.cwd(),o="navbar"===t||i&&i[0]!==a.hash?this.files(i||n.selected()):[],r=o.length,s=function(t){var n=!0;return e.grep(t,function(e){return n=!(!n||!e.read||e.locked)})};return"navbar"===t?r&&o[0].write&&o[0].read?0:-1:!a.write||r&&s(o).length!=r?-1:0}},i.prototype.commands.mkfile=function(){var t=this;this.disableOnSearch=!0,this.updateOnSelect=!1,this.mime="text/plain",this.prefix="untitled file.txt",this.variants=[],this.getTypeName=function(e,n){var i,a=t.fm;return i=(i=a.messages["kind"+a.kinds[e]])?a.i18n(["extentiontype",n.toUpperCase(),i]):a.i18n(["extentionfile",n.toUpperCase()])},this.fm.bind("open reload canMakeEmptyFile",function(){var n=t.fm,i=n.getCommand("edit").getMkfileHides();t.variants=[],n.mimesCanMakeEmpty&&e.each(n.mimesCanMakeEmpty,function(e,a){a&&!i[e]&&n.uploadMimeCheck(e)&&t.variants.push([e,t.getTypeName(e,a)])}),t.change()}),this.getstate=function(){return this.fm.cwd().write?0:-1},this.exec=function(n,i){var a,o,r=t.fm;if(a=r.mimesCanMakeEmpty[i]){if(r.uploadMimeCheck(i))return this.mime=i,this.prefix=r.i18n(["untitled file",a]),e.proxy(r.res("mixin","make"),t)();o=["errMkfile",t.getTypeName(i,a)]}return e.Deferred().reject(o)}},i.prototype.commands.netmount=function(){var t,n=this,i=!1;this.alwaysEnabled=!0,this.updateOnSelect=!1,this.drivers=[],this.handlers={load:function(){var t=n.fm;t.cookieEnabled&&t.one("open",function(){n.drivers=t.netDrivers,n.drivers.length&&e.each(n.drivers,function(){var e=n.options[this];e&&(i=!0,e.integrateInfo&&t.trigger("helpIntegration",Object.assign({cmd:"netmount"},e.integrateInfo)))})})}},this.getstate=function(){return i?0:-1},this.exec=function(){var i,a=n.fm,o=e.Deferred(),r=n.options,s=function(){var s,l=function(){c.protocol.trigger("change","winfocus")},c={protocol:e("").on("change",function(e,n){var o=this.value;t.find(".elfinder-netmount-tr").hide(),t.find(".elfinder-netmount-tr-"+o).show(),i&&i.children(".ui-dialog-buttonpane:first").find("button").show(),"function"==typeof r[o].select&&r[o].select(a,e,n)}).addClass("ui-corner-all")},d={title:a.i18n("netMountDialogTitle"),resizable:!0,modal:!0,destroyOnClose:!1,open:function(){e(window).on("focus."+a.namespace,l),c.protocol.trigger("change")},close:function(){"pending"==o.state()&&o.reject(),e(window).off("focus."+a.namespace,l)},buttons:{}},p=function(){var i,s=c.protocol.val(),l={cmd:"netmount",protocol:s},d=r[s];return e.each(t.find("input.elfinder-netmount-inputs-"+s),function(t,n){var i,a;a=e(n),a.is(":radio,:checkbox")?a.is(":checked")&&(i=e.trim(a.val())):i=e.trim(a.val()),i&&(l[n.name]=i)}),l.host?(l.mnt2res&&(i=!0),a.request({data:l,notify:{type:"netmount",cnt:1,hideCnt:!0}}).done(function(e){var t;e.added&&e.added.length&&(i&&c.protocol.trigger("change","reset"),e.added[0].phash&&(t=a.file(e.added[0].phash))&&(t.dirs||(t.dirs=1,a.change({changed:[t]}))),a.one("netmountdone",function(){a.exec("open",e.added[0].hash)})),o.resolve()}).fail(function(e){d.fail&&"function"==typeof d.fail&&d.fail(a,a.parseError(e)),o.reject(e)}),void n.dialog.elfinderdialog("close")):a.trigger("error",{error:"errNetMountHostReq",opts:{modal:!0}})},u=e('
                    ').on("keydown","input",function(t){var n,i=!0;t.keyCode===e.ui.keyCode.ENTER&&(e.each(u.find("input:visible:not(.elfinder-input-optional)"),function(){if(""===e(this).val())return i=!1,n=e(this),!1}),i?p():n.trigger("focus"))}),h=e("
                    ");return t=e('
                    ').append(e("").append(e(""+a.i18n("protocol")+"")).append(e("").append(c.protocol))),e.each(n.drivers,function(n,i){r[i]&&(c.protocol.append('"),e.each(r[i].inputs,function(n,o){o.attr("name",n),"hidden"!=o.attr("type")?(o.addClass("ui-corner-all elfinder-netmount-inputs-"+i),t.append(e("").addClass("elfinder-netmount-tr elfinder-netmount-tr-"+i).append(e(""+a.i18n(n)+"")).append(e("").append(o)))):(o.addClass("elfinder-netmount-inputs-"+i),h.append(o))}),r[i].protocol=c.protocol)}),t.append(h),t.find(".elfinder-netmount-tr").hide(),t.find(".elfinder-netmount-tr-"+n.drivers[0]).show(),d.buttons[a.i18n("btnMount")]=p,d.buttons[a.i18n("btnCancel")]=function(){n.dialog.elfinderdialog("close")},t.find("select,input").addClass("elfinder-tabstop"),s=n.fmDialog(u.append(t),d).ready(function(){c.protocol.trigger("change"),s.elfinderdialog("posInit")}),i=s.closest(".ui-dialog"),s};return n.dialog?n.dialog.elfinderdialog("open"):n.dialog=s(),o.promise()},n.fm.bind("netmount",function(e){var i=e.data||null,a=n.options,o=function(){a[i.protocol]&&"function"==typeof a[i.protocol].done&&(a[i.protocol].done(n.fm,i),t.find("select,input").addClass("elfinder-tabstop"),n.dialog.elfinderdialog("tabstopsInit"))};i&&i.protocol&&(i.mode&&"redirect"===i.mode?n.fm.request({data:{cmd:"netmount",protocol:i.protocol,host:i.host,user:"init",pass:"return",options:i.options},preventDefault:!0}).done(function(e){i=JSON.parse(e.body),o()}):o())})},i.prototype.commands.netunmount=function(){this.alwaysEnabled=!0,this.updateOnSelect=!1,this.drivers=[],this.handlers={load:function(){this.drivers=this.fm.netDrivers}},this.getstate=function(e){var t,n=this.fm;return e&&this.drivers.length&&!this._disabled&&(t=n.file(e[0]))&&t.netkey?0:-1},this.exec=function(t){var n=this,i=this.fm,a=e.Deferred().fail(function(e){e&&i.error(e)}),o=i.file(t[0]),r=function(t){var n,a=[];return i.leafRoots&&(n=[],e.each(i.leafRoots,function(a,o){var r,s=i.parents(a);(r=e.inArray(t,s))!==-1&&(r=s.length-r,e.each(o,function(e,t){n.push({i:r,hash:t})}))}),n.length&&(n.sort(function(e,t){return e.i').hide().appendTo(e("body"));if(t.UA.Mobile||!h){if(u)h?p.attr("target","_blank"):p.attr("download",a.name),p.attr("href",n).get(0).click();else if(i=window.open(n),!i)return g.reject("errPopup")}else{if(m="string"==typeof w.method&&"get"===w.method.toLowerCase(),!m&&0===n.indexOf(t.options.url)&&t.customData&&Object.keys(t.customData).length&&!a.mime.match(/^(?:video|audio)/)&&(n=""),"window"===x?(s=c=Math.round(2*screen.availWidth/3),l=d=Math.round(2*screen.availHeight/3),parseInt(a.width)&&parseInt(a.height)?(s=parseInt(a.width),l=parseInt(a.height)):a.dim&&(o=a.dim.split("x"),s=parseInt(o[0]),l=parseInt(o[1])),c>=s&&d>=l?(c=s,d=l):s-c>l-d?d=Math.round(l*(c/s)):c=Math.round(s*(d/l)),r="width="+c+",height="+d,i=window.open(n,f,r+",top=50,left=50,scrollbars=yes,resizable=yes,titlebar=no")):("tabs"===x&&(f=a.hash),i=window.open("about:blank",f)),!i)return g.reject("errPopup");if(""===n){var v=document.createElement("form");v.action=t.options.url,v.method="POST",v.target=f,v.style.display="none";var b=Object.assign({},t.customData,{cmd:"file",target:a.hash,_t:a.ts||parseInt(+new Date/1e3)});e.each(b,function(e,t){var n=document.createElement("input");n.name=e,n.value=t,v.appendChild(n)}),document.body.appendChild(v),v.submit()}else"window"!==x&&(i.location=n);e(i).trigger("focus")}p.remove()};try{p=new RegExp(t.option("dispInlineRegex"),"i")}catch(k){p=!1}for(u="string"==typeof e("").get(0).download,b=v.length;b--;){if(f="elf_open_window",a=v[b],!a.read)return g.reject(["errOpen",a.name,"errPerm"]);h=p&&a.mime.match(p),t.openUrl(a.hash,!h,y)}return g.resolve(n)};if(b>1)t.confirm({title:"openMulti",text:["openMultiConfirm",b+""],accept:{label:"cmdopen",callback:function(){k()}},cancel:{label:"btnCancel",callback:function(){g.reject()}},buttons:t.getCommand("zipdl")&&t.isCommandEnabled("zipdl",t.cwd().hash)?[{label:"cmddownload",callback:function(){t.exec("download",n),g.reject()}}]:[]});else{if(f=t.storage("selectAction")||w.selectAction,f&&(e.each(f.split("/"),function(){var e=this.valueOf();return("open"===e||!(m=t.getCommand(e))||!m.enabled())&&void(m=null)}),m))return t.exec(m.name);k()}return g}}).prototype={forceLoad:!0},i.prototype.commands.opendir=function(){this.alwaysEnabled=!0,this.getstate=function(){var e,t=this.fm.selected(),n=t.length;return 1!==n?-1:(e=this.fm.getUI("workzone"),e.hasClass("elfinder-search-result")?0:-1)},this.exec=function(t){var n,i=this.fm,a=e.Deferred(),o=this.files(t),r=o.length;return r&&o[0].phash?(n=o[0].phash,i.trigger("searchend",{noupdate:!0}),i.request({data:{cmd:"open",target:n},notify:{type:"open",cnt:1,hideCnt:!0},syncOnFail:!1}),a):a.reject()}},i.prototype.commands.opennew=function(){var t=this.fm;this.shortcuts=[{pattern:("function"==typeof t.options.getFileCallback?"shift+":"")+"ctrl+enter"}],this.getstate=function(e){var t=this.files(e),n=t.length;return 1===n&&"directory"===t[0].mime&&t[0].read?0:-1},this.exec=function(t){var n,i,a,o,r=e.Deferred(),s=this.files(t),l=s.length,c=this.options;return 1===l&&(n=s[0])&&"directory"===n.mime?(i=window.location,a=c.url?c.url:i.pathname,c.useOriginQuery&&(a.match(/\?/)?i.search&&(a+="&"+i.search.substr(1)):a+=i.search),a+="#elf_"+n.hash,o=window.open(a,"_blank"),setTimeout(function(){o.focus()},1e3),r.resolve()):r.reject()}},i.prototype.commands.paste=function(){this.updateOnSelect=!1,this.handlers={changeclipboard:function(){this.update()}},this.shortcuts=[{pattern:"ctrl+v shift+insert"}],this.getstate=function(e){if(this._disabled)return-1;if(e){if(Array.isArray(e)){if(1!=e.length)return-1;e=this.fm.file(e[0])}}else e=this.fm.cwd();return this.fm.clipboard().length&&"directory"==e.mime&&e.write?0:-1},this.exec=function(t,n){var i,a,o,r=this,s=r.fm,l=n||{},c=t?this.files(t)[0]:s.cwd(),d=s.clipboard(),p=d.length,u=!!p&&d[0].cut,h=l._cmd?l._cmd:u?"move":"copy",f="err"+h.charAt(0).toUpperCase()+h.substr(1),m=[],g=[],v=e.Deferred().fail(function(e){e&&s.error(e)}).always(function(){s.unlockfiles({files:e.map(d,function(e){return e.hash})})}),b=function(t){return t.length&&s._commands.duplicate?s.exec("duplicate",t):e.Deferred().resolve()},y=function(t){var n,i=e.Deferred(),a=[],o={},d=function(t,n){for(var i=[],a=t.length;a--;)e.inArray(t[a].name,n)!==-1&&i.unshift(a);return i},p=function(e){var n=a[e],o=t[n],r=e==a.length-1;o&&s.confirm({title:s.i18n(h+"Files"),text:["errExists",o.name,"restore"===h?"confirmRest":"confirmRepl"],all:!r,accept:{label:"btnYes",callback:function(n){r||n?m(t):p(++e)}},reject:{label:"btnNo",callback:function(n){var i;if(n)for(i=a.length;e{title}',s=e('
                    '),l=e('
                      '),c=e('
                      '),d=(e("base").length?document.location.href.replace(/#.*$/,""):"",function(t){e("#"+a.namespace+"-preference-tab-"+t).trigger("mouseover").trigger("click"),n=t}),p=a.res("class","tabsactive"),u=function(){var u=i.options.categories||{language:["language"],theme:["theme"],toolbar:["toolbarPref"],workspace:["iconSize","columnPref","selectAction","makefileTypes","useStoredEditor","editorMaximized","useFullscreen","showHidden"],dialog:["autoFocusDialog"],selectionInfo:["infoItems","hashChecker"],reset:["clearBrowserData"],all:!0},h=i.options.prefs||["language","theme","toolbarPref","iconSize","columnPref","selectAction","makefileTypes","useStoredEditor","editorMaximized","useFullscreen","showHidden","infoItems","hashChecker","autoFocusDialog","clearBrowserData"];a.cookieEnabled||delete u.language,h=a.arrayFlip(h,!0),a.options.getFileCallback&&delete h.selectAction,a.UA.Fullscreen||delete h.useFullscreen,h.language&&(h.language=function(){var t=e("").on("change",function(){var t=e(this).val();a.storage("lang",t),e("#"+a.id).elfinder("reload")}),n=[],o=i.options.langs||{ar:"العربية",bg:"Български",ca:"Català",cs:"Čeština",da:"Dansk",de:"Deutsch",el:"Ελληνικά",en:"English",es:"Español",fa:"فارسی",fo:"Føroyskt",fr:"Français",fr_CA:"Français (Canada)",he:"עברית",hr:"Hrvatski",hu:"Magyar",id:"Bahasa Indonesia",it:"Italiano",ja:"日本語",ko:"한국어",nl:"Nederlands",no:"Norsk",pl:"Polski",pt_BR:"Português",ro:"Română",ru:"Pусский",si:"සිංහල",sk:"Slovenčina",sl:"Slovenščina",sr:"Srpski",sv:"Svenska",tr:"Türkçe",ug_CN:"ئۇيغۇرچە",uk:"Український",vi:"Tiếng Việt",zh_CN:"简体中文",zh_TW:"正體中文"};return a.cookieEnabled?(e.each(o,function(e,t){n.push('")}),t.append(n.join("")).val(a.lang)):e()}()),h.theme&&(h.theme=function(){var t=a.options.themes?Object.keys(a.options.themes).length:0;if(0===t||1===t&&a.options.themes["default"])return null;var n=e("").on("change",function(){var t=e(this).val();a.changeTheme(t).storage("theme",t)}),i={image:'',link:'$2',data:'
                      $1
                      $2
                      '},o=["image","description","author","email","license"],r=e('').text(a.i18n("default")).on("click",function(e){n.val("default").trigger("change")}),s=e('
                      ').on("click","button",function(){var t=e(this).data("themeid");n.val(t).trigger("change")});return a.options.themes["default"]||n.append('"),e.each(a.options.themes,function(t,r){var l,c=e('"),d=e('
                      '+a.i18n(t)+'
                      ');n.append(c),s.append(d),l=setTimeout(function(){d.find("span.elfinder-spinner").replaceWith(a.i18n(["errRead",t]))},1e4),a.getTheme(t).always(function(){l&&clearTimeout(l)}).done(function(r){var s,l=e(),p=e("
                      ");s=r.link?i.link.replace(/\$1/g,r.link).replace(/\$3/g,a.i18n("website")):"$2",r.name&&c.html(a.i18n(r.name)),d.children("legend").html(s.replace(/\$2/g,a.i18n(r.name)||t)),e.each(o,function(o,s){var l,c=i[s]||i.data;r[s]&&(l=c.replace(/\$0/g,a.escape(s)).replace(/\$1/g,a.i18n(s)).replace(/\$2/g,a.i18n(r[s])),"image"===s&&r.link&&(l=e(l).on("click",function(){n.val(t).trigger("change")}).attr("title",a.i18n("select"))),p.append(l))}),l=l.add(p),l=l.add(e('
                      ').append(e('').data("themeid",t).html(a.i18n("select")))),d.find("span.elfinder-spinner").replaceWith(l)}).fail(function(){d.find("span.elfinder-spinner").replaceWith(a.i18n(["errRead",t]))})}),e("
                      ").append(n.val(a.theme&&a.theme.id?a.theme.id:"default"),r,s)}()),h.toolbarPref&&(h.toolbarPref=function(){var t=e.map(a.options.uiOptions.toolbar,function(t){return e.isArray(t)?t:null}),n=[],i=a.storage("toolbarhides")||{};return e.each(t,function(){var e=this,t=a.i18n("cmd"+e);t==="cmd"+e&&(t=a.i18n(e)),n.push('")}),e(n.join(" ")).on("change","input",function(){var t=e(this).val(),n=e(this).is(":checked");n||i[t]?n&&i[t]&&delete i[t]:i[t]=!0,a.storage("toolbarhides",i),a.trigger("toolbarpref")})}()),h.iconSize&&(h.iconSize=function(){var t=a.options.uiOptions.cwd.iconsView.sizeMax||3,n=a.storage("iconsize")||a.options.uiOptions.cwd.iconsView.size||0,i=e('
                      ').slider({classes:{"ui-slider-handle":"elfinder-tabstop"},value:n,max:t,slide:function(e,t){a.getUI("cwd").trigger("iconpref",{size:t.value})},change:function(e,t){a.storage("iconsize",t.value)}});return a.getUI("cwd").on("iconpref",function(e,t){i.slider("option","value",t.size)}),i}()),h.columnPref&&(h.columnPref=function(){var t=a.options.uiOptions.cwd.listView.columns,n=[],i=a.storage("columnhides")||{};return e.each(t,function(){var e=this,t=a.getColumnName(e);n.push('")}),e(n.join(" ")).on("change","input",function(){var t=e(this).val(),n=e(this).is(":checked");n||i[t]?n&&i[t]&&delete i[t]:i[t]=!0,a.storage("columnhides",i),a.trigger("columnpref",{repaint:!0})})}()),h.selectAction&&(h.selectAction=function(){var t=e("").on("change",function(){var t=e(this).val();a.storage("selectAction","default"===t?null:t)}),n=[],o=i.options.selectActions,r=a.getCommand("open").options.selectAction||"open";return e.inArray(r,o)===-1&&o.unshift(r),e.each(o,function(t,i){var o=e.map(i.split("/"),function(e){var t=a.i18n("cmd"+e);return t==="cmd"+e&&(t=a.i18n(e)),t});n.push('")}),t.append(n.join("")).val(a.storage("selectAction")||r)}()),h.makefileTypes&&(h.makefileTypes=function(){var t=a.getCommand("edit").getMkfileHides(),n=function(){var n=[];return t=a.getCommand("edit").getMkfileHides(),e.each(a.mimesCanMakeEmpty,function(e,i){var o=a.getCommand("mkfile").getTypeName(e,i);n.push('")}),n.join(" ")},i=e("
                      ").on("change","input",function(){var n=e(this).val(),i=e(this).is(":checked");i||t[n]?i&&t[n]&&delete t[n]:t[n]=!0,a.storage("mkfileHides",t),a.trigger("canMakeEmptyFile")}).append(n()),o=e("
                      ").append(e('').on("keydown",function(t){t.keyCode===e.ui.keyCode.ENTER&&e(this).next().trigger("click")}),e('').html(a.i18n("add")).on("click",function(){var t,n=e(this).prev(),i=n.val(),o=a.getUI("toast"),r=function(){return o.appendTo(n.closest(".ui-dialog")),a.toast({msg:a.i18n("errUsupportType"),mode:"warning",onHidden:function(){1===o.children().length&&o.appendTo(a.getUI())}}),n.trigger("focus"),!1};if(!i.match(/\//)){if(i=a.arrayFlip(a.mimeTypes)[i],!i)return r();n.val(i)}return a.mimeIsText(i)&&a.mimeTypes[i]?(a.trigger("canMakeEmptyFile",{mimes:[i],unshift:!0}),t={},t[i]=a.mimeTypes[i],a.storage("mkfileTextMimes",Object.assign(t,a.storage("mkfileTextMimes")||{})),n.val(""),o.appendTo(n.closest(".ui-dialog")),void a.toast({msg:a.i18n(["complete",i+" ("+t[i]+")"]),onHidden:function(){1===o.children().length&&o.appendTo(a.getUI())}})):r()}),e('').html(a.i18n("reset")).on("click",function(){a.one("canMakeEmptyFile",{done:function(){i.empty().append(n())}}),a.trigger("canMakeEmptyFile",{resetTexts:!0})}));return a.bind("canMakeEmptyFile",{done:function(e){e.data&&e.data.mimes&&e.data.mimes.length&&i.empty().append(n())}}),e("
                      ").append(i,o)}()),h.useStoredEditor&&(h.useStoredEditor=e('').prop("checked",function(){var e=a.storage("useStoredEditor");return e?e>0:a.options.commandsOptions.edit.useStoredEditor}()).on("change",function(t){a.storage("useStoredEditor",e(this).is(":checked")?1:-1)})),h.editorMaximized&&(h.editorMaximized=e('').prop("checked",function(){var e=a.storage("editorMaximized");return e?e>0:a.options.commandsOptions.edit.editorMaximized}()).on("change",function(t){a.storage("editorMaximized",e(this).is(":checked")?1:-1)})),h.useFullscreen&&(h.useFullscreen=e('').prop("checked",function(){var e=a.storage("useFullscreen");return e?e>0:"screen"===a.options.commandsOptions.fullscreen.mode}()).on("change",function(t){a.storage("useFullscreen",e(this).is(":checked")?1:-1)})),h.showHidden&&!function(){var t,n=function(){var n,i=a.storage("hide"),o=[];i&&i.items&&e.each(i.items,function(e,t){o.push(a.escape(t))}),r.prop("disabled",!o.length)[o.length?"removeClass":"addClass"]("ui-state-disabled"),n=o.length?o.join("\n"):"",h.showHidden.attr("title",n),t&&h.showHidden.tooltip("option","content",n.replace(/\n/g,"
                      ")).tooltip("close")},i=e('').prop("checked",function(){var e=a.storage("hide");return e&&e.show}()).on("change",function(t){var n={};n[e(this).is(":checked")?"show":"hide"]=!0,a.exec("hide",void 0,n)}),o=e('').append(a.i18n("reset")).on("click",function(){a.exec("hide",void 0,{reset:!0}),e(this).parent().find("input:first").prop("checked",!1),n()}),r=e().add(i).add(o);h.showHidden=e("
                      ").append(i,o),a.bind("hide",function(e){var t=e.data;t.opts&&(t.opts.show||t.opts.hide)||n()}),a.UA.Mobile&&e.fn.tooltip&&(t=!0,h.showHidden.tooltip({classes:{"ui-tooltip":"elfinder-ui-tooltip ui-widget-shadow"},tooltipClass:"elfinder-ui-tooltip ui-widget-shadow",track:!0}).css("user-select","none"),o.css("user-select","none")),n()}(),h.infoItems&&(h.infoItems=function(){var t=a.getCommand("info").items,n=[],i=a.storage("infohides")||a.arrayFlip(a.options.commandsOptions.info.hideItems,!0);return e.each(t,function(){var e=this,t=a.i18n(e);n.push('")}),e(n.join(" ")).on("change","input",function(){var t=e(this).val(),n=e(this).is(":checked");n||i[t]?n&&i[t]&&delete i[t]:i[t]=!0,a.storage("infohides",i),a.trigger("infopref",{repaint:!0})})}()),h.hashChecker&&a.hashCheckers.length&&(h.hashChecker=function(){var t=[],n=a.arrayFlip(a.storage("hashchekcer")||a.options.commandsOptions.info.showHashAlgorisms,!0);return e.each(a.hashCheckers,function(){var e=this,i=a.i18n(e);t.push('")}),e(t.join(" ")).on("change","input",function(){var t=e(this).val(),i=e(this).is(":checked");i?n[t]=!0:n[t]&&delete n[t],a.storage("hashchekcer",e.grep(a.hashCheckers,function(e){return n[e]}))})}()),h.autoFocusDialog&&(h.autoFocusDialog=e('').prop("checked",function(){var e=a.storage("autoFocusDialog");return e?e>0:a.options.uiOptions.dialog.focusOnMouseOver}()).on("change",function(t){a.storage("autoFocusDialog",e(this).is(":checked")?1:-1)})),h.clearBrowserData&&(h.clearBrowserData=e("").text(a.i18n("reset")).button().on("click",function(t){t.preventDefault(),a.storage(),e("#"+a.id).elfinder("reload")})),e.each(u,function(t,i){var s,d;i===!0?d=1:i&&(s=e(),e.each(i,function(t,n){var i,o,r,l="";(i=h[n])&&(d=2,o=a.i18n(n),r=e(i).filter('input[type="checkbox"]'),r.length||(r=e(i).find('input[type="checkbox"]')),1===r.length?(r.attr("id")||r.attr("id","elfinder-preference-"+n+"-checkbox"),o='"):r.length>1&&(l=" elfinder-preference-checkboxes"),s=s.add(e('
                      '+o+"
                      ")).add(e('
                      ').append(i)))})),d&&(l.append(r[o](/\{id\}/g,t)[o](/\{title\}/,a.i18n(t))[o](/\{class\}/,n===t?"elfinder-focus":"")),2===d&&c.append(e('
                      ').hide().append(e("
                      ").append(s))))}),l.on("click","a",function(t){var n=e(t.target),i=n.attr("href");t.preventDefault(),t.stopPropagation(),l.children().removeClass(p),n.removeClass("ui-state-hover").parent().addClass(p),i.match(/all$/)?c.addClass("elfinder-preference-taball").children().show():(c.removeClass("elfinder-preference-taball").children().hide(),e(i).show())}).on("focus blur","a",function(t){e(this).parent().toggleClass("ui-state-focus","focusin"===t.type)}).on("mouseenter mouseleave","li",function(t){e(this).toggleClass("ui-state-hover","mouseenter"===t.type)}),c.find("a,input,select,button").addClass("elfinder-tabstop"),s.append(l,c),t=i.fmDialog(s,{title:i.title,width:i.options.width||600,height:i.options.height||400,maxWidth:"window",maxHeight:"window",autoOpen:!1,destroyOnClose:!1,allowMinimize:!1,open:function(){n&&d(n),n=null},resize:function(){c.height(t.height()-l.outerHeight(!0)-(c.outerHeight(!0)-c.height())-5)}}).on("click",function(e){e.stopPropagation()}).css({overflow:"hidden"}),t.closest(".ui-dialog").css({overflow:"hidden"}).addClass("elfinder-bg-translucent"),n="all"};this.shortcuts=[{pattern:"ctrl+comma",description:this.title}],this.alwaysEnabled=!0,this.getstate=function(){return 0},this.exec=function(n,i){return!t&&u(),i&&(i.tab?d(i.tab):"cwd"===i._currentType&&d("workspace")),t.elfinderdialog("open"),e.Deferred().resolve()}},(i.prototype.commands.quicklook=function(){var t,n,i,a,o,r,s,l,c,d,p=this,u=p.fm,h=0,f=1,m=2,g=3,v=4,b=h,y=Element.update?"quicklookupdate":"update",w="elfinder-quicklook-navbar-icon",x="elfinder-quicklook-fullscreen",k="elfinder-quicklook-info-wrapper",C=function(t){e(document).trigger(e.Event("keydown",{keyCode:t,ctrlKey:!1,shiftKey:!1,altKey:!1,metaKey:!1}))},z=function(e){var t=u.getUI().offset(),n=function(){var t=e.find(".elfinder-cwd-file-wrapper");return t.length?t:e}(),i=n.offset()||{top:0,left:0};return{opacity:0,width:n.width(),height:n.height()-30,top:i.top-t.top,left:i.left-t.left}},T=function(){var i=p.options.contain||u.options.dialogContained,a=i?u.getUI():e(window),o=u.getUI().offset(),r=Math.min(t,a.width()-10),s=Math.min(n,a.height()-80);return{opacity:1,width:r,height:s,top:parseInt((a.height()-s-60)/2+(i?0:a.scrollTop()-o.top)),left:parseInt((a.width()-r)/2+(i?0:a.scrollLeft()-o.left))}},A={},j=function(e,t){var n=t||e.substr(0,e.indexOf("/")),i=A[n]?A[n]:A[n]=document.createElement(n),a=!1;try{a=i.canPlayType&&i.canPlayType(e)}catch(o){}return!(!a||""===a||"no"==a)},O=window.navigator.platform.indexOf("Win")!=-1,S=!1,I=!1,M=!1,F=null,E=e.ui.keyCode.LEFT,D=e.ui.keyCode.RIGHT,U="mousemove touchstart "+("onwheel"in document?"wheel":"onmousewheel"in document?"mousewheel":"DOMMouseScroll"),P=e(''),R=e("
                      "),q=e('
                      '),H=e('
                      '),_=e('
                      ').on("click touchstart",function(t){if(!M){var n=p.window,i=n.hasClass(x),o=e(window),r=function(){p.preview.trigger("changesize")};t.stopPropagation(),t.preventDefault(),i?(G="",L(),n.toggleClass(x).css(n.data("position")),o.trigger(p.resize).off(p.resize,r),V.off("mouseenter mouseleave"),H.off(U)):(n.toggleClass(x).data("position",{left:n.css("left"),top:n.css("top"),width:n.width(),height:n.height(),display:"block"}).removeAttr("style"),e(window).on(p.resize,r).trigger(p.resize),H.on(U,function(e){I||("mousemove"!==e.type&&"touchstart"!==e.type||(L(),F=setTimeout(function(){(u.UA.Mobile||V.parent().find(".elfinder-quicklook-navbar:hover").length<1)&&V.fadeOut("slow",function(){H.show()})},3e3)),H.is(":visible")&&(W(),H.data("tm",setTimeout(function(){H.show()},3e3))))}).show().trigger("mousemove"),V.on("mouseenter mouseleave",function(e){I||("mouseenter"===e.type?L():H.trigger("mousemove"))})),u.zIndex&&n.css("z-index",u.zIndex+1),u.UA.Mobile?V.attr("style",G):V.attr("style",G).draggable(i?"destroy":{start:function(){I=!0,M=!0,H.show(),L()},stop:function(){I=!1,G=p.navbar.attr("style"),requestAnimationFrame(function(){M=!1})}}),e(this).toggleClass(w+"-fullscreen-off");var s=n;a.is(".ui-resizable")&&(s=s.add(a)),s.resizable(i?"enable":"disable").removeClass("ui-state-disabled"),n.trigger("viewchange")}}),N=function(){p.update(void 0,function(){var t=p.fm,n=t.selectedFiles(),i=n.length,a=(p.docked(),function(){var a=0;return e.each(n,function(e,t){var n=parseInt(t.ts);a>=0?n>a&&(a=n):a="unknown"}),{hash:n[0].hash+"/"+ +new Date,name:t.i18n("items")+": "+i,mime:"group",size:J,ts:a,files:e.map(n,function(e){return e.hash}),getSize:!0}});return i||(i=1,n=[t.cwd()]),1===i?n[0]:a()}())},L=function(){p.window.hasClass(x)&&(F&&clearTimeout(F),F=null,V.stop(!0,!0).css("display","block"),W())},W=function(){H.data("tm")&&clearTimeout(H.data("tm")),H.removeData("tm"),H.hide()},B=e('
                      ').on("click touchstart",function(e){return!M&&C(E),!1}),$=e('
                      ').on("click touchstart",function(e){return!M&&C(D),!1}),V=e('
                      ').append(B).append(_).append($).append('
                      ').append(e('
                      ').on("click touchstart",function(e){return!M&&p.window.trigger("close"),!1})),K=e('').on("mousedown",function(e){e.stopPropagation(),p.window.trigger("close")}),X=e('').on("mousedown",function(e){e.stopPropagation(),p.docked()?p.window.trigger("navdockout"):p.window.trigger("navdockin")}),J=''+u.i18n("calc")+'',G="",Y=!0;this.flags={},this.cover=H,this.evUpdate=y,(this.navbar=V)._show=L,this.resize="resize."+u.namespace,this.info=e("
                      ").addClass(k).append(R).append(q),this.autoPlay=function(){return!!p.opened()&&!!p.options[p.docked()?"dockAutoplay":"autoplay"]},this.preview=e('
                      ').on("change",function(){L(),V.attr("style",G),p.docked()&&V.hide(),p.preview.attr("style","").removeClass("elfinder-overflow-auto"),p.info.attr("style","").hide(),p.cover.removeClass("elfinder-quicklook-coverbg"),R.removeAttr("class").attr("style",""),q.html("")}).on(y,function(t){var n,i,a=(p.preview,t.file),r='
                      {value}
                      ',s=function(){var s=p.window.css("overflow","hidden");i=u.escape(a.i18||a.name),!a.read&&t.stopImmediatePropagation(),p.window.data("hash",a.hash),p.preview.off("changesize").trigger("change").children().remove(),P.html(i),B.css("visibility",""),$.css("visibility",""),a.hash===u.cwdId2Hash(o.find("[id]:not(.elfinder-cwd-parent):first").attr("id"))&&B.css("visibility","hidden"),a.hash===u.cwdId2Hash(o.find("[id]:last").attr("id"))&&$.css("visibility","hidden"),"directory"===a.mime?c=[a.hash]:"group"===a.mime&&a.getSize&&(c=a.files),q.html(r.replace(/\{value\}/,i)+r.replace(/\{value\}/,u.mime2kind(a))+r.replace(/\{value\}/,c.length?J:u.formatSize(a.size))+r.replace(/\{value\}/,u.i18n("modify")+": "+u.formatDate(a))),c.length&&(l=u.getSize(c).done(function(e){q.find("span.elfinder-spinner").parent().html(e.formated)}).fail(function(){q.find("span.elfinder-spinner").parent().html(u.i18n("unknown"))}).always(function(){l=null}),l._hash=a.hash),R.addClass("elfinder-cwd-icon ui-corner-all "+u.mime2class(a.mime)),a.icon&&R.css(u.getIconStyle(a,!0)),p.info.attr("class",k),a.csscls&&p.info.addClass(a.csscls),a.read&&(n=u.tmb(a))&&e("").hide().appendTo(p.preview).on("load",function(){R.addClass(n.className).css("background-image","url('"+n.url+"')"),e(this).remove()}).attr("src",n.url),p.info.delay(100).fadeIn(10),p.window.hasClass(x)&&H.trigger("mousemove"),s.css("overflow","")},c=[];a&&!Object.keys(a).length&&(a=u.cwd()),a&&l&&"pending"===l.state()&&l._hash!==a.hash&&l.reject(),a&&(t.forceUpdate||p.window.data("hash")!==a.hash)?s():t.stopImmediatePropagation()}),this.window=e('
                      ').hide().addClass(u.UA.Touch?"elfinder-touch":"").on("click",function(e){var t=this;e.stopPropagation(),b===m&&requestAnimationFrame(function(){b===m&&u.toFront(t)})}).append(e('
                      ').append(e('').append(K,X),P),this.preview,p.info.hide(),H.hide(),V).draggable({handle:"div.elfinder-quicklook-titlebar"}).on("open",function(e,t){var n=p.window,i=p.value,a=u.getUI("cwd"),o=function(e){b=e,p.update(1,p.value),p.change(),n.trigger("resize."+u.namespace)};Y||b!==h?b===v&&(u.getUI("navdock").data("addNode")(c),o(g),p.preview.trigger("changesize"),u.storage("previewDocked","1"),0===u.getUI("navdock").width()&&n.trigger("navdockout")):(i&&i.hash!==r&&(a=u.cwdHash2Elm(i.hash.split("/",2)[0])),G="",V.attr("style",""),b=f,a.trigger("scrolltoview"),W(),n.css(t||z(a)).show().animate(T(),550,function(){o(m),L()}),u.toFront(n))}).on("close",function(e,t){var n,i=p.window,a=p.preview.trigger("change"),r=(p.value,(i.data("hash")||"").split("/",2)[0]),s=function(e,n){b=e,n&&u.toHide(i),a.children().remove(),p.update(0,p.value),i.data("hash",""),t&&t.resolve()};p.opened()&&(l&&"pending"===l.state()&&l.reject(),p.docked()?(c=u.getUI("navdock").data("removeNode")(p.window.attr("id"),"detach"),s(v),u.storage("previewDocked","2")):(b=f,i.hasClass(x)&&_.click(),r&&(n=o.find("#"+r)).length?i.animate(z(n),500,function(){a.off("changesize"),s(h,!0)}):s(h,!0)))}).on("navdockin",function(e,t){var n=p.window,a=u.getUI("navdock"),o=s||a.width(),r=t||{};Y&&(r.init=!0),b=g,i=n.attr("style"),n.toggleClass("ui-front").removeClass("ui-widget").draggable("disable").resizable("disable").removeAttr("style").css({width:"100%",height:o,boxSizing:"border-box",paddingBottom:0,zIndex:"unset"}),V.hide(),X.toggleClass("ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize"),u.toHide(n,!0),a.data("addNode")(n,r),p.preview.trigger("changesize"),u.storage("previewDocked","1")}).on("navdockout",function(t){var n=p.window,a=u.getUI("navdock"),o=(e.Deferred(),z(p.preview));s=n.outerHeight(),a.data("removeNode")(n.attr("id"),u.getUI()),n.toggleClass("ui-front").addClass("ui-widget").draggable("enable").resizable("enable").attr("style",i),X.toggleClass("ui-icon-plusthick ui-icon-minusthick elfinder-icon-full elfinder-icon-minimize"),b=h,n.trigger("open",o),u.storage("previewDocked","0")}).on("resize."+u.namespace,function(){p.preview.trigger("changesize")}),this.alwaysEnabled=!0,this.value=null,this.handlers={select:function(e,t){d&&cancelAnimationFrame(d),e.data&&e.data.selected&&e.data.selected.length?p.opened()&&N():d=requestAnimationFrame(function(){p.opened()&&N()})},error:function(){p.window.is(":visible")&&p.window.trigger("close")},"searchshow searchhide":function(){this.opened()&&this.window.trigger("close")},navbarshow:function(){requestAnimationFrame(function(){p.docked()&&p.preview.trigger("changesize")})},destroy:function(){p.window.remove()}},this.shortcuts=[{pattern:"space"}],this.support={audio:{ogg:j("audio/ogg;"),webm:j("audio/webm;"),mp3:j("audio/mpeg;"),wav:j("audio/wav;"),m4a:j("audio/mp4;")||j("audio/x-m4a;")||j("audio/aac;"),flac:j("audio/flac;"),amr:j("audio/amr;")},video:{ogg:j("video/ogg;"),webm:j("video/webm;"),mp4:j("video/mp4;"),mkv:j("video/x-matroska;")||j("video/webm;"),"3gp":j("video/3gpp;")||j("video/mp4;"),m3u8:j("application/x-mpegURL","video")||j("application/vnd.apple.mpegURL","video"),mpd:j("application/dash+xml","video")}},A={},this.closed=function(){return b==h||b==v},this.opened=function(){return b==m||b==g},this.docked=function(){return b==g},this.addIntegration=function(e){requestAnimationFrame(function(){u.trigger("helpIntegration",Object.assign({cmd:"quicklook"},e))})},this.init=function(){var i,l=this.options,c=this.window,d=this.preview;t=l.width>0?parseInt(l.width):450,n=l.height>0?parseInt(l.height):300,"auto"!==l.dockHeight&&(s=parseInt(l.dockHeight),s||(s=void 0)),u.one("load",function(){S=u.getUI("navdock").data("dockEnabled"),!S&&X.hide(),a=u.getUI(),o=u.getUI("cwd"),u.zIndex&&c.css("z-index",u.zIndex+1),c.appendTo(a),e(document).on("keydown."+u.namespace,function(t){t.keyCode==e.ui.keyCode.ESCAPE&&p.opened()&&!p.docked()&&c.hasClass("elfinder-frontmost")&&c.trigger("close")}),c.resizable({handles:"se",minWidth:350,minHeight:120,resize:function(){d.trigger("changesize")}}),p.change(function(){p.opened()&&p.value&&(p.value.tmb&&1==p.value.tmb&&(p.value=Object.assign({},u.file(p.value.hash))),d.trigger(e.Event(y,{file:p.value})))}),d.on(y,function(e){var t,n,a;if(t=e.file){if(n=t.hash,a=u.searchStatus.mixed&&u.searchStatus.state>1,"directory"!==t.mime)if(parseInt(t.size)||t.mime.match(l.mimeRegexNotEmptyCheck)){if(p.dispInlineRegex=i,a||u.optionsByHashes[n])try{p.dispInlineRegex=new RegExp(u.option("dispInlineRegex",n),"i")}catch(e){try{p.dispInlineRegex=new RegExp(u.isRoot(t)?u.options.dispInlineRegex:u.option("dispInlineRegex",t.phash),"i")}catch(e){p.dispInlineRegex=/^$/}}}else e.stopImmediatePropagation();else p.dispInlineRegex=/^$/;p.info.show()}else e.stopImmediatePropagation()}),e.each(u.commands.quicklook.plugins||[],function(e,t){"function"==typeof t&&new t(p)})}).one("open",function(){var e,t=Number(u.storage("previewDocked")||l.docked);S&&t>=1&&(e=p.window,p.exec(),e.trigger("navdockin",{init:!0}),2===t?e.trigger("close"):(p.update(void 0,u.cwd()),p.change())),Y=!1}).bind("open",function(){r=u.cwd().hash,p.value=u.cwd();try{i=new RegExp(u.option("dispInlineRegex"),"i")}catch(e){i=/^$/}}).bind("change",function(t){t.data&&t.data.changed&&p.opened()&&e.each(t.data.changed,function(){if(p.window.data("hash")===this.hash)return p.window.data("hash",null),p.preview.trigger(y),!1})}).bind("navdockresizestart navdockresizestop",function(e){H["navdockresizestart"===e.type?"show":"hide"]()})},this.getstate=function(){return p.opened()?1:0},this.exec=function(){return p.closed()&&N(),p.enabled()&&p.window.trigger(p.opened()?"close":"open"),e.Deferred().resolve()},this.hideinfo=function(){this.info.stop(!0,!0).hide()}}).prototype={forceLoad:!0},i.prototype.commands.quicklook.plugins=[function(t){var n,i,a=["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp"],o=t.fm.returnBytes(t.options.getDimThreshold||0),r=t.preview;n=new Image,n.onload=n.onerror=function(){2==n.height&&a.push("image/webp")},n.src="data:image/webp;base64,UklGRjoAAABXRUJQVlA4IC4AAACyAgCdASoCAAIALmk0mk0iIiIiIgBoSygABc6WWgAA/veff/0PP8bA//LwYAAA",e.each(navigator.mimeTypes,function(t,n){var i=n.type;0===i.indexOf("image/")&&e.inArray(i,a)&&a.push(i)}),r.on(t.evUpdate,function(n){var s,l,c,d,p=t.fm,u=n.file,h=!1,f=null,m=function(e){var t=p.file(u.hash);t.width=e[0],t.height=e[1]},g=function(){var e,t,n,i,a;f&&f.state&&"pending"===f.state()&&f.reject(),h||(h=!0,e=s.get(0),t=u.width&&u.height?{w:u.width,h:u.height}:e.naturalWidth?null:{w:s.width(),h:s.height()},t&&s.removeAttr("width").removeAttr("height"),n=u.width||e.naturalWidth||e.width||s.width(),i=u.height||e.naturalHeight||e.height||s.height(),u.width&&u.height||m([n,i]),t&&s.width(t.w).height(t.h),a=(n/i).toFixed(2),r.on("changesize",function(){var e,t,n=parseInt(r.width()),i=parseInt(r.height());a<(n/i).toFixed(2)?(t=i,e=Math.floor(t*a)):(e=n,t=Math.floor(e/a)),s.width(e).height(t).css("margin-top",t'+p.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),c=e('
                    ').appendTo(l),s=e("").hide().appendTo(r).on("load",function(){v(),g()}).on("error",function(){l.remove()}),d=p.openUrl(u.hash,!1,function(e){s.attr("src",e)},{progressBar:c}),r.one("change",function(){d&&d.state&&"pending"===d.state()&&d.reject()}),u.width&&u.height?g():u.size>o&&(f=p.request({data:{cmd:"dim",target:u.hash},preventDefault:!0}).done(function(e){if(e.dim){var t=e.dim.split("x");u.width=t[0],u.height=t[1],m(t),g()}})))})},function(t){var n=t.fm,i="image/tiff",a=t.preview;window.Worker&&window.Uint8Array&&a.on(t.evUpdate,function(o){var r,s,l,c,d,p=o.file,u=function(e){c&&c.terminate(),r.remove(),n.debug("error",e)},h=function(e){var t=n.file(p.hash);t.width=e[0],t.height=e[1]};p.mime===i&&(o.stopImmediatePropagation(),r=e('
                    '+n.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),s=e('
                    ').appendTo(r),a.one("change",function(){c&&c.terminate(),r.remove()}),d=n.getContents(p.hash,"arraybuffer",{progressBar:s}).done(function(i){if(i){l=e("
                    ").css({width:"100%",height:"100%"}).hide().appendTo(a);try{c=n.getWorker(),c.onmessage=function(n){var i,o,s,d,u=n.data;c&&c.terminate(),i=document.createElement("canvas"),o=i.getContext("2d"),i.width=u.width,i.height=u.height,s=o.createImageData(u.width,u.height),s.data.set(new Uint8Array(u.image)),o.putImageData(s,0,0),l.append(i).show(),r.remove(),d=(u.width/u.height).toFixed(2),a.on("changesize",function(){var t,n,o=parseInt(a.width()),r=parseInt(a.height());d<(o/r).toFixed(2)?(n=r,t=Math.floor(n*d)):(t=o,n=Math.floor(t/d)),e(i).width(t).height(n).css("margin-top",n'+i.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),d=e('
                    ').appendTo(c),h=i.openUrl(f.hash,"sameorigin",function(t){t&&(l=e("").hide().appendTo(o),n?r(t,l,c):(p=window.define,u=window.require,window.require=null,window.define=null,i.loadScript([i.options.cdns.psd],function(){n=require("psd"),p?window.define=p:delete window.define,u?window.require=u:delete window.require,r(t,l,c)})))},{progressBar:d}),o.one("change",function(){h&&h.state&&"pending"===h.state()&&h.reject()}))})},function(t){var n=t.fm,i=n.arrayFlip(["text/html","application/xhtml+xml"]),a=t.preview;a.on(t.evUpdate,function(o){var r,s,l,c=o.file;i[c.mime]&&t.dispInlineRegex.test(c.mime)&&(!t.options.getSizeMax||c.size<=t.options.getSizeMax)&&(o.stopImmediatePropagation(),s=e('
                    '+n.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),l=e('
                    ').appendTo(s),a.one("change",function(){"pending"==r.state()&&r.reject()}).addClass("elfinder-overflow-auto"),r=n.request({data:{cmd:"get",target:c.hash,conv:1,_t:c.ts},options:{type:"get",cache:!0},preventDefault:!0,progressBar:l}).done(function(n){t.hideinfo();var i=e('').appendTo(a)[0].contentWindow.document;i.open(),i.write(n.content),i.close()}).always(function(){s.remove()}))})},function(t){var n=t.fm,i=n.arrayFlip(["text/x-markdown"]),a=t.preview,o=null,r=function(n,i){t.hideinfo();var r=e('').appendTo(a)[0].contentWindow.document;r.open(),r.write((o.parse||o)(n.content)),r.close(),i.remove()},s=function(e){o=!1,e.remove()};a.on(t.evUpdate,function(l){var c,d,p,u=l.file;i[u.mime]&&n.options.cdns.marked&&o!==!1&&t.dispInlineRegex.test(u.mime)&&(!t.options.getSizeMax||u.size<=t.options.getSizeMax)&&(l.stopImmediatePropagation(),d=e('
                    '+n.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
                    ').appendTo(d),a.one("change",function(){"pending"==c.state()&&c.reject()}).addClass("elfinder-overflow-auto"),c=n.request({data:{cmd:"get",target:u.hash,conv:1,_t:u.ts},options:{type:"get",cache:!0},preventDefault:!0,progressBar:p}).done(function(e){o||window.marked?(o||(o=window.marked),r(e,d)):n.loadScript([n.options.cdns.marked],function(t){o=t||window.marked||!1,delete window.marked,o?r(e,d):s(d)},{tryRequire:!0,error:function(){s(d)}})}).fail(function(){s(d)}))})},function(t){if(t.options.viewerjs){var n=t.fm,i=t.preview,a=t.options.viewerjs,o=a.url?n.arrayFlip(a.mimes||[]):[],r=t.window,s=t.navbar,l=function(){s.css("bottom",r.hasClass("elfinder-quicklook-fullscreen")?"30px":"")};a.url&&i.on("update",function(s){var c,d,p,u,h=s.file;!o[h.mime]||"application/pdf"===h.mime&&a.pdfNative&&t.flags.pdfNative||(s.stopImmediatePropagation(),d=e('
                    '+n.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
                    ').appendTo(d),u=n.openUrl(h.hash,"sameorigin",function(n){n&&(c=e('').css("background-color","transparent").on("load",function(){t.hideinfo(),d.remove(),c.css("background-color","#fff")}).on("error",function(){d.remove(),c.remove()}).appendTo(i).attr("src",a.url+"#"+n),r.on("viewchange.viewerjs",l),l(),i.one("change",function(){r.off("viewchange.viewerjs"),d.remove(),c.off("load").remove()}))},{progressBar:p}),i.one("change",function(){u&&u.state&&"pending"===u.state()&&u.reject()}))})}},function(t){var n=t.fm,i="application/pdf",a=t.preview,o=!1,r="";n.UA.Safari&&"mac"===n.OS&&!n.UA.iOS||n.UA.IE||n.UA.Firefox?o=!0:e.each(navigator.plugins,function(t,n){e.each(n,function(e,t){if(t.type===i)return!(o=!0)})}),t.flags.pdfNative=o,o&&("undefined"==typeof t.options.pdfToolbar||t.options.pdfToolbar||(r="#toolbar=0"),a.on(t.evUpdate,function(s){var l,c=s.file;o&&c.mime===i&&t.dispInlineRegex.test(c.mime)&&(s.stopImmediatePropagation(),l=n.openUrl(c.hash,!1,function(i){i&&(t.hideinfo(),t.cover.addClass("elfinder-quicklook-coverbg"),e('').on("error",function(e){o=!1,t.update(void 0,n.cwd()),t.update(void 0,c)}).appendTo(a))}),a.one("change",function(){l&&l.state&&"pending"===l.state()&&l.reject()}))}))},function(t){var n=t.fm,i="application/x-shockwave-flash",a=t.preview,o=!1;e.each(navigator.plugins,function(t,n){e.each(n,function(e,t){if(t.type===i)return!(o=!0)})}),o&&a.on(t.evUpdate,function(o){var r,s,l=o.file;l.mime===i&&t.dispInlineRegex.test(l.mime)&&(o.stopImmediatePropagation(),s=n.openUrl(l.hash,!1,function(n){n&&(t.hideinfo(),r=e('').appendTo(a))}),a.one("change",function(){s&&s.state&&"pending"===s.state()&&s.reject()}))})},function(t){var n,i,a,o,r,s,l=t.fm,c=t.preview,d={"audio/mpeg":"mp3","audio/mpeg3":"mp3","audio/mp3":"mp3","audio/x-mpeg3":"mp3","audio/x-mp3":"mp3","audio/x-wav":"wav","audio/wav":"wav","audio/x-m4a":"m4a","audio/aac":"m4a","audio/mp4":"m4a","audio/x-mp4":"m4a","audio/ogg":"ogg","audio/webm":"webm","audio/flac":"flac","audio/x-flac":"flac","audio/amr":"amr"},p=t.window,u=t.navbar,h="string"==typeof t.options.mediaControlsList&&t.options.mediaControlsList?' controlsList="'+l.escape(t.options.mediaControlsList)+'"':"",f=function(){u.css("bottom",p.hasClass("elfinder-quicklook-fullscreen")?"50px":"")},m=function(t,i){return e('').on("change",function(e){e.stopPropagation()}).on("error",function(e){n&&n.data("hash")===i&&b()}).data("hash",i).appendTo(c)},g=function(t){var n,i=e.Deferred(),o=e.Deferred().done(function(){var e;e=l.getContents(t,"arraybuffer",{progressBar:s}).done(function(e){try{var t=a.toWAV(new Uint8Array(e));t?i.resolve(URL.createObjectURL(new Blob([t],{type:"audio/x-wav"}))):i.reject()}catch(n){i.reject()}}).fail(function(){i.reject()}),c.one("change",function(){e&&e.state&&"pending"===e.state()&&e.reject()})}).fail(function(){a=!1,i.reject()});return window.TextEncoder&&window.URL&&URL.createObjectURL&&"undefined"==typeof a?(n=window.AMR,delete window.AMR,l.loadScript([l.options.cdns.amr],function(){a=!!window.AMR&&window.AMR,window.AMR=n,o[a?"resolve":"reject"]()},{error:function(){o.reject()}})):o[a?"resolve":"reject"](),i},v=function(e){var t,i=n.data("hash");o&&(t=e.play()),t&&t["catch"]&&t["catch"](function(t){e.paused||n&&n.data("hash")===i&&b()})},b=function(){if(n&&n.parent().length){var e=n[0],t=n.children("source").attr("src");p.off("viewchange.audio");try{e.pause(),n.empty(),t.match(/^blob:/)&&URL.revokeObjectURL(t),e.src="",e.load()}catch(i){}n.remove(),n=null}};c.on(t.evUpdate,function(u){var h,b,y=u.file,w=d[y.mime];d[y.mime]&&t.dispInlineRegex.test(y.mime)&&((h=t.support.audio[w])||"amr"===w)&&(o=t.autoPlay(),i=y.hash,h?(u.stopImmediatePropagation(),r=e('
                    '+l.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),s=e('
                    ').appendTo(r),b=l.openUrl(i,!1,function(e){r.remove(),e?(n=m(e,i),v(n[0]),p.on("viewchange.audio",f),f()):n.remove()},{progressBar:s}),c.one("change",function(){b&&b.state&&"pending"===b.state()&&b.reject()})):l.options.cdns.amr&&"amr"===w&&a!==!1&&(u.stopImmediatePropagation(),r=e('
                    '+l.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),s=e('
                    ').appendTo(r),n=m("",i),g(y.hash).done(function(e){if(r.remove(),i===y.hash){var t=n[0];try{n.children("source").attr("src",e),t.pause(),t.load(),v(t),p.on("viewchange.audio",f),f()}catch(a){URL.revokeObjectURL(e),n.remove()}}else URL.revokeObjectURL(e)}).fail(function(){n.remove()})))}).one("change",b)},function(t){var n,i,a,o,r,s,l,c,d,p,u=t.fm,h=t.preview,f={"video/mp4":"mp4","video/x-m4v":"mp4","video/quicktime":"mp4","video/mpeg":"mpeg","video/ogg":"ogg","application/ogg":"ogg","video/webm":"webm","video/x-matroska":"mkv","video/3gpp":"3gp","application/vnd.apple.mpegurl":"m3u8","application/x-mpegurl":"m3u8","application/dash+xml":"mpd","video/x-flv":"flv","video/x-msvideo":"avi"},m=t.window,g=t.navbar,v="string"==typeof t.options.mediaControlsList&&t.options.mediaControlsList?' controlsList="'+u.escape(t.options.mediaControlsList)+'"':"",b=function(){u.UA.iOS?m.hasClass("elfinder-quicklook-fullscreen")?(h.css("height","-webkit-calc(100% - 50px)"),g._show()):h.css("height",""):g.css("bottom",m.hasClass("elfinder-quicklook-fullscreen")?"50px":"")},y=function(i,a){var r,s=function(e){l>1&&(c&&clearTimeout(c),c=setTimeout(function(){!r&&T(!0)},800))},l=0,d="";o=null,a=a||{},a.cssClass&&(d=" "+a.cssClass),t.hideinfo(),n=e('').on("change",function(e){e.stopPropagation()}).on("timeupdate progress",s).on("canplay",function(){r=!0}).data("hash",i.hash),n[0].addEventListener("error",function(e){a.src&&u.convAbsUrl(a.src)===u.convAbsUrl(e.target.src)&&(++l,s())},!0),a.src&&n.append(''),n.appendTo(h),m.on("viewchange.video",b),b()},w=function(e){var t,a;a=u.openUrl(e.hash,!1,function(a){d.remove(),a&&(y(e),t=new i,t.loadSource(a),t.attachMedia(n[0]),l&&t.on(i.Events.MANIFEST_PARSED,function(){z(n[0])}))},{progressBar:p}),h.one("change",function(){a&&a.state&&"pending"===a.state()&&a.reject()})},x=function(e){var t;t=u.openUrl(e.hash,!1,function(t){var i;d.remove(),t&&(y(e),o=window.dashjs.MediaPlayer().create(),i=o.getDebug(),i.setLogLevel?i.setLogLevel(dashjs.Debug.LOG_LEVEL_FATAL):i.setLogToBrowserConsole&&i.setLogToBrowserConsole(!1),o.initialize(n[0],t,l),o.on("error",function(e){T(!0)}))},{progressBar:p}),h.one("change",function(){t&&t.state&&"pending"===t.state()&&t.reject()})},k=function(e){var t;return r.isSupported()?(t=u.openUrl(e.hash,!1,function(t){if(d.remove(),t){var i=r.createPlayer({type:"flv",url:t});y(e),i.on(r.Events.ERROR,function(){i.destroy(),T(!0)}),i.attachMediaElement(n[0]),i.load(),z(i)}},{progressBar:p}),void h.one("change",function(){t&&t.state&&"pending"===t.state()&&t.reject()})):void(r=!1)},C=function(e){var t;t=u.openUrl(e.hash,!1,function(t){d.remove(),t&&(y(e,{src:t,cssClass:"video-js"}),n[0].src=t,s(n[0],{autoplay:!0}))},{progressBar:p}),h.one("change",function(){t&&t.state&&"pending"===t.state()&&t.reject()})},z=function(e){var t,i=n.data("hash");l&&(t=e.play()),t&&t["catch"]&&t["catch"](function(t){e.paused||n&&n.data("hash")===i&&T(!0)})},T=function(e){if(c&&clearTimeout(c),n&&n.parent().length){var i=n[0];m.off("viewchange.video"),o&&o.reset();try{i.pause(),n.empty(),i.src="",i.load()}catch(a){}n.remove(),n=null}e&&t.info.show()};h.on(t.evUpdate,function(o){var c,m,g=o.file,v=g.mime.toLowerCase(),b=f[v];f[v]&&t.dispInlineRegex.test(g.mime)&&(l=t.autoPlay(),d=e('
                    '+u.i18n("nowLoading")+'
                    '),p=e('
                    ').appendTo(d),t.support.video[b]&&("m3u8"!==b||u.UA.Safari)?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),m=u.openUrl(g.hash,!1,function(e){d.remove(),e&&(y(g,{src:e}),z(n[0]))},{progressBar:p}),h.one("change",function(){m&&m.state&&"pending"===m.state()&&m.reject()})):i!==!1&&u.options.cdns.hls&&"m3u8"===b?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),i?w(g):(c=window.Hls,delete window.Hls,u.loadScript([u.options.cdns.hls],function(e){i=e||window.Hls||!1,window.Hls=c,i&&w(g)},{tryRequire:!0,error:function(){i=!1}}))):a!==!1&&u.options.cdns.dash&&"mpd"===b?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),a?x(g):u.loadScript([u.options.cdns.dash],function(){a=!!window.dashjs,a&&x(g)},{tryRequire:!0,error:function(){a=!1}})):r!==!1&&u.options.cdns.flv&&"flv"===b?(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),r?k(g):(c=window.flvjs,delete window.flvjs,u.loadScript([u.options.cdns.flv],function(e){r=e||window.flvjs||!1,window.flvjs=c,r&&k(g)},{tryRequire:!0,error:function(){r=!1}}))):u.options.cdns.videojs&&(o.stopImmediatePropagation(),d.appendTo(t.info.find(".elfinder-quicklook-info")),s?C(g):u.loadScript([u.options.cdns.videojs+"/video.min.js"],function(e){s=e||window.videojs||!1,s&&C(g)},{tryRequire:!0,error:function(){s=!1}}).loadCss([u.options.cdns.videojs+"/video-js.min.css"])))}).one("change",T)},function(t){var n,i=t.preview,a=[],o=t.window,r=t.navbar;e.each(navigator.plugins,function(t,n){e.each(n,function(e,t){(0===t.type.indexOf("audio/")||0===t.type.indexOf("video/"))&&a.push(t.type)})}),a=t.fm.arrayFlip(a),i.on(t.evUpdate,function(s){var l,c,d,p,u=s.file,h=u.mime,f=function(){r.css("bottom",o.hasClass("elfinder-quicklook-fullscreen")?"50px":"")};a[u.mime]&&t.dispInlineRegex.test(u.mime)&&(s.stopImmediatePropagation(),d=e('
                    '+fm.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
                    ').appendTo(d),c=t.fm.openUrl(u.hash,!1,function(a){d.remove(),a&&((l=0===h.indexOf("video/"))&&t.hideinfo(),n=e('').appendTo(i),o.on("viewchange.embed",f),f())},{progressBar:p}),i.one("change",function(){c&&c.state&&"pending"===c.state()&&c.reject()}))}).one("change",function(){n&&n.parent().length&&(o.off("viewchange.embed"),n.remove(),n=null)})},function(t){var n=t.fm,i=n.arrayFlip(["application/zip","application/x-gzip","application/x-tar","application/x-bzip2"]),a=t.preview,o=n.returnBytes(t.options.unzipMaxSize||0),r=!(!n.options.cdns.zlibUnzip||!n.options.cdns.zlibGunzip),s=!!n.options.cdns.bzip2;window.Worker&&window.Uint8Array&&window.DataView&&a.on(t.evUpdate,function(l){var c=l.file,d="application/x-tar"===c.mime,p="application/x-bzip2"===c.mime,u="application/zip"===c.mime||"application/x-gzip"===c.mime;if(i[c.mime]&&(!o||c.size<=o)&&(d||p&&s||u&&r)){var h,f,m,g,v=function(){h=n.getContents(c.hash,"arraybuffer",{progressBar:g}).fail(function(){m.remove()}).done(function(e){var t=function(e){f&&f.terminate(),m.remove(),u?r=!1:p&&(s=!1),n.debug("error",e)};try{f=n.getWorker(),f.onmessage=function(e){f&&f.terminate(),m.remove(),!e.data||e.data.error?new Error(e.data&&e.data.error?e.data.error:""):b(e.data.files)},f.onerror=t,"application/x-tar"===c.mime?f.postMessage({scripts:[n.getWorkerUrl("quicklook.unzip.js")],data:{type:"tar",bin:e}}):"application/zip"===c.mime?f.postMessage({scripts:[n.options.cdns.zlibUnzip,n.getWorkerUrl("quicklook.unzip.js")],data:{type:"zip",bin:e}}):"application/x-gzip"===c.mime?f.postMessage({scripts:[n.options.cdns.zlibGunzip,n.getWorkerUrl("quicklook.unzip.js")],data:{type:"gzip",bin:e}}):"application/x-bzip2"===c.mime&&f.postMessage({scripts:[n.options.cdns.bzip2,n.getWorkerUrl("quicklook.unzip.js")],data:{type:"bzip2",bin:e}})}catch(i){t(i)}})},b=function(i){var o,r,s,l=0;i&&i.length&&(i=e.map(i,function(e){return n.decodeRawString(e)}),i.sort(),r=n.escape(i.join("\n").replace(/\{formatSize\((\d+)\)\}/g,function(e,t){return l+=parseInt(t),n.formatSize(t)})),o=""+n.escape(c.mime)+" ("+n.formatSize(c.size)+" / "+n.formatSize(l)+")
                    ",s=e('
                    '+o+'
                    '+r+"
                    ").on("touchstart",function(t){e(this)["scroll"+("ltr"===n.direction?"Right":"Left")]()>5&&(t.originalEvent._preventSwipeX=!0)}).appendTo(a),t.hideinfo()),m.remove()};l.stopImmediatePropagation(),m=e('
                    '+n.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),g=e('
                    ').appendTo(m),a.one("change",function(){"pending"===h.state()&&h.reject(),f&&f.terminate(),m.remove()}),v()}})},function(t){var n,i=t.fm,a=i.arrayFlip(["application/x-rar"]),o=t.preview;window.DataView&&o.on(t.evUpdate,function(r){var s=r.file;if(a[s.mime]&&i.options.cdns.rar&&n!==!1){var l,c,d,p,u,h,f=function(a){if(p)return void l.remove();try{d=n({file:a,type:2,xhrHeaders:i.customHeaders,xhrFields:i.xhrFields},function(n){l.remove();var a,r,c=[];return p||n?void(n&&i.debug("error",n)):(e.each(d.entries,function(){c.push(this.path+(this.size?" ("+i.formatSize(this.size)+")":""))}),void(c.length&&(c=e.map(c,function(e){return i.decodeRawString(e)}),c.sort(),a=""+i.escape(s.mime)+" ("+i.formatSize(s.size)+")
                    ",r=e('
                    '+a+'
                    '+i.escape(c.join("\n"))+"
                    ").on("touchstart",function(t){e(this)["scroll"+("ltr"===i.direction?"Right":"Left")]()>5&&(t.originalEvent._preventSwipeX=!0)}).appendTo(o),t.hideinfo())))})}catch(r){l.remove()}},m=function(){n=!1,l.remove()};r.stopImmediatePropagation(),l=e('
                    '+i.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),c=e('
                    ').appendTo(l),o.one("change",function(){d&&(d.abort=!0),l.remove(),p=!0}),h=i.openUrl(s.hash,"sameorigin",function(e){e&&(n?f(e):(window.RarArchive&&(u=window.RarArchive,delete window.RarArchive),i.loadScript([i.options.cdns.rar],function(){i.hasRequire?require(["rar"],function(t){n=t,f(e)},m):(n=window.RarArchive)?(u?window.RarArchive=u:delete window.RarArchive,f(e)):m()},{tryRequire:!0,error:m})))},{progressBar:c,temporary:!0}),o.one("change",function(){h&&h.state&&"pending"===h.state()&&h.reject()})}})},function(t){var n,i=t.fm,a=i.arrayFlip(t.options.sharecadMimes||[]),o=t.preview;t.window;t.options.sharecadMimes.length&&t.addIntegration({title:"ShareCAD.org CAD and 3D-Models viewer",link:"https://sharecad.org/DWGOnlinePlugin"}),o.on(t.evUpdate,function(r){var s=r.file;if(a[s.mime.toLowerCase()]&&i.option("onetimeUrl",s.hash)){var l,c,d;t.window;r.stopImmediatePropagation(),"1"==s.url&&(o.hide(),e('
                    ").appendTo(t.info.find(".elfinder-quicklook-info")).on("click",function(){var n=e(this);n.html(''),i.request({data:{cmd:"url",target:s.hash},preventDefault:!0,progressBar:c}).always(function(){n.html("")}).done(function(e){var n=i.file(s.hash);s.url=n.url=e.url||"",s.url&&o.trigger({type:t.evUpdate,file:s,forceUpdate:!0})})})),""!==s.url&&"1"!=s.url&&(o.one("change",function(){l.remove(),n.off("load").remove(),n=null}).addClass("elfinder-overflow-auto"),l=e('
                    '+i.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),c=e('
                    ').appendTo(l),d=i.convAbsUrl(i.url(s.hash)),n=e('').css("background-color","transparent").appendTo(o).on("load",function(){t.hideinfo(),l.remove(),t.preview.after(t.info),e(this).css("background-color","#fff").show()}).on("error",function(){l.remove(),t.preview.after(t.info)}).attr("src","//sharecad.org/cadframe/load?url="+encodeURIComponent(d)),t.info.after(t.preview))}})},function(t){var n,i,a,o,r,s=t.fm,l={"application/vnd.google-earth.kml+xml":!0,"application/vnd.google-earth.kmz":!0},c=t.preview;t.options.googleMapsApiKey&&(t.addIntegration({title:"Google Maps",link:"https://www.google.com/intl/"+s.lang.replace("_","-")+"/help/terms_maps.html"}),n=window.google&&google.maps,i=function(e,i,a){var r=t.options.googleMapsOpts.maps;s.forExternalUrl(e.hash,{progressBar:a}).done(function(e){if(e)try{new n.KmlLayer(e,Object.assign({map:new n.Map(i.get(0),r)},t.options.googleMapsOpts.kml)),t.hideinfo()}catch(a){o()}else o()})},a=window.gm_authFailure,o=function(){r=null},r="https://maps.googleapis.com/maps/api/js?key="+t.options.googleMapsApiKey,window.gm_authFailure=function(){o(),a&&a()},c.on(t.evUpdate,function(a){var o=a.file;if(r&&l[o.mime.toLowerCase()]){var d,p,u,h=(t.window,"1"==o.url&&!s.option("onetimeUrl",o.hash));a.stopImmediatePropagation(),d=e('
                    '+s.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),p=e('
                    ').appendTo(d),h&&(c.hide(),e('
                    ").appendTo(t.info.find(".elfinder-quicklook-info")).on("click",function(){var n=e(this);n.html(''),s.request({data:{cmd:"url",target:o.hash},preventDefault:!0,progressBar:p}).always(function(){d.remove(),n.html("")}).done(function(e){var n=s.file(o.hash);o.url=n.url=e.url||"",o.url&&c.trigger({type:t.evUpdate,file:o,forceUpdate:!0})})})),""===o.url||h||(u=e('
                    ').appendTo(c),c.one("change",function(){u.remove(),u=null}),n?i(o,u,p):s.loadScript([r],function(){n=window.google&&google.maps,n&&i(o,u,p)}))}}))},function(t){var n,i,a=t.fm,o=Object.assign(a.arrayFlip(t.options.googleDocsMimes||[],"g"),a.arrayFlip(t.options.officeOnlineMimes||[],"m")),r=t.preview,s=(t.window,t.navbar),l={g:"docs.google.com/gview?embedded=true&url=",m:"view.officeapps.live.com/op/embed.aspx?wdStartOn=0&src="},c={g:"56px",m:"24px"},d={xls:5242880,xlsb:5242880,xlsx:5242880,xlsm:5242880,other:10485760};t.options.googleDocsMimes.length&&(i=!0,t.addIntegration({title:"Google Docs Viewer",link:"https://docs.google.com/"})),t.options.officeOnlineMimes.length&&(i=!0,t.addIntegration({title:"MS Online Doc Viewer",link:"https://products.office.com/office-online/view-office-documents-online"})),i&&r.on(t.evUpdate,function(i){var p,u,h=i.file;if(h.size<=26214400&&(p=o[h.mime])){var f,m,g,v=t.window,b=function(){s.css("bottom",v.hasClass("elfinder-quicklook-fullscreen")?c[p]:"")},y=a.mimeTypes[h.mime],w="1"==h.url&&!a.option("onetimeUrl",h.hash);"m"===p&&(d[y]&&h.size>d[y]||h.size>d.other)&&(p="g"),w&&(r.hide(),e('
                    ").appendTo(t.info.find(".elfinder-quicklook-info")).on("click",function(){var n=e(this);n.html(''),a.request({data:{cmd:"url",target:h.hash},preventDefault:!0}).always(function(){n.html("")}).done(function(e){var n=a.file(h.hash);h.url=n.url=e.url||"",h.url&&r.trigger({type:t.evUpdate,file:h,forceUpdate:!0})})})),""===h.url||w||(i.stopImmediatePropagation(),r.one("change",function(){u&&u.status&&"pending"===u.status()&&u.reject(),v.off("viewchange.googledocs"),f.remove(),n.off("load").remove(),n=null}).addClass("elfinder-overflow-auto"),f=e('
                    '+a.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),m=e('
                    ').appendTo(f),n=e('').css("background-color","transparent").appendTo(r),u=a.forExternalUrl(h.hash,{progressBar:m}).done(function(i){var a=function(){try{!n||n.attr("src")&&!n.get(0).contentWindow.document||(n.attr("src","https://"+l[p]+encodeURIComponent(i)),g=setTimeout(a,2e3))}catch(e){}};i?(h.ts&&(i+=(i.match(/\?/)?"&":"?")+"_t="+h.ts),n.on("load",function(){g&&clearTimeout(g),t.hideinfo(),f.remove(),t.preview.after(t.info),e(this).css("background-color","#fff").show()}).on("error",function(){g&&clearTimeout(g),f.remove(),t.preview.after(t.info)}),a()):(f.remove(),n.remove())}),v.on("viewchange.googledocs",b),b(),t.info.after(t.preview))}})},function(t){"use strict";var n,i,a=t.fm,o=t.preview,r=parseInt(t.options.textInitialLines)||150,s=parseInt(t.options.prettifyMaxLines)||500,l=function(){c=function(){return!1},i&&(window.PR=i),n=!1},c=function(e){a.options.cdns.prettify?(c=function(e){return setTimeout(function(){p(e)},100),"pending"},window.PR&&(i=window.PR),a.loadScript([a.options.cdns.prettify+(a.options.cdns.prettify.match(/\?/)?"&":"?")+"autorun=false"],function(t){n=t||window.PR,"object"==typeof n?(c=function(){return!0},i?window.PR=i:delete window.PR,d(e)):l()},{tryRequire:!0,error:l})):l()},d=function(e){e&&!e.hasClass("prettyprinted")&&(e.css("cursor","wait"),requestAnimationFrame(function(){n.prettyPrint&&n.prettyPrint(null,e.get(0)),e.css("cursor","")}))},p=function(e){var t=c(e);t===!0&&d(e)};o.on(t.evUpdate,function(i){var l,c,d,u,h=i.file;h.mime;a.mimeIsText(h.mime)&&(!t.options.getSizeMax||h.size<=t.options.getSizeMax)&&n!==!1&&(i.stopImmediatePropagation(),c=e('
                    '+a.i18n("nowLoading")+'
                    ').appendTo(t.info.find(".elfinder-quicklook-info")),d=e('
                    ').appendTo(c),o.one("change",function(){"pending"==l.state()&&l.reject(),u&&u.remove()}),l=a.request({data:{cmd:"get",target:h.hash,conv:h.encoding||1,_t:h.ts},options:{type:"get",cache:!0},preventDefault:!0,progressBar:d}).done(function(n){var i,l,c,d,u,f=new RegExp("^(data:"+h.mime.replace(/([.+])/g,"\\$1")+";base64,)","i"),m=n.content;"string"==typeof m&&(t.hideinfo(),window.atob&&(u=m.match(f))&&(m=atob(m.substr(u[1].length))),d=m.match(/([^\r\n]{1,100}[\r\n]*)/g),l=d.length-r,l>10?i=d.splice(0,r).join(""):l=0,c=e('
                    '),l&&c.append(e('

                    '+a.i18n("linesLeft",a.toLocaleString(l))+"
                    ").on("click",function(){var t=c.scrollTop();e(this).remove(),c.children("pre").removeClass("prettyprinted").text(m).scrollTop(t),d.length<=s&&p(c)})),c.children("pre").text(i||m),c.on("touchstart",function(t){e(this)["scroll"+("ltr"===a.direction?"Right":"Left")]()>5&&(t.originalEvent._preventSwipeX=!0)}).appendTo(o),n.toasts&&Array.isArray(n.toasts)&&e.each(n.toasts,function(){this.msg&&a.toast(this)}),p(c))}).always(function(n){var i,r,s;(i=a.getCommand("edit"))&&(s=[],n&&n.encoding&&s.push({value:n.encoding}),s.push({value:"UTF-8"}),r=i.getEncSelect(s),r.on("change",function(){h.encoding=r.val(),a.cache(h,"change"),o.trigger({type:t.evUpdate,file:h,forceUpdate:!0})}),u=e('
                    ').append(r),t.window.append(u)),c.remove()}))})}],(i.prototype.commands.reload=function(){"use strict";var t=this,n=!1;this.alwaysEnabled=!0,this.updateOnSelect=!0,this.shortcuts=[{pattern:"ctrl+shift+r f5"}],this.getstate=function(){return 0},this.init=function(){this.fm.bind("search searchend",function(){n="search"==this.type})},this.fm.bind("contextmenu",function(){var n=t.fm;n.options.sync>=1e3&&(t.extra={icon:"accept",node:e("").attr({title:n.i18n("autoSync")}).on("click touchstart",function(t){"touchstart"===t.type&&t.originalEvent.touches.length>1||(t.stopPropagation(), +t.preventDefault(),e(this).parent().toggleClass("ui-state-disabled",n.options.syncStart).parent().removeClass("ui-state-hover"),n.options.syncStart=!n.options.syncStart,n.autoSync(n.options.syncStart?null:"stop"))}).on("ready",function(){e(this).parent().toggleClass("ui-state-disabled",!n.options.syncStart).css("pointer-events","auto")})})}),this.exec=function(){var t=this.fm;if(!n){var i=t.sync(),a=setTimeout(function(){t.notify({type:"reload",cnt:1,hideCnt:!0}),i.always(function(){t.notify({type:"reload",cnt:-1})})},t.notifyDelay);return i.always(function(){clearTimeout(a),t.trigger("reload")})}e("div.elfinder-toolbar > div."+t.res("class","searchbtn")+" > span.ui-icon-search").click()}}).prototype={forceLoad:!0},i.prototype.commands.rename=function(){"use strict";this.fm.options.enableRootRename!==!1&&(this.alwaysEnabled=!0),this.syncTitleOnChange=!0;var t=this,n=t.fm,i=n.options.enableRootRename!==!1,a=function(t,a,o,r){var s,l=a?[o.hash].concat(a):[o.hash],c=l.length,d={};if(n.lockfiles({files:l}),n.isRoot(o)&&!o.netkey&&i){if((s=n.storage("rootNames"))||(s={}),""===r){if(!s[o.hash])return t&&t.reject(),void n.unlockfiles({files:l}).trigger("selectfiles",{files:l});o.name=o._name,o.i18=o._i18,delete s[o.hash],delete o._name,delete o._i18}else"undefined"==typeof o._name&&(o._name=o.name,o._i18=o.i18),o.name=s[o.hash]=r,delete o.i18;return n.storage("rootNames",s),d={changed:[o]},n.updateCache(d),n.change(d),t&&t.resolve(d),void n.unlockfiles({files:l}).trigger("selectfiles",{files:l})}d={cmd:"rename",name:r,target:o.hash},c>1&&(d.targets=a,r.match(/\*/)&&(d.q=r)),n.request({data:d,notify:{type:"rename",cnt:c},navigate:{}}).fail(function(e){var i=n.parseError(e);t&&t.reject(),i&&Array.isArray(i)&&"errRename"===i[0]||n.sync()}).done(function(i){var a;i.added&&i.added.length&&1===c&&(i.undo={cmd:"rename",callback:function(){return n.request({data:{cmd:"rename",target:i.added[0].hash,name:o.name},notify:{type:"undo",cnt:1}})}},i.redo={cmd:"rename",callback:function(){return n.request({data:{cmd:"rename",target:o.hash,name:r},notify:{type:"rename",cnt:1}})}}),t&&t.resolve(i),(a=n.cwd().hash)&&a!==o.hash||n.exec("open",e.map(i.added,function(e){return"directory"===e.mime?e.hash:null})[0])}).always(function(){n.unlockfiles({files:l}).trigger("selectfiles",{files:l})})},o=function(e,t){var i,a,o,r=t||n.selected(),s=n.splitFileExtention(e),l=n.file(r[0]),c=n.file(r[1]);return i=s[1]?"."+s[1]:"",s[1]&&"*"===s[0]?(a='"'+n.splitFileExtention(l.name)[0]+i+'", ',a+='"'+n.splitFileExtention(c.name)[0]+i+'"'):s[0].length>1&&("*"===s[0].substr(-1)?(o=s[0].substr(0,s[0].length-1),a='"'+o+l.name+'", ',a+='"'+o+c.name+'"'):"*"===s[0].substr(0,1)&&(o=s[0].substr(1),a='"'+n.splitFileExtention(l.name)[0]+o+i+'", ',a+='"'+n.splitFileExtention(c.name)[0]+o+i+'"')),a||(a='"'+s[0]+"1"+i+'", "'+s[0]+"2"+i+'"'),r.length>2&&(a+=" ..."),a},r=function(){var i,r=n.selected(),s='',l=function(t,i){return e('").prepend(t)},c=e(''),d=e(s),p=e(s),u=e(s),h=e(s),f=e("
                    ").append(l(d,"plusNumber"),l(p,"asPrefix"),l(u,"asSuffix"),l(h,"changeExtention")),m=e('
                    '),g=e('
                    ').append(e('
                    ').append(c),e('
                    ').append(f),m),v={title:n.i18n("batchRename"),modal:!0,destroyOnClose:!0,width:Math.min(380,n.getUI().width()-20),buttons:{},open:function(){c.on("input",y).trigger("focus")}},b=function(){var e=c.val(),t=n.splitFileExtention(n.file(r[0]).name)[1];return(""!==e||d.is(":checked"))&&(p.is(":checked")?e+="*":u.is(":checked")?e="*"+e+"."+t:h.is(":checked")?e="*."+e:t&&(e+="."+t)),e},y=function(){var e=b();""!==e?m.html(n.i18n(["renameMultiple",r.length,o(e)])):m.empty()},w=f.find("input:radio").on("change",y);v.buttons[n.i18n("btnApply")]=function(){var e,t,o=b();""!==o&&(i.elfinderdialog("close"),t=r,e=n.file(t.shift()),a(void 0,t,e,o))},v.buttons[n.i18n("btnCancel")]=function(){i.elfinderdialog("close")},e.fn.checkboxradio?w.checkboxradio({create:function(e,t){this===d.get(0)&&d.prop("checked",!0).change()}}):f.buttonset({create:function(e,t){d.prop("checked",!0).change()}}),i=t.fmDialog(g,v)};this.noChangeDirOnRemovedCwd=!0,this.shortcuts=[{pattern:"f2"+("mac"==n.OS?" enter":"")},{pattern:"shift+f2",description:"batchRename",callback:function(){n.selected().length>1&&r()}}],this.getstate=function(a){var o,s,l,c,d,p,u=this.files(a),h=u.length;return h?(h>1&&u[0].phash&&(o=u[0].phash,s=n.splitFileExtention(u[0].name)[1].toLowerCase(),l=u[0].mime),1===h&&(p=n.isRoot(u[0])),d=1===h&&(i&&n.cookieEnabled&&p||!u[0].locked)||n.api>2.103&&h===e.grep(u,function(e){return!(c||e.locked||e.phash!==o||n.isRoot(e)||l!==e.mime&&s!==n.splitFileExtention(e.name)[1].toLowerCase())||(c&&(c=!0),!1)}).length?0:-1,!p&&0===d&&n.option("disabledFlip",u[0].hash).rename&&(d=-1),d!==-1&&h>1?t.extra={icon:"preference",node:e("").attr({title:n.i18n("batchRename")}).on("click touchstart",function(e){"touchstart"===e.type&&e.originalEvent.touches.length>1||(e.stopPropagation(),e.preventDefault(),n.getUI().trigger("click"),r())})}:delete t.extra,d):-1},this.exec=function(t,r){var s,l=(n.getUI("cwd"),t||!!n.selected().length&&n.selected()||[n.cwd().hash]),c=l.length,d=n.file(l.shift()),p=".elfinder-cwd-filename",u=r||{},h=n.cwd().hash==d.hash,f="navbar"===u._currentType||"files"===u._currentType?u._currentType:h?"navbar":"files",m="files"!==f,g=n[m?"navHash2Elm":"cwdHash2Elm"](d.hash),v=!m&&"list"!=n.storage("view"),b=function(){requestAnimationFrame(function(){k&&k.trigger("blur")})},y=function(){A.is(":hidden")||A.elfinderoverlay("hide").off("click close",j),T.removeClass("ui-front").css("position","").off("unselect."+n.namespace,b),v?z&&z.css("max-height",""):m||T.css("width","").parent("td").css("overflow","")},w=e.Deferred().fail(function(e){var t=k.parent(),i=n.escape(d.i18||d.name);k.off(),v&&(i=i.replace(/([_.])/g,"​$1")),requestAnimationFrame(function(){m?k.replaceWith(i):t.length?(k.remove(),t.html(i)):g.find(p).html(i)}),e&&n.error(e)}).always(function(){y(),n.unbind("resize",O),n.enable()}),x=function(t){var i=e.trim(k.val()),r=(n.splitFileExtention(i),!0),s=function(){k.off(),y(),m?k.replaceWith(n.escape(i)):z.html(n.escape(i)),a(w,l,d,i)};if(A.is(":hidden")||T.css("z-index",""),""===i){if(!n.isRoot(d))return j();m?k.replaceWith(n.escape(d.name)):z.html(n.escape(d.name))}if(!S&&T.length){if(k.off("blur"),1===c&&i===d.name)return w.reject();if(n.options.validName&&n.options.validName.test)try{r=n.options.validName.test(i)}catch(t){r=!1}if("."===i||".."===i||!r)return S=!0,n.error("directory"===d.mime?"errInvDirname":"errInvName",{modal:!0,close:function(){setTimeout(C,120)}}),!1;if(1===c&&n.fileByName(i,d.phash))return S=!0,n.error(["errExists",i],{modal:!0,close:function(){setTimeout(C,120)}}),!1;1===c?s():(n.confirm({title:"cmdrename",text:["renameMultiple",c,o(i,[d.hash].concat(l))],accept:{label:"btnYes",callback:s},cancel:{label:"btnCancel",callback:function(){setTimeout(function(){S=!0,C()},120)}}}),setTimeout(function(){n.trigger("unselectfiles",{files:n.selected()}).trigger("selectfiles",{files:[d.hash].concat(l)})},120))}},k=e(v?"":'').on("keyup text",function(){v?(this.style.height="1px",this.style.height=this.scrollHeight+"px"):s&&(this.style.width=s+"px",this.scrollWidth>s&&(this.style.width=this.scrollWidth+10+"px"))}).on("keydown",function(t){t.stopImmediatePropagation(),t.keyCode==e.ui.keyCode.ESCAPE?w.reject():t.keyCode==e.ui.keyCode.ENTER&&(t.preventDefault(),k.trigger("blur"))}).on("mousedown click dblclick",function(e){e.stopPropagation(),"dblclick"===e.type&&e.preventDefault()}).on("blur",x).on("dragenter dragleave dragover drop",function(e){e.stopPropagation()}),C=function(){var e=n.splitFileExtention(k.val())[0];S||!n.UA.Mobile||n.UA.iOS||(A.on("click close",j).elfinderoverlay("show"),T.css("z-index",A.css("z-index")+1)),!n.enabled()&&n.enable(),S&&(S=!1,k.on("blur",x)),k.trigger("focus").trigger("select"),k[0].setSelectionRange&&k[0].setSelectionRange(0,e.length)},z=m?g.contents().filter(function(){return 3==this.nodeType&&e(this).parent().attr("id")===n.navHash2Id(d.hash)}):g.find(p),T=z.parent(),A=n.getUI("overlay"),j=function(e){A.is(":hidden")||T.css("z-index",""),S||(w.reject(),e&&(e.stopPropagation(),e.preventDefault()))},O=function(){g.trigger("scrolltoview",{blink:!1})},S=!1;return T.addClass("ui-front").css("position","relative").on("unselect."+n.namespace,b),n.bind("resize",O),m?z.replaceWith(k.val(d.name)):(v?z.css("max-height","none"):m||(s=T.width(),T.width(s-15).parent("td").css("overflow","visible")),z.empty().append(k.val(d.name))),c>1&&n.api<=2.103?w.reject():d&&z.length?!d.locked||n.isRoot(d)&&i?(n.one("select",function(){k.parent().length&&d&&e.inArray(d.hash,n.selected())===-1&&k.trigger("blur")}),k.trigger("keyup"),C(),w):w.reject(["errLocked",d.name]):w.reject("errCmdParams",this.title)},n.bind("select contextmenucreate closecontextmenu",function(e){var i,a=(e.data?e.data.selected||e.data.targets:null)||n.selected();a&&1===a.length&&(i=n.file(a[0]))&&n.isRoot(i)?t.title=n.i18n("kindAlias")+" ("+n.i18n("preference")+")":t.title=n.i18n("cmdrename"),"closecontextmenu"!==e.type?t.update(void 0,t.title):requestAnimationFrame(function(){t.update(void 0,t.title)})}).remove(function(t){var i;t.data&&t.data.removed&&(i=n.storage("rootNames"))&&(e.each(t.data.removed,function(e,t){i[t]&&delete i[t]}),n.storage("rootNames",i))})},i.prototype.commands.resize=function(){"use strict";var t=this.fm,n=0,i=function(t,n,i){var a=[{x:t/2,y:n/2},{x:-t/2,y:n/2},{x:-t/2,y:-n/2},{x:t/2,y:-n/2}],o=[],r={x:Number.MAX_VALUE,y:Number.MAX_VALUE},s={x:Number.MIN_VALUE,y:Number.MIN_VALUE};return e.each(a,function(e,t){o.push({x:t.x*Math.cos(i)-t.y*Math.sin(i),y:t.x*Math.sin(i)+t.y*Math.cos(i)})}),e.each(o,function(e,t){r.x=Math.min(r.x,t.x),r.y=Math.min(r.y,t.y),s.x=Math.max(s.x,t.x),s.y=Math.max(s.y,t.y)}),{width:s.x-r.x,height:s.y-r.y}};this.updateOnSelect=!1,this.getstate=function(){var e=t.selectedFiles();return 1==e.length&&e[0].read&&e[0].write&&e[0].mime.indexOf("image/")!==-1?0:-1},this.resizeRequest=function(n,i,a){var o=i||t.file(n.target),r=(o?o.tmb:null,t.isCommandEnabled("resize",n.target));if(r&&(!o||o&&o.read&&o.write&&o.mime.indexOf("image/")!==-1))return t.request({data:Object.assign(n,{cmd:"resize"}),notify:{type:"resize",cnt:1}}).fail(function(e){a&&a.reject(e)}).done(function(){n.quality&&t.storage("jpgQuality",n.quality===t.option("jpgQuality")?null:n.quality),a&&a.resolve()});var s;return s=o?o.mime.indexOf("image/")===-1?["errResize",o.name,"errUsupportType"]:["errResize",o.name,"errPerm"]:["errResize",n.target,"errPerm"],a?a.reject(s):t.error(s),e.Deferred().reject(s)},this.exec=function(a){var o,r,s,l,c=this,d=this.files(a),p=e.Deferred(),u=t.api>1,h=this.options,f=650,m=t.getUI(),g=e().controlgroup?"controlgroup":"buttonset",v="undefined"==typeof h.grid8px||"disable"!==h.grid8px,b=Array.isArray(h.presetSize)?h.presetSize:[],y="elfinder-dialog-active",w=t.res("class","editing"),x=function(a,o,r){var d,x,k,C,z,T="image/jpeg"===a.mime,A=e('
                    '),j='',O='
                    ',S='
                    ',I=null,M=!1,F=function(){M=!0},E=function(){M&&(M=!1,D.trigger("change"))},D=e('
                    ').on("focus","input[type=text],input[type=number]",function(){e(this).trigger("select")}).on("change",function(){I&&cancelAnimationFrame(I),I=requestAnimationFrame(function(){var e,n,a,o,r,s,c,d,p,u,h,f;at&&!M&&(a=at.data("canvas"))&&(e=D.children("div.elfinder-resize-control-panel:visible"),n=e.find("input.elfinder-resize-quality"),n.is(":visible")&&(o=at.data("ctx"),r=at.get(0),e.hasClass("elfinder-resize-uiresize")?(d=a.width=X.val(),p=a.height=J.val(),o.drawImage(r,0,0,d,p)):e.hasClass("elfinder-resize-uicrop")?(s=G.val(),c=Y.val(),d=Q.val(),p=Z.val(),a.width=d,a.height=p,o.drawImage(r,s,c,d,p,0,0,d,p)):(u=te.val(),h=te.val()*Math.PI/180,f=i(fe,me,h),d=a.width=f.width,p=a.height=f.height,o.save(),u%90!==0&&(o.fillStyle=de.val()||"#FFF",o.fillRect(0,0,d,p)),o.translate(d/2,p/2),o.rotate(h),o.drawImage(r,-r.width/2,-r.height/2,fe,me),o.restore()),a.toBlob(function(e){e&&(l=e.size,n.next("span").text(" ("+t.formatSize(e.size)+")"))},"image/jpeg",Math.max(Math.min(n.val(),100),1)/100)))})}).on("mouseup","input",function(t){e(t.target).trigger("change")}),U=e('
                    ').on("touchmove",function(t){e(t.target).hasClass("touch-punch")&&(t.stopPropagation(),t.preventDefault())}),P=e('
                    '+t.i18n("ntfloadimg")+"
                    "),R=e('
                    '),q=e('
                    '),H=e('
                    '),_=e('
                    '),N=e('
                    '),L=e("").attr("title",t.i18n("rotate-cw")).append(e('')),W=e("").attr("title",t.i18n("rotate-ccw")).append(e('')),B=e(""),$=e('").on("mouseenter mouseleave",function(t){e(this).toggleClass("ui-state-hover","mouseenter"==t.type)}).on("click",function(){d.exec("open",f).done(function(){d.one("opendone",function(){d.trigger("selectfiles",{files:e.map(t.added,function(e){return e.hash})})})})})):d.trigger("selectfiles",{files:e.map(t.added,function(e){return e.hash})}),d.toast({msg:d.i18n(["complete",d.i18n("cmdupload")]),extNode:n}))}}).progress(function(){w.notifyWith(this,Array.from(arguments))})},v=function(e){i.elfinderdialog("close"),h&&(e.target=h[0]),g(e)},b=function(){var t=m.hash,n=e.map(d.files(t),function(e){return"directory"===e.mime&&e.write?e:null});return n.length?e('
                    ').on("click",function(t){t.stopPropagation(),t.preventDefault(),n=d.sortFiles(n);var a=e(this),o=(d.cwd(),i.closest("div.ui-dialog")),r=function(e,t){return{label:d.escape(e.i18||e.name),icon:t,remain:!1,callback:function(){var t=o.children(".ui-dialog-titlebar:first").find("span.elfinder-upload-target");h=[e.hash],t.html(" - "+d.escape(e.i18||e.name)),a.trigger("focus")},options:{className:h&&h.length&&e.hash===h[0]?"ui-state-active":"",iconClass:e.csscls||"",iconImg:e.icon||""}}},s=[r(m,"opendir"),"|"];e.each(n,function(e,t){s.push(r(t,"dir"))}),a.trigger("blur"),d.trigger("contextmenu",{raw:s,x:t.pageX||e(this).offset().left,y:t.pageY||e(this).offset().top,prevNode:o,fitHeight:!0})}).append(''):e()},y=function(n,i){var a=e('").on("click",function(){d.UA.IE&&setTimeout(function(){o.css("display","none").css("position","relative"),requestAnimationFrame(function(){o.css("display","").css("position","")})},100)}).on("change",function(){v({input:a.get(0),type:"files"})}).on("dragover",function(e){e.originalEvent.dataTransfer.dropEffect="copy"}),o=e("
                    ").append(a).on("click",function(e){e.stopPropagation()});return e('
                    '+d.i18n(i)+"
                    ").append(o).on("click",function(e){e.stopPropagation(),e.preventDefault(),a.trigger("click")}).on("mouseenter mouseleave",function(n){e(this).toggleClass(t,"mouseenter"===n.type)})},w=e.Deferred();return r=function(t){t.stopPropagation(),t.preventDefault();var n,i,a=!1,o="",r=null,s="",l=null,c=t._target||null,p=t.dataTransfer||null,u="";if(p){p.types&&p.types.length?(n=e.inArray("application/x-moz-file",p.types))!==-1?u="file":(n=e.inArray("Files",p.types))!==-1&&(u="file"):p.items&&p.items.length&&p.items[0].kind&&(u=p.items[0].kind);try{if(r=p.getData("elfinderfrom"),r&&(s=window.location.href+d.cwd().hash,!c&&r===s||c===s))return void w.reject()}catch(t){}if("file"===u&&(p.items[n].getAsEntry||p.items[n].webkitGetAsEntry||p.items[n].getAsFile))a=p,o="data";else if("string"!==u&&p.files&&p.files.length&&e.inArray("Text",p.types)===-1)a=p.files,o="files";else{try{(l=p.getData("text/html"))&&l.match(/<(?:img|a)/i)&&(a=[l],o="html")}catch(t){}a||((l=p.getData("text"))?(a=[l],o="text"):p&&p.files&&(u="file"))}}a?g({files:a,type:o,target:c,dropEvt:t}):(i=["errUploadNoFiles"],"file"===u&&i.push("errFolderUpload"),d.error(i),w.reject())},!h&&n?(n.input||n.files?(n.type="files",g(n)):n.dropEvt&&r(n.dropEvt),w):(s=function(t){var n,i=t.originalEvent||t,a=[],o=[];if(i.clipboardData){if(i.clipboardData.items&&i.clipboardData.items.length){o=i.clipboardData.items;for(var r=0;r
                  ').append(y("multiple","selectForUpload")),!d.UA.Mobile&&function(e){return"undefined"!=typeof e.webkitdirectory||"undefined"!=typeof e.directory}(document.createElement("input"))&&i.append(y("multiple webkitdirectory directory","selectFolder")),m.dirs&&(m.hash===p||d.navHash2Elm(m.hash).hasClass("elfinder-subtree-loaded")?b().appendTo(i):(l=e('
                  ').append('').appendTo(i),d.request({cmd:"tree",target:m.hash}).done(function(){d.one("treedone",function(){l.replaceWith(b()),c.elfinderdialog("tabstopsInit")})}).fail(function(){l.remove()}))),d.dragUpload?a=e('
                  ').on("paste",function(e){s(e)}).on("mousedown click",function(){e(this).trigger("focus")}).on("focus",function(){this.innerHTML=""}).on("mouseover",function(){e(this).addClass(t)}).on("mouseout",function(){e(this).removeClass(t)}).on("dragenter",function(n){n.stopPropagation(),n.preventDefault(),e(this).addClass(t)}).on("dragleave",function(n){n.stopPropagation(),n.preventDefault(),e(this).removeClass(t)}).on("dragover",function(n){n.stopPropagation(),n.preventDefault(),n.originalEvent.dataTransfer.dropEffect="copy",e(this).addClass(t)}).on("drop",function(e){i.elfinderdialog("close"),h&&(e.originalEvent._target=h[0]),r(e.originalEvent)}).prependTo(i).after('
                  '+d.i18n("or")+"
                  ")[0]:o=e('
                  '+d.i18n("dropFilesBrowser")+"
                  ").on("paste drop",function(e){s(e)}).on("mousedown click",function(){e(this).trigger("focus")}).on("focus",function(){this.innerHTML=""; +}).on("dragenter mouseover",function(){e(this).addClass(t)}).on("dragleave mouseout",function(){e(this).removeClass(t)}).prependTo(i).after('
                  '+d.i18n("or")+"
                  ")[0],c=this.fmDialog(i,{title:this.title+''+(m?" - "+d.escape(m.i18||m.name):"")+"",modal:!0,resizable:!1,destroyOnClose:!0,propagationEvents:["mousemove","mouseup","click"],close:function(){var e=d.getUI("contextmenu");e.is(":visible")&&e.click()}}),w)}},i.prototype.commands.view=function(){"use strict";var t,n=this,i=this.fm;this.value=i.viewType,this.alwaysEnabled=!0,this.updateOnSelect=!1,this.options={ui:"viewbutton"},this.getstate=function(){return 0},this.extra={icon:"menu",node:e("").attr({title:i.i18n("viewtype")}).on("click touchstart",function(t){if(!("touchstart"===t.type&&t.originalEvent.touches.length>1)){var n=e(this);t.stopPropagation(),t.preventDefault(),i.trigger("contextmenu",{raw:getSubMenuRaw(),x:n.offset().left,y:n.offset().top})}})},this.exec=function(){var e=this,t="list"==this.value?"icons":"list";return i.storage("view",t),i.lazy(function(){i.viewchange(),e.update(void 0,t),this.resolve()})},i.bind("init",function(){t=function(){var e,t=i.getUI("cwd"),a=[],o=i.options.uiOptions.cwd.iconsView.sizeNames,r=i.options.uiOptions.cwd.iconsView.sizeMax;for(e=0;e<=r;e++)a.push({label:i.i18n(o[e]||"Size-"+e+" icons"),icon:"view",callback:function(e){return function(){t.trigger("iconpref",{size:e}),i.storage("iconsize",e),"list"===n.value&&n.exec()}}(e)});return a.push("|"),a.push({label:i.i18n("viewlist"),icon:"view-list",callback:function(){"list"!==n.value&&n.exec()}}),a}()}).bind("contextmenucreate",function(){n.extra={icon:"menu",node:e("").attr({title:i.i18n("cmdview")}).on("click touchstart",function(a){if(!("touchstart"===a.type&&a.originalEvent.touches.length>1)){var o,r,s=e(this);t.concat();for(o="list"===n.value?t.length-1:parseInt(i.storage("iconsize")||0),r=0;r
                  ') + .html('' + fm.i18n('ntfloadimg') + '') + .hide() + .appendTo(this), + setup = function() { + node.attr('id', id+'-img') + .attr('src', url || content) + .css({'height':'', 'max-width':'100%', 'max-height':'100%', 'cursor':'pointer'}) + .data('loading', function(done) { + var btns = node.closest('.elfinder-dialog').find('button,.elfinder-titlebar-button'); + btns.prop('disabled', !done)[done? 'removeClass' : 'addClass']('ui-state-disabled'); + node.css('opacity', done? '' : '0.3'); + spnr[done? 'hide' : 'show'](); + return node; + }); + }, + url; + + if (!content.match(/^data:/)) { + fm.openUrl(file.hash, false, function(v) { + url = v; + node.attr('_src', content); + setup(); + }); + } else { + setup(); + } + }, + imgBase64 = function(node, mime) { + var style = node.attr('style'), + img, canvas, ctx, data; + try { + // reset css for getting image size + node.attr('style', ''); + // img node + img = node.get(0); + // New Canvas + canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + // restore css + node.attr('style', style); + // Draw Image + canvas.getContext('2d').drawImage(img, 0, 0); + // To Base64 + data = canvas.toDataURL(mime); + } catch(e) { + data = node.attr('src'); + } + return data; + }, + iframeClose = function(ifm) { + var $ifm = $(ifm), + dfd = $.Deferred().always(function() { + $ifm.off('load', load); + }), + ab = 'about:blank', + chk = function() { + tm = setTimeout(function() { + var src; + try { + src = base.contentWindow.location.href; + } catch(e) { + src = null; + } + if (src === ab) { + dfd.resolve(); + } else if (--cnt > 0){ + chk(); + } else { + dfd.reject(); + } + }, 500); + }, + load = function() { + tm && clearTimeout(tm); + dfd.resolve(); + }, + cnt = 20, // 500ms * 20 = 10sec wait + tm; + $ifm.one('load', load); + ifm.src = ab; + chk(); + return dfd; + }; + + // check getfile callback function + if (getfile) { + getfile = getfile[1]; + if (getfile === 'ckeditor') { + elFinder.prototype._options.getFileCallback = function(file, fm) { + window.opener.CKEDITOR.tools.callFunction((function() { + var reParam = new RegExp('(?:[?&]|&)CKEditorFuncNum=([^&]+)', 'i'), + match = window.location.search.match(reParam); + return (match && match.length > 1) ? match[1] : ''; + })(), fm.convAbsUrl(file.url)); + fm.destroy(); + window.close(); + }; + } + } + + // return editors Array + return [ + { + // tui.image-editor - https://github.com/nhnent/tui.image-editor + info : { + id: 'tuiimgedit', + name: 'TUI Image Editor', + iconImg: 'img/editor-icons.png 0 -48', + dataScheme: true, + schemeContent: true, + openMaximized: true, + canMakeEmpty: false, + integrate: { + title: 'TOAST UI Image Editor', + link: 'http://ui.toast.com/tui-image-editor/' + } + }, + // MIME types to accept + mimes : ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'], + // HTML of this editor + html : '
                  ', + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE8 || fm.UA.Mobile) { + this.disabled = true; + } else { + this.opts = Object.assign({ + version: 'v3.15.3' + }, opts.extraOptions.tuiImgEditOpts || {}, { + iconsPath : fm.baseUrl + 'img/tui-', + theme : {} + }); + if (!fm.isSameOrigin(this.opts.iconsPath)) { + this.disabled = true; + fm.debug('warning', 'Setting `commandOptions.edit.extraOptions.tuiImgEditOpts.iconsPath` MUST follow the same origin policy.'); + } + } + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, content, fm) { + this.data('url', content); + }, + load : function(base) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + cdns = fm.options.cdns, + ver = self.confObj.opts.version, + init = function(editor) { + var $base = $(base), + bParent = $base.parent(), + opts = self.confObj.opts, + iconsPath = opts.iconsPath, + tmpContainer = $('
                  ').appendTo(bParent), + tmpDiv = [ + $('
                  ').appendTo(tmpContainer), + $('
                  ').appendTo(tmpContainer) + ], + iEditor = new editor(base, { + includeUI: { + loadImage: { + path: $base.data('url'), + name: self.file.name + }, + theme: opts.theme, + initMenu: 'filter', + menuBarPosition: 'bottom' + }, + cssMaxWidth: Math.max(300, bParent.width()), + cssMaxHeight: Math.max(200, bParent.height() - (tmpDiv[0].height() + tmpDiv[1].height() + 3 /*margin*/)), + usageStatistics: false + }), + canvas = $base.find('canvas:first').get(0), + zoom = function(v) { + if (typeof v !== 'undefined') { + var c = $(canvas), + w = parseInt(c.attr('width')), + h = parseInt(c.attr('height')), + a = w / h, + z, mw, mh; + if (v === 0) { + mw = w; + mh = h; + } else { + mw = parseInt(c.css('max-width')) + Number(v); + mh = mw / a; + if (mw > w && mh > h) { + mw = w; + mh = h; + } + } + z = Math.round(mw / w * 100); + // Control zoom button of TUI Image Editor + if (z < 100) { + iEditor.resetZoom(); + iEditor.stopDrawingMode(); + tuiZoomCtrls.hide(); + } else { + tuiZoomCtrls.show(); + } + per.text(z + '%'); + iEditor.resizeCanvasDimension({width: mw, height: mh}); + // continually change more + if (zoomMore) { + setTimeout(function() { + zoomMore && zoom(v); + }, 50); + } + } + }, + zup = $('').data('val', 10), + zdown = $('').data('val', -10), + per = $('').css('width', '4em').text('%').attr('title', '100%').data('val', 0), + tuiZoomCtrls, + quty, qutyTm, zoomTm, zoomMore; + + tmpContainer.remove(); + $base.removeData('url').data('mime', self.file.mime); + // jpeg quality controls + if (self.file.mime === 'image/jpeg') { + $base.data('quality', fm.storage('jpgQuality') || fm.option('jpgQuality')); + quty = $('') + .attr('min', '1') + .attr('max', '100') + .attr('title', '1 - 100') + .on('change', function() { + var q = quty.val(); + $base.data('quality', q); + qutyTm && cancelAnimationFrame(qutyTm); + qutyTm = requestAnimationFrame(function() { + canvas.toBlob(function(blob) { + blob && quty.next('span').text(' (' + fm.formatSize(blob.size) + ')'); + }, 'image/jpeg', Math.max(Math.min(q, 100), 1) / 100); + }); + }) + .val($base.data('quality')); + $('
                  ') + .append( + $('').html(fm.i18n('quality') + ' : '), quty, $('') + ) + .prependTo($base.parent().next()); + } else if (self.file.mime === 'image/svg+xml') { + $base.closest('.ui-dialog').trigger('changeType', { + extention: 'png', + mime : 'image/png', + keepEditor: true + }); + } + // zoom scale controls + $('
                  ') + .append( + zdown, per, zup + ) + .attr('title', fm.i18n('scale')) + .on('click', 'span,button', function() { + zoom($(this).data('val')); + }) + .on('mousedown mouseup mouseleave', 'span', function(e) { + zoomMore = false; + zoomTm && clearTimeout(zoomTm); + if (e.type === 'mousedown') { + zoomTm = setTimeout(function() { + zoomMore = true; + zoom($(e.target).data('val')); + }, 500); + } + }) + .prependTo($base.parent().next()); + + // wait canvas ready + setTimeout(function() { + dfrd.resolve(iEditor); + if (quty) { + quty.trigger('change'); + iEditor.on('redoStackChanged undoStackChanged', function() { + quty.trigger('change'); + }); + } + // ZOOM controls of TUI Image Editor + tuiZoomCtrls = $base.find('.tie-btn-zoomIn,.tie-btn-zoomOut,.tie-btn-hand'); + // show initial scale + zoom(null); + }, 100); + + // show color slider (maybe TUI-Image-Editor's bug) + // see https://github.com/nhn/tui.image-editor/issues/153 + $base.find('.tui-colorpicker-palette-container').on('click', '.tui-colorpicker-palette-preview', function() { + $(this).closest('.color-picker-control').height('auto').find('.tui-colorpicker-slider-container').toggle(); + }); + $base.on('click', function() { + $base.find('.tui-colorpicker-slider-container').hide(); + }); + }, + loader; + + if (!self.confObj.editor) { + loader = $.Deferred(); + fm.loadCss([ + cdns.tui + '/tui-color-picker/latest/tui-color-picker.css', + cdns.tui + '/tui-image-editor/'+ver+'/tui-image-editor.css' + ]); + if (fm.hasRequire) { + require.config({ + paths : { + 'fabric/dist/fabric.require' : cdns.fabric + '/fabric.require.min', // for fabric < 2.0.1 + 'fabric' : cdns.fabric + '/fabric.min', // for fabric >= 2.0.1 + 'tui-code-snippet' : cdns.tui + '/tui.code-snippet/latest/tui-code-snippet.min', + 'tui-color-picker' : cdns.tui + '/tui-color-picker/latest/tui-color-picker.min', + 'tui-image-editor' : cdns.tui + '/tui-image-editor/'+ver+'/tui-image-editor.min' + } + }); + require(['tui-image-editor'], function(ImageEditor) { + loader.resolve(ImageEditor); + }); + } else { + fm.loadScript([ + cdns.fabric + '/fabric.min.js', + cdns.tui + '/tui.code-snippet/latest/tui-code-snippet.min.js' + ], function() { + fm.loadScript([ + cdns.tui + '/tui-color-picker/latest/tui-color-picker.min.js' + ], function() { + fm.loadScript([ + cdns.tui + '/tui-image-editor/'+ver+'/tui-image-editor.min.js' + ], function() { + loader.resolve(window.tui.ImageEditor); + }, { + loadType: 'tag' + }); + }, { + loadType: 'tag' + }); + }, { + loadType: 'tag' + }); + } + loader.done(function(editor) { + self.confObj.editor = editor; + init(editor); + }); + } else { + init(self.confObj.editor); + } + return dfrd; + }, + getContent : function(base) { + var editor = this.editor, + fm = editor.fm, + $base = $(base), + quality = $base.data('quality'); + if (editor.instance) { + if ($base.data('mime') === 'image/jpeg') { + quality = quality || fm.storage('jpgQuality') || fm.option('jpgQuality'); + quality = Math.max(0.1, Math.min(1, quality / 100)); + } + return editor.instance.toDataURL({ + format: getExtention($base.data('mime'), fm, true), + quality: quality + }); + } + }, + save : function(base) { + var $base = $(base), + quality = $base.data('quality'), + hash = $base.data('hash'), + file; + this.instance.deactivateAll(); + if (typeof quality !== 'undefined') { + this.fm.storage('jpgQuality', quality); + } + if (hash) { + file = this.fm.file(hash); + $base.data('mime', file.mime); + } + } + }, + { + // Photopea advanced image editor + info : { + id : 'photopea', + name : 'Photopea', + iconImg : 'img/editor-icons.png 0 -160', + single: true, + noContent: true, + arrayBufferContent: true, + openMaximized: true, + // Disable file types that cannot be saved on Photopea. + canMakeEmpty: ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp', 'image/tiff', /*'image/x-adobe-dng',*/ 'image/webp', /*'image/x-xcf',*/ 'image/vnd.adobe.photoshop', 'application/pdf', 'image/x-portable-pixmap', 'image/x-sketch', 'image/x-icon', 'image/vnd-ms.dds', /*'application/x-msmetafile'*/], + integrate: { + title: 'Photopea', + link: 'https://www.photopea.com/learn/' + } + }, + mimes : ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp', 'image/tiff', 'image/x-adobe-dng', 'image/webp', 'image/x-xcf', 'image/vnd.adobe.photoshop', 'application/pdf', 'image/x-portable-pixmap', 'image/x-sketch', 'image/x-icon', 'image/vnd-ms.dds', 'application/x-msmetafile'], + html : '', + // setup on elFinder bootup + setup : function(opts, fm) { + if (fm.UA.IE || fm.UA.Mobile) { + this.disabled = true; + } + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, dum, fm) { + var orig = 'https://www.photopea.com', + ifm = $(this).hide() + //.css('box-sizing', 'border-box') + .on('load', function() { + //spnr.remove(); + ifm.show(); + }) + .on('error', function() { + spnr.remove(); + ifm.show(); + }), + editor = this.editor, + confObj = editor.confObj, + spnr = $('
                  ') + .html('' + fm.i18n('nowLoading') + '') + .appendTo(ifm.parent()), + saveMimes = fm.arrayFlip(confObj.info.canMakeEmpty), + getType = function(mime) { + var ext = getExtention(mime, fm), + extmime = ext2mime[ext]; + + if (!confObj.mimesFlip[extmime]) { + ext = ''; + } else if (ext === 'jpeg') { + ext = 'jpg'; + } + if (!ext || !saveMimes[extmime]) { + ext = 'psd'; + extmime = ext2mime[ext]; + ifm.closest('.ui-dialog').trigger('changeType', { + extention: ext, + mime : extmime, + keepEditor: true + }); + } + return ext; + }, + mime = file.mime, + liveMsg, type, quty; + + if (!confObj.mimesFlip) { + confObj.mimesFlip = fm.arrayFlip(confObj.mimes, true); + } + if (!confObj.liveMsg) { + confObj.liveMsg = function(ifm, spnr, file) { + var wnd = ifm.get(0).contentWindow, + phase = 0, + data = null, + dfdIni = $.Deferred().done(function() { + spnr.remove(); + phase = 1; + wnd.postMessage(data, orig); + }), + dfdGet; + + this.load = function() { + return fm.getContents(file.hash, 'arraybuffer').done(function(d) { + data = d; + }); + }; + + this.receive = function(e) { + var ev = e.originalEvent, + state; + if (ev.origin === orig && ev.source === wnd) { + if (ev.data === 'done') { + if (phase === 0) { + dfdIni.resolve(); + } else if (phase === 1) { + phase = 2; + ifm.trigger('contentsloaded'); + } else { + if (dfdGet && dfdGet.state() === 'pending') { + dfdGet.reject('errDataEmpty'); + } + } + } else if (ev.data === 'Save') { + editor.doSave(); + } else { + if (dfdGet && dfdGet.state() === 'pending') { + if (typeof ev.data === 'object') { + dfdGet.resolve('data:' + mime + ';base64,' + fm.arrayBufferToBase64(ev.data)); + } else { + dfdGet.reject('errDataEmpty'); + } + } + } + } + }; + + this.getContent = function() { + var type, q; + if (phase > 1) { + dfdGet && dfdGet.state() === 'pending' && dfdGet.reject(); + dfdGet = null; + dfdGet = $.Deferred(); + if (phase === 2) { + phase = 3; + dfdGet.resolve('data:' + mime + ';base64,' + fm.arrayBufferToBase64(data)); + data = null; + return dfdGet; + } + if (ifm.data('mime')) { + mime = ifm.data('mime'); + type = getType(mime); + } + if (q = ifm.data('quality')) { + type += ':' + (q / 100); + } + wnd.postMessage('app.activeDocument.saveToOE("' + type + '")', orig); + return dfdGet; + } + }; + }; + } + + ifm.parent().css('padding', 0); + type = getType(file.mime); + liveMsg = editor.liveMsg = new confObj.liveMsg(ifm, spnr, file); + $(window).on('message.' + fm.namespace, liveMsg.receive); + liveMsg.load().done(function() { + var d = JSON.stringify({ + files : [], + environment : { + lang: fm.lang.replace(/_/g, '-'), + customIO: {"save": "app.echoToOE(\"Save\");"} + } + }); + ifm.attr('src', orig + '/#' + encodeURI(d)); + }).fail(function(err) { + err && fm.error(err); + editor.initFail = true; + }); + + // jpeg quality controls + if (file.mime === 'image/jpeg' || file.mime === 'image/webp') { + ifm.data('quality', fm.storage('jpgQuality') || fm.option('jpgQuality')); + quty = $('') + .attr('min', '1') + .attr('max', '100') + .attr('title', '1 - 100') + .on('change', function() { + var q = quty.val(); + ifm.data('quality', q); + }) + .val(ifm.data('quality')); + $('
                  ') + .append( + $('').html(fm.i18n('quality') + ' : '), quty, $('') + ) + .prependTo(ifm.parent().next()); + } + }, + load : function(base) { + var dfd = $.Deferred(), + self = this, + fm = this.fm, + $base = $(base); + if (self.initFail) { + dfd.reject(); + } else { + $base.on('contentsloaded', function() { + dfd.resolve(self.liveMsg); + }); + } + return dfd; + }, + getContent : function() { + return this.editor.liveMsg? this.editor.liveMsg.getContent() : void(0); + }, + save : function(base, liveMsg) { + var $base = $(base), + quality = $base.data('quality'), + hash = $base.data('hash'), + file; + if (typeof quality !== 'undefined') { + this.fm.storage('jpgQuality', quality); + } + if (hash) { + file = this.fm.file(hash); + $base.data('mime', file.mime); + } else { + $base.removeData('mime'); + } + }, + // On dialog closed + close : function(base, liveMsg) { + $(base).attr('src', ''); + liveMsg && $(window).off('message.' + this.fm.namespace, liveMsg.receive); + } + }, + { + // Pixo is cross-platform image editor + info : { + id : 'pixo', + name : 'Pixo Editor', + iconImg : 'img/editor-icons.png 0 -208', + dataScheme: true, + schemeContent: true, + single: true, + canMakeEmpty: false, + integrate: { + title: 'Pixo Editor', + link: 'https://pixoeditor.com/privacy-policy/' + } + }, + // MIME types to accept + mimes : ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/x-ms-bmp'], + // HTML of this editor + html : '
                  ', + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE8 || !opts.extraOptions || !opts.extraOptions.pixo || !opts.extraOptions.pixo.apikey) { + this.disabled = true; + } else { + this.editorOpts = opts.extraOptions.pixo; + } + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, content, fm) { + initImgTag.call(this, id, file, content, fm); + }, + // Get data uri scheme (this: this editors HTML node) + getContent : function() { + return $(this).children('img:first').attr('src'); + }, + // Launch Pixo editor when dialog open + load : function(base) { + var self = this, + fm = this.fm, + $base = $(base), + node = $base.children('img:first'), + dialog = $base.closest('.ui-dialog'), + elfNode = fm.getUI(), + dfrd = $.Deferred(), + container = $('#elfinder-pixo-container'), + init = function(onload) { + var opts; + + if (!container.length) { + container = $('
                  ').css({ + position: 'fixed', + top: 0, + right: 0, + width: '100%', + height: $(window).height(), + overflow: 'hidden' + }).hide().appendTo(elfNode.hasClass('elfinder-fullscreen')? elfNode : 'body'); + // bind switch fullscreen event + elfNode.on('resize.'+fm.namespace, function(e, data) { + e.preventDefault(); + e.stopPropagation(); + data && data.fullscreen && container.appendTo(data.fullscreen === 'on'? elfNode : 'body'); + }); + fm.bind('destroy', function() { + editor && editor.cancelEditing(); + container.remove(); + }); + } else { + // always moves to last + container.appendTo(container.parent()); + } + node.on('click', launch); + // Constructor options + opts = Object.assign({ + type: 'child', + parent: container.get(0), + output: {format: 'png'}, + onSave: function(arg) { + // Check current file.hash, all callbacks are called on multiple instances + var mime = arg.toBlob().type, + ext = getExtention(mime, fm), + draw = function(url) { + node.one('load error', function() { + node.data('loading') && node.data('loading')(true); + }) + .attr('crossorigin', 'anonymous') + .attr('src', url); + }, + url = arg.toDataURL(); + node.data('loading')(); + delete base._canvas; + if (node.data('ext') !== ext) { + changeImageType(url, self.file.mime).done(function(res, cv) { + if (cv) { + base._canvas = canvas = cv; + quty.trigger('change'); + qBase && qBase.show(); + } + draw(res); + }).fail(function() { + dialog.trigger('changeType', { + extention: ext, + mime : mime + }); + draw(url); + }); + } else { + draw(url); + } + }, + onClose: function() { + dialog.removeClass(fm.res('class', 'preventback')); + fm.toggleMaximize(container, false); + container.hide(); + fm.toFront(dialog); + } + }, self.confObj.editorOpts); + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: base, + editorObj: Pixo, + instance: void(0), + opts: opts + }); + // make editor instance + editor = new Pixo.Bridge(opts); + dfrd.resolve(editor); + $base.on('saveAsFail', launch); + if (onload) { + onload(); + } + }, + launch = function() { + dialog.addClass(fm.res('class', 'preventback')); + fm.toggleMaximize(container, true); + fm.toFront(container); + container.show().data('curhash', self.file.hash); + editor.edit(node.get(0)); + node.data('loading')(true); + }, + qBase, quty, qutyTm, canvas, editor; + + node.data('loading')(); + + // jpeg quality controls + if (self.file.mime === 'image/jpeg') { + quty = $('') + .attr('min', '1') + .attr('max', '100') + .attr('title', '1 - 100') + .on('change', function() { + var q = quty.val(); + qutyTm && cancelAnimationFrame(qutyTm); + qutyTm = requestAnimationFrame(function() { + if (canvas) { + canvas.toBlob(function(blob) { + blob && quty.next('span').text(' (' + fm.formatSize(blob.size) + ')'); + }, 'image/jpeg', Math.max(Math.min(q, 100), 1) / 100); + } + }); + }) + .val(fm.storage('jpgQuality') || fm.option('jpgQuality')); + qBase = $('
                  ') + .hide() + .append( + $('').html(fm.i18n('quality') + ' : '), quty, $('') + ) + .prependTo($base.parent().next()); + $base.data('quty', quty); + } + + // load script then init + if (typeof Pixo === 'undefined') { + fm.loadScript(['https://pixoeditor.com:8443/editor/scripts/bridge.m.js'], function() { + init(launch); + }, {loadType: 'tag'}); + } else { + init(); + launch(); + } + return dfrd; + }, + // Convert content url to data uri scheme to save content + save : function(base) { + var self = this, + $base = $(base), + node = $base.children('img:first'), + q; + if (base._canvas) { + if ($base.data('quty')) { + q = $base.data('quty').val(); + q && this.fm.storage('jpgQuality', q); + } + node.attr('src', base._canvas.toDataURL(self.file.mime, q? Math.max(Math.min(q, 100), 1) / 100 : void(0))); + } else if (node.attr('src').substr(0, 5) !== 'data:') { + node.attr('src', imgBase64(node, this.file.mime)); + } + }, + close : function(base, editor) { + editor && editor.destroy(); + } + }, + { + // ACE Editor + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE8 || !fm.options.cdns.ace) { + this.disabled = true; + } + }, + // `mimes` is not set for support everything kind of text file + info : { + id : 'aceeditor', + name : 'ACE Editor', + iconImg : 'img/editor-icons.png 0 -96' + }, + load : function(textarea) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + cdn = fm.options.cdns.ace, + start = function() { + var editor, editorBase, mode, + ta = $(textarea), + taBase = ta.parent(), + dialog = taBase.parent(), + id = textarea.id + '_ace', + ext = self.file.name.replace(/^.+\.([^.]+)|(.+)$/, '$1$2').toLowerCase(), + // MIME/mode map + mimeMode = { + 'text/x-php' : 'php', + 'application/x-php' : 'php', + 'text/html' : 'html', + 'application/xhtml+xml' : 'html', + 'text/javascript' : 'javascript', + 'application/javascript' : 'javascript', + 'text/css' : 'css', + 'text/x-c' : 'c_cpp', + 'text/x-csrc' : 'c_cpp', + 'text/x-chdr' : 'c_cpp', + 'text/x-c++' : 'c_cpp', + 'text/x-c++src' : 'c_cpp', + 'text/x-c++hdr' : 'c_cpp', + 'text/x-shellscript' : 'sh', + 'application/x-csh' : 'sh', + 'text/x-python' : 'python', + 'text/x-java' : 'java', + 'text/x-java-source' : 'java', + 'text/x-ruby' : 'ruby', + 'text/x-perl' : 'perl', + 'application/x-perl' : 'perl', + 'text/x-sql' : 'sql', + 'text/xml' : 'xml', + 'application/docbook+xml' : 'xml', + 'application/xml' : 'xml' + }; + + // set base height + taBase.height(taBase.height()); + + // set basePath of ace + ace.config.set('basePath', cdn); + + // Base node of Ace editor + editorBase = $('
                  ').text(ta.val()).insertBefore(ta.hide()); + + // Editor flag + ta.data('ace', true); + + // Aceeditor instance + editor = ace.edit(id); + + // Ace editor configure + editor.$blockScrolling = Infinity; + editor.setOptions({ + theme: 'ace/theme/monokai', + fontSize: '14px', + wrap: true, + }); + ace.config.loadModule('ace/ext/modelist', function() { + // detect mode + mode = ace.require('ace/ext/modelist').getModeForPath('/' + self.file.name).name; + if (mode === 'text') { + if (mimeMode[self.file.mime]) { + mode = mimeMode[self.file.mime]; + } + } + // show MIME:mode in title bar + taBase.prev().children('.elfinder-dialog-title').append(' (' + self.file.mime + ' : ' + mode.split(/[\/\\]/).pop() + ')'); + editor.setOptions({ + mode: 'ace/mode/' + mode + }); + if (dfrd.state() === 'resolved') { + dialog.trigger('resize'); + } + }); + ace.config.loadModule('ace/ext/language_tools', function() { + ace.require('ace/ext/language_tools'); + editor.setOptions({ + enableBasicAutocompletion: true, + enableSnippets: true, + enableLiveAutocompletion: false + }); + }); + ace.config.loadModule('ace/ext/settings_menu', function() { + ace.require('ace/ext/settings_menu').init(editor); + }); + + // Short cuts + editor.commands.addCommand({ + name : "saveFile", + bindKey: { + win : 'Ctrl-s', + mac : 'Command-s' + }, + exec: function(editor) { + self.doSave(); + } + }); + editor.commands.addCommand({ + name : "closeEditor", + bindKey: { + win : 'Ctrl-w|Ctrl-q', + mac : 'Command-w|Command-q' + }, + exec: function(editor) { + self.doCancel(); + } + }); + + editor.resize(); + + // TextArea button and Setting button + $('
                  ').css('float', 'left') + .append( + $('').html(self.fm.i18n('TextArea')) + .button() + .on('click', function(){ + if (ta.data('ace')) { + ta.removeData('ace'); + editorBase.hide(); + ta.val(editor.session.getValue()).show().trigger('focus'); + $(this).text('AceEditor'); + } else { + ta.data('ace', true); + editorBase.show(); + editor.setValue(ta.hide().val(), -1); + editor.focus(); + $(this).html(self.fm.i18n('TextArea')); + } + }) + ) + .append( + $('') + .button({ + icons: { + primary: 'ui-icon-gear', + secondary: 'ui-icon-triangle-1-e' + }, + text: false + }) + .on('click', function(){ + editor.showSettingsMenu(); + $('#ace_settingsmenu') + .css('font-size', '80%') + .find('div[contains="setOptions"]').hide().end() + .parent().appendTo($('#elfinder')); + }) + ) + .prependTo(taBase.next()); + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: ace, + instance: editor, + opts: {} + }); + + //dialog.trigger('resize'); + dfrd.resolve(editor); + }; + + // check ace & start + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + self.fm.loadScript([ cdn+'/ace.js' ], function() { + self.confObj.loader.resolve(); + }, void 0, {obj: window, name: 'ace'}); + } + self.confObj.loader.done(start); + + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.destroy(); + }, + save : function(textarea, instance) { + instance && $(textarea).data('ace') && (textarea.value = instance.session.getValue()); + }, + focus : function(textarea, instance) { + instance && $(textarea).data('ace') && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + instance && instance.resize(); + } + }, + { + // CodeMirror + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE10 || !fm.options.cdns.codemirror) { + this.disabled = true; + } + }, + // `mimes` is not set for support everything kind of text file + info : { + id : 'codemirror', + name : 'CodeMirror', + iconImg : 'img/editor-icons.png 0 -176' + }, + load : function(textarea) { + var fm = this.fm, + cmUrl = fm.convAbsUrl(fm.options.cdns.codemirror), + dfrd = $.Deferred(), + self = this, + start = function(CodeMirror) { + var ta = $(textarea), + base = ta.parent(), + editor, editorBase, opts; + + // set base height + base.height(base.height()); + + // CodeMirror configure options + opts = { + lineNumbers: true, + lineWrapping: true, + extraKeys : { + 'Ctrl-S': function() { self.doSave(); }, + 'Ctrl-Q': function() { self.doCancel(); }, + 'Ctrl-W': function() { self.doCancel(); } + } + }; + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: CodeMirror, + instance: void(0), + opts: opts + }); + + // CodeMirror configure + editor = CodeMirror.fromTextArea(textarea, opts); + + // return editor instance + dfrd.resolve(editor); + + // Auto mode set + var info, m, mode, spec; + if (! info) { + info = CodeMirror.findModeByMIME(self.file.mime); + } + if (! info && (m = self.file.name.match(/.+\.([^.]+)$/))) { + info = CodeMirror.findModeByExtension(m[1]); + } + if (info) { + CodeMirror.modeURL = useRequire? 'codemirror/mode/%N/%N.min' : cmUrl + '/mode/%N/%N.min.js'; + mode = info.mode; + spec = info.mime; + editor.setOption('mode', spec); + CodeMirror.autoLoadMode(editor, mode); + // show MIME:mode in title bar + base.prev().children('.elfinder-dialog-title').append(' (' + spec + (mode != 'null'? ' : ' + mode : '') + ')'); + } + + // editor base node + editorBase = $(editor.getWrapperElement()).css({ + // fix CSS conflict to SimpleMDE + padding: 0, + border: 'none' + }); + ta.data('cm', true); + + // fit height to base + editorBase.height('100%'); + + // TextArea button and Setting button + $('
                  ').css('float', 'left') + .append( + $('').html(self.fm.i18n('TextArea')) + .button() + .on('click', function(){ + if (ta.data('cm')) { + ta.removeData('cm'); + editorBase.hide(); + ta.val(editor.getValue()).show().trigger('focus'); + $(this).text('CodeMirror'); + } else { + ta.data('cm', true); + editorBase.show(); + editor.setValue(ta.hide().val()); + editor.refresh(); + editor.focus(); + $(this).html(self.fm.i18n('TextArea')); + } + }) + ) + .prependTo(base.next()); + }; + // load script then start + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + if (useRequire) { + require.config({ + packages: [{ + name: 'codemirror', + location: cmUrl, + main: 'codemirror.min' + }], + map: { + 'codemirror': { + 'codemirror/lib/codemirror': 'codemirror' + } + } + }); + require([ + 'codemirror', + 'codemirror/addon/mode/loadmode.min', + 'codemirror/mode/meta.min' + ], function(CodeMirror) { + self.confObj.loader.resolve(CodeMirror); + }); + } else { + self.fm.loadScript([ + cmUrl + '/codemirror.min.js' + ], function() { + self.fm.loadScript([ + cmUrl + '/addon/mode/loadmode.min.js', + cmUrl + '/mode/meta.min.js' + ], function() { + self.confObj.loader.resolve(CodeMirror); + }); + }, {loadType: 'tag'}); + } + self.fm.loadCss(cmUrl + '/codemirror.css'); + } + self.confObj.loader.done(start); + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.toTextArea(); + }, + save : function(textarea, instance) { + instance && $(textarea).data('cm') && (textarea.value = instance.getValue()); + }, + focus : function(textarea, instance) { + instance && $(textarea).data('cm') && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + instance && instance.refresh(); + } + }, + { + // SimpleMDE + // called on initialization of elFinder cmd edit (this: this editor's config object) + setup : function(opts, fm) { + if (fm.UA.ltIE10 || !fm.options.cdns.simplemde) { + this.disabled = true; + } + }, + info : { + id : 'simplemde', + name : 'SimpleMDE', + iconImg : 'img/editor-icons.png 0 -80' + }, + exts : ['md'], + load : function(textarea) { + var self = this, + fm = this.fm, + base = $(textarea).parent(), + dfrd = $.Deferred(), + cdn = fm.options.cdns.simplemde, + start = function(SimpleMDE) { + var h = base.height(), + delta = base.outerHeight(true) - h + 14, + editor, editorBase, opts; + + // fit height function + textarea._setHeight = function(height) { + var h = height || base.height(), + ctrH = 0, + areaH; + base.children('.editor-toolbar,.editor-statusbar').each(function() { + ctrH += $(this).outerHeight(true); + }); + areaH = h - ctrH - delta; + editorBase.height(areaH); + editor.codemirror.refresh(); + return areaH; + }; + + // set base height + base.height(h); + + opts = { + element: textarea, + autofocus: true + }; + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: SimpleMDE, + instance: void(0), + opts: opts + }); + + // make editor + editor = new SimpleMDE(opts); + dfrd.resolve(editor); + + // editor base node + editorBase = $(editor.codemirror.getWrapperElement()); + + // fit height to base + editorBase.css('min-height', '50px') + .children('.CodeMirror-scroll').css('min-height', '50px'); + textarea._setHeight(h); + }; + + // check SimpleMDE & start + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + self.fm.loadCss(cdn+'/simplemde.min.css'); + if (useRequire) { + require([ + cdn+'/simplemde.min.js' + ], function(SimpleMDE) { + self.confObj.loader.resolve(SimpleMDE); + }); + } else { + self.fm.loadScript([cdn+'/simplemde.min.js'], function() { + self.confObj.loader.resolve(SimpleMDE); + }, {loadType: 'tag'}); + } + } + self.confObj.loader.done(start); + + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.toTextArea(); + instance = null; + }, + save : function(textarea, instance) { + instance && (textarea.value = instance.value()); + }, + focus : function(textarea, instance) { + instance && instance.codemirror.focus(); + }, + resize : function(textarea, instance, e, data) { + instance && textarea._setHeight(); + } + }, + { + // CKEditor for html file + info : { + id : 'ckeditor', + name : 'CKEditor', + iconImg : 'img/editor-icons.png 0 0' + }, + exts : ['htm', 'html', 'xhtml'], + setup : function(opts, fm) { + var confObj = this; + if (!fm.options.cdns.ckeditor) { + confObj.disabled = true; + } else { + confObj.ckeOpts = {}; + if (opts.extraOptions) { + confObj.ckeOpts = Object.assign({}, opts.extraOptions.ckeditor || {}); + if (opts.extraOptions.managerUrl) { + confObj.managerUrl = opts.extraOptions.managerUrl; + } + } + } + }, + load : function(textarea) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + init = function() { + var base = $(textarea).parent(), + dlg = base.closest('.elfinder-dialog'), + h = base.height(), + reg = /([&?]getfile=)[^&]+/, + loc = self.confObj.managerUrl || window.location.href.replace(/#.*$/, ''), + name = 'ckeditor', + opts; + + // make manager location + if (reg.test(loc)) { + loc = loc.replace(reg, '$1' + name); + } else { + loc += '?getfile=' + name; + } + // set base height + base.height(h); + + // CKEditor configure options + opts = { + startupFocus : true, + fullPage: true, + allowedContent: true, + filebrowserBrowseUrl : loc, + toolbarCanCollapse: true, + toolbarStartupExpanded: !fm.UA.Mobile, + removePlugins: 'resize', + extraPlugins: 'colorbutton,justify,docprops', + on: { + 'instanceReady' : function(e) { + var editor = e.editor; + editor.resize('100%', h); + // re-build on dom move + dlg.one('beforedommove.'+fm.namespace, function() { + editor.destroy(); + }).one('dommove.'+fm.namespace, function() { + self.load(textarea).done(function(editor) { + self.instance = editor; + }); + }); + // return editor instance + dfrd.resolve(e.editor); + } + } + }; + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: CKEDITOR, + instance: void(0), + opts: opts + }); + + // CKEditor configure + CKEDITOR.replace(textarea.id, Object.assign(opts, self.confObj.ckeOpts)); + CKEDITOR.on('dialogDefinition', function(e) { + var dlg = e.data.definition.dialog; + dlg.on('show', function(e) { + fm.getUI().append($('.cke_dialog_background_cover')).append(this.getElement().$); + }); + dlg.on('hide', function(e) { + $('body:first').append($('.cke_dialog_background_cover')).append(this.getElement().$); + }); + }); + }; + + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + window.CKEDITOR_BASEPATH = fm.options.cdns.ckeditor + '/'; + $.getScript(fm.options.cdns.ckeditor + '/ckeditor.js', function() { + self.confObj.loader.resolve(); + }); + } + self.confObj.loader.done(init); + return dfrd; + }, + close : function(textarea, instance) { + instance && instance.destroy(); + }, + save : function(textarea, instance) { + instance && (textarea.value = instance.getData()); + }, + focus : function(textarea, instance) { + instance && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + var self; + if (instance) { + if (instance.status === 'ready') { + instance.resize('100%', $(textarea).parent().height()); + } + } + } + }, + { + // CKEditor5 balloon mode for html file + info : { + id : 'ckeditor5', + name : 'CKEditor5', + iconImg : 'img/editor-icons.png 0 -16' + }, + exts : ['htm', 'html', 'xhtml'], + html : '
                  ', + setup : function(opts, fm) { + var confObj = this; + // check cdn and ES6 support + if (!fm.options.cdns.ckeditor5 || typeof window.Symbol !== 'function' || typeof Symbol() !== 'symbol') { + confObj.disabled = true; + } else { + confObj.ckeOpts = {}; + if (opts.extraOptions) { + // @deprecated option extraOptions.ckeditor5Mode + if (opts.extraOptions.ckeditor5Mode) { + confObj.ckeditor5Mode = opts.extraOptions.ckeditor5Mode; + } + confObj.ckeOpts = Object.assign({}, opts.extraOptions.ckeditor5 || {}); + if (confObj.ckeOpts.mode) { + confObj.ckeditor5Mode = confObj.ckeOpts.mode; + delete confObj.ckeOpts.mode; + } + if (opts.extraOptions.managerUrl) { + confObj.managerUrl = opts.extraOptions.managerUrl; + } + } + } + fm.bind('destroy', function() { + confObj.editor = null; + }); + }, + // Prepare on before show dialog + prepare : function(base, dialogOpts, file) { + $(base).height(base.editor.fm.getUI().height() - 100); + }, + init : function(id, file, data, fm) { + var m = data.match(/^([\s\S]*]*>)([\s\S]+)(<\/body>[\s\S]*)$/i), + header = '', + body = '', + footer =''; + this.css({ + width: '100%', + height: '100%', + 'box-sizing': 'border-box' + }); + if (m) { + header = m[1]; + body = m[2]; + footer = m[3]; + } else { + body = data; + } + this.data('data', { + header: header, + body: body, + footer: footer + }); + this._setupSelEncoding(data); + }, + load : function(editnode) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + mode = self.confObj.ckeditor5Mode || 'decoupled-document', + lang = (function() { + var l = fm.lang.toLowerCase().replace('_', '-'); + if (l.substr(0, 2) === 'zh' && l !== 'zh-cn') { + l = 'zh'; + } + return l; + })(), + init = function(cEditor) { + var base = $(editnode).parent(), + opts; + + // set base height + base.height(fm.getUI().height() - 100); + + // CKEditor5 configure options + opts = Object.assign({ + toolbar: ["heading", "|", "fontSize", "fontFamily", "|", "bold", "italic", "underline", "strikethrough", "highlight", "|", "alignment", "|", "numberedList", "bulletedList", "blockQuote", "indent", "outdent", "|", "ckfinder", "link", "imageUpload", "insertTable", "mediaEmbed", "|", "undo", "redo"], + language: lang + }, self.confObj.ckeOpts); + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: editnode, + editorObj: cEditor, + instance: void(0), + opts: opts + }); + + cEditor + .create(editnode, opts) + .then(function(editor) { + var ckf = editor.commands.get('ckfinder'), + fileRepo = editor.plugins.get('FileRepository'), + prevVars = {}, isImage, insertImages; + if (editor.ui.view.toolbar && (mode === 'classic' || mode === 'decoupled-document')) { + $(editnode).closest('.elfinder-dialog').children('.ui-widget-header').append($(editor.ui.view.toolbar.element).css({marginRight:'-1em',marginLeft:'-1em'})); + } + if (mode === 'classic') { + $(editnode).closest('.elfinder-edit-editor').css('overflow', 'auto'); + } + // Set up this elFinder instead of CKFinder + if (ckf) { + isImage = function(f) { + return f && f.mime.match(/^image\//i); + }; + insertImages = function(urls) { + var imgCmd = editor.commands.get('imageUpload'); + if (!imgCmd.isEnabled) { + var ntf = editor.plugins.get('Notification'), + i18 = editor.locale.t; + ntf.showWarning(i18('Could not insert image at the current position.'), { + title: i18('Inserting image failed'), + namespace: 'ckfinder' + }); + return; + } + editor.execute('imageInsert', { source: urls }); + }; + // Take over ckfinder execute() + ckf.execute = function() { + var dlg = base.closest('.elfinder-dialog'), + gf = fm.getCommand('getfile'), + rever = function() { + if (prevVars.hasVar) { + dlg.off('resize close', rever); + gf.callback = prevVars.callback; + gf.options.folders = prevVars.folders; + gf.options.multiple = prevVars.multi; + fm.commandMap.open = prevVars.open; + prevVars.hasVar = false; + } + }; + dlg.trigger('togleminimize').one('resize close', rever); + prevVars.callback = gf.callback; + prevVars.folders = gf.options.folders; + prevVars.multi = gf.options.multiple; + prevVars.open = fm.commandMap.open; + prevVars.hasVar = true; + gf.callback = function(files) { + var imgs = []; + if (files.length === 1 && files[0].mime === 'directory') { + fm.one('open', function() { + fm.commandMap.open = 'getfile'; + }).getCommand('open').exec(files[0].hash); + return; + } + fm.getUI('cwd').trigger('unselectall'); + $.each(files, function(i, f) { + if (isImage(f)) { + imgs.push(fm.convAbsUrl(f.url)); + } else { + editor.execute('link', fm.convAbsUrl(f.url)); + } + }); + if (imgs.length) { + insertImages(imgs); + } + dlg.trigger('togleminimize'); + }; + gf.options.folders = true; + gf.options.multiple = true; + fm.commandMap.open = 'getfile'; + fm.toast({ + mode: 'info', + msg: fm.i18n('dblclickToSelect') + }); + }; + } + // Set up image uploader + fileRepo.createUploadAdapter = function(loader) { + return new uploder(loader); + }; + editor.setData($(editnode).data('data').body); + // move .ck-body to elFinder node for fullscreen mode + fm.getUI().append($('body > div.ck-body')); + $('div.ck-balloon-panel').css({ + 'z-index': fm.getMaximizeCss().zIndex + 1 + }); + dfrd.resolve(editor); + /*fm.log({ + defaultConfig: cEditor.defaultConfig, + plugins: cEditor.builtinPlugins.map(function(p) { return p.pluginName; }), + toolbars: Array.from(editor.ui.componentFactory.names()) + });*/ + }) + ['catch'](function(error) { // ['cache'] instead .cache for fix error on ie8 + fm.error(error); + }); + }, + uploder = function(loader) { + var upload = function(file, resolve, reject) { + fm.exec('upload', {files: [file]}, void(0), fm.cwd().hash) + .done(function(data){ + if (data.added && data.added.length) { + fm.url(data.added[0].hash, { async: true }).done(function(url) { + resolve({ + 'default': fm.convAbsUrl(url) + }); + }).fail(function() { + reject('errFileNotFound'); + }); + } else { + reject(fm.i18n(data.error? data.error : 'errUpload')); + } + }) + .fail(function(err) { + var error = fm.parseError(err); + reject(fm.i18n(error? (error === 'userabort'? 'errAbort' : error) : 'errUploadNoFiles')); + }) + .progress(function(data) { + loader.uploadTotal = data.total; + loader.uploaded = data.progress; + }); + }; + this.upload = function() { + return new Promise(function(resolve, reject) { + if (loader.file instanceof Promise || (loader.file && typeof loader.file.then === 'function')) { + loader.file.then(function(file) { + upload(file, resolve, reject); + }); + } else { + upload(loader.file, resolve, reject); + } + }); + }; + this.abort = function() { + fm.getUI().trigger('uploadabort'); + }; + }, loader; + + if (!self.confObj.editor) { + loader = $.Deferred(); + self.fm.loadScript([ + fm.options.cdns.ckeditor5 + '/' + mode + '/ckeditor.js' + ], function(editor) { + if (!editor) { + editor = window.BalloonEditor || window.InlineEditor || window.ClassicEditor || window.DecoupledEditor; + } + if (fm.lang !== 'en') { + self.fm.loadScript([ + fm.options.cdns.ckeditor5 + '/' + mode + '/translations/' + lang + '.js' + ], function(obj) { + loader.resolve(editor); + }, { + tryRequire: true, + loadType: 'tag', + error: function(obj) { + lang = 'en'; + loader.resolve(editor); + } + }); + } else { + loader.resolve(editor); + } + }, { + tryRequire: true, + loadType: 'tag' + }); + loader.done(function(editor) { + self.confObj.editor = editor; + init(editor); + }); + } else { + init(self.confObj.editor); + } + return dfrd; + }, + getContent : function() { + var data = $(this).data('data'); + return data.header + data.body + data.footer; + }, + close : function(editnode, instance) { + instance && instance.destroy(); + }, + save : function(editnode, instance) { + var elm = $(editnode), + data = elm.data('data'); + if (instance) { + data.body = instance.getData(); + elm.data('data', data); + } + }, + focus : function(editnode, instance) { + $(editnode).trigger('focus'); + } + }, + { + // TinyMCE for html file + info : { + id : 'tinymce', + name : 'TinyMCE', + iconImg : 'img/editor-icons.png 0 -64' + }, + exts : ['htm', 'html', 'xhtml'], + setup : function(opts, fm) { + var confObj = this; + if (!fm.options.cdns.tinymce) { + confObj.disabled = true; + } else { + confObj.mceOpts = {}; + if (opts.extraOptions) { + confObj.uploadOpts = Object.assign({}, opts.extraOptions.uploadOpts || {}); + confObj.mceOpts = Object.assign({}, opts.extraOptions.tinymce || {}); + } else { + confObj.uploadOpts = {}; + } + } + }, + load : function(textarea) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + init = function() { + var base = $(textarea).show().parent(), + dlg = base.closest('.elfinder-dialog'), + h = base.height(), + delta = base.outerHeight(true) - h, + // hide MCE dialog and modal block + hideMceDlg = function() { + var mceW; + if (tinymce.activeEditor.windowManager.windows) { + mceW = tinymce.activeEditor.windowManager.windows[0]; + mceDlg = $(mceW? mceW.getEl() : void(0)).hide(); + mceCv = $('#mce-modal-block').hide(); + } else { + mceDlg = $('.tox-dialog-wrap').hide(); + } + }, + // Show MCE dialog and modal block + showMceDlg = function() { + mceCv && mceCv.show(); + mceDlg && mceDlg.show(); + }, + tVer = tinymce.majorVersion, + opts, mceDlg, mceCv; + + // set base height + base.height(h); + // fit height function + textarea._setHeight = function(height) { + if (tVer < 5) { + var base = $(this).parent(), + h = height || base.innerHeight(), + ctrH = 0, + areaH; + base.find('.mce-container-body:first').children('.mce-top-part,.mce-statusbar').each(function() { + ctrH += $(this).outerHeight(true); + }); + areaH = h - ctrH - delta; + base.find('.mce-edit-area iframe:first').height(areaH); + } + }; + + // TinyMCE configure options + opts = { + selector: '#' + textarea.id, + resize: false, + plugins: 'preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help', + toolbar: 'formatselect | bold italic strikethrough forecolor backcolor | link image media | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat', + image_advtab: true, + init_instance_callback : function(editor) { + // fit height on init + textarea._setHeight(h); + // re-build on dom move + dlg.one('beforedommove.'+fm.namespace, function() { + tinymce.execCommand('mceRemoveEditor', false, textarea.id); + }).one('dommove.'+fm.namespace, function() { + self.load(textarea).done(function(editor) { + self.instance = editor; + }); + }); + // return editor instance + dfrd.resolve(editor); + }, + file_picker_callback : function (callback, value, meta) { + var gf = fm.getCommand('getfile'), + revar = function() { + if (prevVars.hasVar) { + gf.callback = prevVars.callback; + gf.options.folders = prevVars.folders; + gf.options.multiple = prevVars.multi; + fm.commandMap.open = prevVars.open; + prevVars.hasVar = false; + } + dlg.off('resize close', revar); + showMceDlg(); + }, + prevVars = {}; + prevVars.callback = gf.callback; + prevVars.folders = gf.options.folders; + prevVars.multi = gf.options.multiple; + prevVars.open = fm.commandMap.open; + prevVars.hasVar = true; + gf.callback = function(file) { + var url, info; + + if (file.mime === 'directory') { + fm.one('open', function() { + fm.commandMap.open = 'getfile'; + }).getCommand('open').exec(file.hash); + return; + } + + // URL normalization + url = fm.convAbsUrl(file.url); + + // Make file info + info = file.name + ' (' + fm.formatSize(file.size) + ')'; + + // Provide file and text for the link dialog + if (meta.filetype == 'file') { + callback(url, {text: info, title: info}); + } + + // Provide image and alt text for the image dialog + if (meta.filetype == 'image') { + callback(url, {alt: info}); + } + + // Provide alternative source and posted for the media dialog + if (meta.filetype == 'media') { + callback(url); + } + dlg.trigger('togleminimize'); + }; + gf.options.folders = true; + gf.options.multiple = false; + fm.commandMap.open = 'getfile'; + + hideMceDlg(); + dlg.trigger('togleminimize').one('resize close', revar); + fm.toast({ + mode: 'info', + msg: fm.i18n('dblclickToSelect') + }); + + return false; + }, + images_upload_handler : function (blobInfo, success, failure) { + var file = blobInfo.blob(), + err = function(e) { + var dlg = e.data.dialog || {}; + if (dlg.hasClass('elfinder-dialog-error') || dlg.hasClass('elfinder-confirm-upload')) { + hideMceDlg(); + dlg.trigger('togleminimize').one('resize close', revert); + fm.unbind('dialogopened', err); + } + }, + revert = function() { + dlg.off('resize close', revert); + showMceDlg(); + }, + clipdata = true; + + // check file object + if (file.name) { + // file blob of client side file object + clipdata = void(0); + } + fm.bind('dialogopened', err).exec('upload', Object.assign({ + files: [file], + clipdata: clipdata // to get unique name on connector + }, self.confObj.uploadOpts), void(0), fm.cwd().hash).done(function(data) { + if (data.added && data.added.length) { + fm.url(data.added[0].hash, { async: true }).done(function(url) { + showMceDlg(); + success(fm.convAbsUrl(url)); + }).fail(function() { + failure(fm.i18n('errFileNotFound')); + }); + } else { + failure(fm.i18n(data.error? data.error : 'errUpload')); + } + }).fail(function(err) { + var error = fm.parseError(err); + if (error) { + if (error === 'errUnknownCmd') { + error = 'errPerm'; + } else if (error === 'userabort') { + error = 'errAbort'; + } + } + failure(fm.i18n(error? error : 'errUploadNoFiles')); + }); + } + }; + + // TinyMCE 5 supports "height: 100%" + if (tVer >= 5) { + opts.height = '100%'; + } + + // trigger event 'editEditorPrepare' + self.trigger('Prepare', { + node: textarea, + editorObj: tinymce, + instance: void(0), + opts: opts + }); + + // TinyMCE configure + tinymce.init(Object.assign(opts, self.confObj.mceOpts)); + }; + + if (!self.confObj.loader) { + self.confObj.loader = $.Deferred(); + self.fm.loadScript([fm.options.cdns.tinymce + (fm.options.cdns.tinymce.match(/\.js/)? '' : '/tinymce.min.js')], function() { + self.confObj.loader.resolve(); + }, { + loadType: 'tag' + }); + } + self.confObj.loader.done(init); + return dfrd; + }, + close : function(textarea, instance) { + instance && tinymce.execCommand('mceRemoveEditor', false, textarea.id); + }, + save : function(textarea, instance) { + instance && instance.save(); + }, + focus : function(textarea, instance) { + instance && instance.focus(); + }, + resize : function(textarea, instance, e, data) { + // fit height to base node on dialog resize + instance && textarea._setHeight(); + } + }, + { + info : { + id : 'zohoeditor', + name : 'Zoho Editor', + iconImg : 'img/editor-icons.png 0 -32', + cmdCheck : 'ZohoOffice', + preventGet: true, + hideButtons: true, + syncInterval : 15000, + canMakeEmpty: true, + integrate: { + title: 'Zoho Office API', + link: 'https://www.zoho.com/officeapi/' + } + }, + mimes : [ + 'application/msword', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + //'application/pdf', + 'application/vnd.oasis.opendocument.text', + 'application/rtf', + 'text/html', + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.sun.xml.calc', + 'text/csv', + 'text/tab-separated-values', + 'application/vnd.ms-powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.sun.xml.impress' + ], + html : '', + // setup on elFinder bootup + setup : function(opts, fm) { + if (fm.UA.Mobile || fm.UA.ltIE8) { + this.disabled = true; + } + }, + // Prepare on before show dialog + prepare : function(base, dialogOpts, file) { + var elfNode = base.editor.fm.getUI(); + $(base).height(elfNode.height()); + dialogOpts.width = Math.max(dialogOpts.width || 0, elfNode.width() * 0.8); + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, dum, fm) { + var ta = this, + ifm = $(this).hide(), + uiToast = fm.getUI('toast'), + spnr = $('
                  ') + .html('' + fm.i18n('nowLoading') + '') + .appendTo(ifm.parent()), + cdata = function() { + var data = ''; + $.each(fm.customData, function(key, val) { + data += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(val); + }); + return data; + }; + + $(ta).data('xhr', fm.request({ + data: { + cmd: 'editor', + name: ta.editor.confObj.info.cmdCheck, + method: 'init', + 'args[target]': file.hash, + 'args[lang]' : fm.lang, + 'args[cdata]' : cdata() + }, + preventDefault : true + }).done(function(data) { + var opts; + if (data.zohourl) { + opts = { + css: { + height: '100%' + } + }; + // trigger event 'editEditorPrepare' + ta.editor.trigger('Prepare', { + node: ta, + editorObj: void(0), + instance: ifm, + opts: opts + }); + + ifm.attr('src', data.zohourl).show().css(opts.css); + if (data.warning) { + uiToast.appendTo(ta.closest('.ui-dialog')); + fm.toast({ + msg: fm.i18n(data.warning), + mode: 'warning', + timeOut: 0, + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + }, + button: { + text: 'btnYes' + } + }); + } + } else { + data.error && fm.error(data.error); + ta.elfinderdialog('destroy'); + } + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }).always(function() { + spnr.remove(); + })); + }, + load : function() {}, + getContent : function() {}, + save : function() {}, + // Before dialog close + beforeclose : iframeClose, + // On dialog closed + close : function(ta) { + var fm = this.fm, + xhr = $(ta).data('xhr'); + if (xhr.state() === 'pending') { + xhr.reject(); + } + } + }, + { + // Zip Archive with FlySystem + info : { + id : 'ziparchive', + name : 'btnMount', + iconImg : 'img/toolbar.png 0 -416', + cmdCheck : 'ZipArchive', + edit : function(file, editor) { + var fm = this, + dfrd = $.Deferred(); + fm.request({ + data:{ + cmd: 'netmount', + protocol: 'ziparchive', + host: file.hash, + path: file.phash + }, + preventFail: true, + notify : {type : 'netmount', cnt : 1, hideCnt : true} + }).done(function(data) { + var pdir; + if (data.added && data.added.length) { + if (data.added[0].phash) { + if (pdir = fm.file(data.added[0].phash)) { + if (! pdir.dirs) { + pdir.dirs = 1; + fm.change({ changed: [ pdir ] }); + } + } + } + fm.one('netmountdone', function() { + fm.exec('open', data.added[0].hash); + fm.one('opendone', function() { + data.toast && fm.toast(data.toast); + }); + }); + } + dfrd.resolve(); + }) + .fail(function(error) { + dfrd.reject(error); + }); + return dfrd; + } + }, + mimes : ['application/zip'], + load : function() {}, + save : function(){} + }, + { + // Simple Text (basic textarea editor) + info : { + id : 'textarea', + name : 'TextArea', + useTextAreaEvent : true + }, + load : function(textarea) { + // trigger event 'editEditorPrepare' + this.trigger('Prepare', { + node: textarea, + editorObj: void(0), + instance: void(0), + opts: {} + }); + textarea.setSelectionRange && textarea.setSelectionRange(0, 0); + $(textarea).trigger('focus').show(); + }, + save : function(){} + }, + { + // File converter with online-convert.com + info : { + id : 'onlineconvert', + name : 'Online Convert', + iconImg : 'img/editor-icons.png 0 -144', + cmdCheck : 'OnlineConvert', + preventGet: true, + hideButtons: true, + single: true, + converter: true, + canMakeEmpty: false, + integrate: { + title: 'ONLINE-CONVERT.COM', + link: 'https://online-convert.com' + } + }, + mimes : ['*'], + html : '
                  ', + // setup on elFinder bootup + setup : function(opts, fm) { + var mOpts = opts.extraOptions.onlineConvert || {maxSize:100,showLink:true}; + if (mOpts.maxSize) { + this.info.maxSize = mOpts.maxSize * 1048576; + } + this.set = Object.assign({ + url : 'https://%s.online-convert.com%s?external_url=', + conv : { + Archive: {'7Z':{}, 'BZ2':{ext:'bz'}, 'GZ':{}, 'ZIP':{}}, + Audio: {'MP3':{}, 'OGG':{ext:'oga'}, 'WAV':{}, 'WMA':{}, 'AAC':{}, 'AIFF':{ext:'aif'}, 'FLAC':{}, 'M4A':{}, 'MMF':{}, 'OPUS':{ext:'oga'}}, + Document: {'DOC':{}, 'DOCX':{}, 'HTML':{}, 'ODT':{}, 'PDF':{}, 'PPT':{}, 'PPTX':{}, 'RTF':{}, 'SWF':{}, 'TXT':{}}, + eBook: {'AZW3':{ext:'azw'}, 'ePub':{}, 'FB2':{ext:'xml'}, 'LIT':{}, 'LRF':{}, 'MOBI':{}, 'PDB':{}, 'PDF':{},'PDF-eBook':{ext:'pdf'}, 'TCR':{}}, + Hash: {'Adler32':{}, 'Apache-htpasswd':{}, 'Blowfish':{}, 'CRC32':{}, 'CRC32B':{}, 'Gost':{}, 'Haval128':{},'MD4':{}, 'MD5':{}, 'RIPEMD128':{}, 'RIPEMD160':{}, 'SHA1':{}, 'SHA256':{}, 'SHA384':{}, 'SHA512':{}, 'Snefru':{}, 'Std-DES':{}, 'Tiger128':{}, 'Tiger128-calculator':{}, 'Tiger128-converter':{}, 'Tiger160':{}, 'Tiger192':{}, 'Whirlpool':{}}, + Image: {'BMP':{}, 'EPS':{ext:'ai'}, 'GIF':{}, 'EXR':{}, 'ICO':{}, 'JPG':{}, 'PNG':{}, 'SVG':{}, 'TGA':{}, 'TIFF':{ext:'tif'}, 'WBMP':{}, 'WebP':{}}, + Video: {'3G2':{}, '3GP':{}, 'AVI':{}, 'FLV':{}, 'HLS':{ext:'m3u8'}, 'MKV':{}, 'MOV':{}, 'MP4':{}, 'MPEG-1':{ext:'mpeg'}, 'MPEG-2':{ext:'mpeg'}, 'OGG':{ext:'ogv'}, 'OGV':{}, 'WebM':{}, 'WMV':{}, 'Android':{link:'/convert-video-for-%s',ext:'mp4'}, 'Blackberry':{link:'/convert-video-for-%s',ext:'mp4'}, 'DPG':{link:'/convert-video-for-%s',ext:'avi'}, 'iPad':{link:'/convert-video-for-%s',ext:'mp4'}, 'iPhone':{link:'/convert-video-for-%s',ext:'mp4'}, 'iPod':{link:'/convert-video-for-%s',ext:'mp4'}, 'Nintendo-3DS':{link:'/convert-video-for-%s',ext:'avi'}, 'Nintendo-DS':{link:'/convert-video-for-%s',ext:'avi'}, 'PS3':{link:'/convert-video-for-%s',ext:'mp4'}, 'Wii':{link:'/convert-video-for-%s',ext:'avi'}, 'Xbox':{link:'/convert-video-for-%s',ext:'wmv'}} + }, + catExts : { + Hash: 'txt' + }, + link : '', + useTabs : ($.fn.tabs && !fm.UA.iOS)? true : false // Can't work on iOS, I don't know why. + }, mOpts); + }, + // Prepare on before show dialog + prepare : function(base, dialogOpts, file) { + var elfNode = base.editor.fm.getUI(); + $(base).height(elfNode.height()); + dialogOpts.width = Math.max(dialogOpts.width || 0, elfNode.width() * 0.8); + }, + // Initialization of editing node (this: this editors HTML node) + init : function(id, file, dum, fm) { + var ta = this, + confObj = ta.editor.confObj, + set = confObj.set, + uiToast = fm.getUI('toast'), + idxs = {}, + allowZip = fm.uploadMimeCheck('application/zip', file.phash), + selfUrl = $('base').length? document.location.href.replace(/#.*$/, '') : '', + getExt = function(cat, con) { + var c; + if (set.catExts[cat]) { + return set.catExts[cat]; + } + if (set.conv[cat] && (c = set.conv[cat][con])) { + return (c.ext || con).toLowerCase(); + } + return con.toLowerCase(); + }, + setOptions = function(cat, done) { + var type, dfdInit, dfd; + if (typeof confObj.api === 'undefined') { + dfdInit = fm.request({ + data: { + cmd: 'editor', + name: 'OnlineConvert', + method: 'init' + }, + preventDefault : true + }); + } else { + dfdInit = $.Deferred().resolve({api: confObj.api}); + } + cat = cat.toLowerCase(); + dfdInit.done(function(data) { + confObj.api = data.api; + if (confObj.api) { + if (cat) { + type = '?category=' + cat; + } else { + type = ''; + cat = 'all'; + } + if (!confObj.conversions) { + confObj.conversions = {}; + } + if (!confObj.conversions[cat]) { + dfd = $.getJSON('https://api2.online-convert.com/conversions' + type); + } else { + dfd = $.Deferred().resolve(confObj.conversions[cat]); + } + dfd.done(function(d) { + confObj.conversions[cat] = d; + $.each(d, function(i, o) { + btns[set.useTabs? 'children' : 'find']('.onlineconvert-category-' + o.category).children('.onlineconvert-' + o.target).trigger('makeoption', o); + }); + done && done(); + }); + } + }); + }, + btns = (function() { + var btns = $('
                  ').on('click', 'button', function() { + var b = $(this), + opts = b.data('opts') || null, + cat = b.closest('.onlineconvert-category').data('cname'), + con = b.data('conv'); + if (confObj.api === true) { + api({ + category: cat, + convert: con, + options: opts + }); + } + }).on('change', function(e) { + var t = $(e.target), + p = t.parent(), + b = t.closest('.elfinder-edit-onlineconvert-button').children('button:first'), + o = b.data('opts') || {}, + v = p.data('type') === 'boolean'? t.is(':checked') : t.val(); + e.stopPropagation(); + if (v) { + if (p.data('type') === 'integer') { + v = parseInt(v); + } + if (p.data('pattern')) { + var reg = new RegExp(p.data('pattern')); + if (!reg.test(v)) { + requestAnimationFrame(function() { + fm.error('"' + fm.escape(v) + '" is not match to "/' + fm.escape(p.data('pattern')) + '/"'); + }); + v = null; + } + } + } + if (v) { + o[t.parent().data('optkey')] = v; + } else { + delete o[p.data('optkey')]; + } + b.data('opts', o); + }), + ul = $('
                    '), + oform = function(n, o) { + var f = $('

                    ').data('optkey', n).data('type', o.type), + checked = '', + disabled = '', + nozip = false, + opts, btn, elm; + if (o.description) { + f.attr('title', fm.i18n(o.description)); + } + if (o.pattern) { + f.data('pattern', o.pattern); + } + f.append($('').text(fm.i18n(n) + ' : ')); + if (o.type === 'boolean') { + if (o['default'] || (nozip = (n === 'allow_multiple_outputs' && !allowZip))) { + checked = ' checked'; + if (nozip) { + disabled = ' disabled'; + } + btn = this.children('button:first'); + opts = btn.data('opts') || {}; + opts[n] = true; + btn.data('opts', opts); + } + f.append($('')); + } else if (o['enum']){ + elm = $('').append($('').text('Select...')); + $.each(o['enum'], function(i, v) { + elm.append($('').text(v)); + }); + f.append(elm); + } else { + f.append($('')); + } + return f; + }, + makeOption = function(o) { + var elm = this, + b = $('').on('click', function() { + f.toggle(); + }), + f = $('
                    ').hide(); + if (o.options) { + $.each(o.options, function(k, v) { + k !== 'download_password' && f.append(oform.call(elm, k, v)); + }); + } + elm.append(b, f); + }, + ts = (+new Date()), + i = 0; + + if (!confObj.ext2mime) { + confObj.ext2mime = Object.assign(fm.arrayFlip(fm.mimeTypes), ext2mime); + } + $.each(set.conv, function(t, c) { + var cname = t.toLowerCase(), + id = 'elfinder-edit-onlineconvert-' + cname + ts, + type = $('
                    ').data('cname', t), + cext; + $.each(c, function(n, o) { + var nl = n.toLowerCase(), + ext = getExt(t, n); + if (!confObj.ext2mime[ext]) { + if (cname === 'audio' || cname === 'image' || cname === 'video') { + confObj.ext2mime[ext] = cname + '/x-' + nl; + } else { + confObj.ext2mime[ext] = 'application/octet-stream'; + } + } + if (fm.uploadMimeCheck(confObj.ext2mime[ext], file.phash)) { + type.append($('
                    ').on('makeoption', function(e, data) { + var elm = $(this); + if (!elm.children('.elfinder-button-icon-preference').length) { + makeOption.call(elm, data); + } + }).append($('').text(n).data('conv', n))); + } + }); + if (type.children().length) { + ul.append($('
                  • ').append($('').attr('href', selfUrl + '#' + id).text(t))); + btns.append(type); + idxs[cname] = i++; + } + }); + if (set.useTabs) { + btns.prepend(ul).tabs({ + beforeActivate: function(e, ui) { + setOptions(ui.newPanel.data('cname')); + } + }); + } else { + $.each(set.conv, function(t) { + var tl = t.toLowerCase(); + btns.append($('
                    ').append($('').text(t)).append(btns.children('.onlineconvert-category-' + tl))); + }); + } + return btns; + })(), + select = $(this) + .append( + btns, + (set.showLink? $(set.link) : null) + ), + spnr = $('
                    ') + .hide() + .html('' + fm.i18n('nowLoading') + '') + .appendTo(select.parent()), + prog = $('
                    ').appendTo(spnr), + _url = null, + url = function() { + var onetime; + if (_url) { + return $.Deferred().resolve(_url); + } else { + spnr.show(); + return fm.forExternalUrl(file.hash, { progressBar: prog }).done(function(url) { + _url = url; + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }).always(function() { + spnr.hide(); + }); + } + }, + api = function(opts) { + $(ta).data('dfrd', url().done(function(url) { + select.fadeOut(); + setStatus({info: 'Start conversion request.'}); + fm.request({ + data: { + cmd: 'editor', + name: 'OnlineConvert', + method: 'api', + 'args[category]' : opts.category.toLowerCase(), + 'args[convert]' : opts.convert.toLowerCase(), + 'args[options]' : JSON.stringify(opts.options), + 'args[source]' : fm.convAbsUrl(url), + 'args[filename]' : fm.splitFileExtention(file.name)[0] + '.' + getExt(opts.category, opts.convert), + 'args[mime]' : file.mime + }, + preventDefault : true + }).done(function(data) { + checkRes(data.apires, opts.category, opts.convert); + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }); + })); + }, + checkRes = function(res, cat, con) { + var status, err = []; + if (res && res.id) { + status = res.status; + if (status.code === 'failed') { + spnr.hide(); + if (res.errors && res.errors.length) { + $.each(res.errors, function(i, o) { + o.message && err.push(o.message); + }); + } + fm.error(err.length? err : status.info); + select.fadeIn(); + } else if (status.code === 'completed') { + upload(res); + } else { + setStatus(status); + setTimeout(function() { + polling(res.id); + }, 1000); + } + } else { + uiToast.appendTo(ta.closest('.ui-dialog')); + if (res.message) { + fm.toast({ + msg: fm.i18n(res.message), + mode: 'error', + timeOut: 5000, + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + } + }); + } + fm.toast({ + msg: fm.i18n('editorConvNoApi'), + mode: 'error', + timeOut: 3000, + onHidden: function() { + uiToast.children().length === 1 && uiToast.appendTo(fm.getUI()); + } + }); + spnr.hide(); + select.show(); + } + }, + setStatus = function(status) { + spnr.show().children('.elfinder-spinner-text').text(status.info); + }, + polling = function(jobid) { + fm.request({ + data: { + cmd: 'editor', + name: 'OnlineConvert', + method: 'api', + 'args[jobid]': jobid + }, + preventDefault : true + }).done(function(data) { + checkRes(data.apires); + }).fail(function(error) { + error && fm.error(error); + ta.elfinderdialog('destroy'); + }); + }, + upload = function(res) { + var output = res.output, + id = res.id, + url = ''; + spnr.hide(); + if (output && output.length) { + ta.elfinderdialog('destroy'); + $.each(output, function(i, o) { + if (o.uri) { + url += o.uri + '\n'; + } + }); + fm.upload({ + target: file.phash, + files: [url], + type: 'text', + extraData: { + contentSaveId: 'OnlineConvert-' + res.id + } + }); + } + }, + mode = 'document', + cl, m; + select.parent().css({overflow: 'auto'}).addClass('overflow-scrolling-touch'); + if (m = file.mime.match(/^(audio|image|video)/)) { + mode = m[1]; + } + if (set.useTabs) { + if (idxs[mode]) { + btns.tabs('option', 'active', idxs[mode]); + } + } else { + cl = Object.keys(set.conv).length; + $.each(set.conv, function(t) { + if (t.toLowerCase() === mode) { + setOptions(t, function() { + $.each(set.conv, function(t0) { + t0.toLowerCase() !== mode && setOptions(t0); + }); + }); + return false; + } + cl--; + }); + if (!cl) { + $.each(set.conv, function(t) { + setOptions(t); + }); + } + select.parent().scrollTop(btns.children('.onlineconvert-fieldset-' + mode).offset().top); + } + }, + load : function() {}, + getContent : function() {}, + save : function() {}, + // On dialog closed + close : function(ta) { + var fm = this.fm, + dfrd = $(ta).data('dfrd'); + if (dfrd && dfrd.state() === 'pending') { + dfrd.reject(); + } + } + } + ]; +}, window.elFinder)); diff --git a/lib/redactor/elfinder/js/extras/editors.default.min.js b/lib/redactor/elfinder/js/extras/editors.default.min.js new file mode 100644 index 0000000..b8bc913 --- /dev/null +++ b/lib/redactor/elfinder/js/extras/editors.default.min.js @@ -0,0 +1,2 @@ +!function(e,t){if("function"==typeof define&&define.amd)define(["elfinder"],e);else if(t){var i=t.prototype._options.commandsOptions.edit.editors;t.prototype._options.commandsOptions.edit.editors=i.concat(e(t))}}(function(e){"use strict";var t,i=window.location.search.match(/getfile=([a-z]+)/),n=e.prototype.hasRequire,o={bmp:"image/x-ms-bmp",dng:"image/x-adobe-dng",gif:"image/gif",jpeg:"image/jpeg",jpg:"image/jpeg",pdf:"application/pdf",png:"image/png",ppm:"image/x-portable-pixmap",psd:"image/vnd.adobe.photoshop",pxd:"image/x-pixlr-data",svg:"image/svg+xml",tiff:"image/tiff",webp:"image/webp",xcf:"image/x-xcf",sketch:"application/x-sketch",ico:"image/x-icon",dds:"image/vnd-ms.dds",emf:"application/x-msmetafile"},a=function(e,i,n){t||(t=i.arrayFlip(o));var a=t[e]||i.mimeTypes[e];return n?"jpg"===a&&(a="jpeg"):"jpeg"===a&&(a="jpg"),a},r=function(e,t){var i=$.Deferred();try{var n=document.createElement("canvas"),o=n.getContext("2d"),a=new Image,r=function(){var e,o,a=n.toDataURL(t);e=(o=a.match(/^data:([a-z0-9]+\/[a-z0-9.+-]+)/i))?o[1]:"",e.toLowerCase()===t.toLowerCase()?i.resolve(n.toDataURL(t),n):i.reject()};return a.src=e,$(a).on("load",function(){try{n.width=a.width,n.height=a.height,o.drawImage(a,0,0),r()}catch(e){i.reject()}}).on("error",function(){i.reject()}),i}catch(s){return i.reject()}},s=function(e,t,i,n){var o,r=$(this).children("img:first").data("ext",a(t.mime,n)),s=$('
                    ').html(''+n.i18n("ntfloadimg")+'').hide().appendTo(this),d=function(){r.attr("id",e+"-img").attr("src",o||i).css({height:"","max-width":"100%","max-height":"100%",cursor:"pointer"}).data("loading",function(e){var t=r.closest(".elfinder-dialog").find("button,.elfinder-titlebar-button");return t.prop("disabled",!e)[e?"removeClass":"addClass"]("ui-state-disabled"),r.css("opacity",e?"":"0.3"),s[e?"hide":"show"](),r})};i.match(/^data:/)?d():n.openUrl(t.hash,!1,function(e){o=e,r.attr("_src",i),d()})},d=function(e,t){var i,n,o,a=e.attr("style");try{e.attr("style",""),i=e.get(0),n=document.createElement("canvas"),n.width=i.width,n.height=i.height,e.attr("style",a),n.getContext("2d").drawImage(i,0,0),o=n.toDataURL(t)}catch(r){o=e.attr("src")}return o},c=function(e){var t,i=$(e),n=$.Deferred().always(function(){i.off("load",r)}),o="about:blank",a=function(){t=setTimeout(function(){var e;try{e=base.contentWindow.location.href}catch(t){e=null}e===o?n.resolve():--s>0?a():n.reject()},500)},r=function(){t&&clearTimeout(t),n.resolve()},s=20;return i.one("load",r),e.src=o,a(),n};return i&&(i=i[1],"ckeditor"===i&&(e.prototype._options.getFileCallback=function(e,t){window.opener.CKEDITOR.tools.callFunction(function(){var e=new RegExp("(?:[?&]|&)CKEditorFuncNum=([^&]+)","i"),t=window.location.search.match(e);return t&&t.length>1?t[1]:""}(),t.convAbsUrl(e.url)),t.destroy(),window.close()})),[{info:{id:"tuiimgedit",name:"TUI Image Editor",iconImg:"img/editor-icons.png 0 -48",dataScheme:!0,schemeContent:!0,openMaximized:!0,canMakeEmpty:!1,integrate:{title:"TOAST UI Image Editor",link:"http://ui.toast.com/tui-image-editor/"}},mimes:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp"],html:'
                    ',setup:function(e,t){t.UA.ltIE8||t.UA.Mobile?this.disabled=!0:(this.opts=Object.assign({version:"v3.15.3"},e.extraOptions.tuiImgEditOpts||{},{iconsPath:t.baseUrl+"img/tui-",theme:{}}),t.isSameOrigin(this.opts.iconsPath)||(this.disabled=!0,t.debug("warning","Setting `commandOptions.edit.extraOptions.tuiImgEditOpts.iconsPath` MUST follow the same origin policy.")))},init:function(e,t,i,n){this.data("url",i)},load:function(e){var t,i=this,n=this.fm,o=$.Deferred(),a=n.options.cdns,r=i.confObj.opts.version,s=function(t){var a,r,s,d,c,l=$(e),p=l.parent(),m=i.confObj.opts,f=(m.iconsPath,$('
                    ').appendTo(p)),u=[$('
                    ').appendTo(f),$('
                    ').appendTo(f)],g=new t(e,{includeUI:{loadImage:{path:l.data("url"),name:i.file.name},theme:m.theme,initMenu:"filter",menuBarPosition:"bottom"},cssMaxWidth:Math.max(300,p.width()),cssMaxHeight:Math.max(200,p.height()-(u[0].height()+u[1].height()+3)),usageStatistics:!1}),h=l.find("canvas:first").get(0),v=function(e){if("undefined"!=typeof e){var t,i,n,o=$(h),r=parseInt(o.attr("width")),s=parseInt(o.attr("height")),d=r/s;0===e?(i=r,n=s):(i=parseInt(o.css("max-width"))+Number(e),n=i/d,i>r&&n>s&&(i=r,n=s)),t=Math.round(i/r*100),t<100?(g.resetZoom(),g.stopDrawingMode(),a.hide()):a.show(),y.text(t+"%"),g.resizeCanvasDimension({width:i,height:n}),c&&setTimeout(function(){c&&v(e)},50)}},b=$('').data("val",10),x=$('').data("val",-10),y=$("").css("width","4em").text("%").attr("title","100%").data("val",0);f.remove(),l.removeData("url").data("mime",i.file.mime),"image/jpeg"===i.file.mime?(l.data("quality",n.storage("jpgQuality")||n.option("jpgQuality")),r=$('').attr("min","1").attr("max","100").attr("title","1 - 100").on("change",function(){var e=r.val();l.data("quality",e),s&&cancelAnimationFrame(s),s=requestAnimationFrame(function(){h.toBlob(function(e){e&&r.next("span").text(" ("+n.formatSize(e.size)+")")},"image/jpeg",Math.max(Math.min(e,100),1)/100)})}).val(l.data("quality")),$('
                    ').append($("").html(n.i18n("quality")+" : "),r,$("")).prependTo(l.parent().next())):"image/svg+xml"===i.file.mime&&l.closest(".ui-dialog").trigger("changeType",{extention:"png",mime:"image/png",keepEditor:!0}),$('
                    ').append(x,y,b).attr("title",n.i18n("scale")).on("click","span,button",function(){v($(this).data("val"))}).on("mousedown mouseup mouseleave","span",function(e){c=!1,d&&clearTimeout(d),"mousedown"===e.type&&(d=setTimeout(function(){c=!0,v($(e.target).data("val"))},500))}).prependTo(l.parent().next()),setTimeout(function(){o.resolve(g),r&&(r.trigger("change"),g.on("redoStackChanged undoStackChanged",function(){r.trigger("change")})),a=l.find(".tie-btn-zoomIn,.tie-btn-zoomOut,.tie-btn-hand"),v(null)},100),l.find(".tui-colorpicker-palette-container").on("click",".tui-colorpicker-palette-preview",function(){$(this).closest(".color-picker-control").height("auto").find(".tui-colorpicker-slider-container").toggle()}),l.on("click",function(){l.find(".tui-colorpicker-slider-container").hide()})};return i.confObj.editor?s(i.confObj.editor):(t=$.Deferred(),n.loadCss([a.tui+"/tui-color-picker/latest/tui-color-picker.css",a.tui+"/tui-image-editor/"+r+"/tui-image-editor.css"]),n.hasRequire?(require.config({paths:{"fabric/dist/fabric.require":a.fabric+"/fabric.require.min",fabric:a.fabric+"/fabric.min","tui-code-snippet":a.tui+"/tui.code-snippet/latest/tui-code-snippet.min","tui-color-picker":a.tui+"/tui-color-picker/latest/tui-color-picker.min","tui-image-editor":a.tui+"/tui-image-editor/"+r+"/tui-image-editor.min"}}),require(["tui-image-editor"],function(e){t.resolve(e)})):n.loadScript([a.fabric+"/fabric.min.js",a.tui+"/tui.code-snippet/latest/tui-code-snippet.min.js"],function(){n.loadScript([a.tui+"/tui-color-picker/latest/tui-color-picker.min.js"],function(){n.loadScript([a.tui+"/tui-image-editor/"+r+"/tui-image-editor.min.js"],function(){t.resolve(window.tui.ImageEditor)},{loadType:"tag"})},{loadType:"tag"})},{loadType:"tag"}),t.done(function(e){i.confObj.editor=e,s(e)})),o},getContent:function(e){var t=this.editor,i=t.fm,n=$(e),o=n.data("quality");if(t.instance)return"image/jpeg"===n.data("mime")&&(o=o||i.storage("jpgQuality")||i.option("jpgQuality"),o=Math.max(.1,Math.min(1,o/100))),t.instance.toDataURL({format:a(n.data("mime"),i,!0),quality:o})},save:function(e){var t,i=$(e),n=i.data("quality"),o=i.data("hash");this.instance.deactivateAll(),"undefined"!=typeof n&&this.fm.storage("jpgQuality",n),o&&(t=this.fm.file(o),i.data("mime",t.mime))}},{info:{id:"photopea",name:"Photopea",iconImg:"img/editor-icons.png 0 -160",single:!0,noContent:!0,arrayBufferContent:!0,openMaximized:!0,canMakeEmpty:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp","image/tiff","image/webp","image/vnd.adobe.photoshop","application/pdf","image/x-portable-pixmap","image/x-sketch","image/x-icon","image/vnd-ms.dds"],integrate:{title:"Photopea",link:"https://www.photopea.com/learn/"}},mimes:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp","image/tiff","image/x-adobe-dng","image/webp","image/x-xcf","image/vnd.adobe.photoshop","application/pdf","image/x-portable-pixmap","image/x-sketch","image/x-icon","image/vnd-ms.dds","application/x-msmetafile"],html:'',setup:function(e,t){(t.UA.IE||t.UA.Mobile)&&(this.disabled=!0)},init:function(e,t,i,n){var r,s,d,c="https://www.photopea.com",l=$(this).hide().on("load",function(){l.show()}).on("error",function(){f.remove(),l.show()}),p=this.editor,m=p.confObj,f=$('
                    ').html(''+n.i18n("nowLoading")+'').appendTo(l.parent()),u=n.arrayFlip(m.info.canMakeEmpty),g=function(e){var t=a(e,n),i=o[t];return m.mimesFlip[i]?"jpeg"===t&&(t="jpg"):t="",t&&u[i]||(t="psd",i=o[t],l.closest(".ui-dialog").trigger("changeType",{extention:t,mime:i,keepEditor:!0})),t},h=t.mime;m.mimesFlip||(m.mimesFlip=n.arrayFlip(m.mimes,!0)),m.liveMsg||(m.liveMsg=function(e,t,i){var o,a=e.get(0).contentWindow,r=0,s=null,d=$.Deferred().done(function(){t.remove(),r=1,a.postMessage(s,c)});this.load=function(){return n.getContents(i.hash,"arraybuffer").done(function(e){s=e})},this.receive=function(t){var i=t.originalEvent;i.origin===c&&i.source===a&&("done"===i.data?0===r?d.resolve():1===r?(r=2,e.trigger("contentsloaded")):o&&"pending"===o.state()&&o.reject("errDataEmpty"):"Save"===i.data?p.doSave():o&&"pending"===o.state()&&("object"==typeof i.data?o.resolve("data:"+h+";base64,"+n.arrayBufferToBase64(i.data)):o.reject("errDataEmpty")))},this.getContent=function(){var t,i;if(r>1)return o&&"pending"===o.state()&&o.reject(),o=null,o=$.Deferred(),2===r?(r=3,o.resolve("data:"+h+";base64,"+n.arrayBufferToBase64(s)),s=null,o):(e.data("mime")&&(h=e.data("mime"),t=g(h)),(i=e.data("quality"))&&(t+=":"+i/100),a.postMessage('app.activeDocument.saveToOE("'+t+'")',c),o)}}),l.parent().css("padding",0),s=g(t.mime),r=p.liveMsg=new m.liveMsg(l,f,t),$(window).on("message."+n.namespace,r.receive),r.load().done(function(){var e=JSON.stringify({files:[],environment:{lang:n.lang.replace(/_/g,"-"),customIO:{save:'app.echoToOE("Save");'}}});l.attr("src",c+"/#"+encodeURI(e))}).fail(function(e){e&&n.error(e),p.initFail=!0}),"image/jpeg"!==t.mime&&"image/webp"!==t.mime||(l.data("quality",n.storage("jpgQuality")||n.option("jpgQuality")),d=$('').attr("min","1").attr("max","100").attr("title","1 - 100").on("change",function(){var e=d.val();l.data("quality",e)}).val(l.data("quality")),$('
                    ').append($("").html(n.i18n("quality")+" : "),d,$("")).prependTo(l.parent().next()))},load:function(e){var t=$.Deferred(),i=this,n=(this.fm,$(e));return i.initFail?t.reject():n.on("contentsloaded",function(){t.resolve(i.liveMsg)}),t},getContent:function(){return this.editor.liveMsg?this.editor.liveMsg.getContent():void 0},save:function(e,t){var i,n=$(e),o=n.data("quality"),a=n.data("hash");"undefined"!=typeof o&&this.fm.storage("jpgQuality",o),a?(i=this.fm.file(a),n.data("mime",i.mime)):n.removeData("mime")},close:function(e,t){$(e).attr("src",""),t&&$(window).off("message."+this.fm.namespace,t.receive)}},{info:{id:"pixo",name:"Pixo Editor",iconImg:"img/editor-icons.png 0 -208",dataScheme:!0,schemeContent:!0,single:!0,canMakeEmpty:!1,integrate:{title:"Pixo Editor",link:"https://pixoeditor.com/privacy-policy/"}},mimes:["image/jpeg","image/png","image/gif","image/svg+xml","image/x-ms-bmp"],html:'
                    ',setup:function(e,t){!t.UA.ltIE8&&e.extraOptions&&e.extraOptions.pixo&&e.extraOptions.pixo.apikey?this.editorOpts=e.extraOptions.pixo:this.disabled=!0},init:function(e,t,i,n){s.call(this,e,t,i,n)},getContent:function(){return $(this).children("img:first").attr("src")},load:function(e){var t,i,n,o,s,d=this,c=this.fm,l=$(e),p=l.children("img:first"),m=l.closest(".ui-dialog"),f=c.getUI(),u=$.Deferred(),g=$("#elfinder-pixo-container"),h=function(n){var h;g.length?g.appendTo(g.parent()):(g=$('
                    ').css({position:"fixed",top:0,right:0,width:"100%",height:$(window).height(),overflow:"hidden"}).hide().appendTo(f.hasClass("elfinder-fullscreen")?f:"body"),f.on("resize."+c.namespace,function(e,t){e.preventDefault(),e.stopPropagation(),t&&t.fullscreen&&g.appendTo("on"===t.fullscreen?f:"body")}),c.bind("destroy",function(){s&&s.cancelEditing(),g.remove()})),p.on("click",v),h=Object.assign({type:"child",parent:g.get(0),output:{format:"png"},onSave:function(n){var s=n.toBlob().type,l=a(s,c),f=function(e){p.one("load error",function(){p.data("loading")&&p.data("loading")(!0)}).attr("crossorigin","anonymous").attr("src",e)},u=n.toDataURL();p.data("loading")(),delete e._canvas,p.data("ext")!==l?r(u,d.file.mime).done(function(n,a){a&&(e._canvas=o=a,i.trigger("change"),t&&t.show()),f(n)}).fail(function(){m.trigger("changeType",{extention:l,mime:s}),f(u)}):f(u)},onClose:function(){m.removeClass(c.res("class","preventback")),c.toggleMaximize(g,!1),g.hide(),c.toFront(m)}},d.confObj.editorOpts),d.trigger("Prepare",{node:e,editorObj:Pixo,instance:void 0,opts:h}),s=new Pixo.Bridge(h),u.resolve(s),l.on("saveAsFail",v),n&&n()},v=function(){m.addClass(c.res("class","preventback")),c.toggleMaximize(g,!0),c.toFront(g),g.show().data("curhash",d.file.hash),s.edit(p.get(0)),p.data("loading")(!0)};return p.data("loading")(),"image/jpeg"===d.file.mime&&(i=$('').attr("min","1").attr("max","100").attr("title","1 - 100").on("change",function(){var e=i.val();n&&cancelAnimationFrame(n),n=requestAnimationFrame(function(){o&&o.toBlob(function(e){e&&i.next("span").text(" ("+c.formatSize(e.size)+")")},"image/jpeg",Math.max(Math.min(e,100),1)/100)})}).val(c.storage("jpgQuality")||c.option("jpgQuality")),t=$('
                    ').hide().append($("").html(c.i18n("quality")+" : "),i,$("")).prependTo(l.parent().next()),l.data("quty",i)),"undefined"==typeof Pixo?c.loadScript(["https://pixoeditor.com:8443/editor/scripts/bridge.m.js"],function(){h(v)},{loadType:"tag"}):(h(),v()),u},save:function(e){var t,i=this,n=$(e),o=n.children("img:first");e._canvas?(n.data("quty")&&(t=n.data("quty").val(),t&&this.fm.storage("jpgQuality",t)),o.attr("src",e._canvas.toDataURL(i.file.mime,t?Math.max(Math.min(t,100),1)/100:void 0))):"data:"!==o.attr("src").substr(0,5)&&o.attr("src",d(o,this.file.mime))},close:function(e,t){t&&t.destroy()}},{setup:function(e,t){!t.UA.ltIE8&&t.options.cdns.ace||(this.disabled=!0)},info:{id:"aceeditor",name:"ACE Editor",iconImg:"img/editor-icons.png 0 -96"},load:function(e){var t=this,i=this.fm,n=$.Deferred(),o=i.options.cdns.ace,a=function(){var i,a,r,s=$(e),d=s.parent(),c=d.parent(),l=e.id+"_ace",p=(t.file.name.replace(/^.+\.([^.]+)|(.+)$/,"$1$2").toLowerCase(),{"text/x-php":"php","application/x-php":"php","text/html":"html","application/xhtml+xml":"html","text/javascript":"javascript","application/javascript":"javascript","text/css":"css","text/x-c":"c_cpp","text/x-csrc":"c_cpp","text/x-chdr":"c_cpp","text/x-c++":"c_cpp","text/x-c++src":"c_cpp","text/x-c++hdr":"c_cpp","text/x-shellscript":"sh","application/x-csh":"sh","text/x-python":"python","text/x-java":"java","text/x-java-source":"java","text/x-ruby":"ruby","text/x-perl":"perl","application/x-perl":"perl","text/x-sql":"sql","text/xml":"xml","application/docbook+xml":"xml","application/xml":"xml"});d.height(d.height()),ace.config.set("basePath",o),a=$('
                    ').text(s.val()).insertBefore(s.hide()),s.data("ace",!0),i=ace.edit(l),i.$blockScrolling=1/0,i.setOptions({theme:"ace/theme/monokai",fontSize:"14px",wrap:!0}),ace.config.loadModule("ace/ext/modelist",function(){r=ace.require("ace/ext/modelist").getModeForPath("/"+t.file.name).name,"text"===r&&p[t.file.mime]&&(r=p[t.file.mime]),d.prev().children(".elfinder-dialog-title").append(" ("+t.file.mime+" : "+r.split(/[\/\\]/).pop()+")"),i.setOptions({mode:"ace/mode/"+r}),"resolved"===n.state()&&c.trigger("resize")}),ace.config.loadModule("ace/ext/language_tools",function(){ace.require("ace/ext/language_tools"),i.setOptions({enableBasicAutocompletion:!0,enableSnippets:!0,enableLiveAutocompletion:!1})}),ace.config.loadModule("ace/ext/settings_menu",function(){ace.require("ace/ext/settings_menu").init(i)}),i.commands.addCommand({name:"saveFile",bindKey:{win:"Ctrl-s",mac:"Command-s"},exec:function(e){t.doSave()}}),i.commands.addCommand({name:"closeEditor",bindKey:{win:"Ctrl-w|Ctrl-q",mac:"Command-w|Command-q"},exec:function(e){t.doCancel()}}),i.resize(),$('
                    ').css("float","left").append($("").html(t.fm.i18n("TextArea")).button().on("click",function(){s.data("ace")?(s.removeData("ace"),a.hide(),s.val(i.session.getValue()).show().trigger("focus"),$(this).text("AceEditor")):(s.data("ace",!0),a.show(),i.setValue(s.hide().val(),-1),i.focus(),$(this).html(t.fm.i18n("TextArea")))})).append($("").button({icons:{primary:"ui-icon-gear",secondary:"ui-icon-triangle-1-e"},text:!1}).on("click",function(){i.showSettingsMenu(),$("#ace_settingsmenu").css("font-size","80%").find('div[contains="setOptions"]').hide().end().parent().appendTo($("#elfinder"))})).prependTo(d.next()),t.trigger("Prepare",{node:e,editorObj:ace,instance:i,opts:{}}),n.resolve(i)};return t.confObj.loader||(t.confObj.loader=$.Deferred(),t.fm.loadScript([o+"/ace.js"],function(){t.confObj.loader.resolve()},void 0,{obj:window,name:"ace"})),t.confObj.loader.done(a),n},close:function(e,t){t&&t.destroy()},save:function(e,t){t&&$(e).data("ace")&&(e.value=t.session.getValue())},focus:function(e,t){t&&$(e).data("ace")&&t.focus()},resize:function(e,t,i,n){t&&t.resize()}},{setup:function(e,t){!t.UA.ltIE10&&t.options.cdns.codemirror||(this.disabled=!0)},info:{id:"codemirror",name:"CodeMirror",iconImg:"img/editor-icons.png 0 -176"},load:function(e){var t=this.fm,i=t.convAbsUrl(t.options.cdns.codemirror),o=$.Deferred(),a=this,r=function(t){var r,s,d,c=$(e),l=c.parent();l.height(l.height()),d={lineNumbers:!0,lineWrapping:!0,extraKeys:{"Ctrl-S":function(){a.doSave()},"Ctrl-Q":function(){a.doCancel()},"Ctrl-W":function(){a.doCancel()}}},a.trigger("Prepare",{node:e,editorObj:t,instance:void 0,opts:d}),r=t.fromTextArea(e,d),o.resolve(r);var p,m,f,u;p||(p=t.findModeByMIME(a.file.mime)),!p&&(m=a.file.name.match(/.+\.([^.]+)$/))&&(p=t.findModeByExtension(m[1])),p&&(t.modeURL=n?"codemirror/mode/%N/%N.min":i+"/mode/%N/%N.min.js",f=p.mode,u=p.mime,r.setOption("mode",u),t.autoLoadMode(r,f),l.prev().children(".elfinder-dialog-title").append(" ("+u+("null"!=f?" : "+f:"")+")")),s=$(r.getWrapperElement()).css({padding:0,border:"none"}),c.data("cm",!0),s.height("100%"),$('
                    ').css("float","left").append($("").html(a.fm.i18n("TextArea")).button().on("click",function(){c.data("cm")?(c.removeData("cm"),s.hide(),c.val(r.getValue()).show().trigger("focus"),$(this).text("CodeMirror")):(c.data("cm",!0),s.show(),r.setValue(c.hide().val()),r.refresh(),r.focus(),$(this).html(a.fm.i18n("TextArea")))})).prependTo(l.next())};return a.confObj.loader||(a.confObj.loader=$.Deferred(),n?(require.config({packages:[{name:"codemirror",location:i,main:"codemirror.min"}],map:{codemirror:{"codemirror/lib/codemirror":"codemirror"}}}),require(["codemirror","codemirror/addon/mode/loadmode.min","codemirror/mode/meta.min"],function(e){a.confObj.loader.resolve(e)})):a.fm.loadScript([i+"/codemirror.min.js"],function(){a.fm.loadScript([i+"/addon/mode/loadmode.min.js",i+"/mode/meta.min.js"],function(){a.confObj.loader.resolve(CodeMirror)})},{loadType:"tag"}),a.fm.loadCss(i+"/codemirror.css")),a.confObj.loader.done(r),o},close:function(e,t){t&&t.toTextArea()},save:function(e,t){t&&$(e).data("cm")&&(e.value=t.getValue())},focus:function(e,t){t&&$(e).data("cm")&&t.focus()},resize:function(e,t,i,n){t&&t.refresh()}},{setup:function(e,t){!t.UA.ltIE10&&t.options.cdns.simplemde||(this.disabled=!0)},info:{id:"simplemde",name:"SimpleMDE",iconImg:"img/editor-icons.png 0 -80"},exts:["md"],load:function(e){var t=this,i=this.fm,o=$(e).parent(),a=$.Deferred(),r=i.options.cdns.simplemde,s=function(i){var n,r,s,d=o.height(),c=o.outerHeight(!0)-d+14;e._setHeight=function(e){var t,i=e||o.height(),a=0;return o.children(".editor-toolbar,.editor-statusbar").each(function(){a+=$(this).outerHeight(!0)}),t=i-a-c,r.height(t),n.codemirror.refresh(),t},o.height(d),s={element:e,autofocus:!0},t.trigger("Prepare",{node:e,editorObj:i,instance:void 0,opts:s}),n=new i(s),a.resolve(n),r=$(n.codemirror.getWrapperElement()),r.css("min-height","50px").children(".CodeMirror-scroll").css("min-height","50px"),e._setHeight(d)};return t.confObj.loader||(t.confObj.loader=$.Deferred(),t.fm.loadCss(r+"/simplemde.min.css"),n?require([r+"/simplemde.min.js"],function(e){t.confObj.loader.resolve(e)}):t.fm.loadScript([r+"/simplemde.min.js"],function(){t.confObj.loader.resolve(SimpleMDE)},{loadType:"tag"})),t.confObj.loader.done(s),a},close:function(e,t){t&&t.toTextArea(),t=null},save:function(e,t){t&&(e.value=t.value())},focus:function(e,t){t&&t.codemirror.focus()},resize:function(e,t,i,n){t&&e._setHeight()}},{info:{id:"ckeditor",name:"CKEditor",iconImg:"img/editor-icons.png 0 0"},exts:["htm","html","xhtml"],setup:function(e,t){var i=this;t.options.cdns.ckeditor?(i.ckeOpts={},e.extraOptions&&(i.ckeOpts=Object.assign({},e.extraOptions.ckeditor||{}),e.extraOptions.managerUrl&&(i.managerUrl=e.extraOptions.managerUrl))):i.disabled=!0},load:function(e){var t=this,i=this.fm,n=$.Deferred(),o=function(){var o,a=$(e).parent(),r=a.closest(".elfinder-dialog"),s=a.height(),d=/([&?]getfile=)[^&]+/,c=t.confObj.managerUrl||window.location.href.replace(/#.*$/,""),l="ckeditor";d.test(c)?c=c.replace(d,"$1"+l):c+="?getfile="+l,a.height(s),o={startupFocus:!0,fullPage:!0,allowedContent:!0,filebrowserBrowseUrl:c,toolbarCanCollapse:!0,toolbarStartupExpanded:!i.UA.Mobile,removePlugins:"resize",extraPlugins:"colorbutton,justify,docprops",on:{instanceReady:function(o){var a=o.editor;a.resize("100%",s),r.one("beforedommove."+i.namespace,function(){a.destroy()}).one("dommove."+i.namespace,function(){t.load(e).done(function(e){t.instance=e})}),n.resolve(o.editor)}}},t.trigger("Prepare",{node:e,editorObj:CKEDITOR,instance:void 0,opts:o}),CKEDITOR.replace(e.id,Object.assign(o,t.confObj.ckeOpts)),CKEDITOR.on("dialogDefinition",function(e){var t=e.data.definition.dialog;t.on("show",function(e){i.getUI().append($(".cke_dialog_background_cover")).append(this.getElement().$)}),t.on("hide",function(e){$("body:first").append($(".cke_dialog_background_cover")).append(this.getElement().$)})})};return t.confObj.loader||(t.confObj.loader=$.Deferred(),window.CKEDITOR_BASEPATH=i.options.cdns.ckeditor+"/",$.getScript(i.options.cdns.ckeditor+"/ckeditor.js",function(){t.confObj.loader.resolve()})),t.confObj.loader.done(o),n},close:function(e,t){t&&t.destroy()},save:function(e,t){t&&(e.value=t.getData())},focus:function(e,t){t&&t.focus()},resize:function(e,t,i,n){t&&"ready"===t.status&&t.resize("100%",$(e).parent().height())}},{info:{id:"ckeditor5",name:"CKEditor5",iconImg:"img/editor-icons.png 0 -16"},exts:["htm","html","xhtml"],html:'
                    ',setup:function(e,t){var i=this;t.options.cdns.ckeditor5&&"function"==typeof window.Symbol&&"symbol"==typeof Symbol()?(i.ckeOpts={},e.extraOptions&&(e.extraOptions.ckeditor5Mode&&(i.ckeditor5Mode=e.extraOptions.ckeditor5Mode),i.ckeOpts=Object.assign({},e.extraOptions.ckeditor5||{}),i.ckeOpts.mode&&(i.ckeditor5Mode=i.ckeOpts.mode,delete i.ckeOpts.mode),e.extraOptions.managerUrl&&(i.managerUrl=e.extraOptions.managerUrl))):i.disabled=!0,t.bind("destroy",function(){i.editor=null})},prepare:function(e,t,i){$(e).height(e.editor.fm.getUI().height()-100)},init:function(e,t,i,n){var o=i.match(/^([\s\S]*]*>)([\s\S]+)(<\/body>[\s\S]*)$/i),a="",r="",s="";this.css({width:"100%",height:"100%","box-sizing":"border-box"}),o?(a=o[1],r=o[2],s=o[3]):r=i,this.data("data",{header:a,body:r,footer:s}),this._setupSelEncoding(i)},load:function(e){var t,i=this,n=this.fm,o=$.Deferred(),a=i.confObj.ckeditor5Mode||"decoupled-document",r=function(){var e=n.lang.toLowerCase().replace("_","-");return"zh"===e.substr(0,2)&&"zh-cn"!==e&&(e="zh"),e}(),s=function(t){var s,c=$(e).parent();c.height(n.getUI().height()-100),s=Object.assign({toolbar:["heading","|","fontSize","fontFamily","|","bold","italic","underline","strikethrough","highlight","|","alignment","|","numberedList","bulletedList","blockQuote","indent","outdent","|","ckfinder","link","imageUpload","insertTable","mediaEmbed","|","undo","redo"],language:r},i.confObj.ckeOpts),i.trigger("Prepare",{node:e,editorObj:t,instance:void 0,opts:s}),t.create(e,s).then(function(t){var i,r,s=t.commands.get("ckfinder"),l=t.plugins.get("FileRepository"),p={};!t.ui.view.toolbar||"classic"!==a&&"decoupled-document"!==a||$(e).closest(".elfinder-dialog").children(".ui-widget-header").append($(t.ui.view.toolbar.element).css({marginRight:"-1em",marginLeft:"-1em"})),"classic"===a&&$(e).closest(".elfinder-edit-editor").css("overflow","auto"),s&&(i=function(e){return e&&e.mime.match(/^image\//i)},r=function(e){var i=t.commands.get("imageUpload");if(!i.isEnabled){var n=t.plugins.get("Notification"),o=t.locale.t;return void n.showWarning(o("Could not insert image at the current position."),{title:o("Inserting image failed"),namespace:"ckfinder"})}t.execute("imageInsert",{source:e})},s.execute=function(){var e=c.closest(".elfinder-dialog"),o=n.getCommand("getfile"),a=function(){p.hasVar&&(e.off("resize close",a),o.callback=p.callback,o.options.folders=p.folders,o.options.multiple=p.multi,n.commandMap.open=p.open,p.hasVar=!1)};e.trigger("togleminimize").one("resize close",a),p.callback=o.callback,p.folders=o.options.folders,p.multi=o.options.multiple,p.open=n.commandMap.open,p.hasVar=!0,o.callback=function(o){var a=[];return 1===o.length&&"directory"===o[0].mime?void n.one("open",function(){n.commandMap.open="getfile"}).getCommand("open").exec(o[0].hash):(n.getUI("cwd").trigger("unselectall"),$.each(o,function(e,o){i(o)?a.push(n.convAbsUrl(o.url)):t.execute("link",n.convAbsUrl(o.url))}),a.length&&r(a),void e.trigger("togleminimize"))},o.options.folders=!0,o.options.multiple=!0,n.commandMap.open="getfile",n.toast({mode:"info",msg:n.i18n("dblclickToSelect")})}),l.createUploadAdapter=function(e){return new d(e)},t.setData($(e).data("data").body),n.getUI().append($("body > div.ck-body")),$("div.ck-balloon-panel").css({"z-index":n.getMaximizeCss().zIndex+1}),o.resolve(t)})["catch"](function(e){n.error(e)})},d=function(e){var t=function(t,i,o){n.exec("upload",{files:[t]},void 0,n.cwd().hash).done(function(e){e.added&&e.added.length?n.url(e.added[0].hash,{async:!0}).done(function(e){i({"default":n.convAbsUrl(e)})}).fail(function(){o("errFileNotFound")}):o(n.i18n(e.error?e.error:"errUpload"))}).fail(function(e){var t=n.parseError(e);o(n.i18n(t?"userabort"===t?"errAbort":t:"errUploadNoFiles"))}).progress(function(t){e.uploadTotal=t.total,e.uploaded=t.progress})};this.upload=function(){return new Promise(function(i,n){e.file instanceof Promise||e.file&&"function"==typeof e.file.then?e.file.then(function(e){t(e,i,n)}):t(e.file,i,n)})},this.abort=function(){n.getUI().trigger("uploadabort")}};return i.confObj.editor?s(i.confObj.editor):(t=$.Deferred(),i.fm.loadScript([n.options.cdns.ckeditor5+"/"+a+"/ckeditor.js"],function(e){e||(e=window.BalloonEditor||window.InlineEditor||window.ClassicEditor||window.DecoupledEditor),"en"!==n.lang?i.fm.loadScript([n.options.cdns.ckeditor5+"/"+a+"/translations/"+r+".js"],function(i){t.resolve(e)},{tryRequire:!0,loadType:"tag",error:function(i){r="en",t.resolve(e)}}):t.resolve(e)},{tryRequire:!0,loadType:"tag"}),t.done(function(e){i.confObj.editor=e,s(e)})),o},getContent:function(){var e=$(this).data("data");return e.header+e.body+e.footer},close:function(e,t){t&&t.destroy()},save:function(e,t){var i=$(e),n=i.data("data");t&&(n.body=t.getData(),i.data("data",n))},focus:function(e,t){$(e).trigger("focus")}},{info:{id:"tinymce",name:"TinyMCE",iconImg:"img/editor-icons.png 0 -64"},exts:["htm","html","xhtml"],setup:function(e,t){var i=this;t.options.cdns.tinymce?(i.mceOpts={},e.extraOptions?(i.uploadOpts=Object.assign({},e.extraOptions.uploadOpts||{}),i.mceOpts=Object.assign({},e.extraOptions.tinymce||{})):i.uploadOpts={}):i.disabled=!0},load:function(e){var t=this,i=this.fm,n=$.Deferred(),o=function(){var o,a,r,s=$(e).show().parent(),d=s.closest(".elfinder-dialog"),c=s.height(),l=s.outerHeight(!0)-c,p=function(){var e;tinymce.activeEditor.windowManager.windows?(e=tinymce.activeEditor.windowManager.windows[0],a=$(e?e.getEl():void 0).hide(),r=$("#mce-modal-block").hide()):a=$(".tox-dialog-wrap").hide()},m=function(){r&&r.show(),a&&a.show()},f=tinymce.majorVersion;s.height(c),e._setHeight=function(e){if(f<5){var t,i=$(this).parent(),n=e||i.innerHeight(),o=0;i.find(".mce-container-body:first").children(".mce-top-part,.mce-statusbar").each(function(){o+=$(this).outerHeight(!0)}),t=n-o-l,i.find(".mce-edit-area iframe:first").height(t)}},o={selector:"#"+e.id,resize:!1,plugins:"preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help",toolbar:"formatselect | bold italic strikethrough forecolor backcolor | link image media | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat",image_advtab:!0,init_instance_callback:function(o){e._setHeight(c),d.one("beforedommove."+i.namespace,function(){tinymce.execCommand("mceRemoveEditor",!1,e.id)}).one("dommove."+i.namespace,function(){t.load(e).done(function(e){t.instance=e})}),n.resolve(o)},file_picker_callback:function(e,t,n){var o=i.getCommand("getfile"),a=function(){r.hasVar&&(o.callback=r.callback,o.options.folders=r.folders,o.options.multiple=r.multi,i.commandMap.open=r.open,r.hasVar=!1),d.off("resize close",a),m()},r={};return r.callback=o.callback,r.folders=o.options.folders,r.multi=o.options.multiple,r.open=i.commandMap.open,r.hasVar=!0,o.callback=function(t){var o,a;return"directory"===t.mime?void i.one("open",function(){i.commandMap.open="getfile"}).getCommand("open").exec(t.hash):(o=i.convAbsUrl(t.url),a=t.name+" ("+i.formatSize(t.size)+")","file"==n.filetype&&e(o,{text:a,title:a}),"image"==n.filetype&&e(o,{alt:a}),"media"==n.filetype&&e(o),void d.trigger("togleminimize"))},o.options.folders=!0,o.options.multiple=!1,i.commandMap.open="getfile",p(),d.trigger("togleminimize").one("resize close",a),i.toast({mode:"info",msg:i.i18n("dblclickToSelect")}),!1},images_upload_handler:function(e,n,o){var a=e.blob(),r=function(e){var t=e.data.dialog||{};(t.hasClass("elfinder-dialog-error")||t.hasClass("elfinder-confirm-upload"))&&(p(),t.trigger("togleminimize").one("resize close",s),i.unbind("dialogopened",r)); +},s=function(){d.off("resize close",s),m()},c=!0;a.name&&(c=void 0),i.bind("dialogopened",r).exec("upload",Object.assign({files:[a],clipdata:c},t.confObj.uploadOpts),void 0,i.cwd().hash).done(function(e){e.added&&e.added.length?i.url(e.added[0].hash,{async:!0}).done(function(e){m(),n(i.convAbsUrl(e))}).fail(function(){o(i.i18n("errFileNotFound"))}):o(i.i18n(e.error?e.error:"errUpload"))}).fail(function(e){var t=i.parseError(e);t&&("errUnknownCmd"===t?t="errPerm":"userabort"===t&&(t="errAbort")),o(i.i18n(t?t:"errUploadNoFiles"))})}},f>=5&&(o.height="100%"),t.trigger("Prepare",{node:e,editorObj:tinymce,instance:void 0,opts:o}),tinymce.init(Object.assign(o,t.confObj.mceOpts))};return t.confObj.loader||(t.confObj.loader=$.Deferred(),t.fm.loadScript([i.options.cdns.tinymce+(i.options.cdns.tinymce.match(/\.js/)?"":"/tinymce.min.js")],function(){t.confObj.loader.resolve()},{loadType:"tag"})),t.confObj.loader.done(o),n},close:function(e,t){t&&tinymce.execCommand("mceRemoveEditor",!1,e.id)},save:function(e,t){t&&t.save()},focus:function(e,t){t&&t.focus()},resize:function(e,t,i,n){t&&e._setHeight()}},{info:{id:"zohoeditor",name:"Zoho Editor",iconImg:"img/editor-icons.png 0 -32",cmdCheck:"ZohoOffice",preventGet:!0,hideButtons:!0,syncInterval:15e3,canMakeEmpty:!0,integrate:{title:"Zoho Office API",link:"https://www.zoho.com/officeapi/"}},mimes:["application/msword","application/vnd.openxmlformats-officedocument.wordprocessingml.document","application/vnd.oasis.opendocument.text","application/rtf","text/html","application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","application/vnd.oasis.opendocument.spreadsheet","application/vnd.sun.xml.calc","text/csv","text/tab-separated-values","application/vnd.ms-powerpoint","application/vnd.openxmlformats-officedocument.presentationml.presentation","application/vnd.openxmlformats-officedocument.presentationml.slideshow","application/vnd.oasis.opendocument.presentation","application/vnd.sun.xml.impress"],html:'',setup:function(e,t){(t.UA.Mobile||t.UA.ltIE8)&&(this.disabled=!0)},prepare:function(e,t,i){var n=e.editor.fm.getUI();$(e).height(n.height()),t.width=Math.max(t.width||0,.8*n.width())},init:function(e,t,i,n){var o=this,a=$(this).hide(),r=n.getUI("toast"),s=$('
                    ').html(''+n.i18n("nowLoading")+'').appendTo(a.parent()),d=function(){var e="";return $.each(n.customData,function(t,i){e+="&"+encodeURIComponent(t)+"="+encodeURIComponent(i)}),e};$(o).data("xhr",n.request({data:{cmd:"editor",name:o.editor.confObj.info.cmdCheck,method:"init","args[target]":t.hash,"args[lang]":n.lang,"args[cdata]":d()},preventDefault:!0}).done(function(e){var t;e.zohourl?(t={css:{height:"100%"}},o.editor.trigger("Prepare",{node:o,editorObj:void 0,instance:a,opts:t}),a.attr("src",e.zohourl).show().css(t.css),e.warning&&(r.appendTo(o.closest(".ui-dialog")),n.toast({msg:n.i18n(e.warning),mode:"warning",timeOut:0,onHidden:function(){1===r.children().length&&r.appendTo(n.getUI())},button:{text:"btnYes"}}))):(e.error&&n.error(e.error),o.elfinderdialog("destroy"))}).fail(function(e){e&&n.error(e),o.elfinderdialog("destroy")}).always(function(){s.remove()}))},load:function(){},getContent:function(){},save:function(){},beforeclose:c,close:function(e){var t=(this.fm,$(e).data("xhr"));"pending"===t.state()&&t.reject()}},{info:{id:"ziparchive",name:"btnMount",iconImg:"img/toolbar.png 0 -416",cmdCheck:"ZipArchive",edit:function(e,t){var i=this,n=$.Deferred();return i.request({data:{cmd:"netmount",protocol:"ziparchive",host:e.hash,path:e.phash},preventFail:!0,notify:{type:"netmount",cnt:1,hideCnt:!0}}).done(function(e){var t;e.added&&e.added.length&&(e.added[0].phash&&(t=i.file(e.added[0].phash))&&(t.dirs||(t.dirs=1,i.change({changed:[t]}))),i.one("netmountdone",function(){i.exec("open",e.added[0].hash),i.one("opendone",function(){e.toast&&i.toast(e.toast)})})),n.resolve()}).fail(function(e){n.reject(e)}),n}},mimes:["application/zip"],load:function(){},save:function(){}},{info:{id:"textarea",name:"TextArea",useTextAreaEvent:!0},load:function(e){this.trigger("Prepare",{node:e,editorObj:void 0,instance:void 0,opts:{}}),e.setSelectionRange&&e.setSelectionRange(0,0),$(e).trigger("focus").show()},save:function(){}},{info:{id:"onlineconvert",name:"Online Convert",iconImg:"img/editor-icons.png 0 -144",cmdCheck:"OnlineConvert",preventGet:!0,hideButtons:!0,single:!0,converter:!0,canMakeEmpty:!1,integrate:{title:"ONLINE-CONVERT.COM",link:"https://online-convert.com"}},mimes:["*"],html:'
                    ',setup:function(e,t){var i=e.extraOptions.onlineConvert||{maxSize:100,showLink:!0};i.maxSize&&(this.info.maxSize=1048576*i.maxSize),this.set=Object.assign({url:"https://%s.online-convert.com%s?external_url=",conv:{Archive:{"7Z":{},BZ2:{ext:"bz"},GZ:{},ZIP:{}},Audio:{MP3:{},OGG:{ext:"oga"},WAV:{},WMA:{},AAC:{},AIFF:{ext:"aif"},FLAC:{},M4A:{},MMF:{},OPUS:{ext:"oga"}},Document:{DOC:{},DOCX:{},HTML:{},ODT:{},PDF:{},PPT:{},PPTX:{},RTF:{},SWF:{},TXT:{}},eBook:{AZW3:{ext:"azw"},ePub:{},FB2:{ext:"xml"},LIT:{},LRF:{},MOBI:{},PDB:{},PDF:{},"PDF-eBook":{ext:"pdf"},TCR:{}},Hash:{Adler32:{},"Apache-htpasswd":{},Blowfish:{},CRC32:{},CRC32B:{},Gost:{},Haval128:{},MD4:{},MD5:{},RIPEMD128:{},RIPEMD160:{},SHA1:{},SHA256:{},SHA384:{},SHA512:{},Snefru:{},"Std-DES":{},Tiger128:{},"Tiger128-calculator":{},"Tiger128-converter":{},Tiger160:{},Tiger192:{},Whirlpool:{}},Image:{BMP:{},EPS:{ext:"ai"},GIF:{},EXR:{},ICO:{},JPG:{},PNG:{},SVG:{},TGA:{},TIFF:{ext:"tif"},WBMP:{},WebP:{}},Video:{"3G2":{},"3GP":{},AVI:{},FLV:{},HLS:{ext:"m3u8"},MKV:{},MOV:{},MP4:{},"MPEG-1":{ext:"mpeg"},"MPEG-2":{ext:"mpeg"},OGG:{ext:"ogv"},OGV:{},WebM:{},WMV:{},Android:{link:"/convert-video-for-%s",ext:"mp4"},Blackberry:{link:"/convert-video-for-%s",ext:"mp4"},DPG:{link:"/convert-video-for-%s",ext:"avi"},iPad:{link:"/convert-video-for-%s",ext:"mp4"},iPhone:{link:"/convert-video-for-%s",ext:"mp4"},iPod:{link:"/convert-video-for-%s",ext:"mp4"},"Nintendo-3DS":{link:"/convert-video-for-%s",ext:"avi"},"Nintendo-DS":{link:"/convert-video-for-%s",ext:"avi"},PS3:{link:"/convert-video-for-%s",ext:"mp4"},Wii:{link:"/convert-video-for-%s",ext:"avi"},Xbox:{link:"/convert-video-for-%s",ext:"wmv"}}},catExts:{Hash:"txt"},link:'',useTabs:!(!$.fn.tabs||t.UA.iOS)},i)},prepare:function(e,t,i){var n=e.editor.fm.getUI();$(e).height(n.height()),t.width=Math.max(t.width||0,.8*n.width())},init:function(e,t,i,n){var a,r,s=this,d=s.editor.confObj,c=d.set,l=n.getUI("toast"),p={},m=n.uploadMimeCheck("application/zip",t.phash),f=$("base").length?document.location.href.replace(/#.*$/,""):"",u=function(e,t){var i;return c.catExts[e]?c.catExts[e]:c.conv[e]&&(i=c.conv[e][t])?(i.ext||t).toLowerCase():t.toLowerCase()},g=function(e,t){var i,o,a;o="undefined"==typeof d.api?n.request({data:{cmd:"editor",name:"OnlineConvert",method:"init"},preventDefault:!0}):$.Deferred().resolve({api:d.api}),e=e.toLowerCase(),o.done(function(n){d.api=n.api,d.api&&(e?i="?category="+e:(i="",e="all"),d.conversions||(d.conversions={}),a=d.conversions[e]?$.Deferred().resolve(d.conversions[e]):$.getJSON("https://api2.online-convert.com/conversions"+i),a.done(function(i){d.conversions[e]=i,$.each(i,function(e,t){h[c.useTabs?"children":"find"](".onlineconvert-category-"+t.category).children(".onlineconvert-"+t.target).trigger("makeoption",t)}),t&&t()}))})},h=function(){var e=$("
                    ").on("click","button",function(){var e=$(this),t=e.data("opts")||null,i=e.closest(".onlineconvert-category").data("cname"),n=e.data("conv");d.api===!0&&k({category:i,convert:n,options:t})}).on("change",function(e){var t=$(e.target),i=t.parent(),o=t.closest(".elfinder-edit-onlineconvert-button").children("button:first"),a=o.data("opts")||{},r="boolean"===i.data("type")?t.is(":checked"):t.val();if(e.stopPropagation(),r&&("integer"===i.data("type")&&(r=parseInt(r)),i.data("pattern"))){var s=new RegExp(i.data("pattern"));s.test(r)||(requestAnimationFrame(function(){n.error('"'+n.escape(r)+'" is not match to "/'+n.escape(i.data("pattern"))+'/"')}),r=null)}r?a[t.parent().data("optkey")]=r:delete a[i.data("optkey")],o.data("opts",a)}),i=$("
                      "),a=function(e,t){var i,o,a,r=$("

                      ").data("optkey",e).data("type",t.type),s="",d="",c=!1;return t.description&&r.attr("title",n.i18n(t.description)),t.pattern&&r.data("pattern",t.pattern),r.append($("").text(n.i18n(e)+" : ")),"boolean"===t.type?((t["default"]||(c="allow_multiple_outputs"===e&&!m))&&(s=" checked",c&&(d=" disabled"),o=this.children("button:first"),i=o.data("opts")||{},i[e]=!0,o.data("opts",i)),r.append($('"))):t["enum"]?(a=$("").append($('').text("Select...")),$.each(t["enum"],function(e,t){a.append($('').text(t))}),r.append(a)):r.append($('')),r},r=function(e){var t=this,i=$('').on("click",function(){n.toggle()}),n=$('
                      ').hide();e.options&&$.each(e.options,function(e,i){"download_password"!==e&&n.append(a.call(t,e,i))}),t.append(i,n)},s=+new Date,l=0;return d.ext2mime||(d.ext2mime=Object.assign(n.arrayFlip(n.mimeTypes),o)),$.each(c.conv,function(o,a){var c=o.toLowerCase(),m="elfinder-edit-onlineconvert-"+c+s,g=$('
                      ').data("cname",o);$.each(a,function(e,i){var a=e.toLowerCase(),s=u(o,e);d.ext2mime[s]||("audio"===c||"image"===c||"video"===c?d.ext2mime[s]=c+"/x-"+a:d.ext2mime[s]="application/octet-stream"),n.uploadMimeCheck(d.ext2mime[s],t.phash)&&g.append($('
                      ').on("makeoption",function(e,t){var i=$(this);i.children(".elfinder-button-icon-preference").length||r.call(i,t)}).append($("").text(e).data("conv",e)))}),g.children().length&&(i.append($("
                    • ").append($("").attr("href",f+"#"+m).text(o))),e.append(g),p[c]=l++)}),c.useTabs?e.prepend(i).tabs({beforeActivate:function(e,t){g(t.newPanel.data("cname"))}}):$.each(c.conv,function(t){var i=t.toLowerCase();e.append($('
                      ').append($("").text(t)).append(e.children(".onlineconvert-category-"+i)))}),e}(),v=$(this).append(h,c.showLink?$(c.link):null),b=$('
                      ').hide().html(''+n.i18n("nowLoading")+'').appendTo(v.parent()),x=$('
                      ').appendTo(b),y=null,w=function(){return y?$.Deferred().resolve(y):(b.show(),n.forExternalUrl(t.hash,{progressBar:x}).done(function(e){y=e}).fail(function(e){e&&n.error(e),s.elfinderdialog("destroy")}).always(function(){b.hide()}))},k=function(e){$(s).data("dfrd",w().done(function(i){v.fadeOut(),j({info:"Start conversion request."}),n.request({data:{cmd:"editor",name:"OnlineConvert",method:"api","args[category]":e.category.toLowerCase(),"args[convert]":e.convert.toLowerCase(),"args[options]":JSON.stringify(e.options),"args[source]":n.convAbsUrl(i),"args[filename]":n.splitFileExtention(t.name)[0]+"."+u(e.category,e.convert),"args[mime]":t.mime},preventDefault:!0}).done(function(t){O(t.apires,e.category,e.convert)}).fail(function(e){e&&n.error(e),s.elfinderdialog("destroy")})}))},O=function(e,t,i){var o,a=[];e&&e.id?(o=e.status,"failed"===o.code?(b.hide(),e.errors&&e.errors.length&&$.each(e.errors,function(e,t){t.message&&a.push(t.message)}),n.error(a.length?a:o.info),v.fadeIn()):"completed"===o.code?M(e):(j(o),setTimeout(function(){C(e.id)},1e3))):(l.appendTo(s.closest(".ui-dialog")),e.message&&n.toast({msg:n.i18n(e.message),mode:"error",timeOut:5e3,onHidden:function(){1===l.children().length&&l.appendTo(n.getUI())}}),n.toast({msg:n.i18n("editorConvNoApi"),mode:"error",timeOut:3e3,onHidden:function(){1===l.children().length&&l.appendTo(n.getUI())}}),b.hide(),v.show())},j=function(e){b.show().children(".elfinder-spinner-text").text(e.info)},C=function(e){n.request({data:{cmd:"editor",name:"OnlineConvert",method:"api","args[jobid]":e},preventDefault:!0}).done(function(e){O(e.apires)}).fail(function(e){e&&n.error(e),s.elfinderdialog("destroy")})},M=function(e){var i=e.output,o=(e.id,"");b.hide(),i&&i.length&&(s.elfinderdialog("destroy"),$.each(i,function(e,t){t.uri&&(o+=t.uri+"\n")}),n.upload({target:t.phash,files:[o],type:"text",extraData:{contentSaveId:"OnlineConvert-"+e.id}}))},T="document";v.parent().css({overflow:"auto"}).addClass("overflow-scrolling-touch"),(r=t.mime.match(/^(audio|image|video)/))&&(T=r[1]),c.useTabs?p[T]&&h.tabs("option","active",p[T]):(a=Object.keys(c.conv).length,$.each(c.conv,function(e){return e.toLowerCase()===T?(g(e,function(){$.each(c.conv,function(e){e.toLowerCase()!==T&&g(e)})}),!1):void a--}),a||$.each(c.conv,function(e){g(e)}),v.parent().scrollTop(h.children(".onlineconvert-fieldset-"+T).offset().top))},load:function(){},getContent:function(){},save:function(){},close:function(e){var t=(this.fm,$(e).data("dfrd"));t&&"pending"===t.state()&&t.reject()}}]},window.elFinder); \ No newline at end of file diff --git a/lib/redactor/elfinder/js/extras/encoding-japanese.min.js b/lib/redactor/elfinder/js/extras/encoding-japanese.min.js new file mode 100644 index 0000000..a02f62a --- /dev/null +++ b/lib/redactor/elfinder/js/extras/encoding-japanese.min.js @@ -0,0 +1,35 @@ +/*! + * encoding-japanese v1.0.25 - Converts character encoding. + * Copyright (c) 2013-2016 polygon planet + * https://github.com/polygonplanet/encoding.js + * @license MIT + */ +!function(a,b,c){"undefined"!=typeof exports?"undefined"!=typeof module&&module.exports?module.exports=c():exports[a]=c():"function"==typeof define&&define.amd?define(c):b[a]=c()}("Encoding",this,function(){"use strict";function a(a){for(var b,c=0,d=a&&a.length;c255)return!1;if(b>=0&&b<=7||255===b)return!0}return!1}function b(a){for(var b,c=0,d=a&&a.length;c255||b>=128&&b<=255||27===b)return!1;return!0}function c(a){for(var b,c,d,e=0,f=a&&a.length;e255||b>=128&&b<=255)return!1;if(27===b){if(e+2>=f)return!1;if(c=a[e+1],d=a[e+2],36===c){if(40===d||64===d||66===d)return!0}else{if(38===c&&64===d)return!0;if(40===c&&(66===d||73===d||74===d))return!0}}}return!1}function d(a){for(var b,c=0,d=a&&a.length;c255||b<142)return!1;if(142===b){if(c+1>=d)return!1;if(b=a[++c],b<161||223=d)return!1;if(b=a[++c],b<162||237=d)return!1;if(b=a[++c],b<161||254128;)if(a[c++]>255)return!1;for(;c239||c+1>=d)return!1;if(b=a[++c],b<64||127===b||b>252)return!1}return!0}function f(a){for(var b,c=0,d=a&&a.length;c255)return!1;if(!(9===b||10===b||13===b||b>=32&&b<=126))if(b>=194&&b<=223){if(c+1>=d||a[c+1]<128||a[c+1]>191)return!1;c++}else if(224===b){if(c+2>=d||a[c+1]<160||a[c+1]>191||a[c+2]<128||a[c+2]>191)return!1;c+=2}else if(b>=225&&b<=236||238===b||239===b){if(c+2>=d||a[c+1]<128||a[c+1]>191||a[c+2]<128||a[c+2]>191)return!1;c+=2}else if(237===b){if(c+2>=d||a[c+1]<128||a[c+1]>159||a[c+2]<128||a[c+2]>191)return!1;c+=2}else if(240===b){if(c+3>=d||a[c+1]<144||a[c+1]>191||a[c+2]<128||a[c+2]>191||a[c+3]<128||a[c+3]>191)return!1;c+=3}else if(b>=241&&b<=243){if(c+3>=d||a[c+1]<128||a[c+1]>191||a[c+2]<128||a[c+2]>191||a[c+3]<128||a[c+3]>191)return!1;c+=3}else{if(244!==b)return!1;if(c+3>=d||a[c+1]<128||a[c+1]>143||a[c+2]<128||a[c+2]>191||a[c+3]<128||a[c+3]>191)return!1;c+=3}}return!0}function g(a){var b,c,d,e,f=0,g=a&&a.length,h=null;if(g<2){if(a[0]>255)return!1}else{if(b=a[0],c=a[1],255===b&&254===c)return!0;if(254===b&&255===c)return!0;for(;f255)return!1}if(null===h)return!1;if(d=a[h+1],void 0!==d&&d>0&&d<128)return!0;if(e=a[h-1],void 0!==e&&e>0&&e<128)return!0}return!1}function h(a){var b,c,d=0,e=a&&a.length,f=null;if(e<2){if(a[0]>255)return!1}else{if(b=a[0],c=a[1],254===b&&255===c)return!0;for(;d255)return!1}if(null===f)return!1;if(f%2===0)return!0}return!1}function i(a){var b,c,d=0,e=a&&a.length,f=null;if(e<2){if(a[0]>255)return!1}else{if(b=a[0],c=a[1],255===b&&254===c)return!0;for(;d255)return!1}if(null===f)return!1;if(f%2!==0)return!0}return!1}function j(a){var b,c,d,e,f,g,h=0,i=a&&a.length,j=null;if(i<4){for(;h255)return!1}else{if(b=a[0],c=a[1],d=a[2],e=a[3],0===b&&0===c&&254===d&&255===e)return!0;if(255===b&&254===c&&0===d&&0===e)return!0;for(;h255)return!1}if(null===j)return!1;if(f=a[j+3],void 0!==f&&f>0&&f<=127)return 0===a[j+2]&&0===a[j+1];if(g=a[j-1],void 0!==g&&g>0&&g<=127)return 0===a[j+1]&&0===a[j+2]}return!1}function k(a){for(var b,c=0,d=a&&a.length;c1114111)return!1;return!0}function l(a){for(var b,c,d=[],e=0,f=0,g=a&&a.length;f>=1,b<47?b+=113:b-=79,c+=c>95?32:31):(b>>=1,b<=47?b+=112:b-=80,c+=126),d[d.length]=255&b,d[d.length]=255&c):2===e?d[d.length]=a[f]+128&255:3===e?d[d.length]=Da:d[d.length]=255&a[f]}return d}function m(a){for(var b=[],c=0,d=a&&a.length,e=0;e=161&&b<=223?(2!==e&&(e=2,d[d.length]=h[6],d[d.length]=h[7],d[d.length]=h[8]),d[d.length]=b-128&255):b>=128?(1!==e&&(e=1,d[d.length]=h[3],d[d.length]=h[4],d[d.length]=h[5]),b<<=1,c=a[++g],c<159?(b-=b<319?225:97,c-=c>126?32:31):(b-=b<319?224:96,c-=126),d[d.length]=255&b,d[d.length]=255&c):(0!==e&&(e=0,d[d.length]=h[0],d[d.length]=h[1],d[d.length]=h[2]),d[d.length]=255&b);return 0!==e&&(d[d.length]=h[0],d[d.length]=h[1],d[d.length]=h[2]),d}function o(a){for(var b,c,d=[],e=a&&a.length,f=0;f=161&&b<=223?(d[d.length]=142,d[d.length]=b):b>=129?(c=a[++f],b<<=1,c<159?(b-=b<319?97:225,c+=c>126?96:97):(b-=b<319?96:224,c+=2),d[d.length]=255&b,d[d.length]=255&c):d[d.length]=255&b;return d}function p(a){for(var b,c=[],d=0,e=a&&a.length,f=0,g=[27,40,66,27,36,66,27,40,73,27,36,40,68];f142?(1!==d&&(d=1,c[c.length]=g[3],c[c.length]=g[4],c[c.length]=g[5]),c[c.length]=b-128&255,c[c.length]=a[++f]-128&255):(0!==d&&(d=0,c[c.length]=g[0],c[c.length]=g[1],c[c.length]=g[2]),c[c.length]=255&b);return 0!==d&&(c[c.length]=g[0],c[c.length]=g[1],c[c.length]=g[2]),c}function q(a){for(var b,c,d=[],e=a&&a.length,f=0;f142?(c=a[++f],1&b?(b>>=1,b+=b<111?49:113,c-=c>223?96:97):(b>>=1,b+=b<=111?48:112,c-=2),d[d.length]=255&b,d[d.length]=255&c):142===b?d[d.length]=255&a[++f]:d[d.length]=255&b;return d}function r(a){Ca();for(var b,c,d,e,f,g,h,i=[],j=0,k=a&&a.length;j=161&&b<=223?(d=b-64,e=188|d>>6&3,f=128|63&d,i[i.length]=239,i[i.length]=255&e,i[i.length]=255&f):b>=128?(c=b<<1,d=a[++j],d<159?(c-=c<319?225:97,d-=d>126?32:31):(c-=c<319?224:96,d-=126),c&=255,g=(c<<8)+d,h=Ya[g],void 0===h?i[i.length]=Da:h<65535?(i[i.length]=h>>8&255,i[i.length]=255&h):(i[i.length]=h>>16&255,i[i.length]=h>>8&255,i[i.length]=255&h)):i[i.length]=255&a[j];return i}function s(a){Ca();for(var b,c,d,e,f,g,h,i,j=[],k=0,l=a&&a.length;k>6&3,e=128|63&c,j[j.length]=239,j[j.length]=255&d,j[j.length]=255&e):143===b?(f=a[++k]-128,g=a[++k]-128,h=(f<<8)+g,i=Za[h],void 0===i?j[j.length]=Da:i<65535?(j[j.length]=i>>8&255,j[j.length]=255&i):(j[j.length]=i>>16&255,j[j.length]=i>>8&255,j[j.length]=255&i)):b>=128?(h=(b-128<<8)+(a[++k]-128),i=Ya[h],void 0===i?j[j.length]=Da:i<65535?(j[j.length]=i>>8&255,j[j.length]=255&i):(j[j.length]=i>>16&255,j[j.length]=i>>8&255,j[j.length]=255&i)):j[j.length]=255&a[k];return j}function t(a){Ca();for(var b,c,d,e,f,g=[],h=0,i=0,j=a&&a.length;i>8&255,g[g.length]=255&f):(g[g.length]=f>>16&255,g[g.length]=f>>8&255,g[g.length]=255&f)):2===h?(b=a[i]+64,c=188|b>>6&3,d=128|63&b,g[g.length]=239,g[g.length]=255&c,g[g.length]=255&d):3===h?(e=(a[i]<<8)+a[++i],f=Za[e],void 0===f?g[g.length]=Da:f<65535?(g[g.length]=f>>8&255,g[g.length]=255&f):(g[g.length]=f>>16&255,g[g.length]=f>>8&255,g[g.length]=255&f)):g[g.length]=255&a[i]}return g}function u(a){for(var b,c,d,e,f,g=[],h=0,i=a&&a.length;h=128?(e=b<=223?(b<<8)+a[++h]:(b<<16)+(a[++h]<<8)+(255&a[++h]), +f=Wa[e],void 0===f?g[g.length]=Da:f<255?g[g.length]=f+128:(f>65536&&(f-=65536),c=f>>8,d=255&f,1&c?(c>>=1,c<47?c+=113:c-=79,d+=d>95?32:31):(c>>=1,c<=47?c+=112:c-=80,d+=126),g[g.length]=255&c,g[g.length]=255&d)):g[g.length]=255&a[h];return g}function v(a){for(var b,c,d,e=[],f=0,g=a&&a.length;f=128?(c=b<=223?(a[f++]<<8)+a[f]:(a[f++]<<16)+(a[f++]<<8)+(255&a[f]),d=Wa[c],void 0===d?(d=Xa[c],void 0===d?e[e.length]=Da:(e[e.length]=143,e[e.length]=(d>>8)-128&255,e[e.length]=(255&d)-128&255)):(d>65536&&(d-=65536),d<255?(e[e.length]=142,e[e.length]=d-128&255):(e[e.length]=(d>>8)-128&255,e[e.length]=(255&d)-128&255))):e[e.length]=255&a[f];return e}function w(a){for(var b,c,d,e=[],f=0,g=a&&a.length,h=0,i=[27,40,66,27,36,66,27,40,73,27,36,40,68];h>8&255,e[e.length]=255&d)):(d>65536&&(d-=65536),d<255?(2!==f&&(f=2,e[e.length]=i[6],e[e.length]=i[7],e[e.length]=i[8]),e[e.length]=255&d):(1!==f&&(f=1,e[e.length]=i[3],e[e.length]=i[4],e[e.length]=i[5]),e[e.length]=d>>8&255,e[e.length]=255&d)));return 0!==f&&(e[e.length]=i[0],e[e.length]=i[1],e[e.length]=i[2]),e}function x(a){for(var b,c,d=[],e=0,f=a&&a.length;e=55296&&b<=56319&&e+1=56320&&c<=57343&&(b=1024*(b-55296)+c-56320+65536,e++)),b<128?d[d.length]=b:b<2048?(d[d.length]=192|b>>6&31,d[d.length]=128|63&b):b<65536?(d[d.length]=224|b>>12&15,d[d.length]=128|b>>6&63,d[d.length]=128|63&b):b<2097152&&(d[d.length]=240|b>>18&15,d[d.length]=128|b>>12&63,d[d.length]=128|b>>6&63,d[d.length]=128|63&b);return d}function y(a){for(var b,c,d,e,f,g,h=[],i=0,j=a&&a.length;i>4,b>=0&&b<=7?g=c:12===b||13===b?(d=a[i++],g=(31&c)<<6|63&d):14===b?(d=a[i++],e=a[i++],g=(15&c)<<12|(63&d)<<6|63&e):15===b&&(d=a[i++],e=a[i++],f=a[i++],g=(7&c)<<18|(63&d)<<12|(63&e)<<6|63&f),g<=65535?h[h.length]=g:(g-=65536,h[h.length]=(g>>10)+55296,h[h.length]=g%1024+56320);return h}function z(a,b){var c;if(b&&b.bom){var d=b.bom;qa(d)||(d="BE");var e,f;"B"===d.charAt(0).toUpperCase()?(e=[254,255],f=A(a)):(e=[255,254],f=B(a)),c=[],c[0]=e[0],c[1]=e[1];for(var g=0,h=f.length;g>8&255,c[c.length]=255&b);return c}function B(a){for(var b,c=[],d=0,e=a&&a.length;d>8&255);return c}function C(a){var b,c,d=[],e=0,f=a&&a.length;for(f>=2&&(254===a[0]&&255===a[1]||255===a[0]&&254===a[1])&&(e=2);e=2&&(254===a[0]&&255===a[1]||255===a[0]&&254===a[1])&&(e=2);e=2&&(254===a[0]&&255===a[1]||255===a[0]&&254===a[1])&&(h=2),c&&(f[0]=c[0],f[1]=c[1]);for(var i,j;h=2&&(254===a[0]&&255===a[1]||255===a[0]&&254===a[1])&&(h=2),c&&(f[0]=c[0],f[1]=c[1]);for(var i,j;h=2&&(254===a[0]&&255===a[1]||255===a[0]&&254===a[1])&&(e=2);eLa&&(Ma=!0),c}catch(a){Ma=!1}}}return va(a)}function va(a){for(var b,c="",d=a&&a.length,e=0;eLa&&(Ma=!0);continue}catch(a){Ma=!1}return wa(a)}c+=Ea.apply(null,b)}return c}function wa(a){for(var b="",c=a&&a.length,d=0;d>2],b[b.length]=Ta[(3&e)<<4],b[b.length]=Va,b[b.length]=Va;break}if(f=a[c++],c==d){b[b.length]=Ta[e>>2],b[b.length]=Ta[(3&e)<<4|(240&f)>>4],b[b.length]=Ta[(15&f)<<2],b[b.length]=Va;break}g=a[c++],b[b.length]=Ta[e>>2],b[b.length]=Ta[(3&e)<<4|(240&f)>>4],b[b.length]=Ta[(15&f)<<2|(192&g)>>6],b[b.length]=Ta[63&g]}return ua(b)}function Ba(a){var b,c,d,e,f,g,h;for(g=a&&a.length,f=0,h=[];f>4;do{if(d=255&a.charCodeAt(f++),61==d)return h;d=Ua[d]}while(f>2; +do{if(e=255&a.charCodeAt(f++),61==e)return h;e=Ua[e]}while(f95&&(Ya[b]=0|a);for(Za={},c=ra(Xa),e=c.length,d=0;d255)return encodeURIComponent(ua(a));b>=97&&b<=122||b>=65&&b<=90||b>=48&&b<=57||33===b||b>=39&&b<=42||45===b||46===b||95===b||126===b?d[d.length]=b:(d[d.length]=37,b<16?(d[d.length]=48,d[d.length]=c[b]):(d[d.length]=c[b>>4&15],d[d.length]=c[15&b]))}return ua(d)},urlDecode:function(a){for(var b,c=[],d=0,e=a&&a.length;d=65281&&c<=65374&&(c-=65248),d[d.length]=c;return b?ua(d):d},toZenkakuCase:function(a){var b=!1;qa(a)&&(b=!0,a=ta(a));for(var c,d=[],e=a&&a.length,f=0;f=33&&c<=126&&(c+=65248),d[d.length]=c;return b?ua(d):d},toHiraganaCase:function(a){var b=!1;qa(a)&&(b=!0,a=ta(a));for(var c,d=[],e=a&&a.length,f=0;f=12449&&c<=12534?c-=96:12535===c?(d[d.length]=12431,c=12443):12538===c&&(d[d.length]=12434,c=12443),d[d.length]=c;return b?ua(d):d},toKatakanaCase:function(a){var b=!1;qa(a)&&(b=!0,a=ta(a));for(var c,d=[],e=a&&a.length,f=0;f=12353&&c<=12438&&((12431===c||12434===c)&&f=12289&&c<=12540&&(e=$a[c],void 0!==e)?f[f.length]=e:12532===c||12535===c||12538===c?(f[f.length]=_a[c],f[f.length]=65438):c>=12459&&c<=12489?(f[f.length]=$a[c-1],f[f.length]=65438):c>=12495&&c<=12509?(d=c%3,f[f.length]=$a[c-d],f[f.length]=ab[d-1]):f[f.length]=c;return b?ua(f):f},toZenkanaCase:function(a){var b=!1;qa(a)&&(b=!0,a=ta(a));var c,d,e,f=[],g=a&&a.length,h=0;for(h=0;h65376&&c<65440&&(d=bb[c-65377],h+165397&&c<65413||c>65417&&c<65423)?(d++,h++):65439===e&&c>65417&&c<65423&&(d+=2,h++)),c=d),f[f.length]=c;return b?ua(f):f},toHankakuSpace:function(a){if(qa(a))return a.replace(/\u3000/g," ");for(var b,c=[],d=a&&a.length,e=0;e
                      ').appendTo(ql.info.find('.elfinder-quicklook-info')) + .on('click', function() { + $(this).html(''); + fm.request({ + data : {cmd : 'url', target : file.hash}, + preventDefault : true + }) + .always(function() { + preview.show(); + $(this).html(''); + }) + .done(function(data) { + var rfile = fm.file(file.hash); + ql.value.url = rfile.url = data.url || ''; + if (ql.value.url) { + preview.trigger($.Event('update', {file : ql.value})); + } + }); + }); + } + if (file.url !== '' && file.url != '1') { + e.stopImmediatePropagation(); + + loading = $('
                      '+fm.i18n('nowLoading')+'
                      ').appendTo(ql.info.find('.elfinder-quicklook-info')); + + node = $('') + .css('background-color', 'transparent') + .on('load', function() { + ql.hideinfo(); + loading.remove(); + node.css('background-color', '#fff'); + }) + .on('error', function() { + loading.remove(); + node.remove(); + }) + .appendTo(preview) + .attr('src', fm.url(file.hash)); + + preview.one('change', function() { + loading.remove(); + node.off('load').remove(); + }); + } + } + + }); + }); +} catch(e) {} +})); diff --git a/lib/redactor/elfinder/js/extras/quicklook.googledocs.min.js b/lib/redactor/elfinder/js/extras/quicklook.googledocs.min.js new file mode 100644 index 0000000..3c33cb6 --- /dev/null +++ b/lib/redactor/elfinder/js/extras/quicklook.googledocs.min.js @@ -0,0 +1 @@ +!function(e,n){"function"==typeof define&&define.amd?define(["elfinder"],n):"undefined"!=typeof exports?module.exports=n(require("elfinder")):n(e.elFinder)}(this,function(e){"use strict";try{e.prototype.commands.quicklook.plugins||(e.prototype.commands.quicklook.plugins=[]),e.prototype.commands.quicklook.plugins.push(function(e){var n=e.fm,o=e.preview;o.on("update",function(i){var r,a,t=(e.window,i.file);0===t.mime.indexOf("application/vnd.google-apps.")&&("1"==t.url&&(o.hide(),$('
                      ").appendTo(e.info.find(".elfinder-quicklook-info")).on("click",function(){$(this).html(''),n.request({data:{cmd:"url",target:t.hash},preventDefault:!0}).always(function(){o.show(),$(this).html("")}).done(function(i){var r=n.file(t.hash);e.value.url=r.url=i.url||"",e.value.url&&o.trigger($.Event("update",{file:e.value}))})})),""!==t.url&&"1"!=t.url&&(i.stopImmediatePropagation(),a=$('
                      '+n.i18n("nowLoading")+'
                      ').appendTo(e.info.find(".elfinder-quicklook-info")),r=$('').css("background-color","transparent").on("load",function(){e.hideinfo(),a.remove(),r.css("background-color","#fff")}).on("error",function(){a.remove(),r.remove()}).appendTo(o).attr("src",n.url(t.hash)),o.one("change",function(){a.remove(),r.off("load").remove()})))})})}catch(n){}}); \ No newline at end of file diff --git a/lib/redactor/elfinder/js/i18n/elfinder.LANG.js b/lib/redactor/elfinder/js/i18n/elfinder.LANG.js new file mode 100644 index 0000000..8995a51 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.LANG.js @@ -0,0 +1,594 @@ +/** + * elFinder translation template + * use this file to create new translation + * submit new translation via https://github.com/Studio-42/elFinder/issues + * or make a pull request + */ + +/** + * XXXXX translation + * @author Translator Name + * @version 201x-xx-xx + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.REPLACE_WITH_xx_OR_xx_YY_LANG_CODE = { + translator : 'Translator name <translator@email.tld>', + language : 'Language of translation in your language', + direction : 'ltr', + dateFormat : 'M d, Y h:i A', // will show like: Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will show like: Today 12:25 PM + nonameDateFormat : 'ymd-His', // noname upload will show like: 120513-172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Error', + 'errUnknown' : 'Unknown error.', + 'errUnknownCmd' : 'Unknown command.', + 'errJqui' : 'Invalid jQuery UI configuration. Selectable, draggable and droppable components must be included.', + 'errNode' : 'elFinder requires DOM Element to be created.', + 'errURL' : 'Invalid elFinder configuration! URL option is not set.', + 'errAccess' : 'Access denied.', + 'errConnect' : 'Unable to connect to backend.', + 'errAbort' : 'Connection aborted.', + 'errTimeout' : 'Connection timeout.', + 'errNotFound' : 'Backend not found.', + 'errResponse' : 'Invalid backend response.', + 'errConf' : 'Invalid backend configuration.', + 'errJSON' : 'PHP JSON module not installed.', + 'errNoVolumes' : 'Readable volumes not available.', + 'errCmdParams' : 'Invalid parameters for command "$1".', + 'errDataNotJSON' : 'Data is not JSON.', + 'errDataEmpty' : 'Data is empty.', + 'errCmdReq' : 'Backend request requires command name.', + 'errOpen' : 'Unable to open "$1".', + 'errNotFolder' : 'Object is not a folder.', + 'errNotFile' : 'Object is not a file.', + 'errRead' : 'Unable to read "$1".', + 'errWrite' : 'Unable to write into "$1".', + 'errPerm' : 'Permission denied.', + 'errLocked' : '"$1" is locked and can not be renamed, moved or removed.', + 'errExists' : 'Item named "$1" already exists.', + 'errInvName' : 'Invalid file name.', + 'errInvDirname' : 'Invalid folder name.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Folder not found.', + 'errFileNotFound' : 'File not found.', + 'errTrgFolderNotFound' : 'Target folder "$1" not found.', + 'errPopup' : 'Browser prevented opening popup window. To open file enable it in browser options.', + 'errMkdir' : 'Unable to create folder "$1".', + 'errMkfile' : 'Unable to create file "$1".', + 'errRename' : 'Unable to rename "$1".', + 'errCopyFrom' : 'Copying files from volume "$1" not allowed.', + 'errCopyTo' : 'Copying files to volume "$1" not allowed.', + 'errMkOutLink' : 'Unable to create a link to outside the volume root.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Upload error.', // old name - errUploadCommon + 'errUploadFile' : 'Unable to upload "$1".', // old name - errUpload + 'errUploadNoFiles' : 'No files found for upload.', + 'errUploadTotalSize' : 'Data exceeds the maximum allowed size.', // old name - errMaxSize + 'errUploadFileSize' : 'File exceeds maximum allowed size.', // old name - errFileMaxSize + 'errUploadMime' : 'File type not allowed.', + 'errUploadTransfer' : '"$1" transfer error.', + 'errUploadTemp' : 'Unable to make temporary file for upload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', // new + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : 'Unable to save "$1".', + 'errCopy' : 'Unable to copy "$1".', + 'errMove' : 'Unable to move "$1".', + 'errCopyInItself' : 'Unable to copy "$1" into itself.', + 'errRm' : 'Unable to remove "$1".', + 'errTrash' : 'Unable into trash.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'Unable to extract files from "$1".', + 'errArchive' : 'Unable to create archive.', + 'errArcType' : 'Unsupported archive type.', + 'errNoArchive' : 'File is not archive or has unsupported archive type.', + 'errCmdNoSupport' : 'Backend does not support this command.', + 'errReplByChild' : 'The folder "$1" can\'t be replaced by an item it contains.', + 'errArcSymlinks' : 'For security reason denied to unpack archives contains symlinks or files with not allowed names.', // edited 24.06.2012 + 'errArcMaxSize' : 'Archive files exceeds maximum allowed size.', + 'errResize' : 'Unable to resize "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', // added 7.3.2013 + 'errResizeRotate' : 'Unable to rotate image.', // added 7.3.2013 + 'errResizeSize' : 'Invalid image size.', // added 7.3.2013 + 'errResizeNoChange' : 'Image size not changed.', // added 7.3.2013 + 'errUsupportType' : 'Unsupported file type.', + 'errNotUTF8Content' : 'File "$1" is not in UTF-8 and cannot be edited.', // added 9.11.2011 + 'errNetMount' : 'Unable to mount "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Unsupported protocol.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount failed.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host required.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + 'errNetUnMount' : 'Unable to unmount.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Not convertible to UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Try the modern browser, If you\'d like to upload the folder.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Timed out while searching "$1". Search result is partial.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Re-authorization is required.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Max number of selectable items is $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Unable to restore from the trash. Can\'t identify the restore destination.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor not found to this file type.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Error occurred on the server side.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Unable to empty folder "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'There are $1 more errors.', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'You can create up to $1 folders at one time.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Create archive', + 'cmdback' : 'Back', + 'cmdcopy' : 'Copy', + 'cmdcut' : 'Cut', + 'cmddownload' : 'Download', + 'cmdduplicate' : 'Duplicate', + 'cmdedit' : 'Edit file', + 'cmdextract' : 'Extract files from archive', + 'cmdforward' : 'Forward', + 'cmdgetfile' : 'Select files', + 'cmdhelp' : 'About this software', + 'cmdhome' : 'Root', + 'cmdinfo' : 'Get info', + 'cmdmkdir' : 'New folder', + 'cmdmkdirin' : 'Into New Folder', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'New file', + 'cmdopen' : 'Open', + 'cmdpaste' : 'Paste', + 'cmdquicklook' : 'Preview', + 'cmdreload' : 'Reload', + 'cmdrename' : 'Rename', + 'cmdrm' : 'Delete', + 'cmdtrash' : 'Into trash', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Restore', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Find files', + 'cmdup' : 'Go to parent folder', + 'cmdupload' : 'Upload files', + 'cmdview' : 'View', + 'cmdresize' : 'Resize & Rotate', + 'cmdsort' : 'Sort', + 'cmdnetmount' : 'Mount network volume', // added 18.04.2012 + 'cmdnetunmount': 'Unmount', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'To Places', // added 28.12.2014 + 'cmdchmod' : 'Change mode', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Open a folder', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Reset column width', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Full Screen', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Move', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Empty the folder', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Undo', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Redo', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferences', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Select all', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Select none', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Invert selection', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Open in new window', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Hide (Preference)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Close', + 'btnSave' : 'Save', + 'btnRm' : 'Remove', + 'btnApply' : 'Apply', + 'btnCancel' : 'Cancel', + 'btnNo' : 'No', + 'btnYes' : 'Yes', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', // added 18.04.2012 + 'btnApprove': 'Goto $1 & approve', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convert', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Here', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'All', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Type', // from v2.1 added 22.5.2015 + 'btnFileName':'Filename', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Save & Close', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Rename', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Rename(All)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Prev ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Next ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Save As', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Open folder', + 'ntffile' : 'Open file', + 'ntfreload' : 'Reload folder content', + 'ntfmkdir' : 'Creating folder', + 'ntfmkfile' : 'Creating files', + 'ntfrm' : 'Delete items', + 'ntfcopy' : 'Copy items', + 'ntfmove' : 'Move items', + 'ntfprepare' : 'Checking existing items', + 'ntfrename' : 'Rename files', + 'ntfupload' : 'Uploading files', + 'ntfdownload' : 'Downloading files', + 'ntfsave' : 'Save files', + 'ntfarchive' : 'Creating archive', + 'ntfextract' : 'Extracting files from archive', + 'ntfsearch' : 'Searching files', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Doing something', + 'ntfloadimg' : 'Loading image', + 'ntfnetmount' : 'Mounting network volume', // added 18.04.2012 + 'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Acquiring image dimension', // added 20.05.2013 + 'ntfreaddir' : 'Reading folder infomation', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Getting URL of link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Changing file mode', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Verifying upload file name', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Creating a file for download', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Getting path infomation', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Processing the uploaded file', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Doing throw in the trash', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Doing restore from the trash', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Checking destination folder', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Undoing previous operation', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Redoing previous undone', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Checking contents', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Trash', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'unknown', + 'Today' : 'Today', + 'Yesterday' : 'Yesterday', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'May', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Oct', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'January', + 'February' : 'February', + 'March' : 'March', + 'April' : 'April', + 'May' : 'May', + 'June' : 'June', + 'July' : 'July', + 'August' : 'August', + 'September' : 'September', + 'October' : 'October', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Sunday', + 'Monday' : 'Monday', + 'Tuesday' : 'Tuesday', + 'Wednesday' : 'Wednesday', + 'Thursday' : 'Thursday', + 'Friday' : 'Friday', + 'Saturday' : 'Saturday', + 'Sun' : 'Sun', + 'Mon' : 'Mon', + 'Tue' : 'Tue', + 'Wed' : 'Wed', + 'Thu' : 'Thu', + 'Fri' : 'Fri', + 'Sat' : 'Sat', + + /******************************** sort variants ********************************/ + 'sortname' : 'by name', + 'sortkind' : 'by kind', + 'sortsize' : 'by size', + 'sortdate' : 'by date', + 'sortFoldersFirst' : 'Folders first', + 'sortperm' : 'by permission', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'by mode', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'by owner', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'by group', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Also Treeview', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NewFile.txt', // added 10.11.2015 + 'untitled folder' : 'NewFolder', // added 10.11.2015 + 'Archive' : 'NewArchive', // from v2.1 added 10.11.2015 + 'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: File', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Confirmation required', + 'confirmRm' : 'Are you sure you want to permanently remove items?
                      This cannot be undone!', + 'confirmRepl' : 'Replace old file with new one? (If it contains folders, it will be merged. To backup and replace, select Backup.)', + 'confirmRest' : 'Replace existing item with the item in trash?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Not in UTF-8
                      Convert to UTF-8?
                      Contents become UTF-8 by saving after conversion.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Character encoding of this file couldn\'t be detected. It need to temporarily convert to UTF-8 for editting.
                      Please select character encoding of this file.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'It has been modified.
                      Losing work if you do not save changes.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Are you sure you want to move items to trash bin?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Are you sure you want to move items to "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Apply to all', + 'name' : 'Name', + 'size' : 'Size', + 'perms' : 'Permissions', + 'modify' : 'Modified', + 'kind' : 'Kind', + 'read' : 'read', + 'write' : 'write', + 'noaccess' : 'no access', + 'and' : 'and', + 'unknown' : 'unknown', + 'selectall' : 'Select all items', + 'selectfiles' : 'Select item(s)', + 'selectffile' : 'Select first item', + 'selectlfile' : 'Select last item', + 'viewlist' : 'List view', + 'viewicons' : 'Icons view', + 'viewSmall' : 'Small icons', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Medium icons', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Large icons', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Extra large icons', // from v2.1.39 added 22.5.2018 + 'places' : 'Places', + 'calc' : 'Calculate', + 'path' : 'Path', + 'aliasfor' : 'Alias for', + 'locked' : 'Locked', + 'dim' : 'Dimensions', + 'files' : 'Files', + 'folders' : 'Folders', + 'items' : 'Items', + 'yes' : 'yes', + 'no' : 'no', + 'link' : 'Link', + 'searcresult' : 'Search results', + 'selected' : 'selected items', + 'about' : 'About', + 'shortcuts' : 'Shortcuts', + 'help' : 'Help', + 'webfm' : 'Web file manager', + 'ver' : 'Version', + 'protocolver' : 'protocol version', + 'homepage' : 'Project home', + 'docs' : 'Documentation', + 'github' : 'Fork us on GitHub', + 'twitter' : 'Follow us on Twitter', + 'facebook' : 'Join us on Facebook', + 'team' : 'Team', + 'chiefdev' : 'chief developer', + 'developer' : 'developer', + 'contributor' : 'contributor', + 'maintainer' : 'maintainer', + 'translator' : 'translator', + 'icons' : 'Icons', + 'dontforget' : 'and don\'t forget to take your towel', + 'shortcutsof' : 'Shortcuts disabled', + 'dropFiles' : 'Drop files here', + 'or' : 'or', + 'selectForUpload' : 'Select files', + 'moveFiles' : 'Move items', + 'copyFiles' : 'Copy items', + 'restoreFiles' : 'Restore items', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Remove from places', + 'aspectRatio' : 'Aspect ratio', + 'scale' : 'Scale', + 'width' : 'Width', + 'height' : 'Height', + 'resize' : 'Resize', + 'crop' : 'Crop', + 'rotate' : 'Rotate', + 'rotate-cw' : 'Rotate 90 degrees CW', + 'rotate-ccw' : 'Rotate 90 degrees CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'User', // added 18.04.2012 + 'pass' : 'Password', // added 18.04.2012 + 'confirmUnmount' : 'Are you unmount $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Drop or Paste files from browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Drop files, Paste URLs or images(clipboard) here', // from v2.1 added 07.04.2014 + 'encoding' : 'Encoding', // from v2.1 added 19.12.2014 + 'locale' : 'Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Target: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Search by input MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Owner', // from v2.1 added 20.6.2015 + 'group' : 'Group', // from v2.1 added 20.6.2015 + 'other' : 'Other', // from v2.1 added 20.6.2015 + 'execute' : 'Execute', // from v2.1 added 20.6.2015 + 'perm' : 'Permission', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Folder is empty', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Folder is empty\\A Drop to add items', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Folder is empty\\A Long tap to add items', // from v2.1.6 added 30.12.2015 + 'quality' : 'Quality', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto sync', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Move up', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Get URL link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Selected items ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Folder ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Allow offline access', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'To re-authenticate', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Now loading...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Open multiple files', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'You are trying to open the $1 files. Are you sure you want to open in browser?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Search results is empty in search target.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'It is editing a file.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'You have selected $1 items.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'You have $1 items in the clipboard.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Incremental search is only from the current view.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Reinstate', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 complete', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Context menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Page turning', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016 + 'reset' : 'Reset', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Background color', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Color picker', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Grid', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Enabled', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Disabled', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Search results is empty in current view.\\APress [Enter] to expand search target.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'First letter search results is empty in current view.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Text label', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 mins left', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Select folder', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'First letter search', // from v2.1.23 added 24.3.2017 + 'presets' : 'Presets', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'It\'s too many items so it can\'t into trash.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Empty the folder "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'There are no items in a folder "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preference', // from v2.1.26 added 28.6.2017 + 'language' : 'Language', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialize the settings saved in this browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Toolbar settings', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 chars left.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 lines left.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Sum', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Rough file size', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focus on the element of dialog with mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Select', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Action when select file', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Open with the editor used last time', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Invert selection', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Are you sure you want to rename $1 selected items like $2?
                      This cannot be undone!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch rename', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Number', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Add prefix', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Add suffix', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Change extention', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Columns settings (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'All changes will reflect immediately to the archive.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Any changes will not reflect until un-mount this volume.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Selection Info', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorithms to show the file hash', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Press again to exit.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Toolbar', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Work Space', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'All', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Icon Size (Icons view)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Open the maximized editor window', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Because conversion by API is not currently available, please convert on the website.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Convert on the site of $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrations', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'This elFinder has the following external services integrated. Please check the terms of use, privacy policy, etc. before using it.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Show hidden items', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Hide hidden items', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Show/Hide hidden items', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'File types to enable with "New file"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type of the Text file', // from v2.1.41 added 7.8.2018 + 'add' : 'Add', // from v2.1.41 added 7.8.2018 + 'theme' : 'Theme', // from v2.1.43 added 19.10.2018 + 'default' : 'Default', // from v2.1.43 added 19.10.2018 + 'description' : 'Description', // from v2.1.43 added 19.10.2018 + 'website' : 'Website', // from v2.1.43 added 19.10.2018 + 'author' : 'Author', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'License', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'This item can\'t be saved. To avoid losing the edits you need to export to your PC.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Double click on the file to select it.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Use fullscreen mode', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Unknown', + 'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Folder', + 'kindSelects' : 'Selections', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Broken alias', + // applications + 'kindApp' : 'Application', + 'kindPostscript' : 'Postscript document', + 'kindMsOffice' : 'Microsoft Office document', + 'kindMsWord' : 'Microsoft Word document', + 'kindMsExcel' : 'Microsoft Excel document', + 'kindMsPP' : 'Microsoft Powerpoint presentation', + 'kindOO' : 'Open Office document', + 'kindAppFlash' : 'Flash application', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent file', + 'kind7z' : '7z archive', + 'kindTAR' : 'TAR archive', + 'kindGZIP' : 'GZIP archive', + 'kindBZIP' : 'BZIP archive', + 'kindXZ' : 'XZ archive', + 'kindZIP' : 'ZIP archive', + 'kindRAR' : 'RAR archive', + 'kindJAR' : 'Java JAR file', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM package', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Text document', + 'kindTextPlain' : 'Plain text', + 'kindPHP' : 'PHP source', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML document', + 'kindJS' : 'Javascript source', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C source', + 'kindCHeader' : 'C header source', + 'kindCPP' : 'C++ source', + 'kindCPPHeader' : 'C++ header source', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python source', + 'kindJava' : 'Java source', + 'kindRuby' : 'Ruby source', + 'kindPerl' : 'Perl script', + 'kindSQL' : 'SQL source', + 'kindXML' : 'XML document', + 'kindAWK' : 'AWK source', + 'kindCSV' : 'Comma separated values', + 'kindDOCBOOK' : 'Docbook XML document', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Image', + 'kindBMP' : 'BMP image', + 'kindJPEG' : 'JPEG image', + 'kindGIF' : 'GIF Image', + 'kindPNG' : 'PNG Image', + 'kindTIFF' : 'TIFF image', + 'kindTGA' : 'TGA image', + 'kindPSD' : 'Adobe Photoshop image', + 'kindXBITMAP' : 'X bitmap image', + 'kindPXM' : 'Pixelmator image', + // media + 'kindAudio' : 'Audio media', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video media', + 'kindVideoDV' : 'DV movie', + 'kindVideoMPEG' : 'MPEG movie', + 'kindVideoMPEG4' : 'MPEG-4 movie', + 'kindVideoAVI' : 'AVI movie', + 'kindVideoMOV' : 'Quick Time movie', + 'kindVideoWM' : 'Windows Media movie', + 'kindVideoFlash' : 'Flash movie', + 'kindVideoMKV' : 'Matroska movie', + 'kindVideoOGG' : 'Ogg movie' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ar.js b/lib/redactor/elfinder/js/i18n/elfinder.ar.js new file mode 100644 index 0000000..5e72e5f --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ar.js @@ -0,0 +1,587 @@ +/** + * الترجمة العربية + * @author Khamis Alqutob + * @author Tawfek Daghistani + * @author Atef Ben Ali + * @version 2020-12-03 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ar = { + translator : 'Khamis Alqutob <alqutob@outlook.com>, Tawfek Daghistani <tawfekov@gmail.com>, Atef Ben Ali <atef.bettaib@gmail.com>', + language : 'Arabic', + direction : 'rtl', + dateFormat : 'M d, Y h:i A', // will show like: Aug 24, 2018 04:39 PM + fancyDateFormat : '$1 h:i A', // will show like: Today 04:39 PM + nonameDateFormat : 'ymd-His', // noname upload will show like: 180824-163916 + messages : { + + /********************************** errors **********************************/ + 'error' : 'خطأ', + 'errUnknown' : 'خطأ غير معروف .', + 'errUnknownCmd' : 'أمر غير معروف .', + 'errJqui' : 'تكوين jQuery UI غير صالح. يجب تضمين المكونات القابلة للتحديد والقابلة للسحب والإفلات', + 'errNode' : 'يتطلب elFinder إنشاء عنصر DOM.', + 'errURL' : 'تكوين elFinder غير صالح ! لم يتم تعيين خيار رابط URL', + 'errAccess' : 'الوصول مرفوض .', + 'errConnect' : 'تعذر الاتصال مع خادم الخلفية', + 'errAbort' : 'تم فصل الإتصال', + 'errTimeout' : 'نفذ وقت الاتصال.', + 'errNotFound' : 'الخادوم الخلفي غير موجود .', + 'errResponse' : 'رد غير مقبول من الخادوم الخلفي', + 'errConf' : 'خطأ في الإعدادات الخاصة بالخادوم الخلفي ', + 'errJSON' : 'موديول PHP JSON module غير مثبت ', + 'errNoVolumes' : 'الأحجام المقروءة غير متوفرة', + 'errCmdParams' : 'معلمات غير صالحة للأمر "$1".', + 'errDataNotJSON' : 'البيانات ليست من نوع JSON ', + 'errDataEmpty' : 'البيانات فارغة', + 'errCmdReq' : 'الخادوم الخلفي يتطلب اسم الأمر ', + 'errOpen' : 'غير قادر على فتح "$1".', + 'errNotFolder' : 'العنصر ليس مجلد', + 'errNotFile' : 'العنصر ليس ملف', + 'errRead' : 'غير قادر على قراءة "$1".', + 'errWrite' : 'غير قادر على الكتابة في "$1".', + 'errPerm' : 'وصول مرفوض ', + 'errLocked' : '"$1" مقفل ولا يمكن إعادة تسميته أو نقله أو إزالته.', + 'errExists' : 'العنصر الذي يحمل الاسم "$1" موجود مسبقاً.', + 'errInvName' : 'اسم الملف غير صالح', + 'errInvDirname' : 'اسم مجلد غير صالح', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'المجلد غير موجود', + 'errFileNotFound' : 'الملف غير موجود', + 'errTrgFolderNotFound' : 'المجلد الهدف "$1" غير موجود ', + 'errPopup' : 'المتصفح منع من فتح نافذة منبثقة. لفتح ملف ، قم بتمكينه في خيارات المتصفح', + 'errMkdir' : ' غير قادر على إنشاء مجلد "$1".', + 'errMkfile' : ' غير قادر على إنشاء ملف "$1".', + 'errRename' : 'غير قادر على إعادة تسمية "$1".', + 'errCopyFrom' : 'نسخ الملفات من الدليل "$1" غير مسموح.', + 'errCopyTo' : 'نسخ الملفات إلى الدليل "$1" غير مسموح .', + 'errMkOutLink' : 'تعذر إنشاء رابط إلى خارج جذر الدليل.', // from v2.1 added 03.10.2015 + 'errUpload' : 'خطأ في عملية الرفع.', // old name - errUploadCommon + 'errUploadFile' : 'غير قادر على رفع "$1".', // old name - errUpload + 'errUploadNoFiles' : 'لم يتم العثور على ملفات للتحميل .', + 'errUploadTotalSize' : 'البيانات تتجاوز الحد الأقصى للحجم المسموح به.', // old name - errMaxSize + 'errUploadFileSize' : 'تجاوز الملف الحد الأقصى للحجم المسموح به.', // old name - errFileMaxSize + 'errUploadMime' : 'نوع الملف غير مسموح به.', + 'errUploadTransfer' : '"$1" خطأ نقل.', + 'errUploadTemp' : 'تعذر إنشاء ملف مؤقت للتحميل .', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'الكائن "$1" موجود بالفعل في هذا الموقع ولا يمكن استبداله بكائن بنوع آخر.', // new + 'errReplace' : 'غير قادر على استبدال "$1".', + 'errSave' : 'غير قادر على حفظ "$1".', + 'errCopy' : 'غير قادر على نسخ "$1".', + 'errMove' : 'غير قادر على نقل "$1".', + 'errCopyInItself' : 'غير قادر على نسخ "$1" داخل نفسه.', + 'errRm' : 'غير قادر على إزالة "$1".', + 'errTrash' : 'غير قادر في سلة المهملات', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'تعذر إزالة ملف (ملفات) المصدر.', + 'errExtract' : 'غير قادر على استخراج الملفات من "$1".', + 'errArchive' : 'غير قادر على إنشاء ملف مضغوط.', + 'errArcType' : 'نوع الملف المضغوط غير مدعوم.', + 'errNoArchive' : 'هذا الملف ليس ملف مضغوط أو ذو صيغة غير مدعومة.', + 'errCmdNoSupport' : 'الخادوم الخلفي لا يدعم هذا الأمر ', + 'errReplByChild' : 'لا يمكن استبدال المجلد "$1" بعنصر محتوِ فيه.', + 'errArcSymlinks' : 'لأسباب أمنية ، تم رفض فك ضغط الأرشيفات التي تحتوي على روابط رمزية أو ملفات بأسماء غير مسموح بها.', // edited 24.06.2012 + 'errArcMaxSize' : 'تتجاوز ملفات الأرشيف الحجم الأقصى المسموح به.', + 'errResize' : 'تعذر تغيير حجم "$1".', + 'errResizeDegree' : 'درجة تدوير غير صالحة.', // added 7.3.2013 + 'errResizeRotate' : 'تعذر تدوير الصورة.', // added 7.3.2013 + 'errResizeSize' : 'حجم الصورة غير صالح.', // added 7.3.2013 + 'errResizeNoChange' : 'حجم الصورة لم يتغير.', // added 7.3.2013 + 'errUsupportType' : 'نوع ملف غير مدعوم.', + 'errNotUTF8Content' : 'الملف "$1" ليس بتنسيق UTF-8 ولا يمكن تحريره.', // added 9.11.2011 + 'errNetMount' : 'غير قادر على التثبيت "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'بروتوكول غير مدعوم.', // added 17.04.2012 + 'errNetMountFailed' : 'فشل التثبيت.', // added 17.04.2012 + 'errNetMountHostReq' : 'المضيف مطلوب.', // added 18.04.2012 + 'errSessionExpires' : 'انتهت جلسة العمل الخاصة بك بسبب عدم الفاعلية.', + 'errCreatingTempDir' : 'تعذر إنشاء دليل مؤقت: "$1"', + 'errFtpDownloadFile' : 'تعذر تنزيل الملف من FTP: "$1"', + 'errFtpUploadFile' : 'تعذر تحميل الملف إلى FTP: "$1"', + 'errFtpMkdir' : 'تعذر إنشاء دليل عن بعد في FTP: "$1"', + 'errArchiveExec' : 'خطأ أثناء أرشفة الملفات: "$1"', + 'errExtractExec' : 'خطأ أثناء استخراج الملفات: "$1"', + 'errNetUnMount' : 'غير قادر على فك التثبيت.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'غير قابل للتحويل إلى UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'جرب المتصفح الحديث ، إذا كنت ترغب في تحميل المجلد.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'انتهت المهلة أثناء البحث "$1". نتيجة البحث جزئية.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'مطلوب إعادة التفويض.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'الحد الأقصى لعدد العناصر القابلة للتحديد هو $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'غير قادر على الاستعادة من سلة المهملات. لا يمكن تحديد وجهة الاستعادة.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'لم يتم العثور على المحرر لهذا النوع من الملفات.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'حدث خطأ من جانب الخادم.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'تعذر إفراغ المجلد "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'يوجد $1 أخطاء إضافية.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'إنشاء أرشيف', + 'cmdback' : 'العودة', + 'cmdcopy' : 'نسخ', + 'cmdcut' : 'قص', + 'cmddownload' : 'تنزيل', + 'cmdduplicate' : 'تكرار', + 'cmdedit' : 'تحرير الملف', + 'cmdextract' : 'إستخراج الملفات من الأرشيف', + 'cmdforward' : 'الأمام', + 'cmdgetfile' : 'اختيار الملفات', + 'cmdhelp' : 'عن هذه البرمجية', + 'cmdhome' : 'الجذر', + 'cmdinfo' : 'الحصول على المعلومات ', + 'cmdmkdir' : 'مجلد جديد', + 'cmdmkdirin' : 'داخل مجلد جديد', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'ملف جديد', + 'cmdopen' : 'فتح', + 'cmdpaste' : 'لصق', + 'cmdquicklook' : 'معاينة', + 'cmdreload' : 'إعادة تحميل', + 'cmdrename' : 'إعادة تسمية', + 'cmdrm' : 'حذف', + 'cmdtrash' : 'داخل سلة المهملات', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'إستعادة', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'بحث عن ملفات', + 'cmdup' : 'انتقل إلى المجلد الأصل', + 'cmdupload' : 'رفع ملفات', + 'cmdview' : 'عرض', + 'cmdresize' : 'تغيير الحجم والتدوير', + 'cmdsort' : 'فرز', + 'cmdnetmount' : 'تثبيت حجم الشبكة', // added 18.04.2012 + 'cmdnetunmount': 'إلغاء التثبيت', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'الى الاماكن', // added 28.12.2014 + 'cmdchmod' : 'تغيير النمط', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'فتح مجلد', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'إعادة تعيين عرض العمود', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'ملء الشاشة', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'نقل', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'تفريغ المجلد', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'تراجع', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'إعادة', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'التفضيلات', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'تحديد الكل', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'تحديد لا شيء', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'عكس الاختيار', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'فتح في نافذة جديدة', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'إخفاء (الأفضلية)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'إغلاق', + 'btnSave' : 'حفظ', + 'btnRm' : 'إزالة', + 'btnApply' : 'تطبيق', + 'btnCancel' : 'إلغاء', + 'btnNo' : 'لا', + 'btnYes' : 'نعم', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'تثبيت', // added 18.04.2012 + 'btnApprove': 'انتقل إلى $1 والموافقة', // from v2.1 added 26.04.2012 + 'btnUnmount': 'إلغاء التثبيت', // from v2.1 added 30.04.2012 + 'btnConv' : 'تحويل', // from v2.1 added 08.04.2014 + 'btnCwd' : 'هنا', // from v2.1 added 22.5.2015 + 'btnVolume' : 'الحجم', // from v2.1 added 22.5.2015 + 'btnAll' : 'الكل', // from v2.1 added 22.5.2015 + 'btnMime' : 'نوع MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'إسم الملف', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'حفظ وإغلاق', // from v2.1 added 12.6.2015 + 'btnBackup' : 'نسخ احتياطي', // fromv2.1 added 28.11.2015 + 'btnRename' : 'إعادة تسمية', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'إعادة تسمية (الجميع)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '($1/$2) السابق', // from v2.1.24 added 11.5.2017 + 'btnNext' : '($1/$2) التالي', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'حفظ كــ', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'فتح مجلد', + 'ntffile' : 'فتح ملف', + 'ntfreload' : 'إعادة تحميل محتوى المجلد', + 'ntfmkdir' : 'إنشاء مجلد', + 'ntfmkfile' : 'إنشاء ملفات', + 'ntfrm' : 'حذف العناصر', + 'ntfcopy' : 'نسخ العناصر', + 'ntfmove' : 'نقل االعناصر', + 'ntfprepare' : 'فحص العناصر الموجودة', + 'ntfrename' : 'إعادة تسمية الملفات', + 'ntfupload' : 'تحميل الملفات', + 'ntfdownload' : 'تنزيل الملفات', + 'ntfsave' : 'حفظ الملفات', + 'ntfarchive' : 'إنشاء أرشيف', + 'ntfextract' : 'استخراج ملفات من الأرشيف', + 'ntfsearch' : 'البحث في الملفات', + 'ntfresize' : 'تغيير حجم الصور', + 'ntfsmth' : 'القيام بشيء ما', + 'ntfloadimg' : 'تحميل الصورة', + 'ntfnetmount' : 'تثبيت حجم الشبكة', // added 18.04.2012 + 'ntfnetunmount': 'إلغاء تثبيت حجم الشبكة', // from v2.1 added 30.04.2012 + 'ntfdim' : 'اكتساب أبعاد الصورة', // added 20.05.2013 + 'ntfreaddir' : 'قراءة معلومات المجلد', // from v2.1 added 01.07.2013 + 'ntfurl' : 'الحصول على URL الرابط', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'تغيير نمط الملف', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'التحقق من اسم ملف التحميل', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'إنشاء ملف للتنزيل', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'الحصول على معلومات المسار', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'معالجة الملف المرفوع', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'القيام بالرمي في القمامة', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'القيام بالاستعادة من سلة المهملات', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'التحقق من مجلد الوجهة', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'التراجع عن العملية السابقة', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'إعادة التراجع السابق', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'فحص المحتويات', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Trash', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'غير معلوم', + 'Today' : 'اليوم', + 'Yesterday' : 'الأمس', + 'msJan' : 'كانون الثاني', + 'msFeb' : 'شباط', + 'msMar' : 'آذار', + 'msApr' : 'نيسان', + 'msMay' : 'أيار', + 'msJun' : 'حزيران', + 'msJul' : 'تموز', + 'msAug' : 'آب', + 'msSep' : 'أيلول', + 'msOct' : 'تشرين الأول', + 'msNov' : 'تشرين الثاني', + 'msDec' : 'كانون الأول ', + 'January' : 'كانون الثاني', + 'February' : 'شباط', + 'March' : 'آذار', + 'April' : 'نيسان', + 'May' : 'أيار', + 'June' : 'حزيران', + 'July' : 'تموز', + 'August' : 'آب', + 'September' : 'أيلول', + 'October' : 'تشرين الأول', + 'November' : 'تشرين الثاني', + 'December' : 'كانون الثاني', + 'Sunday' : 'الأحد', + 'Monday' : 'الاثنين', + 'Tuesday' : 'الثلاثاء', + 'Wednesday' : 'الإربعاء', + 'Thursday' : 'الخميس', + 'Friday' : 'الجمعة', + 'Saturday' : 'السبت', + 'Sun' : 'الأحد', + 'Mon' : 'الاثنين', + 'Tue' : 'الثلاثاء', + 'Wed' : 'الإربعاء', + 'Thu' : 'الخميس', + 'Fri' : 'الجمعة', + 'Sat' : 'السبت', + + /******************************** sort variants ********************************/ + 'sortname' : 'حسب الاسم', + 'sortkind' : 'حسب النوع', + 'sortsize' : 'حسب الحجم', + 'sortdate' : 'حسب التاريخ', + 'sortFoldersFirst' : 'المجلدات أولا', + 'sortperm' : 'حسب الصلاحية', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'حسب النمط', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'حسب المالك', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'حسب المجموعة', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'أيضا عرض الشجرة', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'file.txt بدون عنوان' : 'NewFile.txt', // added 10.11.2015 + 'مجلد بلا عنوان' : 'NewFolder', // added 10.11.2015 + 'Archive' : 'NewArchive', // from v2.1 added 10.11.2015 + 'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: ملف', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'التأكيد مطلوب', + 'confirmRm' : 'هل تريد بالتأكيد إزالة العناصر نهائيًا؟
                      لا يمكن التراجع عن هذا الإجراء! ', + 'confirmRepl' : 'استبدال الملف القديم بملف جديد؟ (إذا كان يحتوي على مجلدات ، فسيتم دمجه. للنسخ الاحتياطي والاستبدال ، حدد النسخ الاحتياطي.)', + 'confirmRest' : 'هل تريد استبدال العنصر الموجود بالعنصر الموجود في المهملات؟', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'ليس بصيغة UTF-8
                      التحويل إلى UTF-8؟
                      تصبح المحتويات UTF-8 بالحفظ بعد التحويل.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'تعذر الكشف عن ترميز الأحرف لهذا الملف. تحتاج إلى التحويل مؤقتاً إلى UTF-8 للتحرير.
                      الرجاء تحديد ترميز الأحرف لهذا الملف.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'لقد تم تعديله.
                      قد تخسر العمل إذا لم تقم بحفظ التغييرات.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'هل أنت متأكد أنك تريد نقل العناصر إلى سلة المهملات؟', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'هل أنت متأكد أنك تريد نقل العناصر إلى "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'تطبيق على الكل', + 'name' : 'الاسم', + 'size' : 'الحجم', + 'perms' : 'الصلاحيات', + 'modify' : 'التعديل', + 'kind' : 'النوع', + 'read' : 'قابل للقراءة', + 'write' : 'قابل للكتابة', + 'noaccess' : 'وصول ممنوع', + 'and' : 'و', + 'unknown' : 'غير معروف', + 'selectall' : 'تحديد كل العناصر', + 'selectfiles' : 'تحديد العناصر', + 'selectffile' : 'تحديد العنصر الأول', + 'selectlfile' : 'تحديد العنصر الأخير', + 'viewlist' : 'عرض القائمة', + 'viewicons' : 'عرض أيْقونات', + 'viewSmall' : 'أيقونات صغيرة', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'أيقونات متوسطة', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'أيقونات كبيرة', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'أيقونات كبيرة جداً', // from v2.1.39 added 22.5.2018 + 'places' : 'المواقع', + 'calc' : 'حساب', + 'path' : 'المسار', + 'aliasfor' : 'اسم مستعار لـ', + 'locked' : 'مقفل', + 'dim' : 'الأبعاد', + 'files' : 'ملفات', + 'folders' : 'مجلدات', + 'items' : 'عناصر', + 'yes' : 'نعم', + 'no' : 'لا', + 'link' : 'الرابط', + 'searcresult' : 'نتائج البحث', + 'selected' : 'العناصر المحددة', + 'about' : 'حول', + 'shortcuts' : 'الاختصارات', + 'help' : 'المساعدة', + 'webfm' : 'مدير ملفات الويب', + 'ver' : 'الإصدار', + 'protocolver' : 'إصدار البرتوكول', + 'homepage' : 'رئيسية المشروع', + 'docs' : 'الوثائق', + 'github' : 'شاركنا على Github', + 'twitter' : 'تابعنا على تويتر', + 'facebook' : 'انضم إلينا على الفيس بوك', + 'team' : 'الفريق', + 'chiefdev' : 'رئيس المبرمجين', + 'developer' : 'مبرمج', + 'contributor' : 'مساهم', + 'maintainer' : 'مشرف', + 'translator' : 'مترجم', + 'icons' : 'أيقونات', + 'dontforget' : 'ولا تنس أن تأخذ المنشفة', + 'shortcutsof' : 'الاختصارات غير مفعلة', + 'dropFiles' : 'إفلات الملفات هنا', + 'or' : 'أو', + 'selectForUpload' : 'اختر الملفات', + 'moveFiles' : 'نقل العناصر', + 'copyFiles' : 'نسخ العناصر', + 'restoreFiles' : 'استعادة العناصر', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'إزالة من الأماكن', + 'aspectRatio' : 'ابعاد متزنة', + 'scale' : 'مقياس', + 'width' : 'عرض', + 'height' : 'طول', + 'resize' : 'تغيير الحجم', + 'crop' : 'قص', + 'rotate' : 'تدوير', + 'rotate-cw' : 'استدارة 90 درجة مع عقارب الساعة', + 'rotate-ccw' : 'استدارة 90 درجة عكس عقارب الساعة', + 'degree' : '°', + 'netMountDialogTitle' : 'تثبيت حجم الشبكة', // added 18.04.2012 + 'protocol' : 'البروتوكول', // added 18.04.2012 + 'host' : 'المضيف', // added 18.04.2012 + 'port' : 'المنفذ', // added 18.04.2012 + 'user' : 'المستخدم', // added 18.04.2012 + 'pass' : 'كلمة المرور', // added 18.04.2012 + 'confirmUnmount' : 'هل أنت متأكد من إلغاء تثبيت $1؟', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'قم بإسقاط أو لصق الملفات من المتصفح', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'قم بإسقاط الملفات أو لصق الروابط أو الصور (الحافظة) هنا', // from v2.1 added 07.04.2014 + 'encoding' : 'الترميز', // from v2.1 added 19.12.2014 + 'locale' : 'اللغة', // from v2.1 added 19.12.2014 + 'searchTarget' : 'الهدف: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'البحث عن طريق إدخال نوع MIME', // from v2.1 added 22.5.2015 + 'owner' : 'المالك', // from v2.1 added 20.6.2015 + 'group' : 'المجموعة', // from v2.1 added 20.6.2015 + 'other' : 'أخرى', // from v2.1 added 20.6.2015 + 'execute' : 'تنفيذ', // from v2.1 added 20.6.2015 + 'perm' : 'التصريح', // from v2.1 added 20.6.2015 + 'mode' : 'النمط', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'المجلد فارغ', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'المجلد فارغ\\إفلات لإضافة عناصر', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'المجلد فارغ\\نقرة طويلة لإضافة العناصر', // from v2.1.6 added 30.12.2015 + 'quality' : 'النوعية', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'مزامنة آلية', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'تحريك لأعلى', // from v2.1.6 added 18.1.2016 + 'getLink' : 'الحصول على رابط URL', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'العناصر المحددة ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'معرف المجلد', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'السماح بالوصول دون اتصال', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'لإعادة المصادقة', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'جاري التحميل الآن...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'فتح ملفات متعددة', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'أنت تحاول فتح $1 ملف. هل أنت متأكد أنك تريد الفتح في المتصفح؟', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'نتائج البحث فارغة في هدف البحث.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'إنها تقوم بتحرير ملف.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'لقد قمت بتحديد $1 عناصر.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'يوجد لديك $1 عناصر في الحافظة.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'البحث المتزايد هو فقط من العرض الحالي.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'إعادة', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 إكتمل', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'قائمة السياق', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'قلب الصفحة', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'جذور الحجم', // from v2.1.16 added 16.9.2016 + 'reset' : 'إعادة تعيين', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'لون الخلفية', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'أداة انتقاء اللون', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'شبكة 8 بكسل', // from v2.1.16 added 4.10.2016 + 'enabled' : 'مفعل', // from v2.1.16 added 4.10.2016 + 'disabled' : 'معطل', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'نتائج البحث فارغة في العرض الحالي. \\ اضغط على [Enter] لتوسيع هدف البحث.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'نتائج البحث الحرف الأول فارغة في العرض الحالي.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'تسمية نصية', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 دقائق باقية', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'إعادة فتح مع الترميز المحدد', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'حفظ مع الترميز المحدد', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'تحديد مجلد', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'البحث بالحرف الأول', // from v2.1.23 added 24.3.2017 + 'presets' : 'الإعدادات المسبقة', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'هناك عدد كبير جداً من العناصر لذا لا يمكن وضعها في سلة المهملات.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'منطقة النص', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'إفراغ المجلد "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'لا توجد عناصر في مجلد "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'الأفضلية', // from v2.1.26 added 28.6.2017 + 'language' : 'اللغة', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'تهيئة الإعدادات المحفوظة في هذا المتصفح', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'إعدادات شريط الأدوات', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 حروف متبقية.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 سطور متبقية.', // from v2.1.52 added 16.1.2020 + 'sum' : 'المجموع', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'حجم ملف تقريبي', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'التركيز على عنصر الحوار مع تمرير الماوس', // from v2.1.30 added 2.11.2017 + 'select' : 'حدد', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'الإجراء عند تحديد الملف', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'الفتح باستخدام المحرر المستخدم آخر مرة', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'عكس الاختيار', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'هل أنت متأكد أنك تريد إعادة تسمية $1 عناصر محددة مثل $2؟
                      هذا لا يمكن التراجع عنه !', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'إعادة تسمية الحزمة', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ رقم', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'إضافة بادئة', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'إضافة لاحقة', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'تغيير الامتداد', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'إعدادات الأعمدة (عرض القائمة)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'ستنعكس جميع التغييرات على الفور على الأرشيف.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'لن تنعكس أي تغييرات حتى يتم فك هذا المجلد.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'المجلد (المجلدات) التالية المركبة على هذا المجلد غير مثبتة أيضاً. هل أنت متأكد من إلغاء تحميله؟', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'معلومات التحديد', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'خوارزميات لإظهار تجزئة الملف', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'عناصر المعلومات (لوحة معلومات التحديد)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'اضغط مرة أخرى للخروج.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'شريط الأدوات', // from v2.1.38 added 4.4.2018 + 'workspace' : 'مساحة العمل', // from v2.1.38 added 4.4.2018 + 'dialog' : 'الحوار', // from v2.1.38 added 4.4.2018 + 'all' : 'الكل', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'حجم الأيقونة (عرض الأيقونات)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'افتح نافذة المحرر المكبرة', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'نظراً لعدم توفر التحويل بواسطة API حالياً ، يرجى التحويل على موقع الويب.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'بعد التحويل ، يجب أن تقوم بالتحميل مع عنوان رابط العنصر أو الملف الذي تم تنزيله لحفظ الملف المحول.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'تحويل على موقع $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'تكاملات', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'يحتوي elFinder على الخدمات الخارجية التالية المتكاملة. يرجى التحقق من شروط الاستخدام وسياسة الخصوصية وما إلى ذلك قبل استخدامها.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'إظهار العناصر المخفية', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'إخفاء العناصر المخفية', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'إظهار / إخفاء العناصر المخفية', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'أنواع الملفات لتفعيلها مع "ملف جديد"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'نوع الملف النصي', // from v2.1.41 added 7.8.2018 + 'add' : 'إضافة', // from v2.1.41 added 7.8.2018 + 'theme' : 'الثيم', // from v2.1.43 added 19.10.2018 + 'default' : 'الافتراضي', // from v2.1.43 added 19.10.2018 + 'description' : 'الوصف', // from v2.1.43 added 19.10.2018 + 'website' : 'الموقع الالكتروني', // from v2.1.43 added 19.10.2018 + 'author' : 'المؤلف', // from v2.1.43 added 19.10.2018 + 'email' : 'البريد الالكتروني', // from v2.1.43 added 19.10.2018 + 'license' : 'الرخصة', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'لا يمكن حفظ هذا العنصر. لتجنب فقدان التحريرات التي تحتاجها للتصدير إلى جهاز الكمبيوتر الخاص بك.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'انقر نقراً مزدوجاً فوق الملف لتحديده.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'استخدام وضع ملء الشاشة', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'غير معروف', + 'kindRoot' : 'جذر الحجم', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'مجلد', + 'kindSelects' : 'مختارات', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'اسم مستعار', + 'kindAliasBroken' : 'اسم مستعار مكسور', + // applications + 'kindApp' : 'التطبيق', + 'kindPostscript' : 'وثيقة Postscript', + 'kindMsOffice' : 'وثيقة Microsoft Office', + 'kindMsWord' : 'وثيقة Microsoft Word', + 'kindMsExcel' : 'وثيقة Microsoft Excel', + 'kindMsPP' : 'عرض تقديمي Microsoft Powerpoint', + 'kindOO' : 'وثيقة Open Office', + 'kindAppFlash' : 'تطبيق فلاش', + 'kindPDF' : 'تنسيق الوثائق المحمولة (PDF)', + 'kindTorrent' : 'ملف Bittorrent ', + 'kind7z' : 'أرشيف 7z', + 'kindTAR' : 'أرشيف TAR', + 'kindGZIP' : 'أرشيف GZIP', + 'kindBZIP' : 'أرشيف BZIP', + 'kindXZ' : 'أرشيف XZ', + 'kindZIP' : 'أرشيف ZIP', + 'kindRAR' : 'أرشيف RAR', + 'kindJAR' : 'أرشيف Java JAR', + 'kindTTF' : 'خط True Type ', + 'kindOTF' : 'خط Open Type ', + 'kindRPM' : 'حزمة RPM', + // fonts + 'kindFont' : 'خط', + 'kindSFNT' : 'خط SFNT', + 'kindEOT' : 'خط Embedded Open Type', + 'kindWOFF' : 'خط Web Open Font Format', + 'kindWOFF2' : 'خط Web Open Font Format 2', + // texts + 'kindText' : 'وثيقة نصية', + 'kindTextPlain' : 'نص عادي', + 'kindPHP' : 'مصدر PHP', + 'kindCSS' : 'ورقة الأنماط المتتالية', + 'kindHTML' : 'وثيقة HTML', + 'kindJS' : 'مصدر Javascript', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'مصدر C', + 'kindCHeader' : 'مصدر C header', + 'kindCPP' : 'مصدر C++', + 'kindCPPHeader' : 'مصدر C++ header', + 'kindShell' : 'مصدر Unix shell', + 'kindPython' : 'مصدر Python', + 'kindJava' : 'مصدر Java', + 'kindRuby' : 'مصدر Ruby', + 'kindPerl' : 'مصدر Perl', + 'kindSQL' : 'مصدر SQL', + 'kindXML' : 'وثيقة XML', + 'kindAWK' : 'مصدر AWK', + 'kindCSV' : 'ملف CSV', + 'kindDOCBOOK' : 'وثيقة Docbook XML', + 'kindMarkdown' : 'نص Markdown', // added 20.7.2015 + // images + 'kindImage' : 'صورة', + 'kindBMP' : 'صورة BMP', + 'kindJPEG' : 'صورة JPEG', + 'kindGIF' : 'صورة GIF', + 'kindPNG' : 'صورة PNG', + 'kindTIFF' : 'صورة TIFF', + 'kindTGA' : 'صورة TGA', + 'kindPSD' : 'صورة Adobe Photoshop', + 'kindXBITMAP' : 'صورة X bitmap', + 'kindPXM' : 'صورة Pixelmator', + // media + 'kindAudio' : 'وسائط صوت', + 'kindAudioMPEG' : 'ملف صوتي MPEG ', + 'kindAudioMPEG4' : 'ملف صوتي MPEG-4', + 'kindAudioMIDI' : 'ملف صوتي MIDI', + 'kindAudioOGG' : 'ملف صوتي Ogg Vorbis', + 'kindAudioWAV' : 'ملف صوتي WAV', + 'AudioPlaylist' : 'قائمة تشغيل MP3', + 'kindVideo' : 'وسائط فيديو', + 'kindVideoDV' : 'ملف فيديو DV', + 'kindVideoMPEG' : 'ملف فيديو MPEG', + 'kindVideoMPEG4' : 'ملف فيديو MPEG-4', + 'kindVideoAVI' : 'ملف فيديو AVI', + 'kindVideoMOV' : 'ملف فيديو Quick Time', + 'kindVideoWM' : 'ملف فيديو Windows Media', + 'kindVideoFlash' : 'ملف فيديو Flash', + 'kindVideoMKV' : 'ملف فيديو Matroska', + 'kindVideoOGG' : 'ملف فيديو Ogg' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.bg.js b/lib/redactor/elfinder/js/i18n/elfinder.bg.js new file mode 100644 index 0000000..5594f38 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.bg.js @@ -0,0 +1,566 @@ +/** + * Bulgarian translation + * @author Stamo Petkov + * @author Nikolay Petkov + * @version 2018-07-28 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.bg = { + translator : 'Stamo Petkov <stamo.petkov@gmail.com>, Nikolay Petkov <office@cmstory.com>', + language : 'Bulgarian', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'Ymd-His', // to apply if upload file is noname: 120513172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Грешка', + 'errUnknown' : 'Непозната грешка.', + 'errUnknownCmd' : 'Непозната команда.', + 'errJqui' : 'Грешна конфигурация на jQuery UI. Компонентите selectable, draggable и droppable трябва да са включени.', + 'errNode' : 'elFinder изисква да бъде създаден DOM елемент.', + 'errURL' : 'Грешка в настройките на elFinder! не е зададена стойност на URL.', + 'errAccess' : 'Достъп отказан.', + 'errConnect' : 'Няма връзка със сървъра.', + 'errAbort' : 'Връзката е прекъсната.', + 'errTimeout' : 'Просрочена връзка.', + 'errNotFound' : 'Сървърът не е намерен.', + 'errResponse' : 'Грешен отговор от сървъра.', + 'errConf' : 'Грешни настройки на сървъра.', + 'errJSON' : 'Не е инсталиран модул на PHP за JSON.', + 'errNoVolumes' : 'Няма дялове достъпни за четене.', + 'errCmdParams' : 'Грешни параметри на командата "$1".', + 'errDataNotJSON' : 'Данните не са JSON.', + 'errDataEmpty' : 'Липсват данни.', + 'errCmdReq' : 'Запитването от сървъра изисква име на команда.', + 'errOpen' : 'Неуспешно отваряне на "$1".', + 'errNotFolder' : 'Обектът не е папка.', + 'errNotFile' : 'Обектът не е файл.', + 'errRead' : 'Неуспешно прочитане на "$1".', + 'errWrite' : 'Неуспешен запис в "$1".', + 'errPerm' : 'Разрешение отказано.', + 'errLocked' : '"$1" е заключен и не може да бъде преименуван, местен или премахван.', + 'errExists' : 'Вече съществува файл с име "$1"', + 'errInvName' : 'Грешно име на файл.', + 'errInvDirname' : 'Невалидно име на папка.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Папката не е открита.', + 'errFileNotFound' : 'Файлът не е открит.', + 'errTrgFolderNotFound' : 'Целевата папка "$1" не е намерена.', + 'errPopup' : 'Браузъра блокира отварянето на прозорец. За да отворите файла, разрешете отварянето в настройките на браузъра.', + 'errMkdir' : 'Неуспешно създаване на папка "$1".', + 'errMkfile' : 'Неуспешно създаване на файл "$1".', + 'errRename' : 'Неуспешно преименуване на "$1".', + 'errCopyFrom' : 'Копирането на файлове от том "$1" не е разрешено.', + 'errCopyTo' : 'Копирането на файлове в том "$1" не е разрешено.', + 'errMkOutLink' : 'Неуспех при създаване на връзка извън началото на ресурса.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Грешка при качване.', // old name - errUploadCommon + 'errUploadFile' : 'Неуспешно качване на "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Не са намерени файлове за качване.', + 'errUploadTotalSize' : 'Данните превишават максимално допостумия размер.', // old name - errMaxSize + 'errUploadFileSize' : 'Файлът превишава максимално допустимия размер.', // old name - errFileMaxSize + 'errUploadMime' : 'Непозволен тип на файла.', + 'errUploadTransfer' : '"$1" грешка при предаване.', + 'errUploadTemp' : 'Неуспешно създаване на временен файл за качване.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Обект "$1" вече съществува на това място и не може да бъде заменен от обект от друг тип.', // new + 'errReplace' : 'Не може да се замени "$1".', + 'errSave' : 'Не може да се запише "$1".', + 'errCopy' : 'Не може да се копира "$1".', + 'errMove' : 'Не може да се премести "$1".', + 'errCopyInItself' : 'Не може да се копира "$1" върху самия него.', + 'errRm' : 'Не може да се премахне "$1".', + 'errTrash' : 'Не може да се премести в кошчето', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Не може да се премахне изходния файл(ове).', + 'errExtract' : 'Не може да се извлекат файловете от "$1".', + 'errArchive' : 'Не може да се създаде архив.', + 'errArcType' : 'Неподдържан тип на архива.', + 'errNoArchive' : 'Файлът не е архив или е от неподдържан тип.', + 'errCmdNoSupport' : 'Сървъра не поддържа тази команда.', + 'errReplByChild' : 'Папката “$1” не може да бъде заменена от съдържащ се в нея елемент.', + 'errArcSymlinks' : 'От съображения за сигурност няма да бъдат разопаковани архиви съдържащи symlinks.', // edited 24.06.2012 + 'errArcMaxSize' : 'Архивните файлове превишават максимално допустимия размер.', + 'errResize' : 'Не може да се преоразмери "$1".', + 'errResizeDegree' : 'Невалиден градус за ротация.', // added 7.3.2013 + 'errResizeRotate' : 'Изображението не е ротирано.', // added 7.3.2013 + 'errResizeSize' : 'Невалиден размер на изображение.', // added 7.3.2013 + 'errResizeNoChange' : 'Размерът на изображението не е променен.', // added 7.3.2013 + 'errUsupportType' : 'Неподдържан тип на файл.', + 'errNotUTF8Content' : 'Файл "$1" не е в UTF-8 формат и не може да бъде редактиран.', // added 9.11.2011 + 'errNetMount' : 'Не може да се монтира "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Неподдържан протокол.', // added 17.04.2012 + 'errNetMountFailed' : 'Монтирането не е успешно.', // added 17.04.2012 + 'errNetMountHostReq' : 'Хост се изисква.', // added 18.04.2012 + 'errSessionExpires' : 'Сесията ви изтече поради липса на активност.', + 'errCreatingTempDir' : 'Не може да се създаде временна директория: "$1"', + 'errFtpDownloadFile' : 'Не може да се изтегли файл от FTP: "$1"', + 'errFtpUploadFile' : 'Не може да се качи файл на FTP: "$1"', + 'errFtpMkdir' : 'Не може да се създаде директория на FTP: "$1"', + 'errArchiveExec' : 'Грешка при архивиране на файлове: "$1"', + 'errExtractExec' : 'Грешка при разархивиране на файлове: "$1"', + 'errNetUnMount' : 'Не може да се размонтира', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Не е конвертируем до UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Опитайте Google Chrome, ако искате да качите папка.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Времето изтече при търсенето на "$1". Резултатът от търсенето е частичен.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Необходимо е повторно оторизиране.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Максималният брой избрани файлове е $ 1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Не може да се възстанови от кошчето. Не може да се определи местоположението за възстановяване.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Не е намерен редактор за този тип файл.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Възникна грешка на сървъра.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Папката "$1" не може да се изпразни.', // from v2.1.25 added 22.6.2017 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Създай архив', + 'cmdback' : 'Назад', + 'cmdcopy' : 'Копирай', + 'cmdcut' : 'Изрежи', + 'cmddownload' : 'Свали', + 'cmdduplicate' : 'Дублирай', + 'cmdedit' : 'Редактирай файл', + 'cmdextract' : 'Извлечи файловете от архива', + 'cmdforward' : 'Напред', + 'cmdgetfile' : 'Избери файлове', + 'cmdhelp' : 'За тази програма', + 'cmdhome' : 'Начало', + 'cmdinfo' : 'Информация', + 'cmdmkdir' : 'Нова папка', + 'cmdmkdirin' : 'В нова папка', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Нов файл', + 'cmdopen' : 'Отвори', + 'cmdpaste' : 'Вмъкни', + 'cmdquicklook' : 'Преглед', + 'cmdreload' : 'Презареди', + 'cmdrename' : 'Преименувай', + 'cmdrm' : 'Изтрий', + 'cmdtrash' : 'В кошчето', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Възстанови', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Намери файлове', + 'cmdup' : 'Една директория нагоре', + 'cmdupload' : 'Качи файлове', + 'cmdview' : 'Виж', + 'cmdresize' : 'Промени изображение', + 'cmdsort' : 'Подреди', + 'cmdnetmount' : 'Монтирай мрежов ресурс', // added 18.04.2012 + 'cmdnetunmount': 'Размонтирай', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Към избрани', // added 28.12.2014 + 'cmdchmod' : 'Промяна на вид', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Отвори папка', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Нулирай ширината на колоната', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Цял екран', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Премести', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Изпразни папката', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Отмени', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Преправи', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Настройки', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Избери всичко', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Избери нищо', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Обърни селекцията', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Отвори в нов прозорец', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Скрий (лично)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Затвори', + 'btnSave' : 'Запиши', + 'btnRm' : 'Премахни', + 'btnApply' : 'Приложи', + 'btnCancel' : 'Отказ', + 'btnNo' : 'Не', + 'btnYes' : 'Да', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Монтирай', // added 18.04.2012 + 'btnApprove': 'Отиди на $1 и одобри', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Размонтирай', // from v2.1 added 30.04.2012 + 'btnConv' : 'Конвертирай', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Тук', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Ресурс', // from v2.1 added 22.5.2015 + 'btnAll' : 'Всички', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME тип', // from v2.1 added 22.5.2015 + 'btnFileName':'Име', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Запази и затвори', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Архивирай', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Преименувай', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Преименувай(Всички)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Пред ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'След ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Запази като', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Отваряне на папка', + 'ntffile' : 'Отваряне на файл', + 'ntfreload' : 'Презареждане съдържанието на папка', + 'ntfmkdir' : 'Създава се директория', + 'ntfmkfile' : 'Създава се файл', + 'ntfrm' : 'Изтриване на файлове', + 'ntfcopy' : 'Копиране на файлове', + 'ntfmove' : 'Преместване на файлове', + 'ntfprepare' : 'Подготовка за копиране на файлове', + 'ntfrename' : 'Преименуване на файлове', + 'ntfupload' : 'Качват се файлове', + 'ntfdownload' : 'Свалят се файлове', + 'ntfsave' : 'Запис на файлове', + 'ntfarchive' : 'Създава се архив', + 'ntfextract' : 'Извличат се файловете от архив', + 'ntfsearch' : 'Търсят се файлове', + 'ntfresize' : 'Преоразмеряват се изображения', + 'ntfsmth' : 'Зает съм >_<', + 'ntfloadimg' : 'Зареждат се изображения', + 'ntfnetmount' : 'Монтира се мрежов ресурс', // added 18.04.2012 + 'ntfnetunmount': 'Размонтира се мрежов ресурс', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Извличат се размерите на изображение', // added 20.05.2013 + 'ntfreaddir' : 'Извлича се информация за папка', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Взима се URL от връзка', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Променя се вида на файл', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Проверка на името на файла за качване', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Създаване на файл за изтегляне', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Получава се информация за пътя', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Обработка на качения файл', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Прехвърлят се позиции в кошчето', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Извършва се възстановяване от кошчето', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Проверка на целевата папка', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Отмяна на предишната операция', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Възстановяване на предходните отменени', // from v2.1.27 added 31.07.2017 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Кошче', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'неизвестна', + 'Today' : 'днес', + 'Yesterday' : 'вчера', + 'msJan' : 'яну', + 'msFeb' : 'фев', + 'msMar' : 'мар', + 'msApr' : 'апр', + 'msMay' : 'май', + 'msJun' : 'юни', + 'msJul' : 'юли', + 'msAug' : 'авг', + 'msSep' : 'сеп', + 'msOct' : 'окт', + 'msNov' : 'ное', + 'msDec' : 'дек', + 'January' : 'януари', + 'February' : 'февруари', + 'March' : 'март', + 'April' : 'април', + 'May' : 'май', + 'June' : 'юни', + 'July' : 'юли', + 'August' : 'август', + 'September' : 'септември', + 'October' : 'октомври', + 'November' : 'ноември', + 'December' : 'декември', + 'Sunday' : 'неделя', + 'Monday' : 'понеделник', + 'Tuesday' : 'вторник', + 'Wednesday' : 'сряда', + 'Thursday' : 'четвъртък', + 'Friday' : 'петък', + 'Saturday' : 'събота', + 'Sun' : 'нед', + 'Mon' : 'пон', + 'Tue' : 'вто', + 'Wed' : 'сря', + 'Thu' : 'чет', + 'Fri' : 'пет', + 'Sat' : 'съб', + + /******************************** sort variants ********************************/ + 'sortname' : 'по име', + 'sortkind' : 'по вид', + 'sortsize' : 'по размер', + 'sortdate' : 'по дата', + 'sortFoldersFirst' : 'Папките първи', + 'sortperm' : 'по права', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'по вид', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'по собственик', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'по група', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Също дървовиден изглед', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NewFile.txt', // added 10.11.2015 + 'untitled folder' : 'NewFolder', // added 10.11.2015 + 'Archive' : 'NewArchive', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'Изисква се подтвърждение', + 'confirmRm' : 'Сигурни ли сте, че желаете да премахнете файловете?
                      Това действие е необратимо!', + 'confirmRepl' : 'Да заменя ли стария файл с новия?', + 'confirmRest' : 'Да се замени ли съществуващата позиция с тази в кошчето?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Не е в UTF-8 формат
                      Конвертиране до UTF-8?
                      Съдържанието става в UTF-8 формат при запазване след конверсията.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Кодирането на този файл не може да бъде открито. Необходимо е временно да се преобразува в UTF-8 за редактиране.
                      Моля, изберете кодиране на този файл.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Има направени промени.
                      Те ще бъдат загубени, ако не запишете промените.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Наистина ли искате да преместите позиции в кошчето за боклук?', //from v2.1.24 added 29.4.2017 + 'apllyAll' : 'Приложи за всички', + 'name' : 'Име', + 'size' : 'Размер', + 'perms' : 'Права', + 'modify' : 'Променено', + 'kind' : 'Вид', + 'read' : 'четене', + 'write' : 'запис', + 'noaccess' : 'без достъп', + 'and' : 'и', + 'unknown' : 'непознат', + 'selectall' : 'Избери всички файлове', + 'selectfiles' : 'Избери файл(ове)', + 'selectffile' : 'Избери първият файл', + 'selectlfile' : 'Избери последният файл', + 'viewlist' : 'Изглед списък', + 'viewicons' : 'Изглед икони', + 'viewSmall' : 'Малки икони', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Средни икони', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Големи икони', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Много големи икони', // from v2.1.39 added 22.5.2018 + 'places' : 'Избрани', + 'calc' : 'Изчисли', + 'path' : 'Път', + 'aliasfor' : 'Връзка към', + 'locked' : 'Заключен', + 'dim' : 'Размери', + 'files' : 'Файлове', + 'folders' : 'Папки', + 'items' : 'Позиции', + 'yes' : 'да', + 'no' : 'не', + 'link' : 'Връзка', + 'searcresult' : 'Резултати от търсенето', + 'selected' : 'Избрани позиции', + 'about' : 'За', + 'shortcuts' : 'Бързи клавиши', + 'help' : 'Помощ', + 'webfm' : 'Файлов менажер за Интернет', + 'ver' : 'Версия', + 'protocolver' : 'версия на протокола', + 'homepage' : 'Начало', + 'docs' : 'Документация', + 'github' : 'Разклонение в Github', + 'twitter' : 'Последвайте ни в Twitter', + 'facebook' : 'Присъединете се към нас във Facebook', + 'team' : 'Екип', + 'chiefdev' : 'Главен разработчик', + 'developer' : 'разработчик', + 'contributor' : 'сътрудник', + 'maintainer' : 'поддръжка', + 'translator' : 'преводач', + 'icons' : 'Икони', + 'dontforget' : 'и не забравяйте да си вземете кърпата', + 'shortcutsof' : 'Преките пътища са изключени', + 'dropFiles' : 'Пуснете файловете тук', + 'or' : 'или', + 'selectForUpload' : 'Избери файлове', + 'moveFiles' : 'Премести файлове', + 'copyFiles' : 'Копирай файлове', + 'restoreFiles' : 'Възстанови файлове', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Премахни от избрани', + 'aspectRatio' : 'Отношение', + 'scale' : 'Мащаб', + 'width' : 'Ширина', + 'height' : 'Височина', + 'resize' : 'Преоразмери', + 'crop' : 'Отрежи', + 'rotate' : 'Ротирай', + 'rotate-cw' : 'Ротирай 90 градуса CW', + 'rotate-ccw' : 'Ротирай 90 градуса CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Монтиране на мрежов ресурс', // added 18.04.2012 + 'protocol' : 'Протокол', // added 18.04.2012 + 'host' : 'Хост', // added 18.04.2012 + 'port' : 'Порт', // added 18.04.2012 + 'user' : 'Потребител', // added 18.04.2012 + 'pass' : 'Парола', // added 18.04.2012 + 'confirmUnmount' : 'Ще размонтирате $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Пусни или вмъкни файлове от браузера', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Тук поснете файловете, URL адресите или изображенията от клипборда', // from v2.1 added 07.04.2014 + 'encoding' : 'Кодировка', // from v2.1 added 19.12.2014 + 'locale' : 'Локали', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Цел: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Търсене по въведен MIME тип', // from v2.1 added 22.5.2015 + 'owner' : 'Собственик', // from v2.1 added 20.6.2015 + 'group' : 'Група', // from v2.1 added 20.6.2015 + 'other' : 'Други', // from v2.1 added 20.6.2015 + 'execute' : 'Изпълнява', // from v2.1 added 20.6.2015 + 'perm' : 'Разрешение', // from v2.1 added 20.6.2015 + 'mode' : 'Вид', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Папката е празна', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Папката е празна\\A Влачи и пусни за да добавите файлове', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Папката е празна\\A Докоснете дълго за да добавите позиции', // from v2.1.6 added 30.12.2015 + 'quality' : 'Качество', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Автоматично синхронизиране', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Премести нагоре', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Вземи URL връзка', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Избрани позиции ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Папка ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Позволи офлайн достъп', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'За повторно удостоверяване', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Сега се зарежда...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Отваряне на няколко файла', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Опитвате се да отворите $1 файла. Наистина ли искате да ги отворите в браузъра?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Няма резултат от търсенето.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Редактира се файл.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Вие сте избрали $1 позиции.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Имате $1 позиции в клипборда.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Инкременталното търсене е само от текущия изглед.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Възстановяване', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 завършени', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Контекстно меню', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Завъртане на страницата', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Начала на ресурси', // from v2.1.16 added 16.9.2016 + 'reset' : 'Нулиране', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Цвят на фона', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Средство за избиране на цвят', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px мрежа', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Активно', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Неактивно', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Няма резултат от търсенето в текущия изглед.\\AНатиснете [Enter] за да разширите целта на търсене.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Резултатите от търсенето на първата буква са празни в текущия изглед.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Текстов етикет', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 мин остават', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Отваряне отново с избрано кодиране', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Запазете с избраното кодиране', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Избери папка', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Търсене по първа буква', // from v2.1.23 added 24.3.2017 + 'presets' : 'Мостри', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Прекалено много позиции, не може да премести в кошчето.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Текстово поле', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Изпразнете папка "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'В папка "$1" няма позиции.', // from v2.1.25 added 22.6.2017 + 'preference' : 'Настройки', // from v2.1.26 added 28.6.2017 + 'language' : 'Настройка на езика', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Инициализирайте настройките запаметени в този браузър', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Настройки на лентата с инструменти', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 символа остават.', // from v2.1.29 added 30.8.2017 + 'sum' : 'Сумарно', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Груб размер на файла', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Фокусирайте върху елемента в диалоговия прозорец с мишката', // from v2.1.30 added 2.11.2017 + 'select' : 'Избери', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Действие при избор на файл', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Отворете с редактора, използван за последен път', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Обърнете селекцията', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Наистина ли искате да преименувате $1 избрани позиции като $2?
                      Това не може да бъде отменено!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Групово преименуване', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Номер', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Добави префикс', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Добави суфикс', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Промени разширение', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Настройки за колони (Изглед в списък)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Всички промени ще се отразят незабавно в архива.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Промените няма да се отразят, докато не размонтирате този диск.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Информация за селекцията', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Алгоритми за показване на файловия хеш', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Натиснете отново, за да излезете.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Лента с инструменти', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Работно пространство', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Диалог', // from v2.1.38 added 4.4.2018 + 'all' : 'Всички', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Размер на иконите (изглед с икони)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Отваря максимизиран прозорец на редактора', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Тъй като в момента не е налична API за конверсията, моля, конвертирайте в уебсайта.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'След конверсията трябва да го качите с URL адреса или изтегления файл, за да запазите конвертирания файл.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Конвертиране на сайта от $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Интеграции', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Този elFinder има следните интегрирани външни услуги. Моля, проверете условията за ползване, декларацията за поверителност и т.н., преди да ги използвате.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Покажи скритите елементи', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Скрий скритите елементи', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Покажи/скрий скритите елементи', // from v2.1.41 added 24.7.2018 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Непознат', + 'kindRoot' : 'Начало на ресурс', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Папка', + 'kindSelects' : 'Селекции', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Връзка', + 'kindAliasBroken' : 'Счупена връзка', + // applications + 'kindApp' : 'Приложение', + 'kindPostscript' : 'Postscript документ', + 'kindMsOffice' : 'Microsoft Office документ', + 'kindMsWord' : 'Microsoft Word документ', + 'kindMsExcel' : 'Microsoft Excel документ', + 'kindMsPP' : 'Microsoft Powerpoint презентация', + 'kindOO' : 'Open Office документ', + 'kindAppFlash' : 'Flash приложение', + 'kindPDF' : 'PDF документ', + 'kindTorrent' : 'Bittorrent файл', + 'kind7z' : '7z архив', + 'kindTAR' : 'TAR архив', + 'kindGZIP' : 'GZIP архив', + 'kindBZIP' : 'BZIP архив', + 'kindXZ' : 'XZ архив', + 'kindZIP' : 'ZIP архив', + 'kindRAR' : 'RAR архив', + 'kindJAR' : 'Java JAR файл', + 'kindTTF' : 'True Type шрифт', + 'kindOTF' : 'Open Type шрифт', + 'kindRPM' : 'RPM пакет', + // fonts + 'kindFont' : 'шрифт', + 'kindSFNT' : 'SFNT шрифт', + 'kindEOT' : 'Embedded Open Type шрифт', + 'kindWOFF' : 'Web Open Font Format шрифт', + 'kindWOFF2' : 'Web Open Font Format 2 шрифт', + // texts + 'kindText' : 'Текстов документ', + 'kindTextPlain' : 'Чист текст', + 'kindPHP' : 'PHP изходен код', + 'kindCSS' : 'CSS таблица със стилове', + 'kindHTML' : 'HTML документ', + 'kindJS' : 'Javascript изходен код', + 'kindRTF' : 'RTF текстови файл', + 'kindC' : 'C изходен код', + 'kindCHeader' : 'C header изходен код', + 'kindCPP' : 'C++ изходен код', + 'kindCPPHeader' : 'C++ header изходен код', + 'kindShell' : 'Unix shell изходен код', + 'kindPython' : 'Python изходен код', + 'kindJava' : 'Java изходен код', + 'kindRuby' : 'Ruby изходен код', + 'kindPerl' : 'Perl изходен код', + 'kindSQL' : 'SQL изходен код', + 'kindXML' : 'XML документ', + 'kindAWK' : 'AWK изходен код', + 'kindCSV' : 'CSV стойности разделени със запетая', + 'kindDOCBOOK' : 'Docbook XML документ', + 'kindMarkdown' : 'Markdown текст', // added 20.7.2015 + // images + 'kindImage' : 'Изображение', + 'kindBMP' : 'BMP изображение', + 'kindJPEG' : 'JPEG изображение', + 'kindGIF' : 'GIF изображение', + 'kindPNG' : 'PNG изображение', + 'kindTIFF' : 'TIFF изображение', + 'kindTGA' : 'TGA изображение', + 'kindPSD' : 'Adobe Photoshop изображение', + 'kindXBITMAP' : 'X bitmap изображение', + 'kindPXM' : 'Pixelmator изображение', + // media + 'kindAudio' : 'Аудио медия', + 'kindAudioMPEG' : 'MPEG звук', + 'kindAudioMPEG4' : 'MPEG-4 звук', + 'kindAudioMIDI' : 'MIDI звук', + 'kindAudioOGG' : 'Ogg Vorbis звук', + 'kindAudioWAV' : 'WAV звук', + 'AudioPlaylist' : 'MP3 списък за изпълнение', + 'kindVideo' : 'Видео медия', + 'kindVideoDV' : 'DV филм', + 'kindVideoMPEG' : 'MPEG филм', + 'kindVideoMPEG4' : 'MPEG-4 филм', + 'kindVideoAVI' : 'AVI филм', + 'kindVideoMOV' : 'Quick Time филм', + 'kindVideoWM' : 'Windows Media филм', + 'kindVideoFlash' : 'Flash филм', + 'kindVideoMKV' : 'Matroska филм', + 'kindVideoOGG' : 'Ogg филм' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ca.js b/lib/redactor/elfinder/js/i18n/elfinder.ca.js new file mode 100644 index 0000000..f5fbc07 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ca.js @@ -0,0 +1,382 @@ +/** + * Catalan translation + * @author Sergio Jovani + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ca = { + translator : 'Sergio Jovani <lesergi@gmail.com>', + language : 'Català', + direction : 'ltr', + dateFormat : 'M d, Y h:i A', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will produce smth like: Today 12:25 PM + messages : { + + /********************************** errors **********************************/ + 'error' : 'Error', + 'errUnknown' : 'Error desconegut.', + 'errUnknownCmd' : 'Ordre desconeguda.', + 'errJqui' : 'La configuració de jQuery UI no és vàlida. S\'han d\'incloure els components "selectable", "draggable" i "droppable".', + 'errNode' : 'elFinder necessita crear elements DOM.', + 'errURL' : 'La configuració de l\'elFinder no és vàlida! L\'opció URL no està configurada.', + 'errAccess' : 'Accés denegat.', + 'errConnect' : 'No s\'ha pogut connectar amb el rerefons.', + 'errAbort' : 'S\'ha interromput la connexió.', + 'errTimeout' : 'Temps de connexió excedit.', + 'errNotFound' : 'No s\'ha trobat el rerefons.', + 'errResponse' : 'La resposta del rerefons no és vàlida.', + 'errConf' : 'La configuració del rerefons no és vàlida.', + 'errJSON' : 'No està instal·lat el mòdul JSON del PHP.', + 'errNoVolumes' : 'No s\'han trobat volums llegibles.', + 'errCmdParams' : 'Els paràmetres per l\'ordre "$1" no són vàlids.', + 'errDataNotJSON' : 'Les dades no són JSON.', + 'errDataEmpty' : 'Les dades estan buides.', + 'errCmdReq' : 'La sol·licitud del rerefons necessita el nom de l\'ordre.', + 'errOpen' : 'No s\'ha pogut obrir "$1".', + 'errNotFolder' : 'L\'objecte no és una carpeta.', + 'errNotFile' : 'L\'objecte no és un fitxer.', + 'errRead' : 'No s\'ha pogut llegir "$1".', + 'errWrite' : 'No s\'ha pogut escriure a "$1".', + 'errPerm' : 'Permís denegat.', + 'errLocked' : '"$1" està bloquejat i no podeu canviar-li el nom, moure-lo ni suprimir-lo.', + 'errExists' : 'Ja existeix un fitxer anomenat "$1".', + 'errInvName' : 'El nom de fitxer no és vàlid.', + 'errFolderNotFound' : 'No s\'ha trobat la carpeta.', + 'errFileNotFound' : 'No s\'ha trobat el fitxer.', + 'errTrgFolderNotFound' : 'No s\'ha trobat la carpeta de destí "$1".', + 'errPopup' : 'El navegador ha evitat obrir una finestra emergent. Autoritzeu-la per obrir el fitxer.', + 'errMkdir' : 'No s\'ha pogut crear la carpeta "$1".', + 'errMkfile' : 'No s\'ha pogut crear el fitxer "$1".', + 'errRename' : 'No s\'ha pogut canviar el nom de "$1".', + 'errCopyFrom' : 'No està permès copiar fitxers des del volum "$1".', + 'errCopyTo' : 'No està permès copiar fitxers al volum "$1".', + 'errUpload' : 'S\'ha produït un error en la càrrega.', + 'errUploadFile' : 'No s\'ha pogut carregar "$1".', + 'errUploadNoFiles' : 'No s\'han trobat fitxers per carregar.', + 'errUploadTotalSize' : 'Les dades excedeixen la mida màxima permesa.', + 'errUploadFileSize' : 'El fitxer excedeix la mida màxima permesa.', + 'errUploadMime' : 'El tipus de fitxer no està permès.', + 'errUploadTransfer' : 'S\'ha produït un error en transferir "$1".', + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : 'No s\'ha pogut desar "$1".', + 'errCopy' : 'No s\'ha pogut copiar "$1".', + 'errMove' : 'No s\'ha pogut moure "$1".', + 'errCopyInItself' : 'No s\'ha pogut copiar "$1" a si mateix.', + 'errRm' : 'No s\'ha pogut suprimir "$1".', + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'No s\'han pogut extreure els fitxers de "$1".', + 'errArchive' : 'No s\'ha pogut crear l\'arxiu.', + 'errArcType' : 'El tipus d\'arxiu no està suportat.', + 'errNoArchive' : 'El fitxer no és un arxiu o és un tipus no suportat.', + 'errCmdNoSupport' : 'El rerefons no suporta aquesta ordre.', + 'errReplByChild' : 'No es pot reemplaçar la carpeta “$1” per un element que conté.', + 'errArcSymlinks' : 'Per raons de seguretat, no es permet extreure arxius que contenen enllaços simbòlics.', + 'errArcMaxSize' : 'Els fitxers de l\'arxiu excedeixen la mida màxima permesa.', + 'errResize' : 'No s\'ha pogut redimensionar "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', + 'errResizeRotate' : 'Unable to rotate image.', + 'errResizeSize' : 'Invalid image size.', + 'errResizeNoChange' : 'Image size not changed.', + 'errUsupportType' : 'El tipus de fitxer no està suportat.', + 'errNotUTF8Content' : 'File "$1" is not in UTF-8 and cannot be edited.', + 'errNetMount' : 'Unable to mount "$1".', + 'errNetMountNoDriver' : 'Unsupported protocol.', + 'errNetMountFailed' : 'Mount failed.', + 'errNetMountHostReq' : 'Host required.', + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Crea arxiu', + 'cmdback' : 'Enrere', + 'cmdcopy' : 'Copia', + 'cmdcut' : 'Retalla', + 'cmddownload' : 'Descarrega', + 'cmdduplicate' : 'Duplica', + 'cmdedit' : 'Edita el fitxer', + 'cmdextract' : 'Extreu els fitxers de l\'arxiu', + 'cmdforward' : 'Endavant', + 'cmdgetfile' : 'Selecciona els fitxers', + 'cmdhelp' : 'Quant a aquest programari', + 'cmdhome' : 'Inici', + 'cmdinfo' : 'Obté informació', + 'cmdmkdir' : 'Nova carpeta', + 'cmdmkfile' : 'Nou fitxer', + 'cmdopen' : 'Obre', + 'cmdpaste' : 'Enganxa', + 'cmdquicklook' : 'Previsualitza', + 'cmdreload' : 'Torna a carregar', + 'cmdrename' : 'Canvia el nom', + 'cmdrm' : 'Suprimeix', + 'cmdsearch' : 'Cerca fitxers', + 'cmdup' : 'Vés al directori superior', + 'cmdupload' : 'Carrega fitxers', + 'cmdview' : 'Visualitza', + 'cmdresize' : 'Redimensiona la imatge', + 'cmdsort' : 'Ordena', + 'cmdnetmount' : 'Mount network volume', + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Tanca', + 'btnSave' : 'Desa', + 'btnRm' : 'Suprimeix', + 'btnApply' : 'Aplica', + 'btnCancel' : 'Cancel·la', + 'btnNo' : 'No', + 'btnYes' : 'Sí', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', + + /******************************** notifications ********************************/ + 'ntfopen' : 'S\'està obrint la carpeta', + 'ntffile' : 'S\'està obrint el fitxer', + 'ntfreload' : 'S\'està tornant a carregar el contingut de la carpeta', + 'ntfmkdir' : 'S\'està creant el directori', + 'ntfmkfile' : 'S\'estan creant el fitxers', + 'ntfrm' : 'S\'estan suprimint els fitxers', + 'ntfcopy' : 'S\'estan copiant els fitxers', + 'ntfmove' : 'S\'estan movent els fitxers', + 'ntfprepare' : 'S\'està preparant per copiar fitxers', + 'ntfrename' : 'S\'estan canviant els noms del fitxers', + 'ntfupload' : 'S\'estan carregant els fitxers', + 'ntfdownload' : 'S\'estan descarregant els fitxers', + 'ntfsave' : 'S\'estan desant els fitxers', + 'ntfarchive' : 'S\'està creant l\'arxiu', + 'ntfextract' : 'S\'estan extreient els fitxers de l\'arxiu', + 'ntfsearch' : 'S\'estan cercant els fitxers', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'S\'estan realitzant operacions', + 'ntfloadimg' : 'S\'està carregant la imatge', + 'ntfnetmount' : 'Mounting network volume', + 'ntfdim' : 'Acquiring image dimension', + + /************************************ dates **********************************/ + 'dateUnknown' : 'desconegut', + 'Today' : 'Avui', + 'Yesterday' : 'Ahir', + 'msJan' : 'gen.', + 'msFeb' : 'febr.', + 'msMar' : 'març', + 'msApr' : 'abr.', + 'msMay' : 'maig', + 'msJun' : 'juny', + 'msJul' : 'jul.', + 'msAug' : 'ag.', + 'msSep' : 'set.', + 'msOct' : 'oct.', + 'msNov' : 'nov.', + 'msDec' : 'des.', + 'January' : 'January', + 'February' : 'February', + 'March' : 'March', + 'April' : 'April', + 'May' : 'May', + 'June' : 'June', + 'July' : 'July', + 'August' : 'August', + 'September' : 'September', + 'October' : 'October', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Sunday', + 'Monday' : 'Monday', + 'Tuesday' : 'Tuesday', + 'Wednesday' : 'Wednesday', + 'Thursday' : 'Thursday', + 'Friday' : 'Friday', + 'Saturday' : 'Saturday', + 'Sun' : 'Sun', + 'Mon' : 'Mon', + 'Tue' : 'Tue', + 'Wed' : 'Wed', + 'Thu' : 'Thu', + 'Fri' : 'Fri', + 'Sat' : 'Sat', + + /******************************** sort variants ********************************/ + 'sortname' : 'per nom', + 'sortkind' : 'per tipus', + 'sortsize' : 'per mida', + 'sortdate' : 'per data', + 'sortFoldersFirst' : 'Folders first', + + /********************************** messages **********************************/ + 'confirmReq' : 'Es necessita confirmació', + 'confirmRm' : 'Voleu suprimir els fitxers?
                      L\'acció es podrà desfer!', + 'confirmRepl' : 'Voleu reemplaçar el fitxer antic amb el nou?', + 'apllyAll' : 'Aplica a tot', + 'name' : 'Nom', + 'size' : 'Mida', + 'perms' : 'Permisos', + 'modify' : 'Modificat', + 'kind' : 'Tipus', + 'read' : 'llegir', + 'write' : 'escriure', + 'noaccess' : 'sense accés', + 'and' : 'i', + 'unknown' : 'desconegut', + 'selectall' : 'Selecciona tots els fitxers', + 'selectfiles' : 'Selecciona el(s) fitxer(s)', + 'selectffile' : 'Selecciona el primer fitxer', + 'selectlfile' : 'Selecciona l\'últim fitxer', + 'viewlist' : 'Vista en llista', + 'viewicons' : 'Vista en icones', + 'places' : 'Llocs', + 'calc' : 'Calcula', + 'path' : 'Camí', + 'aliasfor' : 'Àlies per', + 'locked' : 'Bloquejat', + 'dim' : 'Dimensions', + 'files' : 'Fitxers', + 'folders' : 'Carpetes', + 'items' : 'Elements', + 'yes' : 'sí', + 'no' : 'no', + 'link' : 'Enllaç', + 'searcresult' : 'Resultats de la cerca', + 'selected' : 'Elements seleccionats', + 'about' : 'Quant a', + 'shortcuts' : 'Dreceres', + 'help' : 'Ajuda', + 'webfm' : 'Gestor de fitxers web', + 'ver' : 'Versió', + 'protocolver' : 'versió de protocol', + 'homepage' : 'Pàgina del projecte', + 'docs' : 'Documentació', + 'github' : 'Bifurca\'ns a GitHub', + 'twitter' : 'Segueix-nos a Twitter', + 'facebook' : 'Uniu-vos a Facebook', + 'team' : 'Equip', + 'chiefdev' : 'cap desenvolupador', + 'developer' : 'desenvolupador', + 'contributor' : 'col·laborador', + 'maintainer' : 'mantenidor', + 'translator' : 'traductor', + 'icons' : 'Icones', + 'dontforget' : 'i no oblideu agafar la vostra tovallola', + 'shortcutsof' : 'Les dreceres estan inhabilitades', + 'dropFiles' : 'Arrossegueu els fitxers aquí', + 'or' : 'o', + 'selectForUpload' : 'Seleccioneu els fitxer a carregar', + 'moveFiles' : 'Mou els fitxers', + 'copyFiles' : 'Copia els fitxers', + 'rmFromPlaces' : 'Suprimeix dels llocs', + 'aspectRatio' : 'Relació d\'aspecte', + 'scale' : 'Escala', + 'width' : 'Amplada', + 'height' : 'Alçada', + 'resize' : 'Redimensiona', + 'crop' : 'Retalla', + 'rotate' : 'Rotate', + 'rotate-cw' : 'Rotate 90 degrees CW', + 'rotate-ccw' : 'Rotate 90 degrees CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', + 'protocol' : 'Protocol', + 'host' : 'Host', + 'port' : 'Port', + 'user' : 'User', + 'pass' : 'Password', + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Desconegut', + 'kindFolder' : 'Carpeta', + 'kindAlias' : 'Àlies', + 'kindAliasBroken' : 'Àlies no vàlid', + // applications + 'kindApp' : 'Aplicació', + 'kindPostscript' : 'Document Postscript', + 'kindMsOffice' : 'Document del Microsoft Office', + 'kindMsWord' : 'Document del Microsoft Word', + 'kindMsExcel' : 'Document del Microsoft Excel', + 'kindMsPP' : 'Presentació del Microsoft Powerpoint', + 'kindOO' : 'Document de l\'Open Office', + 'kindAppFlash' : 'Aplicació Flash', + 'kindPDF' : 'Document PDF', + 'kindTorrent' : 'Fitxer Bittorrent', + 'kind7z' : 'Arxiu 7z', + 'kindTAR' : 'Arxiu TAR', + 'kindGZIP' : 'Arxiu GZIP', + 'kindBZIP' : 'Arxiu BZIP', + 'kindXZ' : 'Arxiu XZ', + 'kindZIP' : 'Arxiu ZIP', + 'kindRAR' : 'Arxiu RAR', + 'kindJAR' : 'Fitxer JAR de Java', + 'kindTTF' : 'Tipus de lletra True Type', + 'kindOTF' : 'Tipus de lletra Open Type', + 'kindRPM' : 'Paquet RPM', + // fonts + 'kindFont' : 'Tipus de lletra', + 'kindSFNT' : 'Tipus de lletra SFNT', + 'kindEOT' : 'Tipus de lletra Embedded Open Type', + 'kindWOFF' : 'Tipus de lletra Web Open Font Format', + 'kindWOFF2' : 'Tipus de lletra Web Open Font Format 2', + // texts + 'kindText' : 'Document de text', + 'kindTextPlain' : 'Document de text net', + 'kindPHP' : 'Codi PHP', + 'kindCSS' : 'Full d\'estils CSS', + 'kindHTML' : 'Document HTML', + 'kindJS' : 'Codi Javascript', + 'kindRTF' : 'Document RTF', + 'kindC' : 'Codi C', + 'kindCHeader' : 'Codi de caçalera C', + 'kindCPP' : 'Codi C++', + 'kindCPPHeader' : 'Codi de caçalera C++', + 'kindShell' : 'Script Unix', + 'kindPython' : 'Codi Python', + 'kindJava' : 'Codi Java', + 'kindRuby' : 'Codi Ruby', + 'kindPerl' : 'Script Perl', + 'kindSQL' : 'Codi SQL', + 'kindXML' : 'Document XML', + 'kindAWK' : 'Codi AWK', + 'kindCSV' : 'Document CSV', + 'kindDOCBOOK' : 'Document XML de Docbook', + // images + 'kindImage' : 'Imatge', + 'kindBMP' : 'Imatge BMP', + 'kindJPEG' : 'Imatge JPEG', + 'kindGIF' : 'Imatge GIF', + 'kindPNG' : 'Imatge PNG', + 'kindTIFF' : 'Imatge TIFF', + 'kindTGA' : 'Imatge TGA', + 'kindPSD' : 'Imatge Adobe Photoshop', + 'kindXBITMAP' : 'Imatge X bitmap', + 'kindPXM' : 'Imatge Pixelmator', + // media + 'kindAudio' : 'Fitxer d\'àudio', + 'kindAudioMPEG' : 'Fitxer d\'àudio MPEG', + 'kindAudioMPEG4' : 'Fitxer d\'àudio MPEG-4', + 'kindAudioMIDI' : 'Fitxer d\'àudio MIDI', + 'kindAudioOGG' : 'Fitxer d\'àudio Ogg Vorbis', + 'kindAudioWAV' : 'Fitxer d\'àudio WAV', + 'AudioPlaylist' : 'Llista de reproducció MP3', + 'kindVideo' : 'Fitxer de vídeo', + 'kindVideoDV' : 'Fitxer de vídeo DV', + 'kindVideoMPEG' : 'Fitxer de vídeo MPEG', + 'kindVideoMPEG4' : 'Fitxer de vídeo MPEG-4', + 'kindVideoAVI' : 'Fitxer de vídeo AVI', + 'kindVideoMOV' : 'Fitxer de vídeo Quick Time', + 'kindVideoWM' : 'Fitxer de vídeo Windows Media', + 'kindVideoFlash' : 'Fitxer de vídeo Flash', + 'kindVideoMKV' : 'Fitxer de vídeo Matroska', + 'kindVideoOGG' : 'Fitxer de vídeo Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.cs.js b/lib/redactor/elfinder/js/i18n/elfinder.cs.js new file mode 100644 index 0000000..1145801 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.cs.js @@ -0,0 +1,588 @@ +/** + * Czech translation + * @author RobiNN + * @author Jay Gridley + * @version 2021-06-10 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.cs = { + translator : 'RobiNN <robo@kelcak.com>, Jay Gridley <gridley.jay@hotmail.com>', + language : 'Čeština', + direction : 'ltr', + dateFormat : 'd. m. Y H:i', // will show like: 10. 06. 2021 23:37 + fancyDateFormat : '$1 H:i', // will show like: Dnes 23:37 + nonameDateFormat : 'ymd-His', // noname upload will show like: 210610-233701 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Chyba', + 'errUnknown' : 'Neznámá chyba.', + 'errUnknownCmd' : 'Neznámý příkaz.', + 'errJqui' : 'Nedostačující konfigurace jQuery UI. Musí být zahrnuty komponenty Selectable, Draggable a Droppable.', + 'errNode' : 'elFinder vyžaduje vytvořený DOM Elementu.', + 'errURL' : 'Chybná konfigurace elFinderu! Není nastavena hodnota URL.', + 'errAccess' : 'Přístup zamítnut.', + 'errConnect' : 'Nepodařilo se připojit k backendu.', + 'errAbort' : 'Připojení zrušeno.', + 'errTimeout' : 'Vypšel limit pro připojení.', + 'errNotFound' : 'Backend nenalezen.', + 'errResponse' : 'Nesprávná odpověď backendu.', + 'errConf' : 'Nepsrávná konfigurace backendu.', + 'errJSON' : 'PHP modul JSON není nainstalován.', + 'errNoVolumes' : 'Není dostupný čitelný oddíl.', + 'errCmdParams' : 'Nesprávné parametry příkazu "$1".', + 'errDataNotJSON' : 'Data nejsou ve formátu JSON.', + 'errDataEmpty' : 'Data jsou prázdná.', + 'errCmdReq' : 'Dotaz backendu vyžaduje název příkazu.', + 'errOpen' : 'Chyba při otevírání "$1".', + 'errNotFolder' : 'Objekt není složka.', + 'errNotFile' : 'Objekt není soubor.', + 'errRead' : 'Chyba při čtení "$1".', + 'errWrite' : 'Chyba při zápisu do "$1".', + 'errPerm' : 'Přístup odepřen.', + 'errLocked' : '"$1" je uzamčený a nemůže být přejmenován, přesunut nebo smazán.', + 'errExists' : 'Soubor s názvem "$1" již existuje.', + 'errInvName' : 'Nesprávný název souboru.', + 'errInvDirname' : 'Neplatný název adresáře.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Složka nenalezena.', + 'errFileNotFound' : 'Soubor nenalezen.', + 'errTrgFolderNotFound' : 'Cílová složka "$1" nenalezena.', + 'errPopup' : 'Prohlížeč zabránil otevření vyskakovacího okna. K otevření souboru, povolte vyskakovací okno v prohlížeči.', + 'errMkdir' : 'Nepodařilo se vytvořit složku "$1".', + 'errMkfile' : 'Nepodařilo se vytvořit soubor "$1".', + 'errRename' : 'Nepodařilo se přejmenovat "$1".', + 'errCopyFrom' : 'Kopírování souborů z oddílu "$1" není povoleno.', + 'errCopyTo' : 'Kopírování souborů do oddílu "$1" není povoleno.', + 'errMkOutLink' : 'Nelze vytvořit odkaz mimo kořenového svazku.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Chyba nahrávání.', // old name - errUploadCommon + 'errUploadFile' : 'Nepodařilo se nahrát "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Nejsou vybrány žádné soubory k nahrání.', + 'errUploadTotalSize' : 'Překročena maximální povolená velikost dat.', // old name - errMaxSize + 'errUploadFileSize' : 'Překročena maximální povolená velikost souboru.', // old name - errFileMaxSize + 'errUploadMime' : 'Nepovolený typ souboru.', + 'errUploadTransfer' : '"$1" chyba přenosu.', + 'errUploadTemp' : 'Nelze vytvořit dočasný soubor pro upload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Objekt "$1" v tomto umístění již existuje a nelze jej nahradit s jiným typem objektu.', // new + 'errReplace' : 'Nelze nahradit "$1".', + 'errSave' : '"$1" nelze uložit.', + 'errCopy' : '"$1" nelze zkopírovat.', + 'errMove' : '"$1" nelze přemístit.', + 'errCopyInItself' : '"$1" nelze zkopírovat do sebe sama.', + 'errRm' : '"$1" nelze odstranit.', + 'errTrash' : 'Nelze se dostat do koše.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Nelze odstranit zdrojový soubor(y).', + 'errExtract' : 'Nelze extrahovat soubory z "$1".', + 'errArchive' : 'Nelze vytvořit archív.', + 'errArcType' : 'Nepodporovaný typ archívu.', + 'errNoArchive' : 'Soubor není archív nebo má nepodporovaný formát.', + 'errCmdNoSupport' : 'Backend tento příkaz nepodporuje.', + 'errReplByChild' : 'Složka "$1" nemůže být nahrazena souborem, který sama obsahuje.', + 'errArcSymlinks' : 'Z bezpečnostních důvodů je zakázáno rozbalit archívy obsahující symlinky.', // edited 24.06.2012 + 'errArcMaxSize' : 'Soubory archívu překračují maximální povolenou velikost.', + 'errResize' : 'Nepodařilo se změnit velikost obrázku "$1".', + 'errResizeDegree' : 'Neplatný stupeň rotace.', // added 7.3.2013 + 'errResizeRotate' : 'Nelze otočit obrázek.', // added 7.3.2013 + 'errResizeSize' : 'Neplatná velikost obrázku.', // added 7.3.2013 + 'errResizeNoChange' : 'Velikost obrazu se nezmění.', // added 7.3.2013 + 'errUsupportType' : 'Nepodporovaný typ souboru.', + 'errNotUTF8Content' : 'Soubor "$1" nemá ani obsah kódovaný v UTF-8 a nelze změnit.', // added 9.11.2011 + 'errNetMount' : 'Není možné se připojit "$ 1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Nepodporovaný protokol.', // added 17.04.2012 + 'errNetMountFailed' : 'Připojení se nezdařilo.', // added 17.04.2012 + 'errNetMountHostReq' : 'Hostitel se vyžaduje.', // added 18.04.2012 + 'errSessionExpires' : 'Relace byla ukončena z důvodu nečinnosti.', + 'errCreatingTempDir' : 'Nelze vytvořit dočasný adresář: "$1"', + 'errFtpDownloadFile' : 'Nelze stáhnout soubor z FTP: "$1"', + 'errFtpUploadFile' : 'Nelze nahrát soubor na FTP: "$1"', + 'errFtpMkdir' : 'Nepodařilo se vytvořit vzdálený adresář na FTP: "$1"', + 'errArchiveExec' : 'Při archivaci do souboru došlo k chybě: "$1"', + 'errExtractExec' : 'Chyba při extrahování souboru: "$1"', + 'errNetUnMount' : 'Nepodařilo se odpojit', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Nelze převést na UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Chcete-li nahrát složku, zkuste moderní prohlížeč.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Vypršení časového limitu při hledání "$1". Je částečně výsledkem hledání.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Opětovné povolení je nutné.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Maximální počet volitelných předmětů je $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Nelze obnovit z koše. Nelze identifikovat cíl obnovení.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor tohoto typu souboru nebyl nalezen.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Došlo k chybě na straně serveru.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Nelze vyprázdnit složku "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Existují ještě další $1 chyby.', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'Můžete vytvořit až $1 složek najednou.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Vytvořit archív', + 'cmdback' : 'Zpět', + 'cmdcopy' : 'Kopírovat', + 'cmdcut' : 'Vyjmout', + 'cmddownload' : 'Stáhnout', + 'cmdduplicate' : 'Duplikovat', + 'cmdedit' : 'Upravit soubor', + 'cmdextract' : 'Rozbalit archív', + 'cmdforward' : 'Vpřed', + 'cmdgetfile' : 'Vybrat soubory', + 'cmdhelp' : 'O softwaru', + 'cmdhome' : 'Domů', + 'cmdinfo' : 'Zobrazit informace', + 'cmdmkdir' : 'Nová složka', + 'cmdmkdirin' : 'Do nové složky', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nový soubor', + 'cmdopen' : 'Otevřít', + 'cmdpaste' : 'Vložit', + 'cmdquicklook' : 'Náhled', + 'cmdreload' : 'Obnovit', + 'cmdrename' : 'Přejmenovat', + 'cmdrm' : 'Smazat', + 'cmdtrash' : 'Do koše', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Obnovit', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Najít soubory', + 'cmdup' : 'Přejít do nadřazené složky', + 'cmdupload' : 'Nahrát soubor(y)', + 'cmdview' : 'Zobrazit', + 'cmdresize' : 'Změnit velikost', + 'cmdsort' : 'Seřadit', + 'cmdnetmount' : 'Připojit síťovou jednotku', // added 18.04.2012 + 'cmdnetunmount': 'Odpojit', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Umístění', // added 28.12.2014 + 'cmdchmod' : 'Změnit režim', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Otevření složky', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Obnovení šířku sloupce', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Celá obrazovka', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Posouvat', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Vyprázdnit složku', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Krok zpět', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Udělat to znovu', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preference', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Vyberat vše', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Nic nevyberať', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Invertovat výběr', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Otevři v novém okně', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Skrýt (Předvolba)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Zavřít', + 'btnSave' : 'Uložit', + 'btnRm' : 'Odstranit', + 'btnApply' : 'Použít', + 'btnCancel' : 'Zrušit', + 'btnNo' : 'Ne', + 'btnYes' : 'Ano', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Připojit', // added 18.04.2012 + 'btnApprove': 'Přejít do části 1 $ & schválit', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Odpojit', // from v2.1 added 30.04.2012 + 'btnConv' : 'Převést', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Tu', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Médium', // from v2.1 added 22.5.2015 + 'btnAll' : 'Všechno', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME typ', // from v2.1 added 22.5.2015 + 'btnFileName':'Název souboru', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Uložit & zavřít', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Zálohovat', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Přejmenovat', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Přejmenovat vše', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Předch ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Další ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Uložit jako', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Otevírání složky', + 'ntffile' : 'Otevírání souboru', + 'ntfreload' : 'Obnovování obsahu složky', + 'ntfmkdir' : 'Vytváření složky', + 'ntfmkfile' : 'Vytváření souborů', + 'ntfrm' : 'Vymazání položek', + 'ntfcopy' : 'Kopírování položek', + 'ntfmove' : 'Přemístění položek', + 'ntfprepare' : 'Kontrola existujících položek', + 'ntfrename' : 'Přejmenovávání souborů', + 'ntfupload' : 'Nahrávání souborů', + 'ntfdownload' : 'Stahování souborů', + 'ntfsave' : 'Ukládání souborů', + 'ntfarchive' : 'Vytváření archívu', + 'ntfextract' : 'Rozbalování souborů z archívu', + 'ntfsearch' : 'Vyhledávání souborů', + 'ntfresize' : 'Změna velikosti obrázků', + 'ntfsmth' : 'Čekejte prosím...', + 'ntfloadimg' : 'Načítání obrázků', + 'ntfnetmount' : 'Připojení síťového média', // added 18.04.2012 + 'ntfnetunmount': 'Odpojení síťového média', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Získejte rozměr obrazu', // added 20.05.2013 + 'ntfreaddir' : 'Přečtěte si informace o složce', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Získejte adresu URL odkazu', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Změna souboru', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Zkontrolujte název nahravaného souboru', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Vytvořit soubor ke stažení', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Získání informací o cestě', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Zpracování nahraného souboru', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Hodit do koše', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Obnova z koše', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Kontrola cílové složky', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Zrušit předchozí operaci', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Obnovit předchozí zrušení', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Kontrola obsahu', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Koš', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'neznámý', + 'Today' : 'Dnes', + 'Yesterday' : 'Včera', + 'msJan' : 'Led', + 'msFeb' : 'Úno', + 'msMar' : 'Bře', + 'msApr' : 'Dub', + 'msMay' : 'Kvě', + 'msJun' : 'Čer', + 'msJul' : 'Čec', + 'msAug' : 'Srp', + 'msSep' : 'Zář', + 'msOct' : 'Říj', + 'msNov' : 'Lis', + 'msDec' : 'Pro', + 'January' : 'Leden', + 'February' : 'Únor', + 'March' : 'Březen', + 'April' : 'Duben', + 'May' : 'Květen', + 'June' : 'Červen', + 'July' : 'Červenec', + 'August' : 'Srpen', + 'September' : 'Září', + 'October' : 'Říjen', + 'November' : 'Listopad', + 'December' : 'Prosinec', + 'Sunday' : 'Neděle', + 'Monday' : 'Pondělí', + 'Tuesday' : 'Úterý', + 'Wednesday' : 'Středa', + 'Thursday' : 'Čtvrtek', + 'Friday' : 'Pátek', + 'Saturday' : 'Sobota', + 'Sun' : 'Ne', + 'Mon' : 'Po', + 'Tue' : 'Út', + 'Wed' : 'St', + 'Thu' : 'Čt', + 'Fri' : 'Pá', + 'Sat' : 'So', + + /******************************** sort variants ********************************/ + 'sortname' : 'dle jména', + 'sortkind' : 'dle typu', + 'sortsize' : 'dle velikosti', + 'sortdate' : 'dle data', + 'sortFoldersFirst' : 'Napřed složky', + 'sortperm' : 'dle povolení', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'dle módu', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'dle majitele', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'dle skupiny', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Také stromové zobrazení', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'Nový soubor.txt', // added 10.11.2015 + 'untitled folder' : 'Nová složka', // added 10.11.2015 + 'Archive' : 'Nový archiv', // from v2.1 added 10.11.2015 + 'untitled file' : 'Nový soubor.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1 soubor', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Požadováno potvrzení', + 'confirmRm' : 'Opravdu chcete odstranit tyto soubory?
                      Operace nelze vrátit!', + 'confirmRepl' : 'Nahradit staré soubory novými?', + 'confirmRest' : 'Nahradit stávající položku položkou z koše?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Není v UTF-8, převést do UTF-8?
                      Obsah po převodu se stává UTF-8.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Kódování tohoto souboru nemoholo rozpoznán. Pro úpravy je třeba dočasně převést do kódování UTF-8.
                      Prosím, vyberte kódování znaků souboru.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Byl změněn.
                      Pokud obsahuje neuložené změny, dojde ke ztrátě práce.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Opravdu chcete položky přesunout do koše?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Opravdu chcete položky přesunout do "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Pro všechny', + 'name' : 'Název', + 'size' : 'Velikost', + 'perms' : 'Práva', + 'modify' : 'Upravený', + 'kind' : 'Typ', + 'read' : 'čtení', + 'write' : 'zápis', + 'noaccess' : 'přístup odepřen', + 'and' : 'a', + 'unknown' : 'neznámý', + 'selectall' : 'Vybrat všechny položky', + 'selectfiles' : 'Vybrat položku(y)', + 'selectffile' : 'Vybrat první položku', + 'selectlfile' : 'Vybrat poslední položku', + 'viewlist' : 'Seznam', + 'viewicons' : 'Ikony', + 'viewSmall' : 'Malé ikony', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Střední ikony', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Velké ikony', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Extra velké ikony', // from v2.1.39 added 22.5.2018 + 'places' : 'Místa', + 'calc' : 'Vypočítat', + 'path' : 'Cesta', + 'aliasfor' : 'Zástupce pro', + 'locked' : 'Uzamčený', + 'dim' : 'Rozměry', + 'files' : 'Soubory', + 'folders' : 'Složky', + 'items' : 'Položky', + 'yes' : 'ano', + 'no' : 'ne', + 'link' : 'Odkaz', + 'searcresult' : 'Výsledky hledání', + 'selected' : 'vybrané položky', + 'about' : 'O softwaru', + 'shortcuts' : 'Zkratky', + 'help' : 'Nápověda', + 'webfm' : 'Webový správce souborů', + 'ver' : 'Verze', + 'protocolver' : 'verze protokolu', + 'homepage' : 'Domovská stránka projektu', + 'docs' : 'Dokumentace', + 'github' : 'Najdete nás na Gitgube', + 'twitter' : 'Následujte nás na Twitteri', + 'facebook' : 'Připojte se k nám na Facebooku', + 'team' : 'Tým', + 'chiefdev' : 'séf vývojářů', + 'developer' : 'vývojár', + 'contributor' : 'spolupracovník', + 'maintainer' : 'údržba', + 'translator' : 'překlad', + 'icons' : 'Ikony', + 'dontforget' : 'a nezapomeňte si vzít plavky', + 'shortcutsof' : 'Zkratky nejsou povoleny', + 'dropFiles' : 'Sem přetáhněte soubory', + 'or' : 'nebo', + 'selectForUpload' : 'Vyberte soubory', + 'moveFiles' : 'Přesunout sobory', + 'copyFiles' : 'Zkopírovat soubory', + 'restoreFiles' : 'Obnovit položky', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Odstranit z míst', + 'aspectRatio' : 'Poměr stran', + 'scale' : 'Měřítko', + 'width' : 'Šířka', + 'height' : 'Výška', + 'resize' : 'Změnit vel.', + 'crop' : 'Ořezat', + 'rotate' : 'Otočit', + 'rotate-cw' : 'Otočit o +90 stupňů', + 'rotate-ccw' : 'Otočit o -90 stupňů', + 'degree' : ' stupňů', + 'netMountDialogTitle' : 'Připojení síťového média', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Uživatel', // added 18.04.2012 + 'pass' : 'Heslo', // added 18.04.2012 + 'confirmUnmount' : 'Chcete odpojit $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Přemístěte nebo přesuňte soubory z prohlížeče', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Zde přemístěte nebo přesuňte soubory a adresy URL', // from v2.1 added 07.04.2014 + 'encoding' : 'Kódování', // from v2.1 added 19.12.2014 + 'locale' : 'Lokalizce', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Cíl: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Vyhledávání podle vstupního MIME typu', // from v2.1 added 22.5.2015 + 'owner' : 'Majitel', // from v2.1 added 20.6.2015 + 'group' : 'Skupina', // from v2.1 added 20.6.2015 + 'other' : 'Ostatní', // from v2.1 added 20.6.2015 + 'execute' : 'Spustit', // from v2.1 added 20.6.2015 + 'perm' : 'Povolení', // from v2.1 added 20.6.2015 + 'mode' : 'Režim', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Složka je prázdná', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Složka je prázdná, přesunout nebo zkontrolovat položky', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Složka je prázdná, dlouhim kliknutím přidáte položky', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kvalita', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Automatická synchronizace', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Přesunout nahoru', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Získat URL odkaz', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Vybrané položky ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID složky', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Povolit přístup offline', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Znovu ověřit', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Načítání...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Otevření více souborů', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Pokoušíte se otevřít soubor $1. Chcete jej otevřít v prohlížeči?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Výsledky hledání jsou prázdné', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Upravujete soubor.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Vybrali jste $1 položky.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Máte $1 položky v schránce.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Inkrementální hledání je pouze z aktuálního zobrazení.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Obnovit', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 kompletní', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Kontextové menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Otáčení stránky', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Kořeny média', // from v2.1.16 added 16.9.2016 + 'reset' : 'Obnovit', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Barva pozadí', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Výběr barvy', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px mřížka', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Povoleno', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Zakázáno', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Výsledky hledání jsou prázdné v aktuálním zobrazení.\\Stisknutím tlačítka [Enter] rozšíříte vyhledávání cíle.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Výsledky vyhledávání prvního listu jsou v aktuálním zobrazení prázdné.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Nápis textu', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 minut zůstává', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Otevřít pomocí zvoleného kódování', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Uložit s vybraným kódováním', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Vyberte složku', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Hledání prvního listu', // from v2.1.23 added 24.3.2017 + 'presets' : 'Předvolby', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Je to příliš mnoho položek, takže se nemohou dostat do koše.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Textarea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Vyprázdnit složku "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Ve složce "$1" nejsou žádné položky.', // from v2.1.25 added 22.6.2017 + 'preference' : 'Předvolby', // from v2.1.26 added 28.6.2017 + 'language' : 'Nastavte jazyk', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Inicializujte nastavení uložená v tomto prohlížeči', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Nastavení panelu nástrojů', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '...$1 znaků zbývá.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '...$1 řádků zůstává.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Součet', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Hrubá velikost souboru', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Zaměření na prvek dialogu s mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Vybrat', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Akce při vybraném souboru', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Otevřít pomocí naposledy použitého editoru', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Obrátit výběr položek', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Opravdu chcete přejmenovat $1 vybraných položek, jako například $2
                      Není to možné vrátit zpět!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch přejmenování', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Číslo', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Přidat předponu', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Přidat příponu', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Změnit příponu', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Nastavení sloupců (Zobrazení seznamu)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Všechny změny se okamžitě projeví v archivu.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Jakékoliv změny se nebudou odrážet, dokud nebude tento svazek odpojen.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Následující svazky namontované na tomto svazku jsou také odpojeny. Opravdu ji odpojíte?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Informace o výběru', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmy pro zobrazení hashování souborů', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Informační položky (panel s informacemi o výběru)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Dalším stisknutím opustíte.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Panel nástrojů', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Pracovní prostor', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'Všechno', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Velikost ikony (zobrazení ikon)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Otevřete maximalizované okno editora', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Protože konverze podle API momentálně není k dispozici, převeďte na webové stránce.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Po konverzi musíte nahrát převeden soubor pomocí URL položky nebo stažený soubor k uložení převedeného souboru.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Převést na stránce $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrace', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Tento elFinder má integrované následující externí služby. Před použitím zkontrolujte podmínky používání, zásady ochrany osobních údajů atd.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Zobrazit skryté položky', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Skrýt skryté položky', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Zobrazit/skrýt skryté položky', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Typy souborů, jež mají být povoleny pomocí "Nový soubor"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Typ textového souboru', // from v2.1.41 added 7.8.2018 + 'add' : 'Přidat', // from v2.1.41 added 7.8.2018 + 'theme' : 'Téma', // from v2.1.43 added 19.10.2018 + 'default' : 'Výchozí', // from v2.1.43 added 19.10.2018 + 'description' : 'Popis', // from v2.1.43 added 19.10.2018 + 'website' : 'Stránka', // from v2.1.43 added 19.10.2018 + 'author' : 'Autor', // from v2.1.43 added 19.10.2018 + 'email' : 'E-mail', // from v2.1.43 added 19.10.2018 + 'license' : 'Licence', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Tuto položku nelze uložit. Abyste se vyhnuli ztrátě úprav, musíte je exportovat do počítače.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Poklepáním na soubor jej vyberte.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Použít režim celé obrazovky', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Neznámý', + 'kindRoot' : 'Kořen média', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Složka', + 'kindSelects' : 'Výběry', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Zlomený alias', + // applications + 'kindApp' : 'Aplikace', + 'kindPostscript' : 'Dokument Postscriptu', + 'kindMsOffice' : 'Dokument Microsoft Office', + 'kindMsWord' : 'Dokument Microsoft Word', + 'kindMsExcel' : 'Dokument Microsoft Excel', + 'kindMsPP' : 'Prezentace Microsoft Powerpoint', + 'kindOO' : 'Otevřít dokument Office', + 'kindAppFlash' : 'Flash aplikace', + 'kindPDF' : 'PDF', + 'kindTorrent' : 'Soubor BitTorrent', + 'kind7z' : 'Archív 7z', + 'kindTAR' : 'Archív TAR', + 'kindGZIP' : 'Archív GZIP', + 'kindBZIP' : 'Archív BZIP', + 'kindXZ' : 'Archív XZ', + 'kindZIP' : 'Archív ZIP', + 'kindRAR' : 'Archív RAR', + 'kindJAR' : 'Soubor Java JAR', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM balíček', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Textový dokument', + 'kindTextPlain' : 'Čistý text', + 'kindPHP' : 'PHP zdrojový kód', + 'kindCSS' : 'Kaskádové styly', + 'kindHTML' : 'HTML dokument', + 'kindJS' : 'Javascript zdrojový kód', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C zdrojový kód', + 'kindCHeader' : 'C hlavička', + 'kindCPP' : 'C++ zdrojový kód', + 'kindCPPHeader' : 'C++ hlavička', + 'kindShell' : 'Unix shell skript', + 'kindPython' : 'Python zdrojový kód', + 'kindJava' : 'Java zdrojový kód', + 'kindRuby' : 'Ruby zdrojový kód', + 'kindPerl' : 'Perl skript', + 'kindSQL' : 'SQL zdrojový kód', + 'kindXML' : 'Dokument XML', + 'kindAWK' : 'AWK zdrojový kód', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Docbook XML dokument', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Obrázek', + 'kindBMP' : 'Obrázek BMP', + 'kindJPEG' : 'Obrázek JPEG', + 'kindGIF' : 'Obrázek GIF', + 'kindPNG' : 'Obrázek PNG', + 'kindTIFF' : 'Obrázek TIFF', + 'kindTGA' : 'Obrázek TGA', + 'kindPSD' : 'Obrázek Adobe Photoshop', + 'kindXBITMAP' : 'Obrázek X bitmapa', + 'kindPXM' : 'Obrázek Pixelmator', + // media + 'kindAudio' : 'Audio sobory', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video sobory', + 'kindVideoDV' : 'DV video', + 'kindVideoMPEG' : 'MPEG video', + 'kindVideoMPEG4' : 'MPEG-4 video', + 'kindVideoAVI' : 'AVI video', + 'kindVideoMOV' : 'Quick Time video', + 'kindVideoWM' : 'Windows Media video', + 'kindVideoFlash' : 'Flash video', + 'kindVideoMKV' : 'Matroska video', + 'kindVideoOGG' : 'Ogg video' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.da.js b/lib/redactor/elfinder/js/i18n/elfinder.da.js new file mode 100644 index 0000000..7998e9f --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.da.js @@ -0,0 +1,587 @@ +/** + * Danish translation + * @author Mark Topper (webman.io) + * @author Helmuth Mikkelsen + * @version 2020-11-27 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.da = { + translator : 'Mark Topper (webman.io), Helmuth Mikkelsen <helmuthm@gmail.com>', + language : 'Danish', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // will show like: 27.11.2020 11:50 + fancyDateFormat : '$1 H:i', // will show like: I dag 11:50 + nonameDateFormat : 'Ymd-His', // noname upload will show like: 20201127-115006 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Fejl', + 'errUnknown' : 'Ukendt fejl.', + 'errUnknownCmd' : 'Ukendt kommando.', + 'errJqui' : 'Ugyldig jQuery UI-konfiguration. Valgbare, trækbare og dropbare komponenter skal medtages.', + 'errNode' : 'elFinder kræver DOM Element oprettet.', + 'errURL' : 'Ugyldig elFinder konfiguration! URL option er ikke sat.', + 'errAccess' : 'Adgang nægtet.', + 'errConnect' : 'Kan ikke få kontatkt med backend.', + 'errAbort' : 'Forbindelse afbrudt.', + 'errTimeout' : 'Forbindelse timeout.', + 'errNotFound' : 'Backend ikke fundet.', + 'errResponse' : 'Ugyldigt backend svar.', + 'errConf' : 'Ugyldig backend konfiguration.', + 'errJSON' : 'PHP JSON modul ikke installeret.', + 'errNoVolumes' : 'Læsbare diskenheder er ikke tilgængelige.', + 'errCmdParams' : 'Ugyldige parametre for kommando "$1".', + 'errDataNotJSON' : 'Data er ikke JSON.', + 'errDataEmpty' : 'Data er tom.', + 'errCmdReq' : 'Backend-anmodning kræver kommandonavn.', + 'errOpen' : 'Kunne ikke åbne "$1".', + 'errNotFolder' : 'Objektet er ikke en mappe.', + 'errNotFile' : 'Objektet er ikke en fil.', + 'errRead' : 'Kunne ikke læse "$1".', + 'errWrite' : 'Kunne ikke skrive til "$1".', + 'errPerm' : 'Adgang nægtet.', + 'errLocked' : '"$1" er låst og kan ikke blive omdøbt, flyttet eller slettet.', + 'errExists' : 'Der findes allerede en fil ved navn "$1".', + 'errInvName' : 'Ugyldigt filnavn.', + 'errInvDirname' : 'Ugyldigt mappenavn.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Mappe ikke fundet.', + 'errFileNotFound' : 'Fil ikke fundet.', + 'errTrgFolderNotFound' : 'Mappen "$1" blev ikke fundet.', + 'errPopup' : 'Browser forhindrede åbning af pop up-vindue. For at åbne filen skal du aktivere den i browserindstillinger.', + 'errMkdir' : 'Kunne ikke oprette mappen "$1".', + 'errMkfile' : 'Kunne ikke oprette filen "$1".', + 'errRename' : 'Kunne ikke omdøbe "$1".', + 'errCopyFrom' : 'Kopiering af filer fra diskenhed "$1" er ikke tilladt.', + 'errCopyTo' : 'Kopiering af filer til diskenhed "$1" er ikke tilladt.', + 'errMkOutLink' : 'Kan ikke oprette et link til uden for diskenhedsroden.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Upload fejl.', // old name - errUploadCommon + 'errUploadFile' : 'Kunne ikke uploade "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Ingen filer fundet til upload.', + 'errUploadTotalSize' : 'Data overskrider den maksimalt tilladte størrelse.', // old name - errMaxSize + 'errUploadFileSize' : 'Fil overskrider den maksimalt tilladte størrelse.', // old name - errFileMaxSize + 'errUploadMime' : 'Filtype ikke godkendt.', + 'errUploadTransfer' : '"$1" overførselsfejl.', + 'errUploadTemp' : 'Kan ikke oprette midlertidig fil til upload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Objekt "$1" findes allerede på dette sted og kan ikke erstattes af objekt med en anden type.', // new + 'errReplace' : 'Kan ikke erstatte "$1".', + 'errSave' : 'Kunne ikke gemme "$1".', + 'errCopy' : 'Kunne ikke kopiere "$1".', + 'errMove' : 'Kunne ikke flytte "$1".', + 'errCopyInItself' : 'Kunne ikke kopiere "$1" til sig selv.', + 'errRm' : 'Kunne ikke slette "$1".', + 'errTrash' : 'Kan ikke komme i papirkurven.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Kunne ikke fjerne kildefil(er).', + 'errExtract' : 'Kunne ikke udpakke filer fra "$1".', + 'errArchive' : 'Kunne ikke oprette arkiv.', + 'errArcType' : 'Arkivtypen er ikke understøttet.', + 'errNoArchive' : 'Filen er ikke et arkiv eller har ien kke-understøttet arkivtype.', + 'errCmdNoSupport' : 'Backend understøtter ikke denne kommando.', + 'errReplByChild' : 'Mappen "$1" kan ikke erstattes af et element, den indeholder.', + 'errArcSymlinks' : 'Af sikkerhedsmæssige årsager nægtes at udpakke arkiver der indeholder symlinks eller filer med ikke-tilladte navne.', // edited 24.06.2012 + 'errArcMaxSize' : 'Arkivfiler overskrider den maksimalt tilladte størrelse.', + 'errResize' : 'Kunne ikke ændre størrelsen på "$1".', + 'errResizeDegree' : 'Ugyldig rotationsgrad.', // added 7.3.2013 + 'errResizeRotate' : 'Kunne ikke rotere billedet.', // added 7.3.2013 + 'errResizeSize' : 'Ugyldig billedstørrelse.', // added 7.3.2013 + 'errResizeNoChange' : 'Billedstørrelse ikke ændret.', // added 7.3.2013 + 'errUsupportType' : 'Ikke-understøttet filtype.', + 'errNotUTF8Content' : 'Filen "$1" er ikke i UTF-8 og kan ikke blive redigeret.', // added 9.11.2011 + 'errNetMount' : 'Kunne ikke mounte "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Ikke-understøttet protokol.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount mislykkedes.', // added 17.04.2012 + 'errNetMountHostReq' : 'Værten kræves.', // added 18.04.2012 + 'errSessionExpires' : 'Din session er udløbet på grund af inaktivitet.', + 'errCreatingTempDir' : 'Kunne ikke oprette midlertidig mappe: "$1"', + 'errFtpDownloadFile' : 'Kunne ikke downloade filen fra FTP: "$1"', + 'errFtpUploadFile' : 'Kunne ikke uploade filen til FTP: "$1"', + 'errFtpMkdir' : 'Kunne ikke oprette fjernmappe på FTP: "$1"', + 'errArchiveExec' : 'Fejl under arkivering af filer: "$1"', + 'errExtractExec' : 'Fejl under udpakning af filer: "$1"', + 'errNetUnMount' : 'Kan ikke unmounte.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Kan ikke konverteres til UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Prøv den nyeste browser, hvis du vil uploade mappen.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Time out under søgning på "$1". Søgeresultatet er delvis.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Re-autorisation er påkrævet.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Maksimalt antal valgbare emner er $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Kan ikke gendannes fra papirkurven. Kan ikke identificere gendannelsesdestinationen.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor blev ikke fundet til denne filtype.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Der opstod en fejl på serversiden.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Kunne ikke tømme mappen "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Der er $1 flere fejl.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Opret arkiv', + 'cmdback' : 'Tilbage', + 'cmdcopy' : 'Kopier', + 'cmdcut' : 'Klip', + 'cmddownload' : 'Download', + 'cmdduplicate' : 'Dupliker', + 'cmdedit' : 'Rediger fil', + 'cmdextract' : 'Udpak filer fra arkiv', + 'cmdforward' : 'Frem', + 'cmdgetfile' : 'Vælg filer', + 'cmdhelp' : 'Om denne software', + 'cmdhome' : 'Hjem', + 'cmdinfo' : 'Information', + 'cmdmkdir' : 'Ny mappe', + 'cmdmkdirin' : 'I en ny mappe', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Ny fil', + 'cmdopen' : 'Åben', + 'cmdpaste' : 'Indsæt', + 'cmdquicklook' : 'Vis', + 'cmdreload' : 'Genindlæs', + 'cmdrename' : 'Omdøb', + 'cmdrm' : 'Slet', + 'cmdtrash' : 'I papirkurven', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Gendan', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Find filer', + 'cmdup' : 'Gå til overordnet mappe', + 'cmdupload' : 'Upload filer', + 'cmdview' : 'Vis', + 'cmdresize' : 'Tilpas størrelse & Roter', + 'cmdsort' : 'Sorter', + 'cmdnetmount' : 'Mount netværksdrev', // added 18.04.2012 + 'cmdnetunmount': 'Unmount', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Til steder', // added 28.12.2014 + 'cmdchmod' : 'Skift tilstand', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Åbn en mappe', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Nulstil søjlebredde', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Fuld skærm', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Flyt', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Tøm mappe', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Fortryd', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Gentag igen', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Præferencer', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Vælg alle', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Vælg ingen', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Inverter valg', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Åbn i nyt vindue', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Skjul (præference)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Luk', + 'btnSave' : 'Gem', + 'btnRm' : 'Slet', + 'btnApply' : 'Anvend', + 'btnCancel' : 'Annuler', + 'btnNo' : 'Nej', + 'btnYes' : 'Ja', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', // added 18.04.2012 + 'btnApprove': 'Gå til $1 & godkend', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Konverter', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Her', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Diskenhed', // from v2.1 added 22.5.2015 + 'btnAll' : 'Alle', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME-type', // from v2.1 added 22.5.2015 + 'btnFileName':'Filnavn', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Gem & Luk', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Omdøb', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Omdøb(Alle)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Forrige ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Næste ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Gem som', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Åben mappe', + 'ntffile' : 'Åben fil', + 'ntfreload' : 'Genindlæs mappeindhold', + 'ntfmkdir' : 'Opretter mappe', + 'ntfmkfile' : 'Opretter filer', + 'ntfrm' : 'Sletter filer', + 'ntfcopy' : 'Kopier filer', + 'ntfmove' : 'Flytter filer', + 'ntfprepare' : 'Kontrol af eksisterende emner', + 'ntfrename' : 'Omdøb filer', + 'ntfupload' : 'Uploader filer', + 'ntfdownload' : 'Downloader filer', + 'ntfsave' : 'Gemmer filer', + 'ntfarchive' : 'Opretter arkiv', + 'ntfextract' : 'Udpakker filer fra arkiv', + 'ntfsearch' : 'Søger filer', + 'ntfresize' : 'Ændring af størrelsen på billeder', + 'ntfsmth' : 'Gør noget', + 'ntfloadimg' : 'Henter billede', + 'ntfnetmount' : 'Mounter netværksdrev', // added 18.04.2012 + 'ntfnetunmount': 'Unmounter netværksdrev', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Henter billeddimension', // added 20.05.2013 + 'ntfreaddir' : 'Læser folderinfomation', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Får URL til link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Ændring af filtilstand', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Bekræftelse af upload filnavn', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Oprettelse af en fil til download', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Få stiinformation', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Behandler den uploadede fil', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Smider i papirkurv', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Udfører gendannelse fra papirkurven', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Kontrollerer destinationsmappe', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Fortryder tidligere handling', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Gentager tidligere fortryd', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Kontrol af indhold', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Papirkurv', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'ukendt', + 'Today' : 'I dag', + 'Yesterday' : 'I går', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Maj', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Januar', + 'February' : 'Februar', + 'March' : 'Marts', + 'April' : 'April', + 'May' : 'Maj', + 'June' : 'Juni', + 'July' : 'Juli', + 'August' : 'August', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Søndag', + 'Monday' : 'Mandag', + 'Tuesday' : 'Tirsdag', + 'Wednesday' : 'Onsdag', + 'Thursday' : 'Torsdag', + 'Friday' : 'Fredag', + 'Saturday' : 'Lørdag', + 'Sun' : 'Søn', + 'Mon' : 'Man', + 'Tue' : 'Tir', + 'Wed' : 'Ons', + 'Thu' : 'Tor', + 'Fri' : 'Fre', + 'Sat' : 'Lør', + + /******************************** sort variants ********************************/ + 'sortname' : 'efter navn', + 'sortkind' : 'efter type', + 'sortsize' : 'efter størrelse', + 'sortdate' : 'efter dato', + 'sortFoldersFirst' : 'Mapper først', + 'sortperm' : 'efter tilladelse', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'efter mode', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'efter ejer', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'efter gruppe', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Også Treeview', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NyFil.txt', // added 10.11.2015 + 'untitled folder' : 'NyFolder', // added 10.11.2015 + 'Archive' : 'NytArkiv', // from v2.1 added 10.11.2015 + 'untitled file' : 'NyFil.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: Fil', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Bekræftelse påkrævet', + 'confirmRm' : 'Er du sikker på du vil slette valgte filer?
                      Dette kan ikke fortrydes!', + 'confirmRepl' : 'Erstat gammel fil med ny fil?', + 'confirmRest' : 'Erstat eksisterende element med elementet i papirkurven?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Ikke i UTF-8
                      Konverter til UTF-8?
                      Indholdet bliver UTF-8 ved at gemme efter konvertering.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Tegnkodning af denne fil kunne ikke registreres. Det er nødvendigt at konvertere midlertidigt til UTF-8 til redigering.
                      Vælg tegnkodning af denne fil.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Det er blevet ændret.
                      Du mister arbejde, hvis du ikke gemmer ændringer.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Er du sikker på, at du vil flytte emner til papirkurven?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Er du sikker på, at du vil flytte emner til "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Anvend ved alle', + 'name' : 'Navn', + 'size' : 'Størrelse', + 'perms' : 'Rettigheder', + 'modify' : 'Ændret', + 'kind' : 'Type', + 'read' : 'læse', + 'write' : 'skrive', + 'noaccess' : 'ingen adgang', + 'and' : 'og', + 'unknown' : 'ukendt', + 'selectall' : 'Vælg alle filer', + 'selectfiles' : 'Vælg fil(er)', + 'selectffile' : 'Vælg første fil', + 'selectlfile' : 'Vælg sidste fil', + 'viewlist' : 'Listevisning', + 'viewicons' : 'Ikonvisning', + 'viewSmall' : 'Små ikoner', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Medium ikoner', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Store ikoner', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Ekstra store ikoner', // from v2.1.39 added 22.5.2018 + 'places' : 'Placeringer', + 'calc' : 'Beregn', + 'path' : 'Sti', + 'aliasfor' : 'Alias for', + 'locked' : 'Låst', + 'dim' : 'Størrelser', + 'files' : 'Filer', + 'folders' : 'Mapper', + 'items' : 'Emner', + 'yes' : 'ja', + 'no' : 'nej', + 'link' : 'Link', + 'searcresult' : 'Søgeresultater', + 'selected' : 'valgte emner', + 'about' : 'Om', + 'shortcuts' : 'Genveje', + 'help' : 'Hjælp', + 'webfm' : 'Internet filmanager', + 'ver' : 'Version', + 'protocolver' : 'protokol version', + 'homepage' : 'Projektside', + 'docs' : 'Dokumentation', + 'github' : 'Fork os på Github', + 'twitter' : 'Følg os på Twitter', + 'facebook' : 'Følg os på Facebook', + 'team' : 'Hold', + 'chiefdev' : 'hovedudvikler', + 'developer' : 'udvikler', + 'contributor' : 'bidragyder', + 'maintainer' : 'vedligeholder', + 'translator' : 'oversætter', + 'icons' : 'Ikoner', + 'dontforget' : 'og glem ikke at tage dit håndklæde', + 'shortcutsof' : 'Gemveje deaktiveret', + 'dropFiles' : 'Drop filer hertil', + 'or' : 'eller', + 'selectForUpload' : 'Vælg filer', + 'moveFiles' : 'Flyt filer', + 'copyFiles' : 'Kopier filer', + 'restoreFiles' : 'Gendan emner', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Slet fra placering', + 'aspectRatio' : 'Skærmformat', + 'scale' : 'Skala', + 'width' : 'Bredde', + 'height' : 'Højde', + 'resize' : 'Tilpas størrelse', + 'crop' : 'Beskær', + 'rotate' : 'Roter', + 'rotate-cw' : 'Roter 90 grader med uret', + 'rotate-ccw' : 'Roter 90 grader mod uret', + 'degree' : 'Grader', + 'netMountDialogTitle' : 'Mount netwærkdrev', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Vært', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Bruger', // added 18.04.2012 + 'pass' : 'Kodeord', // added 18.04.2012 + 'confirmUnmount' : 'Unmounter du $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Slip eller indsæt filer fra browseren', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Slip filer, indsæt webadresser eller billeder (udklipsholder) her', // from v2.1 added 07.04.2014 + 'encoding' : 'Encoding', // from v2.1 added 19.12.2014 + 'locale' : 'Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Target: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Søg efter input MIME-type', // from v2.1 added 22.5.2015 + 'owner' : 'Ejer', // from v2.1 added 20.6.2015 + 'group' : 'Gruppe', // from v2.1 added 20.6.2015 + 'other' : 'Andet', // from v2.1 added 20.6.2015 + 'execute' : 'Udfør', // from v2.1 added 20.6.2015 + 'perm' : 'Tilladelse', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Mappe er tom', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Mappe er tom\\A Drop for at tilføje enmer', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Mappen er tom\\A Langt tryk for at tilføje emner', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kvalitet', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Autosync', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Flyt op', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Hent URL-link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Valgte emner ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Folder-ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Tillad offline adgang', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'For at godkende igen', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Indlæser nu...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Åben flere filer', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Du prøver at åbne $1-filerne. Er du sikker på, at du vil åbne i browseren?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Søgeresultaterne er tomme i søgemålet.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Redigerer en fil.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Du har valgt $1 emner.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Du har $1 emner i udklipsholder.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Inkrementel søgning er kun fra den aktuelle visning.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Genindsæt', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 færdig', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Kontekstmenu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Sidevending', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Diskenheds rødder', // from v2.1.16 added 16.9.2016 + 'reset' : 'Nulstil', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Baggrundsfarve', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Farvevælger', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px grid', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Aktiveret', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Deaktiveret', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Søgeresultaterne er tomme i den aktuelle visning.\\ATryk på [Enter] for at udvide søgemålet.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Førstebogstavs søgeresultater er tomme i den aktuelle visning.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Tekstlabel', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 minutter tilbage', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Åbn igen med valgt encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Gem med valgt encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Vælg mappe', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Førstebogstavs søgning', // from v2.1.23 added 24.3.2017 + 'presets' : 'Forudindstillinger', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Det er for mange emner, så det kan ikke komme i papirkurven.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Tøm mappen "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Der er ingen emner i mappen "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Præference', // from v2.1.26 added 28.6.2017 + 'language' : 'Sprog', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialiser de indstillinger, der er gemt i denne browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Værktøjslinjens indstillinger', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 tegn tilbage.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 linjer tilbage.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Sum', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Omtrentlig filstørrelse', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Fokuser på elementet i dialog med musemarkering', // from v2.1.30 added 2.11.2017 + 'select' : 'Vælg', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Handling, når du vælger fil', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Åbn med den editor, der blev brugt sidst', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Inverter valg', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Er du sikker på, at du vil omdøbe $1 valgte emner som $2?
                      Dette kan ikke fortrydes!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch omdøbning', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Tal', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Tilføj prefix', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Tilføj suffix', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Skift filendelse', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Kolonneindstillinger (listevisning)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Alle ændringer påvirker straks arkivet.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Eventuelle ændringer gennemføres ikke, før denne enhed fjernes.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Følgende disk(e) mounted på denne enhed unmountes også. Er du sikker på at unmounte den?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Valg info', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmer, der viser filens hash', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info-emner (panelet til valg af info)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Tryk igen for at afslutte.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Værktøjslinje', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Arbejdsområde', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'Alle', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Ikonstørrelse (ikonvisning)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Åbn det maksimerede editorvindue', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Da konvertering via API ikke er tilgængelig i øjeblikket, bedes du konvertere på webstedet.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Efter konvertering skal du uploade med elementets URL eller en downloadet fil for at gemme den konverterede fil.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Konverter på stedet på $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrationer', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Denne elFinder har følgende eksterne tjenester integreret. Kontroller venligst vilkårene for brug, fortrolighedspolitik osv. inden du bruger det.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Vis skjulte emner', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Skjul skjulte emner', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Vis / Skjul skjulte emner', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Filtyper, der skal aktiveres med "Ny fil"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type af tekstfilen', // from v2.1.41 added 7.8.2018 + 'add' : 'Tilføj', // from v2.1.41 added 7.8.2018 + 'theme' : 'Tema', // from v2.1.43 added 19.10.2018 + 'default' : 'Standard', // from v2.1.43 added 19.10.2018 + 'description' : 'Beskrivelse', // from v2.1.43 added 19.10.2018 + 'website' : 'Hjemmeside', // from v2.1.43 added 19.10.2018 + 'author' : 'Forfatter', // from v2.1.43 added 19.10.2018 + 'email' : 'Mail', // from v2.1.43 added 19.10.2018 + 'license' : 'Licens', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Dette element kan ikke gemmes. For at undgå at miste redigeringerne skal du eksportere til din pc.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Dobbeltklik på filen for at vælge den.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Brug fuldskærmstilstand', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Ukendt', + 'kindRoot' : 'Diskenheds rod', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Mappe', + 'kindSelects' : 'Valg', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Ødelagt alias', + // applications + 'kindApp' : 'Applikation', + 'kindPostscript' : 'Postscript dokument', + 'kindMsOffice' : 'Microsoft Office dokument', + 'kindMsWord' : 'Microsoft Word dokument', + 'kindMsExcel' : 'Microsoft Excel dokument', + 'kindMsPP' : 'Microsoft Powerpoint præsentation', + 'kindOO' : 'Open Office dokument', + 'kindAppFlash' : 'Flash applikation', + 'kindPDF' : 'Flytbart Dokument Format (PDF)', + 'kindTorrent' : 'Bittorrent fil', + 'kind7z' : '7z arkiv', + 'kindTAR' : 'TAR arkiv', + 'kindGZIP' : 'GZIP arkiv', + 'kindBZIP' : 'BZIP arkiv', + 'kindXZ' : 'XZ arkiv', + 'kindZIP' : 'ZIP arkiv', + 'kindRAR' : 'RAR arkiv', + 'kindJAR' : 'Java JAR fil', + 'kindTTF' : 'True Type skrift', + 'kindOTF' : 'Open Type skrift', + 'kindRPM' : 'RPM pakke', + // fonts + 'kindFont' : 'Skrift', + 'kindSFNT' : 'SFNT skrift', + 'kindEOT' : 'Embedded Open Type skrift', + 'kindWOFF' : 'Web Open Font Format skrift', + 'kindWOFF2' : 'Web Open Font Format 2 skrift', + // texts + 'kindText' : 'Tekstdokument', + 'kindTextPlain' : 'Ren tekst', + 'kindPHP' : 'PHP-kode', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML-dokument', + 'kindJS' : 'Javascript-kode', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'Ckkode', + 'kindCHeader' : 'C header-kode', + 'kindCPP' : 'C++-kode', + 'kindCPPHeader' : 'C++ header-kode', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python-kode', + 'kindJava' : 'Java-kode', + 'kindRuby' : 'Ruby-kode', + 'kindPerl' : 'Perlscript', + 'kindSQL' : 'SQ- kode', + 'kindXML' : 'XML-dokument', + 'kindAWK' : 'AWK-kode', + 'kindCSV' : 'Komma seperarede værdier', + 'kindDOCBOOK' : 'Docbook XML-dokument', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Billede', + 'kindBMP' : 'BMP-billede', + 'kindJPEG' : 'JPEG-billede', + 'kindGIF' : 'GIF-billede', + 'kindPNG' : 'PNG-billede', + 'kindTIFF' : 'TIFF-billede', + 'kindTGA' : 'TGA-billede', + 'kindPSD' : 'Adobe Photoshop-billede', + 'kindXBITMAP' : 'X bitmap-billede', + 'kindPXM' : 'Pixelmator-billede', + // media + 'kindAudio' : 'Lydmedie', + 'kindAudioMPEG' : 'MPEG-lyd', + 'kindAudioMPEG4' : 'MPEG-4-lyd', + 'kindAudioMIDI' : 'MIDI-lyd', + 'kindAudioOGG' : 'Ogg Vorbis-lyd', + 'kindAudioWAV' : 'WAV-lyd', + 'AudioPlaylist' : 'MP3-spilleliste', + 'kindVideo' : 'Videomedie', + 'kindVideoDV' : 'DV-video', + 'kindVideoMPEG' : 'MPEG-video', + 'kindVideoMPEG4' : 'MPEG-4-video', + 'kindVideoAVI' : 'AVI-video', + 'kindVideoMOV' : 'Quick Time-video', + 'kindVideoWM' : 'Windows Media-video', + 'kindVideoFlash' : 'Flash-video', + 'kindVideoMKV' : 'Matroska-video', + 'kindVideoOGG' : 'Ogg-video' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.de.js b/lib/redactor/elfinder/js/i18n/elfinder.de.js new file mode 100644 index 0000000..1930229 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.de.js @@ -0,0 +1,589 @@ +/** + * German Translation / Deutsche Übersetzung + * @author JPG & Mace + * @author tora60 from pragmaMx.org + * @author Timo-Linde + * @author OSWorX + * @author Maximilian Schwarz + * @author SF Webdesign + * @version 2019-12-13 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.de = { + translator : 'JPG & Mace <dev@flying-datacenter.de>, tora60 from pragmaMx.org, Timo-Linde <info@timo-linde.de>, OSWorX <info@osworx.net>, Maximilian Schwarz <info@deefuse.de>, SF Webdesign <webdesign@stephan-frank.de>', + language : 'Deutsch', + direction : 'ltr', + dateFormat : 'j. F Y H:i', // 3. März 2020 14:58 + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'ymd-His', // to apply if upload file is noname: 120513172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Fehler', + 'errUnknown' : 'Unbekannter Fehler.', + 'errUnknownCmd' : 'Unbekannter Befehl.', + 'errJqui' : 'Ungültige jQuery UI-Konfiguration. Die Komponenten Selectable, Draggable und Droppable müssen inkludiert sein.', + 'errNode' : 'Für elFinder muss das DOM-Element erstellt werden.', + 'errURL' : 'Ungültige elFinder-Konfiguration! Die URL-Option ist nicht gesetzt.', + 'errAccess' : 'Zugriff verweigert.', + 'errConnect' : 'Verbindung zum Backend fehlgeschlagen.', + 'errAbort' : 'Verbindung abgebrochen.', + 'errTimeout' : 'Zeitüberschreitung der Verbindung.', + 'errNotFound' : 'Backend nicht gefunden.', + 'errResponse' : 'Ungültige Backend-Antwort.', + 'errConf' : 'Ungültige Backend-Konfiguration.', + 'errJSON' : 'PHP JSON-Modul nicht vorhanden.', + 'errNoVolumes' : 'Keine lesbaren Laufwerke vorhanden.', + 'errCmdParams' : 'Ungültige Parameter für Befehl: "$1".', + 'errDataNotJSON' : 'Daten nicht im JSON-Format.', + 'errDataEmpty' : 'Daten sind leer.', + 'errCmdReq' : 'Backend-Anfrage benötigt Befehl.', + 'errOpen' : 'Kann "$1" nicht öffnen.', + 'errNotFolder' : 'Objekt ist kein Ordner.', + 'errNotFile' : 'Objekt ist keine Datei.', + 'errRead' : 'Kann "$1" nicht öffnen.', + 'errWrite' : 'Kann nicht in "$1" schreiben.', + 'errPerm' : 'Zugriff verweigert.', + 'errLocked' : '"$1" ist gesperrt und kann nicht umbenannt, verschoben oder gelöscht werden.', + 'errExists' : 'Die Datei "$1" existiert bereits.', + 'errInvName' : 'Ungültiger Dateiname.', + 'errInvDirname' : 'Ungültiger Ordnername.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Ordner nicht gefunden.', + 'errFileNotFound' : 'Datei nicht gefunden.', + 'errTrgFolderNotFound' : 'Zielordner "$1" nicht gefunden.', + 'errPopup' : 'Der Browser hat das Pop-Up-Fenster unterbunden. Um die Datei zu öffnen, Pop-Ups in den Browsereinstellungen aktivieren.', + 'errMkdir' : 'Kann Ordner "$1" nicht erstellen.', + 'errMkfile' : 'Kann Datei "$1" nicht erstellen.', + 'errRename' : 'Kann "$1" nicht umbenennen.', + 'errCopyFrom' : 'Kopieren von Dateien von "$1" nicht erlaubt.', + 'errCopyTo' : 'Kopieren von Dateien nach "$1" nicht erlaubt.', + 'errMkOutLink' : 'Der Link kann nicht außerhalb der Partition führen.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Upload-Fehler.', // old name - errUploadCommon + 'errUploadFile' : 'Kann "$1" nicht hochladen.', // old name - errUpload + 'errUploadNoFiles' : 'Keine Dateien zum Hochladen gefunden.', + 'errUploadTotalSize' : 'Gesamtgröße überschreitet die Maximalgröße.', // old name - errMaxSize + 'errUploadFileSize' : 'Die Datei überschreitet die Maximalgröße.', // old name - errFileMaxSize + 'errUploadMime' : 'Dateiart (mime) nicht zulässig.', + 'errUploadTransfer' : '"$1" Übertragungsfehler.', + 'errUploadTemp' : 'Kann temporäre Datei nicht erstellen.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Das Objekt "$1" existiert bereits an dieser Stelle und kann nicht durch ein Objekt eines anderen Typs ersetzt werden.', // new + 'errReplace' : 'Kann "$1" nicht ersetzen.', + 'errSave' : 'Kann "$1" nicht speichern.', + 'errCopy' : 'Kann "$1" nicht kopieren.', + 'errMove' : 'Kann "$1" nicht verschieben.', + 'errCopyInItself' : '"$1" kann sich nicht in sich selbst kopieren.', + 'errRm' : 'Kann "$1" nicht entfernen.', + 'errTrash' : 'Kann Objekt nicht in Mülleimer legen.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Kann Quelldatei(en) nicht entfernen.', + 'errExtract' : 'Kann "$1" nicht entpacken.', + 'errArchive' : 'Archiv konnte nicht erstellt werden.', + 'errArcType' : 'Archivtyp nicht untersützt.', + 'errNoArchive' : 'Bei der Datei handelt es sich nicht um ein Archiv, oder die Archivart wird nicht unterstützt.', + 'errCmdNoSupport' : 'Das Backend unterstützt diesen Befehl nicht.', + 'errReplByChild' : 'Der Ordner "$1" kann nicht durch etwas ersetzt werden, das ihn selbst enthält.', + 'errArcSymlinks' : 'Aus Sicherheitsgründen ist es verboten, ein Archiv mit symbolischen Links zu extrahieren.', // edited 24.06.2012 + 'errArcMaxSize' : 'Die Archivdateien übersteigen die maximal erlaubte Größe.', + 'errResize' : 'Größe von "$1" kann nicht geändert werden.', + 'errResizeDegree' : 'Ungültiger Rotationswert.', // added 7.3.2013 + 'errResizeRotate' : 'Bild konnte nicht gedreht werden.', // added 7.3.2013 + 'errResizeSize' : 'Ungültige Bildgröße.', // added 7.3.2013 + 'errResizeNoChange' : 'Bildmaße nicht geändert.', // added 7.3.2013 + 'errUsupportType' : 'Nicht unterstützte Dateiart.', + 'errNotUTF8Content' : 'Die Datei "$1" ist nicht im UTF-8-Format und kann nicht bearbeitet werden.', // added 9.11.2011 + 'errNetMount' : 'Verbindung mit "$1" nicht möglich.', // added 17.04.2012 + 'errNetMountNoDriver' : 'Nicht unterstütztes Protokoll.', // added 17.04.2012 + 'errNetMountFailed' : 'Verbindung fehlgeschlagen.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host benötigt.', // added 18.04.2012 + 'errSessionExpires' : 'Diese Sitzung ist aufgrund von Inaktivität abgelaufen.', + 'errCreatingTempDir' : 'Erstellung des temporären Ordners nicht möglich: "$1"', + 'errFtpDownloadFile' : 'Download der Datei über FTP nicht möglich: "$1"', + 'errFtpUploadFile' : 'Upload der Datei zu FTP nicht möglich: "$1"', + 'errFtpMkdir' : 'Erstellung des Remote-Ordners mit FTP nicht möglich: "$1"', + 'errArchiveExec' : 'Fehler beim Archivieren der Dateien: "$1"', + 'errExtractExec' : 'Fehler beim Extrahieren der Dateien: "$1"', + 'errNetUnMount' : 'Kann nicht ausgehängt werden.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Kann nicht zu UTF-8 konvertiert werden.', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Ordner kann nich hochladen werden, eventuell mit Google Chrome versuchen.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Zeitüberschreitung während der Suche nach "$1". Suchergebnis ist unvollständig.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Erneutes Anmelden ist erforderlich.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Die maximale Anzahl auswählbarer Elemente ist $1', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Datei konnte nicht aus Mülleimer wieder hergestellt werden bzw. Ziel für Wiederherstellung nicht gefunden.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Kein Editor für diesen Dateityp gefunden.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Ein serverseitiger Fehler trat auf.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Konnte Ordner "$1" nicht Leeren.', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Es sind noch $1 weitere Fehler.', // from v2.1.44 added 13.12.2019 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Archiv erstellen', + 'cmdback' : 'Zurück', + 'cmdcopy' : 'Kopieren', + 'cmdcut' : 'Ausschneiden', + 'cmddownload' : 'Herunterladen', + 'cmdduplicate' : 'Duplizieren', + 'cmdedit' : 'Datei bearbeiten', + 'cmdextract' : 'Archiv entpacken', + 'cmdforward' : 'Vorwärts', + 'cmdgetfile' : 'Datei auswählen', + 'cmdhelp' : 'Über diese Software', + 'cmdhome' : 'Startordner', + 'cmdinfo' : 'Informationen', + 'cmdmkdir' : 'Neuer Ordner', + 'cmdmkdirin' : 'In neuen Ordner', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Neuer Datei', + 'cmdopen' : 'Öffnen', + 'cmdpaste' : 'Einfügen', + 'cmdquicklook' : 'Vorschau', + 'cmdreload' : 'Aktualisieren', + 'cmdrename' : 'Umbenennen', + 'cmdrm' : 'Löschen', + 'cmdtrash' : 'In den Mülleimer legen', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Wiederherstellen', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Suchen', + 'cmdup' : 'In übergeordneten Ordner wechseln', + 'cmdupload' : 'Datei hochladen', + 'cmdview' : 'Ansehen', + 'cmdresize' : 'Größe ändern & drehen', + 'cmdsort' : 'Sortieren', + 'cmdnetmount' : 'Verbinde mit Netzwerkspeicher', // added 18.04.2012 + 'cmdnetunmount': 'Abhängen', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Favoriten', // added 28.12.2014 + 'cmdchmod' : 'Berechtigung ändern', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Einen Ordner öffnen', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Spaltenbreite zurücksetzen', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Vollbild', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Verschieben', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Ordner Leeren', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Rückgängig', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Wiederholen', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Einstellungen', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Alle auswählen', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Keine auswählen', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Auswahl rückgängig machen', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'In neuem Fenster öffnen', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Verstecken', // from v2.1.41 added 13.12.2019 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Schließen', + 'btnSave' : 'Speichern', + 'btnRm' : 'Entfernen', + 'btnApply' : 'Anwenden', + 'btnCancel' : 'Abbrechen', + 'btnNo' : 'Nein', + 'btnYes' : 'Ja', + 'btnDiscard': 'Änderungen verwerfen', + 'btnMount' : 'Verbinden', // added 18.04.2012 + 'btnApprove': 'Gehe zu $1 und genehmige', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Auswerfen', // from v2.1 added 30.04.2012 + 'btnConv' : 'Konvertieren', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Arbeitspfad', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Partition', // from v2.1 added 22.5.2015 + 'btnAll' : 'Alle', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME-Typ', // from v2.1 added 22.5.2015 + 'btnFileName':'Dateiname', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Speichern & Schließen', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Sicherung', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Umbenennen', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Alle Umbenennen', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Zurück ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Weiter ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Speichern als', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Öffne Ordner', + 'ntffile' : 'Öffne Datei', + 'ntfreload' : 'Ordnerinhalt neu', + 'ntfmkdir' : 'Erstelle Ordner', + 'ntfmkfile' : 'Erstelle Dateien', + 'ntfrm' : 'Lösche Dateien', + 'ntfcopy' : 'Kopiere Dateien', + 'ntfmove' : 'Verschiebe Dateien', + 'ntfprepare' : 'Kopiervorgang initialisieren', + 'ntfrename' : 'Benenne Dateien um', + 'ntfupload' : 'Dateien hochladen', + 'ntfdownload' : 'Dateien herunterladen', + 'ntfsave' : 'Speichere Datei', + 'ntfarchive' : 'Erstelle Archiv', + 'ntfextract' : 'Entpacke Dateien', + 'ntfsearch' : 'Suche', + 'ntfresize' : 'Bildgrößen ändern', + 'ntfsmth' : 'Bin beschäftigt ..', + 'ntfloadimg' : 'Lade Bild ..', + 'ntfnetmount' : 'Mit Netzwerkspeicher verbinden', // added 18.04.2012 + 'ntfnetunmount': 'Netzwerkspeicher auswerfen', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Bildgröße erfassen', // added 20.05.2013 + 'ntfreaddir' : 'Lese Ordnerinformationen', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Hole URL von Link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Ändere Dateiberechtigungen', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Upload-Dateinamen überprüfen', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Erstelle Datei zum Download', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Beziehe Pfad Informationen', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Upload läuft', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Bewege in den Mülleimer', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Wiederherstellung aus Mülleimer', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Prüfe Zielordner', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Vorherige Operation rückgängig machen', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Wiederherstellen', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Überprüfe Inhalte', // from v2.1.41 added 13.12.2019 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Mülleimer', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'unbekannt', + 'Today' : 'Heute', + 'Yesterday' : 'Gestern', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mär', + 'msApr' : 'Apr', + 'msMay' : 'Mai', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dez', + 'January' : 'Januar', + 'February' : 'Februar', + 'March' : 'März', + 'April' : 'April', + 'May' : 'Mai', + 'June' : 'Juni', + 'July' : 'Juli', + 'August' : 'August', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'November', + 'December' : 'Dezember', + 'Sunday' : 'Sonntag', + 'Monday' : 'Montag', + 'Tuesday' : 'Dienstag', + 'Wednesday' : 'Mittwoch', + 'Thursday' : 'Donnerstag', + 'Friday' : 'Freitag', + 'Saturday' : 'Samstag', + 'Sun' : 'So', + 'Mon' : 'Mo', + 'Tue' : 'Di', + 'Wed' : 'Mi', + 'Thu' : 'Do', + 'Fri' : 'Fr', + 'Sat' : 'Sa', + + /******************************** sort variants ********************************/ + 'sortname' : 'nach Name', + 'sortkind' : 'nach Art', + 'sortsize' : 'nach Größe', + 'sortdate' : 'nach Datum', + 'sortFoldersFirst' : 'Ordner zuerst', + 'sortperm' : 'nach Berechtigung', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'nach Modus', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'nach Besitzer', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'nach Gruppe', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'auch Baumansicht', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'Neues Textdokument (.txt)', // added 10.11.2015 + 'untitled folder' : 'Neuer Ordner', // added 10.11.2015 + 'Archive' : 'Neues Archiv', // from v2.1 added 10.11.2015 + 'untitled file' : 'Neue Datei $1', // from v2.1.41 added 13.12.2019 + 'extentionfile' : '$1: Datei', // from v2.1.41 added 13.12.2019 + 'extentiontype' : '$1: $2', // from v2.1.43 added 13.12.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Bestätigung benötigt', + 'confirmRm' : 'Sollen die Dateien gelöscht werden?
                      Vorgang ist endgültig!', + 'confirmRepl' : 'Datei ersetzen?', + 'confirmRest' : 'Vorhandenes Element durch das Element aus Mülleimer ersetzen?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Nicht UTF-8 kodiert
                      Zu UTF-8 konvertieren?
                      Inhalte werden zu UTF-8 konvertiert bei Speicherung.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Die Zeichencodierung dieser Datei konnte nicht erkannt werden. Es muss vorübergehend in UTF-8 zur Bearbeitung konvertiert werden.
                      Bitte eine Zeichenkodierung dieser Datei auswählen.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Die Datei wurde geändert.
                      Änderungen gehen verloren, wenn nicht gespeichert wird.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Sicher diese Elemente in den Mülleimer verschieben?', // from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Sicher alle Elemente nach "$1" verschieben?', // from v2.1.50 added 13.12.2019 + 'apllyAll' : 'Alles bestätigen', + 'name' : 'Name', + 'size' : 'Größe', + 'perms' : 'Berechtigungen', + 'modify' : 'Geändert', + 'kind' : 'Typ', + 'read' : 'Lesen', + 'write' : 'Schreiben', + 'noaccess' : 'Kein Zugriff', + 'and' : 'und', + 'unknown' : 'unbekannt', + 'selectall' : 'Alle Dateien auswählen', + 'selectfiles' : 'Dateien auswählen', + 'selectffile' : 'Erste Datei auswählen', + 'selectlfile' : 'Letzte Datei auswählen', + 'viewlist' : 'Spaltenansicht', + 'viewicons' : 'Symbolansicht', + 'viewSmall' : 'Kleine Icons', // from v2.1.39 added 13.12.2019 + 'viewMedium' : 'Medium Icons', // from v2.1.39 added 13.12.2019 + 'viewLarge' : 'Große Icons', // from v2.1.39 added 13.12.2019 + 'viewExtraLarge' : 'Extragroße Icons', // from v2.1.39 added 13.12.2019 + 'places' : 'Favoriten', + 'calc' : 'Berechne', + 'path' : 'Pfad', + 'aliasfor' : 'Verknüpfung zu', + 'locked' : 'Gesperrt', + 'dim' : 'Bildgröße', + 'files' : 'Dateien', + 'folders' : 'Ordner', + 'items' : 'Objekte', + 'yes' : 'ja', + 'no' : 'nein', + 'link' : 'Link', + 'searcresult' : 'Suchergebnisse', + 'selected' : 'Objekte ausgewählt', + 'about' : 'Über', + 'shortcuts' : 'Tastenkombinationen', + 'help' : 'Hilfe', + 'webfm' : 'Web-Dateiverwaltung', + 'ver' : 'Version', + 'protocolver' : 'Protokoll-Version', + 'homepage' : 'Projekt-Webseite', + 'docs' : 'Dokumentation', + 'github' : 'Forke uns auf Github', + 'twitter' : 'Folge uns auf twitter', + 'facebook' : 'Begleite uns auf facebook', + 'team' : 'Team', + 'chiefdev' : 'Chefentwickler', + 'developer' : 'Entwickler', + 'contributor' : 'Unterstützer', + 'maintainer' : 'Maintainer', + 'translator' : 'Übersetzer', + 'icons' : 'Icons', + 'dontforget' : 'und vergiss nicht .. morgen ist auch noch ein Tag ..', + 'shortcutsof' : 'Tastenkombinationen deaktiviert', + 'dropFiles' : 'Dateien hier ablegen', + 'or' : 'oder', + 'selectForUpload' : 'Dateien zum Upload auswählen', + 'moveFiles' : 'Dateien verschieben', + 'copyFiles' : 'Dateien kopieren', + 'restoreFiles' : 'Elemente wiederherstellen', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Lösche von Favoriten', + 'aspectRatio' : 'Seitenverhältnis', + 'scale' : 'Maßstab', + 'width' : 'Breite', + 'height' : 'Höhe', + 'resize' : 'Größe ändern', + 'crop' : 'Zuschneiden', + 'rotate' : 'Drehen', + 'rotate-cw' : 'Drehe 90° im Uhrzeigersinn', + 'rotate-ccw' : 'Drehe 90° gegen Uhrzeigersinn', + 'degree' : '°', + 'netMountDialogTitle' : 'verbinde Netzwerkspeicher', // added 18.04.2012 + 'protocol' : 'Protokoll', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Benutzer', // added 18.04.2012 + 'pass' : 'Passwort', // added 18.04.2012 + 'confirmUnmount' : 'Soll "$1" ausgehängt werden', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Dateien in den Browser ziehen', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Dateien hier loslassen', // from v2.1 added 07.04.2014 + 'encoding' : 'Kodierung', // from v2.1 added 19.12.2014 + 'locale' : 'Lokal', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Ziel: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Suche nach MIME-Typ', // from v2.1 added 22.5.2015 + 'owner' : 'Besitzer', // from v2.1 added 20.6.2015 + 'group' : 'Gruppe', // from v2.1 added 20.6.2015 + 'other' : 'Andere', // from v2.1 added 20.6.2015 + 'execute' : 'Ausführen', // from v2.1 added 20.6.2015 + 'perm' : 'Berechtigung', // from v2.1 added 20.6.2015 + 'mode' : 'Modus', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Der Ordner ist leer', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Der Ordner ist leer\\A Elemente durch Ziehen hinzufügen', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Der Ordner ist leer\\A Elemente durch langes Tippen hinzufügen', // from v2.1.6 added 30.12.2015 + 'quality' : 'Qualität', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Automatische Synchronisation', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Nach oben bewegen', // from v2.1.6 added 18.1.2016 + 'getLink' : 'URL-Link holen', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Ausgewählte Objekte ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Ordner-ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Offline-Zugriff erlauben', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Erneut anmelden', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Wird geladen...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'mehrere Dateien öffnen', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Es wird versucht die $1 Dateien zu öffnen .. sicher im Browser öffnen?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Kein Suchergebnis', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Datei wird bearbeitet.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1 Objekt(e) ausgewählt.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '$1 Objekte im Clipboard.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Inkrementelle Suche bezieht sich nur auf die aktuelle Ansicht.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Wiederherstellen', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 abgeschlossen', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Kontextmenü', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Seite umblättern', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume-Rootverzeichnisse', // from v2.1.16 added 16.9.2016 + 'reset' : 'Neustart', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Hintergrund Farbe', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Farbauswahl', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Raster', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Ein', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Aus', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Keine Ergebnisse in der aktuellen Anzeige', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Die Ergebnisse der ersten Buchstabensuche sind in der aktuellen Ansicht leer.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Text Bezeichnung', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 Minuten übrig', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Wiedereröffnen mit ausgewählter Codierung', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Speichern mit der gewählten Kodierung', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Verzeichnis auswählen', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Erster Buchstabe suche', // from v2.1.23 added 24.3.2017 + 'presets' : 'Voreinstellungen', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Zu viele Elemente auf einmal für den Mülleimer.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Textbereich', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Leere Ordner "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Es befinden sich keine Elemente im Ordner "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Einstellungen', // from v2.1.26 added 28.6.2017 + 'language' : 'Spracheinstellungen', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialisiere die Einstellungen, welche in diesem Browser gespeichert sind', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Toolbareinstellung', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 Zeichen übrig', // from v2.1.29 added 30.8.2017 + 'sum' : 'Summe', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Ungefähre Dateigröße', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Fokussierung auf das Element Dialog mit Mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Auswählen', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Aktion bei der Auswahl der Datei', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Öffnen mit dem zuletzt verwendeten Editor', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Auswahl umkehren', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Sicher $1 ausgewählte Elemente in $2 umbenennen?
                      Rückgängig nicht möglich!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Stapelumbenennung', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Nummer', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Vorzeichen hinzufügen', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Nachzeichen hinzufügen', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Erweiterung ändern', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Spalteneinstellungen (Listenansicht)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Alle Änderungen werden sofort im Archiv angewendet.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Alle Änderungen werden nicht angewendet bis dieses Volume entfernt wird.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Die folgenden Datenträger, die auf diesem Datenträger eingehängt sind, werden ebenfalls ausgehängt. Sicher dass alle aushängt werden sollen?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Auswahl Info', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Datei-Hash-Algorithmen', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info-Elemente (Auswahl-Info-Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Drücken Sie erneut, um zu beenden.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Symbolleiste', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Arbeitsplatz', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'Alle', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Icongröße (Symbolansicht)', // form v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Öffne Editorfenster in voller Größe', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Aktuell keine API zur Bearbeitung verfügbar, bitte auf Webseite bearbeiten', //from v2.1.40 added 13.12.2019 + 'editorConvNeedUpload' : 'Um zu speichern nach der Bearbeitung Element entweder mit URL hochladen oder mit herunter geladener Datei', // from v2.1.40 added 13.12.2019 + 'convertOn' : 'Bearbeiten auf Seite $1', // from v2.1.40 added 13.12.2019 + 'integrations' : 'Integrationen', // from v2.1.40 added 13.12.2019 + 'integrationWith' : 'Diese Software hat folgende externe Dienste integriert. Vor Anwendung bitte die jeweiligen Nutzungsbedingungen usw. beachten', // from v2.1.40 added 13.12.2019 + 'showHidden' : 'Zeige versteckte Elemente', // from v2.1.41 added 13.12.2019 + 'hideHidden' : 'Verberge versteckte Elemente', // from v2.1.41 added 13.12.2019 + 'toggleHidden' : 'Zeige/Verberge versteckte Elemente', // from v2.1.41 added 13.12.2019 + 'makefileTypes' : 'Dateiarten bei "Neue Datei" aktivieren', // from v2.1.41 added 13.12.2019 + 'typeOfTextfile' : 'Art der Textdatei', // from v2.1.41 added 13.12.2019 + 'add' : 'Neu', // from v2.1.41 added 13.12.2019 + 'theme' : 'Thema', // from v2.1.43 added 13.12.2019 + 'default' : 'Standard', // from v2.1.43 added 13.12.2019 + 'description' : 'Beschreibung', // from v2.1.43 added 13.12.2019 + 'website' : 'Webseite', // from v2.1.43 added 13.12.2019 + 'author' : 'Autor', // from v2.1.43 added 13.12.2019 + 'email' : 'Email', // from v2.1.43 added 13.12.2019 + 'license' : 'Lizenz', // from v2.1.43 added 13.12.2019 + 'exportToSave' : 'Dieses Element kann nicht gespeichert werden. Um Änderungen nicht zu verlieren, muss es auf den lokalen PC exportiert werden', // from v2.1.44 added 13.12.2019 + 'dblclickToSelect': 'Doppelt auf Datei klicken um auszuwählen', // from v2.1.47 added 13.12.2019 + 'useFullscreen' : 'Gesamter Bildschirm', // from v2.1.47 added 13.12.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Unbekannt', + 'kindRoot' : 'Stammverzeichnis', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Ordner', + 'kindSelects' : 'Auswahlkriterien', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Verknüpfung', + 'kindAliasBroken' : 'Defekte Verknüpfung', + // applications + 'kindApp' : 'Programm', + 'kindPostscript' : 'Postscript-Dokument', + 'kindMsOffice' : 'MS Office-Dokument', + 'kindMsWord' : 'MS Word-Dokument', + 'kindMsExcel' : 'MS Excel-Dokument', + 'kindMsPP' : 'MS Powerpoint-Präsentation', + 'kindOO' : 'Open Office-Dokument', + 'kindAppFlash' : 'Flash', + 'kindPDF' : 'Portables Dokumentenformat (PDF)', + 'kindTorrent' : 'Bittorrent-Datei', + 'kind7z' : '7z-Archiv', + 'kindTAR' : 'TAR-Archiv', + 'kindGZIP' : 'GZIP-Archiv', + 'kindBZIP' : 'BZIP-Archiv', + 'kindXZ' : 'XZ-Archiv', + 'kindZIP' : 'ZIP-Archiv', + 'kindRAR' : 'RAR-Archiv', + 'kindJAR' : 'Java JAR-Datei', + 'kindTTF' : 'True Type-Schrift', + 'kindOTF' : 'Open Type-Schrift', + 'kindRPM' : 'RPM-Paket', + // fonts + 'kindFont' : 'Schriftart', + 'kindSFNT' : 'SFNT-Schrift', + 'kindEOT' : 'Embedded-Open-Type-Schrift', + 'kindWOFF' : 'Web-Open-Font-Format-Schrift', + 'kindWOFF2' : 'Web-Open-Font-Format-2-Schrift', + // texts + 'kindText' : 'Text-Dokument', + 'kindTextPlain' : 'Text-Dokument', + 'kindPHP' : 'PHP-Quelltext', + 'kindCSS' : 'CSS Stilvorlage', + 'kindHTML' : 'HTML-Dokument', + 'kindJS' : 'Javascript-Quelltext', + 'kindRTF' : 'Formatierte Textdatei', + 'kindC' : 'C-Quelltext', + 'kindCHeader' : 'C Header-Quelltext', + 'kindCPP' : 'C++ Quelltext', + 'kindCPPHeader' : 'C++ Header-Quelltext', + 'kindShell' : 'Unix-Shell-Skript', + 'kindPython' : 'Python-Quelltext', + 'kindJava' : 'Java-Quelltext', + 'kindRuby' : 'Ruby-Quelltext', + 'kindPerl' : 'Perl Script', + 'kindSQL' : 'SQL-Quelltext', + 'kindXML' : 'XML-Dokument', + 'kindAWK' : 'AWK-Quelltext', + 'kindCSV' : 'Kommagetrennte Daten', + 'kindDOCBOOK' : 'Docbook XML-Dokument', + 'kindMarkdown' : 'Markdown-Text', // added 20.7.2015 + // images + 'kindImage' : 'Bild', + 'kindBMP' : 'Bitmap-Bild', + 'kindJPEG' : 'JPEG-Bild', + 'kindGIF' : 'GIF-Bild', + 'kindPNG' : 'PNG-Bild', + 'kindTIFF' : 'TIFF-Bild', + 'kindTGA' : 'TGA-Bild', + 'kindPSD' : 'Adobe Photoshop-Dokument', + 'kindXBITMAP' : 'X Bitmap-Bild', + 'kindPXM' : 'Pixelmator-Bild', + // media + 'kindAudio' : 'Audiodatei', + 'kindAudioMPEG' : 'MPEG Audio', + 'kindAudioMPEG4' : 'MPEG-4 Audio', + 'kindAudioMIDI' : 'MIDI Audio', + 'kindAudioOGG' : 'Ogg Vorbis Audio', + 'kindAudioWAV' : 'WAV Audio', + 'AudioPlaylist' : 'MP3-Playlist', + 'kindVideo' : 'Videodatei', + 'kindVideoDV' : 'DV Film', + 'kindVideoMPEG' : 'MPEG Film', + 'kindVideoMPEG4' : 'MPEG4 Film', + 'kindVideoAVI' : 'AVI Film', + 'kindVideoMOV' : 'QuickTime Film', + 'kindVideoWM' : 'Windows Media Film', + 'kindVideoFlash' : 'Flash Film', + 'kindVideoMKV' : 'Matroska Film', + 'kindVideoOGG' : 'Ogg Film' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.el.js b/lib/redactor/elfinder/js/i18n/elfinder.el.js new file mode 100644 index 0000000..0ade5a4 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.el.js @@ -0,0 +1,381 @@ +/** + * Greek translation + * @author yawd , Romanos + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.el = { + translator : 'yawd <ingo@yawd.eu>', + language : 'Ελληνικά', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', + fancyDateFormat : '$1 H:i', + messages : { + + /********************************** errors **********************************/ + 'error' : 'Πρόβλημα', + 'errUnknown' : 'Άγνωστο πρόβλημα.', + 'errUnknownCmd' : 'Άγνωστη εντολή.', + 'errJqui' : 'Μη έγκυρη ρύθμιση του jQuery UI. Τα components "selectable", "draggable" και "droppable" πρέπει να περιληφούν.', + 'errNode' : 'το elFinder χρειάζεται να έχει δημιουργηθεί το DOM Element.', + 'errURL' : 'Μη έγκυρες ρυθμίσεις για το elFinder! η επιλογή URL δεν έχει οριστεί.', + 'errAccess' : 'Απαγορεύεται η πρόσβαση.', + 'errConnect' : 'Δεν ήταν δυνατή η σύνδεση με το backend.', + 'errAbort' : 'Η σύνδεση εγκαταλείφθηκε.', + 'errTimeout' : 'Η σύνδεση έληξε.', + 'errNotFound' : 'Δε βρέθηκε το backend.', + 'errResponse' : 'Μή έγκυρη απάντηση από το backend.', + 'errConf' : 'Μη έγκυρες ρυθμίσεις για το backend.', + 'errJSON' : 'Το PHP JSON module δεν είναι εγκατεστημένο.', + 'errNoVolumes' : 'Δεν βρέθηκαν αναγνώσιμα volumes.', + 'errCmdParams' : 'Μη έγκυρες παράμετροι για την εντολή "$1".', + 'errDataNotJSON' : 'Τα δεδομένα δεν είναι JSON.', + 'errDataEmpty' : 'Τα δεδομένα είναι άδεια.', + 'errCmdReq' : 'Το Backend request χρειάζεται όνομα εντολής.', + 'errOpen' : 'Δεν ήταν δυνατό να ανοίξει το "$1".', + 'errNotFolder' : 'Το αντικείμενο δεν είναι φάκελος.', + 'errNotFile' : 'Το αντικείμενο δεν είναι αρχείο.', + 'errRead' : 'Δεν ήταν δυνατόν να διαβαστεί το "$1".', + 'errWrite' : 'Δεν ήταν δυνατή η εγγραφή στο "$1".', + 'errPerm' : 'Απαγορεύεται η πρόσβαση.', + 'errLocked' : '"$1" είναι κλειδωμένο και δεν μπορεί να μετονομαστεί, μετακινηθεί ή διαγραφεί.', + 'errExists' : 'Το αρχείο με όνομα "$1" υπάρχει ήδη.', + 'errInvName' : 'Μη έγκυρο όνομα αρχείου.', + 'errFolderNotFound' : 'Ο φάκελος δε βρέθηκε.', + 'errFileNotFound' : 'Το αρχείο δε βρέθηκε.', + 'errTrgFolderNotFound' : 'Ο φάκελος "$1" δε βρέθηκε.', + 'errPopup' : 'Το πρόγραμμα πλήγησης εμπόδισε το άνοιγμα αναδυόμενου παραθύρου. Για ανοίξετε το αρχείο ενεργοποιήστε το στις επιλογές του περιηγητή.', + 'errMkdir' : 'Η δυμιουργία του φακέλου "$1" δεν ήταν δυνατή.', + 'errMkfile' : 'Η δημιουργία του αρχείου "$1" δεν ήταν δυνατή.', + 'errRename' : 'Η μετονομασία του αρχείου "$1" δεν ήταν δυνατή.', + 'errCopyFrom' : 'Δεν επιτρέπεται η αντιγραφή αρχείων από το volume "$1".', + 'errCopyTo' : 'Δεν επιτρέπεται η αντιγραφή αρχείων στο volume "$1".', + 'errUpload' : 'Πρόβλημα κατά το upload.', + 'errUploadFile' : 'Το αρχείο "$1" δεν μπόρεσε να γίνει upload.', + 'errUploadNoFiles' : 'Δεν βρέθηκαν αρχεία για upload.', + 'errUploadTotalSize' : 'Τα δεδομένα υπερβαίνουν το επιτρεπόμενο μέγιστο μέγεθος δεδομένων.', + 'errUploadFileSize' : 'Το αρχείο υπερβαίνει το επιτρεπόμενο μέγιστο μέγεθος.', + 'errUploadMime' : 'Ο τύπος αρχείου δεν επιτρέπεται.', + 'errUploadTransfer' : 'Πρόβλημα μεταφοράς για το "$1".', + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : 'Το "$1" δεν ήταν δυνατόν να αποθηκευτεί.', + 'errCopy' : 'Δεν ήταν δυνατή η αντιγραφή του "$1".', + 'errMove' : 'Δεν ήταν δυνατή η μετακίνηση του "$1".', + 'errCopyInItself' : 'Δεν είναι δυνατή η αντιγραφή του "$1" στον εαυτό του.', + 'errRm' : 'Δεν ήταν δυνατή η αφαίρεση του "$1".', + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'Δεν ήταν δυνατή η ανάγνωση των αρχείων από "$1".', + 'errArchive' : 'Δεν ήταν δυνατή η δημιουργία του αρχείου.', + 'errArcType' : 'Ο τύπος αρχείου δεν υποστηρίζεται.', + 'errNoArchive' : 'Το αρχείο δεν είναι έγκυρο ή δεν υποστηρίζεται ο τύπος του.', + 'errCmdNoSupport' : 'Το backend δεν υποστηρίζει αυτή την εντολή.', + 'errReplByChild' : 'Ο φάκελος “$1” δεν μπορεί να αντικατασταθεί από οποιοδήποτε αρχείο περιέχεται σε αυτόν.', + 'errArcSymlinks' : 'Για λόγους ασφαλείας δεν είναι δυνατόν να διαβαστούν αρχεία που περιέχουν symlinks orη αρχεία με μη επιτρεπτά ονόματα.', // edited 24.06.2012 + 'errArcMaxSize' : 'Το μέγεθος του αρχείου υπερβαίνει το μέγιστο επιτρεπτό όριο.', + 'errResize' : 'Δεν ήταν δυνατή η αλλαγή μεγέθους του "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', + 'errResizeRotate' : 'Unable to rotate image.', + 'errResizeSize' : 'Invalid image size.', + 'errResizeNoChange' : 'Image size not changed.', + 'errUsupportType' : 'Ο τύπος αρχείου δεν υποστηρίζεται.', + 'errNotUTF8Content' : 'Το αρχείο "$1" δεν είναι UTF-8 και δεν μπορεί να επεξεργασθεί.', // added 9.11.2011 + 'errNetMount' : 'Δεν ήταν δυνατή η φόρτωση του "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Μη υποστηριζόμενο πρωτόκολο.', // added 17.04.2012 + 'errNetMountFailed' : 'Η φόρτωση απέτυχε.', // added 17.04.2012 + 'errNetMountHostReq' : 'Απαιτείται host εξυπηρετητής.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Δημιουργία archive αρχείου', + 'cmdback' : 'Πίσω', + 'cmdcopy' : 'Αντιγραφή', + 'cmdcut' : 'Αφαίρεση', + 'cmddownload' : 'Μεταφόρτωση', + 'cmdduplicate' : 'Αντίγραφο', + 'cmdedit' : 'Επεξεργασία αρχείου', + 'cmdextract' : 'Εξαγωγή αρχείων από archive', + 'cmdforward' : 'Προώθηση', + 'cmdgetfile' : 'Επιλέξτε αρχεία', + 'cmdhelp' : 'Σχετικά με αυτό το λογισμικό', + 'cmdhome' : 'Home', + 'cmdinfo' : 'Πληροφορίες', + 'cmdmkdir' : 'Νέος φάκελος', + 'cmdmkfile' : 'Νέος αρχείο', + 'cmdopen' : 'Άνοιγμα', + 'cmdpaste' : 'Επικόλληση', + 'cmdquicklook' : 'Προεπισκόπηση', + 'cmdreload' : 'Ανανέωση', + 'cmdrename' : 'Μετονομασία', + 'cmdrm' : 'Διαγραφή', + 'cmdsearch' : 'Έυρεση αρχείων', + 'cmdup' : 'Μετάβαση στο γονικό φάκελο', + 'cmdupload' : 'Ανέβασμα αρχείων', + 'cmdview' : 'Προβολή', + 'cmdresize' : 'Αλλαγή μεγέθους εικόνας', + 'cmdsort' : 'Ταξινόμηση', + 'cmdnetmount' : 'Mount network volume', + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Κλείσιμο', + 'btnSave' : 'Αποθήκευση', + 'btnRm' : 'Αφαίρεση', + 'btnApply' : 'Εφαρμογή', + 'btnCancel' : 'Ακύρωση', + 'btnNo' : 'Όχι', + 'btnYes' : 'Ναι', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', + + /******************************** notifications ********************************/ + 'ntfopen' : 'Άνοιγμα φακέλου', + 'ntffile' : 'Άνοιγμα αρχείου', + 'ntfreload' : 'Ανανέωση περιεχομένων φακέλου', + 'ntfmkdir' : 'Δημιουργία φακέλου', + 'ntfmkfile' : 'Δημιουργία αρχείων', + 'ntfrm' : 'Διαγραφή αρχείων', + 'ntfcopy' : 'Αντιγραφή αρχείων', + 'ntfmove' : 'Μετακίνηση αρχείων', + 'ntfprepare' : 'Προετοιμασία αντιγραφής αρχείων', + 'ntfrename' : 'Μετονομασία αρχείων', + 'ntfupload' : 'Ανέβασμα αρχείων', + 'ntfdownload' : 'Μεταφόρτωση αρχείων', + 'ntfsave' : 'Αποθήκευση αρχείων', + 'ntfarchive' : 'Δημιουργία αρχείου', + 'ntfextract' : 'Εξαγωγή αρχείων από το archive', + 'ntfsearch' : 'Αναζήτηση αρχείων', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Σύστημα απασχολημένο>_<', + 'ntfloadimg' : 'Φόρτωση εικόνας', + 'ntfnetmount' : 'Φόρτωση δικτυακού δίσκου', // added 18.04.2012 + 'ntfdim' : 'Acquiring image dimension', + + /************************************ dates **********************************/ + 'dateUnknown' : 'άγνωστο', + 'Today' : 'Σήμερα', + 'Yesterday' : 'Χθές', + 'msJan' : 'Ιαν', + 'msFeb' : 'Φεβ', + 'msMar' : 'Μαρ', + 'msApr' : 'Απρ', + 'msMay' : 'Μαϊ', + 'msJun' : 'Ιουν', + 'msJul' : 'Ιουλ', + 'msAug' : 'Αυγ', + 'msSep' : 'Σεπ', + 'msOct' : 'Οκτ', + 'msNov' : 'Νοεμ', + 'msDec' : 'Δεκ', + 'January' : 'Ιανουάριος', + 'February' : 'Φεβρουάριος', + 'March' : 'Μάρτιος', + 'April' : 'Απρίλιος', + 'May' : 'Μάϊος', + 'June' : 'Ιούνιος', + 'July' : 'Ιούλιος', + 'August' : 'Αύγουστος', + 'September' : 'Σεπτέμβριος', + 'October' : 'Οκτώβριος', + 'November' : 'Νοέμβριος', + 'December' : 'Δεκέμβριος', + 'Sunday' : 'Κυριακή', + 'Monday' : 'Δευτέρα', + 'Tuesday' : 'Τρίτη', + 'Wednesday' : 'Τετάρτη', + 'Thursday' : 'Πέμπτη', + 'Friday' : 'Παρασκευή', + 'Saturday' : 'Σάββατο', + 'Sun' : 'Κυρ', + 'Mon' : 'Δευ', + 'Tue' : 'Τρ', + 'Wed' : 'Τετ', + 'Thu' : 'Πεμ', + 'Fri' : 'Παρ', + 'Sat' : 'Σαβ', + + /******************************** sort variants ********************************/ + 'sortname' : 'κατά όνομα', + 'sortkind' : 'κατά είδος', + 'sortsize' : 'κατά μέγεθος', + 'sortdate' : 'κατά ημερομηνία', + 'sortFoldersFirst' : 'Πρώτα οι φάκελοι', // added 22.06.2012 + + /********************************** messages **********************************/ + 'confirmReq' : 'Απαιτείται επιβεβαίωση', + 'confirmRm' : 'Είστε σίγουροι πως θέλετε να διαγράψετε τα αρχεία?
                      Οι αλλαγές θα είναι μόνιμες!', + 'confirmRepl' : 'Αντικατάσταση του παλιού αρχείου με το νέο?', + 'apllyAll' : 'Εφαρμογή σε όλα', + 'name' : 'Όνομα', + 'size' : 'Μέγεθος', + 'perms' : 'Δικαιώματα', + 'modify' : 'Τροποποιήθηκε', + 'kind' : 'Είδος', + 'read' : 'ανάγνωση', + 'write' : 'εγγραφή', + 'noaccess' : 'δεν υπάρχει πρόσβαση', + 'and' : 'και', + 'unknown' : 'άγνωστο', + 'selectall' : 'Επιλογή όλων', + 'selectfiles' : 'Επιλογή αρχείων', + 'selectffile' : 'Επιλογή πρώτου αρχείου', + 'selectlfile' : 'Επιλογή τελευταίου αρχείου', + 'viewlist' : 'Προβολή λίστας', + 'viewicons' : 'Προβολή εικονιδίων', + 'places' : 'Τοποθεσίες', + 'calc' : 'Υπολογισμός', + 'path' : 'Διαδρομή', + 'aliasfor' : 'Ψευδώνυμο για', + 'locked' : 'Κλειδωμένο', + 'dim' : 'Διαστάσεις', + 'files' : 'Αρχεία', + 'folders' : 'Φάκελοι', + 'items' : 'Αντικείμενα', + 'yes' : 'ναι', + 'no' : 'όχι', + 'link' : 'Σύνδεσμος', + 'searcresult' : 'Αποτελέσματα αναζήτησης', + 'selected' : 'επιλεγμένα αντικείμενα', + 'about' : 'Σχετικά', + 'shortcuts' : 'Συντομεύσεις', + 'help' : 'Βοήθεια', + 'webfm' : 'εργαλείο διαχείρισης αρχείων από το web', + 'ver' : 'Έκδοση', + 'protocolver' : 'έκδοση πρωτοκόλλου', + 'homepage' : 'Σελίδα του project', + 'docs' : 'Τεκμηρίωση (documentation)', + 'github' : 'Κάντε μας fork στο Github', + 'twitter' : 'Ακολουθήστε μας στο twitter', + 'facebook' : 'Βρείτε μας στο facebook', + 'team' : 'Ομάδα', + 'chiefdev' : 'κύριος προγραμματιστής', + 'developer' : 'προγραμματιστής', + 'contributor' : 'συνεισφορά', + 'maintainer' : 'συντηρητής', + 'translator' : 'μεταφραστής', + 'icons' : 'Εικονίδια', + 'dontforget' : 'και μην ξεχάσεις την πετσέτα σου!', + 'shortcutsof' : 'Οι συντομεύσεις είναι απενεργοποιημένες', + 'dropFiles' : 'Κάντε drop τα αρχεία εδώ', + 'or' : 'ή', + 'selectForUpload' : 'Επιλογή αρχείων για ανέβασμα', + 'moveFiles' : 'Μετακίνηση αρχείων', + 'copyFiles' : 'Αντιγραφή αρχείων', + 'rmFromPlaces' : 'Αντιγραφή από τοποθεσίες', + 'aspectRatio' : 'Αναλογία διαστάσεων', + 'scale' : 'Κλίμακα', + 'width' : 'Πλάτος', + 'height' : 'Ύψος', + 'resize' : 'Αλλαγή μεγέθους', + 'crop' : 'Crop', + 'rotate' : 'Περιστροφή', + 'rotate-cw' : 'Περιστροφή κατά 90 βαθμούς CW', + 'rotate-ccw' : 'Περιστροφή κατά 90 βαθμούς CCW', + 'degree' : 'Βαθμός', + 'netMountDialogTitle' : 'Φορτώστε δικτυακό δίσκο', // added 18.04.2012 + 'protocol' : 'Πρωτόκολλο', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Χρήστης', // added 18.04.2012 + 'pass' : 'Κωδικός', // added 18.04.2012 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Άγνωστο', + 'kindFolder' : 'Φάκελος', + 'kindAlias' : 'Ψευδώνυμο (alias)', + 'kindAliasBroken' : 'Μη έγκυρο ψευδώνυμο', + // applications + 'kindApp' : 'Εφαρμογή', + 'kindPostscript' : 'Έγγραφο Postscript', + 'kindMsOffice' : 'Έγγραφο Microsoft Office', + 'kindMsWord' : 'Έγγραφο Microsoft Word', + 'kindMsExcel' : 'Έγγραφο Microsoft Excel', + 'kindMsPP' : 'Παρουσίαση Microsoft Powerpoint', + 'kindOO' : 'Έγγραφο Open Office', + 'kindAppFlash' : 'Εφαρμογή Flash', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Αρχείο Bittorrent', + 'kind7z' : 'Αρχείο 7z', + 'kindTAR' : 'Αρχείο TAR', + 'kindGZIP' : 'Αρχείο GZIP', + 'kindBZIP' : 'Αρχείο BZIP', + 'kindXZ' : 'Αρχείο XZ', + 'kindZIP' : 'Αρχείο ZIP', + 'kindRAR' : 'Αρχείο RAR', + 'kindJAR' : 'Αρχείο Java JAR', + 'kindTTF' : 'Γραμματοσειρά True Type', + 'kindOTF' : 'Γραμματοσειρά Open Type', + 'kindRPM' : 'Πακέτο RPM', + // fonts + 'kindFont' : 'Γραμματοσειρά', + 'kindSFNT' : 'Γραμματοσειρά SFNT', + 'kindEOT' : 'Γραμματοσειρά Embedded Open Type', + 'kindWOFF' : 'Γραμματοσειρά Web Open Font Format', + 'kindWOFF2' : 'Γραμματοσειρά Web Open Font Format 2', + // texts + 'kindText' : 'Έγγραφο κειμένου', + 'kindTextPlain' : 'Απλό κείμενο', + 'kindPHP' : 'Κώδικας PHP', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'Έγγραφο HTML', + 'kindJS' : 'Κώδικας Javascript', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'Κώδικας C', + 'kindCHeader' : 'Κώδικας κεφαλίδας C', + 'kindCPP' : 'Κώδικας C++', + 'kindCPPHeader' : 'Κώδικας κεφαλίδας C++', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Κώδικας Python', + 'kindJava' : 'Κώδικας Java', + 'kindRuby' : 'Κώδικας Ruby', + 'kindPerl' : 'Perl script', + 'kindSQL' : 'Κώδικας SQL', + 'kindXML' : 'Έγγραφο XML', + 'kindAWK' : 'Κώδικας AWK', + 'kindCSV' : 'Τιμές χωρισμένες με κόμμα', + 'kindDOCBOOK' : 'Έγγραφο Docbook XML', + // images + 'kindImage' : 'Εικόνα', + 'kindBMP' : 'Εικόνα BMP', + 'kindJPEG' : 'Εικόνα JPEG', + 'kindGIF' : 'Εικόνα GIF', + 'kindPNG' : 'Εικόνα PNG', + 'kindTIFF' : 'Εικόνα TIFF', + 'kindTGA' : 'Εικόνα TGA', + 'kindPSD' : 'Εικόνα Adobe Photoshop', + 'kindXBITMAP' : 'Εικόνα X bitmap', + 'kindPXM' : 'Εικόνα Pixelmator', + // media + 'kindAudio' : 'Αρχεία ήχου', + 'kindAudioMPEG' : 'Ήχος MPEG', + 'kindAudioMPEG4' : 'Εικόνα MPEG-4', + 'kindAudioMIDI' : 'Εικόνα MIDI', + 'kindAudioOGG' : 'Εικόνα Ogg Vorbis', + 'kindAudioWAV' : 'Εικόνα WAV', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Αρχεία media', + 'kindVideoDV' : 'Ταινία DV', + 'kindVideoMPEG' : 'Ταινία MPEG', + 'kindVideoMPEG4' : 'Ταινία MPEG-4', + 'kindVideoAVI' : 'Ταινία AVI', + 'kindVideoMOV' : 'Ταινία Quick Time', + 'kindVideoWM' : 'Ταινία Windows Media', + 'kindVideoFlash' : 'Ταινία flash', + 'kindVideoMKV' : 'Ταινία matroska', + 'kindVideoOGG' : 'Ταινία ogg' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.es.js b/lib/redactor/elfinder/js/i18n/elfinder.es.js new file mode 100644 index 0000000..c7c7988 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.es.js @@ -0,0 +1,553 @@ +/** + * Español internacional translation + * @author Julián Torres + * @author Luis Faura + * @author Adrià Vilanova + * @author Wilman Marín Duran + * @version 2018-04-10 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.es = { + translator : 'Julián Torres <julian.torres@pabernosmatao.com>, Luis Faura <luis@luisfaura.es>, Adrià Vilanova <me@avm99963.tk>, Wilman Marín Duran <fuclo05@hotmail.com>', + language : 'Español internacional', + direction : 'ltr', + dateFormat : 'M d, Y h:i A', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'ymd-His', // to apply if upload file is noname: 120513172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Error', + 'errUnknown' : 'Error desconocido.', + 'errUnknownCmd' : 'Comando desconocido.', + 'errJqui' : 'Configuración no válida de jQuery UI. Deben estar incluidos los componentes selectable, draggable y droppable.', + 'errNode' : 'elFinder necesita crear elementos DOM.', + 'errURL' : '¡Configuración no válida de elFinder! La opción URL no está configurada.', + 'errAccess' : 'Acceso denegado.', + 'errConnect' : 'No se ha podido conectar con el backend.', + 'errAbort' : 'Conexión cancelada.', + 'errTimeout' : 'Conexión cancelada por timeout.', + 'errNotFound' : 'Backend no encontrado.', + 'errResponse' : 'Respuesta no válida del backend.', + 'errConf' : 'Configuración no válida del backend .', + 'errJSON' : 'El módulo PHP JSON no está instalado.', + 'errNoVolumes' : 'No hay disponibles volúmenes legibles.', + 'errCmdParams' : 'Parámetros no válidos para el comando "$1".', + 'errDataNotJSON' : 'los datos no están en formato JSON.', + 'errDataEmpty' : 'No hay datos.', + 'errCmdReq' : 'La petición del backend necesita un nombre de comando.', + 'errOpen' : 'No se puede abrir "$1".', + 'errNotFolder' : 'El objeto no es una carpeta.', + 'errNotFile' : 'El objeto no es un archivo.', + 'errRead' : 'No se puede leer "$1".', + 'errWrite' : 'No se puede escribir en "$1".', + 'errPerm' : 'Permiso denegado.', + 'errLocked' : '"$1" está bloqueado y no puede ser renombrado, movido o borrado.', + 'errExists' : 'Ya existe un archivo llamado "$1".', + 'errInvName' : 'Nombre de archivo no válido.', + 'errInvDirname' : 'Nombre de carpeta inválido.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Carpeta no encontrada.', + 'errFileNotFound' : 'Archivo no encontrado.', + 'errTrgFolderNotFound' : 'Carpeta de destino "$1" no encontrada.', + 'errPopup' : 'El navegador impide abrir nuevas ventanas. Puede activarlo en las opciones del navegador.', + 'errMkdir' : 'No se puede crear la carpeta "$1".', + 'errMkfile' : 'No se puede crear el archivo "$1".', + 'errRename' : 'No se puede renombrar "$1".', + 'errCopyFrom' : 'No se permite copiar archivos desde el volumen "$1".', + 'errCopyTo' : 'No se permite copiar archivos al volumen "$1".', + 'errMkOutLink' : 'No se ha podido crear el enlace fuera del volumen raíz.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Error en el envío.', // old name - errUploadCommon + 'errUploadFile' : 'No se ha podido cargar "$1".', // old name - errUpload + 'errUploadNoFiles' : 'No hay archivos para subir.', + 'errUploadTotalSize' : 'El tamaño de los datos excede el máximo permitido.', // old name - errMaxSize + 'errUploadFileSize' : 'El tamaño del archivo excede el máximo permitido.', // old name - errFileMaxSize + 'errUploadMime' : 'Tipo de archivo no permitido.', + 'errUploadTransfer' : 'Error al transferir "$1".', + 'errUploadTemp' : 'No se ha podido crear el archivo temporal para la subida.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'El objeto "$1" ya existe y no puede ser reemplazado por otro con otro tipo.', // new + 'errReplace' : 'No se puede reemplazar "$1".', + 'errSave' : 'No se puede guardar "$1".', + 'errCopy' : 'No se puede copiar "$1".', + 'errMove' : 'No se puede mover "$1".', + 'errCopyInItself' : 'No se puede copiar "$1" en si mismo.', + 'errRm' : 'No se puede borrar "$1".', + 'errTrash' : 'No se puede enviar a la papelera.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'No se puede(n) borrar los archivo(s).', + 'errExtract' : 'No se puede extraer archivos desde "$1".', + 'errArchive' : 'No se puede crear el archivo.', + 'errArcType' : 'Tipo de archivo no soportado.', + 'errNoArchive' : 'El archivo no es de tipo archivo o es de un tipo no soportado.', + 'errCmdNoSupport' : 'El backend no soporta este comando.', + 'errReplByChild' : 'La carpeta “$1” no puede ser reemplazada por un elemento contenido en ella.', + 'errArcSymlinks' : 'Por razones de seguridad no se pueden descomprimir archivos que contengan enlaces simbólicos.', // edited 24.06.2012 + 'errArcMaxSize' : 'El tamaño del archivo excede el máximo permitido.', + 'errResize' : 'Error al redimensionar "$1".', + 'errResizeDegree' : 'Grado de rotación inválido.', // added 7.3.2013 + 'errResizeRotate' : 'Error al rotar la imagen.', // added 7.3.2013 + 'errResizeSize' : 'Tamaño de imagen inválido.', // added 7.3.2013 + 'errResizeNoChange' : 'No se puede cambiar el tamaño de la imagen.', // added 7.3.2013 + 'errUsupportType' : 'Tipo de archivo no soportado.', + 'errNotUTF8Content' : 'El archivo "$1" no está en formato UTF-8 y no puede ser editado.', // added 9.11.2011 + 'errNetMount' : 'Fallo al montar "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protocolo no soportado.', // added 17.04.2012 + 'errNetMountFailed' : 'Fallo al montar.', // added 17.04.2012 + 'errNetMountHostReq' : 'Dominio requerido.', // added 18.04.2012 + 'errSessionExpires' : 'La sesión ha expirado por inactividad', + 'errCreatingTempDir' : 'No se ha podido crear al directorio temporal: "$1"', + 'errFtpDownloadFile' : 'No se ha podido descargar el archivo desde FTP: "$1"', + 'errFtpUploadFile' : 'No se ha podido cargar el archivo a FTP: "$1"', + 'errFtpMkdir' : 'No se ha podido crear el directorio remoto en FTP: "$1"', + 'errArchiveExec' : 'Se ha producido un error durante el archivo: "$1"', + 'errExtractExec' : 'Se ha producido un error durante la extracción de archivos: "$1"', + 'errNetUnMount' : 'Imposible montar', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'No es convertible a UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Prueba con un navegador moderno, si quieres subir la carpeta completa.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Se agotó el tiempo de espera buscando "$1". Los resultados de búsqueda son parciales.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Se requiere autorizar de nuevo.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Número máximo de elementos seleccionables es $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'No se puede restaurar desde la papelera. No se puede identificar el destino de restauración.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor no encontrado para este tipo de archivo.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Error ocurrido en el lado del servidor.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'No es posible vaciar la carpeta "$1".', // from v2.1.25 added 22.6.2017 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Crear archivo', + 'cmdback' : 'Atrás', + 'cmdcopy' : 'Copiar', + 'cmdcut' : 'Cortar', + 'cmddownload' : 'Descargar', + 'cmdduplicate' : 'Duplicar', + 'cmdedit' : 'Editar archivo', + 'cmdextract' : 'Extraer elementos del archivo', + 'cmdforward' : 'Adelante', + 'cmdgetfile' : 'Seleccionar archivos', + 'cmdhelp' : 'Acerca de este software', + 'cmdhome' : 'Inicio', + 'cmdinfo' : 'Obtener información', + 'cmdmkdir' : 'Nueva carpeta', + 'cmdmkdirin' : 'En una nueva carpeta', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nueva archivo', + 'cmdopen' : 'Abrir', + 'cmdpaste' : 'Pegar', + 'cmdquicklook' : 'Previsualizar', + 'cmdreload' : 'Recargar', + 'cmdrename' : 'Cambiar nombre', + 'cmdrm' : 'Eliminar', + 'cmdtrash' : 'Enviar a la papelera', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Restaurar', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Buscar archivos', + 'cmdup' : 'Ir a la carpeta raíz', + 'cmdupload' : 'Subir archivos', + 'cmdview' : 'Ver', + 'cmdresize' : 'Redimensionar y rotar', + 'cmdsort' : 'Ordenar', + 'cmdnetmount' : 'Montar volumen en red', // added 18.04.2012 + 'cmdnetunmount': 'Desmontar', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'A Lugares', // added 28.12.2014 + 'cmdchmod' : 'Cambiar modo', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Abrir una carpeta', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Restablecer ancho de columna', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Pantalla completa', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Mover', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Vaciar la carpeta', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Deshacer', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Rehacer', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferencias', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Seleccionar todo', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Seleccionar ninguno', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Invertir selección', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Abrir en nueva ventana', // from v2.1.38 added 3.4.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Cerrar', + 'btnSave' : 'Guardar', + 'btnRm' : 'Eliminar', + 'btnApply' : 'Aplicar', + 'btnCancel' : 'Cancelar', + 'btnNo' : 'No', + 'btnYes' : 'Sí', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Montar', // added 18.04.2012 + 'btnApprove': 'Ir a $1 y aprobar', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Desmontar', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convertir', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Aquí', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volumen', // from v2.1 added 22.5.2015 + 'btnAll' : 'Todos', // from v2.1 added 22.5.2015 + 'btnMime' : 'Tipo MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nombre de archivo', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Guardar y cerrar', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Copia de seguridad', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Renombrar', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Renombrar(Todo)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Ant ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Sig ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Guardar como', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Abrir carpeta', + 'ntffile' : 'Abrir archivo', + 'ntfreload' : 'Actualizar contenido de la carpeta', + 'ntfmkdir' : 'Creando directorio', + 'ntfmkfile' : 'Creando archivos', + 'ntfrm' : 'Eliminando archivos', + 'ntfcopy' : 'Copiar archivos', + 'ntfmove' : 'Mover archivos', + 'ntfprepare' : 'Preparar copia de archivos', + 'ntfrename' : 'Renombrar archivos', + 'ntfupload' : 'Subiendo archivos', + 'ntfdownload' : 'Descargando archivos', + 'ntfsave' : 'Guardar archivos', + 'ntfarchive' : 'Creando archivo', + 'ntfextract' : 'Extrayendo elementos del archivo', + 'ntfsearch' : 'Buscando archivos', + 'ntfresize' : 'Redimensionando imágenes', + 'ntfsmth' : 'Haciendo algo', + 'ntfloadimg' : 'Cargando imagen', + 'ntfnetmount' : 'Montando volumen en red', // added 18.04.2012 + 'ntfnetunmount': 'Desmontando volumen en red', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Adquiriendo tamaño de imagen', // added 20.05.2013 + 'ntfreaddir' : 'Leyendo información de la carpeta', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Obteniendo URL del enlace', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Cambiando el modo de archivo', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Verificando nombre del archivo subido', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Creando un archivo para descargar', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Obteniendo información de la ruta', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Procesando el archivo cargado', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Enviando a la papelera', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Restaurando desde la papelera', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Comprobando carpeta de destino', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Deshaciendo operación previa', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Rehaciendo previo deshacer', // from v2.1.27 added 31.07.2017 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Papelera', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'desconocida', + 'Today' : 'Hoy', + 'Yesterday' : 'Ayer', + 'msJan' : 'Ene', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Abr', + 'msMay' : 'May', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Ago', + 'msSep' : 'Sep', + 'msOct' : 'Oct', + 'msNov' : 'Nov', + 'msDec' : 'Dic', + 'January' : 'Enero', + 'February' : 'Febrero', + 'March' : 'Marzo', + 'April' : 'Abril', + 'May' : 'Mayo', + 'June' : 'Junio', + 'July' : 'Julio', + 'August' : 'Agosto', + 'September' : 'Septiembre', + 'October' : 'Octubre', + 'November' : 'Noviembre', + 'December' : 'Diciembre', + 'Sunday' : 'Domingo', + 'Monday' : 'Lunes', + 'Tuesday' : 'Martes', + 'Wednesday' : 'Miércoles', + 'Thursday' : 'Jueves', + 'Friday' : 'Viernes', + 'Saturday' : 'Sábado', + 'Sun' : 'Dom', + 'Mon' : 'Lun', + 'Tue' : 'Mar', + 'Wed' : 'Mie', + 'Thu' : 'Jue', + 'Fri' : 'Vie', + 'Sat' : 'Sab', + + /******************************** sort variants ********************************/ + 'sortname' : 'por nombre', + 'sortkind' : 'por tipo', + 'sortsize' : 'por tamaño', + 'sortdate' : 'por fecha', + 'sortFoldersFirst' : 'Las carpetas primero', + 'sortperm' : 'por permiso', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'por modo', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'por propietario', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'por grupo', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'También árbol de directorios', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NuevoArchivo.txt', // added 10.11.2015 + 'untitled folder' : 'NuevaCarpeta', // added 10.11.2015 + 'Archive' : 'NuevoArchivo', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'Se necesita confirmación', + 'confirmRm' : '¿Está seguro de querer eliminar archivos?
                      ¡Esto no se puede deshacer!', + 'confirmRepl' : '¿Reemplazar el antiguo archivo con el nuevo?', + 'confirmRest' : '¿Reemplazar elemento existente con el elemento en la papelera?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'No está en UTF-8
                      Convertir a UTF-8?
                      Los contenidos se guardarán en UTF-8 tras la conversión.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Codificación de caracteres de este archivo no pudo ser detectada. Es necesario convertir temporalmente a UTF-8 para editarlo.
                      Por favor, seleccione la codificación de caracteres de este archivo.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Ha sido modificado.
                      Perderás los cambios si no los guardas.', // from v2.1 added 15.7.2015 + 'confirmTrash' : '¿Estás seguro que quieres mover los elementos a la papelera?', //from v2.1.24 added 29.4.2017 + 'apllyAll' : 'Aplicar a todo', + 'name' : 'Nombre', + 'size' : 'Tamaño', + 'perms' : 'Permisos', + 'modify' : 'Modificado', + 'kind' : 'Tipo', + 'read' : 'lectura', + 'write' : 'escritura', + 'noaccess' : 'sin acceso', + 'and' : 'y', + 'unknown' : 'desconocido', + 'selectall' : 'Seleccionar todos los archivos', + 'selectfiles' : 'Seleccionar archivo(s)', + 'selectffile' : 'Seleccionar primer archivo', + 'selectlfile' : 'Seleccionar último archivo', + 'viewlist' : 'ver como lista', + 'viewicons' : 'Ver como iconos', + 'places' : 'Lugares', + 'calc' : 'Calcular', + 'path' : 'Ruta', + 'aliasfor' : 'Alias para', + 'locked' : 'Bloqueado', + 'dim' : 'Dimensiones', + 'files' : 'Archivos', + 'folders' : 'Carpetas', + 'items' : 'Elementos', + 'yes' : 'sí', + 'no' : 'no', + 'link' : 'Enlace', + 'searcresult' : 'Resultados de la búsqueda', + 'selected' : 'elementos seleccionados', + 'about' : 'Acerca', + 'shortcuts' : 'Accesos directos', + 'help' : 'Ayuda', + 'webfm' : 'Administrador de archivos web', + 'ver' : 'Versión', + 'protocolver' : 'versión del protocolo', + 'homepage' : 'Inicio', + 'docs' : 'Documentación', + 'github' : 'Bifúrcanos en Github', + 'twitter' : 'Síguenos en Twitter', + 'facebook' : 'Únete a nosotros en Facebook', + 'team' : 'Equipo', + 'chiefdev' : 'desarrollador jefe', + 'developer' : 'desarrollador', + 'contributor' : 'contribuyente', + 'maintainer' : 'mantenedor', + 'translator' : 'traductor', + 'icons' : 'Iconos', + 'dontforget' : 'y no olvide traer su toalla', + 'shortcutsof' : 'Accesos directos desactivados', + 'dropFiles' : 'Arrastre archivos aquí', + 'or' : 'o', + 'selectForUpload' : 'Seleccione archivos para subir', + 'moveFiles' : 'Mover archivos', + 'copyFiles' : 'Copiar archivos', + 'restoreFiles' : 'Restaurar elementos', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Eliminar en sus ubicaciones', + 'aspectRatio' : 'Relación de aspecto', + 'scale' : 'Escala', + 'width' : 'Ancho', + 'height' : 'Alto', + 'resize' : 'Redimensionar', + 'crop' : 'Recortar', + 'rotate' : 'Rotar', + 'rotate-cw' : 'Rotar 90 grados en sentido horario', + 'rotate-ccw' : 'Rotar 90 grados en sentido anti-horario', + 'degree' : '°', + 'netMountDialogTitle' : 'Montar volumen en red', // added 18.04.2012 + 'protocol' : 'Protocolo', // added 18.04.2012 + 'host' : 'Dominio', // added 18.04.2012 + 'port' : 'Puerto', // added 18.04.2012 + 'user' : 'Usuario', // added 18.04.2012 + 'pass' : 'Contraseña', // added 18.04.2012 + 'confirmUnmount' : '¿Desmontar $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Arrastra o pega archivos del navegador', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Arrastra o pega enlaces URL aquí', // from v2.1 added 07.04.2014 + 'encoding' : 'Codificando', // from v2.1 added 19.12.2014 + 'locale' : 'Local', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Destino: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Buscar entrada por tipo MIME', // from v2.1 added 22.5.2015 + 'owner' : 'Propietario', // from v2.1 added 20.6.2015 + 'group' : 'Grupo', // from v2.1 added 20.6.2015 + 'other' : 'Otro', // from v2.1 added 20.6.2015 + 'execute' : 'Ejecutar', // from v2.1 added 20.6.2015 + 'perm' : 'Permiso', // from v2.1 added 20.6.2015 + 'mode' : 'Modo', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'La carpeta está vacía', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'La carpeta está vacía\\A Arrastrar para añadir elementos', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'La carpeta está vacía\\A Presiona durante un rato para añadir elementos', // from v2.1.6 added 30.12.2015 + 'quality' : 'Calidad', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Sincronización automática', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Mover arriba', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Obtener enlace', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Elementos seleccionados ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID carpeta', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Permitir acceso sin conexión', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Para volver a autenticarse', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Cargando ahora...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Abrir múltiples archivos', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Estás tratando de abrir los $1 archivos. ¿Estás seguro que quieres abrir en el navegador?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'No se encontraron resultados en el objetivo de búsqueda.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Está editando un archivo.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Has seleccionado $1 elementos.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Posees $1 elementos en el portapapeles.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'La búsqueda incremental solo se realiza desde la vista actual.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Reinstanciar', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 completo', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Menú contextual', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Cambio de página', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Raíces del volumen', // from v2.1.16 added 16.9.2016 + 'reset' : 'Reiniciar', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Color de fondo', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Selector de color', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Cuadricula', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Habilitado', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Deshabilitado', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Los resultados de la búsqueda están vacíos en la vista actual. \\ APulse [Intro] para expandir el objetivo de búsqueda.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'La primera letra de los resultados de búsqueda está vacía en la vista actual.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Etiqueta de texto', // from v2.1.17 added 13.10.2016 + 'minsLeft' : 'Falta $1 minuto(s)', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Abrir nuevamente con la codificación seleccionada', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Guardar con la codificación seleccionada', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Seleccionar carpeta', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Primera letra de búsqueda', // from v2.1.23 added 24.3.2017 + 'presets' : 'Preestablecidos', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Son demasiados elementos, por lo que no puede enviarse a la papelera.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Área de texto', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Vaciar la carpeta "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'No hay elementos en la carpeta "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preferencia', // from v2.1.26 added 28.6.2017 + 'language' : 'Lenguaje', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Inicializa la configuración guardada en este navegador', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Configuración de la barra de herramientas', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '...falta $1 caracteres.', // from v2.1.29 added 30.8.2017 + 'sum' : 'Suma', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Tamaño de archivo aproximado', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Centrado en el elemento de diálogo con \'mouseover\'', // from v2.1.30 added 2.11.2017 + 'select' : 'Seleccionar', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Acción cuando selecciona un archivo', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Abrir con el editor utilizado la última vez', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Invertir selección', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : '¿Estás seguro que quieres renombrar $1 elementos seleccionados como $2?
                      ¡Esto no puede ser deshecho!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Cambiar el nombre del lote', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Número', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Añadir prefijo', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Añadir sufijo', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Cambiar extensión', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Configuración de columnas (Vista de lista)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Todos los cambios se reflejarán inmediatamente en el archivo.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Cualquier cambio no se reflejará hasta que no se desmonte este volumen.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Los siguientes volúmenes montados en este volumen también se desmontaron. ¿Estás seguro de desmontarlo?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Información de la selección', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmos para mostrar el hash de archivos', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Elementos de información (Panel de información de selección)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Presiona de nuevo para salir.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Barra de herramienta', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Espacio de trabajo', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Diálogo', // from v2.1.38 added 4.4.2018 + 'all' : 'Todo', // from v2.1.38 added 4.4.2018 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Desconocido', + 'kindRoot' : 'Raíces del volumen', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Carpeta', + 'kindSelects' : 'Selecciones', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Alias roto', + // applications + 'kindApp' : 'Aplicación', + 'kindPostscript' : 'Documento Postscript', + 'kindMsOffice' : 'Documento Microsoft Office', + 'kindMsWord' : 'Documento Microsoft Word', + 'kindMsExcel' : 'Documento Microsoft Excel', + 'kindMsPP' : 'Presentación Microsoft Powerpoint', + 'kindOO' : 'Documento Open Office', + 'kindAppFlash' : 'Aplicación Flash', + 'kindPDF' : 'Documento PDF', + 'kindTorrent' : 'Archivo Bittorrent', + 'kind7z' : 'Archivo 7z', + 'kindTAR' : 'Archivo TAR', + 'kindGZIP' : 'Archivo GZIP', + 'kindBZIP' : 'Archivo BZIP', + 'kindXZ' : 'Archivo XZ', + 'kindZIP' : 'Archivo ZIP', + 'kindRAR' : 'Archivo RAR', + 'kindJAR' : 'Archivo Java JAR', + 'kindTTF' : 'Fuente True Type', + 'kindOTF' : 'Fuente Open Type', + 'kindRPM' : 'Paquete RPM', + // fonts + 'kindFont' : 'Fuente', + 'kindSFNT' : 'Fuente SFNT', + 'kindEOT' : 'Fuente Embedded Open Type', + 'kindWOFF' : 'Fuente Web Open Font Format', + 'kindWOFF2' : 'Fuente Web Open Font Format 2', + // texts + 'kindText' : 'Documento de texto', + 'kindTextPlain' : 'Texto plano', + 'kindPHP' : 'Código PHP', + 'kindCSS' : 'Hoja de estilos CSS', + 'kindHTML' : 'Documento HTML', + 'kindJS' : 'Código Javascript', + 'kindRTF' : 'Documento RTF', + 'kindC' : 'Código C', + 'kindCHeader' : 'Código C cabeceras', + 'kindCPP' : 'Código C++', + 'kindCPPHeader' : 'Código C++ cabeceras', + 'kindShell' : 'Script de terminal de Unix', + 'kindPython' : 'Código Python', + 'kindJava' : 'Código Java', + 'kindRuby' : 'Código Ruby', + 'kindPerl' : 'Código Perl', + 'kindSQL' : 'Código QL', + 'kindXML' : 'Documento XML', + 'kindAWK' : 'Código AWK', + 'kindCSV' : 'Documento CSV (valores separados por comas)', + 'kindDOCBOOK' : 'Documento Docbook XML', + 'kindMarkdown' : 'Texto Markdown', // added 20.7.2015 + // images + 'kindImage' : 'Imagen', + 'kindBMP' : 'Imagen BMP', + 'kindJPEG' : 'Imagen JPEG', + 'kindGIF' : 'Imagen GIF', + 'kindPNG' : 'Imagen PNG', + 'kindTIFF' : 'Imagen TIFF', + 'kindTGA' : 'Imagen TGA', + 'kindPSD' : 'Imagen Adobe Photoshop', + 'kindXBITMAP' : 'Imagen X bitmap', + 'kindPXM' : 'Imagen Pixelmator', + // media + 'kindAudio' : 'Archivo de audio', + 'kindAudioMPEG' : 'Audio MPEG', + 'kindAudioMPEG4' : 'Audio MPEG-4', + 'kindAudioMIDI' : 'Audio MIDI', + 'kindAudioOGG' : 'Audio Ogg Vorbis', + 'kindAudioWAV' : 'Audio WAV', + 'AudioPlaylist' : 'Lista de reproducción MP3', + 'kindVideo' : 'Archivo de vídeo', + 'kindVideoDV' : 'Película DV', + 'kindVideoMPEG' : 'Película MPEG', + 'kindVideoMPEG4' : 'Película MPEG-4', + 'kindVideoAVI' : 'Película AVI', + 'kindVideoMOV' : 'Película Quick Time', + 'kindVideoWM' : 'Película Windows Media', + 'kindVideoFlash' : 'Película Flash', + 'kindVideoMKV' : 'Película Matroska MKV', + 'kindVideoOGG' : 'Película Ogg' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.fa.js b/lib/redactor/elfinder/js/i18n/elfinder.fa.js new file mode 100644 index 0000000..754e39a --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.fa.js @@ -0,0 +1,587 @@ +/** + * فارسی translation + * @author Keyhan Mohammadpour + * @author mhs prog + * @version 2021-04-14 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.fa = { + translator : 'Keyhan Mohammadpour <keyhan_universityworks@yahoo.com>, Farhad Zare <farhad@persianoc.com>', + language : 'فارسی', + direction : 'rtl', + dateFormat : 'd.m.Y H:i', // will show like: 14.04.2021 19:24 + fancyDateFormat : '$1 H:i', // will show like: امروز 19:24 + nonameDateFormat : 'ymd-His', // noname upload will show like: 210414-192445 + messages : { + + /********************************** errors **********************************/ + 'error' : 'خطا', + 'errUnknown' : 'خطای ناشناخته.', + 'errUnknownCmd' : 'دستور ناشناخته.', + 'errJqui' : 'تنظیمات کتابخانه JQuery UI شما به درستی انجام نشده است. این کتابخانه بایستی شامل Resizable ،Draggable و Droppable باشد.', + 'errNode' : 'elfinder به درستی ایجاد نشده است.', + 'errURL' : 'تنظیمات elfinder شما به درستی انجام نشده است. تنظیم Url را اصلاح نمایید.', + 'errAccess' : 'محدودیت سطح دسترسی', + 'errConnect' : 'امکان اتصال به مدیریت وجود ندارد.', + 'errAbort' : 'ارتباط قطع شده است.', + 'errTimeout' : 'مهلت زمانی ارتباط شما به اتمام رسیده است.', + 'errNotFound' : 'تنظیم مدیریت یافت نشد.', + 'errResponse' : 'پاسخ دریافتی از مدیریت صحیح نمی باشد.', + 'errConf' : 'تنطیمات مدیریت به درستی انجام نشده است.', + 'errJSON' : 'ماژول PHP JSON نصب نیست.', + 'errNoVolumes' : 'درایوهای قابل خواندن یافت نشدند.', + 'errCmdParams' : 'پارامترهای دستور "$1" به صورت صحیح ارسال نشده است.', + 'errDataNotJSON' : 'داده ها در قالب JSON نمی باشند.', + 'errDataEmpty' : 'داده دریافتی خالی است.', + 'errCmdReq' : 'درخواست از سمت مدیریت نیازمند نام دستور می باشد.', + 'errOpen' : 'امکان باز نمودن "$1" وجود ندارد.', + 'errNotFolder' : 'آیتم موردنظر پوشه نیست.', + 'errNotFile' : 'آیتم موردنظر فایل نیست.', + 'errRead' : 'امکان خواندن "$1" وجود ندارد.', + 'errWrite' : 'امکان نوشتن در درون "$1" وجود ندارد.', + 'errPerm' : 'شما مجاز به انجام این عمل نمی باشید.', + 'errLocked' : '"$1" قفل گردیده است و شما قادر به تغییر نام ، حذف و یا جابجایی آن نمی باشید.', + 'errExists' : 'فایلی با نام "$1" هم اکنون وجود دارد.', + 'errInvName' : 'نام انتخابی شما صحیح نمی باشد.', + 'errInvDirname' : 'نام پوشه غیرمعتبر می باشد.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'پوشه مورد نظر یافت نشد.', + 'errFileNotFound' : 'فایل مورد نظر یافت نشد.', + 'errTrgFolderNotFound' : 'پوشه مقصد با نام "$1" یافت نشد.', + 'errPopup' : 'مرورگر شما ار باز شدن پنجره popup جلوگیری می کند، لطفا تنظیمات مربوطه را در مرورگر خود فعال نمایید.', + 'errMkdir' : 'امکان ایجاد پوشه ای با نام "$1" وجود ندارد.', + 'errMkfile' : 'امکان ایجاد فایلی با نام "$1" وجود ندارد.', + 'errRename' : 'امکان تغییر نام فایل "$1" وجود ندارد.', + 'errCopyFrom' : 'کپی نمودن از درایو با نام "$1" ممکن نمی باشد.', + 'errCopyTo' : 'کپی نمودن به درایو با نام "$1" ممکن نمی باشد.', + 'errMkOutLink' : 'امکان ایجاد لینک به خارج از مسیر ریشه وجود ندارد.', // from v2.1 added 03.10.2015 + 'errUpload' : 'خطای آپلود', // old name - errUploadCommon + 'errUploadFile' : 'امکان آپلود "$1" وجود ندارد.', // old name - errUpload + 'errUploadNoFiles' : 'فایلی برای آپلود یافت نشد.', + 'errUploadTotalSize' : 'حجم داده بیش از حد مجاز می باشد.', // old name - errMaxSize + 'errUploadFileSize' : 'حجم فایل بیش از حد مجاز می باشد.', // old name - errFileMaxSize + 'errUploadMime' : 'نوع فایل انتخابی مجاز نمی باشد.', + 'errUploadTransfer' : 'در انتقال "$1" خطایی رخ داده است.', + 'errUploadTemp' : 'امکان ایجاد فایل موقت جهت آپلود وجود ندارد.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'آیتم "$1" از قبل وجود دارد و امکان جایگزینی آن با آیتمی از نوع دیگر وجود ندارد.', // new + 'errReplace' : 'امکان جایگزینی "$1" وجود ندارد.', + 'errSave' : 'امکان ذخیره کردن "$1" وجود ندارد.', + 'errCopy' : 'امکان کپی کردن "$1" وجود ندارد.', + 'errMove' : 'امکان جابجایی "$1" وجود ندارد.', + 'errCopyInItself' : 'امکان کپی کردن "$1" در درون خودش وجود ندارد.', + 'errRm' : 'امکان حذف کردن "$1" وجود ندارد.', + 'errTrash' : 'امکان حذف وجود ندارد.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'امکان حذف فایل(ها) از مبدا وجود ندارد.', + 'errExtract' : 'امکان استخراج فایل فشرده "$1" وجود ندارد.', + 'errArchive' : 'امکان ایجاد فایل فشرده وجود ندارد.', + 'errArcType' : 'نوع ناشناخته برای فایل فشرده.', + 'errNoArchive' : 'این فایل فشرده نیست یا اینکه این نوع فایل فشرده پشتیبانی نمی شود.', + 'errCmdNoSupport' : 'مدیریت از این دستور پشتیبانی نمی کند.', + 'errReplByChild' : 'امکان جایگزینی پوشه "$1" با یک آیتم از درون خودش وجود ندارد.', + 'errArcSymlinks' : 'به دلایل مسائل امنیتی امکان باز کردن فایل فشرده دارای symlinks وجود ندارد.', // edited 24.06.2012 + 'errArcMaxSize' : 'فایل های فشرده به حداکثر اندازه تعیین شده رسیده اند.', + 'errResize' : 'امکان تغییر اندازه "$1" وجود ندارد.', + 'errResizeDegree' : 'درجه چرخش نامعتبر است.', // added 7.3.2013 + 'errResizeRotate' : 'امکان چرخش تصویر وجود ندارد.', // added 7.3.2013 + 'errResizeSize' : 'اندازه تصویر نامعتبر است.', // added 7.3.2013 + 'errResizeNoChange' : 'تغییری در اندازه تصویر ایجاد نشده است.', // added 7.3.2013 + 'errUsupportType' : 'این نوع فایل پشتیبانی نمی شود.', + 'errNotUTF8Content' : 'فایل "$1" به صورت UTF-8 ذخیره نشده و امکان ویرایش آن وجود ندارد.', // added 9.11.2011 + 'errNetMount' : 'امکان اتصال "$1" وجود ندارد.', // added 17.04.2012 + 'errNetMountNoDriver' : 'این پروتکل پشتیبانی نمی شود.', // added 17.04.2012 + 'errNetMountFailed' : 'اتصال ناموفق بود.', // added 17.04.2012 + 'errNetMountHostReq' : 'میزبان موردنیاز است.', // added 18.04.2012 + 'errSessionExpires' : 'اعتبار جلسه کاری شما بدلیل عدم فعالیت برای مدت زمان طولانی به اتمام رسیده است.', + 'errCreatingTempDir' : 'امکان ایجاد دایرکتوری موقت وجود ندارد: "$1"', + 'errFtpDownloadFile' : 'امکان دریافت فایل از FTP وجود ندارد: "$1"', + 'errFtpUploadFile' : 'امکان آپلود فایل به FTP وجود ندارد: "$1"', + 'errFtpMkdir' : 'امکان ایجاد دایرکتوری برروی FTP وجود ندارد: "$1"', + 'errArchiveExec' : 'خطا در زمان فشرده سازی این فایل‌ها: "$1"', + 'errExtractExec' : 'خطا در زمان بازگشایی این فایل‌ها: "$1"', + 'errNetUnMount' : 'امکان قطع اتصال وجود ندارد.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'امکان تبدیل به UTF-8 وجود ندارد', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'جهت آپلود کردن پوشه، از یک مرورگر مدرن استفاده نمایید.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'در هنگان جستجو برای "$1" خطایی رخ داده است. نتیجه جستجو به صورت ناتمام می باشد.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'اعتبارسنجی مجدد موردنیاز است.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'حداکثر تعداد انتخاب قابل قبول $1 می‌باشد.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'امکان بازیابی وجود ندارد. مقصد بازیابی نامشخص است.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'ویرایشگری برای این نوع فایل یافت نشد.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'خطایی در سمت سرور به وجود آمده است.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'امکان خالی کردن پوشه "$1" وجود ندارد.', // from v2.1.25 added 22.6.2017 + 'moreErrors' : '$1 خطای دیگر نیز وجود دارد.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'ایجاد فایل فشرده', + 'cmdback' : 'بازگشت به عقب', + 'cmdcopy' : 'کپی', + 'cmdcut' : 'بریدن', + 'cmddownload' : 'دانلود', + 'cmdduplicate' : 'تکثیر فایل', + 'cmdedit' : 'ویرایش محتوای فایل', + 'cmdextract' : 'بازگشایی فایل فشرده', + 'cmdforward' : 'حرکت به جلو', + 'cmdgetfile' : 'انتخاب فایل‌ها', + 'cmdhelp' : 'درباره این نرم‌افزار', + 'cmdhome' : 'ریشه', + 'cmdinfo' : 'مشاهده مشخصات', + 'cmdmkdir' : 'پوشه جدید', + 'cmdmkdirin' : 'انتقال به پوشه جدید', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'فایل جدید', + 'cmdopen' : 'باز کردن', + 'cmdpaste' : 'چسباندن', + 'cmdquicklook' : 'پیش نمایش', + 'cmdreload' : 'بارگذاری مجدد', + 'cmdrename' : 'تغییر نام', + 'cmdrm' : 'حذف', + 'cmdtrash' : 'انتقال به سطل بازیافت', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'بازیابی', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'جستجوی فایل', + 'cmdup' : 'رفتن به سطح بالاتر', + 'cmdupload' : 'آپلود فایل', + 'cmdview' : 'مشاهده', + 'cmdresize' : 'تغییر اندازه و چرخش', + 'cmdsort' : 'مرتب سازی', + 'cmdnetmount' : 'اتصال درایو شبکه', // added 18.04.2012 + 'cmdnetunmount': 'قطع اتصال', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'به مسیرهای', // added 28.12.2014 + 'cmdchmod' : 'تغییر حالت', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'بازکردن یک پوشه', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'بازنشانی عرض ستون', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'حالت نمایش تمام صفحه', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'انتقال', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'خالی کردن پوشه', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'خنثی‌سازی', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'انجام مجدد', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'تنظیمات', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'انتخاب همه موارد', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'لغو انتخاب', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'انتخاب معکوس', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'باز کردن در پنجره جدید', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'مخفی (پیشنهادی)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'بستن', + 'btnSave' : 'ذخیره', + 'btnRm' : 'حذف', + 'btnApply' : 'اعمال', + 'btnCancel' : 'انصراف', + 'btnNo' : 'خیر', + 'btnYes' : 'بلی', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'اتصال', // added 18.04.2012 + 'btnApprove': 'رفتن به $1 و تایید', // from v2.1 added 26.04.2012 + 'btnUnmount': 'قطع اتصال', // from v2.1 added 30.04.2012 + 'btnConv' : 'تبدیل', // from v2.1 added 08.04.2014 + 'btnCwd' : 'اینجا', // from v2.1 added 22.5.2015 + 'btnVolume' : 'درایو', // from v2.1 added 22.5.2015 + 'btnAll' : 'همه', // from v2.1 added 22.5.2015 + 'btnMime' : 'نوع فایل', // from v2.1 added 22.5.2015 + 'btnFileName':'نام فایل', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'ذخیره و بستن', // from v2.1 added 12.6.2015 + 'btnBackup' : 'پشتیبان‌گیری', // fromv2.1 added 28.11.2015 + 'btnRename' : 'تغییر نام', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'تغییر نام(همه)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'قبلی ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'بعدی ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'ذخیره با نام جدید', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'در حال باز کردن پوشه', + 'ntffile' : 'در حال باز کردن فایل', + 'ntfreload' : 'بارگذاری مجدد محتویات پوشه', + 'ntfmkdir' : 'در حال ایجاد پوشه', + 'ntfmkfile' : 'در حال ایجاد فایل', + 'ntfrm' : 'در حال حذف موارد موردنظر', + 'ntfcopy' : 'در حال کپی موارد موردنظر', + 'ntfmove' : 'در حال انتقال موارد موردنظر', + 'ntfprepare' : 'بررسی موارد موجود', + 'ntfrename' : 'در حال تغییر نام فایل', + 'ntfupload' : 'در حال آپلود فایل', + 'ntfdownload' : 'در حال دانلود فایل', + 'ntfsave' : 'در حال ذخیره فایل', + 'ntfarchive' : 'در حال ایجاد فایل فشرده', + 'ntfextract' : 'در حال استخراج فایل ها از حالت فشرده', + 'ntfsearch' : 'در حال جستجوی فایل', + 'ntfresize' : 'در حال تغییر اندازه تصاویر', + 'ntfsmth' : 'درحال انجام عملیات ....', + 'ntfloadimg' : 'در حال بارگذاری تصویر', + 'ntfnetmount' : 'در حال اتصال درایو شبکه', // added 18.04.2012 + 'ntfnetunmount': 'قطع اتصال درایو شبکه', // from v2.1 added 30.04.2012 + 'ntfdim' : 'در حال محاسبه ابعاد تصویر', // added 20.05.2013 + 'ntfreaddir' : 'در حال دریافت مشخصات پوشه', // from v2.1 added 01.07.2013 + 'ntfurl' : 'در حال دریافت URL', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'در حال تغییر نوع فایل', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'در حال تایید نام فایل جهت آپلود', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'در حال ایجاد فایل جهت دانلود', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'در حال دریافت اطلاعات مسیر', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'در حال پردازش فایل آپلود شده', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'در حال انتقال به سطل بازیافت', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'در حال بازیابی از سطل بازیافت', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'بررسی پوشه مقصد', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'در حال خنثی‌سازی آخرین عملیات', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'در حال انجام مجدد آخرین عملیات', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'در حال بررسی مطالب', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'سطل بازیافت', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'نامعلوم', + 'Today' : 'امروز', + 'Yesterday' : 'دیروز', + 'msJan' : 'ژانویه', + 'msFeb' : 'فوریه', + 'msMar' : 'مارس', + 'msApr' : 'آوریل', + 'msMay' : 'می', + 'msJun' : 'جون', + 'msJul' : 'جولای', + 'msAug' : 'آگوست', + 'msSep' : 'سپتامبر', + 'msOct' : 'اکتبر', + 'msNov' : 'نوامبر', + 'msDec' : 'دسامبر', + 'January' : 'ژانویه', + 'February' : 'فوریه', + 'March' : 'مارس', + 'April' : 'آوریل', + 'May' : 'می', + 'June' : 'جون', + 'July' : 'جولای', + 'August' : 'آگوست', + 'September' : 'سپتامبر', + 'October' : 'اکتبر', + 'November' : 'نوامبر', + 'December' : 'دسامبر', + 'Sunday' : 'یک‌شنبه', + 'Monday' : 'دوشنبه', + 'Tuesday' : 'سه‌شنبه', + 'Wednesday' : 'چهارشنبه', + 'Thursday' : 'پنج‌شنبه', + 'Friday' : 'جمعه', + 'Saturday' : 'شنبه', + 'Sun' : 'یک‌شنبه', + 'Mon' : 'دوشنبه', + 'Tue' : 'سه‌شنبه', + 'Wed' : 'چهارشنبه', + 'Thu' : 'پنج‌شنبه', + 'Fri' : 'جمعه', + 'Sat' : 'شنبه', + + /******************************** sort variants ********************************/ + 'sortname' : 'بر اساس نام', + 'sortkind' : 'بر اساس نوع', + 'sortsize' : 'بر اساس اندازه', + 'sortdate' : 'بر اساس تاریخ', + 'sortFoldersFirst' : 'پوشه‌ها در ابتدای لیست', + 'sortperm' : 'براساس سطح دسترسی', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'براساس مد دسترسی', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'براساس مالک', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'براساس گروه', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'همچنین نمای درختی', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'فایل .txt جدید', // added 10.11.2015 + 'untitled folder' : 'پوشه جدید', // added 10.11.2015 + 'Archive' : 'بایگانی جدید', // from v2.1 added 10.11.2015 + 'untitled file' : '$1 فایل جدید', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: فایل', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'تایید نهایی عملیات ضروری است.', + 'confirmRm' : 'آیا مطمئنید که موارد انتخابی حذف شوند؟ موارد حدف شده قابل بازیابی نخواهند بود!', + 'confirmRepl' : 'مالیلد جایگزینی فایل قدیمی با فایل جدید انجام شود؟ (برای جایگزینی پوشه محتوای قدیمی با محتوای پوشه جدید ادغام خواهد شد. برای تهیه پشتیبانی و سپس جایگزینی گزینه پشتیبان‌گیری را انتخاب نمایید)', + 'confirmRest' : 'آیا مایلید موارد موجود با موارد بازیابی شده از سطل بازیافت جایگزین شود؟', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'UTF-8 نیست
                      تبدیل به UTF-8 انجام شود؟
                      پس از ذخیره سازی محتوا به صورت UTF-8 خواهد بود.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'encoding این فایل قابل تشخیص نیست. جهت ویرایش نیاز است که به صورت موقت به UTF-8 تبدیل شود.
                      لطفا encoding فایل را انتخاب نمایید.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'تغییراتی اعمال شده است.
                      در صورت عدم ذخیره تغییرات از بین خواهد رفت.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'آیا مطمئنید که این موارد به سطل بازیافت منتقل شوند؟', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'آیا مطمئن هستید که می خواهید موارد را به "$1" منتقل کنید؟', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'اعمال تغییرات به همه موارد', + 'name' : 'نام', + 'size' : 'اندازه', + 'perms' : 'سطح دسترسی', + 'modify' : 'آخرین تغییرات', + 'kind' : 'نوع', + 'read' : 'خواندن', + 'write' : 'نوشتن', + 'noaccess' : 'دسترسی وجود ندارد', + 'and' : 'و', + 'unknown' : 'نامعلوم', + 'selectall' : 'انتخاب همه موارد', + 'selectfiles' : 'انتخاب یک یا چند مورد', + 'selectffile' : 'انتخاب اولین مورد', + 'selectlfile' : 'انتخاب آخرین مورد', + 'viewlist' : 'حالت نمایش لیست', + 'viewicons' : 'نمایش با آیکون', + 'viewSmall' : 'آیکون‌های کوچک', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'آیکون‌های متوسط', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'آیکون‌های بزرگ', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'آیکون‌های خیلی بزرگ', // from v2.1.39 added 22.5.2018 + 'places' : 'مسیرها', + 'calc' : 'محاسبه', + 'path' : 'مسیر', + 'aliasfor' : 'نام مستعار برای', + 'locked' : 'قفل شده', + 'dim' : 'ابعاد', + 'files' : 'فایل‌ها', + 'folders' : 'پوشه‌ها', + 'items' : 'آیتم‌ها', + 'yes' : 'بلی', + 'no' : 'خیر', + 'link' : 'لینک', + 'searcresult' : 'نتایج جستجو', + 'selected' : 'موارد انتخاب شده', + 'about' : 'درباره', + 'shortcuts' : 'میانبرها', + 'help' : 'راهنمایی', + 'webfm' : 'مدیر فایل تحت وب', + 'ver' : 'نسخه', + 'protocolver' : 'نسخه پروتکل', + 'homepage' : 'صفحه اصلی پروژه', + 'docs' : 'مستندات', + 'github' : 'صفحه پروژه را در Github مشاهده کنید', + 'twitter' : 'ما را در Twitter دنبال کنید', + 'facebook' : 'به ما در facebook ملحق شوید', + 'team' : 'تیم', + 'chiefdev' : 'توسعه دهنده اصلی', + 'developer' : 'توسعه دهنده', + 'contributor' : 'مشارکت کننده', + 'maintainer' : 'پشتیبان', + 'translator' : 'مترجم', + 'icons' : 'آیکون‌ها', + 'dontforget' : 'and don\'t forget to take your towel', + 'shortcutsof' : 'میانبرها غیرفعال شده‌اند.', + 'dropFiles' : 'فایل ها در این بخش رها کنید.', + 'or' : 'یا', + 'selectForUpload' : 'انتخاب فایل جهت آپلود', + 'moveFiles' : 'انتقال موارد', + 'copyFiles' : 'کپی موارد', + 'restoreFiles' : 'بازیابی موارد', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'حذف', + 'aspectRatio' : 'نسبت تصویر', + 'scale' : 'مقیاس', + 'width' : 'طول', + 'height' : 'ارتفاع', + 'resize' : 'تغییر اندازه', + 'crop' : 'بریدن', + 'rotate' : 'چرخاندن', + 'rotate-cw' : 'چرخاندن 90 درجه در جهت عقربه‌های ساعت', + 'rotate-ccw' : 'چرخاندن 90 درجه در جهت خلاف عقربه‌های ساعت', + 'degree' : '°', + 'netMountDialogTitle' : 'اتصال درایو شبکه', // added 18.04.2012 + 'protocol' : 'پروتکل', // added 18.04.2012 + 'host' : 'میزبان', // added 18.04.2012 + 'port' : 'پورت', // added 18.04.2012 + 'user' : 'نام کاربری', // added 18.04.2012 + 'pass' : 'کلمه عبور', // added 18.04.2012 + 'confirmUnmount' : 'مطمئن به قطع اتصال $1 می باشد؟', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'فایل‌ها را به داخل این کادر بیندازید یا از حافظه paste کنید', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'فایل‌ها را به داخل این کادر بیندازید یا از داخل حافظه آدرس URL/تصاویر را paste کنید', // from v2.1 added 07.04.2014 + 'encoding' : 'نوع کد گذاری', // from v2.1 added 19.12.2014 + 'locale' : 'نوع Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'مقصد: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'جستجو براساس MIME Type وارد شده', // from v2.1 added 22.5.2015 + 'owner' : 'مالک', // from v2.1 added 20.6.2015 + 'group' : 'گروه', // from v2.1 added 20.6.2015 + 'other' : 'سایر', // from v2.1 added 20.6.2015 + 'execute' : 'قابل اجرا', // from v2.1 added 20.6.2015 + 'perm' : 'سطح دسترسی', // from v2.1 added 20.6.2015 + 'mode' : 'مد دسترسی', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'پوشه خالی است', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'پوشه خالی است، فایل‌ها را جهت افزودن کشیده و رها کنید', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'پوشه خالی است، یک اشاره طولانی برای افزودن فایل کافی است', // from v2.1.6 added 30.12.2015 + 'quality' : 'کیفیت', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'همگام‌سازی خودکار', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'حرکت به بالا', // from v2.1.6 added 18.1.2016 + 'getLink' : 'دریافت URL لینک', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'موارد انتخاب شده ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'شناسه پوشه', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'اجازه دسترسی به صورت آفلاین', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'جهت اعتبارسنجی مجدد', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'در حال بازگذاری...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'بازکردن چندین فایل', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'شما قصد باز کردن $1 فایل را دارید. آیا مایلید همه موارد در مرورگر باز شود؟', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'موردی یافت نشد.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'در حال ویرایش یک فایل.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'شما $1 مورد را انتخاب کرده‌اید.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'در حافظه $1 مورد وجود دارد.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'جستجوی افزایش فقط از نمای فعلی.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'بازگرداندن', // from v2.1.15 added 3.8.2016 + 'complete' : 'عملیات $1 انجام شد', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'منو راست', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'چرخش صفحه', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'ریشه‌های درایو', // from v2.1.16 added 16.9.2016 + 'reset' : 'بازنشانی', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'رنگ پس زمینه', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'انتخابگر رنگ', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'گرید 8px', // from v2.1.16 added 4.10.2016 + 'enabled' : 'فعال شده', // from v2.1.16 added 4.10.2016 + 'disabled' : 'غیرفعال شده', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'در نمای فعلی موردی یافت نشد.\\Aبا فشردن کلید Enter مسیر جستجو را تغییر دهید.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'برای جستجوی تک حرفی در نمایش فعلی موردی یافت نشد.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'عنوان متنی', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 دقیقه باقیمانده', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'باز کردن مجدد با کد گذاری انتخاب شده', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'ذخیره با کد گذاری انتخاب شده', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'انتخاب پوشه', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'جستجوی تک حرفی', // from v2.1.23 added 24.3.2017 + 'presets' : 'از پیش تعیین شده', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'موارد زیاد است و امکان انتقال به سطل بازیافت وجود ندارد.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'ویرایش محتوا', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'خالی کردن پوشه "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'پوشه "$1" ‌ذاتا خالی است.', // from v2.1.25 added 22.6.2017 + 'preference' : 'تنظیمات', // from v2.1.26 added 28.6.2017 + 'language' : 'زبان', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'بازبینی تنظیمات ذخیره شده در این مرورگر', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'تنظیمات نوار ابزار', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 کاراکتر باقیمانده.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '$1 خط مانده است', // from v2.1.52 added 16.1.2020 + 'sum' : 'مجموع', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'اندازه فایل نامتعارف', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'انتخاب عناصر داخل دیالوگ با mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'انتخاب', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'عملیات به هنگام انتخاب فایل', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'باز کردن با ویرایشگر مورداستفاده در آخرین دفعه', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'انتخاب معکوس', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'آیا مایل به تغییر نام $1 مورد انتخاب شده همانند $2 هستید؟
                      امکان بازگرداندن این تغییر پس از اعمالو جود ندارد!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'تغییرنام گروهی', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ عدد', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'افزودن پیشوند', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'افزودن پسوند', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'تغییر پسوند فایل', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'تنظیمات ستون‌ها (حالت نمایش لیست)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'تمامی تغییرات به صورت آنی برروی فایل فشرده اعمال خواهد شد.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'تمامی تغییرات تا زمانی که اتصال این درایو قطع نشده است اعمال نخواهند شد.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'اتصال به درایوهای زیر قطع خواهد شد. آیا مطمئن به ادامه عملیات هستید؟', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'مشخصات', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'الگوریتم های نمایش hash فایل', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'موارد اطلاعات', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'جهت خروج مجدد فشار دهید.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'نوار ابزار', // from v2.1.38 added 4.4.2018 + 'workspace' : 'فضای کاری', // from v2.1.38 added 4.4.2018 + 'dialog' : 'پنجره دیالوگ', // from v2.1.38 added 4.4.2018 + 'all' : 'همه', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'اندازه آیکون‌ها (نمایش به صورت آیکون)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'باز کردن پنجره ویرایشگر به صورت تمام صفحه', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'بدلیل در دسترسی نبودن تبدیل از طریق API، لطفا برروی وب سایت تبدیل را انجام دهید.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'پس از تبدیل, شما بایستی از طریق آدرس URL یا فایل دریافت شده آپلود را انجاد دهید تا فایل تبدیل شده ذخیره گردد.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'تبدیل برروی سایت از $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'هماهنگ سازی‌ها', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'elFinder با سرویس های زیر هماهنگ شده است. لطفا ابتدا شرایط استفاده، مقررات حریم خصوصی و سایر موارد را مطالعه بفرمایید.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'نمایش موارد پنهان', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'موارد مخفی را پنهان کنید', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'نمایش / پنهان کردن موارد پنهان', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'File types to enable with "New file"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'نوع فایل نوشتاری', // from v2.1.41 added 7.8.2018 + 'add' : 'اضافه کردن', // from v2.1.41 added 7.8.2018 + 'theme' : 'Theme', // from v2.1.43 added 19.10.2018 + 'default' : 'پیش فرض', // from v2.1.43 added 19.10.2018 + 'description' : 'توضیحات', // from v2.1.43 added 19.10.2018 + 'website' : 'وب سایت', // from v2.1.43 added 19.10.2018 + 'author' : 'نویستده', // from v2.1.43 added 19.10.2018 + 'email' : 'ایمیل', // from v2.1.43 added 19.10.2018 + 'license' : 'لایسنس', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'این مورد ذخیره نمی شود برای جلوگیری از دست دادن ویرایش ها ، آنها را به رایانه خود منتقل کنید.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'برای انتخاب پرونده ، دوبار کلیک کنید.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'از حالت تمام صفحه استفاده کنید', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'نامعلوم', + 'kindRoot' : 'ریشه درایو', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'پوشه', + 'kindSelects' : 'انتخاب شده‌ها', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'اسم مستعار', + 'kindAliasBroken' : 'اسم مستعار ناقص', + // applications + 'kindApp' : 'برنامه', + 'kindPostscript' : 'سند Postscript', + 'kindMsOffice' : 'سند Microsoft Office', + 'kindMsWord' : 'سند Microsoft Word', + 'kindMsExcel' : 'سند Microsoft Excel', + 'kindMsPP' : 'فایل ارایه Microsoft Powerpoint', + 'kindOO' : 'سند Open Office', + 'kindAppFlash' : 'برنامه فلش', + 'kindPDF' : 'سند قابل حمل (PDF)', + 'kindTorrent' : 'فایل تورنت', + 'kind7z' : 'فایل فشرده 7z', + 'kindTAR' : 'فایل فشرده TAR', + 'kindGZIP' : 'فایل فشرده GZIP', + 'kindBZIP' : 'فایل فشرده BZIP', + 'kindXZ' : 'فایل فشرده XZ', + 'kindZIP' : 'فایل فشرده ZIP', + 'kindRAR' : 'فایل فشرده RAR', + 'kindJAR' : 'فایل JAR مربوط به جاوا', + 'kindTTF' : 'فونت True Type', + 'kindOTF' : 'فونت Open Type', + 'kindRPM' : 'بسته RPM', + // fonts + 'kindFont' : 'فونت', + 'kindSFNT' : 'فونت SFNT', + 'kindEOT' : 'فونت Embedded Open Type', + 'kindWOFF' : 'فونت Web Open Font Format', + 'kindWOFF2' : 'فونت Web Open Font Format 2', + // texts + 'kindText' : 'سند متنی', + 'kindTextPlain' : 'سند متنی ساده', + 'kindPHP' : 'سورس کد PHP', + 'kindCSS' : 'فایل style sheet', + 'kindHTML' : 'سند HTML', + 'kindJS' : 'سورس کد Javascript', + 'kindRTF' : 'سند متنی غنی', + 'kindC' : 'سورس کد C', + 'kindCHeader' : 'سورس کد C header', + 'kindCPP' : 'سورس کد C++', + 'kindCPPHeader' : 'سورس کد C++ header', + 'kindShell' : 'اسکریپت شل یونیکس', + 'kindPython' : 'سورس کد Python', + 'kindJava' : 'سورس کد Java', + 'kindRuby' : 'سورس کد Ruby', + 'kindPerl' : 'اسکریپت Perl', + 'kindSQL' : 'سورس کد SQL', + 'kindXML' : 'سند XML', + 'kindAWK' : 'سورس کد AWK', + 'kindCSV' : 'مقادیر جداشده با کامل', + 'kindDOCBOOK' : 'سند Docbook XML', + 'kindMarkdown' : 'سند متنی Markdown', // added 20.7.2015 + // images + 'kindImage' : 'تصویر', + 'kindBMP' : 'تصویر BMP', + 'kindJPEG' : 'تصویر JPEG', + 'kindGIF' : 'تصویر GIF', + 'kindPNG' : 'تصویر PNG', + 'kindTIFF' : 'تصویر TIFF', + 'kindTGA' : 'تصویر TGA', + 'kindPSD' : 'تصویر Adobe Photoshop', + 'kindXBITMAP' : 'تصویر X bitmap', + 'kindPXM' : 'تصویر Pixelmator', + // media + 'kindAudio' : 'فایل صوتی', + 'kindAudioMPEG' : 'فایل صوتی MPEG', + 'kindAudioMPEG4' : 'فایل صوتی MPEG-4', + 'kindAudioMIDI' : 'فایل صوتی MIDI', + 'kindAudioOGG' : 'فایل صوتی Ogg Vorbis', + 'kindAudioWAV' : 'فایل صوتی WAV', + 'AudioPlaylist' : 'لیست پخش MP3', + 'kindVideo' : 'فایل ویدیویی', + 'kindVideoDV' : 'فایل ویدیویی DV', + 'kindVideoMPEG' : 'فایل ویدیویی MPEG', + 'kindVideoMPEG4' : 'فایل ویدیویی MPEG-4', + 'kindVideoAVI' : 'فایل ویدیویی AVI', + 'kindVideoMOV' : 'فایل ویدیویی Quick Time', + 'kindVideoWM' : 'فایل ویدیویی Windows Media', + 'kindVideoFlash' : 'فایل ویدیویی Flash', + 'kindVideoMKV' : 'فایل ویدیویی Matroska', + 'kindVideoOGG' : 'فایل ویدیویی Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.fallback.js b/lib/redactor/elfinder/js/i18n/elfinder.fallback.js new file mode 100644 index 0000000..5aa4a09 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.fallback.js @@ -0,0 +1,11 @@ +(function(factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(); + } else { + factory(); + } +}(this, function() { + return void 0; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.fo.js b/lib/redactor/elfinder/js/i18n/elfinder.fo.js new file mode 100644 index 0000000..43ab05f --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.fo.js @@ -0,0 +1,426 @@ +/** + * Faroese translation + * @author Marius Hammer + * @version 2015-12-03 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.fo = { + translator : 'Marius Hammer <marius@vrg.fo>', + language : 'Faroese', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + messages : { + + /********************************** errors **********************************/ + 'error' : 'Villa íkomin', + 'errUnknown' : 'Ókend villa.', + 'errUnknownCmd' : 'Ókend boð.', + 'errJqui' : 'Ógildig jQuery UI konfiguratión. Vælbærar, sum kunnu hálast runt og kunnu sleppast skulu takast við.', + 'errNode' : 'elFinder krevur DOM Element stovna.', + 'errURL' : 'Ugyldig elFinder konfiguration! URL stilling er ikki ásett.', + 'errAccess' : 'Atgongd nokta.', + 'errConnect' : 'Far ikki samband við backend.', + 'errAbort' : 'Sambandi avbrotið.', + 'errTimeout' : 'Sambandi broti av.', + 'errNotFound' : 'Backend ikki funnið.', + 'errResponse' : 'Ógildugt backend svar.', + 'errConf' : 'Ógildugt backend konfiguratión.', + 'errJSON' : 'PHP JSON modulið er ikki innstallera.', + 'errNoVolumes' : 'Lesiligar mappur er ikki atkomulig.', + 'errCmdParams' : 'Ógildigar stillingar fyri kommando "$1".', + 'errDataNotJSON' : 'Dáta er ikki JSON.', + 'errDataEmpty' : 'Dáta er tømt.', + 'errCmdReq' : 'Backend krevur eitt kommando navn.', + 'errOpen' : 'Kundi ikki opna "$1".', + 'errNotFolder' : 'Luturin er ikki ein mappa.', + 'errNotFile' : 'Luturin er ikki ein fíla.', + 'errRead' : 'Kundi ikki lesa til "$1".', + 'errWrite' : 'Kundi ikki skriva til "$1".', + 'errPerm' : 'Atgongd nokta.', + 'errLocked' : '"$1" er løst og kann ikki umdoybast, flytast ella strikast.', + 'errExists' : 'Tað finst longu ein fíla við navn "$1".', + 'errInvName' : 'Ógildugt fíla navn.', + 'errFolderNotFound' : 'Mappa ikki funnin.', + 'errFileNotFound' : 'Fíla ikki funnin.', + 'errTrgFolderNotFound' : 'Mappan "$1" bleiv ikke funnin.', + 'errPopup' : 'Kagin forðaði í at opna eitt popup-vindeyga. Fyri at opna fíluna, aktivera popup-vindeygu í tínum kaga stillingum.', + 'errMkdir' : '\'Kundi ikki stovna mappu "$1".', + 'errMkfile' : 'Kundi ikki stovna mappu "$1".', + 'errRename' : 'Kundi ikki umdoyba "$1".', + 'errCopyFrom' : 'Kopiering av fílum frá mappuni "$1" er ikke loyvt.', + 'errCopyTo' : 'Kopiering av fílum til mappuna "$1" er ikke loyvt.', + 'errMkOutLink' : 'Ikki ført fyri at stovna leinkju til uttanfyri \'volume\' rót.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Innlegginar feilur.', // old name - errUploadCommon + 'errUploadFile' : 'Kundi ikki leggja "$1" inn.', // old name - errUpload + 'errUploadNoFiles' : 'Ongar fílar funnir at leggja inn.', + 'errUploadTotalSize' : 'Dátain er størri enn mest loyvda støddin.', // old name - errMaxSize + 'errUploadFileSize' : 'Fíla er størri enn mest loyvda støddin.', // old name - errFileMaxSize + 'errUploadMime' : 'Fílu slag ikki góðkent.', + 'errUploadTransfer' : '"$1" innleggingar feilur.', + 'errUploadTemp' : 'Ikki ført fyri at gera fyribils fílu fyri innlegging.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Lutur "$1" finst longu á hesum stað og can ikki skiftast út av lutið av øðrum slag.', // new + 'errReplace' : 'Ikki ført fyri at erstattae "$1".', + 'errSave' : 'Kundi ikki goyma "$1".', + 'errCopy' : 'Kundi ikki kopiera "$1".', + 'errMove' : 'Kundi ikki flyta "$1".', + 'errCopyInItself' : 'Kundi ikki kopiera "$1" inn í seg sjálva.', + 'errRm' : 'Kundi ikki strika "$1".', + 'errRmSrc' : 'Ikki ført fyri at strika keldu fíla(r).', + 'errExtract' : 'Kundi ikki útpakka fílar frá "$1".', + 'errArchive' : 'Kundi ikki stovna arkiv.', + 'errArcType' : 'Arkiv slagið er ikki stuðla.', + 'errNoArchive' : 'Fílan er ikki eitt arkiv ella er ikki eitt stuðla arkiva slag.', + 'errCmdNoSupport' : 'Backend stuðlar ikki hesi boð.', + 'errReplByChild' : 'appan "$1" kann ikki erstattast av einari vøru, hon inniheldur.', + 'errArcSymlinks' : 'Av trygdarávum grundum, noktaði skipanin at pakka út arkivir ið innihalda symlinks ella fílur við nøvn ið ikki eru loyvd.', // edited 24.06.2012 + 'errArcMaxSize' : 'Arkiv fílar fylla meir enn mest loyvda støddin.', + 'errResize' : 'Kundi ikki broyta støddina á "$1".', + 'errResizeDegree' : 'Ógildugt roterings stig.', // added 7.3.2013 + 'errResizeRotate' : 'Ikki ført fyri at rotera mynd.', // added 7.3.2013 + 'errResizeSize' : 'Ógildug myndastødd.', // added 7.3.2013 + 'errResizeNoChange' : 'Mynda stødd ikki broytt.', // added 7.3.2013 + 'errUsupportType' : 'Ikki stuðla fíla slag.', + 'errNotUTF8Content' : 'Fílan "$1" er ikki í UTF-8 og kann ikki vera rættað.', // added 9.11.2011 + 'errNetMount' : 'Kundi ikki "mounta" "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Ikki stuðla protokol.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount miseydnaðist.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host kravt.', // added 18.04.2012 + 'errSessionExpires' : 'Tín seta er útgingin vegna óvirkniy.', + 'errCreatingTempDir' : 'Ikki ført fyri at stovna fyribils fíluskrá: "$1"', + 'errFtpDownloadFile' : 'Ikki ført fyri at taka fílu niður frá FTP: "$1"', + 'errFtpUploadFile' : 'Ikki ført fyri at leggja fílu til FTP: "$1"', + 'errFtpMkdir' : 'Ikki ført fyri at stovna fjar-fílaskrá á FTP: "$1"', + 'errArchiveExec' : 'Villa íkomin undir arkiveran af fílar: "$1"', + 'errExtractExec' : 'Villa íkomin undir útpakking af fílum: "$1"', + 'errNetUnMount' : 'Unable to unmount', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Kann ikki broytast til UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Royn Google Chrome, um tú ynskir at leggja mappu innn.', // from v2.1 added 26.6.2015 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Stovna arkiv', + 'cmdback' : 'Aftur\'', + 'cmdcopy' : 'Kopier', + 'cmdcut' : 'Klipp', + 'cmddownload' : 'Tak niður', + 'cmdduplicate' : 'Tvífalda', + 'cmdedit' : 'Rætta fílu', + 'cmdextract' : 'Pakka út fílar úr arkiv', + 'cmdforward' : 'Fram', + 'cmdgetfile' : 'Vel fílar', + 'cmdhelp' : 'Um hesa software', + 'cmdhome' : 'Heim', + 'cmdinfo' : 'Fá upplýsingar', + 'cmdmkdir' : 'Nýggja mappu', + 'cmdmkfile' : 'Nýggja fílu', + 'cmdopen' : 'Opna', + 'cmdpaste' : 'Set inn', + 'cmdquicklook' : 'Forsýning', + 'cmdreload' : 'Les inn umaftur', + 'cmdrename' : 'Umdoyp', + 'cmdrm' : 'Strika', + 'cmdsearch' : 'Finn fílar', + 'cmdup' : 'Eitt stig upp', + 'cmdupload' : 'Legg fílar inn', + 'cmdview' : 'Síggj', + 'cmdresize' : 'Tillaga stødd & Roter', + 'cmdsort' : 'Raða', + 'cmdnetmount' : 'Mount network volume', // added 18.04.2012 + 'cmdnetunmount': 'Unmount', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Til støð', // added 28.12.2014 + 'cmdchmod' : 'Broytir stíl', // from v2.1 added 20.6.2015 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Lat aftur', + 'btnSave' : 'Goym', + 'btnRm' : 'Strika', + 'btnApply' : 'Brúka', + 'btnCancel' : 'Angra', + 'btnNo' : 'Nei', + 'btnYes' : 'Ja', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', // added 18.04.2012 + 'btnApprove': 'Goto $1 & approve', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Konverter', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Her', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'Øll', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Slag', // from v2.1 added 22.5.2015 + 'btnFileName':'Fílunavn', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Goym & Lat aftur', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Opna mappu', + 'ntffile' : '\'Opna fílu', + 'ntfreload' : 'Les innaftur mappu innihald', + 'ntfmkdir' : 'Stovnar mappu', + 'ntfmkfile' : 'Stovnar fílur', + 'ntfrm' : 'Strikar fílur', + 'ntfcopy' : 'Kopierar fílur', + 'ntfmove' : 'Flytur fílar', + 'ntfprepare' : 'Ger klárt at kopiera fílar', + 'ntfrename' : 'Umdoyp fílar', + 'ntfupload' : 'Leggur inn fílar', + 'ntfdownload' : 'Tekur fílar niður', + 'ntfsave' : 'Goymir fílar', + 'ntfarchive' : 'Stovnar arkiv', + 'ntfextract' : 'Útpakkar fílar frá arkiv', + 'ntfsearch' : 'Leitar eftir fílum', + 'ntfresize' : 'Broytir stødd á fílur', + 'ntfsmth' : '\'Ger okkurt >_<', + 'ntfloadimg' : 'Lesur mynd inn', + 'ntfnetmount' : 'Mounting network volume', // added 18.04.2012 + 'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Tekur mynda vídd', // added 20.05.2013 + 'ntfreaddir' : 'Lesur mappu upplýsingar', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Far URL af leinkju', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Broyti fílu stíl', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Kannar fílunavnið á fílu', // from v2.1 added 31.11.2015 + + /************************************ dates **********************************/ + 'dateUnknown' : 'ókent', + 'Today' : 'Í dag', + 'Yesterday' : 'Í gjár', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Mai', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Des', + 'January' : 'Januar', + 'February' : 'Februar', + 'March' : 'Mars', + 'April' : 'Apríl', + 'May' : 'Mai', + 'June' : 'Juni', + 'July' : 'Juli', + 'August' : 'August', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'November', + 'December' : 'Desember', + 'Sunday' : 'Sunnudag', + 'Monday' : 'Mánadag', + 'Tuesday' : 'Týsdag', + 'Wednesday' : 'Mikudag', + 'Thursday' : 'Hósdag', + 'Friday' : 'Fríggjadag', + 'Saturday' : 'Leygardag', + 'Sun' : 'Sun', + 'Mon' : 'Mán', + 'Tue' : 'Týs', + 'Wed' : 'Mik', + 'Thu' : 'Hós', + 'Fri' : 'Frí', + 'Sat' : 'Ley', + + /******************************** sort variants ********************************/ + 'sortname' : 'eftir navn', + 'sortkind' : 'eftir slag', + 'sortsize' : 'eftir stødd', + 'sortdate' : 'eftir dato', + 'sortFoldersFirst' : 'mappur fyrst', + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NýggjaFílu.txt', // added 10.11.2015 + 'untitled folder' : 'NýggjaMappu', // added 10.11.2015 + 'Archive' : 'NýtArkiv', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'Váttan kravd', + 'confirmRm' : 'Ert tú vísur í at tú ynskir at strika fílarnar?
                      Hetta kann ikki angrast!', + 'confirmRepl' : 'Erstatta gomlu fílu við nýggja?', + 'confirmConvUTF8' : 'Brúka á øll', // from v2.1 added 08.04.2014 + 'confirmNotSave' : 'Er blivi rættað.
                      Missir sínar broytingar um tú ikki goymir.', // from v2.1 added 15.7.2015 + 'apllyAll' : 'Brúka til øll', + 'name' : 'Navn', + 'size' : 'Stødd', + 'perms' : 'Rættindi', + 'modify' : 'Rættað', + 'kind' : 'Slag', + 'read' : 'síggja', + 'write' : 'broyta', + 'noaccess' : 'onga atgongd', + 'and' : 'og', + 'unknown' : 'ókent', + 'selectall' : 'Vel allar fílur', + 'selectfiles' : 'Vel fílu(r)', + 'selectffile' : 'Vel fyrstu fílu', + 'selectlfile' : 'Vel síðstu fílu', + 'viewlist' : 'Lista vísing', + 'viewicons' : 'Ikon vísing', + 'places' : 'Støð', + 'calc' : 'Rokna', + 'path' : 'Stiga', + 'aliasfor' : 'Hjánavn fyri', + 'locked' : 'Læst', + 'dim' : 'Vídd', + 'files' : 'Fílur', + 'folders' : 'Mappur', + 'items' : 'Myndir', + 'yes' : 'ja', + 'no' : 'nei', + 'link' : 'Leinkja', + 'searcresult' : 'Leiti úrslit', + 'selected' : 'valdar myndir', + 'about' : 'Um', + 'shortcuts' : 'Snarvegir', + 'help' : 'Hjálp', + 'webfm' : 'Web fílu umsitan', + 'ver' : 'Útgáva', + 'protocolver' : 'protokol versión', + 'homepage' : 'Verkætlan heim', + 'docs' : 'Skjalfesting', + 'github' : 'Mynda okkum á Github', + 'twitter' : 'Fylg okkum á twitter', + 'facebook' : 'Fylg okkum á facebook', + 'team' : 'Lið', + 'chiefdev' : 'forritaleiðari', + 'developer' : 'forritari', + 'contributor' : 'stuðulsveitari', + 'maintainer' : 'viðlíkahaldari', + 'translator' : 'umsetari', + 'icons' : 'Ikonir', + 'dontforget' : 'and don\'t forget to take your towel', + 'shortcutsof' : 'Snarvegir sligi frá', + 'dropFiles' : 'Slepp fílur her', + 'or' : 'ella', + 'selectForUpload' : 'Vel fílur at leggja inn', + 'moveFiles' : 'Flyt fílur', + 'copyFiles' : 'Kopier fílur', + 'rmFromPlaces' : 'Flyt frá støð', + 'aspectRatio' : 'Skermformat', + 'scale' : 'Skalera', + 'width' : 'Longd', + 'height' : 'Hædd', + 'resize' : 'Tilliga stødd', + 'crop' : 'Sker til', + 'rotate' : 'Rotera', + 'rotate-cw' : 'Rotera 90 gradir við urið', + 'rotate-ccw' : 'otera 90 gradir móti urið', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Brúkari', // added 18.04.2012 + 'pass' : 'Loyniorð', // added 18.04.2012 + 'confirmUnmount' : 'Are you unmount $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Hála ella set innn fílar frá kaga', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Hála ella set inn fílar frá URls her', // from v2.1 added 07.04.2014 + 'encoding' : 'Encoding', // from v2.1 added 19.12.2014 + 'locale' : 'Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Target: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Leita við input MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Eigari', // from v2.1 added 20.6.2015 + 'group' : 'Bólkur', // from v2.1 added 20.6.2015 + 'other' : 'Annað', // from v2.1 added 20.6.2015 + 'execute' : 'Útfør', // from v2.1 added 20.6.2015 + 'perm' : 'Rættindi', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Ókent', + 'kindFolder' : 'Mappa', + 'kindAlias' : 'Hjánavn', + 'kindAliasBroken' : 'Óvirki hjánavn', + // applications + 'kindApp' : 'Applikatión', + 'kindPostscript' : 'Postscript skjal', + 'kindMsOffice' : 'Microsoft Office skjal', + 'kindMsWord' : 'Microsoft Word skjal', + 'kindMsExcel' : 'Microsoft Excel skjal', + 'kindMsPP' : 'Microsoft Powerpoint framløga', + 'kindOO' : 'Open Office skjal', + 'kindAppFlash' : 'Flash applikatión', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent fíla', + 'kind7z' : '7z arkiv', + 'kindTAR' : 'TAR arkiv', + 'kindGZIP' : 'GZIP arkiv', + 'kindBZIP' : 'BZIP arkiv', + 'kindXZ' : 'XZ arkiv', + 'kindZIP' : 'ZIP arkiv', + 'kindRAR' : 'RAR arkiv', + 'kindJAR' : 'Java JAR ffílaile', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM pakki', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Text skjal', + 'kindTextPlain' : 'Reinur tekstur', + 'kindPHP' : 'PHP kelda', + 'kindCSS' : 'Cascading style sheet (CSS)', + 'kindHTML' : 'HTML skjal', + 'kindJS' : 'Javascript kelda', + 'kindRTF' : 'Rich Text Format (RTF)', + 'kindC' : 'C kelda', + 'kindCHeader' : 'C header kelda', + 'kindCPP' : 'C++ kelda', + 'kindCPPHeader' : 'C++ header kelda', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python kelda', + 'kindJava' : 'Java kelda', + 'kindRuby' : 'Ruby kelda', + 'kindPerl' : 'Perl script', + 'kindSQL' : 'SQL kelda', + 'kindXML' : 'XML skjal', + 'kindAWK' : 'AWK kelda', + 'kindCSV' : 'Comma separated values (CSV)', + 'kindDOCBOOK' : 'Docbook XML skjal', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Mynd', + 'kindBMP' : 'BMP mynd', + 'kindJPEG' : 'JPEG mynd', + 'kindGIF' : 'GIF mynd', + 'kindPNG' : 'PNG mynd', + 'kindTIFF' : 'TIFF mynd', + 'kindTGA' : 'TGA mynd', + 'kindPSD' : 'Adobe Photoshop mynd', + 'kindXBITMAP' : 'X bitmap mynd', + 'kindPXM' : 'Pixelmator mynd', + // media + 'kindAudio' : 'Audio media', + 'kindAudioMPEG' : 'MPEG ljóðfíla', + 'kindAudioMPEG4' : 'MPEG-4 ljóðfíla', + 'kindAudioMIDI' : 'MIDI ljóðfíla', + 'kindAudioOGG' : 'Ogg Vorbis ljóðfíla', + 'kindAudioWAV' : 'WAV ljóðfíla', + 'AudioPlaylist' : 'MP3 playlisti', + 'kindVideo' : 'Video media', + 'kindVideoDV' : 'DV filmur', + 'kindVideoMPEG' : 'MPEG filmur', + 'kindVideoMPEG4' : 'MPEG-4 filmur', + 'kindVideoAVI' : 'AVI filmur', + 'kindVideoMOV' : 'Quick Time filmur', + 'kindVideoWM' : 'Windows Media filmur', + 'kindVideoFlash' : 'Flash filmur', + 'kindVideoMKV' : 'Matroska filmur', + 'kindVideoOGG' : 'Ogg filmur' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.fr.js b/lib/redactor/elfinder/js/i18n/elfinder.fr.js new file mode 100644 index 0000000..abae816 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.fr.js @@ -0,0 +1,589 @@ +/** + * française translation + * @author Régis Guyomarch + * @author Benoit Delachaux + * @author Jonathan Grunder + * @version 2023-04-16 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.fr = { + translator : 'Régis Guyomarch <regisg@gmail.com>, Benoit Delachaux <benorde33@gmail.com>, Jonathan Grunder <jonathan.grunder@gmail.com>', + language : 'française', + direction : 'ltr', + dateFormat : 'd/M/Y H:i', // will show like: 16/Avr/2023 12:36 + fancyDateFormat : '$1 H:i', // will show like: Aujourd'hui 12:36 + nonameDateFormat : 'ymd-His', // noname upload will show like: 230416-123657 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Erreur', + 'errUnknown' : 'Erreur inconnue.', + 'errUnknownCmd' : 'Commande inconnue.', + 'errJqui' : 'Mauvaise configuration de jQuery UI. Les composants Selectable, draggable et droppable doivent être inclus.', + 'errNode' : 'elFinder requiert que l\'élément DOM ait été créé.', + 'errURL' : 'Mauvaise configuration d\'elFinder ! L\'option URL n\'a pas été définie.', + 'errAccess' : 'Accès refusé.', + 'errConnect' : 'Impossible de se connecter au backend.', + 'errAbort' : 'Connexion interrompue.', + 'errTimeout' : 'Délai de connexion dépassé.', + 'errNotFound' : 'Backend non trouvé.', + 'errResponse' : 'Mauvaise réponse du backend.', + 'errConf' : 'Mauvaise configuration du backend.', + 'errJSON' : 'Le module PHP JSON n\'est pas installé.', + 'errNoVolumes' : 'Aucun volume lisible.', + 'errCmdParams' : 'Mauvais paramétrage de la commande "$1".', + 'errDataNotJSON' : 'Les données ne sont pas au format JSON.', + 'errDataEmpty' : 'Données inexistantes.', + 'errCmdReq' : 'La requête au Backend doit comporter le nom de la commande.', + 'errOpen' : 'Impossible d\'ouvrir "$1".', + 'errNotFolder' : 'Cet objet n\'est pas un dossier.', + 'errNotFile' : 'Cet objet n\'est pas un fichier.', + 'errRead' : 'Impossible de lire "$1".', + 'errWrite' : 'Impossible d\'écrire dans "$1".', + 'errPerm' : 'Permission refusée.', + 'errLocked' : '"$1" est verrouillé et ne peut être déplacé ou supprimé.', + 'errExists' : 'Un élément nommé "$1" existe déjà.', + 'errInvName' : 'Nom de fichier incorrect.', + 'errInvDirname' : 'Nom de dossier incorrect.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Dossier non trouvé.', + 'errFileNotFound' : 'Fichier non trouvé.', + 'errTrgFolderNotFound' : 'Dossier destination "$1" non trouvé.', + 'errPopup' : 'Le navigateur web a empêché l\'ouverture d\'une fenêtre "popup". Pour ouvrir le fichier, modifiez les options du navigateur web.', + 'errMkdir' : 'Impossible de créer le dossier "$1".', + 'errMkfile' : 'Impossible de créer le fichier "$1".', + 'errRename' : 'Impossible de renommer "$1".', + 'errCopyFrom' : 'Interdiction de copier des fichiers depuis le volume "$1".', + 'errCopyTo' : 'Interdiction de copier des fichiers vers le volume "$1".', + 'errMkOutLink' : 'Impossible de créer un lien en dehors du volume principal.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Erreur lors de l\'envoi du fichier.', // old name - errUploadCommon + 'errUploadFile' : 'Impossible d\'envoyer "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Aucun fichier à envoyer.', + 'errUploadTotalSize' : 'Les données dépassent la taille maximale allouée.', // old name - errMaxSize + 'errUploadFileSize' : 'Le fichier dépasse la taille maximale allouée.', // old name - errFileMaxSize + 'errUploadMime' : 'Type de fichier non autorisé.', + 'errUploadTransfer' : '"$1" erreur de transfert.', + 'errUploadTemp' : 'Impossible de créer un fichier temporaire pour transférer les fichiers.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'L\'objet "$1" existe déjà à cet endroit et ne peut être remplacé par un objet d\'un type différent.', // new + 'errReplace' : 'Impossible de remplacer "$1".', + 'errSave' : 'Impossible de sauvegarder "$1".', + 'errCopy' : 'Impossible de copier "$1".', + 'errMove' : 'Impossible de déplacer "$1".', + 'errCopyInItself' : 'Impossible de copier "$1" sur lui-même.', + 'errRm' : 'Impossible de supprimer "$1".', + 'errTrash' : 'Impossible de déplacer dans la corbeille', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Impossible de supprimer le(s) fichier(s) source(s).', + 'errExtract' : 'Imbossible d\'extraire les fichiers à partir de "$1".', + 'errArchive' : 'Impossible de créer l\'archive.', + 'errArcType' : 'Type d\'archive non supporté.', + 'errNoArchive' : 'Le fichier n\'est pas une archive, ou c\'est un type d\'archive non supporté.', + 'errCmdNoSupport' : 'Le Backend ne prend pas en charge cette commande.', + 'errReplByChild' : 'Le dossier “$1” ne peut pas être remplacé par un élément qu\'il contient.', + 'errArcSymlinks' : 'Par mesure de sécurité, il est défendu d\'extraire une archive contenant des liens symboliques ou des noms de fichier non autorisés.', // edited 24.06.2012 + 'errArcMaxSize' : 'Les fichiers de l\'archive excèdent la taille maximale autorisée.', + 'errResize' : 'Impossible de redimensionner "$1".', + 'errResizeDegree' : 'Degré de rotation invalide.', // added 7.3.2013 + 'errResizeRotate' : 'L\'image ne peut pas être tournée.', // added 7.3.2013 + 'errResizeSize' : 'Dimension de l\'image non-valide.', // added 7.3.2013 + 'errResizeNoChange' : 'L\'image n\'est pas redimensionnable.', // added 7.3.2013 + 'errUsupportType' : 'Type de fichier non supporté.', + 'errNotUTF8Content' : 'Le fichier "$1" n\'est pas en UTF-8, il ne peut être édité.', // added 9.11.2011 + 'errNetMount' : 'Impossible de monter "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protocole non supporté.', // added 17.04.2012 + 'errNetMountFailed' : 'Echec du montage.', // added 17.04.2012 + 'errNetMountHostReq' : 'Hôte requis.', // added 18.04.2012 + 'errSessionExpires' : 'Votre session a expiré en raison de son inactivité.', + 'errCreatingTempDir' : 'Impossible de créer le répertoire temporaire : "$1"', + 'errFtpDownloadFile' : 'Impossible de télécharger le file depuis l\'accès FTP : "$1"', + 'errFtpUploadFile' : 'Impossible d\'envoyer le fichier vers l\'accès FTP : "$1"', + 'errFtpMkdir' : 'Impossible de créer un répertoire distant sur l\'accès FTP :"$1"', + 'errArchiveExec' : 'Erreur lors de l\'archivage des fichiers : "$1"', + 'errExtractExec' : 'Erreur lors de l\'extraction des fichiers : "$1"', + 'errNetUnMount' : 'Impossible de démonter.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Conversion en UTF-8 impossible', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Essayez Google Chrome, si voulez envoyer le dossier.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Délai d’attente dépassé pour la recherche "$1". Le résultat de la recherche est partiel.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Réauthorisation requise.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Le nombre maximal d\'éléments pouvant être sélectionnés est $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Impossible de restaurer la corbeille. La destination de la restauration n\'a pu être identifiée.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Aucun éditeur n\'a été trouvé pour ce type de fichier.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Une erreur est survenue du côté serveur.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Impossible de vider le dossier "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Il y a encore $1 erreur(s).', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'Vous ne pouvez créer que $1 dossier au même moment.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Créer une archive', + 'cmdback' : 'Précédent', + 'cmdcopy' : 'Copier', + 'cmdcut' : 'Couper', + 'cmddownload' : 'Télécharger', + 'cmdduplicate' : 'Dupliquer', + 'cmdedit' : 'Éditer le fichier', + 'cmdextract' : 'Extraire les fichiers de l\'archive', + 'cmdforward' : 'Suivant', + 'cmdgetfile' : 'Sélectionner les fichiers', + 'cmdhelp' : 'À propos de ce logiciel', + 'cmdhome' : 'Accueil', + 'cmdinfo' : 'Informations', + 'cmdmkdir' : 'Nouveau dossier', + 'cmdmkdirin' : 'Dans un nouveau dossier', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nouveau fichier', + 'cmdopen' : 'Ouvrir', + 'cmdpaste' : 'Coller', + 'cmdquicklook' : 'Prévisualiser', + 'cmdreload' : 'Actualiser', + 'cmdrename' : 'Renommer', + 'cmdrm' : 'Supprimer', + 'cmdtrash' : 'À la corbeille', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Restaurer', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Trouver les fichiers', + 'cmdup' : 'Remonter au dossier parent', + 'cmdupload' : 'Envoyer les fichiers', + 'cmdview' : 'Vue', + 'cmdresize' : 'Redimensionner l\'image', + 'cmdsort' : 'Trier', + 'cmdnetmount' : 'Monter un volume réseau', // added 18.04.2012 + 'cmdnetunmount': 'Démonter', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Vers Favoris', // added 28.12.2014 + 'cmdchmod' : 'Changer de mode', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Ouvrir un dossier', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Réinitialiser largeur colone', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Plein écran', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Déplacer', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Vider le dossier', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Annuler', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Refaire', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Préférences', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Tout sélectionner', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Tout désélectionner', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Inverser la sélection', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Ouvrir dans une nouvelle fenêtre', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Cacher (Préférence)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Fermer', + 'btnSave' : 'Enregistrer', + 'btnRm' : 'Supprimer', + 'btnApply' : 'Appliquer', + 'btnCancel' : 'Annuler', + 'btnNo' : 'Non', + 'btnYes' : 'Oui', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Monter', // added 18.04.2012 + 'btnApprove': 'Aller à $1 & approuver', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Démonter', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convertir', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Ici', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'Tous', // from v2.1 added 22.5.2015 + 'btnMime' : 'Type MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nom du fichier', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Sauvegarder & Fermer', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Sauvegarde', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Renommer', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Renommer (tous)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Préc. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Suiv. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Sauvegarder sous', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Ouvrir le dossier', + 'ntffile' : 'Ouvrir le fichier', + 'ntfreload' : 'Actualiser le contenu du dossier', + 'ntfmkdir' : 'Création du dossier', + 'ntfmkfile' : 'Création des fichiers', + 'ntfrm' : 'Supprimer les éléments', + 'ntfcopy' : 'Copier les éléments', + 'ntfmove' : 'Déplacer les éléments', + 'ntfprepare' : 'Préparation de la copie des éléments', + 'ntfrename' : 'Renommer les fichiers', + 'ntfupload' : 'Envoi des fichiers', + 'ntfdownload' : 'Téléchargement des fichiers', + 'ntfsave' : 'Sauvegarder les fichiers', + 'ntfarchive' : 'Création de l\'archive', + 'ntfextract' : 'Extraction des fichiers de l\'archive', + 'ntfsearch' : 'Recherche des fichiers', + 'ntfresize' : 'Redimensionner les images', + 'ntfsmth' : 'Fait quelque chose', + 'ntfloadimg' : 'Chargement de l\'image', + 'ntfnetmount' : 'Monte le volume réseau', // added 18.04.2012 + 'ntfnetunmount': 'Démonte le volume réseau', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Calcule la dimension de l\'image', // added 20.05.2013 + 'ntfreaddir' : 'Lecture des informations du dossier', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Récupération de l’URL du lien', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Changement de mode', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Vérification du nom du fichier envoyé', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Création d’un fichier pour le téléchargement', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Traitement de l\'information du chemin', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Traitement du fichier envoyé', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Mettre à la corbeille', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Restaurer depuis la corbeille', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Validation du dossier de destination', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Annuler l\'opération précédente', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Refaire l\'opération annulée', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Vérification du contenu', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Corbeille', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Inconnue', + 'Today' : 'Aujourd\'hui', + 'Yesterday' : 'Hier', + 'msJan' : 'Jan', + 'msFeb' : 'Fév', + 'msMar' : 'Mar', + 'msApr' : 'Avr', + 'msMay' : 'Mai', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aoû', + 'msSep' : 'Sep', + 'msOct' : 'Oct', + 'msNov' : 'Nov', + 'msDec' : 'Déc', + 'January' : 'Janvier', + 'February' : 'Février', + 'March' : 'Mars', + 'April' : 'Avril', + 'May' : 'Mai', + 'June' : 'Juin', + 'July' : 'Juillet', + 'August' : 'Août', + 'September' : 'Septembre', + 'October' : 'Octobre', + 'November' : 'Novembre', + 'December' : 'Décembre', + 'Sunday' : 'Dimanche', + 'Monday' : 'Lundi', + 'Tuesday' : 'Mardi', + 'Wednesday' : 'Mercredi', + 'Thursday' : 'Jeudi', + 'Friday' : 'Vendredi', + 'Saturday' : 'Samedi', + 'Sun' : 'Dim', + 'Mon' : 'Lun', + 'Tue' : 'Mar', + 'Wed' : 'Mer', + 'Thu' : 'Jeu', + 'Fri' : 'Ven', + 'Sat' : 'Sam', + + /******************************** sort variants ********************************/ + 'sortname' : 'par nom', + 'sortkind' : 'par type', + 'sortsize' : 'par taille', + 'sortdate' : 'par date', + 'sortFoldersFirst' : 'Dossiers en premier', + 'sortperm' : 'par permission', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'par mode', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'par propriétaire', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'par groupe', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Egalement arborescence', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NouveauFichier.txt', // added 10.11.2015 + 'untitled folder' : 'NouveauDossier', // added 10.11.2015 + 'Archive' : 'NouvelleArchive', // from v2.1 added 10.11.2015 + 'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: Fichier', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Confirmation requise', + 'confirmRm' : 'Êtes-vous certain de vouloir supprimer les éléments ?
                      Cela ne peut être annulé !', + 'confirmRepl' : 'Remplacer l\'ancien fichier par le nouveau ?', + 'confirmRest' : 'Remplacer l\'élément existant par l\'élément de la corbeille ?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'L\'encodage n\'est pas UTf-8
                      Convertir en UTF-8 ?
                      Les contenus deviendront UTF-8 en sauvegardant après la conversion.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Impossible de détecter l\'encodage de ce fichier. Pour être modifié, il doit être temporairement convertit en UTF-8.
                      Veuillez s\'il vous plaît sélectionner un encodage pour ce fichier.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Ce fichier a été modifié.
                      Les données seront perdues si les changements ne sont pas sauvegardés.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Êtes-vous certain de vouloir déplacer les éléments vers la corbeille?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Etes-vous sûr de vouloir déplacer ces éléments vers "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Appliquer à tous', + 'name' : 'Nom', + 'size' : 'Taille', + 'perms' : 'Permissions', + 'modify' : 'Modifié', + 'kind' : 'Type', + 'read' : 'Lecture', + 'write' : 'Écriture', + 'noaccess' : 'Pas d\'accès', + 'and' : 'et', + 'unknown' : 'inconnu', + 'selectall' : 'Sélectionner tous les éléments', + 'selectfiles' : 'Sélectionner le(s) élément(s)', + 'selectffile' : 'Sélectionner le premier élément', + 'selectlfile' : 'Sélectionner le dernier élément', + 'viewlist' : 'Vue par liste', + 'viewicons' : 'Vue par icônes', + 'viewSmall' : 'Petites icônes', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Moyennes icônes', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Grandes icônes', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Très grandes icônes', // from v2.1.39 added 22.5.2018 + 'places' : 'Favoris', + 'calc' : 'Calculer', + 'path' : 'Chemin', + 'aliasfor' : 'Raccourcis pour', + 'locked' : 'Verrouiller', + 'dim' : 'Dimensions', + 'files' : 'Fichiers', + 'folders' : 'Dossiers', + 'items' : 'Éléments', + 'yes' : 'oui', + 'no' : 'non', + 'link' : 'Lien', + 'searcresult' : 'Résultats de la recherche', + 'selected' : 'Éléments sélectionnés', + 'about' : 'À propos', + 'shortcuts' : 'Raccourcis', + 'help' : 'Aide', + 'webfm' : 'Gestionnaire de fichier Web', + 'ver' : 'Version', + 'protocolver' : 'Version du protocole', + 'homepage' : 'Page du projet', + 'docs' : 'Documentation', + 'github' : 'Forkez-nous sur Github', + 'twitter' : 'Suivez nous sur Twitter', + 'facebook' : 'Joignez-nous sur Facebook', + 'team' : 'Équipe', + 'chiefdev' : 'Développeur en chef', + 'developer' : 'Développeur', + 'contributor' : 'Contributeur', + 'maintainer' : 'Mainteneur', + 'translator' : 'Traducteur', + 'icons' : 'Icônes', + 'dontforget' : 'et n\'oubliez pas votre serviette', + 'shortcutsof' : 'Raccourcis désactivés', + 'dropFiles' : 'Déposez les fichiers ici', + 'or' : 'ou', + 'selectForUpload' : 'Sélectionner les fichiers à envoyer', + 'moveFiles' : 'Déplacer les éléments', + 'copyFiles' : 'Copier les éléments', + 'restoreFiles' : 'Restaurer les éléments', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Retirer des favoris', + 'aspectRatio' : 'Ratio d’affichage', + 'scale' : 'Mise à l\'échelle', + 'width' : 'Largeur', + 'height' : 'Hauteur', + 'resize' : 'Redimensionner', + 'crop' : 'Recadrer', + 'rotate' : 'Rotation', + 'rotate-cw' : 'Rotation de 90 degrés horaire', + 'rotate-ccw' : 'Rotation de 90 degrés antihoraire', + 'degree' : '°', + 'netMountDialogTitle' : 'Monter un volume réseau', // added 18.04.2012 + 'protocol' : 'Protocole', // added 18.04.2012 + 'host' : 'Hôte', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Utilisateur', // added 18.04.2012 + 'pass' : 'Mot de passe', // added 18.04.2012 + 'confirmUnmount' : 'Démonter $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Glissez-déposez depuis le navigateur de fichier', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Glissez-déposez les fichiers ici', // from v2.1 added 07.04.2014 + 'encoding' : 'Encodage', // from v2.1 added 19.12.2014 + 'locale' : 'Encodage régional', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Destination: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Recherche par type MIME', // from v2.1 added 22.5.2015 + 'owner' : 'Propriétaire', // from v2.1 added 20.6.2015 + 'group' : 'Groupe', // from v2.1 added 20.6.2015 + 'other' : 'Autre', // from v2.1 added 20.6.2015 + 'execute' : 'Exécuter', // from v2.1 added 20.6.2015 + 'perm' : 'Permission', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Le dossier est vide', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Le dossier est vide.\\ Glissez-déposez pour ajouter des éléments.', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Le dossier est vide.\\ Appuyez longuement pour ajouter des éléments.', // from v2.1.6 added 30.12.2015 + 'quality' : 'Qualité', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Synchronisation automatique', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Déplacer vers le haut', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Obtenir le lien d’URL', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Éléments sélectionnés ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID du dossier', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Permettre l\'accès hors-ligne', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Pour se réauthentifier', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'En cours de chargement...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Ouvrir multiples fichiers', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Vous allez ouvrir $1 fichiers. Êtes-vous sûr de vouloir les ouvrir dans le navigateur ?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Aucun résultat trouvé avec les paramètres de recherche.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Modification d\'un fichier.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Vous avez sélectionné $1 éléments.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Vous avez $1 éléments dans le presse-papier.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Recherche incrémentale disponible uniquement pour la vue active.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Rétablir', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 complété', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Menu contextuel', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Tourner la page', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volumes principaux', // from v2.1.16 added 16.9.2016 + 'reset' : 'Réinitialiser', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Couleur de fond', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Sélecteur de couleur', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'Grille 8px', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Actif', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Inactif', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Aucun résultat trouvé.\\Appuyez sur [Entrée] pour développer la cible de recherche.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Aucun résultat trouvé pour la recherche par première lettre.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Label texte', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 mins restantes', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Réouvrir avec l\'encodage sélectionné', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Sauvegarder avec l\'encodage sélectionné', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Choisir le dossier', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Recherche par première lettre', // from v2.1.23 added 24.3.2017 + 'presets' : 'Présélections', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Impossible de mettre autant d\'éléments à la corbeille.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Zone de texte', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Vider le dossier "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Il n\'y a pas d\'élément dans le dossier "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Préférences', // from v2.1.26 added 28.6.2017 + 'language' : 'Configuration de langue', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialisation des configurations sauvegardées dans ce navigateur', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Paramètres de la barre d\'outils', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 caractère(s) restant(s).', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 ligne(s) restante(s).', // from v2.1.52 added 16.1.2020 + 'sum' : 'Somme', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Taille de fichier brute', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Concentrez-vous sur l\'élément de dialogue avec le survol de la souris', // from v2.1.30 added 2.11.2017 + 'select' : 'Sélectionner', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Action lors de la sélection d\'un fichier', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Ouvrir avec le dernier éditeur utilisé', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Inverser la sélection', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Êtes-vous sûr de vouloir renommer les éléments sélectionnés $1 en $2 ?
                      L\'action est définitive !', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Renommer le Batch', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Nombre', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Ajouter un préfixe', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Ajouter un suffixe', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Modifier l\'extention', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Paramètres des colonnes (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Les changements seront immédiatement appliqués à l\'archive.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Aucun changement ne sera appliqué tant que ce volume n\'a pas été démonté.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Le(s) volume(s) suivant(s) montés sur ce volume seront également démontés. Êtes-vous sûr de vouloir le démonter ?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Informations sur la sélection', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorithme de hachage de fichier', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Éléments d\'information (panneau de sélection d\'informations )', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Appuyez à nouveau pour quitter.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Barre d\'outils', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Espace de travail', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialogue', // from v2.1.38 added 4.4.2018 + 'all' : 'Tout', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Dimensions de l\'icône (Aperçu)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Ouvrir la fenêtre d\'édition à la taille maximale', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Étant donné que la conversion par API n\'est pas disponible actuellement, veuillez effectuer la conversion sur le site Web.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Après la conversion, vous devez ajouter l\'URL de l\'élément ou un fichier téléchargé pour enregistrer le fichier converti.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Convertir sur le site de $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Intégrations', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Cet elFinder intègre les services externes suivants. Veuillez vérifier les conditions d\'utilisation, la politique de confidentialité, etc. avant de l\'utiliser.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Afficher les élément cachés', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Ne pas afficher les élément cachés', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Afficher/Cacher les éléments cachés', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Type de ficher autorisé avec "Nouveau fichier"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type du fichier de texte', // from v2.1.41 added 7.8.2018 + 'add' : 'Ajouter', // from v2.1.41 added 7.8.2018 + 'theme' : 'Thème', // from v2.1.43 added 19.10.2018 + 'default' : 'Par Défaut', // from v2.1.43 added 19.10.2018 + 'description' : 'Description', // from v2.1.43 added 19.10.2018 + 'website' : 'Site Web', // from v2.1.43 added 19.10.2018 + 'author' : 'Aauteur', // from v2.1.43 added 19.10.2018 + 'email' : 'E-mail', // from v2.1.43 added 19.10.2018 + 'license' : 'License', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Cet élément ne peut être enregistrer. Pour éviter de perdre les modifications, vous devez exporter vers votre ordinateur.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Double-cliquez sur le fichier pour le sélectionner.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Utiliser le mode plein écran', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Inconnu', + 'kindRoot' : 'Volume principal', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Dossier', + 'kindSelects' : 'Sélections', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Raccourci', + 'kindAliasBroken' : 'Raccourci cassé', + // applications + 'kindApp' : 'Application', + 'kindPostscript' : 'Document Postscript', + 'kindMsOffice' : 'Document Microsoft Office', + 'kindMsWord' : 'Document Microsoft Word', + 'kindMsExcel' : 'Document Microsoft Excel', + 'kindMsPP' : 'Présentation Microsoft PowerPoint', + 'kindOO' : 'Document OpenOffice', + 'kindAppFlash' : 'Application Flash', + 'kindPDF' : 'Format de document portable (PDF)', + 'kindTorrent' : 'Fichier BitTorrent', + 'kind7z' : 'Archive 7z', + 'kindTAR' : 'Archive TAR', + 'kindGZIP' : 'Archive GZIP', + 'kindBZIP' : 'Archive BZIP', + 'kindXZ' : 'Archive XZ', + 'kindZIP' : 'Archive ZIP', + 'kindRAR' : 'Archive RAR', + 'kindJAR' : 'Fichier Java JAR', + 'kindTTF' : 'Police True Type', + 'kindOTF' : 'Police Open Type', + 'kindRPM' : 'Package RPM', + // fonts + 'kindFont' : 'Police', + 'kindSFNT' : 'Police font', + 'kindEOT' : 'Police Embedded Open Type', + 'kindWOFF' : 'Police Web Open Font Format', + 'kindWOFF2' : 'Police Web Open Font Format 2', + // texts + 'kindText' : 'Document Text', + 'kindTextPlain' : 'Texte non formaté', + 'kindPHP' : 'Source PHP', + 'kindCSS' : 'Feuille de style en cascade', + 'kindHTML' : 'Document HTML', + 'kindJS' : 'Source JavaScript', + 'kindRTF' : 'Format de texte enrichi (Rich Text Format)', + 'kindC' : 'Source C', + 'kindCHeader' : 'Source header C', + 'kindCPP' : 'Source C++', + 'kindCPPHeader' : 'Source header C++', + 'kindShell' : 'Shell script Unix', + 'kindPython' : 'Source Python', + 'kindJava' : 'Source Java', + 'kindRuby' : 'Source Ruby', + 'kindPerl' : 'Script Perl', + 'kindSQL' : 'Source SQL', + 'kindXML' : 'Document XML', + 'kindAWK' : 'Source AWK', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Document Docbook XML', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Image', + 'kindBMP' : 'Image BMP', + 'kindJPEG' : 'Image JPEG', + 'kindGIF' : 'Image GIF', + 'kindPNG' : 'Image PNG', + 'kindTIFF' : 'Image TIFF', + 'kindTGA' : 'Image TGA', + 'kindPSD' : 'Image Adobe Photoshop', + 'kindXBITMAP' : 'Image X bitmap', + 'kindPXM' : 'Image Pixelmator', + // media + 'kindAudio' : 'Son', + 'kindAudioMPEG' : 'Son MPEG', + 'kindAudioMPEG4' : 'Son MPEG-4', + 'kindAudioMIDI' : 'Son MIDI', + 'kindAudioOGG' : 'Son Ogg Vorbis', + 'kindAudioWAV' : 'Son WAV', + 'AudioPlaylist' : 'Liste de lecture audio', + 'kindVideo' : 'Vidéo', + 'kindVideoDV' : 'Vidéo DV', + 'kindVideoMPEG' : 'Vidéo MPEG', + 'kindVideoMPEG4' : 'Vidéo MPEG-4', + 'kindVideoAVI' : 'Vidéo AVI', + 'kindVideoMOV' : 'Vidéo Quick Time', + 'kindVideoWM' : 'Vidéo Windows Media', + 'kindVideoFlash' : 'Vidéo Flash', + 'kindVideoMKV' : 'Vidéo Matroska', + 'kindVideoOGG' : 'Vidéo Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.fr_CA.js b/lib/redactor/elfinder/js/i18n/elfinder.fr_CA.js new file mode 100644 index 0000000..6c46120 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.fr_CA.js @@ -0,0 +1,587 @@ +/** + * Traduction canadienne française (identique à la traduction française) + * @author Régis Guyomarch + * @author Benoit Delachaux + * @author Jonathan Grunder + * @version 2019-10-15 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.fr_CA = { + translator : 'Régis Guyomarch <regisg@gmail.com>, Benoit Delachaux <benorde33@gmail.com>, Jonathan Grunder <jonathan.grunder@gmail.com>', + language : 'française', + direction : 'ltr', + dateFormat : 'd/M/Y H:i', // will show like: 15/Oct/2019 14:47 + fancyDateFormat : '$1 H:i', // will show like: Aujourd'hui 14:47 + nonameDateFormat : 'ymd-His', // noname upload will show like: 191015-144704 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Erreur', + 'errUnknown' : 'Erreur inconnue.', + 'errUnknownCmd' : 'Commande inconnue.', + 'errJqui' : 'Mauvaise configuration de jQuery UI. Les composants Selectable, draggable et droppable doivent être inclus.', + 'errNode' : 'elFinder requiert que l\'élément DOM ait été créé.', + 'errURL' : 'Mauvaise configuration d\'elFinder ! L\'option URL n\'a pas été définie.', + 'errAccess' : 'Accès refusé.', + 'errConnect' : 'Impossible de se connecter au backend.', + 'errAbort' : 'Connexion interrompue.', + 'errTimeout' : 'Délai de connexion dépassé.', + 'errNotFound' : 'Backend non trouvé.', + 'errResponse' : 'Mauvaise réponse du backend.', + 'errConf' : 'Mauvaise configuration du backend.', + 'errJSON' : 'Le module PHP JSON n\'est pas installé.', + 'errNoVolumes' : 'Aucun volume lisible.', + 'errCmdParams' : 'Mauvais paramétrage de la commande "$1".', + 'errDataNotJSON' : 'Les données ne sont pas au format JSON.', + 'errDataEmpty' : 'Données inexistantes.', + 'errCmdReq' : 'La requête au Backend doit comporter le nom de la commande.', + 'errOpen' : 'Impossible d\'ouvrir "$1".', + 'errNotFolder' : 'Cet objet n\'est pas un dossier.', + 'errNotFile' : 'Cet objet n\'est pas un fichier.', + 'errRead' : 'Impossible de lire "$1".', + 'errWrite' : 'Impossible d\'écrire dans "$1".', + 'errPerm' : 'Permission refusée.', + 'errLocked' : '"$1" est verrouillé et ne peut être déplacé ou supprimé.', + 'errExists' : 'Un élément nommé "$1" existe déjà.', + 'errInvName' : 'Nom de fichier incorrect.', + 'errInvDirname' : 'Nom de dossier incorrect.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Dossier non trouvé.', + 'errFileNotFound' : 'Fichier non trouvé.', + 'errTrgFolderNotFound' : 'Dossier destination "$1" non trouvé.', + 'errPopup' : 'Le navigateur web a empêché l\'ouverture d\'une fenêtre "popup". Pour ouvrir le fichier, modifiez les options du navigateur web.', + 'errMkdir' : 'Impossible de créer le dossier "$1".', + 'errMkfile' : 'Impossible de créer le fichier "$1".', + 'errRename' : 'Impossible de renommer "$1".', + 'errCopyFrom' : 'Interdiction de copier des fichiers depuis le volume "$1".', + 'errCopyTo' : 'Interdiction de copier des fichiers vers le volume "$1".', + 'errMkOutLink' : 'Impossible de créer un lien en dehors du volume principal.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Erreur lors de l\'envoi du fichier.', // old name - errUploadCommon + 'errUploadFile' : 'Impossible d\'envoyer "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Aucun fichier à envoyer.', + 'errUploadTotalSize' : 'Les données dépassent la taille maximale allouée.', // old name - errMaxSize + 'errUploadFileSize' : 'Le fichier dépasse la taille maximale allouée.', // old name - errFileMaxSize + 'errUploadMime' : 'Type de fichier non autorisé.', + 'errUploadTransfer' : '"$1" erreur transfert.', + 'errUploadTemp' : 'Impossible de créer un fichier temporaire pour transférer les fichiers.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'L\'objet "$1" existe déjà à cet endroit et ne peut être remplacé par un objet d\'un type différent.', // new + 'errReplace' : 'Impossible de remplacer "$1".', + 'errSave' : 'Impossible de sauvegarder "$1".', + 'errCopy' : 'Impossible de copier "$1".', + 'errMove' : 'Impossible de déplacer "$1".', + 'errCopyInItself' : 'Impossible de copier "$1" sur lui-même.', + 'errRm' : 'Impossible de supprimer "$1".', + 'errTrash' : 'Impossible de déplacer dans la corbeille', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Impossible de supprimer le(s) fichier(s) source(s).', + 'errExtract' : 'Imbossible d\'extraire les fichiers à partir de "$1".', + 'errArchive' : 'Impossible de créer l\'archive.', + 'errArcType' : 'Type d\'archive non supporté.', + 'errNoArchive' : 'Le fichier n\'est pas une archive, ou c\'est un type d\'archive non supporté.', + 'errCmdNoSupport' : 'Le Backend ne prend pas en charge cette commande.', + 'errReplByChild' : 'Le dossier “$1” ne peut pas être remplacé par un élément qu\'il contient.', + 'errArcSymlinks' : 'Par mesure de sécurité, il est défendu d\'extraire une archive contenant des liens symboliques ou des noms de fichier non autorisés.', // edited 24.06.2012 + 'errArcMaxSize' : 'Les fichiers de l\'archive excèdent la taille maximale autorisée.', + 'errResize' : 'Impossible de redimensionner "$1".', + 'errResizeDegree' : 'Degré de rotation invalide.', // added 7.3.2013 + 'errResizeRotate' : 'L\'image ne peut pas être tournée.', // added 7.3.2013 + 'errResizeSize' : 'Dimension de l\'image non-valide.', // added 7.3.2013 + 'errResizeNoChange' : 'L\'image n\'est pas redimensionnable.', // added 7.3.2013 + 'errUsupportType' : 'Type de fichier non supporté.', + 'errNotUTF8Content' : 'Le fichier "$1" n\'est pas en UTF-8, il ne peut être édité.', // added 9.11.2011 + 'errNetMount' : 'Impossible de monter "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protocole non supporté.', // added 17.04.2012 + 'errNetMountFailed' : 'Echec du montage.', // added 17.04.2012 + 'errNetMountHostReq' : 'Hôte requis.', // added 18.04.2012 + 'errSessionExpires' : 'Votre session a expiré en raison de son inactivité.', + 'errCreatingTempDir' : 'Impossible de créer le répertoire temporaire : "$1"', + 'errFtpDownloadFile' : 'Impossible de télécharger le file depuis l\'accès FTP : "$1"', + 'errFtpUploadFile' : 'Impossible d\'envoyer le fichier vers l\'accès FTP : "$1"', + 'errFtpMkdir' : 'Impossible de créer un répertoire distant sur l\'accès FTP :"$1"', + 'errArchiveExec' : 'Erreur lors de l\'archivage des fichiers : "$1"', + 'errExtractExec' : 'Erreur lors de l\'extraction des fichiers : "$1"', + 'errNetUnMount' : 'Impossible de démonter.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Conversion en UTF-8 impossible', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Essayez Google Chrome, si voulez envoyer le dossier.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Délai d’attente dépassé pour la recherche "$1". Le résultat de la recherche est partiel.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Réauthorisation requise.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Le nombre maximal d\'éléments pouvant être sélectionnés est $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Impossible de restaurer la corbeille. La destination de la restauration n\'a pu être identifiée.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Aucun éditeur n\'a été trouvé pour ce type de fichier.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Une erreur est survenue du côté serveur.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Impossible de vider le dossier "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'There are $1 more errors.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Créer une archive', + 'cmdback' : 'Précédent', + 'cmdcopy' : 'Copier', + 'cmdcut' : 'Couper', + 'cmddownload' : 'Télécharger', + 'cmdduplicate' : 'Dupliquer', + 'cmdedit' : 'Éditer le fichier', + 'cmdextract' : 'Extraire les fichiers de l\'archive', + 'cmdforward' : 'Suivant', + 'cmdgetfile' : 'Sélectionner les fichiers', + 'cmdhelp' : 'À propos de ce logiciel', + 'cmdhome' : 'Accueil', + 'cmdinfo' : 'Informations', + 'cmdmkdir' : 'Nouveau dossier', + 'cmdmkdirin' : 'Dans un nouveau dossier', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nouveau fichier', + 'cmdopen' : 'Ouvrir', + 'cmdpaste' : 'Coller', + 'cmdquicklook' : 'Prévisualiser', + 'cmdreload' : 'Actualiser', + 'cmdrename' : 'Renommer', + 'cmdrm' : 'Supprimer', + 'cmdtrash' : 'À la corbeille', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Restaurer', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Trouver les fichiers', + 'cmdup' : 'Remonter au dossier parent', + 'cmdupload' : 'Envoyer les fichiers', + 'cmdview' : 'Vue', + 'cmdresize' : 'Redimensionner l\'image', + 'cmdsort' : 'Trier', + 'cmdnetmount' : 'Monter un volume réseau', // added 18.04.2012 + 'cmdnetunmount': 'Démonter', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Vers Favoris', // added 28.12.2014 + 'cmdchmod' : 'Changer de mode', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Ouvrir un dossier', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Réinitialiser largeur colone', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Plein écran', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Déplacer', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Vider le dossier', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Annuler', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Refaire', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Préférences', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Tout sélectionner', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Tout désélectionner', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Inverser la sélection', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Ouvrir dans une nouvelle fenêtre', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Hide (Preference)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Fermer', + 'btnSave' : 'Sauvegarder', + 'btnRm' : 'Supprimer', + 'btnApply' : 'Confirmer', + 'btnCancel' : 'Annuler', + 'btnNo' : 'Non', + 'btnYes' : 'Oui', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Monter', // added 18.04.2012 + 'btnApprove': 'Aller à $1 & approuver', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Démonter', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convertir', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Ici', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'Tous', // from v2.1 added 22.5.2015 + 'btnMime' : 'Type MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nom du fichier', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Enregistrer & Ferme', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Sauvegarde', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Renommer', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Renommer (tous)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Préc. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Suiv. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Sauvegarder sous', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Ouvrir le dossier', + 'ntffile' : 'Ouvrir le fichier', + 'ntfreload' : 'Actualiser le contenu du dossier', + 'ntfmkdir' : 'Création du dossier', + 'ntfmkfile' : 'Création des fichiers', + 'ntfrm' : 'Supprimer les éléments', + 'ntfcopy' : 'Copier les éléments', + 'ntfmove' : 'Déplacer les éléments', + 'ntfprepare' : 'Préparation de la copie des éléments', + 'ntfrename' : 'Renommer les fichiers', + 'ntfupload' : 'Envoi des fichiers', + 'ntfdownload' : 'Téléchargement des fichiers', + 'ntfsave' : 'Sauvegarder les fichiers', + 'ntfarchive' : 'Création de l\'archive', + 'ntfextract' : 'Extraction des fichiers de l\'archive', + 'ntfsearch' : 'Recherche des fichiers', + 'ntfresize' : 'Redimensionner les images', + 'ntfsmth' : 'Fait quelque chose', + 'ntfloadimg' : 'Chargement de l\'image', + 'ntfnetmount' : 'Monte le volume réseau', // added 18.04.2012 + 'ntfnetunmount': 'Démonte le volume réseau', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Calcule la dimension de l\'image', // added 20.05.2013 + 'ntfreaddir' : 'Lecture des informations du dossier', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Récupération de l’URL du lien', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Changement de mode', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Vérification du nom du fichier envoyé', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Création d’un fichier pour le téléchargement', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Traitement de l\'information du chemin', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Traitement du fichier envoyé', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Mettre à la corbeille', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Restaurer depuis la corbeille', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Validation du dossier de destination', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Annuler l\'opération précédente', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Refaire l\'opération annulée', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Checking contents', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Corbeille', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Inconnue', + 'Today' : 'Aujourd\'hui', + 'Yesterday' : 'Hier', + 'msJan' : 'Jan', + 'msFeb' : 'Fév', + 'msMar' : 'Mar', + 'msApr' : 'Avr', + 'msMay' : 'Mai', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aoû', + 'msSep' : 'Sep', + 'msOct' : 'Oct', + 'msNov' : 'Nov', + 'msDec' : 'Déc', + 'January' : 'Janvier', + 'February' : 'Février', + 'March' : 'Mars', + 'April' : 'Avril', + 'May' : 'Mai', + 'June' : 'Juin', + 'July' : 'Huillet', + 'August' : 'Août', + 'September' : 'Septembre', + 'October' : 'Octobre', + 'November' : 'Novembre', + 'December' : 'Décembre', + 'Sunday' : 'Dimanche', + 'Monday' : 'Lundi', + 'Tuesday' : 'Mardi', + 'Wednesday' : 'Mercredi', + 'Thursday' : 'Jeudi', + 'Friday' : 'Vendredi', + 'Saturday' : 'Samedi', + 'Sun' : 'Dim', + 'Mon' : 'Lun', + 'Tue' : 'Mar', + 'Wed' : 'Mer', + 'Thu' : 'Jeu', + 'Fri' : 'Ven', + 'Sat' : 'Sam', + + /******************************** sort variants ********************************/ + 'sortname' : 'par nom', + 'sortkind' : 'par type', + 'sortsize' : 'par taille', + 'sortdate' : 'par date', + 'sortFoldersFirst' : 'Dossiers en premier', + 'sortperm' : 'par permission', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'par mode', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'par propriétaire', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'par groupe', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Egalement arborescence', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NouveauFichier.txt', // added 10.11.2015 + 'untitled folder' : 'NouveauDossier', // added 10.11.2015 + 'Archive' : 'NouvelleArchive', // from v2.1 added 10.11.2015 + 'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: File', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Confirmation requise', + 'confirmRm' : 'Êtes-vous certain de vouloir supprimer les éléments ?
                      Cela ne peut être annulé !', + 'confirmRepl' : 'Supprimer l\'ancien fichier par le nouveau ?', + 'confirmRest' : 'Remplacer l\'élément existant par l\'élément de la corbeille ?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'L\'encodage n\'est pas UTf-8
                      Convertir en UTF-8 ?
                      Les contenus deviendront UTF-8 en sauvegardant après la conversion.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Impossible de détecter l\'encodage de ce fichier. Pour être modifié, il doit être temporairement convertit en UTF-8.
                      Veuillez s\'il vous plaît sélectionner un encodage pour ce fichier.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Ce fichier a été modifié.
                      Les données seront perdues si les changements ne sont pas sauvegardés.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Êtes-vous certain de vouloir déplacer les éléments vers la corbeille?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Are you sure you want to move items to "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Appliquer à tous', + 'name' : 'Nom', + 'size' : 'Taille', + 'perms' : 'Permissions', + 'modify' : 'Modifié', + 'kind' : 'Type', + 'read' : 'Lecture', + 'write' : 'Écriture', + 'noaccess' : 'Pas d\'accès', + 'and' : 'et', + 'unknown' : 'inconnu', + 'selectall' : 'Sélectionner tous les éléments', + 'selectfiles' : 'Sélectionner le(s) élément(s)', + 'selectffile' : 'Sélectionner le premier élément', + 'selectlfile' : 'Sélectionner le dernier élément', + 'viewlist' : 'Vue par liste', + 'viewicons' : 'Vue par icônes', + 'viewSmall' : 'Petites icônes', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Moyennes icônes', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Grandes icônes', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Très grandes icônes', // from v2.1.39 added 22.5.2018 + 'places' : 'Favoris', + 'calc' : 'Calculer', + 'path' : 'Chemin', + 'aliasfor' : 'Raccourcis pour', + 'locked' : 'Verrouiller', + 'dim' : 'Dimensions', + 'files' : 'Fichiers', + 'folders' : 'Dossiers', + 'items' : 'Éléments', + 'yes' : 'oui', + 'no' : 'non', + 'link' : 'Lien', + 'searcresult' : 'Résultats de la recherche', + 'selected' : 'Éléments sélectionnés', + 'about' : 'À propos', + 'shortcuts' : 'Raccourcis', + 'help' : 'Aide', + 'webfm' : 'Gestionnaire de fichier Web', + 'ver' : 'Version', + 'protocolver' : 'Version du protocole', + 'homepage' : 'Page du projet', + 'docs' : 'Documentation', + 'github' : 'Forkez-nous sur Github', + 'twitter' : 'Suivez nous sur twitter', + 'facebook' : 'Joignez-nous facebook', + 'team' : 'Équipe', + 'chiefdev' : 'Développeur en chef', + 'developer' : 'Développeur', + 'contributor' : 'Contributeur', + 'maintainer' : 'Mainteneur', + 'translator' : 'Traducteur', + 'icons' : 'Icônes', + 'dontforget' : 'et n\'oubliez pas votre serviette', + 'shortcutsof' : 'Raccourcis désactivés', + 'dropFiles' : 'Déposez les fichiers ici', + 'or' : 'ou', + 'selectForUpload' : 'Sélectionner les fichiers à envoyer', + 'moveFiles' : 'Déplacer les éléments', + 'copyFiles' : 'Copier les éléments', + 'restoreFiles' : 'Restaurer les éléments', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Retirer des favoris', + 'aspectRatio' : 'Ratio d’affichage', + 'scale' : 'Mise à l\'échelle', + 'width' : 'Largeur', + 'height' : 'Hauteur', + 'resize' : 'Redimensionner', + 'crop' : 'Recadrer', + 'rotate' : 'Rotation', + 'rotate-cw' : 'Rotation de 90 degrés horaire', + 'rotate-ccw' : 'Rotation de 90 degrés antihoraire', + 'degree' : '°', + 'netMountDialogTitle' : 'Monter un volume réseau', // added 18.04.2012 + 'protocol' : 'Protocole', // added 18.04.2012 + 'host' : 'Hôte', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Utilisateur', // added 18.04.2012 + 'pass' : 'Mot de passe', // added 18.04.2012 + 'confirmUnmount' : 'Démonter $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Glissez-déposez depuis le navigateur de fichier', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Glissez-déposez les fichiers ici', // from v2.1 added 07.04.2014 + 'encoding' : 'Encodage', // from v2.1 added 19.12.2014 + 'locale' : 'Encodage régional', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Destination: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Recherche par type MIME', // from v2.1 added 22.5.2015 + 'owner' : 'Propriétaire', // from v2.1 added 20.6.2015 + 'group' : 'Groupe', // from v2.1 added 20.6.2015 + 'other' : 'Autre', // from v2.1 added 20.6.2015 + 'execute' : 'Exécuter', // from v2.1 added 20.6.2015 + 'perm' : 'Permission', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Le dossier est vide', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Le dossier est vide.\\ Glissez-déposez pour ajouter des éléments.', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Le dossier est vide.\\ Appuyez longuement pour ajouter des éléments.', // from v2.1.6 added 30.12.2015 + 'quality' : 'Qualité', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Synchronisation automatique', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Déplacer vers le haut', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Obtenir le lien d’URL', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Éléments sélectionnés ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID du dossier', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Permettre l\'accès hors-ligne', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Pour se réauthentifier', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'En cours de chargement...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Ouvrir multiples fichiers', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Vous allez ouvrir $1 fichiers. Êtes-vous sûr de vouloir les ouvrir dans le navigateur ?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Aucun résultat trouvé avec les paramètres de recherche.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Modification d\'un fichier.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Vous avez sélectionné $1 éléments.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Vous avez $1 éléments dans le presse-papier.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Recherche incrémentale disponible uniquement pour la vue active.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Rétablir', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 complété', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Menu contextuel', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Tourner la page', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volumes principaux', // from v2.1.16 added 16.9.2016 + 'reset' : 'Réinitialiser', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Couleur de fond', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Sélecteur de couleur', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'Grille 8px', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Actif', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Inactif', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Aucun résultat trouvé.\\AAppuyez sur [Entrée] pour développer la cible de recherche.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Aucun résultat trouvé pour la recherche par première lettre.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Label texte', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 mins restantes', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Réouvrir avec l\'encodage sélectionné', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Sauvegarder avec l\'encodage sélectionné', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Choisir le dossier', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Recherche par première lettre', // from v2.1.23 added 24.3.2017 + 'presets' : 'Présélections', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Impossible de mettre autant d\'éléments à la corbeille.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Zone de texte', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Vider le dossier "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Il n\'y a pas d\'élément dans le dossier "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Préférence', // from v2.1.26 added 28.6.2017 + 'language' : 'Configuration de langue', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialisation des configurations sauvegardées dans ce navigateur', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Paramètres de la barre d\'outils', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 caractères restants.', // from v2.1.29 added 30.8.2017 + 'sum' : 'Somme', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Taille de fichier brute', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focus on the element of dialog with mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Sélectionner', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Action lors de la sélection d\'un fichier', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Ouvrir avec le dernier éditeur utilisé', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Inverser la sélection', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Êtes-vous sûr de vouloir renommer les éléments sélectionnés $1 en $2 ?
                      L\'action est définitive !', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Renommer le Batch', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Nombre', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Ajouter un préfixe', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Ajouter un suffixe', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Modifier l\'extention', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Paramètres des colonnes (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Les changements seront immédiatement appliqués à l\'archive.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Aucun changement ne sera appliqué tant que ce volume n\'a pas été démonté.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Le(s) volume(s) suivant(s) montés sur ce volume seront également démontés. Êtes-vous sûr de vouloir le démonter ?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Informations sur la sélection', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorithme de hachage de fichier', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Appuyez à nouveau pour quitter.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Barre d\'outils', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Espace de travail', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialogue', // from v2.1.38 added 4.4.2018 + 'all' : 'Tout', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Icon Size (Icons view)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Open the maximized editor window', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Because conversion by API is not currently available, please convert on the website.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Convert on the site of $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrations', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'This elFinder has the following external services integrated. Please check the terms of use, privacy policy, etc. before using it.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Show hidden items', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Hide hidden items', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Show/Hide hidden items', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'File types to enable with "New file"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type of the Text file', // from v2.1.41 added 7.8.2018 + 'add' : 'Add', // from v2.1.41 added 7.8.2018 + 'theme' : 'Theme', // from v2.1.43 added 19.10.2018 + 'default' : 'Default', // from v2.1.43 added 19.10.2018 + 'description' : 'Description', // from v2.1.43 added 19.10.2018 + 'website' : 'Website', // from v2.1.43 added 19.10.2018 + 'author' : 'Author', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'License', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'This item can\'t be saved. To avoid losing the edits you need to export to your PC.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Double click on the file to select it.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Use fullscreen mode', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Inconnu', + 'kindRoot' : 'Volume principal', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Dossier', + 'kindSelects' : 'Sélections', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Raccourci', + 'kindAliasBroken' : 'Raccourci cassé', + // applications + 'kindApp' : 'Application', + 'kindPostscript' : 'Document Postscript', + 'kindMsOffice' : 'Document Microsoft Office', + 'kindMsWord' : 'Document Microsoft Word', + 'kindMsExcel' : 'Document Microsoft Excel', + 'kindMsPP' : 'Présentation Microsoft PowerPoint', + 'kindOO' : 'Document OpenOffice', + 'kindAppFlash' : 'Application Flash', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Fichier BitTorrent', + 'kind7z' : 'Archive 7z', + 'kindTAR' : 'Archive TAR', + 'kindGZIP' : 'Archive GZIP', + 'kindBZIP' : 'Archive BZIP', + 'kindXZ' : 'Archive XZ', + 'kindZIP' : 'Archive ZIP', + 'kindRAR' : 'Archive RAR', + 'kindJAR' : 'Fichier Java JAR', + 'kindTTF' : 'Police True Type', + 'kindOTF' : 'Police Open Type', + 'kindRPM' : 'Package RPM', + // fonts + 'kindFont' : 'Police', + 'kindSFNT' : 'Police SFNT', + 'kindEOT' : 'Police Embedded Open Type', + 'kindWOFF' : 'Police Web Open Font Format', + 'kindWOFF2' : 'Police Web Open Font Format 2', + // texts + 'kindText' : 'Document Text', + 'kindTextPlain' : 'Texte non formaté', + 'kindPHP' : 'Source PHP', + 'kindCSS' : 'Feuille de style en cascade', + 'kindHTML' : 'Document HTML', + 'kindJS' : 'Source JavaScript', + 'kindRTF' : 'Format de texte enrichi (Rich Text Format)', + 'kindC' : 'Source C', + 'kindCHeader' : 'Source header C', + 'kindCPP' : 'Source C++', + 'kindCPPHeader' : 'Source header C++', + 'kindShell' : 'Shell script Unix', + 'kindPython' : 'Source Python', + 'kindJava' : 'Source Java', + 'kindRuby' : 'Source Ruby', + 'kindPerl' : 'Script Perl', + 'kindSQL' : 'Source SQL', + 'kindXML' : 'Document XML', + 'kindAWK' : 'Source AWK', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Document Docbook XML', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Image', + 'kindBMP' : 'Image BMP', + 'kindJPEG' : 'Image JPEG', + 'kindGIF' : 'Image GIF', + 'kindPNG' : 'Image PNG', + 'kindTIFF' : 'Image TIFF', + 'kindTGA' : 'Image TGA', + 'kindPSD' : 'Image Adobe Photoshop', + 'kindXBITMAP' : 'Image X bitmap', + 'kindPXM' : 'Image Pixelmator', + // media + 'kindAudio' : 'Son', + 'kindAudioMPEG' : 'Son MPEG', + 'kindAudioMPEG4' : 'Son MPEG-4', + 'kindAudioMIDI' : 'Son MIDI', + 'kindAudioOGG' : 'Son Ogg Vorbis', + 'kindAudioWAV' : 'Son WAV', + 'AudioPlaylist' : 'Liste de lecture audio', + 'kindVideo' : 'Vidéo', + 'kindVideoDV' : 'Vidéo DV', + 'kindVideoMPEG' : 'Vidéo MPEG', + 'kindVideoMPEG4' : 'Vidéo MPEG-4', + 'kindVideoAVI' : 'Vidéo AVI', + 'kindVideoMOV' : 'Vidéo Quick Time', + 'kindVideoWM' : 'Vidéo Windows Media', + 'kindVideoFlash' : 'Vidéo Flash', + 'kindVideoMKV' : 'Vidéo Matroska', + 'kindVideoOGG' : 'Vidéo Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.he.js b/lib/redactor/elfinder/js/i18n/elfinder.he.js new file mode 100644 index 0000000..f57ff3f --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.he.js @@ -0,0 +1,382 @@ +/** + * עברית translation + * @author Yaron Shahrabani + * @version 2015-11-02 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.he = { + translator : 'Yaron Shahrabani ', + language : 'עברית', + direction : 'rtl', + dateFormat : 'd.m.Y H:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + messages : { + + /********************************** errors **********************************/ + 'error' : 'שגיאה', + 'errUnknown' : 'שגיאה בלתי מוכרת.', + 'errUnknownCmd' : 'פקודה בלתי מוכרת.', + 'errJqui' : 'תצורת ה־jQuery UI שגויה. יש לכלול רכיבים הניתנים לבחירה, גרירה והשלכה.', + 'errNode' : 'elFinder דורש יצירה של רכיב DOM.', + 'errURL' : 'התצורה של elFinder שגויה! אפשרות הכתובת (URL) לא הוגדרה.', + 'errAccess' : 'הגישה נדחית.', + 'errConnect' : 'לא ניתן להתחבר למנגנון.', + 'errAbort' : 'החיבור בוטל.', + 'errTimeout' : 'זמן החיבור פג.', + 'errNotFound' : 'לא נמצא מנגנון.', + 'errResponse' : 'תגובת המנגנון שגויה.', + 'errConf' : 'תצורת המנגנון שגויה.', + 'errJSON' : 'המודול PHP JSON לא מותקן.', + 'errNoVolumes' : 'אין כוננים זמינים לקריאה.', + 'errCmdParams' : 'פרמטרים שגויים לפקודה „$1“.', + 'errDataNotJSON' : 'הנתונים אינם JSON.', + 'errDataEmpty' : 'הנתונים ריקים.', + 'errCmdReq' : 'בקשה למנגנון דורשת שם פקודה.', + 'errOpen' : 'לא ניתן לפתוח את „$1“.', + 'errNotFolder' : 'הפריט אינו תיקייה.', + 'errNotFile' : 'הפריט אינו קובץ.', + 'errRead' : 'לא ניתן לקרוא את „$1“.', + 'errWrite' : 'לא ניתן לכתוב אל „$1“.', + 'errPerm' : 'ההרשאה נדחתה.', + 'errLocked' : '„$1“ נעול ואין אפשרות לשנות את שמו, להעבירו או להסירו.', + 'errExists' : 'קובץ בשם „$1“ כבר קיים.', + 'errInvName' : 'שם הקובץ שגוי.', + 'errFolderNotFound' : 'התיקייה לא נמצאה.', + 'errFileNotFound' : 'הקובץ לא נמצא.', + 'errTrgFolderNotFound' : 'תיקיית היעד „$1“ לא נמצאה.', + 'errPopup' : 'הדפדפן מנע פתיחת חלון קובץ. כדי לפתוח קובץ יש לאפשר זאת בהגדרות הדפדפן.', + 'errMkdir' : 'לא ניתן ליצור את התיקייה „$1“.', + 'errMkfile' : 'לא ניתן ליצור את הקובץ „$1“.', + 'errRename' : 'לא ניתן לשנות את השם של „$1“.', + 'errCopyFrom' : 'העתקת קבצים מהכונן „$1“ אינה מאופשרת.', + 'errCopyTo' : 'העתקת קבצים אל הכונן „$1“ אינה מאופשרת.', + 'errUpload' : 'שגיאת העלאה.', // old name - errUploadCommon + 'errUploadFile' : 'לא ניתן להעלות את „$1“.', // old name - errUpload + 'errUploadNoFiles' : 'לא נמצאו קבצים להעלאה.', + 'errUploadTotalSize' : 'הנתונים חורגים מהגודל המרבי המותר.', // old name - errMaxSize + 'errUploadFileSize' : 'הקובץ חורג מהגודל המרבי המותר.', // old name - errFileMaxSize + 'errUploadMime' : 'סוג הקובץ אינו מורשה.', + 'errUploadTransfer' : 'שגיאת העברה „$1“.', + 'errNotReplace' : 'הפריט „$1“ כבר קיים במיקום זה ואי אפשר להחליפו בפריט מסוג אחר.', // new + 'errReplace' : 'לא ניתן להחליף את „$1“.', + 'errSave' : 'לא ניתן לשמור את „$1“.', + 'errCopy' : 'לא ניתן להעתיק את „$1“.', + 'errMove' : 'לא ניתן להעביר את „$1“.', + 'errCopyInItself' : 'לא ניתן להעתיק את „$1“ לתוך עצמו.', + 'errRm' : 'לא ניתן להסיר את „$1“.', + 'errRmSrc' : 'לא ניתן להסיר את קובצי המקור.', + 'errExtract' : 'לא ניתן לחלץ קבצים מהארכיון „$1“.', + 'errArchive' : 'לא ניתן ליצור ארכיון.', + 'errArcType' : 'סוג הארכיון אינו נתמך.', + 'errNoArchive' : 'הקובץ אינו ארכיון או שסוג הקובץ שלו אינו נתמך.', + 'errCmdNoSupport' : 'המנגנון אינו תומך בפקודה זו.', + 'errReplByChild' : 'לא ניתן להחליף את התיקייה „$1“ בפריט מתוכה.', + 'errArcSymlinks' : 'מטעמי אבטחה לא ניתן לחלץ ארכיונים שמכילים קישורים סימבוליים או קבצים עם שמות בלתי מורשים.', // edited 24.06.2012 + 'errArcMaxSize' : 'הארכיון חורג מהגודל המרבי המותר.', + 'errResize' : 'לא ניתן לשנות את הגודל של „$1“.', + 'errResizeDegree' : 'מעלות ההיפוך שגויות.', // added 7.3.2013 + 'errResizeRotate' : 'לא ניתן להפוך את התמונה.', // added 7.3.2013 + 'errResizeSize' : 'גודל התמונה שגוי.', // added 7.3.2013 + 'errResizeNoChange' : 'גודל התמונה לא השתנה.', // added 7.3.2013 + 'errUsupportType' : 'סוג הקובץ אינו נתמך.', + 'errNotUTF8Content' : 'הקובץ „$1“ הוא לא בתסדיר UTF-8 ולא ניתן לערוך אותו.', // added 9.11.2011 + 'errNetMount' : 'לא ניתן לעגן את „$1“.', // added 17.04.2012 + 'errNetMountNoDriver' : 'פרוטוקול בלתי נתמך.', // added 17.04.2012 + 'errNetMountFailed' : 'העיגון נכשל.', // added 17.04.2012 + 'errNetMountHostReq' : 'נדרש מארח.', // added 18.04.2012 + 'errSessionExpires' : 'ההפעלה שלך פגה עקב חוסר פעילות.', + 'errCreatingTempDir' : 'לא ניתן ליצור תיקייה זמנית: „$1“', + 'errFtpDownloadFile' : 'לא ניתן להוריד קובץ מ־ FTP: „$1“', + 'errFtpUploadFile' : 'לא ניתן להעלות קובץ ל־FTP: „$1“', + 'errFtpMkdir' : 'לא ניתן ליצור תיקייה מרוחקת ב־FTP: „$1“', + 'errArchiveExec' : 'שמירת הקבצים בארכיון נכשלה: „$1“', + 'errExtractExec' : 'חילוץ קבצים נכשל: „$1“', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'יצירת ארכיון', + 'cmdback' : 'חזרה', + 'cmdcopy' : 'העתקה', + 'cmdcut' : 'גזירה', + 'cmddownload' : 'הורדה', + 'cmdduplicate' : 'שכפול', + 'cmdedit' : 'עריכת קובץ', + 'cmdextract' : 'חילוץ קבצים מארכיון', + 'cmdforward' : 'העברה', + 'cmdgetfile' : 'בחירת קבצים', + 'cmdhelp' : 'פרטים על התכנית הזו', + 'cmdhome' : 'בית', + 'cmdinfo' : 'קבלת מידע', + 'cmdmkdir' : 'תיקייה חדשה', + 'cmdmkfile' : 'קובץ חדש', + 'cmdopen' : 'פתיחה', + 'cmdpaste' : 'הדבקה', + 'cmdquicklook' : 'תצוגה מקדימה', + 'cmdreload' : 'רענון', + 'cmdrename' : 'שינוי שם', + 'cmdrm' : 'מחיקה', + 'cmdsearch' : 'חיפוש קבצים', + 'cmdup' : 'מעבר לתיקיית ההורה', + 'cmdupload' : 'העלאת קבצים', + 'cmdview' : 'תצוגה', + 'cmdresize' : 'שינוי גודל והיפוך', + 'cmdsort' : 'מיון', + 'cmdnetmount' : 'עיגון כונן רשת', // added 18.04.2012 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'סגירה', + 'btnSave' : 'שמירה', + 'btnRm' : 'הסרה', + 'btnApply' : 'החלה', + 'btnCancel' : 'ביטול', + 'btnNo' : 'לא', + 'btnYes' : 'כן', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'עיגון', // added 18.04.2012 + + /******************************** notifications ********************************/ + 'ntfopen' : 'פתיחת תיקייה', + 'ntffile' : 'פתיחת קובץ', + 'ntfreload' : 'רענון תוכן התיקייה', + 'ntfmkdir' : 'תיקייה נוצרת', + 'ntfmkfile' : 'קבצים נוצרים', + 'ntfrm' : 'קבצים נמחקים', + 'ntfcopy' : 'קבצים מועתקים', + 'ntfmove' : 'קבצים מועברים', + 'ntfprepare' : 'העתקת קבצים בהכנה', + 'ntfrename' : 'שמות קבצים משתנים', + 'ntfupload' : 'קבצים נשלחים', + 'ntfdownload' : 'קבצים מתקבלים', + 'ntfsave' : 'שמירת קבצים', + 'ntfarchive' : 'ארכיון נוצר', + 'ntfextract' : 'מחולצים קבצים מארכיון', + 'ntfsearch' : 'קבצים בחיפוש', + 'ntfresize' : 'גודל קבצים משתנה', + 'ntfsmth' : 'מתבצעת פעולה', + 'ntfloadimg' : 'נטענת תמונה', + 'ntfnetmount' : 'כונן רשת מעוגן', // added 18.04.2012 + 'ntfdim' : 'ממדי תמונה מתקבלים', // added 20.05.2013 + + /************************************ dates **********************************/ + 'dateUnknown' : 'לא ידוע', + 'Today' : 'היום', + 'Yesterday' : 'מחר', + 'msJan' : 'ינו׳', + 'msFeb' : 'פבר׳', + 'msMar' : 'מרץ', + 'msApr' : 'אפר׳', + 'msMay' : 'מאי', + 'msJun' : 'יונ׳', + 'msJul' : 'יול׳', + 'msAug' : 'אוג׳', + 'msSep' : 'ספט׳', + 'msOct' : 'אוק׳', + 'msNov' : 'נוב׳', + 'msDec' : 'דצמ׳', + 'January' : 'ינואר', + 'February' : 'פברואר', + 'March' : 'מרץ', + 'April' : 'אפריל', + 'May' : 'מאי', + 'June' : 'יוני', + 'July' : 'יולי', + 'August' : 'אוגוסט', + 'September' : 'ספטמבר', + 'October' : 'אוקטובר', + 'November' : 'נובמבר', + 'December' : 'דצמבר', + 'Sunday' : 'יום ראשון', + 'Monday' : 'יום שני', + 'Tuesday' : 'יום שלישי', + 'Wednesday' : 'יום רביעי', + 'Thursday' : 'יום חמישי', + 'Friday' : 'יום שישי', + 'Saturday' : 'שבת', + 'Sun' : 'א׳', + 'Mon' : 'ב׳', + 'Tue' : 'ג׳', + 'Wed' : 'ד׳', + 'Thu' : 'ה', + 'Fri' : 'ו׳', + 'Sat' : 'ש׳', + + /******************************** sort variants ********************************/ + 'sortname' : 'לפי שם', + 'sortkind' : 'לפי סוג', + 'sortsize' : 'לפי גודל', + 'sortdate' : 'לפי תאריך', + 'sortFoldersFirst' : 'תיקיות תחילה', + + /********************************** messages **********************************/ + 'confirmReq' : 'נדרש אישור', + 'confirmRm' : 'להסיר את הקבצים?
                      פעולה זו בלתי הפיכה!', + 'confirmRepl' : 'להחליף קובץ ישן בקובץ חדש?', + 'apllyAll' : 'להחיל על הכול', + 'name' : 'שם', + 'size' : 'גודל', + 'perms' : 'הרשאות', + 'modify' : 'שינוי', + 'kind' : 'סוג', + 'read' : 'קריאה', + 'write' : 'כתיבה', + 'noaccess' : 'אין גישה', + 'and' : 'וגם', + 'unknown' : 'לא ידוע', + 'selectall' : 'בחירת כל הקבצים', + 'selectfiles' : 'בחירת קובץ אחד ומעלה', + 'selectffile' : 'בחירת הקובץ הראשון', + 'selectlfile' : 'בחירת הקובץ האחרון', + 'viewlist' : 'תצוגת רשימה', + 'viewicons' : 'תצוגת סמלים', + 'places' : 'מיקומים', + 'calc' : 'חישוב', + 'path' : 'נתיב', + 'aliasfor' : 'כינוי עבור', + 'locked' : 'נעול', + 'dim' : 'ממדים', + 'files' : 'קבצים', + 'folders' : 'תיקיות', + 'items' : 'פריטים', + 'yes' : 'כן', + 'no' : 'לא', + 'link' : 'קישור', + 'searcresult' : 'תוצאות חיפוש', + 'selected' : 'קבצים נבחרים', + 'about' : 'על אודות', + 'shortcuts' : 'קיצורי דרך', + 'help' : 'עזרה', + 'webfm' : 'מנהל קבצים בדפדפן', + 'ver' : 'גרסה', + 'protocolver' : 'גרסת פרוטוקול', + 'homepage' : 'דף הבית של המיזם', + 'docs' : 'תיעוד', + 'github' : 'פילוג עותק ב־Github', + 'twitter' : 'לעקוב אחרינו בטוויטר', + 'facebook' : 'להצטרף אלינו בפייסבוק', + 'team' : 'צוות', + 'chiefdev' : 'מפתח ראשי', + 'developer' : 'מתכנת', + 'contributor' : 'תורם', + 'maintainer' : 'מתחזק', + 'translator' : 'מתרגם', + 'icons' : 'סמלים', + 'dontforget' : 'לא לשכוח לקחת את המגבת שלך', + 'shortcutsof' : 'קיצורי הדרך מנוטרלים', + 'dropFiles' : 'ניתן להשליך את הקבצים לכאן', + 'or' : 'או', + 'selectForUpload' : 'לבחור קבצים להעלאה', + 'moveFiles' : 'העברת קבצים', + 'copyFiles' : 'העתקת קבצים', + 'rmFromPlaces' : 'הסרה ממיקומים', + 'aspectRatio' : 'יחס תצוגה', + 'scale' : 'מתיחה', + 'width' : 'רוחב', + 'height' : 'גובה', + 'resize' : 'שינוי הגודל', + 'crop' : 'חיתוך', + 'rotate' : 'היפוך', + 'rotate-cw' : 'היפוך ב־90 מעלות נגד השעון', + 'rotate-ccw' : 'היפוך ב־90 מעלות עם השעון CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'עיגון כונן רשת', // added 18.04.2012 + 'protocol' : 'פרוטוקול', // added 18.04.2012 + 'host' : 'מארח', // added 18.04.2012 + 'port' : 'פתחה', // added 18.04.2012 + 'user' : 'משתמש', // added 18.04.2012 + 'pass' : 'ססמה', // added 18.04.2012 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'בלתי ידוע', + 'kindFolder' : 'תיקייה', + 'kindAlias' : 'כינוי', + 'kindAliasBroken' : 'כינוי שבור', + // applications + 'kindApp' : 'יישום', + 'kindPostscript' : 'מסמך Postscript', + 'kindMsOffice' : 'מסמך Microsoft Office', + 'kindMsWord' : 'מסמך Microsoft Word', + 'kindMsExcel' : 'מסמך Microsoft Excel', + 'kindMsPP' : 'מצגת Microsoft Powerpoint', + 'kindOO' : 'מסמך Open Office', + 'kindAppFlash' : 'יישום Flash', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'קובץ Bittorrent', + 'kind7z' : 'ארכיון 7z', + 'kindTAR' : 'ארכיון TAR', + 'kindGZIP' : 'ארכיון GZIP', + 'kindBZIP' : 'ארכיון BZIP', + 'kindXZ' : 'ארכיון XZ', + 'kindZIP' : 'ארכיון ZIP', + 'kindRAR' : 'ארכיון RAR', + 'kindJAR' : 'קובץ JAR של Java', + 'kindTTF' : 'גופן True Type', + 'kindOTF' : 'גופן Open Type', + 'kindRPM' : 'חבילת RPM', + // fonts + 'kindFont' : 'גופן', + 'kindSFNT' : 'גופן SFNT', + 'kindEOT' : 'גופן Embedded Open Type', + 'kindWOFF' : 'גופן Web Open Font Format', + 'kindWOFF2' : 'גופן Web Open Font Format 2', + // texts + 'kindText' : 'מסמך טקסט', + 'kindTextPlain' : 'טקסט פשוט', + 'kindPHP' : 'מקור PHP', + 'kindCSS' : 'גיליון סגנון מדורג', + 'kindHTML' : 'מסמך HTML', + 'kindJS' : 'מקור Javascript', + 'kindRTF' : 'תבנית טקסט עשיר', + 'kindC' : 'מקור C', + 'kindCHeader' : 'מקור כותרת C', + 'kindCPP' : 'מקור C++', + 'kindCPPHeader' : 'מקור כותרת C++', + 'kindShell' : 'תסריט מעטפת יוניקס', + 'kindPython' : 'מקור Python', + 'kindJava' : 'מקור Java', + 'kindRuby' : 'מקור Ruby', + 'kindPerl' : 'תסריט Perl', + 'kindSQL' : 'מקור SQL', + 'kindXML' : 'מקור XML', + 'kindAWK' : 'מקור AWK', + 'kindCSV' : 'ערכים מופרדים בפסיקים', + 'kindDOCBOOK' : 'מסמךDocbook XML', + // images + 'kindImage' : 'תמונה', + 'kindBMP' : 'תמונת BMP', + 'kindJPEG' : 'תמונת JPEG', + 'kindGIF' : 'תמונת GIF', + 'kindPNG' : 'תמונת PNG', + 'kindTIFF' : 'תמונת TIFF', + 'kindTGA' : 'תמונת TGA', + 'kindPSD' : 'תמונת Adobe Photoshop', + 'kindXBITMAP' : 'תמונת מפת סיביות X', + 'kindPXM' : 'תמונת Pixelmator', + // media + 'kindAudio' : 'מדיה מסוג שמע', + 'kindAudioMPEG' : 'שמע MPEG', + 'kindAudioMPEG4' : 'שמע MPEG-4', + 'kindAudioMIDI' : 'שמע MIDI', + 'kindAudioOGG' : 'שמע Ogg Vorbis', + 'kindAudioWAV' : 'שמע WAV', + 'AudioPlaylist' : 'רשימת נגינה MP3', + 'kindVideo' : 'מדיה מסוג וידאו', + 'kindVideoDV' : 'סרטון DV', + 'kindVideoMPEG' : 'סרטון MPEG', + 'kindVideoMPEG4' : 'סרטון MPEG-4', + 'kindVideoAVI' : 'סרטון AVI', + 'kindVideoMOV' : 'סרטון Quick Time', + 'kindVideoWM' : 'סרטון Windows Media', + 'kindVideoFlash' : 'סרטון Flash', + 'kindVideoMKV' : 'סרטון Matroska', + 'kindVideoOGG' : 'סרטון Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.hr.js b/lib/redactor/elfinder/js/i18n/elfinder.hr.js new file mode 100644 index 0000000..ce788dc --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.hr.js @@ -0,0 +1,441 @@ +/** + * hr translation + * @version 2016-04-18 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.hr = { + translator : '', + language : 'Croatian', + direction : 'ltr', + dateFormat : 'd.m.Y. H:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + messages : { + + /********************************** errors **********************************/ + 'error' : 'Greška', + 'errUnknown' : 'Nepoznata greška.', + 'errUnknownCmd' : 'Nepoznata naredba.', + 'errJqui' : 'Kriva jQuery UI konfiguracija. Selectable, draggable, i droppable komponente moraju biti uključene.', + 'errNode' : 'elFinder zahtjeva DOM element da bi bio stvoren.', + 'errURL' : 'Krivo konfiguriran elFinder. Opcija URL nije postavljena.', + 'errAccess' : 'Zabranjen pristup.', + 'errConnect' : 'Nije moguće spajanje na server.', + 'errAbort' : 'Prekinuta veza.', + 'errTimeout' : 'Veza je istekla.', + 'errNotFound' : 'Server nije pronađen.', + 'errResponse' : 'Krivi odgovor servera.', + 'errConf' : 'Krivo konfiguriran server', + 'errJSON' : 'Nije instaliran PHP JSON modul.', + 'errNoVolumes' : 'Disk nije dostupan.', + 'errCmdParams' : 'Krivi parametri za naredbu "$1".', + 'errDataNotJSON' : 'Podaci nisu tipa JSON.', + 'errDataEmpty' : 'Nema podataka.', + 'errCmdReq' : 'Backend request requires command name.', + 'errOpen' : 'Ne mogu otvoriti "$1".', + 'errNotFolder' : 'Objekt nije mapa.', + 'errNotFile' : 'Objekt nije dokument.', + 'errRead' : 'Ne mogu pročitati "$1".', + 'errWrite' : 'Ne mogu pisati u "$1".', + 'errPerm' : 'Pristup zabranjen', + 'errLocked' : '"$1" je zaključan i ne može biti preimenovan, premješten ili obrisan.', + 'errExists' : 'Dokument s imenom "$1" već postoji.', + 'errInvName' : 'Krivo ime dokumenta', + 'errFolderNotFound' : 'Mapa nije pronađena', + 'errFileNotFound' : 'Dokument nije pronađen', + 'errTrgFolderNotFound' : 'Mapa "$1" nije pronađena', + 'errPopup' : 'Browser prevented opening popup window. To open file enable it in browser options.', + 'errMkdir' : 'Ne mogu napraviti mapu "$1".', + 'errMkfile' : 'Ne mogu napraviti dokument "$1".', + 'errRename' : 'Ne mogu preimenovati "$1".', + 'errCopyFrom' : 'Kopiranje s diska "$1" nije dozvoljeno.', + 'errCopyTo' : 'Kopiranje na disk "$1" nije dozvoljeno.', + 'errMkOutLink' : 'Unable to create a link to outside the volume root.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Greška pri prebacivanju dokumenta na server.', // old name - errUploadCommon + 'errUploadFile' : 'Ne mogu prebaciti "$1" na server', // old name - errUpload + 'errUploadNoFiles' : 'Nema dokumenata za prebacivanje na server', + 'errUploadTotalSize' : 'Dokumenti prelaze maksimalnu dopuštenu veličinu.', // old name - errMaxSize + 'errUploadFileSize' : 'Dokument je prevelik.', // old name - errFileMaxSize + 'errUploadMime' : 'Ovaj tip dokumenta nije dopušten.', + 'errUploadTransfer' : '"$1" greška pri prebacivanju', + 'errUploadTemp' : 'Ne mogu napraviti privremeni dokument za prijenos na server', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', // new + 'errReplace' : 'Ne mogu zamijeniti "$1".', + 'errSave' : 'Ne mogu spremiti "$1".', + 'errCopy' : 'Ne mogu kopirati "$1".', + 'errMove' : 'Ne mogu premjestiti "$1".', + 'errCopyInItself' : 'Ne mogu kopirati "$1" na isto mjesto.', + 'errRm' : 'Ne mogu ukloniti "$1".', + 'errRmSrc' : 'Ne mogu ukloniti izvorni kod.', + 'errExtract' : 'Unable to extract files from "$1".', + 'errArchive' : 'Unable to create archive.', + 'errArcType' : 'Unsupported archive type.', + 'errNoArchive' : 'File is not archive or has unsupported archive type.', + 'errCmdNoSupport' : 'Backend does not support this command.', + 'errReplByChild' : 'The folder "$1" can\'t be replaced by an item it contains.', + 'errArcSymlinks' : 'For security reason denied to unpack archives contains symlinks or files with not allowed names.', // edited 24.06.2012 + 'errArcMaxSize' : 'Archive files exceeds maximum allowed size.', + 'errResize' : 'Unable to resize "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', // added 7.3.2013 + 'errResizeRotate' : 'Unable to rotate image.', // added 7.3.2013 + 'errResizeSize' : 'Invalid image size.', // added 7.3.2013 + 'errResizeNoChange' : 'Image size not changed.', // added 7.3.2013 + 'errUsupportType' : 'Unsupported file type.', + 'errNotUTF8Content' : 'File "$1" is not in UTF-8 and cannot be edited.', // added 9.11.2011 + 'errNetMount' : 'Unable to mount "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Unsupported protocol.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount failed.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host required.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + 'errNetUnMount' : 'Unable to unmount', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Not convertible to UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Try Google Chrome, If you\'d like to upload the folder.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Timed out while searching "$1". Search result is partial.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Re-authorization is required.', // from v2.1.10 added 3.24.2016 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Arhiviraj', + 'cmdback' : 'Nazad', + 'cmdcopy' : 'Kopiraj', + 'cmdcut' : 'Izreži', + 'cmddownload' : 'Preuzmi', + 'cmdduplicate' : 'Dupliciraj', + 'cmdedit' : 'Uredi dokument', + 'cmdextract' : 'Raspakiraj arhivu', + 'cmdforward' : 'Naprijed', + 'cmdgetfile' : 'Odaberi dokumente', + 'cmdhelp' : 'O programu', + 'cmdhome' : 'Početak', + 'cmdinfo' : 'Info', + 'cmdmkdir' : 'Nova mapa', + 'cmdmkdirin' : 'U novu mapu', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nova файл', + 'cmdopen' : 'Otvori', + 'cmdpaste' : 'Zalijepi', + 'cmdquicklook' : 'Pregled', + 'cmdreload' : 'Ponovo učitaj', + 'cmdrename' : 'Preimenuj', + 'cmdrm' : 'Obriši', + 'cmdsearch' : 'Pronađi', + 'cmdup' : 'Roditeljska mapa', + 'cmdupload' : 'Prebaci dokumente na server', + 'cmdview' : 'Pregledaj', + 'cmdresize' : 'Promjeni veličinu i rotiraj', + 'cmdsort' : 'Sortiraj', + 'cmdnetmount' : 'Spoji se na mrežni disk', // added 18.04.2012 + 'cmdnetunmount': 'Odspoji disk', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'To Places', // added 28.12.2014 + 'cmdchmod' : 'Change mode', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Otvori mapu', // from v2.1 added 13.1.2016 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Zatvori', + 'btnSave' : 'Spremi', + 'btnRm' : 'Ukloni', + 'btnApply' : 'Primjeni', + 'btnCancel' : 'Odustani', + 'btnNo' : 'Ne', + 'btnYes' : 'Da', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', // added 18.04.2012 + 'btnApprove': 'Goto $1 & approve', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convert', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Here', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'All', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Type', // from v2.1 added 22.5.2015 + 'btnFileName':'Filename', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Spremi i zatvori', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Otvori mapu', + 'ntffile' : 'Otvori dokument', + 'ntfreload' : 'Ponovo učitaj sadržaj mape', + 'ntfmkdir' : 'Radim mapu', + 'ntfmkfile' : 'Radim dokumente', + 'ntfrm' : 'Brišem dokumente', + 'ntfcopy' : 'Kopiram dokumente', + 'ntfmove' : 'Mičem dokumente', + 'ntfprepare' : 'Priprema za kopiranje dokumenata', + 'ntfrename' : 'Preimenuj dokumente', + 'ntfupload' : 'Pohranjujem dokumente na server', + 'ntfdownload' : 'Preuzimam dokumente', + 'ntfsave' : 'Spremi dokumente', + 'ntfarchive' : 'Radim arhivu', + 'ntfextract' : 'Extracting files from archive', + 'ntfsearch' : 'Tražim dokumente', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Doing something', + 'ntfloadimg' : 'Učitavam sliku', + 'ntfnetmount' : 'Mounting network volume', // added 18.04.2012 + 'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Acquiring image dimension', // added 20.05.2013 + 'ntfreaddir' : 'Reading folder infomation', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Getting URL of link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Changing file mode', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Verifying upload file name', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Creating a file for download', // from v2.1.7 added 23.1.2016 + + /************************************ dates **********************************/ + 'dateUnknown' : 'nepoznato', + 'Today' : 'Danas', + 'Yesterday' : 'Jučer', + 'msJan' : 'Sij', + 'msFeb' : 'Vel', + 'msMar' : 'Ožu', + 'msApr' : 'Tra', + 'msMay' : 'Svi', + 'msJun' : 'Lip', + 'msJul' : 'Srp', + 'msAug' : 'Kol', + 'msSep' : 'Ruj', + 'msOct' : 'Lis', + 'msNov' : 'Stu', + 'msDec' : 'Pro', + 'January' : 'Siječanj', + 'February' : 'Veljača', + 'March' : 'Ožujak', + 'April' : 'Travanj', + 'May' : 'Svibanj', + 'June' : 'Lipanj', + 'July' : 'Srpanj', + 'August' : 'Kolovoz', + 'September' : 'Rujan', + 'October' : 'Listopad', + 'November' : 'Studeni', + 'December' : 'Prosinac', + 'Sunday' : 'Nedjelja', + 'Monday' : 'Ponedjeljak', + 'Tuesday' : 'Utorak', + 'Wednesday' : 'Srijeda', + 'Thursday' : 'Četvrtak', + 'Friday' : 'Petak', + 'Saturday' : 'Subota', + 'Sun' : 'Ned', + 'Mon' : 'Pon', + 'Tue' : 'Uto', + 'Wed' : 'Sri', + 'Thu' : 'Čet', + 'Fri' : 'Pet', + 'Sat' : 'Sub', + + /******************************** sort variants ********************************/ + 'sortname' : 'po imenu', + 'sortkind' : 'po tipu', + 'sortsize' : 'po veličini', + 'sortdate' : 'po datumu', + 'sortFoldersFirst' : 'Prvo mape', + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NoviDokument.txt', // added 10.11.2015 + 'untitled folder' : 'NovaMapa', // added 10.11.2015 + 'Archive' : 'NovaArhiva', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'Potvrda', + 'confirmRm' : 'Jeste li sigurni?', + 'confirmRepl' : 'Zamijeni stare dokumente novima?', + 'confirmConvUTF8' : 'Not in UTF-8
                      Convert to UTF-8?
                      Contents become UTF-8 by saving after conversion.', // from v2.1 added 08.04.2014 + 'confirmNotSave' : 'It has been modified.
                      Losing work if you do not save changes.', // from v2.1 added 15.7.2015 + 'apllyAll' : 'Primjeni na sve ', + 'name' : 'Ime', + 'size' : 'Veličina', + 'perms' : 'Dozvole', + 'modify' : 'Modificiran', + 'kind' : 'Tip', + 'read' : 'čitanje', + 'write' : 'pisanje', + 'noaccess' : 'bez pristupa', + 'and' : 'i', + 'unknown' : 'nepoznato', + 'selectall' : 'Odaberi sve', + 'selectfiles' : 'Odaberi dokument(e)', + 'selectffile' : 'Odaberi prvi dokument', + 'selectlfile' : 'Odaberi zadnji dokument', + 'viewlist' : 'Lista', + 'viewicons' : 'Ikone', + 'places' : 'Mjesta', + 'calc' : 'Računaj', + 'path' : 'Put', + 'aliasfor' : 'Drugo ime za', + 'locked' : 'Zaključano', + 'dim' : 'Dimenzije', + 'files' : 'Dokumenti', + 'folders' : 'Mape', + 'items' : 'Items', + 'yes' : 'da', + 'no' : 'ne', + 'link' : 'poveznica', + 'searcresult' : 'Rezultati pretrage', + 'selected' : 'selected items', + 'about' : 'Info', + 'shortcuts' : 'Prečaci', + 'help' : 'Pomoć', + 'webfm' : 'Web file manager', + 'ver' : 'Verzija', + 'protocolver' : 'protocol version', + 'homepage' : 'Project home', + 'docs' : 'Dokumentacija', + 'github' : 'Fork us on Github', + 'twitter' : 'Follow us on twitter', + 'facebook' : 'Join us on facebook', + 'team' : 'Tim', + 'chiefdev' : 'glavni developer', + 'developer' : 'developer', + 'contributor' : 'contributor', + 'maintainer' : 'maintainer', + 'translator' : 'translator', + 'icons' : 'Ikone', + 'dontforget' : 'and don\'t forget to take your towel', + 'shortcutsof' : 'Prečaci isključeni', + 'dropFiles' : 'Ovdje ispusti dokumente', + 'or' : 'ili', + 'selectForUpload' : 'Odaberi dokumente koje prebacuješ na server', + 'moveFiles' : 'Premjesti dokumente', + 'copyFiles' : 'Kopiraj dokumente', + 'rmFromPlaces' : 'Remove from places', + 'aspectRatio' : 'Aspect ratio', + 'scale' : 'Skaliraj', + 'width' : 'Širina', + 'height' : 'Visina', + 'resize' : 'Resize', + 'crop' : 'Crop', + 'rotate' : 'Rotate', + 'rotate-cw' : 'Rotate 90 degrees CW', + 'rotate-ccw' : 'Rotate 90 degrees CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'User', // added 18.04.2012 + 'pass' : 'Password', // added 18.04.2012 + 'confirmUnmount' : 'Are you unmount $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Drop or Paste files from browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Drop or Paste files and URLs here', // from v2.1 added 07.04.2014 + 'encoding' : 'Encoding', // from v2.1 added 19.12.2014 + 'locale' : 'Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Target: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Search by input MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Vlasnik', // from v2.1 added 20.6.2015 + 'group' : 'Grupa', // from v2.1 added 20.6.2015 + 'other' : 'Other', // from v2.1 added 20.6.2015 + 'execute' : 'Izvrši', // from v2.1 added 20.6.2015 + 'perm' : 'Dozvole', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Mapa je prazna', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Mapa je prazna\\A Dovuci dokumente koje želiš dodati', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Mapa je prazna\\A Pritisni dugo za dodavanje dokumenata', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kvaliteta', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto sync', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Gore', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Get URL link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Selected items ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Folder ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Allow offline access', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'To re-authenticate', // from v2.1.10 added 3.25.2016 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Unknown', + 'kindFolder' : 'Mapa', + 'kindAlias' : 'Drugo ime', + 'kindAliasBroken' : 'Broken alias', + // applications + 'kindApp' : 'Aplikacija', + 'kindPostscript' : 'Postscript document', + 'kindMsOffice' : 'Microsoft Office dokument', + 'kindMsWord' : 'Microsoft Word dokument', + 'kindMsExcel' : 'Microsoft Excel dokument', + 'kindMsPP' : 'Microsoft Powerpoint prezentacija', + 'kindOO' : 'Open Office dokument', + 'kindAppFlash' : 'Flash aplikacija', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent dokument', + 'kind7z' : '7z arhiva', + 'kindTAR' : 'TAR arhiva', + 'kindGZIP' : 'GZIP arhiva', + 'kindBZIP' : 'BZIP arhiva', + 'kindXZ' : 'XZ arhiva', + 'kindZIP' : 'ZIP arhiva', + 'kindRAR' : 'RAR arhiva', + 'kindJAR' : 'Java JAR dokument', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM paket', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Tekst arhiva', + 'kindTextPlain' : 'Obični tekst', + 'kindPHP' : 'PHP source', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML document', + 'kindJS' : 'Javascript source', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C source', + 'kindCHeader' : 'C header source', + 'kindCPP' : 'C++ source', + 'kindCPPHeader' : 'C++ header source', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python source', + 'kindJava' : 'Java source', + 'kindRuby' : 'Ruby source', + 'kindPerl' : 'Perl skripta', + 'kindSQL' : 'SQL source', + 'kindXML' : 'XML dokument', + 'kindAWK' : 'AWK source', + 'kindCSV' : 'vrijednosti razdvojene zarezom', + 'kindDOCBOOK' : 'Docbook XML dokument', + 'kindMarkdown' : 'Markdown tekst', // added 20.7.2015 + // images + 'kindImage' : 'slika', + 'kindBMP' : 'BMP slika', + 'kindJPEG' : 'JPEG slika', + 'kindGIF' : 'GIF slika', + 'kindPNG' : 'PNG slika', + 'kindTIFF' : 'TIFF slika', + 'kindTGA' : 'TGA slika', + 'kindPSD' : 'Adobe Photoshop slika', + 'kindXBITMAP' : 'X bitmap slika', + 'kindPXM' : 'Pixelmator slika', + // media + 'kindAudio' : 'Audio', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 lista', + 'kindVideo' : 'Video ', + 'kindVideoDV' : 'DV video', + 'kindVideoMPEG' : 'MPEG video', + 'kindVideoMPEG4' : 'MPEG-4 video', + 'kindVideoAVI' : 'AVI video', + 'kindVideoMOV' : 'Quick Time video', + 'kindVideoWM' : 'Windows Media video', + 'kindVideoFlash' : 'Flash video', + 'kindVideoMKV' : 'Matroska video', + 'kindVideoOGG' : 'Ogg video' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.hu.js b/lib/redactor/elfinder/js/i18n/elfinder.hu.js new file mode 100644 index 0000000..09cb824 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.hu.js @@ -0,0 +1,587 @@ +/** + * Hungarian translation + * @author Gáspár Lajos + * @author karrak1 + * @version 2020-11-27 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.hu = { + translator : 'Gáspár Lajos <info@glsys.eu>, karrak1', + language : 'Hungarian', + direction : 'ltr', + dateFormat : 'Y.F.d H:i:s', // will show like: 2020.November.27 20:52:18 + fancyDateFormat : '$1 H:i', // will show like: Ma 20:52 + nonameDateFormat : 'ymd-His', // noname upload will show like: 201127-205218 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Hiba', + 'errUnknown' : 'Ismeretlen hiba.', + 'errUnknownCmd' : 'Ismeretlen parancs.', + 'errJqui' : 'Hibás jQuery UI konfiguráció. A "selectable", "draggable" és a "droppable" komponensek szükségesek.', + 'errNode' : 'Az elFinder "DOM" elem létrehozását igényli.', + 'errURL' : 'Hibás elFinder konfiguráció! "URL" paraméter nincs megadva.', + 'errAccess' : 'Hozzáférés megtagadva.', + 'errConnect' : 'Nem sikerült csatlakozni a kiszolgálóhoz.', + 'errAbort' : 'Kapcsolat megszakítva.', + 'errTimeout' : 'Kapcsolat időtúllépés.', + 'errNotFound' : 'A backend nem elérhető.', + 'errResponse' : 'Hibás backend válasz.', + 'errConf' : 'Hibás backend konfiguráció.', + 'errJSON' : 'PHP JSON modul nincs telepítve.', + 'errNoVolumes' : 'Nem állnak rendelkezésre olvasható kötetek.', + 'errCmdParams' : 'érvénytelen paraméterek a parancsban. ("$1")', + 'errDataNotJSON' : 'A válasz nem JSON típusú adat.', + 'errDataEmpty' : 'Nem érkezett adat.', + 'errCmdReq' : 'A backend kérelem parancsnevet igényel.', + 'errOpen' : '"$1" megnyitása nem sikerült.', + 'errNotFolder' : 'Az objektum nem egy mappa.', + 'errNotFile' : 'Az objektum nem egy fájl.', + 'errRead' : '"$1" olvasása nem sikerült.', + 'errWrite' : '"$1" írása nem sikerült.', + 'errPerm' : 'Engedély megtagadva.', + 'errLocked' : '"$1" zárolás alatt van, és nem lehet átnevezni, mozgatni vagy eltávolítani.', + 'errExists' : '"$1" nevű fájl már létezik.', + 'errInvName' : 'Érvénytelen fáljnév.', + 'errInvDirname' : 'Invalid folder name.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Mappa nem található.', + 'errFileNotFound' : 'Fájl nem található.', + 'errTrgFolderNotFound' : 'Cél mappa nem található. ("$1")', + 'errPopup' : 'A böngésző megakadályozta egy felugró ablak megnyitását. A fájl megnyitását tegye lehetővé a böngésző beállitásaiban.', + 'errMkdir' : '"$1" mappa létrehozása sikertelen.', + 'errMkfile' : '"$1" fájl létrehozása sikertelen.', + 'errRename' : '"$1" átnevezése sikertelen.', + 'errCopyFrom' : 'Fájlok másolása a kötetről nem megengedett. ("$1")', + 'errCopyTo' : 'Fájlok másolása a kötetre nem megengedett. ("$1")', + 'errMkOutLink' : 'Hivatkozás létrehozása a root köteten kívül nem megengedett.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Feltöltési hiba.', // old name - errUploadCommon + 'errUploadFile' : 'Nem sikerült a fájlt feltölteni. ($1)', // old name - errUpload + 'errUploadNoFiles' : 'Nem található fájl feltöltéshez.', + 'errUploadTotalSize' : 'Az adat meghaladja a maximálisan megengedett méretet.', // old name - errMaxSize + 'errUploadFileSize' : 'A fájl meghaladja a maximálisan megengedett méretet.', // old name - errFileMaxSize + 'errUploadMime' : 'A fájltípus nem engedélyezett.', + 'errUploadTransfer' : '"$1" transzfer hiba.', + 'errUploadTemp' : 'Sikertelen az ideiglenes fájl léterhezozása feltöltéshez.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Az objektum "$1" már létezik ezen a helyen, és nem lehet cserélni másik típusra', // new + 'errReplace' : '"$1" nem cserélhető.', + 'errSave' : '"$1" mentése nem sikerült.', + 'errCopy' : '"$1" másolása nem sikerült.', + 'errMove' : '"$1" áthelyezése nem sikerült.', + 'errCopyInItself' : '"$1" nem másolható saját magára.', + 'errRm' : '"$1" törlése nem sikerült.', + 'errTrash' : 'Unable into trash.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Forrásfájl(ok) eltávolítása sikertelen.', + 'errExtract' : 'Nem sikerült kikibontani a "$1" fájlokat.', + 'errArchive' : 'Nem sikerült létrehozni az archívumot.', + 'errArcType' : 'Nem támogatott archívum típus.', + 'errNoArchive' : 'A fájl nem archív, vagy nem támogatott archívumtípust tartalmaz.', + 'errCmdNoSupport' : 'A backend nem támogatja ezt a parancsot.', + 'errReplByChild' : 'Az „$1” mappát nem lehet helyettesíteni egy abban található elemmel.', + 'errArcSymlinks' : 'Biztonsági okokból az archívumok kicsomagolásának megtagadása szimbolikus linkeket vagy fájlokat tartalmaz, amelyek nem engedélyezettek.', // edited 24.06.2012 + 'errArcMaxSize' : 'Az archív fájlok meghaladják a megengedett legnagyobb méretet.', + 'errResize' : 'Nem lehet átméretezni a (z) "$1".', + 'errResizeDegree' : 'Érvénytelen forgatási fok.', // added 7.3.2013 + 'errResizeRotate' : 'Nem lehet elforgatni a képet.', // added 7.3.2013 + 'errResizeSize' : 'Érvénytelen képméret.', // added 7.3.2013 + 'errResizeNoChange' : 'A kép mérete nem változott.', // added 7.3.2013 + 'errUsupportType' : 'Nem támogatott fájl típus', + 'errNotUTF8Content' : 'Az "$1" fájl nincs az UTF-8-ban, és nem szerkeszthető.', // added 9.11.2011 + 'errNetMount' : 'Nem lehet beilleszteni a(z) "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Nem támogatott protokoll.', // added 17.04.2012 + 'errNetMountFailed' : 'A csatlakozás nem sikerült.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host szükséges.', // added 18.04.2012 + 'errSessionExpires' : 'A session inaktivitás miatt lejárt.', + 'errCreatingTempDir' : 'Nem lehet ideiglenes könyvtárat létrehozni: "$1"', + 'errFtpDownloadFile' : 'Nem lehet letölteni a fájlt az FTP-ről: "$1"', + 'errFtpUploadFile' : 'Nem lehet feltölteni a fájlt az FTP-re: "$1"', + 'errFtpMkdir' : 'Nem sikerült távoli könyvtárat létrehozni az FTP-n: "$1"', + 'errArchiveExec' : 'Hiba a fájlok archiválásakor: "$1"', + 'errExtractExec' : 'Hiba a fájlok kibontásakor: "$1"', + 'errNetUnMount' : 'Nem lehet leválasztani', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Nem konvertálható UTF-8-ra', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Próbálja ki a Google Chrome-ot, ha szeretné feltölteni a mappát.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Dőtúllépés a(z) "$1" keresése közben. A keresési eredmény részleges.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Új engedélyre van szükség.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Max number of selectable items is $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Unable to restore from the trash. Can\'t identify the restore destination.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor not found to this file type.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Error occurred on the server side.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Unable to empty folder "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'There are $1 more errors.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Archívum létrehozása', + 'cmdback' : 'Vissza', + 'cmdcopy' : 'Másolás', + 'cmdcut' : 'Kivágás', + 'cmddownload' : 'Letöltés', + 'cmdduplicate' : 'Másolat készítés', + 'cmdedit' : 'Szerkesztés', + 'cmdextract' : 'Kibontás', + 'cmdforward' : 'Előre', + 'cmdgetfile' : 'Fájlok kijelölése', + 'cmdhelp' : 'Erről a programról...', + 'cmdhome' : 'Főkönyvtár', + 'cmdinfo' : 'Tulajdonságok', + 'cmdmkdir' : 'Új mappa', + 'cmdmkdirin' : 'Új mappába', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Új fájl', + 'cmdopen' : 'Megnyitás', + 'cmdpaste' : 'Beillesztés', + 'cmdquicklook' : 'Előnézet', + 'cmdreload' : 'Frissítés', + 'cmdrename' : 'Átnevezés', + 'cmdrm' : 'Törlés', + 'cmdtrash' : 'Into trash', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Restore', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Keresés', + 'cmdup' : 'Ugrás a szülőmappába', + 'cmdupload' : 'Feltöltés', + 'cmdview' : 'Nézet', + 'cmdresize' : 'Átméretezés és forgatás', + 'cmdsort' : 'Rendezés', + 'cmdnetmount' : 'Csatlakoztassa a hálózat hangerejét', // added 18.04.2012 + 'cmdnetunmount': 'Leválaszt', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Helyekhez', // added 28.12.2014 + 'cmdchmod' : 'Módváltás', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Mappa megnyitása', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Állítsa vissza az oszlop szélességét', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Full Screen', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Move', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Empty the folder', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Undo', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Redo', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferences', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Select all', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Select none', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Invert selection', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Open in new window', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Hide (Preference)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Bezár', + 'btnSave' : 'Ment', + 'btnRm' : 'Töröl', + 'btnApply' : 'Alkalmaz', + 'btnCancel' : 'Mégsem', + 'btnNo' : 'Nem', + 'btnYes' : 'Igen', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Csatlakoztat', // added 18.04.2012 + 'btnApprove': 'Tovább $1 és jóváhagyás', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Leválaszt', // from v2.1 added 30.04.2012 + 'btnConv' : 'Átalakít', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Itt', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Hangerő', // from v2.1 added 22.5.2015 + 'btnAll' : 'Összes', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Tipus', // from v2.1 added 22.5.2015 + 'btnFileName':'Fájl név', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Mentés és Kilépés', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Biztonsági mentés', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Rename', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Rename(All)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Prev ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Next ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Save As', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Mappa megnyitás', + 'ntffile' : 'Fájl megnyitás', + 'ntfreload' : 'A mappa tartalmának újratöltése', + 'ntfmkdir' : 'Mappa létrehozása', + 'ntfmkfile' : 'Fájlok létrehozása', + 'ntfrm' : 'Fájlok törélse', + 'ntfcopy' : 'Fájlok másolása', + 'ntfmove' : 'Fájlok áthelyezése', + 'ntfprepare' : 'Checking existing items', + 'ntfrename' : 'Fájlok átnevezése', + 'ntfupload' : 'Fájlok feltöltése', + 'ntfdownload' : 'Fájlok letöltése', + 'ntfsave' : 'Fájlok mentése', + 'ntfarchive' : 'Archívum létrehozása', + 'ntfextract' : 'Kibontás archívumból', + 'ntfsearch' : 'Fájlok keresése', + 'ntfresize' : 'Képek átméretezése', + 'ntfsmth' : 'Csinál valamit >_<', + 'ntfloadimg' : 'Kép betöltése', + 'ntfnetmount' : 'Hálózati meghajtó hozzáadása', // added 18.04.2012 + 'ntfnetunmount': 'Hálózati meghajtó leválasztása', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Képméret megállapítása', // added 20.05.2013 + 'ntfreaddir' : 'A mappa adatainak olvasása', // from v2.1 added 01.07.2013 + 'ntfurl' : 'A link URL-jének lekérdezése', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'A fájlmód megváltoztatása', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'A feltöltött fájlnév ellenőrzése', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Fájl létrehozása letöltésre', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Getting path infomation', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Processing the uploaded file', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Doing throw in the trash', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Doing restore from the trash', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Checking destination folder', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Undoing previous operation', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Redoing previous undone', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Checking contents', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Trash', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Ismeretlen', + 'Today' : 'Ma', + 'Yesterday' : 'Tegnap', + 'msJan' : 'jan', + 'msFeb' : 'febr', + 'msMar' : 'márc', + 'msApr' : 'ápr', + 'msMay' : 'máj', + 'msJun' : 'jún', + 'msJul' : 'júl', + 'msAug' : 'aug', + 'msSep' : 'szept', + 'msOct' : 'okt', + 'msNov' : 'nov', + 'msDec' : 'dec', + 'January' : 'Január', + 'February' : 'Február', + 'March' : 'Március', + 'April' : 'Április', + 'May' : 'Május', + 'June' : 'Június', + 'July' : 'Július', + 'August' : 'Augusztus', + 'September' : 'Szeptember', + 'October' : 'Október', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Vasárnap', + 'Monday' : 'Hétfő', + 'Tuesday' : 'Kedd', + 'Wednesday' : 'Szerda', + 'Thursday' : 'Csütörtök', + 'Friday' : 'Péntek', + 'Saturday' : 'Szombat', + 'Sun' : 'V', + 'Mon' : 'H', + 'Tue' : 'K', + 'Wed' : 'Sz', + 'Thu' : 'Cs', + 'Fri' : 'P', + 'Sat' : 'Szo', + + /******************************** sort variants ********************************/ + 'sortname' : 'név szerint', + 'sortkind' : 'by kind', + 'sortsize' : 'méret szerint', + 'sortdate' : 'dátum szerint', + 'sortFoldersFirst' : 'Először a mappák', + 'sortperm' : 'engedély alapján', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'mód szerint', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'tulajdonos alapján', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'csoportok szerint', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Also Treeview', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NewFile.txt', // added 10.11.2015 + 'untitled folder' : 'NewFolder', // added 10.11.2015 + 'Archive' : 'NewArchive', // from v2.1 added 10.11.2015 + 'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: File', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Megerősítés szükséges', + 'confirmRm' : 'Valóban törölni akarja a kijelölt adatokat?
                      Ez később nem fordítható vissza!', + 'confirmRepl' : 'Replace old file with new one? (If it contains folders, it will be merged. To backup and replace, select Backup.)', + 'confirmRest' : 'Replace existing item with the item in trash?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Nem UTF-8.
                      Átalakítsam UTF-8-ra?
                      A tartalom mentés után UTF-8 lesz..', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Character encoding of this file couldn\'t be detected. It need to temporarily convert to UTF-8 for editting.
                      Please select character encoding of this file.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Megváltozott.
                      Módosítások elvesznek, ha nem menti el azokat.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Are you sure you want to move items to trash bin?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Are you sure you want to move items to "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Mindenre vonatkozik', + 'name' : 'Név', + 'size' : 'Méret', + 'perms' : 'Jogok', + 'modify' : 'Módosítva', + 'kind' : 'Típus', + 'read' : 'olvasás', + 'write' : 'írás', + 'noaccess' : '-', + 'and' : 'és', + 'unknown' : 'ismeretlen', + 'selectall' : 'Összes kijelölése', + 'selectfiles' : 'Fájlok kijelölése', + 'selectffile' : 'Első fájl kijelölése', + 'selectlfile' : 'Utolsó fájl kijelölése', + 'viewlist' : 'Lista nézet', + 'viewicons' : 'Ikon nézet', + 'viewSmall' : 'Small icons', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Medium icons', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Large icons', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Extra large icons', // from v2.1.39 added 22.5.2018 + 'places' : 'Helyek', + 'calc' : 'Kiszámítja', + 'path' : 'Útvonal', + 'aliasfor' : 'Cél', + 'locked' : 'Zárolt', + 'dim' : 'Méretek', + 'files' : 'Fájlok', + 'folders' : 'Mappák', + 'items' : 'Elemek', + 'yes' : 'igen', + 'no' : 'nem', + 'link' : 'Parancsikon', + 'searcresult' : 'Keresés eredménye', + 'selected' : 'kijelölt elemek', + 'about' : 'Névjegy', + 'shortcuts' : 'Gyorsbillenytyűk', + 'help' : 'Súgó', + 'webfm' : 'Web file manager', + 'ver' : 'Verzió', + 'protocolver' : 'protokol verzió', + 'homepage' : 'Projekt honlap', + 'docs' : 'Dokumentáció', + 'github' : 'Hozz létre egy új verziót a Github-on', + 'twitter' : 'Kövess minket a twitter-en', + 'facebook' : 'Csatlakozz hozzánk a facebook-on', + 'team' : 'Csapat', + 'chiefdev' : 'vezető fejlesztő', + 'developer' : 'fejlesztő', + 'contributor' : 'külsős hozzájáruló', + 'maintainer' : 'karbantartó', + 'translator' : 'fordító', + 'icons' : 'Ikonok', + 'dontforget' : 'törölközőt ne felejts el hozni!', + 'shortcutsof' : 'Shortcuts disabled', + 'dropFiles' : 'Fájlok dobása ide', + 'or' : 'vagy', + 'selectForUpload' : 'fájlok böngészése', + 'moveFiles' : 'Fájlok áthelyezése', + 'copyFiles' : 'Fájlok másolása', + 'restoreFiles' : 'Restore items', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Távolítsa el a helyekről', + 'aspectRatio' : 'Oldalarány', + 'scale' : 'Skála', + 'width' : 'Szélesség', + 'height' : 'Magasság', + 'resize' : 'Átméretezés', + 'crop' : 'Vág', + 'rotate' : 'Forgat', + 'rotate-cw' : 'Forgassa el 90 fokkal', + 'rotate-ccw' : 'Forgassa el 90 fokkal CCW irányban', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protokoll', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Felhasználó', // added 18.04.2012 + 'pass' : 'Jelszó', // added 18.04.2012 + 'confirmUnmount' : 'Leválasztod $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Fájlok dobása vagy beillesztése a böngészőből', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Drop files, Paste URLs or images(clipboard) here', // from v2.1 added 07.04.2014 + 'encoding' : 'Kódolás', // from v2.1 added 19.12.2014 + 'locale' : 'Nyelv', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Cél: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Keresés a MIME típus bevitele alapján', // from v2.1 added 22.5.2015 + 'owner' : 'Tulajdonos', // from v2.1 added 20.6.2015 + 'group' : 'Csoport', // from v2.1 added 20.6.2015 + 'other' : 'Egyéb', // from v2.1 added 20.6.2015 + 'execute' : 'Végrehajt', // from v2.1 added 20.6.2015 + 'perm' : 'Engedély', // from v2.1 added 20.6.2015 + 'mode' : 'Mód', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'A mappa üres', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'A mappa üres\\Elem eldobása', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'A mappa üres\\Hosszú koppintás elemek hozzáadásához', // from v2.1.6 added 30.12.2015 + 'quality' : 'Minőség', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto sync', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Mozgatás fel', // from v2.1.6 added 18.1.2016 + 'getLink' : 'URL-link letöltése', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Kiválasztott elemek ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Mappa ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Offline hozzáférés engedélyezése', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Újrahitelesítéshez', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Most betölt...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Több fájl megnyitása', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Megpróbálja megnyitni a $1 fájlokat. Biztosan meg akarja nyitni a böngészőben?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Search results is empty in search target.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'It is editing a file.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1 elemet választott ki.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '$1 elem van a vágólapon.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Incremental search is only from the current view.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Reinstate', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 complete', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Context menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Page turning', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016 + 'reset' : 'Reset', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Background color', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Color picker', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Grid', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Enabled', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Disabled', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Search results is empty in current view.\\APress [Enter] to expand search target.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'First letter search results is empty in current view.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Text label', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 mins left', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Select folder', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'First letter search', // from v2.1.23 added 24.3.2017 + 'presets' : 'Presets', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'It\'s too many items so it can\'t into trash.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Empty the folder "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'There are no items in a folder "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preference', // from v2.1.26 added 28.6.2017 + 'language' : 'Language', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialize the settings saved in this browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Toolbar settings', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 chars left.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 lines left.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Sum', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Rough file size', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focus on the element of dialog with mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Select', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Action when select file', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Open with the editor used last time', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Invert selection', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Are you sure you want to rename $1 selected items like $2?
                      This cannot be undone!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch rename', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Number', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Add prefix', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Add suffix', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Change extention', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Columns settings (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'All changes will reflect immediately to the archive.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Any changes will not reflect until un-mount this volume.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Selection Info', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorithms to show the file hash', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Press again to exit.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Toolbar', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Work Space', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'All', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Icon Size (Icons view)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Open the maximized editor window', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Because conversion by API is not currently available, please convert on the website.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Convert on the site of $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrations', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'This elFinder has the following external services integrated. Please check the terms of use, privacy policy, etc. before using it.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Show hidden items', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Hide hidden items', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Show/Hide hidden items', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'File types to enable with "New file"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type of the Text file', // from v2.1.41 added 7.8.2018 + 'add' : 'Add', // from v2.1.41 added 7.8.2018 + 'theme' : 'Theme', // from v2.1.43 added 19.10.2018 + 'default' : 'Default', // from v2.1.43 added 19.10.2018 + 'description' : 'Description', // from v2.1.43 added 19.10.2018 + 'website' : 'Website', // from v2.1.43 added 19.10.2018 + 'author' : 'Author', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'License', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'This item can\'t be saved. To avoid losing the edits you need to export to your PC.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Double click on the file to select it.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Use fullscreen mode', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Ismeretlen', + 'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Mappa', + 'kindSelects' : 'Selections', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Parancsikon', + 'kindAliasBroken' : 'Hibás parancsikon', + // applications + 'kindApp' : 'Alkalmazás', + 'kindPostscript' : 'Postscript dokumentum', + 'kindMsOffice' : 'Microsoft Office dokumentum', + 'kindMsWord' : 'Microsoft Word dokumentum', + 'kindMsExcel' : 'Microsoft Excel dokumentum', + 'kindMsPP' : 'Microsoft Powerpoint bemutató', + 'kindOO' : 'Open Office dokumentum', + 'kindAppFlash' : 'Flash alkalmazás', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent fájl', + 'kind7z' : '7z archívum', + 'kindTAR' : 'TAR archívum', + 'kindGZIP' : 'GZIP archívum', + 'kindBZIP' : 'BZIP archívum', + 'kindXZ' : 'XZ archívum', + 'kindZIP' : 'ZIP archívum', + 'kindRAR' : 'RAR archívum', + 'kindJAR' : 'Java JAR fájl', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM csomag', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Szöveges dokumentum', + 'kindTextPlain' : 'Plain text', + 'kindPHP' : 'PHP forráskód', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML dokumentum', + 'kindJS' : 'Javascript forráskód', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C forráskód', + 'kindCHeader' : 'C header forráskód', + 'kindCPP' : 'C++ forráskód', + 'kindCPPHeader' : 'C++ header forráskód', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python forráskód', + 'kindJava' : 'Java forráskód', + 'kindRuby' : 'Ruby forráskód', + 'kindPerl' : 'Perl script', + 'kindSQL' : 'SQL forráskód', + 'kindXML' : 'XML dokumentum', + 'kindAWK' : 'AWK forráskód', + 'kindCSV' : 'Comma separated values', + 'kindDOCBOOK' : 'Docbook XML dokumentum', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Kép', + 'kindBMP' : 'BMP kép', + 'kindJPEG' : 'JPEG kép', + 'kindGIF' : 'GIF kép', + 'kindPNG' : 'PNG kép', + 'kindTIFF' : 'TIFF kép', + 'kindTGA' : 'TGA kép', + 'kindPSD' : 'Adobe Photoshop kép', + 'kindXBITMAP' : 'X bitmap image', + 'kindPXM' : 'Pixelmator image', + // media + 'kindAudio' : 'Hangfájl', + 'kindAudioMPEG' : 'MPEG hangfájl', + 'kindAudioMPEG4' : 'MPEG-4 hangfájl', + 'kindAudioMIDI' : 'MIDI hangfájl', + 'kindAudioOGG' : 'Ogg Vorbis hangfájl', + 'kindAudioWAV' : 'WAV hangfájl', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Film', + 'kindVideoDV' : 'DV film', + 'kindVideoMPEG' : 'MPEG film', + 'kindVideoMPEG4' : 'MPEG-4 film', + 'kindVideoAVI' : 'AVI film', + 'kindVideoMOV' : 'Quick Time film', + 'kindVideoWM' : 'Windows Media film', + 'kindVideoFlash' : 'Flash film', + 'kindVideoMKV' : 'Matroska film', + 'kindVideoOGG' : 'Ogg film' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.id.js b/lib/redactor/elfinder/js/i18n/elfinder.id.js new file mode 100644 index 0000000..207802f --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.id.js @@ -0,0 +1,505 @@ +/** + * Bahasa Indonesia translation + * @author Suyadi <1441177004009@student.unsika.ac.id> + * @author Ammar Faizi + * @version 2017-05-28 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.id = { + translator : 'Suyadi <1441177004009@student.unsika.ac.id>, Ammar Faizi <ammarfaizi2@gmail.com>', + language : 'Bahasa Indonesia', + direction : 'ltr', + dateFormat : 'j F, Y H:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'd m Y - H : i : s', // to apply if upload file is noname: 120513172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Kesalahan', + 'errUnknown' : 'Kesalahan tak dikenal.', + 'errUnknownCmd' : 'Perintah tak dikenal.', + 'errJqui' : 'Konfigurasi jQuery UI tidak valid. Komponen pemilih, penyeret dan penaruh harus disertakan.', + 'errNode' : 'elFinder membutuhkan pembuatan elemen DOM.', + 'errURL' : 'Konfigurasi elFinder tidak valid! opsi URL belum diatur.', + 'errAccess' : 'Akses ditolak.', + 'errConnect' : 'Tidak dapat tersambung ke backend.', + 'errAbort' : 'Koneksi dibatalkan.', + 'errTimeout' : 'Waktu koneksi habis.', + 'errNotFound' : 'Backend tidak ditemukan.', + 'errResponse' : 'Respon backend tidak valid.', + 'errConf' : 'Konfigurasi elFinder tidak valid.', + 'errJSON' : 'Modul PHP JSON belum terpasang.', + 'errNoVolumes' : 'Tidak tersedia ruang kosong.', + 'errCmdParams' : 'Parameter perintah "$1" tidak valid.', + 'errDataNotJSON' : 'Data bukan merupakan JSON.', + 'errDataEmpty' : 'Data masih kosong.', + 'errCmdReq' : 'Permintaan ke backend membutuhkan nama perintah.', + 'errOpen' : 'Tidak dapat membuka "$1".', + 'errNotFolder' : 'Obyek ini bukan folder.', + 'errNotFile' : 'Obyek ini bukan berkas.', + 'errRead' : 'Tidak dapat membaca "$1".', + 'errWrite' : 'Tidak dapat menulis ke "$1".', + 'errPerm' : 'Ijin ditolak.', + 'errLocked' : '"$1" ini terkunci dan tak dapat dipidahkan, diubah atau dihapus.', + 'errExists' : 'Berkas bernama "$1" sudah ada.', + 'errInvName' : 'Nama berkas tidak valid.', + 'errInvDirname' : 'Nama folder salah.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Folder tidak ditemukan.', + 'errFileNotFound' : 'Berkas tidak ditemukan.', + 'errTrgFolderNotFound' : 'Folder tujuan "$1" tidak ditemukan.', + 'errPopup' : 'Peramban anda mencegah untuk membuka jendela munculan. Untuk dapat membuka berkas ini ubah pengaturan pada peramban anda.', + 'errMkdir' : 'Tidak dapat membuat folder "$1".', + 'errMkfile' : 'Tidak dapat membuat berkas "$1".', + 'errRename' : 'Tidak dapat mengubah nama "$1".', + 'errCopyFrom' : 'Tidak diizinkan menyalin berkas dari volume "$1".', + 'errCopyTo' : 'tidak diizinkan menyalin berkas ke volume "$1".', + 'errMkOutLink' : 'Tidak dapat membuat tautan diluar volume root.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Kesalahan saat mengunggah.', // old name - errUploadCommon + 'errUploadFile' : 'Tidak dapat mengunggah "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Tak ada berkas untuk diunggah.', + 'errUploadTotalSize' : 'Data melampaui ukuran yang diperbolehkan.', // old name - errMaxSize + 'errUploadFileSize' : 'Berkas melampaui ukuran yang diperbolehkan.', // old name - errFileMaxSize + 'errUploadMime' : 'Jenis berkas ini tidak diijinkan.', + 'errUploadTransfer' : 'Kesalahan transfer "$1".', + 'errUploadTemp' : 'Tidak dapat membuat file sementara untuk diupload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Obyek "$1" sudah ada di lokasi ini dan tidak dapat ditimpa oleh obyek jenis lain.', // new + 'errReplace' : 'Tidak dapat menimpa "$1".', + 'errSave' : 'Tidak dapat menyimpan "$1".', + 'errCopy' : 'Tidak dapat menyalin "$1".', + 'errMove' : 'Tidak dapat memindahkan "$1".', + 'errCopyInItself' : 'Tidak dapat menyalin "$1" ke dirinya sendiri.', + 'errRm' : 'Tidak dapat menghapus "$1".', + 'errTrash' : 'Tidak dapat masuk ke tempat sampah.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Tidak dapat menghapus sumber berkas.', + 'errExtract' : 'Tidak dapat mengekstrak berkas dari "$1".', + 'errArchive' : 'Tidak dapat membuat arsip.', + 'errArcType' : 'Jenis arsip tidak didukung.', + 'errNoArchive' : 'Berkas ini bukan arsip atau arsip jenis ini tidak didukung.', + 'errCmdNoSupport' : 'Backend tidak mendukung perintah ini.', + 'errReplByChild' : 'Folder “$1” tidak dapat ditimpa dengan berkas didalamnya.', + 'errArcSymlinks' : 'Untuk keamanan tak diijinkan mengekstrak arsip berisi symlink atau jenis berkas yang tak diijinkan.', // edited 24.06.2012 + 'errArcMaxSize' : 'Arsip ini melampaui ukuran yang diijinkan.', + 'errResize' : 'Tidak dapat mengubah ukuran "$1".', + 'errResizeDegree' : 'Derajat putaran tidak valid.', // added 7.3.2013 + 'errResizeRotate' : 'Citra tidak diputar.', // added 7.3.2013 + 'errResizeSize' : 'Ukuran citra tidak valid.', // added 7.3.2013 + 'errResizeNoChange' : 'Ukuran citra tidak diubah.', // added 7.3.2013 + 'errUsupportType' : 'Jenis berkas tidak didukung.', + 'errNotUTF8Content' : 'Berkas "$1" tidak dalam format UTF-8 dan tidak dapat disunting.', // added 9.11.2011 + 'errNetMount' : 'Tidak dapat membaca susunan "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protokol tidak didukung.', // added 17.04.2012 + 'errNetMountFailed' : 'Tidak dapat membaca susunannya.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host harus ada.', // added 18.04.2012 + 'errSessionExpires' : 'Sesi anda telah kadaluwarsa karena lama tidak aktif.', + 'errCreatingTempDir' : 'Tidak dapat membuat direktori sementara: "$1"', + 'errFtpDownloadFile' : 'Tidak dapat mengunduh berkas dari FTP: "$1"', + 'errFtpUploadFile' : 'Tidak dapat mengunggah berkas dari FTP: "$1"', + 'errFtpMkdir' : 'Tidak dapat membuat remot direktori dari FTP: "$1"', + 'errArchiveExec' : 'Kesalahan saat mengarsipkan berkas: "$1"', + 'errExtractExec' : 'Kesalahan saat mengekstrak berkas: "$1"', + 'errNetUnMount' : 'Tidak dapat melakukan mount.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Tidak cocok untuk konversi ke UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Coba dengan browser yang modern, Jika akan mengupload folder.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Waktu habis selama melakukan pencarian "$1". Hasil sementara.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Re-authorization dibutuhkan.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Berkas maksimal yang dipilih adalah $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Tidak dapat mengembalikan berkas dari tempat sampah. Tujuan tidak ditemukan.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Tidak ditemukan editor untuk file tipe ini.', // from v2.1.25 added 23.5.2017 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Buat arsip', + 'cmdback' : 'Kembali', + 'cmdcopy' : 'Salin', + 'cmdcut' : 'Potong', + 'cmddownload' : 'Unduh', + 'cmdduplicate' : 'Gandakan', + 'cmdedit' : 'Sunting berkas', + 'cmdextract' : 'Ekstrak berkas dari arsip', + 'cmdforward' : 'Maju', + 'cmdgetfile' : 'Pilih berkas', + 'cmdhelp' : 'Tentang software ini', + 'cmdhome' : 'Rumah', + 'cmdinfo' : 'Dapatkan info', + 'cmdmkdir' : 'Buat folder', + 'cmdmkdirin' : 'Masuk ke folder baru', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Buat fail', + 'cmdopen' : 'Buka', + 'cmdpaste' : 'Tempel', + 'cmdquicklook' : 'Pratinjau', + 'cmdreload' : 'Muat-ulang', + 'cmdrename' : 'Ganti nama', + 'cmdrm' : 'Hapus', + 'cmdtrash' : 'Sampahkan', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Kembalikan', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Cari berkas', + 'cmdup' : 'Ke direktori utama', + 'cmdupload' : 'Unggah berkas', + 'cmdview' : 'Lihat', + 'cmdresize' : 'Ubah ukuran & Putar', + 'cmdsort' : 'Urutkan', + 'cmdnetmount' : 'Baca-susun volume jaringan', // added 18.04.2012 + 'cmdnetunmount': 'Unmount', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Ke Tempat', // added 28.12.2014 + 'cmdchmod' : 'Mode mengubah', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Membuka folder', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Reset column width', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Layar Penuh', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Pindah', // from v2.1.15 added 21.08.2016 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Tutup', + 'btnSave' : 'Simpan', + 'btnRm' : 'Buang', + 'btnApply' : 'Terapkan', + 'btnCancel' : 'Batal', + 'btnNo' : 'Tidak', + 'btnYes' : 'Ya', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Baca susunan', // added 18.04.2012 + 'btnApprove': 'Menuju ke $1 & setujui', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Konversi', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Disini', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'Semua', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Type', // from v2.1 added 22.5.2015 + 'btnFileName':'Nama file', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Simpan & Tutup', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Ubah nama', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Ubah nama(Semua)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Sebelumnya ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Selanjutnya ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Simpan sebagai', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Buka folder', + 'ntffile' : 'Buka berkas', + 'ntfreload' : 'Muat-ulang isi folder', + 'ntfmkdir' : 'Membuat direktori', + 'ntfmkfile' : 'Membuat berkas', + 'ntfrm' : 'Menghapus berkas', + 'ntfcopy' : 'Salin berkas', + 'ntfmove' : 'Pindahkan berkas', + 'ntfprepare' : 'Persiapan menyalin berkas', + 'ntfrename' : 'Ubah nama berkas', + 'ntfupload' : 'Unggah berkas', + 'ntfdownload' : 'Mengunduh berkas', + 'ntfsave' : 'Simpan berkas', + 'ntfarchive' : 'Membuat arsip', + 'ntfextract' : 'Mengekstrak berkas dari arsip', + 'ntfsearch' : 'Mencari berkas', + 'ntfresize' : 'Mengubah ukuran citra', + 'ntfsmth' : 'Melakukan sesuatu', + 'ntfloadimg' : 'Memuat citra', + 'ntfnetmount' : 'Membaca susunan volume jaringan', // added 18.04.2012 + 'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Mendapatkan dimensi citra', // added 20.05.2013 + 'ntfreaddir' : 'Membaca informasi folder', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Mendapatkan URL dari link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Dalam mode mengubah', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Sedang memverifikasi nama file yang diupload', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Membuat file untuk didownload', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Mengambil informasi path', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Sedang mengupload file', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Sedang melempar ke tempat sampah', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Sedang mengembalikan dari tempat sampah', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Mengecek folder tujuan', // from v2.1.24 added 3.5.2017 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Sampah', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'tak diketahui', + 'Today' : 'Hari ini', + 'Yesterday' : 'Kemarin', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Mei', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Agt', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nop', + 'msDec' : 'Des', + 'January' : 'Januari', + 'February' : 'Pebruari', + 'March' : 'Maret', + 'April' : 'April', + 'May' : 'Mei', + 'June' : 'Juni', + 'July' : 'Juli', + 'August' : 'Agustus', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'Nopember', + 'December' : 'Desember', + 'Sunday' : 'Minggu', + 'Monday' : 'Senin', + 'Tuesday' : 'Selasa', + 'Wednesday' : 'Rabu', + 'Thursday' : 'Kamis', + 'Friday' : 'Jum \'at', + 'Saturday' : 'Sabtu', + 'Sun' : 'Min', + 'Mon' : 'Sen', + 'Tue' : 'Sel', + 'Wed' : 'Rab', + 'Thu' : 'Kam', + 'Fri' : 'Jum', + 'Sat' : 'Sab', + + /******************************** sort variants ********************************/ + 'sortname' : 'menurut nama', + 'sortkind' : 'menurut jenis', + 'sortsize' : 'menurut ukuran', + 'sortdate' : 'menurut tanggal', + 'sortFoldersFirst' : 'Utamakan folder', + 'sortperm' : 'menurut perizinan', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'menurut mode', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'menurut pemilik', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'menurut grup', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Also Treeview', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'FileBaru.txt', // added 10.11.2015 + 'untitled folder' : 'FolderBaru', // added 10.11.2015 + 'Archive' : 'ArsipBaru', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'Diperlukan konfirmasi', + 'confirmRm' : 'Anda yakin akan menghapus berkas?
                      Ini tidak dapat kembalikan!', + 'confirmRepl' : 'Timpa berkas lama dengan yang baru?', + 'confirmRest' : 'Timpa berkas yang ada dengan berkas dari sampah?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Bukan UTF-8
                      Konversi ke UTF-8?
                      Konten akan berubah menjadi UTF-8 ketika disimpan dengan konversi.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Character encoding of this file couldn\'t be detected. It need to temporarily convert to UTF-8 for editting.
                      Please select character encoding of this file.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Telah terjadi perubahan.
                      Kehilangan perkerjaan jika kamu tidak menyimpan.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Anda yakin untuk membuang berkas ke tempat sampah?', //from v2.1.24 added 29.4.2017 + 'apllyAll' : 'Terapkan ke semua', + 'name' : 'Nama', + 'size' : 'Ukuran', + 'perms' : 'Perijinan', + 'modify' : 'Diubah', + 'kind' : 'Jenis', + 'read' : 'baca', + 'write' : 'tulis', + 'noaccess' : 'tidak ada akses', + 'and' : 'dan', + 'unknown' : 'tak diketahui', + 'selectall' : 'Pilih semua berkas', + 'selectfiles' : 'Pilih berkas', + 'selectffile' : 'Pilih berkas pertama', + 'selectlfile' : 'Pilih berkas terakhir', + 'viewlist' : 'Tampilan daftar', + 'viewicons' : 'Tampilan ikon', + 'places' : 'Lokasi', + 'calc' : 'Hitung', + 'path' : 'Alamat', + 'aliasfor' : 'Nama lain untuk', + 'locked' : 'Dikunci', + 'dim' : 'Dimensi', + 'files' : 'Berkas', + 'folders' : 'Folder', + 'items' : 'Pokok', + 'yes' : 'ya', + 'no' : 'tidak', + 'link' : 'Tautan', + 'searcresult' : 'Hasil pencarian', + 'selected' : 'Pokok terpilih', + 'about' : 'Tentang', + 'shortcuts' : 'Pintasan', + 'help' : 'Bantuan', + 'webfm' : 'Pengelola berkas web', + 'ver' : 'Versi', + 'protocolver' : 'versi protokol', + 'homepage' : 'Rumah proyek', + 'docs' : 'Dokumentasi', + 'github' : 'Ambil kami di Github', + 'twitter' : 'Ikuti kami di twitter', + 'facebook' : 'Gabung dengan kami di facebook', + 'team' : 'Tim', + 'chiefdev' : 'kepala pengembang', + 'developer' : 'pengembang', + 'contributor' : 'kontributor', + 'maintainer' : 'pengurus', + 'translator' : 'penerjemah', + 'icons' : 'Ikon', + 'dontforget' : 'dan jangan lupa pakai handukmu', + 'shortcutsof' : 'Pintasan dimatikan', + 'dropFiles' : 'Seret berkas anda kesini', + 'or' : 'atau', + 'selectForUpload' : 'Pilih berkas untuk diunggah', + 'moveFiles' : 'Pindahkan berkas', + 'copyFiles' : 'Salin berkas', + 'restoreFiles' : 'Kembalikan berkas', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Hapus dari lokasi', + 'aspectRatio' : 'Aspek rasio', + 'scale' : 'Skala', + 'width' : 'Lebar', + 'height' : 'Tinggi', + 'resize' : 'Ubah ukuran', + 'crop' : 'Potong', + 'rotate' : 'Putar', + 'rotate-cw' : 'Putar 90 derajat ke kanan', + 'rotate-ccw' : 'Putar 90 derajat ke kiri', + 'degree' : '°', + 'netMountDialogTitle' : 'Baca susunan volume jaringan', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Pengguna', // added 18.04.2012 + 'pass' : 'Sandi', // added 18.04.2012 + 'confirmUnmount' : 'Apakah anda unmount $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Seret atau Tempel file dari browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Seret file, Tempel URL atau gambar dari clipboard', // from v2.1 added 07.04.2014 + 'encoding' : 'Encoding', // from v2.1 added 19.12.2014 + 'locale' : 'Lokasi', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Target: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Mencari berdasarkan inpu MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Pemilik', // from v2.1 added 20.6.2015 + 'group' : 'Grup', // from v2.1 added 20.6.2015 + 'other' : 'Lainnya', // from v2.1 added 20.6.2015 + 'execute' : 'Eksekusi', // from v2.1 added 20.6.2015 + 'perm' : 'Izin', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Folder kosong', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Folder kosong\\A Seret untuk tambahkan berkas', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Folder kosong\\A Tekan yang lama untuk tambahkan berkas', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kualitas', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Sinkronasi Otomatis', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Pindah ke atas', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Mendepatkan URL link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : '($1) berkas dipilih', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID Folder', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Izin akses offline', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'To re-authenticate', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Sedang memuat...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Membuka file bersamaan', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Anda mencoba membuka file $1. Apakah anda ingin membuka di browser?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Hasil pencarian kosong dalam target', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Sedang mengedit file', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Anda memilih $1 berkas', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Kamu mempunyai $i berkas di clipboard', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Hanya pencarian bertamah untuk menampilkan tampilan sekarang', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Reinstate', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 selesai', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Context menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Page turning', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016 + 'reset' : 'Reset', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Warna background', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Mengambil warna', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Grid', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Diaktifkan', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Nonaktifkan', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Search results is empty in current view.\\APress [Enter] to expand search target.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'First letter search results is empty in current view.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Text label', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 mins left', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Select folder', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'First letter search', // from v2.1.23 added 24.3.2017 + 'presets' : 'Presets', // from v2.1.25 added 26.5.2017 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Tak diketahui', + 'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Folder', + 'kindAlias' : 'Nama lain', + 'kindAliasBroken' : 'Nama lain rusak', + // applications + 'kindApp' : 'Aplikasi', + 'kindPostscript' : 'Dokumen postscript', + 'kindMsOffice' : 'Dokumen Ms. Office', + 'kindMsWord' : 'Dokumen Ms. Word', + 'kindMsExcel' : 'Dokumen Ms. Excel', + 'kindMsPP' : 'Dokumen Ms. Powerpoint', + 'kindOO' : 'Dokumen Open Office', + 'kindAppFlash' : 'Aplikasi Flash', + 'kindPDF' : 'Portable Dokumen Format (PDF)', + 'kindTorrent' : 'Berkas Bittorrent', + 'kind7z' : 'Arsip 7z', + 'kindTAR' : 'Arsip TAR', + 'kindGZIP' : 'Arsip GZIP', + 'kindBZIP' : 'Arsip BZIP', + 'kindXZ' : 'Arsip XZ', + 'kindZIP' : 'Arsip ZIP', + 'kindRAR' : 'Arsip RAR', + 'kindJAR' : 'Berkas Java JAR', + 'kindTTF' : 'Huruf True Type', + 'kindOTF' : 'Huruf Open Type', + 'kindRPM' : 'Paket RPM', + // fonts + 'kindFont' : 'Huruf', + 'kindSFNT' : 'Huruf SFNT', + 'kindEOT' : 'Huruf Embedded Open Type', + 'kindWOFF' : 'Huruf Web Open Font Format', + 'kindWOFF2' : 'Huruf Web Open Font Format 2', + // texts + 'kindText' : 'Dokumen teks', + 'kindTextPlain' : 'Berkas teks biasa', + 'kindPHP' : 'Kode-sumber PHP', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'Dokumen HTML', + 'kindJS' : 'Kode-sumber Javascript', + 'kindRTF' : 'Berkas Rich Text', + 'kindC' : 'Kode-sumber C', + 'kindCHeader' : 'Kode-sumber header C', + 'kindCPP' : 'Kode-sumber C++', + 'kindCPPHeader' : 'Kode-sumber header C++', + 'kindShell' : 'Berkas shell Unix', + 'kindPython' : 'Kode-sumber Python', + 'kindJava' : 'Kode-sumber Java', + 'kindRuby' : 'Kode-sumber Ruby', + 'kindPerl' : 'Kode-sumber Perl', + 'kindSQL' : 'Kode-sumber SQL', + 'kindXML' : 'Dokumen XML', + 'kindAWK' : 'Kode-sumber AWK', + 'kindCSV' : 'Dokumen CSV', + 'kindDOCBOOK' : 'Dokumen Docbook XML', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Citra', + 'kindBMP' : 'Citra BMP', + 'kindJPEG' : 'Citra JPEG', + 'kindGIF' : 'Citra GIF', + 'kindPNG' : 'Citra PNG', + 'kindTIFF' : 'Citra TIFF', + 'kindTGA' : 'Citra TGA', + 'kindPSD' : 'Citra Adobe Photoshop', + 'kindXBITMAP' : 'Citra X bitmap', + 'kindPXM' : 'Citra Pixelmator', + // media + 'kindAudio' : 'Berkas audio', + 'kindAudioMPEG' : 'Berkas audio MPEG', + 'kindAudioMPEG4' : 'Berkas audio MPEG-4', + 'kindAudioMIDI' : 'Berkas audio MIDI', + 'kindAudioOGG' : 'Berkas audio Ogg Vorbis', + 'kindAudioWAV' : 'Berkas audio WAV', + 'AudioPlaylist' : 'Berkas daftar putar MP3', + 'kindVideo' : 'Berkas video', + 'kindVideoDV' : 'Berkas video DV', + 'kindVideoMPEG' : 'Berkas video MPEG', + 'kindVideoMPEG4' : 'Berkas video MPEG-4', + 'kindVideoAVI' : 'Berkas video AVI', + 'kindVideoMOV' : 'Berkas video Quick Time', + 'kindVideoWM' : 'Berkas video Windows Media', + 'kindVideoFlash' : 'Berkas video Flash', + 'kindVideoMKV' : 'Berkas video Matroska', + 'kindVideoOGG' : 'Berkas video Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.it.js b/lib/redactor/elfinder/js/i18n/elfinder.it.js new file mode 100644 index 0000000..ed77073 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.it.js @@ -0,0 +1,591 @@ +/** + * Italiano translation + * @author Alberto Tocci (alberto.tocci@gmail.com) + * @author Claudio Nicora (coolsoft.ita@gmail.com) + * @author Stefano Galeazzi + * @author Thomas Camaran + * @author Fabio Ferrero + * @version 2023-04-21 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.it = { + translator : 'Alberto Tocci (alberto.tocci@gmail.com), Claudio Nicora (coolsoft.ita@gmail.com), Stefano Galeazzi <stefano.galeazzi@probanet.it>, Thomas Camaran <camaran@gmail.com>, Fabio Ferrero <fabioferrero@gmail.com>', + language : 'Italiano', + direction : 'ltr', + dateFormat : 'd/m/Y H:i', // will show like: 21/04/2023 16:21 + fancyDateFormat : '$1 H:i', // will show like: Oggi 16:21 + nonameDateFormat : 'ymd-His', // noname upload will show like: 230421-162111 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Errore', + 'errUnknown' : 'Errore sconosciuto.', + 'errUnknownCmd' : 'Comando sconosciuto.', + 'errJqui' : 'Configurazione JQuery UI non valida. Devono essere inclusi i plugin Selectable, Draggable e Droppable.', + 'errNode' : 'elFinder necessita dell\'elemento DOM per essere inizializzato.', + 'errURL' : 'Configurazione non valida.Il parametro URL non è settato.', + 'errAccess' : 'Accesso negato.', + 'errConnect' : 'Impossibile collegarsi al backend.', + 'errAbort' : 'Connessione annullata.', + 'errTimeout' : 'Timeout di connessione.', + 'errNotFound' : 'Backend non trovato.', + 'errResponse' : 'Risposta non valida dal backend.', + 'errConf' : 'Configurazione backend non valida.', + 'errJSON' : 'Modulo PHP JSON non installato.', + 'errNoVolumes' : 'Non è stato possibile leggere i volumi.', + 'errCmdParams' : 'Parametri non validi per il comando "$1".', + 'errDataNotJSON' : 'I dati non sono nel formato JSON.', + 'errDataEmpty' : 'Stringa vuota.', + 'errCmdReq' : 'La richiesta al backend richiede il nome del comando.', + 'errOpen' : 'Impossibile aprire "$1".', + 'errNotFolder' : 'L\'oggetto non è una cartella..', + 'errNotFile' : 'L\'oggetto non è un file.', + 'errRead' : 'Impossibile leggere "$1".', + 'errWrite' : 'Non è possibile scrivere in "$1".', + 'errPerm' : 'Permesso negato.', + 'errLocked' : '"$1" è bloccato e non può essere rinominato, spostato o eliminato.', + 'errExists' : 'Il file "$1" è già esistente.', + 'errInvName' : 'Nome file non valido.', + 'errInvDirname' : 'Nome cartella non valido.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Cartella non trovata.', + 'errFileNotFound' : 'File non trovato.', + 'errTrgFolderNotFound' : 'La cartella di destinazione"$1" non è stata trovata.', + 'errPopup' : 'Il tuo Browser non consente di aprire finestre di pop-up. Per aprire il file abilita questa opzione nelle impostazioni del tuo Browser.', + 'errMkdir' : 'Impossibile creare la cartella "$1".', + 'errMkfile' : 'Impossibile creare il file "$1".', + 'errRename' : 'Impossibile rinominare "$1".', + 'errCopyFrom' : 'Non è possibile copiare file da "$1".', + 'errCopyTo' : 'Non è possibile copiare file in "$1".', + 'errMkOutLink' : 'Impossibile creare un link all\'esterno della radice del volume.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Errore di Caricamento.', // old name - errUploadCommon + 'errUploadFile' : 'Impossibile Caricare "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Non sono stati specificati file da caricare.', + 'errUploadTotalSize' : 'La dimensione totale dei file supera il limite massimo consentito.', // old name - errMaxSize + 'errUploadFileSize' : 'Le dimensioni del file superano il massimo consentito.', // old name - errFileMaxSize + 'errUploadMime' : 'FileType non consentito.', + 'errUploadTransfer' : 'Trasferimento errato del file "$1".', + 'errUploadTemp' : 'Impossibile creare il file temporaneo per l\'upload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'L\'oggetto "$1" esiste già in questa cartella e non può essere sostituito con un oggetto di un tipo differente.', // new + 'errReplace' : 'Impossibile sostituire "$1".', + 'errSave' : 'Impossibile salvare "$1".', + 'errCopy' : 'Impossibile copiare "$1".', + 'errMove' : 'Impossibile spostare "$1".', + 'errCopyInItself' : 'Sorgente e destinazione risultato essere uguali.', + 'errRm' : 'Impossibile rimuovere "$1".', + 'errTrash' : 'Impossibile cestinare.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Impossibile eliminare i file origine.', + 'errExtract' : 'Impossibile estrarre file da "$1".', + 'errArchive' : 'Impossibile creare archivio.', + 'errArcType' : 'Tipo di archivio non supportato.', + 'errNoArchive' : 'Il file non è un archivio o contiene file non supportati.', + 'errCmdNoSupport' : 'Il Backend non supporta questo comando.', + 'errReplByChild' : 'La cartella $1 non può essere sostituita da un oggetto in essa contenuto.', + 'errArcSymlinks' : 'Per questioni di sicurezza non è possibile estrarre archivi che contengono collegamenti..', // edited 24.06.2012 + 'errArcMaxSize' : 'La dimensione dell\'archivio supera le massime dimensioni consentite.', + 'errResize' : 'Impossibile ridimensionare "$1".', + 'errResizeDegree' : 'Angolo di rotazione non valido.', // added 7.3.2013 + 'errResizeRotate' : 'Impossibile ruotare l\'immagine.', // added 7.3.2013 + 'errResizeSize' : 'Dimensione dell\'immagine non valida.', // added 7.3.2013 + 'errResizeNoChange' : 'Dimensione dell\'immagine non modificata.', // added 7.3.2013 + 'errUsupportType' : 'Tipo di file non supportato.', + 'errNotUTF8Content' : 'Il file "$1" non è nel formato UTF-8 e non può essere modificato.', // added 9.11.2011 + 'errNetMount' : 'Impossibile montare "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protocollo non supportato.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount fallito.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host richiesto.', // added 18.04.2012 + 'errSessionExpires' : 'La sessione è scaduta a causa di inattività.', + 'errCreatingTempDir' : 'Impossibile creare la cartella temporanea: "$1"', + 'errFtpDownloadFile' : 'Impossibile scaricare il file tramite FTP: "$1"', + 'errFtpUploadFile' : 'Impossibile caricare il file tramite FTP: "$1"', + 'errFtpMkdir' : 'Impossibile creare la cartella remota tramite FTP: "$1"', + 'errArchiveExec' : 'Errore durante l\'archiviazione dei file: "$1"', + 'errExtractExec' : 'Errore durante l\'estrazione dei file: "$1"', + 'errNetUnMount' : 'Impossibile smontare', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Non convertibile nel formato UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Per uploadare l0intera cartella usare Google Chrome.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Timeout durante la ricerca di "$1". I risultati della ricerca sono parziali.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'E\' necessaria la riautorizzazione.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Il numero massimo di oggetti selezionabili è $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Impossibile ripristinare dal cestino: destinazione di ripristino non trovata.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Impossibile trovare un editor per questo tipo di file.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Si è verificato un errore lato server.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Impossibile svuotare la cartella "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Ci sono $1 ulteriori errori.', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'Puoi creare fino a $1 cartelle alla volta.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Crea archivio', + 'cmdback' : 'Indietro', + 'cmdcopy' : 'Copia', + 'cmdcut' : 'Taglia', + 'cmddownload' : 'Scarica', + 'cmdduplicate' : 'Duplica', + 'cmdedit' : 'Modifica File', + 'cmdextract' : 'Estrai Archivio', + 'cmdforward' : 'Avanti', + 'cmdgetfile' : 'Seleziona File', + 'cmdhelp' : 'Informazioni su...', + 'cmdhome' : 'Home', + 'cmdinfo' : 'Informazioni', + 'cmdmkdir' : 'Nuova cartella', + 'cmdmkdirin' : 'In una nuova cartella', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nuovo file', + 'cmdopen' : 'Apri', + 'cmdpaste' : 'Incolla', + 'cmdquicklook' : 'Anteprima', + 'cmdreload' : 'Ricarica', + 'cmdrename' : 'Rinomina', + 'cmdrm' : 'Elimina', + 'cmdtrash' : 'Nel cestino', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Ripristina', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Ricerca file', + 'cmdup' : 'Vai alla directory padre', + 'cmdupload' : 'Carica File', + 'cmdview' : 'Visualizza', + 'cmdresize' : 'Ridimensiona Immagine', + 'cmdsort' : 'Ordina', + 'cmdnetmount' : 'Monta disco di rete', // added 18.04.2012 + 'cmdnetunmount': 'Smonta', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Aggiungi ad Accesso rapido', // added 28.12.2014 + 'cmdchmod' : 'Cambia modalità', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Apri una cartella', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Reimposta dimensione colonne', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Schermo intero', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Sposta', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Svuota la cartella', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Annulla', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Ripeti', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferenze', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Seleziona tutto', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Annulla selezione', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Inverti selezione', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Apri in una nuova finestra', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Nascondi (Preference)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Chiudi', + 'btnSave' : 'Salva', + 'btnRm' : 'Elimina', + 'btnApply' : 'Applica', + 'btnCancel' : 'Annulla', + 'btnNo' : 'No', + 'btnYes' : 'Sì', + 'btnDiscard': 'Scartare le modifiche', + 'btnMount' : 'Monta', // added 18.04.2012 + 'btnApprove': 'Vai a $1 & approva', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Smonta', // from v2.1 added 30.04.2012 + 'btnConv' : 'Converti', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Qui', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Disco', // from v2.1 added 22.5.2015 + 'btnAll' : 'Tutti', // from v2.1 added 22.5.2015 + 'btnMime' : 'Tipo MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nome file', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Salva & Chiudi', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Rinomina', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Rinomina (tutto)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Indietro ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Avanti ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Salva come', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Apri cartella', + 'ntffile' : 'Apri file', + 'ntfreload' : 'Ricarica il contenuto della cartella', + 'ntfmkdir' : 'Creazione delle directory in corso', + 'ntfmkfile' : 'Creazione dei files in corso', + 'ntfrm' : 'Eliminazione dei files in corso', + 'ntfcopy' : 'Copia file in corso', + 'ntfmove' : 'Spostamento file in corso', + 'ntfprepare' : 'Preparazione della copia dei file.', + 'ntfrename' : 'Sto rinominando i file', + 'ntfupload' : 'Caricamento file in corso', + 'ntfdownload' : 'Downloading file in corso', + 'ntfsave' : 'Salvataggio file in corso', + 'ntfarchive' : 'Creazione archivio in corso', + 'ntfextract' : 'Estrazione file dall\'archivio in corso', + 'ntfsearch' : 'Ricerca files in corso', + 'ntfresize' : 'Ridimensionamento immagini', + 'ntfsmth' : 'Operazione in corso. Attendere...', + 'ntfloadimg' : 'Caricamento immagine in corso', + 'ntfnetmount' : 'Montaggio disco di rete', // added 18.04.2012 + 'ntfnetunmount': 'Smontaggio disco di rete', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Lettura dimensioni immagine', // added 20.05.2013 + 'ntfreaddir' : 'Lettura informazioni cartella', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Lettura URL del collegamento', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Modifica della modalità del file', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Verifica del nome del file caricato', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Creazione del file da scaricare', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Ottenimento informazioni percorso', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Processazione file caricato', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Spostamento nel cestino', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Ripristino dal cestino', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Controllo cartella destinazione', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Annullamento operazione precedente', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Rifacimento precedente annullamento', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Controllo contenuto', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Cestino', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Sconosciuto', + 'Today' : 'Oggi', + 'Yesterday' : 'Ieri', + 'msJan' : 'Gen', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Mag', + 'msJun' : 'Giu', + 'msJul' : 'Lug', + 'msAug' : 'Ago', + 'msSep' : 'Set', + 'msOct' : 'Ott', + 'msNov' : 'Nov', + 'msDec' : 'Dic', + 'January' : 'Gennaio', + 'February' : 'Febbraio', + 'March' : 'Marzo', + 'April' : 'Aprile', + 'May' : 'Maggio', + 'June' : 'Giugno', + 'July' : 'Luglio', + 'August' : 'Agosto', + 'September' : 'Settembre', + 'October' : 'Ottobre', + 'November' : 'Novembre', + 'December' : 'Dicembre', + 'Sunday' : 'Domenica', + 'Monday' : 'Lunedì', + 'Tuesday' : 'Martedì', + 'Wednesday' : 'Mercoledì', + 'Thursday' : 'Giovedì', + 'Friday' : 'Venerdì', + 'Saturday' : 'Sabato', + 'Sun' : 'Dom', + 'Mon' : 'Lun', + 'Tue' : 'Mar', + 'Wed' : 'Mer', + 'Thu' : 'Gio', + 'Fri' : 'Ven', + 'Sat' : 'Sab', + + /******************************** sort variants ********************************/ + 'sortname' : 'per nome', + 'sortkind' : 'per tipo', + 'sortsize' : 'per dimensione', + 'sortdate' : 'per data', + 'sortFoldersFirst' : 'cartelle in testa', + 'sortperm' : 'per permessi', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'per modalità', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'per possessore', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'per gruppo', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Anche vista ad albero', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NuovoFile.txt', // added 10.11.2015 + 'untitled folder' : 'NuovaCartella', // added 10.11.2015 + 'Archive' : 'NuovoArchivio', // from v2.1 added 10.11.2015 + 'untitled file' : 'NuovoFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: File', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Conferma richiesta', + 'confirmRm' : 'Sei sicuro di voler eliminare i file?
                      L\'operazione non è reversibile!', + 'confirmRepl' : 'Sostituire i file ?', + 'confirmRest' : 'Rimpiazza l\'oggetto esistente con quello nel cestino?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Non in formato UTF-8
                      Convertire in UTF-8?
                      Il contenuto diventerà UTF-8 salvando dopo la conversione.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'La codifica caratteri di questo file non può essere determinata. Sarà temporaneamente convertito in UTF-8 per l\'editting.
                      Per cortesia, selezionare la codifica caratteri per il file.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Il contenuto è stato modificato.
                      Le modifiche andranno perse se non si salveranno.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Sei sicuro di voler cestinare gli oggetti?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Sei sicuro di voler spostare gli oggetti in "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Applica a tutti', + 'name' : 'Nome', + 'size' : 'Dimensione', + 'perms' : 'Permessi', + 'modify' : 'Modificato il', + 'kind' : 'Tipo', + 'read' : 'lettura', + 'write' : 'scrittura', + 'noaccess' : 'nessun accesso', + 'and' : 'e', + 'unknown' : 'sconosciuto', + 'selectall' : 'Seleziona tutti i file', + 'selectfiles' : 'Seleziona file', + 'selectffile' : 'Seleziona il primo file', + 'selectlfile' : 'Seleziona l\'ultimo file', + 'viewlist' : 'Visualizza Elenco', + 'viewicons' : 'Visualizza Icone', + 'viewSmall' : 'Icone piccole', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Icone medie', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Icone grandi', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Icone molto grandi', // from v2.1.39 added 22.5.2018 + 'places' : 'Accesso rapido', + 'calc' : 'Calcola', + 'path' : 'Percorso', + 'aliasfor' : 'Alias per', + 'locked' : 'Bloccato', + 'dim' : 'Dimensioni', + 'files' : 'File', + 'folders' : 'Cartelle', + 'items' : 'Oggetti', + 'yes' : 'sì', + 'no' : 'no', + 'link' : 'Collegamento', + 'searcresult' : 'Risultati ricerca', + 'selected' : 'oggetti selezionati', + 'about' : 'Informazioni', + 'shortcuts' : 'Scorciatoie', + 'help' : 'Aiuto', + 'webfm' : 'Gestore file WEB', + 'ver' : 'Versione', + 'protocolver' : 'versione protocollo', + 'homepage' : 'Home del progetto', + 'docs' : 'Documentazione', + 'github' : 'Seguici su Github', + 'twitter' : 'Seguici su Twitter', + 'facebook' : 'Seguici su Facebook', + 'team' : 'Gruppo', + 'chiefdev' : 'sviluppatore capo', + 'developer' : 'sviluppatore', + 'contributor' : 'collaboratore', + 'maintainer' : 'manutentore', + 'translator' : 'traduttore', + 'icons' : 'Icone', + 'dontforget' : 'e non dimenticate di portare l\'asciugamano', + 'shortcutsof' : 'Scorciatoie disabilitate', + 'dropFiles' : 'Trascina i file qui', + 'or' : 'o', + 'selectForUpload' : 'Seleziona file da caricare', + 'moveFiles' : 'Sposta file', + 'copyFiles' : 'Copia file', + 'restoreFiles' : 'Ripristina oggetti', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Rimuovi da Accesso rapido', + 'aspectRatio' : 'Proporzioni', + 'scale' : 'Scala', + 'width' : 'Larghezza', + 'height' : 'Altezza', + 'resize' : 'Ridimensione', + 'crop' : 'Ritaglia', + 'rotate' : 'Ruota', + 'rotate-cw' : 'Ruota di 90° in senso orario', + 'rotate-ccw' : 'Ruota di 90° in senso antiorario', + 'degree' : 'Gradi', + 'netMountDialogTitle' : 'Monta disco di rete', // added 18.04.2012 + 'protocol' : 'Protocollo', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Porta', // added 18.04.2012 + 'user' : 'Utente', // added 18.04.2012 + 'pass' : 'Password', // added 18.04.2012 + 'confirmUnmount' : 'Vuoi smontare $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Rilascia o incolla dal browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Rilascia o incolla files e indirizzi URL qui', // from v2.1 added 07.04.2014 + 'encoding' : 'Codifica', // from v2.1 added 19.12.2014 + 'locale' : 'Lingua', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Destinazione: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Cerca per MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Possessore', // from v2.1 added 20.6.2015 + 'group' : 'Gruppo', // from v2.1 added 20.6.2015 + 'other' : 'Altri', // from v2.1 added 20.6.2015 + 'execute' : 'Esegui', // from v2.1 added 20.6.2015 + 'perm' : 'Permessi', // from v2.1 added 20.6.2015 + 'mode' : 'Modalità', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'La cartella è vuota', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'La cartella è vuota\\A Trascina e rilascia per aggiungere elementi', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'La cartella è vuota\\A Premi a lungo per aggiungere elementi', // from v2.1.6 added 30.12.2015 + 'quality' : 'Qualità', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Sincr. automatica', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Sposta in alto', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Mostra URL link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Elementi selezionati ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID cartella', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Permetti accesso non in linea', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Per ri-autenticarsi', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Caricamento...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Apri più files', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Stai cercando di aprire $1 files. Sei sicuro di volerli aprire nel browser?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Nessun risultato soddisfa i criteri di ricerca', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Il file è in modifica.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1 elementi sono selezionati.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '$1 elementi negli appunti.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'La ricerca incrementale è solo dalla vista corrente.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Reistanzia', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 completato', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Menu contestuale', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Orientamento pagina', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Percorsi base del volume', // from v2.1.16 added 16.9.2016 + 'reset' : 'Resetta', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Colore di sfondo', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Selettore colori', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'Griglia di 8px', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Abilitato', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Disabilitato', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Nessun risultato di ricerca nella vista corrente\\APremere [Invio] per espandere l\'oggetto della ricerca.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Nessun risultato di ricerca tramite prima lettera nella vista corrente.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Etichetta di testo', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 minuti rimanenti', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Riapri con la codifica di caratteri selezionata', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Salva con la codifica di caratteri selezionata', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Seleziona cartella', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Cerca tramite la prima lettera', // from v2.1.23 added 24.3.2017 + 'presets' : 'Opzioni predefinite', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Troppi oggetti da spostare nel cestino', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Area di testo', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Svuota la cartella "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Non ci sono oggetti nella cartella "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preferenze', // from v2.1.26 added 28.6.2017 + 'language' : 'Impostazioni Lingua', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Inizializza le impostazioni salvate nel browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Impostazioni ToolBar', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 caratteri rimanenti.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 linee rimaste.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Somma', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Dimensione file approssimativa', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Fuoco sull\'elemento sotto al mouse', // from v2.1.30 added 2.11.2017 + 'select' : 'Seleziona', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Azione quando un file è selezionato', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Apri con l\'editor usato l\'ultima volta', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Inverti selezione', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Sei sicuro di voler rinominare $1 selezionati come $2?
                      Questo non può essere annullato!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Rinomina gruppo', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Numero', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Aggiungi prefisso', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Aggiungi sufisso', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Cambia estensione', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Impostazioni delle colonne (visualizzazione elenco)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Tutti i cambiamenti saranno immeditamente applicati.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Qualsiasi modifica non sarà visibile fino a quando non si monta questo volume.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'I seguenti volumi montati su questo volume saranno smontati. Sei sicuro di volerlo smontare?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Seleziona Info', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmi per visualizzare l\'hash del file', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Informazioni (pannello di informazioni sulla selezione)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Premi di nuovo per uscire.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Toolbar', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Spazio di lavoro', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialogo', // from v2.1.38 added 4.4.2018 + 'all' : 'Tutti', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Dimensione icona (Visualizzazione icone)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Apri la finestra di modifica massimizzata', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Dato che le API di conversione non sono disponibili, effettua la conversione sul sito web.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Dopo la conversione, devi caricarlo con l\'URL o con il file scaricato per salvare il file convertito.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Converti sul sito di $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrazioni', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Questo elFinder ha i seguenti servizi esterni integrati. Controlla i termini di utilizzo, le politiche sulla privacy, etc, prima di utilizzarli.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Mostra oggetti nascosti', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Nascondi oggetti nascosti', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Visualizza/Nascondi oggetti nascosti', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Tipi di file da abilitare con "Nuovo file"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Tipo del file di testo', // from v2.1.41 added 7.8.2018 + 'add' : 'Aggiungi', // from v2.1.41 added 7.8.2018 + 'theme' : 'Tema', // from v2.1.43 added 19.10.2018 + 'default' : 'Default', // from v2.1.43 added 19.10.2018 + 'description' : 'Descrizione', // from v2.1.43 added 19.10.2018 + 'website' : 'Website', // from v2.1.43 added 19.10.2018 + 'author' : 'Autore', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'Licenza', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'L\'oggetto non può essere salvato. Per non perdere le modifiche, devi esportarlo sul tuo computer.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Doppio click sul file per selezionarlo.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Usa schermo intero', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Sconosciuto', + 'kindRoot' : 'Percorso base del volume', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Cartella', + 'kindSelects' : 'Selezioni', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Alias guasto', + // applications + 'kindApp' : 'Applicazione', + 'kindPostscript' : 'Documento Postscript', + 'kindMsOffice' : 'Documento Microsoft Office', + 'kindMsWord' : 'Documento Microsoft Word', + 'kindMsExcel' : 'Documento Microsoft Excel', + 'kindMsPP' : 'Presentazione Microsoft Powerpoint', + 'kindOO' : 'Documento Open Office', + 'kindAppFlash' : 'Applicazione Flash', + 'kindPDF' : 'Documento PDF', + 'kindTorrent' : 'File Bittorrent', + 'kind7z' : 'Archivio 7z', + 'kindTAR' : 'Archivio TAR', + 'kindGZIP' : 'Archivio GZIP', + 'kindBZIP' : 'Archivio BZIP', + 'kindXZ' : 'Archivio XZ', + 'kindZIP' : 'Archivio ZIP', + 'kindRAR' : 'Archivio RAR', + 'kindJAR' : 'File Java JAR', + 'kindTTF' : 'Font True Type', + 'kindOTF' : 'Font Open Type', + 'kindRPM' : 'Pacchetto RPM', + // fonts + 'kindFont' : 'File font', + 'kindSFNT' : 'Font SFNT', + 'kindEOT' : 'Font Embedded Open Type', + 'kindWOFF' : 'Font Web Open Font Format', + 'kindWOFF2' : 'Font Web Open Font Format 2', + // texts + 'kindText' : 'Documento di testo', + 'kindTextPlain' : 'Testo Semplice', + 'kindPHP' : 'File PHP', + 'kindCSS' : 'File CSS (Cascading Style Sheet)', + 'kindHTML' : 'Documento HTML', + 'kindJS' : 'File Javascript', + 'kindRTF' : 'File RTF (Rich Text Format)', + 'kindC' : 'File C', + 'kindCHeader' : 'File C (header)', + 'kindCPP' : 'File C++', + 'kindCPPHeader' : 'File C++ (header)', + 'kindShell' : 'Script Unix shell', + 'kindPython' : 'File Python', + 'kindJava' : 'File Java', + 'kindRuby' : 'File Ruby', + 'kindPerl' : 'File Perl', + 'kindSQL' : 'File SQL', + 'kindXML' : 'File XML', + 'kindAWK' : 'File AWK', + 'kindCSV' : 'File CSV (Comma separated values)', + 'kindDOCBOOK' : 'File Docbook XML', + 'kindMarkdown' : 'Testo markdown', // added 20.7.2015 + // images + 'kindImage' : 'Immagine', + 'kindBMP' : 'Immagine BMP', + 'kindJPEG' : 'Immagine JPEG', + 'kindGIF' : 'Immagine GIF', + 'kindPNG' : 'Immagine PNG', + 'kindTIFF' : 'Immagine TIFF', + 'kindTGA' : 'Immagine TGA', + 'kindPSD' : 'Immagine Adobe Photoshop', + 'kindXBITMAP' : 'Immagine X bitmap', + 'kindPXM' : 'Immagine Pixelmator', + // media + 'kindAudio' : 'File Audio', + 'kindAudioMPEG' : 'Audio MPEG', + 'kindAudioMPEG4' : 'Audio MPEG-4', + 'kindAudioMIDI' : 'Audio MIDI', + 'kindAudioOGG' : 'Audio Ogg Vorbis', + 'kindAudioWAV' : 'Audio WAV', + 'AudioPlaylist' : 'Playlist MP3', + 'kindVideo' : 'File Video', + 'kindVideoDV' : 'Filmato DV', + 'kindVideoMPEG' : 'Filmato MPEG', + 'kindVideoMPEG4' : 'Filmato MPEG-4', + 'kindVideoAVI' : 'Filmato AVI', + 'kindVideoMOV' : 'Filmato Quick Time', + 'kindVideoWM' : 'Filmato Windows Media', + 'kindVideoFlash' : 'Filmato Flash', + 'kindVideoMKV' : 'Filmato Matroska', + 'kindVideoOGG' : 'Filmato Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ja.js b/lib/redactor/elfinder/js/i18n/elfinder.ja.js new file mode 100644 index 0000000..dfe33b7 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ja.js @@ -0,0 +1,588 @@ +/** + * Japanese translation + * @author Tomoaki Yoshida + * @author Naoki Sawada + * @version 2021-06-02 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ja = { + translator : 'Tomoaki Yoshida <info@yoshida-studio.jp>, Naoki Sawada <hypweb+elfinder@gmail.com>', + language : 'Japanese', + direction : 'ltr', + dateFormat : 'Y/m/d h:i A', // will show like: 2018/08/24 04:37 PM + fancyDateFormat : '$1 h:i A', // will show like: 今日 04:37 PM + nonameDateFormat : 'ymd-His', // noname upload will show like: 180824-163717 + messages : { + + /********************************** errors **********************************/ + 'error' : 'エラー', + 'errUnknown' : '不明なエラーです。', + 'errUnknownCmd' : '不明なコマンドです。', + 'errJqui' : '無効な jQuery UI 設定です。Selectable, Draggable, Droppable コンポーネントを含める必要があります。', + 'errNode' : 'elFinder は DOM Element が必要です。', + 'errURL' : '無効な elFinder 設定です! URLを設定されていません。', + 'errAccess' : 'アクセスが拒否されました。', + 'errConnect' : 'バックエンドとの接続ができません。', + 'errAbort' : '接続が中断されました。', + 'errTimeout' : '接続がタイムアウトしました。', + 'errNotFound' : 'バックエンドが見つかりません。', + 'errResponse' : '無効なバックエンドレスポンスです。', + 'errConf' : 'バックエンドの設定が有効ではありません。', + 'errJSON' : 'PHP JSON モジュールがインストールされていません。', + 'errNoVolumes' : '読み込み可能なボリュームがありません。', + 'errCmdParams' : 'コマンド "$1"のパラメーターが無効です。', + 'errDataNotJSON' : 'JSONデータではありません。', + 'errDataEmpty' : '空のデータです。', + 'errCmdReq' : 'バックエンドリクエストはコマンド名が必要です。', + 'errOpen' : '"$1" を開くことができません。', + 'errNotFolder' : 'オブジェクトがフォルダではありません。', + 'errNotFile' : 'オブジェクトがファイルではありません。', + 'errRead' : '"$1" を読み込むことができません。', + 'errWrite' : '"$1" に書き込むことができません。', + 'errPerm' : '権限がありません。', + 'errLocked' : '"$1" はロックされているので名前の変更、移動、削除ができません。', + 'errExists' : '"$1" というアイテム名はすでに存在しています。', + 'errInvName' : '無効なファイル名です。', + 'errInvDirname' : '無効なフォルダ名です。', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'フォルダが見つかりません。', + 'errFileNotFound' : 'ファイルが見つかりません。', + 'errTrgFolderNotFound' : 'ターゲットとするフォルダ "$1" が見つかりません。', + 'errPopup' : 'ポップアップウィンドウが開けません。ファイルを開くにはブラウザの設定を変更してください。', + 'errMkdir' : 'フォルダ "$1" を作成することができません。', + 'errMkfile' : 'ファイル "$1" を作成することができません。', + 'errRename' : '"$1" の名前を変更することができません。', + 'errCopyFrom' : '"$1" からのファイルコピーは許可されていません。', + 'errCopyTo' : '"$1" へのファイルコピーは許可されていません。', + 'errMkOutLink' : 'ボリュームルート外へのリンクを作成することはできません。', // from v2.1 added 03.10.2015 + 'errUpload' : 'アップロードエラー', // old name - errUploadCommon + 'errUploadFile' : '"$1" をアップロードすることができません。', // old name - errUpload + 'errUploadNoFiles' : 'アップロードされたファイルはありません。', + 'errUploadTotalSize' : 'データが許容サイズを超えています。', // old name - errMaxSize + 'errUploadFileSize' : 'ファイルが許容サイズを超えています。', // old name - errFileMaxSize + 'errUploadMime' : '許可されていないファイル形式です。', + 'errUploadTransfer' : '"$1" 転送エラーです。', + 'errUploadTemp' : 'アップロード用一時ファイルを作成できません。', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'アイテム "$1" はすでにこの場所にあり、アイテムのタイプが違うので置き換えることはできません。', // new + 'errReplace' : '"$1" を置き換えることができません。', + 'errSave' : '"$1" を保存することができません。', + 'errCopy' : '"$1" をコピーすることができません。', + 'errMove' : '"$1" を移動することができません。', + 'errCopyInItself' : '"$1" をそれ自身の中にコピーすることはできません。', + 'errRm' : '"$1" を削除することができません。', + 'errTrash' : 'ごみ箱に入れることができません。', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : '元ファイルを削除することができません。', + 'errExtract' : '"$1" を解凍することができません。', + 'errArchive' : 'アーカイブを作成することができません。', + 'errArcType' : 'サポート外のアーカイブ形式です。', + 'errNoArchive' : 'アーカイブでないかサポートされていないアーカイブ形式です。', + 'errCmdNoSupport' : 'サポートされていないコマンドです。', + 'errReplByChild' : 'フォルダ "$1" に含まれてるアイテムを置き換えることはできません。', + 'errArcSymlinks' : 'シンボリックリンクまたは許容されないファイル名を含むアーカイブはセキュリティ上、解凍できません。', // edited 24.06.2012 + 'errArcMaxSize' : 'アーカイブが許容されたサイズを超えています。', + 'errResize' : '"$1" のリサイズまたは回転ができません。', + 'errResizeDegree' : 'イメージの回転角度が不正です。', // added 7.3.2013 + 'errResizeRotate' : 'イメージを回転できません。', // added 7.3.2013 + 'errResizeSize' : '指定されたイメージサイズが不正です。', // added 7.3.2013 + 'errResizeNoChange' : 'イメージサイズなどの変更点がありません。', // added 7.3.2013 + 'errUsupportType' : 'このファイルタイプはサポートされていません。', + 'errNotUTF8Content' : 'ファイル "$1" には UTF-8 以外の文字が含まれているので編集できません。', // added 9.11.2011 + 'errNetMount' : '"$1" をマウントできません。', // added 17.04.2012 + 'errNetMountNoDriver' : 'サポートされていないプロトコルです。', // added 17.04.2012 + 'errNetMountFailed' : 'マウントに失敗しました。', // added 17.04.2012 + 'errNetMountHostReq' : 'ホスト名は必須です。', // added 18.04.2012 + 'errSessionExpires' : 'アクションがなかったため、セッションが期限切れになりました。', + 'errCreatingTempDir' : '一時ディレクトリを作成できません:"$1"', + 'errFtpDownloadFile' : 'FTP からファイルをダウンロードできません:"$1"', + 'errFtpUploadFile' : 'FTP へファイルをアップロードできません:"$1"', + 'errFtpMkdir' : 'FTP にリモートディレクトリを作成できません:"$1"', + 'errArchiveExec' : 'ファイルのアーカイブ中にエラーが発生しました:"$1"', + 'errExtractExec' : 'ファイルの抽出中にエラーが発生しました:"$1"', + 'errNetUnMount' : 'アンマウントできません。', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'UTF-8 に変換できませんでした。', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'フォルダをアップロードしたいのであれば、モダンブラウザを試してください。', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '"$1" を検索中にタイムアウトしました。検索結果は部分的です。', // from v2.1 added 12.1.2016 + 'errReauthRequire' : '再認可が必要です。', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : '選択可能な最大アイテム数は $1 個です。', // from v2.1.17 added 17.10.2016 + 'errRestore' : '宛先の特定ができないため、ごみ箱から戻せません。', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'このファイルタイプのエディターがありません。', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'サーバー側でエラーが発生しました。', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'フォルダ"$1"を空にすることができません。', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'さらに $1 件のエラーがあります。', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : '一度に作成できるフォルダーは $1 個までです。', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'アーカイブ作成', + 'cmdback' : '戻る', + 'cmdcopy' : 'コピー', + 'cmdcut' : 'カット', + 'cmddownload' : 'ダウンロード', + 'cmdduplicate' : '複製', + 'cmdedit' : 'ファイル編集', + 'cmdextract' : 'アーカイブを解凍', + 'cmdforward' : '進む', + 'cmdgetfile' : 'ファイル選択', + 'cmdhelp' : 'このソフトウェアについて', + 'cmdhome' : 'ルート', + 'cmdinfo' : '情報', + 'cmdmkdir' : '新規フォルダ', + 'cmdmkdirin' : '新規フォルダへ', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : '新規ファイル', + 'cmdopen' : '開く', + 'cmdpaste' : 'ペースト', + 'cmdquicklook' : 'プレビュー', + 'cmdreload' : 'リロード', + 'cmdrename' : 'リネーム', + 'cmdrm' : '削除', + 'cmdtrash' : 'ごみ箱へ', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : '復元', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'ファイルを探す', + 'cmdup' : '親フォルダへ移動', + 'cmdupload' : 'ファイルアップロード', + 'cmdview' : 'ビュー', + 'cmdresize' : 'リサイズと回転', + 'cmdsort' : 'ソート', + 'cmdnetmount' : 'ネットワークボリュームをマウント', // added 18.04.2012 + 'cmdnetunmount': 'アンマウント', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'よく使う項目へ', // added 28.12.2014 + 'cmdchmod' : '属性変更', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'フォルダを開く', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : '列幅リセット', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'フルスクリーン', // from v2.1.15 added 03.08.2016 + 'cmdmove' : '移動', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'フォルダを空に', // from v2.1.25 added 22.06.2017 + 'cmdundo' : '元に戻す', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'やり直し', // from v2.1.27 added 31.07.2017 + 'cmdpreference': '個人設定', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'すべて選択', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': '選択解除', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': '選択を反転', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : '新しいウィンドウで開く', // from v2.1.38 added 3.4.2018 + 'cmdhide' : '非表示 (個人設定)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : '閉じる', + 'btnSave' : '保存', + 'btnRm' : '削除', + 'btnApply' : '適用', + 'btnCancel' : 'キャンセル', + 'btnNo' : 'いいえ', + 'btnYes' : 'はい', + 'btnDiscard': '変更を破棄', + 'btnMount' : 'マウント', // added 18.04.2012 + 'btnApprove': '$1へ行き認可する', // from v2.1 added 26.04.2012 + 'btnUnmount': 'アンマウント', // from v2.1 added 30.04.2012 + 'btnConv' : '変換', // from v2.1 added 08.04.2014 + 'btnCwd' : 'この場所', // from v2.1 added 22.5.2015 + 'btnVolume' : 'ボリューム', // from v2.1 added 22.5.2015 + 'btnAll' : '全て', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIMEタイプ', // from v2.1 added 22.5.2015 + 'btnFileName':'ファイル名', // from v2.1 added 22.5.2015 + 'btnSaveClose': '保存して閉じる', // from v2.1 added 12.6.2015 + 'btnBackup' : 'バックアップ', // fromv2.1 added 28.11.2015 + 'btnRename' : 'リネーム', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'リネーム(全て)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '前へ ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : '次へ ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : '別名保存', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'フォルダを開いています', + 'ntffile' : 'ファイルを開いています', + 'ntfreload' : 'フォルダを再読込しています', + 'ntfmkdir' : 'フォルダを作成しています', + 'ntfmkfile' : 'ファイルを作成しています', + 'ntfrm' : 'アイテムを削除しています', + 'ntfcopy' : 'アイテムをコピーしています', + 'ntfmove' : 'アイテムを移動しています', + 'ntfprepare' : '既存アイテムを確認しています', + 'ntfrename' : 'ファイル名を変更しています', + 'ntfupload' : 'ファイルをアップロードしています', + 'ntfdownload' : 'ファイルをダウンロードしています', + 'ntfsave' : 'ファイルを保存しています', + 'ntfarchive' : 'アーカイブ作成しています', + 'ntfextract' : 'アーカイブを解凍しています', + 'ntfsearch' : 'ファイル検索中', + 'ntfresize' : 'リサイズしています', + 'ntfsmth' : '処理をしています', + 'ntfloadimg' : 'イメージを読み込んでいます', + 'ntfnetmount' : 'ネットボリュームをマウント中', // added 18.04.2012 + 'ntfnetunmount': 'ネットボリュームをアンマウント中', // from v2.1 added 30.04.2012 + 'ntfdim' : '画像サイズを取得しています', // added 20.05.2013 + 'ntfreaddir' : 'フォルダ情報を読み取っています', // from v2.1 added 01.07.2013 + 'ntfurl' : 'リンクURLを取得しています', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'ファイル属性を変更しています', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'アップロードファイル名を検証中', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'ダウンロード用ファイルを作成中', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'パス情報を取得しています', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'アップロード済みファイルを処理中', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'ごみ箱に入れています', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'ごみ箱から元に戻しています', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : '宛先フォルダを確認しています', // from v2.1.24 added 3.5.2017 + 'ntfundo' : '前の操作を取り消して元に戻しています', // from v2.1.27 added 31.07.2017 + 'ntfredo' : '元に戻した操作をやり直しています', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'コンテンツをチェックしています', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'ごみ箱', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : '不明', + 'Today' : '今日', + 'Yesterday' : '昨日', + 'msJan' : '1月', + 'msFeb' : '2月', + 'msMar' : '3月', + 'msApr' : '4月', + 'msMay' : '5月', + 'msJun' : '6月', + 'msJul' : '7月', + 'msAug' : '8月', + 'msSep' : '9月', + 'msOct' : '10月', + 'msNov' : '11月', + 'msDec' : '12月', + 'January' : '1月', + 'February' : '2月', + 'March' : '3月', + 'April' : '4月', + 'May' : '5月', + 'June' : '6月', + 'July' : '7月', + 'August' : '8月', + 'September' : '9月', + 'October' : '10月', + 'November' : '11月', + 'December' : '12月', + 'Sunday' : '日曜日', + 'Monday' : '月曜日', + 'Tuesday' : '火曜日', + 'Wednesday' : '水曜日', + 'Thursday' : '木曜日', + 'Friday' : '金曜日', + 'Saturday' : '土曜日', + 'Sun' : '(日)', + 'Mon' : '(月)', + 'Tue' : '(火)', + 'Wed' : '(水)', + 'Thu' : '(木)', + 'Fri' : '(金)', + 'Sat' : '(土)', + + /******************************** sort variants ********************************/ + 'sortname' : '名前順', + 'sortkind' : '種類順', + 'sortsize' : 'サイズ順', + 'sortdate' : '日付順', + 'sortFoldersFirst' : 'フォルダ優先', + 'sortperm' : '権限順', // from v2.1.13 added 13.06.2016 + 'sortmode' : '属性順', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'オーナー順', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'グループ順', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'ツリービューも', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : '新規ファイル.txt', // added 10.11.2015 + 'untitled folder' : '新規フォルダ', // added 10.11.2015 + 'Archive' : '新規アーカイブ', // from v2.1 added 10.11.2015 + 'untitled file' : '新規ファイル.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: ファイル', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : '処理を実行しますか?', + 'confirmRm' : 'アイテムを完全に削除してもよろしいですか?
                      この操作は取り消しできません!', + 'confirmRepl' : '古いファイルを新しいファイルで上書きしますか? (フォルダが含まれている場合は統合されます。置き換える場合は「バックアップ」選択してください。)', + 'confirmRest' : '既存のアイテムをごみ箱のアイテムで上書きしますか?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'UTF-8 以外の文字が含まれています。
                      UTF-8 に変換しますか?
                      変換後の保存でコンテンツは UTF-8 になります。', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'このファイルの文字エンコーディングを判別できませんでした。編集するには一時的に UTF-8 に変換する必要があります。
                      文字エンコーディングを指定してください。', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : '変更されています。
                      保存せずに閉じると編集内容が失われます。', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'アイテムをごみ箱に移動してもよろしいですか?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'アイテムを"$1"に移動してもよろしいですか?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : '全てに適用します', + 'name' : '名前', + 'size' : 'サイズ', + 'perms' : '権限', + 'modify' : '更新', + 'kind' : '種類', + 'read' : '読み取り', + 'write' : '書き込み', + 'noaccess' : 'アクセス禁止', + 'and' : ',', + 'unknown' : '不明', + 'selectall' : 'すべてのアイテムを選択', + 'selectfiles' : 'アイテム選択', + 'selectffile' : '最初のアイテムを選択', + 'selectlfile' : '最後のアイテムを選択', + 'viewlist' : 'リスト形式で表示', + 'viewicons' : 'アイコン形式で表示', + 'viewSmall' : '小アイコン', // from v2.1.39 added 22.5.2018 + 'viewMedium' : '中アイコン', // from v2.1.39 added 22.5.2018 + 'viewLarge' : '大アイコン', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : '特大アイコン', // from v2.1.39 added 22.5.2018 + 'places' : 'よく使う項目', + 'calc' : '計算中', + 'path' : 'パス', + 'aliasfor' : 'エイリアス', + 'locked' : 'ロック', + 'dim' : '画素数', + 'files' : 'ファイル', + 'folders' : 'フォルダ', + 'items' : 'アイテム', + 'yes' : 'はい', + 'no' : 'いいえ', + 'link' : 'リンク', + 'searcresult' : '検索結果', + 'selected' : '選択されたアイテム', + 'about' : '概要', + 'shortcuts' : 'ショートカット', + 'help' : 'ヘルプ', + 'webfm' : 'ウェブファイルマネージャー', + 'ver' : 'バージョン', + 'protocolver' : 'プロトコルバージョン', + 'homepage' : 'プロジェクトホーム', + 'docs' : 'ドキュメンテーション', + 'github' : 'Github でフォーク', + 'twitter' : 'Twitter でフォロー', + 'facebook' : 'Facebookグループ に参加', + 'team' : 'チーム', + 'chiefdev' : 'チーフデベロッパー', + 'developer' : 'デベロッパー', + 'contributor' : 'コントリビュータ', + 'maintainer' : 'メインテナー', + 'translator' : '翻訳者', + 'icons' : 'アイコン', + 'dontforget' : 'タオル忘れちゃだめよ~', + 'shortcutsof' : 'ショートカットは利用できません', + 'dropFiles' : 'ここにファイルをドロップ', + 'or' : 'または', + 'selectForUpload' : 'ファイルを選択', + 'moveFiles' : 'アイテムを移動', + 'copyFiles' : 'アイテムをコピー', + 'restoreFiles' : 'アイテムを元に戻す', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'ここから削除', + 'aspectRatio' : '縦横比維持', + 'scale' : '表示縮尺', + 'width' : '幅', + 'height' : '高さ', + 'resize' : 'リサイズ', + 'crop' : '切り抜き', + 'rotate' : '回転', + 'rotate-cw' : '90度左回転', + 'rotate-ccw' : '90度右回転', + 'degree' : '度', + 'netMountDialogTitle' : 'ネットワークボリュームのマウント', // added 18.04.2012 + 'protocol' : 'プロトコル', // added 18.04.2012 + 'host' : 'ホスト名', // added 18.04.2012 + 'port' : 'ポート', // added 18.04.2012 + 'user' : 'ユーザー名', // added 18.04.2012 + 'pass' : 'パスワード', // added 18.04.2012 + 'confirmUnmount' : '$1をアンマウントしますか?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'ブラウザからファイルをドロップまたは貼り付け', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'ここにファイルをドロップ または URLリスト, 画像(クリップボード) を貼り付け', // from v2.1 added 07.04.2014 + 'encoding' : 'エンコーディング', // from v2.1 added 19.12.2014 + 'locale' : 'ロケール', // from v2.1 added 19.12.2014 + 'searchTarget' : '検索範囲: $1', // from v2.1 added 22.5.2015 + 'searchMime' : '指定した MIME タイプで検索', // from v2.1 added 22.5.2015 + 'owner' : 'オーナー', // from v2.1 added 20.6.2015 + 'group' : 'グループ', // from v2.1 added 20.6.2015 + 'other' : 'その他', // from v2.1 added 20.6.2015 + 'execute' : '実行', // from v2.1 added 20.6.2015 + 'perm' : 'パーミッション', // from v2.1 added 20.6.2015 + 'mode' : '属性', // from v2.1 added 20.6.2015 + 'emptyFolder' : '空のフォルダ', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : '空のフォルダ\\Aアイテムを追加するにはここへドロップ', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : '空のフォルダ\\Aアイテムを追加するにはここをロングタップ', // from v2.1.6 added 30.12.2015 + 'quality' : '品質', // from v2.1.6 added 5.1.2016 + 'autoSync' : '自動更新', // from v2.1.6 added 10.1.2016 + 'moveUp' : '上へ移動', // from v2.1.6 added 18.1.2016 + 'getLink' : 'リンクURLを取得', // from v2.1.7 added 9.2.2016 + 'selectedItems' : '選択アイテム ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'フォルダID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'オフライン アクセスを可能にする', // from v2.1.10 added 3.25.2016 + 'reAuth' : '再認証する', // from v2.1.10 added 3.25.2016 + 'nowLoading' : '読み込んでいます...', // from v2.1.12 added 4.26.2016 + 'openMulti' : '複数ファイルオープン', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': '$1 個のファイルを開こうとしています。このままブラウザで開きますか?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : '検索対象に該当するアイテムはありません。', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'ファイルを編集中です。', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1 個のアイテムを選択中です。', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '$1 個のアイテムがクリップボードに入っています。', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : '逐次検索対象は現在のビューのみです。', // from v2.1.13 added 6.30.2016 + 'reinstate' : '元に戻す', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 完了', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'コンテキストメニュー', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'ページめくり', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'ボリュームルート', // from v2.1.16 added 16.9.2016 + 'reset' : 'リセット', // from v2.1.16 added 1.10.2016 + 'bgcolor' : '背景色', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'カラーピッカー', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8pxグリッド', // from v2.1.16 added 4.10.2016 + 'enabled' : '有効', // from v2.1.16 added 4.10.2016 + 'disabled' : '無効', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : '現在のビュー内に該当するアイテムはありません。\\A[Enter]キーで検索対象を拡げます。', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : '現在のビュー内に指定された文字で始まるアイテムはありません。', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'テキストラベル', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '残り$1分', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : '選択したエンコーディングで開き直す', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : '選択したエンコーディングで保存', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'フォルダを選択', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': '一文字目で検索', // from v2.1.23 added 24.3.2017 + 'presets' : 'プリセット', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'アイテム数が多すぎるのでごみ箱に入れられません。', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'テキストエリア', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'フォルダ"$1"を空にします。', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'フォルダ"$1"にアイテムはありません。', // from v2.1.25 added 22.6.2017 + 'preference' : '個人設定', // from v2.1.26 added 28.6.2017 + 'language' : '言語', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'ブラウザに保存された設定を初期化する', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'ツールバー設定', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... 残り $1 文字', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... 残り $1 行', // from v2.1.52 added 16.1.2020 + 'sum' : '合計', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : '大まかなファイルサイズ', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'マウスオーバーでダイアログの要素にフォーカスする', // from v2.1.30 added 2.11.2017 + 'select' : '選択', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'ファイル選択時の動作', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : '前回使用したエディターで開く', // from v2.1.30 added 23.11.2017 + 'selectinvert' : '選択アイテムを反転', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : '選択した $1 個のアイテムを $2 のようにリネームしますか?
                      この操作は取り消しできません!', // from v2.1.31 added 4.12.2017 + 'batchRename' : '一括リネーム', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ 連番', // from v2.1.31 added 8.12.2017 + 'asPrefix' : '先頭に追加', // from v2.1.31 added 8.12.2017 + 'asSuffix' : '末尾に追加', // from v2.1.31 added 8.12.2017 + 'changeExtention' : '拡張子変更', // from v2.1.31 added 8.12.2017 + 'columnPref' : '列項目設定(リストビュー)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : '全ての変更は、直ちにアーカイブに反映されます。', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'このボリュームをアンマウントするまで、変更は反映されません。', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'このボリュームにマウントされている以下のボリュームもアンマウントされます。アンマウントしますか?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : '選択情報', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'ファイルハッシュを表示するアルゴリズム', // from v2.1.33 added 10.3.2018 + 'infoItems' : '情報項目 (選択情報パネル)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'もう一度押すと終了します。', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'ツールバー', // from v2.1.38 added 4.4.2018 + 'workspace' : 'ワークスペース', // from v2.1.38 added 4.4.2018 + 'dialog' : 'ダイアログ', // from v2.1.38 added 4.4.2018 + 'all' : 'すべて', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'アイコンサイズ (アイコンビュー)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'エディターウィンドウを最大化して開く', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : '現在 API による変換は利用できないので、Web サイトで変換を行ってください。', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : '変換後に変換されたファイルを保存するには、アイテムの URL またはダウンロードしたファイルをアップロードする必要があります。', //from v2.1.40 added 8.7.2018 + 'convertOn' : '$1 のサイト上で変換する', // from v2.1.40 added 10.7.2018 + 'integrations' : '統合', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'この elFinder は次の外部サービスが統合されています。それらの利用規約、プライバシーポリシーなどをご確認の上、ご利用ください。', // from v2.1.40 added 11.7.2018 + 'showHidden' : '非表示アイテムを表示', // from v2.1.41 added 24.7.2018 + 'hideHidden' : '非表示アイテムを隠す', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : '非表示アイテムの表示/非表示', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : '「新しいファイル」で有効にするファイルタイプ', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'テキストファイルのタイプ', // from v2.1.41 added 7.8.2018 + 'add' : '追加', // from v2.1.41 added 7.8.2018 + 'theme' : 'テーマ', // from v2.1.43 added 19.10.2018 + 'default' : 'デフォルト', // from v2.1.43 added 19.10.2018 + 'description' : '説明', // from v2.1.43 added 19.10.2018 + 'website' : 'ウェブサイト', // from v2.1.43 added 19.10.2018 + 'author' : '作者', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'ライセンス', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'このアイテムは保存できません。 編集内容を失わないようにするには、PCにエクスポートする必要があります。', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'ファイルをダブルクリックして選択します。', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'フルスクリーンモードの利用', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : '不明', + 'kindRoot' : 'ボリュームルート', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'フォルダ', + 'kindSelects' : '複数選択', // from v2.1.29 added 29.8.2017 + 'kindAlias' : '別名', + 'kindAliasBroken' : '宛先不明の別名', + // applications + 'kindApp' : 'アプリケーション', + 'kindPostscript' : 'Postscript ドキュメント', + 'kindMsOffice' : 'Microsoft Office ドキュメント', + 'kindMsWord' : 'Microsoft Word ドキュメント', + 'kindMsExcel' : 'Microsoft Excel ドキュメント', + 'kindMsPP' : 'Microsoft Powerpoint プレゼンテーション', + 'kindOO' : 'Open Office ドキュメント', + 'kindAppFlash' : 'Flash アプリケーション', + 'kindPDF' : 'PDF', + 'kindTorrent' : 'Bittorrent ファイル', + 'kind7z' : '7z アーカイブ', + 'kindTAR' : 'TAR アーカイブ', + 'kindGZIP' : 'GZIP アーカイブ', + 'kindBZIP' : 'BZIP アーカイブ', + 'kindXZ' : 'XZ アーカイブ', + 'kindZIP' : 'ZIP アーカイブ', + 'kindRAR' : 'RAR アーカイブ', + 'kindJAR' : 'Java JAR ファイル', + 'kindTTF' : 'True Type フォント', + 'kindOTF' : 'Open Type フォント', + 'kindRPM' : 'RPM パッケージ', + // fonts + 'kindFont' : 'フォント', + 'kindSFNT' : 'SFNT フォント', + 'kindEOT' : 'Embedded Open Type フォント', + 'kindWOFF' : 'Web Open Font Format フォント', + 'kindWOFF2' : 'Web Open Font Format 2 フォント', + // texts + 'kindText' : 'Text ドキュメント', + 'kindTextPlain' : 'プレインテキスト', + 'kindPHP' : 'PHP ソース', + 'kindCSS' : 'スタイルシート', + 'kindHTML' : 'HTML ドキュメント', + 'kindJS' : 'Javascript ソース', + 'kindRTF' : 'Rich Text フォーマット', + 'kindC' : 'C ソース', + 'kindCHeader' : 'C ヘッダーソース', + 'kindCPP' : 'C++ ソース', + 'kindCPPHeader' : 'C++ ヘッダーソース', + 'kindShell' : 'Unix shell スクリプト', + 'kindPython' : 'Python ソース', + 'kindJava' : 'Java ソース', + 'kindRuby' : 'Ruby ソース', + 'kindPerl' : 'Perl スクリプト', + 'kindSQL' : 'SQL ソース', + 'kindXML' : 'XML ドキュメント', + 'kindAWK' : 'AWK ソース', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Docbook XML ドキュメント', + 'kindMarkdown' : 'Markdown テキスト', // added 20.7.2015 + // images + 'kindImage' : 'イメージ', + 'kindBMP' : 'BMP イメージ', + 'kindJPEG' : 'JPEG イメージ', + 'kindGIF' : 'GIF イメージ', + 'kindPNG' : 'PNG イメージ', + 'kindTIFF' : 'TIFF イメージ', + 'kindTGA' : 'TGA イメージ', + 'kindPSD' : 'Adobe Photoshop イメージ', + 'kindXBITMAP' : 'X bitmap イメージ', + 'kindPXM' : 'Pixelmator イメージ', + // media + 'kindAudio' : 'オーディオメディア', + 'kindAudioMPEG' : 'MPEG オーディオ', + 'kindAudioMPEG4' : 'MPEG-4 オーディオ', + 'kindAudioMIDI' : 'MIDI オーディオ', + 'kindAudioOGG' : 'Ogg Vorbis オーディオ', + 'kindAudioWAV' : 'WAV オーディオ', + 'AudioPlaylist' : 'MP3 プレイリスト', + 'kindVideo' : 'ビデオメディア', + 'kindVideoDV' : 'DV ムービー', + 'kindVideoMPEG' : 'MPEG ムービー', + 'kindVideoMPEG4' : 'MPEG-4 ムービー', + 'kindVideoAVI' : 'AVI ムービー', + 'kindVideoMOV' : 'Quick Time ムービー', + 'kindVideoWM' : 'Windows Media ムービー', + 'kindVideoFlash' : 'Flash ムービー', + 'kindVideoMKV' : 'Matroska ムービー', + 'kindVideoOGG' : 'Ogg ムービー' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.jp.js b/lib/redactor/elfinder/js/i18n/elfinder.jp.js new file mode 100644 index 0000000..c613649 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.jp.js @@ -0,0 +1,505 @@ +/** + * Japanese translation + * @author Tomoaki Yoshida + * @author Naoki Sawada + * @version 2017-06-22 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.jp = { + translator : 'Tomoaki Yoshida <info@yoshida-studio.jp>, Naoki Sawada <hypweb@gmail.com>', + language : 'Japanese', + direction : 'ltr', + dateFormat : 'Y/m/d h:i A', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'ymd-His', // to apply if upload file is noname: 120513172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'エラー', + 'errUnknown' : '不明なエラーです。', + 'errUnknownCmd' : '不明なコマンドです。', + 'errJqui' : '無効な jQuery UI 設定です。Selectable, Draggable, Droppable コンポーネントを含める必要があります。', + 'errNode' : 'elFinder は DOM Element が必要です。', + 'errURL' : '無効な elFinder 設定です! URLを設定されていません。', + 'errAccess' : 'アクセスが拒否されました。', + 'errConnect' : 'バックエンドとの接続ができません。', + 'errAbort' : '接続が中断されました。', + 'errTimeout' : '接続がタイムアウトしました。', + 'errNotFound' : 'バックエンドが見つかりません。', + 'errResponse' : '無効なバックエンドレスポンスです。', + 'errConf' : 'バックエンドの設定が有効ではありません。', + 'errJSON' : 'PHP JSON モジュールがインストールされていません。', + 'errNoVolumes' : '読み込み可能なボリュームがありません。', + 'errCmdParams' : 'コマンド "$1"のパラメーターが無効です。', + 'errDataNotJSON' : 'JSONデータではありません。', + 'errDataEmpty' : '空のデータです。', + 'errCmdReq' : 'バックエンドリクエストはコマンド名が必要です。', + 'errOpen' : '"$1" を開くことができません。', + 'errNotFolder' : 'オブジェクトがフォルダーではありません。', + 'errNotFile' : 'オブジェクトがファイルではありません。', + 'errRead' : '"$1" を読み込むことができません。', + 'errWrite' : '"$1" に書き込むことができません。', + 'errPerm' : '権限がありません。', + 'errLocked' : '"$1" はロックされているので名前の変更、移動、削除ができません。', + 'errExists' : '"$1" というアイテム名はすでに存在しています。', + 'errInvName' : '無効なファイル名です。', + 'errInvDirname' : '無効なフォルダ名です。', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'フォルダーが見つかりません。', + 'errFileNotFound' : 'ファイルが見つかりません。', + 'errTrgFolderNotFound' : 'ターゲットとするフォルダー "$1" が見つかりません。', + 'errPopup' : 'ポップアップウィンドウが開けません。ファイルを開くにはブラウザの設定を変更してください。', + 'errMkdir' : 'フォルダー "$1" を作成することができません。', + 'errMkfile' : 'ファイル "$1" を作成することができません。', + 'errRename' : '"$1" の名前を変更することができません。', + 'errCopyFrom' : '"$1" からのファイルコピーは許可されていません。', + 'errCopyTo' : '"$1" へのファイルコピーは許可されていません。', + 'errMkOutLink' : 'ボリュームルート外へのリンクを作成することはできません。', // from v2.1 added 03.10.2015 + 'errUpload' : 'アップロードエラー', // old name - errUploadCommon + 'errUploadFile' : '"$1" をアップロードすることができません。', // old name - errUpload + 'errUploadNoFiles' : 'アップロードされたファイルはありません。', + 'errUploadTotalSize' : 'データが許容サイズを超えています。', // old name - errMaxSize + 'errUploadFileSize' : 'ファイルが許容サイズを超えています。', // old name - errFileMaxSize + 'errUploadMime' : '許可されていないファイル形式です。', + 'errUploadTransfer' : '"$1" 転送エラーです。', + 'errUploadTemp' : 'アップロード用一時ファイルを作成できません。', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'アイテム "$1" はすでにこの場所にあり、アイテムのタイプが違うので置き換えることはできません。', // new + 'errReplace' : '"$1" を置き換えることができません。', + 'errSave' : '"$1" を保存することができません。', + 'errCopy' : '"$1" をコピーすることができません。', + 'errMove' : '"$1" を移動することができません。', + 'errCopyInItself' : '"$1" をそれ自身の中にコピーすることはできません。', + 'errRm' : '"$1" を削除することができません。', + 'errTrash' : 'ごみ箱に入れることができません。', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : '元ファイルを削除することができません。', + 'errExtract' : '"$1" を解凍することができません。', + 'errArchive' : 'アーカイブを作成することができません。', + 'errArcType' : 'サポート外のアーカイブ形式です。', + 'errNoArchive' : 'アーカイブでないかサポートされていないアーカイブ形式です。', + 'errCmdNoSupport' : 'サポートされていないコマンドです。', + 'errReplByChild' : 'フォルダ "$1" に含まれてるアイテムを置き換えることはできません。', + 'errArcSymlinks' : 'シンボリックリンクまたは許容されないファイル名を含むアーカイブはセキュリティ上、解凍できません。', // edited 24.06.2012 + 'errArcMaxSize' : 'アーカイブが許容されたサイズを超えています。', + 'errResize' : '"$1" のリサイズまたは回転ができません。', + 'errResizeDegree' : 'イメージの回転角度が不正です。', // added 7.3.2013 + 'errResizeRotate' : 'イメージを回転できません。', // added 7.3.2013 + 'errResizeSize' : '指定されたイメージサイズが不正です。', // added 7.3.2013 + 'errResizeNoChange' : 'イメージサイズなどの変更点がありません。', // added 7.3.2013 + 'errUsupportType' : 'このファイルタイプはサポートされていません。', + 'errNotUTF8Content' : 'ファイル "$1" には UTF-8 以外の文字が含まれているので編集できません。', // added 9.11.2011 + 'errNetMount' : '"$1" をマウントできません。', // added 17.04.2012 + 'errNetMountNoDriver' : 'サポートされていないプロトコルです。', // added 17.04.2012 + 'errNetMountFailed' : 'マウントに失敗しました。', // added 17.04.2012 + 'errNetMountHostReq' : 'ホスト名は必須です。', // added 18.04.2012 + 'errSessionExpires' : 'アクションがなかったため、セッションが期限切れになりました。', + 'errCreatingTempDir' : '一時ディレクトリを作成できません:"$1"', + 'errFtpDownloadFile' : 'FTP からファイルをダウンロードできません:"$1"', + 'errFtpUploadFile' : 'FTP へファイルをアップロードできません:"$1"', + 'errFtpMkdir' : 'FTP にリモートディレクトリを作成できません:"$1"', + 'errArchiveExec' : 'ファイルのアーカイブ中にエラーが発生しました:"$1"', + 'errExtractExec' : 'ファイルの抽出中にエラーが発生しました:"$1"', + 'errNetUnMount' : 'アンマウントできません。', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'UTF-8 に変換できませんでした。', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'フォルダをアップロードしたいのであれば、モダンブラウザを試してください。', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '"$1" を検索中にタイムアウトしました。検索結果は部分的です。', // from v2.1 added 12.1.2016 + 'errReauthRequire' : '再認可が必要です。', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : '選択可能な最大アイテム数は $1 個です。', // from v2.1.17 added 17.10.2016 + 'errRestore' : '宛先の特定ができないため、ごみ箱から戻せません。', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'このファイルタイプのエディターがありません。', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'サーバー側でエラーが発生しました。', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'フォルダー"$1"を空にすることができません。', // from v2.1.25 added 22.6.2017 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'アーカイブ作成', + 'cmdback' : '戻る', + 'cmdcopy' : 'コピー', + 'cmdcut' : 'カット', + 'cmddownload' : 'ダウンロード', + 'cmdduplicate' : '複製', + 'cmdedit' : 'ファイル編集', + 'cmdextract' : 'アーカイブを解凍', + 'cmdforward' : '進む', + 'cmdgetfile' : 'ファイル選択', + 'cmdhelp' : 'このソフトウェアについて', + 'cmdhome' : 'ホーム', + 'cmdinfo' : '情報', + 'cmdmkdir' : '新規フォルダー', + 'cmdmkdirin' : '新規フォルダーへ', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : '新規テキストファイル', + 'cmdopen' : '開く', + 'cmdpaste' : 'ペースト', + 'cmdquicklook' : 'プレビュー', + 'cmdreload' : 'リロード', + 'cmdrename' : 'リネーム', + 'cmdrm' : '削除', + 'cmdtrash' : 'ごみ箱へ', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : '元に戻す', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'ファイルを探す', + 'cmdup' : '親ディレクトリーへ移動', + 'cmdupload' : 'ファイルアップロード', + 'cmdview' : 'ビュー', + 'cmdresize' : 'リサイズと回転', + 'cmdsort' : 'ソート', + 'cmdnetmount' : 'ネットワークボリュームをマウント', // added 18.04.2012 + 'cmdnetunmount': 'アンマウント', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'お気に入りへ', // added 28.12.2014 + 'cmdchmod' : '属性変更', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'フォルダを開く', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : '列幅リセット', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'フルスクリーン', // from v2.1.15 added 03.08.2016 + 'cmdmove' : '移動', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'フォルダーを空に', // from v2.1.25 added 22.06.2017 + + /*********************************** buttons ***********************************/ + 'btnClose' : '閉じる', + 'btnSave' : '保存', + 'btnRm' : '削除', + 'btnApply' : '適用', + 'btnCancel' : 'キャンセル', + 'btnNo' : 'いいえ', + 'btnYes' : 'はい', + 'btnMount' : 'マウント', // added 18.04.2012 + 'btnApprove': '$1へ行き認可する', // from v2.1 added 26.04.2012 + 'btnUnmount': 'アンマウント', // from v2.1 added 30.04.2012 + 'btnConv' : '変換', // from v2.1 added 08.04.2014 + 'btnCwd' : 'この場所', // from v2.1 added 22.5.2015 + 'btnVolume' : 'ボリューム', // from v2.1 added 22.5.2015 + 'btnAll' : '全て', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIMEタイプ', // from v2.1 added 22.5.2015 + 'btnFileName':'ファイル名', // from v2.1 added 22.5.2015 + 'btnSaveClose': '保存して閉じる', // from v2.1 added 12.6.2015 + 'btnBackup' : 'バックアップ', // fromv2.1 added 28.11.2015 + 'btnRename' : 'リネーム', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'リネーム(全て)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '前へ ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : '次へ ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : '別名保存', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'フォルダーを開いています', + 'ntffile' : 'ファイルを開いています', + 'ntfreload' : 'フォルダーを再読込しています', + 'ntfmkdir' : 'フォルダーを作成しています', + 'ntfmkfile' : 'ファイルを作成しています', + 'ntfrm' : 'ファイルを削除しています', + 'ntfcopy' : 'ファイルをコピーしています', + 'ntfmove' : 'ファイルを移動しています', + 'ntfprepare' : '既存アイテムを確認しています', + 'ntfrename' : 'ファイル名を変更しています', + 'ntfupload' : 'ファイルをアップロードしています', + 'ntfdownload' : 'ファイルをダウンロードしています', + 'ntfsave' : 'ファイルを保存しています', + 'ntfarchive' : 'アーカイブ作成しています', + 'ntfextract' : 'アーカイブを解凍しています', + 'ntfsearch' : 'ファイル検索中', + 'ntfresize' : 'リサイズしています', + 'ntfsmth' : '処理をしています', + 'ntfloadimg' : 'イメージを読み込んでいます', + 'ntfnetmount' : 'ネットボリュームをマウント中', // added 18.04.2012 + 'ntfnetunmount': 'ネットボリュームをアンマウント中', // from v2.1 added 30.04.2012 + 'ntfdim' : '画像サイズを取得しています', // added 20.05.2013 + 'ntfreaddir' : 'ホルダ情報を読み取っています', // from v2.1 added 01.07.2013 + 'ntfurl' : 'リンクURLを取得しています', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'ファイル属性を変更しています', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'アップロードファイル名を検証中', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'ダウンロード用ファイルを作成中', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'パス情報を取得しています', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'アップロード済みファイルを処理中', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'ごみ箱に入れています', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'ごみ箱から元に戻しています', // from v2.1.24 added 2.5.2017 + 'ntfchkdir' : '宛先ホルダーを確認しています', // from v2.1.24 added 3.5.2017 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'ごみ箱', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : '不明', + 'Today' : '今日', + 'Yesterday' : '昨日', + 'msJan' : '1月', + 'msFeb' : '2月', + 'msMar' : '3月', + 'msApr' : '4月', + 'msMay' : '5月', + 'msJun' : '6月', + 'msJul' : '7月', + 'msAug' : '8月', + 'msSep' : '9月', + 'msOct' : '10月', + 'msNov' : '11月', + 'msDec' : '12月', + 'January' : '1月', + 'February' : '2月', + 'March' : '3月', + 'April' : '4月', + 'May' : '5月', + 'June' : '6月', + 'July' : '7月', + 'August' : '8月', + 'September' : '9月', + 'October' : '10月', + 'November' : '11月', + 'December' : '12月', + 'Sunday' : '日曜日', + 'Monday' : '月曜日', + 'Tuesday' : '火曜日', + 'Wednesday' : '水曜日', + 'Thursday' : '木曜日', + 'Friday' : '金曜日', + 'Saturday' : '土曜日', + 'Sun' : '(日)', + 'Mon' : '(月)', + 'Tue' : '(火)', + 'Wed' : '(水)', + 'Thu' : '(木)', + 'Fri' : '(金)', + 'Sat' : '(土)', + + /******************************** sort variants ********************************/ + 'sortname' : '名前順', + 'sortkind' : '種類順', + 'sortsize' : 'サイズ順', + 'sortdate' : '日付順', + 'sortFoldersFirst' : 'フォルダ優先', + 'sortperm' : '権限順', // from v2.1.13 added 13.06.2016 + 'sortmode' : '属性順', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'オーナー順', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'グループ順', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'ツリービューも', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : '新規ファイル.txt', // added 10.11.2015 + 'untitled folder' : '新規フォルダ', // added 10.11.2015 + 'Archive' : '新規アーカイブ', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : '処理を実行しますか?', + 'confirmRm' : 'アイテムを完全に削除してもよろしいですか?
                      この操作は取り消せません!', + 'confirmRepl' : '古いアイテムを新しいアイテムで上書きしますか?', + 'confirmRest' : '既存のアイテムをごみ箱のアイテムで上書きしますか?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'UTF-8 以外の文字が含まれています。
                      UTF-8 に変換しますか?
                      変換後の保存でコンテンツは UTF-8 になります。', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'このファイルの文字エンコーディングを判別できませんでした。編集するには一時的に UTF-8 に変換する必要があります。
                      文字エンコーディングを指定してください。', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : '変更されています。
                      保存せずに閉じると編集内容が失われます。', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'アイテムをごみ箱に移動してもよろしいですか?', //from v2.1.24 added 29.4.2017 + 'apllyAll' : '全てに適用します', + 'name' : '名前', + 'size' : 'サイズ', + 'perms' : '権限', + 'modify' : '更新', + 'kind' : '種類', + 'read' : '読み取り', + 'write' : '書き込み', + 'noaccess' : 'アクセス禁止', + 'and' : ',', + 'unknown' : '不明', + 'selectall' : '全てのファイルを選択', + 'selectfiles' : 'ファイル選択', + 'selectffile' : '最初のファイルを選択', + 'selectlfile' : '最後のファイルを選択', + 'viewlist' : 'リスト形式で表示', + 'viewicons' : 'アイコン形式で表示', + 'places' : 'お気に入り', + 'calc' : '計算中', + 'path' : 'パス', + 'aliasfor' : 'エイリアス', + 'locked' : 'ロック', + 'dim' : 'サイズ', + 'files' : 'ファイル', + 'folders' : 'フォルダー', + 'items' : 'アイテム', + 'yes' : 'はい', + 'no' : 'いいえ', + 'link' : 'リンク', + 'searcresult' : '検索結果', + 'selected' : '選択されたアイテム', + 'about' : 'アバウト', + 'shortcuts' : 'ショートカット', + 'help' : 'ヘルプ', + 'webfm' : 'ウェブファイルマネージャー', + 'ver' : 'バージョン', + 'protocolver' : 'プロトコルバージョン', + 'homepage' : 'プロジェクトホーム', + 'docs' : 'ドキュメンテーション', + 'github' : 'Github でフォーク', + 'twitter' : 'Twitter でフォロー', + 'facebook' : 'Facebookグループ に参加', + 'team' : 'チーム', + 'chiefdev' : 'チーフデベロッパー', + 'developer' : 'デベロッパー', + 'contributor' : 'コントリビュータ', + 'maintainer' : 'メインテナー', + 'translator' : '翻訳者', + 'icons' : 'アイコン', + 'dontforget' : 'タオル忘れちゃだめよ~', + 'shortcutsof' : 'ショートカットは利用できません', + 'dropFiles' : 'ここにファイルをドロップ', + 'or' : 'または', + 'selectForUpload' : 'ファイルを選択', + 'moveFiles' : 'アイテムを移動', + 'copyFiles' : 'アイテムをコピー', + 'restoreFiles' : 'アイテムを元に戻す', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'ここから削除', + 'aspectRatio' : '縦横比維持', + 'scale' : '表示縮尺', + 'width' : '幅', + 'height' : '高さ', + 'resize' : 'リサイズ', + 'crop' : '切り抜き', + 'rotate' : '回転', + 'rotate-cw' : '90度左回転', + 'rotate-ccw' : '90度右回転', + 'degree' : '度', + 'netMountDialogTitle' : 'ネットワークボリュームのマウント', // added 18.04.2012 + 'protocol' : 'プロトコル', // added 18.04.2012 + 'host' : 'ホスト名', // added 18.04.2012 + 'port' : 'ポート', // added 18.04.2012 + 'user' : 'ユーザー名', // added 18.04.2012 + 'pass' : 'パスワード', // added 18.04.2012 + 'confirmUnmount' : '$1をアンマウントしますか?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'ブラウザからファイルをドロップまたは貼り付け', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'ここにファイルをドロップ または URLリスト, 画像(クリップボード) を貼り付け', // from v2.1 added 07.04.2014 + 'encoding' : 'エンコーディング', // from v2.1 added 19.12.2014 + 'locale' : 'ロケール', // from v2.1 added 19.12.2014 + 'searchTarget' : '検索範囲: $1', // from v2.1 added 22.5.2015 + 'searchMime' : '指定した MIME タイプで検索', // from v2.1 added 22.5.2015 + 'owner' : 'オーナー', // from v2.1 added 20.6.2015 + 'group' : 'グループ', // from v2.1 added 20.6.2015 + 'other' : 'その他', // from v2.1 added 20.6.2015 + 'execute' : '実行', // from v2.1 added 20.6.2015 + 'perm' : 'パーミッション', // from v2.1 added 20.6.2015 + 'mode' : '属性', // from v2.1 added 20.6.2015 + 'emptyFolder' : '空のフォルダ', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : '空のフォルダ\\Aアイテムを追加するにはここへドロップ', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : '空のフォルダ\\Aアイテムを追加するにはここをロングタップ', // from v2.1.6 added 30.12.2015 + 'quality' : '品質', // from v2.1.6 added 5.1.2016 + 'autoSync' : '自動更新', // from v2.1.6 added 10.1.2016 + 'moveUp' : '上へ移動', // from v2.1.6 added 18.1.2016 + 'getLink' : 'リンクURLを取得', // from v2.1.7 added 9.2.2016 + 'selectedItems' : '選択アイテム ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'フォルダID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'オフライン アクセスを可能にする', // from v2.1.10 added 3.25.2016 + 'reAuth' : '再認証する', // from v2.1.10 added 3.25.2016 + 'nowLoading' : '読み込んでいます...', // from v2.1.12 added 4.26.2016 + 'openMulti' : '複数ファイルオープン', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': '$1 個のファイルを開こうとしています。このままブラウザで開きますか?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : '検索対象に該当するアイテムはありません。', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'ファイルを編集中です。', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1 個のアイテムを選択中です。', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '$1 個のアイテムがクリップボードに入っています。', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : '逐次検索対象は現在のビューのみです。', // from v2.1.13 added 6.30.2016 + 'reinstate' : '元に戻す', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 完了', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'コンテキストメニュー', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'ページめくり', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'ボリュームルート', // from v2.1.16 added 16.9.2016 + 'reset' : 'リセット', // from v2.1.16 added 1.10.2016 + 'bgcolor' : '背景色', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'カラーピッカー', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8pxグリッド', // from v2.1.16 added 4.10.2016 + 'enabled' : '有効', // from v2.1.16 added 4.10.2016 + 'disabled' : '無効', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : '現在のビュー内に該当するアイテムはありません。\\A[Enter]キーで検索対象を拡げます。', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : '現在のビュー内に指定された文字で始まるアイテムはありません。', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'テキストラベル', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '残り$1分', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : '選択したエンコーディングで開き直す', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : '選択したエンコーディングで保存', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'フォルダーを選択', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': '一文字目で検索', // from v2.1.23 added 24.3.2017 + 'presets' : 'プリセット', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'アイテム数が多すぎるのでごみ箱に入れられません。', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'テキストエリア', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'フォルダー"$1"を空にします。', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'フォルダー"$1"にアイテムはありません。', // from v2.1.25 added 22.6.2017 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : '不明', + 'kindRoot' : 'ボリュームルート', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'フォルダー', + 'kindAlias' : '別名', + 'kindAliasBroken' : '宛先不明の別名', + // applications + 'kindApp' : 'アプリケーション', + 'kindPostscript' : 'Postscript ドキュメント', + 'kindMsOffice' : 'Microsoft Office ドキュメント', + 'kindMsWord' : 'Microsoft Word ドキュメント', + 'kindMsExcel' : 'Microsoft Excel ドキュメント', + 'kindMsPP' : 'Microsoft Powerpoint プレゼンテーション', + 'kindOO' : 'Open Office ドキュメント', + 'kindAppFlash' : 'Flash アプリケーション', + 'kindPDF' : 'PDF', + 'kindTorrent' : 'Bittorrent ファイル', + 'kind7z' : '7z アーカイブ', + 'kindTAR' : 'TAR アーカイブ', + 'kindGZIP' : 'GZIP アーカイブ', + 'kindBZIP' : 'BZIP アーカイブ', + 'kindXZ' : 'XZ アーカイブ', + 'kindZIP' : 'ZIP アーカイブ', + 'kindRAR' : 'RAR アーカイブ', + 'kindJAR' : 'Java JAR ファイル', + 'kindTTF' : 'True Type フォント', + 'kindOTF' : 'Open Type フォント', + 'kindRPM' : 'RPM パッケージ', + // texts + 'kindText' : 'Text ドキュメント', + 'kindTextPlain' : 'プレインテキスト', + 'kindPHP' : 'PHP ソース', + 'kindCSS' : 'スタイルシート', + 'kindHTML' : 'HTML ドキュメント', + 'kindJS' : 'Javascript ソース', + 'kindRTF' : 'Rich Text フォーマット', + 'kindC' : 'C ソース', + 'kindCHeader' : 'C ヘッダーソース', + 'kindCPP' : 'C++ ソース', + 'kindCPPHeader' : 'C++ ヘッダーソース', + 'kindShell' : 'Unix shell スクリプト', + 'kindPython' : 'Python ソース', + 'kindJava' : 'Java ソース', + 'kindRuby' : 'Ruby ソース', + 'kindPerl' : 'Perl スクリプト', + 'kindSQL' : 'SQL ソース', + 'kindXML' : 'XML ドキュメント', + 'kindAWK' : 'AWK ソース', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Docbook XML ドキュメント', + 'kindMarkdown' : 'Markdown テキスト', // added 20.7.2015 + // images + 'kindImage' : 'イメージ', + 'kindBMP' : 'BMP イメージ', + 'kindJPEG' : 'JPEG イメージ', + 'kindGIF' : 'GIF イメージ', + 'kindPNG' : 'PNG イメージ', + 'kindTIFF' : 'TIFF イメージ', + 'kindTGA' : 'TGA イメージ', + 'kindPSD' : 'Adobe Photoshop イメージ', + 'kindXBITMAP' : 'X bitmap イメージ', + 'kindPXM' : 'Pixelmator イメージ', + // media + 'kindAudio' : 'オーディオメディア', + 'kindAudioMPEG' : 'MPEG オーディオ', + 'kindAudioMPEG4' : 'MPEG-4 オーディオ', + 'kindAudioMIDI' : 'MIDI オーディオ', + 'kindAudioOGG' : 'Ogg Vorbis オーディオ', + 'kindAudioWAV' : 'WAV オーディオ', + 'AudioPlaylist' : 'MP3 プレイリスト', + 'kindVideo' : 'ビデオメディア', + 'kindVideoDV' : 'DV ムービー', + 'kindVideoMPEG' : 'MPEG ムービー', + 'kindVideoMPEG4' : 'MPEG-4 ムービー', + 'kindVideoAVI' : 'AVI ムービー', + 'kindVideoMOV' : 'Quick Time ムービー', + 'kindVideoWM' : 'Windows Media ムービー', + 'kindVideoFlash' : 'Flash ムービー', + 'kindVideoMKV' : 'Matroska ムービー', + 'kindVideoOGG' : 'Ogg ムービー' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ko.js b/lib/redactor/elfinder/js/i18n/elfinder.ko.js new file mode 100644 index 0000000..31321dc --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ko.js @@ -0,0 +1,590 @@ +/** + * Korea-한국어 translation + * @author Hwang Ahreum; + * @author Park Sungyong; + * @author Yeonjeong Woo + * @author Kwon Hyungjoo + * @version 2024-03-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ko = { + translator : 'Hwang Ahreum; <luckmagic@naver.com>, Park Sungyong; <sungyong@gmail.com>, Yeonjeong Woo <eat_sweetly@naver.com>, Kwon Hyungjoo <hyung778@gmail.com>', + language : 'Korea-한국어', + direction : 'ltr', + dateFormat : 'Y-m-d H:i', // will show like: 2024-03-19 16:27 + fancyDateFormat : '$1 H:i', // will show like: 오늘 16:27 + nonameDateFormat : 'ymd-His', // noname upload will show like: 240319-162748 + messages : { + + /********************************** errors **********************************/ + 'error' : '오류', + 'errUnknown' : '알 수 없는 오류.', + 'errUnknownCmd' : '알 수 없는 명령어.', + 'errJqui' : 'jQuery UI 설정이 올바르지 않습니다. Selectable, draggable 및 droppable 구성 요소가 포함되어 있어야 합니다.', + 'errNode' : 'elFinder를 생성하기 위해서는 DOM Element를 요구합니다.', + 'errURL' : 'elFinder 환경설정이 올바르지 않습니다! URL 옵션이 설정되지 않았습니다.', + 'errAccess' : '접근 제한.', + 'errConnect' : 'Backend에 연결할 수 없습니다.', + 'errAbort' : '연결 실패.', + 'errTimeout' : '연결시간 초과.', + 'errNotFound' : 'Backend를 찾을 수 없습니다.', + 'errResponse' : 'Backend가 응답하지 않습니다.', + 'errConf' : 'Backend 환경설정이 올바르지 않습니다.', + 'errJSON' : 'PHP JSON 모듈이 설치되지 않았습니다.', + 'errNoVolumes' : '읽을 수 있는 볼륨이 없습니다.', + 'errCmdParams' : '"$1" 명령에 잘못된 매개 변수가 있습니다.', + 'errDataNotJSON' : '데이터가 JSON이 아닙니다.', + 'errDataEmpty' : '데이터가 비어있습니다.', + 'errCmdReq' : 'Backend 요청에는 명령어 이름이 필요합니다.', + 'errOpen' : '"$1"을(를) 열 수 없습니다.', + 'errNotFolder' : '폴더가 아닙니다.', + 'errNotFile' : '파일이 아닙니다.', + 'errRead' : '"$1"을(를) 읽을 수 없습니다.', + 'errWrite' : '"$1"에 쓸 수 없습니다.', + 'errPerm' : '권한이 없습니다.', + 'errLocked' : '"$1"이(가) 잠겨 있습니다, 이동, 삭제가 불가능합니다', + 'errExists' : '이미 "$1"파일이 존재합니다.', + 'errInvName' : '파일명에 올바르지 않은 문자가 포함되었습니다.', + 'errInvDirname' : '폴더명에 올바르지 않은 문자가 포함되었습니다.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : '폴더를 찾을 수 없습니다.', + 'errFileNotFound' : '파일을 찾을 수 없습니다.', + 'errTrgFolderNotFound' : '"$1" 폴더를 찾을 수 없습니다.', + 'errPopup' : '브라우저에서 팝업을 차단하였습니다. 팝업을 허용하려면 브라우저 옵션을 변경하세요.', + 'errMkdir' : '"$1" 폴더를 생성할 수 없습니다.', + 'errMkfile' : '"$1" 파일을 생성할 수 없습니다.', + 'errRename' : '"$1"의 이름을 변경할 수 없습니다.', + 'errCopyFrom' : '볼률 "$1"으(로)부터 파일을 복사할 수 없습니다.', + 'errCopyTo' : '볼률 "$1"에 파일을 복사할 수 없습니다.', + 'errMkOutLink' : 'root 볼륨 외부에 링크를 만들 수 없습니다.', // from v2.1 added 03.10.2015 + 'errUpload' : '업로드 오류.', // old name - errUploadCommon + 'errUploadFile' : '"$1"을(를) 업로드할 수 없습니다.', // old name - errUpload + 'errUploadNoFiles' : '업로드할 파일이 없습니다.', + 'errUploadTotalSize' : '데이터가 허용된 최대크기를 초과하였습니다.', // old name - errMaxSize + 'errUploadFileSize' : '파일이 허용된 최대크기를 초과하였습니다.', // old name - errFileMaxSize + 'errUploadMime' : '잘못된 파일형식입니다.', + 'errUploadTransfer' : '"$1" 전송 오류.', + 'errUploadTemp' : '업로드에 필요한 임시파일 생성을 할 수 없습니다.', // from v2.1 added 26.09.2015 + 'errNotReplace' : '"$1"개체가 현재 위치에 이미 존재하며 다른 유형의 개체로 대체 할 수 없습니다.', // new + 'errReplace' : '"$1"을(를) 변경할 수 없습니다.', + 'errSave' : '"$1"을(를) 저장할 수 없습니다.', + 'errCopy' : '"$1"을(를) 복사할 수 없습니다.', + 'errMove' : '"$1"을(를) 이동할 수 없습니다.', + 'errCopyInItself' : '"$1"을(를) 자기 자신에게 복사할 수 없습니다.', + 'errRm' : '"$1"의 이름을 변경할 수 없습니다.', + 'errTrash' : '휴지통으로 보낼 수 없습니다.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : '원본 파일을 제거할 수 없습니다.', + 'errExtract' : '"$1"에 압축을 풀 수 없습니다.', + 'errArchive' : '압축파일을 생성할 수 없습니다.', + 'errArcType' : '지원하지 않는 압축파일 형식입니다.', + 'errNoArchive' : '압축파일이 아니거나 지원하지 않는 압축파일 형식입니다.', + 'errCmdNoSupport' : 'Backend에서 이 명령을 지원하지 않습니다.', + 'errReplByChild' : '"$1" 폴더에 덮어쓸수 없습니다.', + 'errArcSymlinks' : '보안상의 이유로 압축파일이 심볼릭 링크를 포함하거나 허용되지 않는 이름이 있을 경우 압축 해제가 불가능합니다.', // edited 24.06.2012 + 'errArcMaxSize' : '압축파일이 허용된 최대크기를 초과하였습니다.', + 'errResize' : '"$1"의 크기 변경을 할 수 없습니다.', + 'errResizeDegree' : '회전가능한 각도가 아닙니다.', // added 7.3.2013 + 'errResizeRotate' : '이미지를 회전할 수 없습니다.', // added 7.3.2013 + 'errResizeSize' : '올바르지 않은 크기의 이미지입니다.', // added 7.3.2013 + 'errResizeNoChange' : '이미지 크기가 변경되지 않았습니다.', // added 7.3.2013 + 'errUsupportType' : '지원하지 않는 파일 형식.', + 'errNotUTF8Content' : '파일 "$1"은 UTF-8 형식이 아니어서 편집할 수 없습니다.', // added 9.11.2011 + 'errNetMount' : '"$1"을(를) 마운트할 수 없습니다.', // added 17.04.2012 + 'errNetMountNoDriver' : '지원되지 않는 프로토콜.', // added 17.04.2012 + 'errNetMountFailed' : '마운드 실패.', // added 17.04.2012 + 'errNetMountHostReq' : '호스트가 필요합니다.', // added 18.04.2012 + 'errSessionExpires' : '활동이 없어 세션이 만료되었습니다.', + 'errCreatingTempDir' : '임시 폴더 생성에 실패했습니다: "$1"', + 'errFtpDownloadFile' : 'FTP를 통한 다운로드에 실패했습니다: "$1"', + 'errFtpUploadFile' : 'FTP에 업로드 실패했습니다: "$1"', + 'errFtpMkdir' : 'FTP에서 폴더 생성에 실패했습니다: "$1"', + 'errArchiveExec' : '압축중 오류가 발생했습니다: "$1"', + 'errExtractExec' : '압축해제중 오류가 발생했습니다: "$1"', + 'errNetUnMount' : '마운트를 해제할 수 없습니다.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'UTF-8로 변환할 수 없습니다.', // from v2.1 added 08.04.2014 + 'errFolderUpload' : '폴더를 업로드 하려면 최신 브라우저를 사용하세요.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '"$1" 검색중 시간을 초과하였습니다. 일부 결과만 표시됩니다.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : '재인증이 필요합니다.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : '선택 가능한 최대 개수는 $1개입니다.', // from v2.1.17 added 17.10.2016 + 'errRestore' : '휴지통에서 복원할 수 없습니다. 복원할 위치를 확인할 수 없습니다.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : '이 파일 형식을 위한 편집기를 찾지 못했습니다.', // from v2.1.25 added 23.5.2017 + 'errServerError' : '서버측에서 오류가 발생했습니다.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : '"$1" 폴더를 비울 수 없습니다.', // from v2.1.25 added 22.6.2017 + 'moreErrors' : '$1개의 오류가 더 발생했습니다.', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'You can create up to $1 folders at one time.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : '압축파일생성', + 'cmdback' : '뒤로', + 'cmdcopy' : '복사', + 'cmdcut' : '자르기', + 'cmddownload' : '다운로드', + 'cmdduplicate' : '사본', + 'cmdedit' : '편집', + 'cmdextract' : '압축풀기', + 'cmdforward' : '앞으로', + 'cmdgetfile' : '선택', + 'cmdhelp' : '이 소프트웨어는', + 'cmdhome' : '홈', + 'cmdinfo' : '파일정보', + 'cmdmkdir' : '새 폴더', + 'cmdmkdirin' : '새 폴더로', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : '새 파일', + 'cmdopen' : '열기', + 'cmdpaste' : '붙여넣기', + 'cmdquicklook' : '미리보기', + 'cmdreload' : '새로고침', + 'cmdrename' : '이름바꾸기', + 'cmdrm' : '삭제', + 'cmdtrash' : '휴지통으로', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : '복원', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : '파일찾기', + 'cmdup' : '상위폴더', + 'cmdupload' : '업로드', + 'cmdview' : '보기', + 'cmdresize' : '이미지 크기 변경 & 회전', + 'cmdsort' : '정렬', + 'cmdnetmount' : '네트워크 볼륨 마운트', // added 18.04.2012 + 'cmdnetunmount': '마운트 해제', // from v2.1 added 30.04.2012 + 'cmdplaces' : '즐겨찾기로', // added 28.12.2014 + 'cmdchmod' : '모드 변경', // from v2.1 added 20.6.2015 + 'cmdopendir' : '폴더 열기', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : '컬럼 넓이 초기화', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': '전체 화면', // from v2.1.15 added 03.08.2016 + 'cmdmove' : '이동', // from v2.1.15 added 21.08.2016 + 'cmdempty' : '폴더 비우기', // from v2.1.25 added 22.06.2017 + 'cmdundo' : '실행 취소', // from v2.1.27 added 31.07.2017 + 'cmdredo' : '다시 실행', // from v2.1.27 added 31.07.2017 + 'cmdpreference': '환경설정', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : '전체 선택', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': '선택 취소', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': '선택 반전', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : '새 창으로 열기', // from v2.1.38 added 3.4.2018 + 'cmdhide' : '숨기기 (환경설정)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : '닫기', + 'btnSave' : '저장', + 'btnRm' : '삭제', + 'btnApply' : '적용', + 'btnCancel' : '취소', + 'btnNo' : '아니오', + 'btnYes' : '예', + 'btnDiscard': 'Discard changes', + 'btnMount' : '마운트', // added 18.04.2012 + 'btnApprove': '$1로 이동 및 승인', // from v2.1 added 26.04.2012 + 'btnUnmount': '마운트 해제', // from v2.1 added 30.04.2012 + 'btnConv' : '변환', // from v2.1 added 08.04.2014 + 'btnCwd' : '여기', // from v2.1 added 22.5.2015 + 'btnVolume' : '볼륨', // from v2.1 added 22.5.2015 + 'btnAll' : '전체', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME 타입', // from v2.1 added 22.5.2015 + 'btnFileName':'파일 이름', // from v2.1 added 22.5.2015 + 'btnSaveClose': '저장후 닫기', // from v2.1 added 12.6.2015 + 'btnBackup' : '백업', // fromv2.1 added 28.11.2015 + 'btnRename' : '이름변경', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : '전체이름 변경', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '이전 ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : '다음 ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : '다른 이름으로 저장하기', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : '폴더 열기', + 'ntffile' : '파일 열기', + 'ntfreload' : '새로고침', + 'ntfmkdir' : '폴더 생성', + 'ntfmkfile' : '파일 생성', + 'ntfrm' : '삭제', + 'ntfcopy' : '복사', + 'ntfmove' : '이동', + 'ntfprepare' : '복사 준비', + 'ntfrename' : '이름바꾸기', + 'ntfupload' : '업로드', + 'ntfdownload' : '다운로드', + 'ntfsave' : '저장하기', + 'ntfarchive' : '압축파일만들기', + 'ntfextract' : '압축풀기', + 'ntfsearch' : '검색', + 'ntfresize' : '이미지 크기 변경', + 'ntfsmth' : '작업중 >_<', + 'ntfloadimg' : '이미지 불러오는 중', + 'ntfnetmount' : '네트워크 볼륨 마운트 중', // added 18.04.2012 + 'ntfnetunmount': '네트워크 볼륨 마운트 해제 중', // from v2.1 added 30.04.2012 + 'ntfdim' : '이미지 해상도 가져오는 중', // added 20.05.2013 + 'ntfreaddir' : '폴더 정보 읽는 중', // from v2.1 added 01.07.2013 + 'ntfurl' : '링크 URL 가져오는 중', // from v2.1 added 11.03.2014 + 'ntfchmod' : '파일 모드 변경하는 중', // from v2.1 added 20.6.2015 + 'ntfpreupload': '업로드된 파일명 검증 중', // from v2.1 added 31.11.2015 + 'ntfzipdl' : '다운로드할 파일 생성 중', // from v2.1.7 added 23.1.2016 + 'ntfparents' : '경로 정보 가져오는 중', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': '업로드된 파일 처리 중', // from v2.1.17 added 2.11.2016 + 'ntftrash' : '휴지통으로 이동 중', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : '휴지통에서 복원 중', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : '대상 폴더 점검 중', // from v2.1.24 added 3.5.2017 + 'ntfundo' : '이전 작업 취소 중', // from v2.1.27 added 31.07.2017 + 'ntfredo' : '취소된 작업 다시 하는 중', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : '내용 확인 중', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : '휴지통', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : '알 수 없음', + 'Today' : '오늘', + 'Yesterday' : '어제', + 'msJan' : '1월', + 'msFeb' : '2월', + 'msMar' : '3월', + 'msApr' : '4월', + 'msMay' : '5월', + 'msJun' : '6월', + 'msJul' : '7월', + 'msAug' : '8월', + 'msSep' : '9월', + 'msOct' : '10월', + 'msNov' : '11월', + 'msDec' : '12월', + 'January' : '1월', + 'February' : '2월', + 'March' : '3월', + 'April' : '4월', + 'May' : '5월', + 'June' : '6월', + 'July' : '7월', + 'August' : '8월', + 'September' : '9월', + 'October' : '10월', + 'November' : '11월', + 'December' : '12월', + 'Sunday' : '일요일', + 'Monday' : '월요일', + 'Tuesday' : '화요일', + 'Wednesday' : '수요일', + 'Thursday' : '목요일', + 'Friday' : '금요일', + 'Saturday' : '토요일', + 'Sun' : '일', + 'Mon' : '월', + 'Tue' : '화', + 'Wed' : '수', + 'Thu' : '목', + 'Fri' : '금', + 'Sat' : '토', + + /******************************** sort variants ********************************/ + 'sortname' : '이름', + 'sortkind' : '종류', + 'sortsize' : '크기', + 'sortdate' : '날짜', + 'sortFoldersFirst' : '폴더 먼저', + 'sortperm' : '퍼미션별', // from v2.1.13 added 13.06.2016 + 'sortmode' : '모드별', // from v2.1.13 added 13.06.2016 + 'sortowner' : '소유자별', // from v2.1.13 added 13.06.2016 + 'sortgroup' : '그룹별', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : '트리뷰도 같이', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : '새파일.txt', // added 10.11.2015 + 'untitled folder' : '새폴더', // added 10.11.2015 + 'Archive' : '새아카이브', // from v2.1 added 10.11.2015 + 'untitled file' : '새파일.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: 파일', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : '확인', + 'confirmRm' : '이 파일을 정말로 삭제 하겠습니까?
                      실행 후 되돌릴 수 없습니다!', + 'confirmRepl' : '오래된 파일을 새 파일로 바꾸시겠습니까? (폴더가 포함되어 있으면 병합됩니다. 백업 및 교체하려면 백업을 선택하세요.)', + 'confirmRest' : '이미 있는 파일을 휴지통에 있는 파일로 교체하시겠습니까?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'UTF-8이 아닙니다
                      UTF-8로 변환할까요?
                      변환후 저장하면 UTF-8로 바뀝니다.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : '이 파일의 인코딩 타입을 알아내지 못했습니다. 편집하려면 임시로 UTF-8로 변환해야 합니다.
                      이 파일의 인코딩을 선택해주세요.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : '변경된 부분이 있습니다.
                      저장하지 않는다면 현재 작업중인 내용을 잃을 수 있습니다.', // from v2.1 added 15.7.2015 + 'confirmTrash' : '휴지통으로 이동하시겠습니까?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : '이 파일을 정말 "$1"(으)로 이동하시겠습니까?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : '모두 적용', + 'name' : '이름', + 'size' : '크기', + 'perms' : '권한', + 'modify' : '수정된 시간', + 'kind' : '종류', + 'read' : '읽기', + 'write' : '쓰기', + 'noaccess' : '액세스 불가', + 'and' : '와', + 'unknown' : '알 수 없음', + 'selectall' : '모든 파일 선택', + 'selectfiles' : '파일 선택', + 'selectffile' : '첫번째 파일 선택', + 'selectlfile' : '마지막 파일 선택', + 'viewlist' : '리스트 보기', + 'viewicons' : '아이콘 보기', + 'viewSmall' : '작은 아이콘', // from v2.1.39 added 22.5.2018 + 'viewMedium' : '중간 아이콘', // from v2.1.39 added 22.5.2018 + 'viewLarge' : '큰 아이콘', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : '아주 큰 아이콘', // from v2.1.39 added 22.5.2018 + 'places' : '즐겨찾기', + 'calc' : '계산', + 'path' : '경로', + 'aliasfor' : '별명', + 'locked' : '잠금', + 'dim' : '크기', + 'files' : '파일', + 'folders' : '폴더', + 'items' : '아이템', + 'yes' : '예', + 'no' : '아니오', + 'link' : '링크', + 'searcresult' : '검색 결과', + 'selected' : '아이템 선택', + 'about' : '이 프로그램은..', + 'shortcuts' : '단축아이콘', + 'help' : '도움말', + 'webfm' : '웹 파일매니저', + 'ver' : '버전', + 'protocolver' : '프로토콜 버전', + 'homepage' : '홈페이지', + 'docs' : '문서', + 'github' : 'Github에서 포크하기', + 'twitter' : '트위터에서 팔로우하기', + 'facebook' : '페이스북에서 가입하기', + 'team' : '팀', + 'chiefdev' : '개발팀장', + 'developer' : '개발자', + 'contributor' : '공헌자', + 'maintainer' : '관리자', + 'translator' : '번역', + 'icons' : '아이콘', + 'dontforget' : '그리고 수건 가져가는 것을 잊지 마세요', + 'shortcutsof' : '단축아이콘 사용불가', + 'dropFiles' : '여기로 이동하기', + 'or' : '또는', + 'selectForUpload' : '업로드 파일 선택', + 'moveFiles' : '파일 이동', + 'copyFiles' : '파일 복사', + 'restoreFiles' : '복원하기', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : '현재 폴더에서 삭제하기', + 'aspectRatio' : '화면비율', + 'scale' : '크기', + 'width' : '가로', + 'height' : '세로', + 'resize' : '사이즈 변경', + 'crop' : '자르기', + 'rotate' : '회전', + 'rotate-cw' : '반시계방향 90도 회전', + 'rotate-ccw' : '시계방향 90도 회전', + 'degree' : '도', + 'netMountDialogTitle' : '네트워크 볼륨 마운트', // added 18.04.2012 + 'protocol' : '프로토콜', // added 18.04.2012 + 'host' : '호스트', // added 18.04.2012 + 'port' : '포트', // added 18.04.2012 + 'user' : '사용자', // added 18.04.2012 + 'pass' : '비밀번호', // added 18.04.2012 + 'confirmUnmount' : '$1을(를) 마운트 해제하시겠습니까?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': '브라우저에서 파일을 끌어오거나 붙여넣으세요', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : '파일을 끌어오거나, 클립보드의 URL이나 이미지들을 붙여넣으세요', // from v2.1 added 07.04.2014 + 'encoding' : '인코딩', // from v2.1 added 19.12.2014 + 'locale' : '로케일', // from v2.1 added 19.12.2014 + 'searchTarget' : '대상: $1', // from v2.1 added 22.5.2015 + 'searchMime' : '입력한 MIME 타입으로 검색하기', // from v2.1 added 22.5.2015 + 'owner' : '소유자', // from v2.1 added 20.6.2015 + 'group' : '그룹', // from v2.1 added 20.6.2015 + 'other' : '그외', // from v2.1 added 20.6.2015 + 'execute' : '실행', // from v2.1 added 20.6.2015 + 'perm' : '권한', // from v2.1 added 20.6.2015 + 'mode' : '모드', // from v2.1 added 20.6.2015 + 'emptyFolder' : '빈 폴더입니다', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : '빈 폴더입니다\\A 드래드 앤 드롭으로 파일을 추가하세요', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : '빈 폴더입니다\\A 길게 눌러 파일을 추가하세요', // from v2.1.6 added 30.12.2015 + 'quality' : '품질', // from v2.1.6 added 5.1.2016 + 'autoSync' : '자동 동기', // from v2.1.6 added 10.1.2016 + 'moveUp' : '위로 이동', // from v2.1.6 added 18.1.2016 + 'getLink' : 'URL 링크 가져오기', // from v2.1.7 added 9.2.2016 + 'selectedItems' : '선택된 항목 ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : '폴더 ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : '오프라인 접근 허용', // from v2.1.10 added 3.25.2016 + 'reAuth' : '재인증하기', // from v2.1.10 added 3.25.2016 + 'nowLoading' : '로딩중...', // from v2.1.12 added 4.26.2016 + 'openMulti' : '여러 파일 열기', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': '$1 파일을 열려고 합니다. 브라우저에서 열겠습니까?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : '검색결과가 없습니다.', // from v2.1.12 added 5.16.2016 + 'editingFile' : '편집중인 파일입니다.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1개를 선택했습니다.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '클립보드에 $1개가 있습니다.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : '증분 검색은 현재 보기에서만 가능합니다.', // from v2.1.13 added 6.30.2016 + 'reinstate' : '복원', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 완료', // from v2.1.15 added 21.8.2016 + 'contextmenu' : '컨텍스트 메뉴', // from v2.1.15 added 9.9.2016 + 'pageTurning' : '페이지 전환', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : '볼륨 루트', // from v2.1.16 added 16.9.2016 + 'reset' : '초기화', // from v2.1.16 added 1.10.2016 + 'bgcolor' : '배경색', // from v2.1.16 added 1.10.2016 + 'colorPicker' : '색 선택기', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px 그리드', // from v2.1.16 added 4.10.2016 + 'enabled' : '활성', // from v2.1.16 added 4.10.2016 + 'disabled' : '비활성', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : '현재 보기에는 검색결과가 없습니다.\\A[Enter]를 눌러 검색 대상을 확장하세요.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : '현재 보기에는 첫 글자 검색 결과가 없습니다.', // from v2.1.23 added 24.3.2017 + 'textLabel' : '텍스트 라벨', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 분 남았습니다', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : '선택한 인코딩으로 다시 열기', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : '선택한 인코딩으로 저장하기', // from v2.1.19 added 2.12.2016 + 'selectFolder' : '폴더 선택', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': '첫 글자 검색', // from v2.1.23 added 24.3.2017 + 'presets' : '프리셋', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : '휴지통으로 옮기기엔 항목이 너무 많습니다.', // from v2.1.25 added 9.6.2017 + 'TextArea' : '글자영역', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : '"$1" 폴더를 비우세요.', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : '"$1" 폴더에 아무것도 없습니다.', // from v2.1.25 added 22.6.2017 + 'preference' : '환경설정', // from v2.1.26 added 28.6.2017 + 'language' : '언어 설정', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': '이 브라우저에 저장된 설정값 초기화하기', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : '툴바 설정', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 글자 남았습니다.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 줄 남았습니다.', // from v2.1.52 added 16.1.2020 + 'sum' : '합계', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : '대략적인 파일 크기', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : '마우스를 가져갈 때 대화창 요소에 초점 맞추기', // from v2.1.30 added 2.11.2017 + 'select' : '선택', // from v2.1.30 added 23.11.2017 + 'selectAction' : '파일 선택시 동작', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : '마지막 사용한 편집기로 열기', // from v2.1.30 added 23.11.2017 + 'selectinvert' : '선택 반전', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : '선택한 $1을(를) $2와 같이 바꾸겠습니까?
                      이 작업은 되돌릴 수 없습니다!', // from v2.1.31 added 4.12.2017 + 'batchRename' : '일괄 이름 바꾸기', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ 숫자', // from v2.1.31 added 8.12.2017 + 'asPrefix' : '접두사 추가', // from v2.1.31 added 8.12.2017 + 'asSuffix' : '접미사 추가', // from v2.1.31 added 8.12.2017 + 'changeExtention' : '확장자 변경', // from v2.1.31 added 8.12.2017 + 'columnPref' : '사이드바 설정 (리스트 보기)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : '모든 변경은 아카이브에 즉시 반영됩니다.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : '이 볼륨의 마운트를 해제할 때까지는 어떠한 변경사항도 반영되지 않습니다.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : '아래의 볼륨들도 이 볼륨과 함께 마운트가 해제됩니다. 계속하시겠습니까?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : '선택 정보', // from v2.1.33 added 7.3.2018 + 'hashChecker' : '파일 해쉬 알고리즘', // from v2.1.33 added 10.3.2018 + 'infoItems' : '정보 (선택 정보 패널)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': '나가기 위해서 한 번 더 누르세요.', // from v2.1.38 added 1.4.2018 + 'toolbar' : '툴바', // from v2.1.38 added 4.4.2018 + 'workspace' : '작업공간', // from v2.1.38 added 4.4.2018 + 'dialog' : '대화상자', // from v2.1.38 added 4.4.2018 + 'all' : '전체', // from v2.1.38 added 4.4.2018 + 'iconSize' : '아이콘 크기 (아이콘 보기)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : '최대화된 편집기 창을 엽니다', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : '현재 API를 통한 변환이 불가능하므로 웹 사이트에서 변환하시기 바랍니다.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : '변환 후 변환된 파일을 저장하기 위해서는 파일 URL이나 다운로드받은 파일을 업로드 해야 합니다.', //from v2.1.40 added 8.7.2018 + 'convertOn' : '$1 사이트에서 변환하시기 바랍니다.', // from v2.1.40 added 10.7.2018 + 'integrations' : '통합', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'elFinder에는 다음과 같은 외부 서비스가 통합되어 있습니다. 이용하기 전에 이용 약관, 개인정보 보호정책 등을 확인하시기 바랍니다.', // from v2.1.40 added 11.7.2018 + 'showHidden' : '숨겨진 파일 표시', // from v2.1.41 added 24.7.2018 + 'hideHidden' : '숨겨진 파일 숨기기', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : '숨겨진 항목 표시/숨기기', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : '"새 파일"에서 사용할 파일 형식', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : '텍스트 파일 유형', // from v2.1.41 added 7.8.2018 + 'add' : '추가', // from v2.1.41 added 7.8.2018 + 'theme' : '테마', // from v2.1.43 added 19.10.2018 + 'default' : '기본값', // from v2.1.43 added 19.10.2018 + 'description' : '설명', // from v2.1.43 added 19.10.2018 + 'website' : '웹사이트', // from v2.1.43 added 19.10.2018 + 'author' : '저자', // from v2.1.43 added 19.10.2018 + 'email' : '이메일', // from v2.1.43 added 19.10.2018 + 'license' : '라이선스', // from v2.1.43 added 19.10.2018 + 'exportToSave' : '이 파일은 저장될 수 없습니다. 편집한 내용을 유지하려면 PC로 내보내시기 바랍니다.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': '파일을 두 번 클릭하여 선택하세요.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : '전체 화면 모드 사용', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : '알 수 없음', + 'kindRoot' : 'Root 볼륨', // from v2.1.16 added 16.10.2016 + 'kindFolder' : '폴더', + 'kindSelects' : '선택', // from v2.1.29 added 29.8.2017 + 'kindAlias' : '별칭', + 'kindAliasBroken' : '손상된 별칭', + // applications + 'kindApp' : '응용프로그램', + 'kindPostscript' : 'Postscript 문서', + 'kindMsOffice' : 'Microsoft Office 문서', + 'kindMsWord' : 'Microsoft Word 문서', + 'kindMsExcel' : 'Microsoft Excel 문서', + 'kindMsPP' : 'Microsoft Powerpoint 프레젠테이션', + 'kindOO' : 'Open Office 문서', + 'kindAppFlash' : '플래쉬 파일', + 'kindPDF' : 'PDF 문서', + 'kindTorrent' : '비트토렌트 파일', + 'kind7z' : '7z 압축파일', + 'kindTAR' : 'TAR 압축파일', + 'kindGZIP' : 'GZIP 압축파일', + 'kindBZIP' : 'BZIP 압축파일', + 'kindXZ' : 'XZ 압축파일', + 'kindZIP' : 'ZIP 압축파일', + 'kindRAR' : 'RAR 압축파일', + 'kindJAR' : '자바 JAR 파일', + 'kindTTF' : '트루 타입 글꼴', + 'kindOTF' : '오픈 타입 글꼴', + 'kindRPM' : 'RPM 패키지', + // fonts + 'kindFont' : '글꼴', + 'kindSFNT' : 'SFNT 글꼴', + 'kindEOT' : 'Embedded Open Type 글꼴', + 'kindWOFF' : 'Web Open Font Format 글꼴', + 'kindWOFF2' : 'Web Open Font Format 2 글꼴', + // texts + 'kindText' : '텍스트 문서', + 'kindTextPlain' : '일반 텍스트', + 'kindPHP' : 'PHP 소스', + 'kindCSS' : 'CSS 문서', + 'kindHTML' : 'HTML 문서', + 'kindJS' : '자바스크립트 소스', + 'kindRTF' : 'RTF 형식', + 'kindC' : 'C 소스', + 'kindCHeader' : 'C 헤더 소스', + 'kindCPP' : 'C++ 소스', + 'kindCPPHeader' : 'C++ 헤더 소스', + 'kindShell' : '유닉스 쉘 스크립트', + 'kindPython' : '파이썬 소스', + 'kindJava' : '자바 소스', + 'kindRuby' : '루비 소스', + 'kindPerl' : '펄 스크립트', + 'kindSQL' : 'SQL 소스', + 'kindXML' : 'XML 문서', + 'kindAWK' : 'AWK 소스', + 'kindCSV' : 'CSV 파일', + 'kindDOCBOOK' : '닥북 XML 문서', + 'kindMarkdown' : '마크다운 문서', // added 20.7.2015 + // images + 'kindImage' : '이미지', + 'kindBMP' : 'BMP 이미지', + 'kindJPEG' : 'JPEG 이미지', + 'kindGIF' : 'GIF 이미지', + 'kindPNG' : 'PNG 이미지', + 'kindTIFF' : 'TIFF 이미지', + 'kindTGA' : 'TGA 이미지', + 'kindPSD' : 'Adobe Photoshop 이미지', + 'kindXBITMAP' : 'X 비트맵 이미지', + 'kindPXM' : 'Pixelmator 이미지', + // media + 'kindAudio' : '오디오 미디어', + 'kindAudioMPEG' : 'MPEG 오디오', + 'kindAudioMPEG4' : 'MPEG-4 오디오', + 'kindAudioMIDI' : 'MIDI 오디오', + 'kindAudioOGG' : 'Ogg Vorbis 오디오', + 'kindAudioWAV' : 'WAV 오디오', + 'AudioPlaylist' : 'MP3 플레이 리스트', + 'kindVideo' : '동영상 미디어', + 'kindVideoDV' : 'DV 동영상', + 'kindVideoMPEG' : 'MPEG 동영상', + 'kindVideoMPEG4' : 'MPEG-4 동영상', + 'kindVideoAVI' : 'AVI 동영상', + 'kindVideoMOV' : '퀵 타임 동영상', + 'kindVideoWM' : '윈도우 미디어 플레이어 동영상', + 'kindVideoFlash' : '플래쉬 동영상', + 'kindVideoMKV' : 'Matroska 동영상', + 'kindVideoOGG' : 'Ogg 동영상' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.nl.js b/lib/redactor/elfinder/js/i18n/elfinder.nl.js new file mode 100644 index 0000000..d2b884c --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.nl.js @@ -0,0 +1,588 @@ +/** + * Dutch translation + * @author Barry vd. Heuvel + * @author Patrick Tingen + * @version 2019-04-17 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.nl = { + translator : 'Barry vd. Heuvel <barry@fruitcakestudio.nl>, Patrick Tingen <patrick@tingen.net>', + language : 'Nederlands', + direction : 'ltr', + dateFormat : 'd-m-Y H:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 H:i', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'ymd-His', // noname upload will show like: 120513-172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Fout', + 'errUnknown' : 'Onbekend fout', + 'errUnknownCmd' : 'Onbekend commando', + 'errJqui' : 'Ongeldige jQuery UI configuratie. Selectable, draggable en droppable componenten moeten aanwezig zijn', + 'errNode' : 'Voor elFinder moet een DOM Element gemaakt worden', + 'errURL' : 'Ongeldige elFinder configuratie! URL optie is niet ingesteld', + 'errAccess' : 'Toegang geweigerd', + 'errConnect' : 'Kan geen verbinding met de backend maken', + 'errAbort' : 'Verbinding afgebroken', + 'errTimeout' : 'Verbinding time-out', + 'errNotFound' : 'Backend niet gevonden', + 'errResponse' : 'Ongeldige reactie van de backend', + 'errConf' : 'Ongeldige backend configuratie', + 'errJSON' : 'PHP JSON module niet geïnstalleerd', + 'errNoVolumes' : 'Leesbaar volume is niet beschikbaar', + 'errCmdParams' : 'Ongeldige parameters voor commando "$1"', + 'errDataNotJSON' : 'Data is niet JSON', + 'errDataEmpty' : 'Data is leeg', + 'errCmdReq' : 'Backend verzoek heeft een commando naam nodig', + 'errOpen' : 'Kan "$1" niet openen', + 'errNotFolder' : 'Object is geen map', + 'errNotFile' : 'Object is geen bestand', + 'errRead' : 'Kan "$1" niet lezen', + 'errWrite' : 'Kan niet schrijven in "$1"', + 'errPerm' : 'Toegang geweigerd', + 'errLocked' : '"$1" is vergrendeld en kan niet hernoemd, verplaats of verwijderd worden', + 'errExists' : 'Bestand "$1" bestaat al', + 'errInvName' : 'Ongeldige bestandsnaam', + 'errFolderNotFound' : 'Map niet gevonden', + 'errFileNotFound' : 'Bestand niet gevonden', + 'errTrgFolderNotFound' : 'Doelmap "$1" niet gevonden', + 'errPopup' : 'De browser heeft voorkomen dat de pop-up is geopend. Pas de browser instellingen aan om de popup te kunnen openen', + 'errMkdir' : 'Kan map "$1" niet aanmaken', + 'errMkfile' : 'Kan bestand "$1" niet aanmaken', + 'errRename' : 'Kan "$1" niet hernoemen', + 'errCopyFrom' : 'Bestanden kopiëren van "$1" is niet toegestaan', + 'errCopyTo' : 'Bestanden kopiëren naar "$1" is niet toegestaan', + 'errMkOutLink' : 'Kan geen link maken buiten de hoofdmap', // from v2.1 added 03.10.2015 + 'errUpload' : 'Upload fout', // old name - errUploadCommon + 'errUploadFile' : 'Kan "$1" niet uploaden', // old name - errUpload + 'errUploadNoFiles' : 'Geen bestanden gevonden om te uploaden', + 'errUploadTotalSize' : 'Data overschrijdt de maximale grootte', // old name - errMaxSize + 'errUploadFileSize' : 'Bestand overschrijdt de maximale grootte', // old name - errFileMaxSize + 'errUploadMime' : 'Bestandstype niet toegestaan', + 'errUploadTransfer' : '"$1" overdrachtsfout', + 'errUploadTemp' : 'Kan geen tijdelijk bestand voor de upload maken', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Object "$1" bestaat al op deze locatie en kan niet vervangen worden door een ander type object', // new + 'errReplace' : 'Kan "$1" niet vervangen', + 'errSave' : 'Kan "$1" niet opslaan', + 'errCopy' : 'Kan "$1" niet kopiëren', + 'errMove' : 'Kan "$1" niet verplaatsen', + 'errCopyInItself' : 'Kan "$1" niet in zichzelf kopiëren', + 'errRm' : 'Kan "$1" niet verwijderen', + 'errRmSrc' : 'Kan bronbestanden niet verwijderen', + 'errExtract' : 'Kan de bestanden van "$1" niet uitpakken', + 'errArchive' : 'Kan het archief niet maken', + 'errArcType' : 'Archief type is niet ondersteund', + 'errNoArchive' : 'Bestand is geen archief of geen ondersteund archief type', + 'errCmdNoSupport' : 'Backend ondersteund dit commando niet', + 'errReplByChild' : 'De map "$1" kan niet vervangen worden door een item uit die map', + 'errArcSymlinks' : 'Om veiligheidsredenen kan een bestand met symlinks of bestanden met niet toegestane namen niet worden uitgepakt ', // edited 24.06.2012 + 'errArcMaxSize' : 'Archief overschrijdt de maximale bestandsgrootte', + 'errResize' : 'Kan het formaat van "$1" niet wijzigen', + 'errResizeDegree' : 'Ongeldig aantal graden om te draaien', // added 7.3.2013 + 'errResizeRotate' : 'Afbeelding kan niet gedraaid worden', // added 7.3.2013 + 'errResizeSize' : 'Ongeldig afbeelding formaat', // added 7.3.2013 + 'errResizeNoChange' : 'Afbeelding formaat is niet veranderd', // added 7.3.2013 + 'errUsupportType' : 'Bestandstype wordt niet ondersteund', + 'errNotUTF8Content' : 'Bestand "$1" is niet in UTF-8 and kan niet aangepast worden', // added 9.11.2011 + 'errNetMount' : 'Kan "$1" niet mounten', // added 17.04.2012 + 'errNetMountNoDriver' : 'Niet ondersteund protocol', // added 17.04.2012 + 'errNetMountFailed' : 'Mount mislukt', // added 17.04.2012 + 'errNetMountHostReq' : 'Host is verplicht', // added 18.04.2012 + 'errSessionExpires' : 'Uw sessie is verlopen vanwege inactiviteit', + 'errCreatingTempDir' : 'Kan de tijdelijke map niet aanmaken: "$1" ', + 'errFtpDownloadFile' : 'Kan het bestand niet downloaden vanaf FTP: "$1"', + 'errFtpUploadFile' : 'Kan het bestand niet uploaden naar FTP: "$1"', + 'errFtpMkdir' : 'Kan het externe map niet aanmaken op de FTP-server: "$1"', + 'errArchiveExec' : 'Er is een fout opgetreden bij het archivering van de bestanden: "$1" ', + 'errExtractExec' : 'Er is een fout opgetreden bij het uitpakken van de bestanden: "$1" ', + 'errNetUnMount' : 'Kan niet unmounten', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Niet om te zetten naar UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Probeer een moderne browser als je bestanden wil uploaden', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Time-out bij zoeken naar "$1". Zoekresulataat is niet compleet', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Je moet je opnieuw aanmelden', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Max aantal selecteerbare items is $1', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Kan niet herstellen uit prullenbak, weet niet waar het heen moet', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Geen editor voor dit type bestand', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Fout opgetreden op de server', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Kan folder "$1" niet legen', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Er zijn nog $1 fouten', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Maak archief', + 'cmdback' : 'Vorige', + 'cmdcopy' : 'Kopieer', + 'cmdcut' : 'Knip', + 'cmddownload' : 'Download', + 'cmdduplicate' : 'Dupliceer', + 'cmdedit' : 'Pas bestand aan', + 'cmdextract' : 'Bestanden uit archief uitpakken', + 'cmdforward' : 'Volgende', + 'cmdgetfile' : 'Kies bestanden', + 'cmdhelp' : 'Over deze software', + 'cmdhome' : 'Home', + 'cmdinfo' : 'Bekijk info', + 'cmdmkdir' : 'Nieuwe map', + 'cmdmkdirin' : 'In nieuwe map', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nieuw bestand', + 'cmdopen' : 'Open', + 'cmdpaste' : 'Plak', + 'cmdquicklook' : 'Voorbeeld', + 'cmdreload' : 'Vernieuwen', + 'cmdrename' : 'Naam wijzigen', + 'cmdrm' : 'Verwijder', + 'cmdtrash' : 'Naar prullenbak', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Herstellen', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Zoek bestanden', + 'cmdup' : 'Ga een map hoger', + 'cmdupload' : 'Upload bestanden', + 'cmdview' : 'Bekijk', + 'cmdresize' : 'Formaat wijzigen', + 'cmdsort' : 'Sorteren', + 'cmdnetmount' : 'Mount netwerk volume', // added 18.04.2012 + 'cmdnetunmount' : 'Unmount', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Naar Plaatsen', // added 28.12.2014 + 'cmdchmod' : 'Wijzig modus', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Open een map', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Herstel kolombreedtes', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen' : 'Volledig scherm', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Verplaatsen', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Map leegmaken', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Undo', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Redo', // from v2.1.27 added 31.07.2017 + 'cmdpreference' : 'Voorkeuren', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Selecteer alles', // from v2.1.28 added 15.08.2017 + 'cmdselectnone' : 'Deselecteer alles', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert' : 'Selectie omkeren', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Open in nieuw venster', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Verberg (voorkeur)', // from v2.1.41 added 24.7.2018 + + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Sluit', + 'btnSave' : 'Opslaan', + 'btnRm' : 'Verwijder', + 'btnApply' : 'Toepassen', + 'btnCancel' : 'Annuleren', + 'btnNo' : 'Nee', + 'btnYes' : 'Ja', + 'btnDiscard' : 'Wijzigingen weggooien', + 'btnMount' : 'Mount', // added 18.04.2012 + 'btnApprove' : 'Ga naar $1 & keur goed', // from v2.1 added 26.04.2012 + 'btnUnmount' : 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Converteer', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Hier', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'Alles', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Type', // from v2.1 added 22.5.2015 + 'btnFileName' : 'Bestandsnaam', // from v2.1 added 22.5.2015 + 'btnSaveClose' : 'Opslaan & Sluiten', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Back-up', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Hernoemen', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Hernoem alles', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Vorige ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Volgende ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Opslaan als', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Bezig met openen van map', + 'ntffile' : 'Bezig met openen bestand', + 'ntfreload' : 'Herladen map inhoud', + 'ntfmkdir' : 'Bezig met map maken', + 'ntfmkfile' : 'Bezig met Bestanden maken', + 'ntfrm' : 'Verwijderen bestanden', + 'ntfcopy' : 'Kopieer bestanden', + 'ntfmove' : 'Verplaats bestanden', + 'ntfprepare' : 'Voorbereiden kopiëren', + 'ntfrename' : 'Hernoem bestanden', + 'ntfupload' : 'Bestanden uploaden actief', + 'ntfdownload' : 'Bestanden downloaden actief', + 'ntfsave' : 'Bestanden opslaan', + 'ntfarchive' : 'Archief aan het maken', + 'ntfextract' : 'Bestanden uitpakken actief', + 'ntfsearch' : 'Zoeken naar bestanden', + 'ntfresize' : 'Formaat wijzigen van afbeeldingen', + 'ntfsmth' : 'Iets aan het doen', + 'ntfloadimg' : 'Laden van plaatje', + 'ntfnetmount' : 'Mounten van netwerk volume', // added 18.04.2012 + 'ntfnetunmount' : 'Unmounten van netwerk volume', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Opvragen afbeeldingen dimensies', // added 20.05.2013 + 'ntfreaddir' : 'Map informatie lezen', // from v2.1 added 01.07.2013 + 'ntfurl' : 'URL van link ophalen', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Bestandsmodus wijzigen', // from v2.1 added 20.6.2015 + 'ntfpreupload' : 'Upload bestandsnaam verifiëren', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Zipbestand aan het maken', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Verzamelen padinformatie', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge' : 'Aan het verwerken', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Aan het verwijderen', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Aan het herstellen', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Controleren doelmap', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Vorige bewerking ongedaan maken', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Opnieuw doen', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Inhoud controleren', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Prullenbak', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'onbekend', + 'Today' : 'Vandaag', + 'Yesterday' : 'Gisteren', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Mei', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Januari', + 'February' : 'Februari', + 'March' : 'Maart', + 'April' : 'April', + 'May' : 'Mei', + 'June' : 'Juni', + 'July' : 'Juli', + 'August' : 'Augustus', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Zondag', + 'Monday' : 'Maandag', + 'Tuesday' : 'Dinsdag', + 'Wednesday' : 'Woensdag', + 'Thursday' : 'Donderdag', + 'Friday' : 'Vrijdag', + 'Saturday' : 'Zaterdag', + 'Sun' : 'Zo', + 'Mon' : 'Ma', + 'Tue' : 'Di', + 'Wed' : 'Wo', + 'Thu' : 'Do', + 'Fri' : 'Vr', + 'Sat' : 'Za', + + /******************************** sort variants ********************************/ + 'sortname' : 'op naam', + 'sortkind' : 'op type', + 'sortsize' : 'op grootte', + 'sortdate' : 'op datum', + 'sortFoldersFirst' : 'Mappen eerst', + 'sortperm' : 'op rechten', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'op mode', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'op eigenaar', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'op groep', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Als boom', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NieuwBestand.txt', // added 10.11.2015 + 'untitled folder' : 'NieuweMap', // added 10.11.2015 + 'Archive' : 'NieuwArchief', // from v2.1 added 10.11.2015 + 'untitled file' : 'NieuwBestand.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: Bestand', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Bevestiging nodig', + 'confirmRm' : 'Weet u zeker dat u deze bestanden wil verwijderen?
                      Deze actie kan niet ongedaan gemaakt worden!', + 'confirmRepl' : 'Oud bestand vervangen door het nieuwe bestand?', + 'confirmRest' : 'Replace existing item with the item in trash?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Niet in UTF-8
                      Converteren naar UTF-8?
                      De inhoud wordt UTF-8 door op te slaan na de conversie', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Character encoding of this file couldn\'t be detected. It need to temporarily convert to UTF-8 for editting.
                      Please select character encoding of this file.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Het is aangepast.
                      Wijzigingen gaan verloren als je niet opslaat', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Are you sure you want to move items to trash bin?', //from v2.1.24 added 29.4.2017 + 'apllyAll' : 'Toepassen op alles', + 'name' : 'Naam', + 'size' : 'Grootte', + 'perms' : 'Rechten', + 'modify' : 'Aangepast', + 'kind' : 'Type', + 'read' : 'lees', + 'write' : 'schrijf', + 'noaccess' : 'geen toegang', + 'and' : 'en', + 'unknown' : 'onbekend', + 'selectall' : 'Selecteer alle bestanden', + 'selectfiles' : 'Selecteer bestand(en)', + 'selectffile' : 'Selecteer eerste bestand', + 'selectlfile' : 'Selecteer laatste bestand', + 'viewlist' : 'Lijst weergave', + 'viewicons' : 'Icoon weergave', + 'viewSmall' : 'Klein', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Middelgroot', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Groot', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Extra groot', // from v2.1.39 added 22.5.2018 + 'places' : 'Plaatsen', + 'calc' : 'Bereken', + 'path' : 'Pad', + 'aliasfor' : 'Alias voor', + 'locked' : 'Vergrendeld', + 'dim' : 'Dimensies', + 'files' : 'Bestanden', + 'folders' : 'Mappen', + 'items' : 'Items', + 'yes' : 'ja', + 'no' : 'nee', + 'link' : 'Link', + 'searcresult' : 'Zoek resultaten', + 'selected' : 'geselecteerde items', + 'about' : 'Over', + 'shortcuts' : 'Snelkoppelingen', + 'help' : 'Help', + 'webfm' : 'Web bestandsmanager', + 'ver' : 'Versie', + 'protocolver' : 'protocol versie', + 'homepage' : 'Project home', + 'docs' : 'Documentatie', + 'github' : 'Fork ons op Github', + 'twitter' : 'Volg ons op twitter', + 'facebook' : 'Wordt lid op facebook', + 'team' : 'Team', + 'chiefdev' : 'Hoofd ontwikkelaar', + 'developer' : 'ontwikkelaar', + 'contributor' : 'bijdrager', + 'maintainer' : 'onderhouder', + 'translator' : 'vertaler', + 'icons' : 'Iconen', + 'dontforget' : 'En vergeet je handdoek niet!', + 'shortcutsof' : 'Snelkoppelingen uitgeschakeld', + 'dropFiles' : 'Sleep hier uw bestanden heen', + 'or' : 'of', + 'selectForUpload' : 'Selecteer bestanden om te uploaden', + 'moveFiles' : 'Verplaats bestanden', + 'copyFiles' : 'Kopieer bestanden', + 'restoreFiles' : 'Items herstellen', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Verwijder uit Plaatsen', + 'aspectRatio' : 'Aspect ratio', + 'scale' : 'Schaal', + 'width' : 'Breedte', + 'height' : 'Hoogte', + 'resize' : 'Verkleinen', + 'crop' : 'Bijsnijden', + 'rotate' : 'Draaien', + 'rotate-cw' : 'Draai 90 graden rechtsom', + 'rotate-ccw' : 'Draai 90 graden linksom', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount netwerk volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Poort', // added 18.04.2012 + 'user' : 'Gebruikersnaams', // added 18.04.2012 + 'pass' : 'Wachtwoord', // added 18.04.2012 + 'confirmUnmount' : 'Weet u zeker dat u $1 wil unmounten?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser' : 'Sleep of plak bestanden vanuit de browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Sleep of plak bestanden hier', // from v2.1 added 07.04.2014 + 'encoding' : 'Encodering', // from v2.1 added 19.12.2014 + 'locale' : 'Localisatie', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Doel: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Zoek op invoer MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Eigenaar', // from v2.1 added 20.6.2015 + 'group' : 'Groep', // from v2.1 added 20.6.2015 + 'other' : 'Overig', // from v2.1 added 20.6.2015 + 'execute' : 'Uitvoeren', // from v2.1 added 20.6.2015 + 'perm' : 'Rechten', // from v2.1 added 20.6.2015 + 'mode' : 'Modus', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Map is leeg', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Map is leeg\\A Sleep hier naar toe om toe te voegen', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Map is leeg\\A Lang ingedrukt houden om toe te voegen', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kwaliteit', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto sync', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Omhoog', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Geef link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Geselecteerde items ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Map ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Toestaan offline toegang', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Opnieuw autenticeren', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Laden..', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Open meerdere bestanden', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm' : 'Je probeert het $1 bestanden te openen. Weet je zeker dat je dat in je browser wil doen?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Geen zoekresultaten', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Bestand wordt bewerkt', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Je hebt $1 items geselecteerd', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Je hebt $1 items op het clipboard', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Verder zoeken kan alleen vanuit huidige view', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Herstellen', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 compleet', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Context menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Pagina omslaan', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016 + 'reset' : 'Reset', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Achtergrondkleur', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Kleurkiezer', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Grid', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Actief', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Inactief', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Zoekresultaten zijn leeg in actuele view\\ADruk [Enter] om zoekgebied uit te breiden', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Zoeken op eerste letter is leeg in actuele view', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Tekstlabel', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 minuten over', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Opnieuw openen met geselecteerde encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Opslaan met geselecteerde encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Selecteer map', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch' : 'Zoeken op eerste letter', // from v2.1.23 added 24.3.2017 + 'presets' : 'Voorkeuren', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Teveel voor in de prullenbak', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Tekstgebied', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Map "$1" legen', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Er zijn geen items in map "$1"', // from v2.1.25 added 22.6.2017 + 'preference' : 'Voorkeur', // from v2.1.26 added 28.6.2017 + 'language' : 'Taal', // from v2.1.26 added 28.6.2017 + 'clearBrowserData' : 'Initialiseer instellingen van deze browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Toolbar instellingen', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 tekens over', // from v2.1.29 added 30.8.2017 + 'sum' : 'Totaal', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Geschatte bestandsgrootte', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focus op het dialoogelement met mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Selecteren', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Actie als bestand is geselecteerd', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Open met laatstgebruikte editor', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Selectie omkeren', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Weet je zeker dat je $1 items wil hernoemen naar $2?
                      Dit kan niet ongedaan worden gemaakt!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch hernoemen', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Nummer', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Voeg prefix toe', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Voeg suffix toe', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Verander extentie', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Kolominstelllingen (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Aanpassingen worden direct toegepast op het archief', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Aanpassingen worden pas toegepast na re-mount van dit volume', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Deze volume(s) worden ook unmounted. Weet je het zeker?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Selectie informatie', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmes voor file hash', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Informatie Items (Selectie Info Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit' : 'Druk nogmaals om te eindigen', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Toolbar', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Work Space', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialoog', // from v2.1.38 added 4.4.2018 + 'all' : 'Alles', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Icoongrootte (Icons view)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Open de maximale editor', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Conversie via API is niet beschikbaar, converteer aub op de website', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Converteer op de site $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integratie', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Deze elFinder heeft de volgende externe services. Controleer de voorwaarden, privacy policy, etc. voor gebruik', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Toon verborgen items', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Verberg verborgen items', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Toon/verberg verborgen items', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'File types die aangemaakt mogen worden', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type voor tekstbestand', // from v2.1.41 added 7.8.2018 + 'add' : 'Toevoegen', // from v2.1.41 added 7.8.2018 + 'theme' : 'Thema', // from v2.1.43 added 19.10.2018 + 'default' : 'Default', // from v2.1.43 added 19.10.2018 + 'description' : 'Beschrijving', // from v2.1.43 added 19.10.2018 + 'website' : 'Website', // from v2.1.43 added 19.10.2018 + 'author' : 'Auteur', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'Licensie', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Dit item kan niet worden opgeslagen, exporteer naar je pc om wijzingen te bewaren', // from v2.1.44 added 1.12.2018 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Onbekend', + 'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Map', + 'kindSelects' : 'Selecties', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Verbroken alias', + + /********************************** applications **********************************/ + 'kindApp' : 'Applicatie', + 'kindPostscript' : 'Postscript document', + 'kindMsOffice' : 'Microsoft Office document', + 'kindMsWord' : 'Microsoft Word document', + 'kindMsExcel' : 'Microsoft Excel document', + 'kindMsPP' : 'Microsoft Powerpoint presentation', + 'kindOO' : 'Open Office document', + 'kindAppFlash' : 'Flash applicatie', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent bestand', + 'kind7z' : '7z archief', + 'kindTAR' : 'TAR archief', + 'kindGZIP' : 'GZIP archief', + 'kindBZIP' : 'BZIP archief', + 'kindXZ' : 'XZ archief', + 'kindZIP' : 'ZIP archief', + 'kindRAR' : 'RAR archief', + 'kindJAR' : 'Java JAR bestand', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM package', + /********************************** fonts **********************************/ + 'kindFont' : 'Lettertype bestand', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + + /********************************** texts **********************************/ + 'kindText' : 'Tekst bestand', + 'kindTextPlain' : 'Tekst', + 'kindPHP' : 'PHP bronbestand', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML document', + 'kindJS' : 'Javascript bronbestand', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C bronbestand', + 'kindCHeader' : 'C header bronbestand', + 'kindCPP' : 'C++ bronbestand', + 'kindCPPHeader' : 'C++ header bronbestand', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python bronbestand', + 'kindJava' : 'Java bronbestand', + 'kindRuby' : 'Ruby bronbestand', + 'kindPerl' : 'Perl bronbestand', + 'kindSQL' : 'SQL bronbestand', + 'kindXML' : 'XML document', + 'kindAWK' : 'AWK bronbestand', + 'kindCSV' : 'Komma gescheiden waardes', + 'kindDOCBOOK' : 'Docbook XML document', + 'kindMarkdown' : 'Markdown tekst', // added 20.7.2015 + + /********************************** images **********************************/ + + // + 'kindImage' : 'Afbeelding', + 'kindBMP' : 'BMP afbeelding', + 'kindJPEG' : 'JPEG afbeelding', + 'kindGIF' : 'GIF afbeelding', + 'kindPNG' : 'PNG afbeelding', + 'kindTIFF' : 'TIFF afbeelding', + 'kindTGA' : 'TGA afbeelding', + 'kindPSD' : 'Adobe Photoshop afbeelding', + 'kindXBITMAP' : 'X bitmap afbeelding', + 'kindPXM' : 'Pixelmator afbeelding', + + /********************************** media **********************************/ + 'kindAudio' : 'Audio media', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video media', + 'kindVideoDV' : 'DV video', + 'kindVideoMPEG' : 'MPEG video', + 'kindVideoMPEG4' : 'MPEG-4 video', + 'kindVideoAVI' : 'AVI video', + 'kindVideoMOV' : 'Quick Time video', + 'kindVideoWM' : 'Windows Media video', + 'kindVideoFlash' : 'Flash video', + 'kindVideoMKV' : 'Matroska video', + 'kindVideoOGG' : 'Ogg video' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.no.js b/lib/redactor/elfinder/js/i18n/elfinder.no.js new file mode 100644 index 0000000..718b8fb --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.no.js @@ -0,0 +1,381 @@ +/** + * Norwegian translation + * @author Stian Jacobsen + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.no = { + translator : 'Stian Jacobsen <stian@promonorge.no>', + language : 'Norwegian Bokmål', + dateFormat : 'M d, Y h:i A', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will produce smth like: Today 12:25 PM + direction : 'ltr', + messages : { + + /********************************** errors **********************************/ + 'error' : 'Feil', + 'errUnknown' : 'Ukjent feil.', + 'errUnknownCmd' : 'Ukjent kommando.', + 'errJqui' : 'Ugyldig jQuery UI konfigurasjon. Selectable, draggable og droppable komponentene må være inkludert.', + 'errNode' : 'elFinder påkrever at DOM Elementer kan opprettes.', + 'errURL' : 'Ugyldig elFinder konfigurasjon! URL-valget er ikke satt.', + 'errAccess' : 'Ingen adgang.', + 'errConnect' : 'Kunne ikke koble til.', + 'errAbort' : 'Tilkoblingen avbrutt.', + 'errTimeout' : 'Tilkoblingen tidsavbrudd.', + 'errNotFound' : 'Backend ble ikke funnet', + 'errResponse' : 'Ugyldig backend respons.', + 'errConf' : 'Ugyldig backend konfigurasjon.', + 'errJSON' : 'PHP JSON modul er ikke installert.', + 'errNoVolumes' : 'Lesbar volum er ikke tilgjennelig.', + 'errCmdParams' : 'Ugyldig parameter for kommando "$1".', + 'errDataNotJSON' : 'Innhold er ikke JSON.', + 'errDataEmpty' : 'Innholdet er tomt.', + 'errCmdReq' : 'Backend spørringen påkrever kommando.', + 'errOpen' : 'Kunne ikke åpne "$1".', + 'errNotFolder' : 'Objektet er ikke en mappe.', + 'errNotFile' : 'Objektet er ikke en fil.', + 'errRead' : 'Kunne ikke lese "$1".', + 'errWrite' : 'Kunne ikke skrive til "$1".', + 'errPerm' : 'Du har ikke rettigheter.', + 'errLocked' : '"$1" er låst og kan ikke flyttes, slettes eller endres', + 'errExists' : 'Filen "$1" finnes allerede.', + 'errInvName' : 'Ugyldig filnavn.', + 'errFolderNotFound' : 'Mappen finnes ikke.', + 'errFileNotFound' : 'Filen finnes ikke.', + 'errTrgFolderNotFound' : 'Målmappen "$1" ble ikke funnet.', + 'errPopup' : 'Nettleseren din blokkerte et pop-up vindu. For å åpne filen må du aktivere pop-up i din nettlesers innstillinger.', + 'errMkdir' : 'Kunne ikke opprette mappen "$1".', + 'errMkfile' : 'Kunne ikke opprette filen "$1".', + 'errRename' : 'Kunne ikke gi nytt navn til "$1".', + 'errCopyFrom' : 'Kopiere filer fra "$1" er ikke tillatt.', + 'errCopyTo' : 'Kopiere filer til "$1" er ikke tillatt.', + 'errUpload' : 'Feil under opplasting.', + 'errUploadFile' : 'Kunne ikke laste opp "$1".', + 'errUploadNoFiles' : 'Ingen filer funnet til opplasting.', + 'errUploadTotalSize' : 'Innholdet overgår maksimum tillatt størrelse.', + 'errUploadFileSize' : 'Filen vergår maksimum tillatt størrelse.', + 'errUploadMime' : 'Filtypen ikke tillatt.', + 'errUploadTransfer' : '"$1" overførings feil.', + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : 'Kunne ikke lagre "$1".', + 'errCopy' : 'Kunne ikke kopiere "$1".', + 'errMove' : 'Kunne ikke flytte "$1".', + 'errCopyInItself' : 'Kunne ikke kopiere "$1" til seg selv.', + 'errRm' : 'Kunne ikke slette "$1".', + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'Kunne ikke pakke ut filer fra "$1".', + 'errArchive' : 'Kunne ikke opprette arkiv.', + 'errArcType' : 'akriv-typen er ikke støttet.', + 'errNoArchive' : 'Filen er ikke et arkiv eller et arkiv som ikke er støttet.', + 'errCmdNoSupport' : 'Backend støtter ikke denne kommandoen.', + 'errReplByChild' : 'The folder “$1” can’t be replaced by an item it contains.', + 'errArcSymlinks' : 'For security reason denied to unpack archives contains symlinks or files with not allowed names.', // edited 24.06.2012 + 'errArcMaxSize' : 'Archive files exceeds maximum allowed size.', + 'errResize' : 'Unable to resize "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', // added 7.3.2013 + 'errResizeRotate' : 'Unable to rotate image.', // added 7.3.2013 + 'errResizeSize' : 'Invalid image size.', // added 7.3.2013 + 'errResizeNoChange' : 'Image size not changed.', // added 7.3.2013 + 'errUsupportType' : 'Unsupported file type.', + 'errNotUTF8Content' : 'File "$1" is not in UTF-8 and cannot be edited.', // added 9.11.2011 + 'errNetMount' : 'Unable to mount "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Unsupported protocol.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount failed.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host required.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Opprett arkiv', + 'cmdback' : 'Tilbake', + 'cmdcopy' : 'Kopier', + 'cmdcut' : 'Klipp ut', + 'cmddownload' : 'Last ned', + 'cmdduplicate' : 'Dupliser', + 'cmdedit' : 'Rediger fil', + 'cmdextract' : 'Pakk ut filer fra arkiv', + 'cmdforward' : 'Frem', + 'cmdgetfile' : 'Velg filer', + 'cmdhelp' : 'Om', + 'cmdhome' : 'Hjem', + 'cmdinfo' : 'Vis info', + 'cmdmkdir' : 'Ny mappe', + 'cmdmkfile' : 'Ny fil', + 'cmdopen' : 'Åpne', + 'cmdpaste' : 'Lim inn', + 'cmdquicklook' : 'Forhåndsvis', + 'cmdreload' : 'Last inn på nytt', + 'cmdrename' : 'Gi nytt navn', + 'cmdrm' : 'Slett', + 'cmdsearch' : 'Find filer', + 'cmdup' : 'Opp et nivå', + 'cmdupload' : 'Last opp filer', + 'cmdview' : 'Vis', + 'cmdresize' : 'Resize & Rotate', + 'cmdsort' : 'Sort', + 'cmdnetmount' : 'Mount network volume', + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Lukk', + 'btnSave' : 'Lagre', + 'btnRm' : 'Slett', + 'btnApply' : 'Apply', + 'btnCancel' : 'Avbryt', + 'btnNo' : 'Nei', + 'btnYes' : 'Ja', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', + + /******************************** notifications ********************************/ + 'ntfopen' : 'Åpne mappe', + 'ntffile' : 'Åpne fil', + 'ntfreload' : 'Last inn mappen på nytt', + 'ntfmkdir' : 'Oppretter mappe', + 'ntfmkfile' : 'Oppretter filer', + 'ntfrm' : 'Sletter filer', + 'ntfcopy' : 'Kopierer filer', + 'ntfmove' : 'Flytter filer', + 'ntfprepare' : 'Gjør klar til kopiering av filer', + 'ntfrename' : 'Gir nytt navn til filer', + 'ntfupload' : 'Laster opp filer', + 'ntfdownload' : 'Laster ned filer', + 'ntfsave' : 'Lagrer filer', + 'ntfarchive' : 'Oppretter arkiv', + 'ntfextract' : 'Pakker ut filer fra arkiv', + 'ntfsearch' : 'Søker i filer', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Gjør noe... >_<', + 'ntfloadimg' : 'Loading image', + 'ntfnetmount' : 'Mounting network volume', // added 18.04.2012 + 'ntfdim' : 'Acquiring image dimension', // added 20.05.2013 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Ukjent', + 'Today' : 'I dag', + 'Yesterday' : 'I går', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Mai', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Des', + 'January' : 'January', + 'February' : 'February', + 'March' : 'March', + 'April' : 'April', + 'May' : 'May', + 'June' : 'June', + 'July' : 'July', + 'August' : 'August', + 'September' : 'September', + 'October' : 'October', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Sunday', + 'Monday' : 'Monday', + 'Tuesday' : 'Tuesday', + 'Wednesday' : 'Wednesday', + 'Thursday' : 'Thursday', + 'Friday' : 'Friday', + 'Saturday' : 'Saturday', + 'Sun' : 'Sun', + 'Mon' : 'Mon', + 'Tue' : 'Tue', + 'Wed' : 'Wed', + 'Thu' : 'Thu', + 'Fri' : 'Fri', + 'Sat' : 'Sat', + + /******************************** sort variants ********************************/ + 'sortname' : 'by name', + 'sortkind' : 'by kind', + 'sortsize' : 'by size', + 'sortdate' : 'by date', + 'sortFoldersFirst' : 'Folders first', + + /********************************** messages **********************************/ + 'confirmReq' : 'Bekreftelse nødvendig', + 'confirmRm' : 'Er du sikker på at du ønsker å slette filene?', + 'confirmRepl' : 'Erstatt fil?', + 'apllyAll' : 'Apply to all', + 'name' : 'Navn', + 'size' : 'Størrelse', + 'perms' : 'Rettigheter', + 'modify' : 'Endret', + 'kind' : 'Type', + 'read' : 'les', + 'write' : 'skriv', + 'noaccess' : 'ingen adgang', + 'and' : 'og', + 'unknown' : 'ukjent', + 'selectall' : 'Velg alle filene', + 'selectfiles' : 'Velg fil(er)', + 'selectffile' : 'Velg første fil', + 'selectlfile' : 'Velg siste fil', + 'viewlist' : 'Listevisning', + 'viewicons' : 'Ikoner', + 'places' : 'Områder', + 'calc' : 'Beregn', + 'path' : 'Bane', + 'aliasfor' : 'Alias for', + 'locked' : 'Låst', + 'dim' : 'Størrelser', + 'files' : 'Filer', + 'folders' : 'Mapper', + 'items' : 'objekter', + 'yes' : 'ja', + 'no' : 'nei', + 'link' : 'Link', + 'searcresult' : 'Søkeresultater', + 'selected' : 'valgte filer', + 'about' : 'Om', + 'shortcuts' : 'Snarveier', + 'help' : 'Hjelp', + 'webfm' : 'Web-filbehandler', + 'ver' : 'Versjon', + 'protocolver' : 'protokol versjon', + 'homepage' : 'Project home', + 'docs' : 'dokumentasjon', + 'github' : 'Fork us on Github', + 'twitter' : 'Follow us on twitter', + 'facebook' : 'Join us on facebook', + 'team' : 'Team', + 'chiefdev' : 'chief developer', + 'developer' : 'developer', + 'contributor' : 'contributor', + 'maintainer' : 'maintainer', + 'translator' : 'translator', + 'icons' : 'Ikoner', + 'dontforget' : 'and don\'t forget to bring a towel', + 'shortcutsof' : 'Snarveier avslått', + 'dropFiles' : 'Slipp filer her', + 'or' : 'eller', + 'selectForUpload' : 'Velg filer til opplasting', + 'moveFiles' : 'Flytt filer', + 'copyFiles' : 'Kopier filer', + 'rmFromPlaces' : 'Remove from places', + 'aspectRatio' : 'Aspect ratio', + 'scale' : 'Scale', + 'width' : 'Width', + 'height' : 'Height', + 'resize' : 'Resize', + 'crop' : 'Crop', + 'rotate' : 'Rotate', + 'rotate-cw' : 'Rotate 90 degrees CW', + 'rotate-ccw' : 'Rotate 90 degrees CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'User', // added 18.04.2012 + 'pass' : 'Password', // added 18.04.2012 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Ukjent', + 'kindFolder' : 'Mappe', + 'kindAlias' : 'Snarvei', + 'kindAliasBroken' : 'Ugyldig snarvei', + // applications + 'kindApp' : 'Programfil', + 'kindPostscript' : 'Postscript dokument', + 'kindMsOffice' : 'Microsoft Office dokument', + 'kindMsWord' : 'Microsoft Word dokument', + 'kindMsExcel' : 'Microsoft Excel dokument', + 'kindMsPP' : 'Microsoft Powerpoint presentation', + 'kindOO' : 'Open Office dokument', + 'kindAppFlash' : 'Flash', + 'kindPDF' : 'Portabelt dokument (PDF)', + 'kindTorrent' : 'Bittorrent file', + 'kind7z' : '7z arkiv', + 'kindTAR' : 'TAR arkiv', + 'kindGZIP' : 'GZIP arkiv', + 'kindBZIP' : 'BZIP arkiv', + 'kindXZ' : 'XZ arkiv', + 'kindZIP' : 'ZIP arkiv', + 'kindRAR' : 'RAR ar', + 'kindJAR' : 'Java JAR file', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM package', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Tekst dokument', + 'kindTextPlain' : 'Plain text', + 'kindPHP' : 'PHP kilde', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML dokument', + 'kindJS' : 'Javascript', + 'kindRTF' : 'Rikt Tekst Format', + 'kindC' : 'C kilde', + 'kindCHeader' : 'C header kilde', + 'kindCPP' : 'C++ kilde', + 'kindCPPHeader' : 'C++ header kilde', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python kilde', + 'kindJava' : 'Java kilde', + 'kindRuby' : 'Ruby kilde', + 'kindPerl' : 'Perl script', + 'kindSQL' : 'SQL skilde', + 'kindXML' : 'XML dokument', + 'kindAWK' : 'AWK kilde', + 'kindCSV' : 'Comma separated values', + 'kindDOCBOOK' : 'Docbook XML dokument', + // Images + 'kindImage' : 'Bilde', + 'kindBMP' : 'BMP bilde', + 'kindJPEG' : 'JPEG bilde', + 'kindGIF' : 'GIF bilde', + 'kindPNG' : 'PNG bilde', + 'kindTIFF' : 'TIFF bilde', + 'kindTGA' : 'TGA bilde', + 'kindPSD' : 'Adobe Photoshop bilde', + 'kindXBITMAP' : 'X bitmap bilde', + 'kindPXM' : 'Pixelmator bilde', + // media + 'kindAudio' : 'Audio media', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 spilleliste', + 'kindVideo' : 'Video media', + 'kindVideoDV' : 'DV film', + 'kindVideoMPEG' : 'MPEG film', + 'kindVideoMPEG4' : 'MPEG-4 film', + 'kindVideoAVI' : 'AVI film', + 'kindVideoMOV' : 'Quick Time film', + 'kindVideoWM' : 'Windows Media film', + 'kindVideoFlash' : 'Flash film', + 'kindVideoMKV' : 'Matroska film', + 'kindVideoOGG' : 'Ogg film' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.pl.js b/lib/redactor/elfinder/js/i18n/elfinder.pl.js new file mode 100644 index 0000000..12e4a42 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.pl.js @@ -0,0 +1,587 @@ +/** + * Polskie tłumaczenie + * @author Marcin Mikołajczyk + * @author Bogusław Zięba + * @version 2020-03-29 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.pl = { + translator : 'Marcin Mikołajczyk <marcin@pjwstk.edu.pl>, Bogusław Zięba <bobi@poczta.fm>, Bogusław Zięba <bobi@poczta.fm>', + language : 'Polski', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // will show like: 29.03.2020 06:58 + fancyDateFormat : '$1 H:i', // will show like: Dzisiaj 06:58 + nonameDateFormat : 'ymd-His', // noname upload will show like: 200329-065813 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Błąd', + 'errUnknown' : 'Nieznany błąd.', + 'errUnknownCmd' : 'Nieznane polecenie.', + 'errJqui' : 'Niepoprawna konfiguracja jQuery UI. Muszą być zawarte komponenty selectable, draggable i droppable.', + 'errNode' : 'elFinder wymaga utworzenia obiektu DOM.', + 'errURL' : 'Niepoprawna konfiguracja elFinder! Pole URL nie jest ustawione.', + 'errAccess' : 'Dostęp zabroniony.', + 'errConnect' : 'Błąd połączenia z zapleczem.', + 'errAbort' : 'Połączenie zostało przerwane.', + 'errTimeout' : 'Upłynął czas oczekiwania na połączenie.', + 'errNotFound' : 'Zaplecze nie zostało znalezione.', + 'errResponse' : 'Nieprawidłowa odpowiedź zaplecza.', + 'errConf' : 'Niepoprawna konfiguracja zaplecza.', + 'errJSON' : 'Moduł PHP JSON nie jest zainstalowany.', + 'errNoVolumes' : 'Brak możliwości odczytu katalogów.', + 'errCmdParams' : 'Nieprawidłowe parametry dla polecenia "$1".', + 'errDataNotJSON' : 'Dane nie są JSON.', + 'errDataEmpty' : 'Dane są puste.', + 'errCmdReq' : 'Zaplecze wymaga podania nazwy polecenia.', + 'errOpen' : 'Nie można otworzyć "$1".', + 'errNotFolder' : 'Obiekt nie jest katalogiem.', + 'errNotFile' : 'Obiekt nie jest plikiem.', + 'errRead' : 'Nie można odczytać "$1".', + 'errWrite' : 'Nie można zapisać do "$1".', + 'errPerm' : 'Brak uprawnień.', + 'errLocked' : '"$1" jest zablokowany i nie może zostać zmieniony, przeniesiony lub usunięty.', + 'errExists' : 'Plik "$1" już istnieje.', + 'errInvName' : 'Nieprawidłowa nazwa pliku.', + 'errInvDirname' : 'Nieprawidłowa nazwa folderu.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Nie znaleziono folderu.', + 'errFileNotFound' : 'Plik nie został znaleziony.', + 'errTrgFolderNotFound' : 'Katalog docelowy "$1" nie został znaleziony.', + 'errPopup' : 'Przeglądarka zablokowała otwarcie nowego okna. Aby otworzyć plik, zmień ustawienia przeglądarki.', + 'errMkdir' : 'Nie można utworzyć katalogu "$1".', + 'errMkfile' : 'Nie można utworzyć pliku "$1".', + 'errRename' : 'Nie można zmienić nazwy "$1".', + 'errCopyFrom' : 'Kopiowanie z katalogu "$1" nie jest możliwe.', + 'errCopyTo' : 'Kopiowanie do katalogu "$1" nie jest możliwe.', + 'errMkOutLink' : 'Nie można utworzyć link do zewnętrznego katalogu głównego.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Błąd wysyłania.', // old name - errUploadCommon + 'errUploadFile' : 'Nie można wysłać "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Nie znaleziono plików do wysłania.', + 'errUploadTotalSize' : 'Przekroczono dopuszczalny rozmiar wysyłanych plików.', // old name - errMaxSize + 'errUploadFileSize' : 'Plik przekracza dopuszczalny rozmiar.', // old name - errFileMaxSize + 'errUploadMime' : 'Niedozwolony typ pliku.', + 'errUploadTransfer' : 'Błąd przesyłania "$1".', + 'errUploadTemp' : 'Nie można wykonać tymczasowego pliku do przesłania.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Obiekt "$1" istnieje już w tej lokalizacji i nie może być zastąpiony przez inny typ obiektu.', // new + 'errReplace' : 'Nie można zastąpić "$1".', + 'errSave' : 'Nie można zapisać "$1".', + 'errCopy' : 'Nie można skopiować "$1".', + 'errMove' : 'Nie można przenieść "$1".', + 'errCopyInItself' : 'Nie można skopiować "$1" w miejsce jego samego.', + 'errRm' : 'Nie można usunąć "$1".', + 'errTrash' : 'Nie można do kosza.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Nie należy usunąć pliku(s) źródłowy.', + 'errExtract' : 'Nie można wypakować plików z "$1".', + 'errArchive' : 'Nie można utworzyć archiwum.', + 'errArcType' : 'Nieobsługiwany typ archiwum.', + 'errNoArchive' : 'Plik nie jest prawidłowym typem archiwum.', + 'errCmdNoSupport' : 'Zaplecze nie obsługuje tego polecenia.', + 'errReplByChild' : 'Nie można zastąpić katalogu "$1" elementem w nim zawartym', + 'errArcSymlinks' : 'Ze względów bezpieczeństwa rozpakowywanie archiwów zawierających dowiązania symboliczne (symlinks) jest niedozwolone.', // edited 24.06.2012 + 'errArcMaxSize' : 'Archiwum przekracza maksymalny dopuszczalny rozmiar.', + 'errResize' : 'Nie można zmienić rozmiaru "$1".', + 'errResizeDegree' : 'Nieprawidłowy stopień obracania.', // added 7.3.2013 + 'errResizeRotate' : 'Nie można obrócić obrazu.', // added 7.3.2013 + 'errResizeSize' : 'Nieprawidłowy rozmiar obrazu.', // added 7.3.2013 + 'errResizeNoChange' : 'Nie zmieniono rozmiaru obrazu.', // added 7.3.2013 + 'errUsupportType' : 'Nieobsługiwany typ pliku.', + 'errNotUTF8Content' : 'Plik "$1" nie jest UTF-8 i nie może być edytowany.', // added 9.11.2011 + 'errNetMount' : 'Nie można zamontować "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Nieobsługiwany protokół.', // added 17.04.2012 + 'errNetMountFailed' : 'Montowanie nie powiodło się.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host wymagany.', // added 18.04.2012 + 'errSessionExpires' : 'Twoja sesja wygasła z powodu nieaktywności.', + 'errCreatingTempDir' : 'Nie można utworzyć katalogu tymczasowego: "$1"', + 'errFtpDownloadFile' : 'Nie można pobrać pliku z FTP: "$1"', + 'errFtpUploadFile' : 'Nie można przesłać pliku na serwer FTP: "$1"', + 'errFtpMkdir' : 'Nie można utworzyć zdalnego katalogu FTP: "$1"', + 'errArchiveExec' : 'Błąd podczas archiwizacji plików: "$1"', + 'errExtractExec' : 'Błąd podczas wyodrębniania plików: "$1"', + 'errNetUnMount' : 'Nie można odmontować', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Nie wymienialne na UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Wypróbuj Google Chrome, jeśli chcesz przesłać katalog.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Upłynął limit czasu podczas wyszukiwania "$1". Wynik wyszukiwania jest częściowy.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Wymagana jest ponowna autoryzacja.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Maks. liczba elementów do wyboru to $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Nie można przywrócić z kosza. Nie można zidentyfikować przywrócić docelowego.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Nie znaleziono edytora tego typu pliku.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Wystąpił błąd po stronie serwera .', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Nie można do pustego folderu "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Jest jeszcze $1 błąd/błędy.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Utwórz archiwum', + 'cmdback' : 'Wstecz', + 'cmdcopy' : 'Kopiuj', + 'cmdcut' : 'Wytnij', + 'cmddownload' : 'Pobierz', + 'cmdduplicate' : 'Duplikuj', + 'cmdedit' : 'Edytuj plik', + 'cmdextract' : 'Wypakuj pliki z archiwum', + 'cmdforward' : 'Dalej', + 'cmdgetfile' : 'Wybierz pliki', + 'cmdhelp' : 'Informacje o programie', + 'cmdhome' : 'Główny', + 'cmdinfo' : 'Właściwości', + 'cmdmkdir' : 'Nowy katalog', + 'cmdmkdirin' : 'Do nowego katalogu', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nowy plik', + 'cmdopen' : 'Otwórz', + 'cmdpaste' : 'Wklej', + 'cmdquicklook' : 'Podgląd', + 'cmdreload' : 'Odśwież', + 'cmdrename' : 'Zmień nazwę', + 'cmdrm' : 'Usuń', + 'cmdtrash' : 'Do kosza', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Przywróć', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Wyszukaj pliki', + 'cmdup' : 'Przejdź do katalogu nadrzędnego', + 'cmdupload' : 'Wyślij pliki', + 'cmdview' : 'Widok', + 'cmdresize' : 'Zmień rozmiar i Obróć', + 'cmdsort' : 'Sortuj', + 'cmdnetmount' : 'Zamontuj wolumin sieciowy', // added 18.04.2012 + 'cmdnetunmount': 'Odmontuj', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Do Miejsc', // added 28.12.2014 + 'cmdchmod' : 'Zmiana trybu', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Otwórz katalog', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Resetuj szerokość kolumny', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Pełny ekran', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Przenieś', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Opróżnij folder', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Cofnij', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Ponów', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferencje', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Zaznacz wszystko', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Odznacz wszystko', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Odwróć wybór', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Otwórz w nowym oknie', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Ukryj (osobiste)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Zamknij', + 'btnSave' : 'Zapisz', + 'btnRm' : 'Usuń', + 'btnApply' : 'Zastosuj', + 'btnCancel' : 'Anuluj', + 'btnNo' : 'Nie', + 'btnYes' : 'Tak', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Montuj', // added 18.04.2012 + 'btnApprove': 'Idź do $1 & zatwierdź', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Odmontuj', // from v2.1 added 30.04.2012 + 'btnConv' : 'Konwertuj', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Tutaj', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Wolumin', // from v2.1 added 22.5.2015 + 'btnAll' : 'Wszystko', // from v2.1 added 22.5.2015 + 'btnMime' : 'Typ MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nazwa pliku', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Zapisz & Zamknij', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Kopia zapasowa', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Zmień nazwę', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Zmień nazwę(Wszystkie)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Poprz ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Nast ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Zapisz Jako', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Otwieranie katalogu', + 'ntffile' : 'Otwórz plik', + 'ntfreload' : 'Odśwież zawartość katalogu', + 'ntfmkdir' : 'Tworzenie katalogu', + 'ntfmkfile' : 'Tworzenie plików', + 'ntfrm' : 'Usuwanie plików', + 'ntfcopy' : 'Kopiowanie plików', + 'ntfmove' : 'Przenoszenie plików', + 'ntfprepare' : 'Przygotowanie do kopiowania plików', + 'ntfrename' : 'Zmiana nazw plików', + 'ntfupload' : 'Wysyłanie plików', + 'ntfdownload' : 'Pobieranie plików', + 'ntfsave' : 'Zapisywanie plików', + 'ntfarchive' : 'Tworzenie archiwum', + 'ntfextract' : 'Wypakowywanie plików z archiwum', + 'ntfsearch' : 'Wyszukiwanie plików', + 'ntfresize' : 'Zmiana rozmiaru obrazów', + 'ntfsmth' : 'Robienie czegoś >_<', + 'ntfloadimg' : 'Ładowanie obrazu', + 'ntfnetmount' : 'Montaż woluminu sieciowego', // added 18.04.2012 + 'ntfnetunmount': 'Odłączanie woluminu sieciowego', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Pozyskiwanie wymiaru obrazu', // added 20.05.2013 + 'ntfreaddir' : 'Odczytywanie informacji katalogu', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Pobieranie URL linku', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Zmiana trybu pliku', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Weryfikacja nazwy przesłanego pliku', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Tworzenie pliku do pobrania', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Uzyskiwanie informacji o ścieżce', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Przetwarzanie przesłanego pliku', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Wykonuje wrzucanie do kosza', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Wykonuje przywracanie z kosza', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Sprawdzanie folderu docelowego', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Cofanie poprzedniej operacji', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Ponownie poprzednio cofnięte', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Sprawdzanie zawartości', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Śmieci', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'nieznana', + 'Today' : 'Dzisiaj', + 'Yesterday' : 'Wczoraj', + 'msJan' : 'Sty', + 'msFeb' : 'Lut', + 'msMar' : 'Mar', + 'msApr' : 'Kwi', + 'msMay' : 'Maj', + 'msJun' : 'Cze', + 'msJul' : 'Lip', + 'msAug' : 'Sie', + 'msSep' : 'Wrz', + 'msOct' : 'Paź', + 'msNov' : 'Lis', + 'msDec' : 'Gru', + 'January' : 'Styczeń', + 'February' : 'Luty', + 'March' : 'Marzec', + 'April' : 'Kwiecień', + 'May' : 'Maj', + 'June' : 'Czerwiec', + 'July' : 'Lipiec', + 'August' : 'Sierpień', + 'September' : 'Wrzesień', + 'October' : 'Październik', + 'November' : 'Listopad', + 'December' : 'Grudzień', + 'Sunday' : 'Niedziela', + 'Monday' : 'Poniedziałek', + 'Tuesday' : 'Wtorek', + 'Wednesday' : 'Środa', + 'Thursday' : 'Czwartek', + 'Friday' : 'Piątek', + 'Saturday' : 'Sobota', + 'Sun' : 'Nie', + 'Mon' : 'Pon', + 'Tue' : 'Wto', + 'Wed' : 'Śro', + 'Thu' : 'Czw', + 'Fri' : 'Pią', + 'Sat' : 'Sob', + + /******************************** sort variants ********************************/ + 'sortname' : 'w/g nazwy', + 'sortkind' : 'w/g typu', + 'sortsize' : 'w/g rozmiaru', + 'sortdate' : 'w/g daty', + 'sortFoldersFirst' : 'katalogi pierwsze', + 'sortperm' : 'wg/nazwy', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'wg/trybu', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'wg/właściciela', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'wg/grup', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Również drzewa katalogów', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NowyPlik.txt', // added 10.11.2015 + 'untitled folder' : 'NowyFolder', // added 10.11.2015 + 'Archive' : 'NoweArchiwum', // from v2.1 added 10.11.2015 + 'untitled file' : 'NowyPlik.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1 Plik', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Wymagane potwierdzenie', + 'confirmRm' : 'Czy na pewno chcesz usunąć pliki?
                      Tej operacji nie można cofnąć!', + 'confirmRepl' : 'Zastąpić stary plik nowym?', + 'confirmRest' : 'Zamienić istniejący element na pozycję w koszu?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Nie w UTF-8
                      Konwertować na UTF-8?
                      Zawartość stanie się UTF-8 poprzez zapisanie po konwersji.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Nie można wykryć kodowania tego pliku. Musi być tymczasowo przekształcony do UTF-8.
                      Proszę wybrać kodowanie znaków tego pliku.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Został zmodyfikowany.
                      Utracisz pracę, jeśli nie zapiszesz zmian.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Czy na pewno chcesz przenieść elementy do kosza?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Czy na pewno chcesz przenieść elementy do "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Zastosuj do wszystkich', + 'name' : 'Nazwa', + 'size' : 'Rozmiar', + 'perms' : 'Uprawnienia', + 'modify' : 'Zmodyfikowany', + 'kind' : 'Typ', + 'read' : 'odczyt', + 'write' : 'zapis', + 'noaccess' : 'brak dostępu', + 'and' : 'i', + 'unknown' : 'nieznany', + 'selectall' : 'Zaznacz wszystkie pliki', + 'selectfiles' : 'Zaznacz plik(i)', + 'selectffile' : 'Zaznacz pierwszy plik', + 'selectlfile' : 'Zaznacz ostatni plik', + 'viewlist' : 'Widok listy', + 'viewicons' : 'Widok ikon', + 'viewSmall' : 'Małe ikony', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Średnie ikony', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Duże ikony', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Bardzo duże ikony', // from v2.1.39 added 22.5.2018 + 'places' : 'Ulubione', + 'calc' : 'Obliczanie', + 'path' : 'Ścieżka', + 'aliasfor' : 'Alias do', + 'locked' : 'Zablokowany', + 'dim' : 'Wymiary', + 'files' : 'Plik(ów)', + 'folders' : 'Katalogi', + 'items' : 'Element(ów)', + 'yes' : 'tak', + 'no' : 'nie', + 'link' : 'Odnośnik', + 'searcresult' : 'Wyniki wyszukiwania', + 'selected' : 'zaznaczonych obiektów', + 'about' : 'O programie', + 'shortcuts' : 'Skróty klawiaturowe', + 'help' : 'Pomoc', + 'webfm' : 'Menedżer plików sieciowych', + 'ver' : 'Wersja', + 'protocolver' : 'wersja protokołu', + 'homepage' : 'Strona projektu', + 'docs' : 'Dokumentacja', + 'github' : 'Obserwuj rozwój projektu na Github', + 'twitter' : 'Śledź nas na Twitterze', + 'facebook' : 'Dołącz do nas na Facebooku', + 'team' : 'Zespół', + 'chiefdev' : 'główny programista', + 'developer' : 'programista', + 'contributor' : 'współautor', + 'maintainer' : 'koordynator', + 'translator' : 'tłumacz', + 'icons' : 'Ikony', + 'dontforget' : 'i nie zapomnij zabrać ręcznika', + 'shortcutsof' : 'Skróty klawiaturowe są wyłączone', + 'dropFiles' : 'Upuść pliki tutaj', + 'or' : 'lub', + 'selectForUpload' : 'Wybierz pliki', + 'moveFiles' : 'Przenieś pliki', + 'copyFiles' : 'Kopiuj pliki', + 'restoreFiles' : 'Przywróć elementy', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Usuń z miejsc', + 'aspectRatio' : 'Zachowaj proporcje', + 'scale' : 'Skala', + 'width' : 'Szerokość', + 'height' : 'Wysokość', + 'resize' : 'Zmień rozmiar', + 'crop' : 'Przytnij', + 'rotate' : 'Obróć', + 'rotate-cw' : 'Obróć 90° w lewo', + 'rotate-ccw' : 'Obróć 90° w prawo', + 'degree' : '°', + 'netMountDialogTitle' : 'Montaż woluminu sieciowego', // added 18.04.2012 + 'protocol' : 'Protokół', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Użytkownik', // added 18.04.2012 + 'pass' : 'Hasło', // added 18.04.2012 + 'confirmUnmount' : 'Czy chcesz odmontować $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Upuść lub Wklej pliki z przeglądarki', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Upuść lub Wklej tutaj pliki i adresy URL', // from v2.1 added 07.04.2014 + 'encoding' : 'Kodowanie', // from v2.1 added 19.12.2014 + 'locale' : 'Lokalne', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Docelowo: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Wyszukiwanie poprzez wpisanie typu MIME', // from v2.1 added 22.5.2015 + 'owner' : 'Właściciel', // from v2.1 added 20.6.2015 + 'group' : 'Grupa', // from v2.1 added 20.6.2015 + 'other' : 'Inne', // from v2.1 added 20.6.2015 + 'execute' : 'Wykonaj', // from v2.1 added 20.6.2015 + 'perm' : 'Uprawnienia', // from v2.1 added 20.6.2015 + 'mode' : 'Tryb', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Katalog jest pusty', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Katalog jest pusty\\AUpuść aby dodać pozycje', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Katalog jest pusty\\ADotknij dłużej aby dodać pozycje', // from v2.1.6 added 30.12.2015 + 'quality' : 'Jakość', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto synchronizacja', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Przenieś w górę', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Pobierz URL linku', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Wybrane pozycje ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID Katalogu', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Zezwól na dostęp offline', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Aby ponownie uwierzytelnić', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Teraz ładuję...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Otwieranie wielu plików', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Próbujesz otworzyć $1 plików. Czy na pewno chcesz, aby otworzyć w przeglądarce?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Wynik wyszukiwania jest pusty', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Edytujesz plik.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Masz wybranych $1 pozycji.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Masz $1 pozycji w schowku.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Wyszukiwanie przyrostowe jest wyłącznie z bieżącego widoku.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Przywracanie', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 zakończone', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Menu kontekstowe', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Obracanie strony', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Wolumin główny', // from v2.1.16 added 16.9.2016 + 'reset' : 'Resetuj', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Kolor tła', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Wybierania kolorów', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Kratka', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Włączone', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Wyłączone', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Wyniki wyszukiwania są puste w bieżącym widoku.\\AWciśnij [Enter] aby poszerzyć zakres wyszukiwania.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Wyszukiwanie pierwszej litery brak wyników w bieżącym widoku.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Etykieta tekstowa', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 min pozostało', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Otwórz ponownie z wybranym kodowaniem', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Zapisz z wybranym kodowaniem', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Wybierz katalog', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Wyszukiwanie pierwszej litery', // from v2.1.23 added 24.3.2017 + 'presets' : 'Wstępnie ustalone', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'To zbyt wiele rzeczy, więc nie mogą być w koszu.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'PoleTekstowe', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Opróżnij folder "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Brak elementów w folderze "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preferencje', // from v2.1.26 added 28.6.2017 + 'language' : 'Ustawienie języka', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Zainicjuj ustawienia zapisane w tej przeglądarce', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Ustawienia paska narzędzi', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... pozostało $1 znak(ów).', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... pozostało $1 lini.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Suma', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Przybliżony rozmiar pliku', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Skoncentruj się na elemencie dialogowym po najechaniu myszą', // from v2.1.30 added 2.11.2017 + 'select' : 'Wybierz', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Działanie po wybraniu pliku', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Otwórz za pomocą ostatnio używanego edytora', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Odwróć zaznaczenie', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Czy na pewno chcesz zmienić nazwę $1 wybranych elementów takich jak $2?
                      Tego nie da się cofnąć!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Zmień partiami', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Liczba', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Dodaj prefix', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Dodaj suffix', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Zmień rozszerzenie', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Ustawienia kolumn (Widok listy)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Wszystkie zmiany widoczne natychmiast w archiwum.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Wszelkie zmiany nie będą widoczne, dopóki nie odłączysz tego woluminu.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Następujący wolumin (y), zamontowany na tym urządzeniu również niezamontowany. Czy na pewno chcesz go odmontować?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Informacje Wyboru', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorytmy do pokazywania hash pliku', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info Elementów (Wybór Panelu Informacyjnego)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Naciśnij ponownie, aby wyjść.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Pasek narzędziowy', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Obszar Pracy', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'Wszystko', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Rozmiar Ikony (Podgląd ikon)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Otwórz zmaksymalizowane okno edytora', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Ponieważ konwersja przez API nie jest obecnie dostępna, należy dokonać konwersji w witrynie.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Po konwersji musisz przesłać z adresem URL pozycji lub pobranym plikiem, aby zapisać przekonwertowany plik.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Konwertuj na stronie $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integracje', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Ten elFinder ma zintegrowane następujące usługi zewnętrzne. Przed użyciem ich sprawdź warunki użytkowania, politykę prywatności itp.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Pokaż ukryte pozycje', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Ukryj ukryte pozycje', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Pokaż/Ukryj ukryte pozycje', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Typy plików, które można włączyć za pomocą "Nowy plik"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Typ pliku tekstowego', // from v2.1.41 added 7.8.2018 + 'add' : 'Dodaj', // from v2.1.41 added 7.8.2018 + 'theme' : 'Motyw', // from v2.1.43 added 19.10.2018 + 'default' : 'Domyślnie', // from v2.1.43 added 19.10.2018 + 'description' : 'Opis', // from v2.1.43 added 19.10.2018 + 'website' : 'Witryna', // from v2.1.43 added 19.10.2018 + 'author' : 'Autor', // from v2.1.43 added 19.10.2018 + 'email' : 'E-mail', // from v2.1.43 added 19.10.2018 + 'license' : 'Licencja', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Tego elementu nie można zapisać. Aby uniknąć utraty zmian, musisz wyeksportować go na swój komputer.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Kliknij dwukrotnie plik, aby go wybrać.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Użyj trybu pełnoekranowego', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Nieznany', + 'kindRoot' : 'Główny Wolumin', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Katalog', + 'kindSelects' : 'Zaznaczenie', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Utracony alias', + // applications + 'kindApp' : 'Aplikacja', + 'kindPostscript' : 'Dokument Postscript', + 'kindMsOffice' : 'Dokument Office', + 'kindMsWord' : 'Dokument Word', + 'kindMsExcel' : 'Dokument Excel', + 'kindMsPP' : 'Prezentacja PowerPoint', + 'kindOO' : 'Dokument OpenOffice', + 'kindAppFlash' : 'Aplikacja Flash', + 'kindPDF' : 'Dokument przenośny PDF', + 'kindTorrent' : 'Plik BitTorrent', + 'kind7z' : 'Archiwum 7z', + 'kindTAR' : 'Archiwum TAR', + 'kindGZIP' : 'Archiwum GZIP', + 'kindBZIP' : 'Archiwum BZIP', + 'kindXZ' : 'Archiwum XZ', + 'kindZIP' : 'Archiwum ZIP', + 'kindRAR' : 'Archiwum RAR', + 'kindJAR' : 'Plik Java JAR', + 'kindTTF' : 'Czcionka TrueType', + 'kindOTF' : 'Czcionka OpenType', + 'kindRPM' : 'Pakiet RPM', + // fonts + 'kindFont' : 'Czcionka', + 'kindSFNT' : 'Czcionka SFNT', + 'kindEOT' : 'Czcionka Embedded Open Type', + 'kindWOFF' : 'Czcionka Web Open Font Format', + 'kindWOFF2' : 'Czcionka Web Open Font Format 2', + // texts + 'kindText' : 'Dokument tekstowy', + 'kindTextPlain' : 'Zwykły tekst', + 'kindPHP' : 'Kod źródłowy PHP', + 'kindCSS' : 'Kaskadowe arkusze stylów', + 'kindHTML' : 'Dokument HTML', + 'kindJS' : 'Kod źródłowy Javascript', + 'kindRTF' : 'Tekst sformatowany RTF', + 'kindC' : 'Kod źródłowy C', + 'kindCHeader' : 'Plik nagłówka C', + 'kindCPP' : 'Kod źródłowy C++', + 'kindCPPHeader' : 'Plik nagłówka C++', + 'kindShell' : 'Skrypt powłoki Unix', + 'kindPython' : 'Kod źródłowy Python', + 'kindJava' : 'Kod źródłowy Java', + 'kindRuby' : 'Kod źródłowy Ruby', + 'kindPerl' : 'Skrypt Perl', + 'kindSQL' : 'Kod źródłowy SQL', + 'kindXML' : 'Dokument XML', + 'kindAWK' : 'Kod źródłowy AWK', + 'kindCSV' : 'Tekst rozdzielany przecinkami CSV', + 'kindDOCBOOK' : 'Dokument Docbook XML', + 'kindMarkdown' : 'Tekst promocyjny', // added 20.7.2015 + // images + 'kindImage' : 'Obraz', + 'kindBMP' : 'Obraz BMP', + 'kindJPEG' : 'Obraz JPEG', + 'kindGIF' : 'Obraz GIF', + 'kindPNG' : 'Obraz PNG', + 'kindTIFF' : 'Obraz TIFF', + 'kindTGA' : 'Obraz TGA', + 'kindPSD' : 'Obraz Adobe Photoshop', + 'kindXBITMAP' : 'Obraz X BitMap', + 'kindPXM' : 'Obraz Pixelmator', + // media + 'kindAudio' : 'Plik dźwiękowy', + 'kindAudioMPEG' : 'Plik dźwiękowy MPEG', + 'kindAudioMPEG4' : 'Plik dźwiękowy MPEG-4', + 'kindAudioMIDI' : 'Plik dźwiękowy MIDI', + 'kindAudioOGG' : 'Plik dźwiękowy Ogg Vorbis', + 'kindAudioWAV' : 'Plik dźwiękowy WAV', + 'AudioPlaylist' : 'Lista odtwarzania MP3', + 'kindVideo' : 'Plik wideo', + 'kindVideoDV' : 'Plik wideo DV', + 'kindVideoMPEG' : 'Plik wideo MPEG', + 'kindVideoMPEG4' : 'Plik wideo MPEG-4', + 'kindVideoAVI' : 'Plik wideo AVI', + 'kindVideoMOV' : 'Plik wideo Quick Time', + 'kindVideoWM' : 'Plik wideo Windows Media', + 'kindVideoFlash' : 'Plik wideo Flash', + 'kindVideoMKV' : 'Plik wideo Matroska', + 'kindVideoOGG' : 'Plik wideo Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.pt_BR.js b/lib/redactor/elfinder/js/i18n/elfinder.pt_BR.js new file mode 100644 index 0000000..3966b57 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.pt_BR.js @@ -0,0 +1,587 @@ +/** + * Português translation + * @author Leandro Carvalho + * @author Wesley Osorio + * @author Fernando H. Bandeira + * @author Gustavo Brito + * @version 2019-10-22 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.pt_BR = { + translator : 'Leandro Carvalho <contato@leandrowebdev.net>, Wesley Osorio<wesleyfosorio@hotmail.com>, Fernando H. Bandeira <fernando.bandeira94@gmail.com>, Gustavo Brito <britopereiragustavo@gmail.com>', + language : 'Português', + direction : 'ltr', + dateFormat : 'd M Y H:i', // will show like: 22 Out 2019 11:34 + fancyDateFormat : '$1 H:i', // will show like: Hoje 11:34 + nonameDateFormat : 'ymd-His', // noname upload will show like: 191022-113433 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Erro', + 'errUnknown' : 'Erro desconhecido.', + 'errUnknownCmd' : 'Comando desconhecido.', + 'errJqui' : 'Configuração inválida do JQuery UI. Verifique se os componentes selectable, draggable e droppable estão incluídos.', + 'errNode' : 'elFinder requer um elemento DOM para ser criado.', + 'errURL' : 'Configuração inválida do elFinder! Você deve setar a opção da URL.', + 'errAccess' : 'Acesso negado.', + 'errConnect' : 'Incapaz de conectar ao backend.', + 'errAbort' : 'Conexão abortada.', + 'errTimeout' : 'Tempo de conexão excedido', + 'errNotFound' : 'Backend não encontrado.', + 'errResponse' : 'Resposta inválida do backend.', + 'errConf' : 'Configuração inválida do backend.', + 'errJSON' : 'Módulo PHP JSON não está instalado.', + 'errNoVolumes' : 'Não existe nenhum volume legível disponivel.', + 'errCmdParams' : 'Parâmetro inválido para o comando "$1".', + 'errDataNotJSON' : 'Dados não estão no formato JSON.', + 'errDataEmpty' : 'Dados vazios.', + 'errCmdReq' : 'Requisição do Backend requer nome de comando.', + 'errOpen' : 'Incapaz de abrir "$1".', + 'errNotFolder' : 'Objeto não é uma pasta.', + 'errNotFile' : 'Objeto não é um arquivo.', + 'errRead' : 'Incapaz de ler "$1".', + 'errWrite' : 'Incapaz de escrever em "$1".', + 'errPerm' : 'Permissão negada.', + 'errLocked' : '"$1" está bloqueado e não pode ser renomeado, movido ou removido.', + 'errExists' : 'O nome do arquivo "$1" já existe neste local.', + 'errInvName' : 'Nome do arquivo inválido.', + 'errInvDirname' : 'Nome da pasta inválida.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Pasta não encontrada.', + 'errFileNotFound' : 'Arquivo não encontrado.', + 'errTrgFolderNotFound' : 'Pasta de destino "$1" não encontrada.', + 'errPopup' : 'O seu navegador está bloqueando popup\'s. Para abrir o arquivo, altere esta opção no seu Navegador.', + 'errMkdir' : 'Incapaz de criar a pasta "$1".', + 'errMkfile' : 'Incapaz de criar o arquivo "$1".', + 'errRename' : 'Incapaz de renomear "$1".', + 'errCopyFrom' : 'Copia dos arquivos do volume "$1" não permitida.', + 'errCopyTo' : 'Copia dos arquivos para o volume "$1" não permitida.', + 'errMkOutLink' : 'Incapaz de criar um link fora da unidade raiz.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Erro no upload.', // old name - errUploadCommon + 'errUploadFile' : 'Não foi possível fazer o upload "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Não foi encontrado nenhum arquivo para upload.', + 'errUploadTotalSize' : 'Os dados excedem o tamanho máximo permitido.', // old name - errMaxSize + 'errUploadFileSize' : 'Arquivo excede o tamanho máximo permitido.', // old name - errFileMaxSize + 'errUploadMime' : 'Tipo de arquivo não permitido.', + 'errUploadTransfer' : '"$1" erro na transferência.', + 'errUploadTemp' : 'Incapaz de criar um arquivo temporário para upload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Objeto "$1" já existe neste local e não pode ser substituído por um objeto com outro tipo.', // new + 'errReplace' : 'Incapaz de substituir "$1".', + 'errSave' : 'Incapaz de salvar "$1".', + 'errCopy' : 'Incapaz de copiar "$1".', + 'errMove' : 'Incapaz de mover "$1".', + 'errCopyInItself' : 'Incapaz de copiar "$1" nele mesmo.', + 'errRm' : 'Incapaz de remover "$1".', + 'errTrash' : 'Incapaz de deletar.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Incapaz de remover o(s) arquivo(s) fonte.', + 'errExtract' : 'Incapaz de extrair os arquivos de "$1".', + 'errArchive' : 'Incapaz de criar o arquivo.', + 'errArcType' : 'Tipo de arquivo não suportado.', + 'errNoArchive' : 'Arquivo inválido ou é de um tipo não suportado.', + 'errCmdNoSupport' : 'Backend não suporta este comando.', + 'errReplByChild' : 'A pasta “$1” não pode ser substituída por um item que contém.', + 'errArcSymlinks' : 'Por razões de segurança, negada a permissão para descompactar arquivos que contenham links ou arquivos com nomes não permitidos.', // edited 24.06.2012 + 'errArcMaxSize' : 'Arquivo excede o tamanho máximo permitido.', + 'errResize' : 'Incapaz de redimensionar "$1".', + 'errResizeDegree' : 'Grau de rotação inválido.', // added 7.3.2013 + 'errResizeRotate' : 'Incapaz de rotacionar a imagem.', // added 7.3.2013 + 'errResizeSize' : 'Tamanho inválido de imagem.', // added 7.3.2013 + 'errResizeNoChange' : 'Tamanho da imagem não alterado.', // added 7.3.2013 + 'errUsupportType' : 'Tipo de arquivo não suportado.', + 'errNotUTF8Content' : 'Arquivo "$1" não está em UTF-8 e não pode ser editado.', // added 9.11.2011 + 'errNetMount' : 'Incapaz de montar montagem "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protocolo não suportado.', // added 17.04.2012 + 'errNetMountFailed' : 'Montagem falhou.', // added 17.04.2012 + 'errNetMountHostReq' : 'Servidor requerido.', // added 18.04.2012 + 'errSessionExpires' : 'Sua sessão expirou por inatividade.', + 'errCreatingTempDir' : 'Não foi possível criar um diretório temporário: "$1"', + 'errFtpDownloadFile' : 'Não foi possível fazer o download do arquivo do FTP: "$1"', + 'errFtpUploadFile' : 'Não foi possível fazer o upload do arquivo para o FTP: "$1"', + 'errFtpMkdir' : 'Não foi possível criar um diretório remoto no FTP: "$1"', + 'errArchiveExec' : 'Erro ao arquivar os arquivos: "$1"', + 'errExtractExec' : 'Erro na extração dos arquivos: "$1"', + 'errNetUnMount' : 'Incapaz de desmontar', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Não conversivel para UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Tente utilizar o Google Chrome, se você deseja enviar uma pasta.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Tempo limite atingido para a busca "$1". O resultado da pesquisa é parcial.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Re-autorização é necessária.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'O número máximo de itens selecionáveis ​​é $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Não foi possível restaurar a partir do lixo. Não é possível identificar o destino da restauração.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor não encontrado para este tipo de arquivo.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Ocorreu um erro no lado do servidor.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Não foi possível esvaziar a pasta "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Existem mais $1 erros.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Criar arquivo', + 'cmdback' : 'Voltar', + 'cmdcopy' : 'Copiar', + 'cmdcut' : 'Cortar', + 'cmddownload' : 'Baixar', + 'cmdduplicate' : 'Duplicar', + 'cmdedit' : 'Editar arquivo', + 'cmdextract' : 'Extrair arquivo de ficheiros', + 'cmdforward' : 'Avançar', + 'cmdgetfile' : 'Selecionar arquivos', + 'cmdhelp' : 'Sobre este software', + 'cmdhome' : 'Home', + 'cmdinfo' : 'Propriedades', + 'cmdmkdir' : 'Nova pasta', + 'cmdmkdirin' : 'Em uma nova pasta', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Novo arquivo', + 'cmdopen' : 'Abrir', + 'cmdpaste' : 'Colar', + 'cmdquicklook' : 'Pré-vizualização', + 'cmdreload' : 'Recarregar', + 'cmdrename' : 'Renomear', + 'cmdrm' : 'Deletar', + 'cmdtrash' : 'Mover para a lixeira', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Restaurar', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Achar arquivos', + 'cmdup' : 'Ir para o diretório pai', + 'cmdupload' : 'Fazer upload de arquivo', + 'cmdview' : 'Vizualizar', + 'cmdresize' : 'Redimencionar & Rotacionar', + 'cmdsort' : 'Ordenar', + 'cmdnetmount' : 'Montar unidade de rede', // added 18.04.2012 + 'cmdnetunmount': 'Desmontar', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Para locais', // added 28.12.2014 + 'cmdchmod' : 'Alterar permissão', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Abrir pasta', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Redefinir largura da coluna', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Tela cheia', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Mover', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Esvaziar a pasta', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Desfazer', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Refazer', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferências', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Selecionar tudo', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Selecionar nenhum', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Inverter seleção', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Abrir em nova janela', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Ocultar (preferência)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Fechar', + 'btnSave' : 'Salvar', + 'btnRm' : 'Remover', + 'btnApply' : 'Aplicar', + 'btnCancel' : 'Cancelar', + 'btnNo' : 'Não', + 'btnYes' : 'Sim', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Montar', // added 18.04.2012 + 'btnApprove': 'Vá para $1 & aprove', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Desmontar', // from v2.1 added 30.04.2012 + 'btnConv' : 'Converter', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Aqui', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'Todos', // from v2.1 added 22.5.2015 + 'btnMime' : 'Tipo MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nome do arquivo', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Salvar & Fechar', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Renomear', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Renomear (tudo)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Anterior ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Próximo ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Salvar como', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Abrir pasta', + 'ntffile' : 'Abrir arquivo', + 'ntfreload' : 'Recarregar conteudo da pasta', + 'ntfmkdir' : 'Criar diretório', + 'ntfmkfile' : 'Criar arquivos', + 'ntfrm' : 'Deletar arquivos', + 'ntfcopy' : 'Copiar arquivos', + 'ntfmove' : 'Mover arquivos', + 'ntfprepare' : 'Preparando para copiar arquivos', + 'ntfrename' : 'Renomear arquivos', + 'ntfupload' : 'Subindo os arquivos', + 'ntfdownload' : 'Baixando os arquivos', + 'ntfsave' : 'Salvando os arquivos', + 'ntfarchive' : 'Criando os arquivos', + 'ntfextract' : 'Extraindo arquivos compactados', + 'ntfsearch' : 'Procurando arquivos', + 'ntfresize' : 'Redimensionando imagens', + 'ntfsmth' : 'Fazendo alguma coisa', + 'ntfloadimg' : 'Carregando Imagem', + 'ntfnetmount' : 'Montando unidade de rede', // added 18.04.2012 + 'ntfnetunmount': 'Desmontando unidade de rede', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Adquirindo dimensão da imagem', // added 20.05.2013 + 'ntfreaddir' : 'Lendo informações da pasta', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Recebendo URL do link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Alterando permissões do arquivo', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Verificando o nome do arquivo de upload', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Criando um arquivo para download', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Obtendo informações do caminho', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Processando o arquivo carregado', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Movendo para a lixeira', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Restaurando da lixeira', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Verificando a pasta de destino', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Desfazendo a operação anterior', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Refazendo o desfazer anterior', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Verificando conteúdos', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Lixo', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Desconhecido', + 'Today' : 'Hoje', + 'Yesterday' : 'Ontem', + 'msJan' : 'Jan', + 'msFeb' : 'Fev', + 'msMar' : 'Mar', + 'msApr' : 'Abr', + 'msMay' : 'Mai', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Ago', + 'msSep' : 'Set', + 'msOct' : 'Out', + 'msNov' : 'Nov', + 'msDec' : 'Dez', + 'January' : 'Janeiro', + 'February' : 'Fevereiro', + 'March' : 'Março', + 'April' : 'Abril', + 'May' : 'Maio', + 'June' : 'Junho', + 'July' : 'Julho', + 'August' : 'Agosto', + 'September' : 'Setembro', + 'October' : 'Outubro', + 'November' : 'Novembro', + 'December' : 'Dezembro', + 'Sunday' : 'Domingo', + 'Monday' : 'Segunda-feira', + 'Tuesday' : 'Terça-feira', + 'Wednesday' : 'Quarta-feira', + 'Thursday' : 'Quinta-feira', + 'Friday' : 'Sexta-feira', + 'Saturday' : 'Sábado', + 'Sun' : 'Dom', + 'Mon' : 'Seg', + 'Tue' : 'Ter', + 'Wed' : 'Qua', + 'Thu' : 'Qui', + 'Fri' : 'Sex', + 'Sat' : 'Sáb', + + /******************************** sort variants ********************************/ + 'sortname' : 'por nome', + 'sortkind' : 'por tipo', + 'sortsize' : 'por tam.', + 'sortdate' : 'por data', + 'sortFoldersFirst' : 'Pastas primeiro', + 'sortperm' : 'Com permissão', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'Por modo', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'Por proprietário', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'Por grupo', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Vizualizar em árvore', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NovoArquivo.txt', // added 10.11.2015 + 'untitled folder' : 'NovaPasta', // added 10.11.2015 + 'Archive' : 'NovoArquivo', // from v2.1 added 10.11.2015 + 'untitled file' : 'NovoArquivo.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: Arquivo', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Confirmação requerida', + 'confirmRm' : 'Você tem certeza que deseja remover os arquivos?
                      Isto não pode ser desfeito!', + 'confirmRepl' : 'Substituir arquivo velho com este novo?', + 'confirmRest' : 'Substituir o item existente pelo item na lixeira?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Não está em UTF-8
                      Converter para UTF-8?
                      Conteúdo se torna UTF-8 após salvar as conversões.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Não foi possível detectar a codificação de caracteres deste arquivo. Ele precisa ser convertido temporariamente em UTF-8 para edição. Por favor, selecione a codificação de caracteres deste arquivo.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Isto foi modificado.
                      Você vai perder seu trabalho caso não salve as mudanças.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Tem certeza de que deseja mover itens para a lixeira?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Tem certeza de que deseja mover itens para "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Aplicar a todos', + 'name' : 'Nome', + 'size' : 'Tamanho', + 'perms' : 'Permissões', + 'modify' : 'Modificado', + 'kind' : 'Tipo', + 'read' : 'Ler', + 'write' : 'Escrever', + 'noaccess' : 'Inacessível', + 'and' : 'e', + 'unknown' : 'Desconhecido', + 'selectall' : 'Selecionar todos arquivos', + 'selectfiles' : 'Selecionar arquivo(s)', + 'selectffile' : 'Selecionar primeiro arquivo', + 'selectlfile' : 'Slecionar último arquivo', + 'viewlist' : 'Exibir como lista', + 'viewicons' : 'Exibir como ícones', + 'viewSmall' : 'Ícones pequenos', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Ícones médios', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Ícones grandes', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Ícones gigantes', // from v2.1.39 added 22.5.2018 + 'places' : 'Lugares', + 'calc' : 'Calcular', + 'path' : 'Caminho', + 'aliasfor' : 'Alias para', + 'locked' : 'Bloqueado', + 'dim' : 'Dimesões', + 'files' : 'Arquivos', + 'folders' : 'Pastas', + 'items' : 'Itens', + 'yes' : 'sim', + 'no' : 'não', + 'link' : 'Link', + 'searcresult' : 'Resultados da pesquisa', + 'selected' : 'itens selecionados', + 'about' : 'Sobre', + 'shortcuts' : 'Atalhos', + 'help' : 'Ajuda', + 'webfm' : 'Gerenciador de arquivos web', + 'ver' : 'Versão', + 'protocolver' : 'Versão do protocolo', + 'homepage' : 'Home do projeto', + 'docs' : 'Documentação', + 'github' : 'Fork us on Github', + 'twitter' : 'Siga-nos no twitter', + 'facebook' : 'Junte-se a nós no Facebook', + 'team' : 'Time', + 'chiefdev' : 'Desenvolvedor chefe', + 'developer' : 'Desenvolvedor', + 'contributor' : 'Contribuinte', + 'maintainer' : 'Mantenedor', + 'translator' : 'Tradutor', + 'icons' : 'Ícones', + 'dontforget' : 'e não se esqueça de levar a sua toalha', + 'shortcutsof' : 'Atalhos desabilitados', + 'dropFiles' : 'Solte os arquivos aqui', + 'or' : 'ou', + 'selectForUpload' : 'Selecione arquivos para upload', + 'moveFiles' : 'Mover arquivos', + 'copyFiles' : 'Copiar arquivos', + 'restoreFiles' : 'Restaurar itens', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Remover de Lugares', + 'aspectRatio' : 'Manter aspecto', + 'scale' : 'Tamanho', + 'width' : 'Largura', + 'height' : 'Altura', + 'resize' : 'Redimencionar', + 'crop' : 'Cortar', + 'rotate' : 'Rotacionar', + 'rotate-cw' : 'Girar 90 graus CW', + 'rotate-ccw' : 'Girar 90 graus CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Montar Unidade de rede', // added 18.04.2012 + 'protocol' : 'Protocolo', // added 18.04.2012 + 'host' : 'Servidor', // added 18.04.2012 + 'port' : 'Porta', // added 18.04.2012 + 'user' : 'Usuário', // added 18.04.2012 + 'pass' : 'Senha', // added 18.04.2012 + 'confirmUnmount' : 'Deseja desmontar $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Soltar ou colar arquivos do navegador', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Solte ou cole arquivos aqui', // from v2.1 added 07.04.2014 + 'encoding' : 'Codificação', // from v2.1 added 19.12.2014 + 'locale' : 'Local', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Alvo: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Perquisar por input MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'Dono', // from v2.1 added 20.6.2015 + 'group' : 'Grupo', // from v2.1 added 20.6.2015 + 'other' : 'Outro', // from v2.1 added 20.6.2015 + 'execute' : 'Executar', // from v2.1 added 20.6.2015 + 'perm' : 'Permissão', // from v2.1 added 20.6.2015 + 'mode' : 'Modo', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Pasta vazia', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Pasta vazia\\A Arraste itens para os adicionar', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Pasta vazia\\A De um toque longo para adicionar itens', // from v2.1.6 added 30.12.2015 + 'quality' : 'Qualidade', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto sincronização', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Mover para cima', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Obter link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Itens selecionados ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID da pasta', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Permitir acesso offline', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Se autenticar novamente', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Carregando...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Abrir múltiplos arquivos', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Você está tentando abrir os arquivos $1. Tem certeza de que deseja abrir no navegador?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Os resultados da pesquisa estão vazios no destino da pesquisa.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Arquivo sendo editado.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Voce selecionou $1 itens.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Você tem $1 itens na área de transferência.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'A pesquisa incremental é apenas da visualização atual.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Restabelecer', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 completo', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Menu contextual', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Virar página', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Raízes de volume', // from v2.1.16 added 16.9.2016 + 'reset' : 'Resetar', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Cor de fundo', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Seletor de cores', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'Grade 8px', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Ativado', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Desativado', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Os resultados da pesquisa estão vazios na exibição atual.\\APressione [Enter] para expandir o alvo da pesquisa.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Os resultados da pesquisa da primeira letra estão vazios na exibição atual.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Texto do rótulo', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 minutos restantes', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Reabrir com a codificação selecionada', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Salvar com a codificação selecionada', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Selecione a pasta', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Buscar primeira letra', // from v2.1.23 added 24.3.2017 + 'presets' : 'Predefinições', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'São muitos itens, portanto não podem ser jogados no lixo.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Esvaziar a pasta "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Não há itens em uma pasta "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preferência', // from v2.1.26 added 28.6.2017 + 'language' : 'Língua', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Inicialize as configurações salvas neste navegador', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Barra de ferramentas', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 caracteres restantes.', // from v2.1.29 added 30.8.2017 + 'sum' : 'Somar', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Tamanho aproximado do arquivo', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focar no elemento do diálogo com o mouse por cima', // from v2.1.30 added 2.11.2017 + 'select' : 'Selecione', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Ação ao selecionar arquivo', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Abrir com o editor usado pela última vez', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Inverter seleção', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Tem certeza de que deseja renomear $1 itens selecionados como $2?
                      Isto não poderá ser desfeito!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Renomear Batch', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Número', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Adicionar prefixo', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Adicionar sufixo', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Alterar extensão', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Configurações de colunas (exibição em lista)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Todas as alterações serão refletidas imediatamente no arquivo.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Quaisquer alterações não serão refletidas até desmontar este volume.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'O(s) seguinte(s) volume(s) montado neste volume também desmontado. Você tem certeza que quer desmontá-lo(s)?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Informações da seleção', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmos para mostrar o hash do arquivo', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Itens de informação (painel Informações de seleção)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Pressione novamente para sair.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Barra de ferramentas', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Área de trabalho', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Diálogo', // from v2.1.38 added 4.4.2018 + 'all' : 'Tudo', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Tamanho do ícone (Visualização de ícones)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Abra a janela maximizada do editor', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Como a conversão por API não está disponível no momento, faça a conversão no site.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Após a conversão, você deve fazer o upload com o URL do item ou um arquivo baixado para salvar o arquivo convertido.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Converter no site $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrações', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Este elFinder possui os seguintes serviços externos integrados. Por favor, verifique os termos de uso, política de privacidade, etc. antes de usá-lo.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Mostrar itens ocultos', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Ocultar itens ocultos', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Mostrar/Ocultar itens ocultos', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Tipos de arquivo para ativar com "Novo arquivo"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Tipo do arquivo de texto', // from v2.1.41 added 7.8.2018 + 'add' : 'Adicionar', // from v2.1.41 added 7.8.2018 + 'theme' : 'Tema', // from v2.1.43 added 19.10.2018 + 'default' : 'Padrão', // from v2.1.43 added 19.10.2018 + 'description' : 'Descrição', // from v2.1.43 added 19.10.2018 + 'website' : 'Site da internet', // from v2.1.43 added 19.10.2018 + 'author' : 'Autor', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'Licença', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Este item não pode ser salvo. Para evitar perder as edições, você precisa exportar para o seu PC.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Clique duas vezes no arquivo para selecioná-lo.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Usar o modo de tela cheia', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Desconhecio', + 'kindRoot' : 'Raiz do volume', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Pasta', + 'kindSelects' : 'Seleções', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Alias inválido', + // applications + 'kindApp' : 'Aplicação', + 'kindPostscript' : 'Documento Postscript', + 'kindMsOffice' : 'Documento Microsoft Office', + 'kindMsWord' : 'Documento Microsoft Word', + 'kindMsExcel' : 'Documento Microsoft Excel', + 'kindMsPP' : 'Apresentação Microsoft Powerpoint', + 'kindOO' : 'Documento Open Office', + 'kindAppFlash' : 'Aplicação Flash', + 'kindPDF' : 'Formato de Documento Portátil (PDF)', + 'kindTorrent' : 'Arquivo Bittorrent', + 'kind7z' : 'Arquivo 7z', + 'kindTAR' : 'Arquivo TAR', + 'kindGZIP' : 'Arquivo GZIP', + 'kindBZIP' : 'Arquivo BZIP', + 'kindXZ' : 'Arquivo XZ', + 'kindZIP' : 'Arquivo ZIP', + 'kindRAR' : 'Arquivo RAR', + 'kindJAR' : 'Arquivo JAR', + 'kindTTF' : 'Tipo verdadeiro da fonte', + 'kindOTF' : 'Abrir tipo de fonte', + 'kindRPM' : 'Pacote RPM', + // fonts + 'kindFont' : 'Fonte', + 'kindSFNT' : 'SFNT fonte', + 'kindEOT' : 'Embedded Open Type fonte', + 'kindWOFF' : 'Web Open Font Format fonte', + 'kindWOFF2' : 'Web Open Font Format 2 fonte', + // texts + 'kindText' : 'Arquivo de texto', + 'kindTextPlain' : 'Texto simples', + 'kindPHP' : 'PHP', + 'kindCSS' : 'CSS', + 'kindHTML' : 'Documento HTML', + 'kindJS' : 'Javascript', + 'kindRTF' : 'Formato Rich Text', + 'kindC' : 'C', + 'kindCHeader' : 'C cabeçalho', + 'kindCPP' : 'C++', + 'kindCPPHeader' : 'C++ cabeçalho', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python', + 'kindJava' : 'Java', + 'kindRuby' : 'Ruby', + 'kindPerl' : 'Perl', + 'kindSQL' : 'SQL', + 'kindXML' : 'Documento XML', + 'kindAWK' : 'AWK', + 'kindCSV' : 'Valores separados por vírgula', + 'kindDOCBOOK' : 'Documento Docbook XML', + 'kindMarkdown' : 'Texto Markdown', // added 20.7.2015 + // images + 'kindImage' : 'Imagem', + 'kindBMP' : 'Imagem BMP', + 'kindJPEG' : 'Imagem JPEG', + 'kindGIF' : 'Imagem GIF', + 'kindPNG' : 'Imagem PNG', + 'kindTIFF' : 'Imagem TIFF', + 'kindTGA' : 'Imagem TGA', + 'kindPSD' : 'Imagem Adobe Photoshop', + 'kindXBITMAP' : 'Imagem X bitmap', + 'kindPXM' : 'Imagem Pixelmator', + // media + 'kindAudio' : 'Arquivo de audio', + 'kindAudioMPEG' : 'Audio MPEG', + 'kindAudioMPEG4' : 'Audio MPEG-4', + 'kindAudioMIDI' : 'Audio MIDI', + 'kindAudioOGG' : 'Audio Ogg Vorbis', + 'kindAudioWAV' : 'Audio WAV', + 'AudioPlaylist' : 'Lista de reprodução MP3 ', + 'kindVideo' : 'Arquivo de video', + 'kindVideoDV' : 'DV filme', + 'kindVideoMPEG' : 'Video MPEG', + 'kindVideoMPEG4' : 'Video MPEG-4', + 'kindVideoAVI' : 'Video AVI', + 'kindVideoMOV' : 'Filme rápido', + 'kindVideoWM' : 'Video Windows Media', + 'kindVideoFlash' : 'Video Flash', + 'kindVideoMKV' : 'MKV', + 'kindVideoOGG' : 'Video Ogg' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ro.js b/lib/redactor/elfinder/js/i18n/elfinder.ro.js new file mode 100644 index 0000000..d546aec --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ro.js @@ -0,0 +1,424 @@ +/** + * Română translation + * @author Cristian Tabacitu + * @version 2015-11-13 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ro = { + translator : 'Cristian Tabacitu <hello@tabacitu.ro>', + language : 'Română', + direction : 'ltr', + dateFormat : 'd M Y h:i', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will produce smth like: Today 12:25 PM + messages : { + + /********************************** errors **********************************/ + 'error' : 'Eroare', + 'errUnknown' : 'Eroare necunoscută.', + 'errUnknownCmd' : 'Comandă necunoscuta.', + 'errJqui' : 'Configurație jQuery UI necunoscută. Componentele selectable, draggable și droppable trebuie să fie incluse.', + 'errNode' : 'elFinder necesită ca DOM Element să fie creat.', + 'errURL' : 'Configurație elFinder nevalidă! URL option nu este setat.', + 'errAccess' : 'Acces interzis.', + 'errConnect' : 'Nu ne-am putut conecta la backend.', + 'errAbort' : 'Conexiunea a fost oprită.', + 'errTimeout' : 'Conexiunea a fost întreruptă.', + 'errNotFound' : 'Nu am gasit backend-ul.', + 'errResponse' : 'Răspuns backend greșit.', + 'errConf' : 'Configurație backend greșită.', + 'errJSON' : 'Modulul PHP JSON nu este instalat.', + 'errNoVolumes' : 'Volumele citibile nu sunt disponibile.', + 'errCmdParams' : 'Parametri greșiți pentru comanda "$1".', + 'errDataNotJSON' : 'Datele nu sunt în format JSON.', + 'errDataEmpty' : 'Datele sunt goale.', + 'errCmdReq' : 'Cererea către backend necesită un nume de comandă.', + 'errOpen' : 'Nu am putut deschide "$1".', + 'errNotFolder' : 'Obiectul nu este un dosar.', + 'errNotFile' : 'Obiectul nu este un fișier.', + 'errRead' : 'Nu am putut citi "$1".', + 'errWrite' : 'Nu am putu scrie în "$1".', + 'errPerm' : 'Nu ai permisiunea necesară.', + 'errLocked' : '"$1" este blocat și nu poate fi redenumit, mutat sau șters.', + 'errExists' : 'Un fișier cu numele "$1" există deja.', + 'errInvName' : 'Numele pentru fișier este greșit.', + 'errFolderNotFound' : 'Nu am găsit dosarul.', + 'errFileNotFound' : 'Nu am găsit fișierul.', + 'errTrgFolderNotFound' : 'Nu am găsit dosarul pentru destinație "$1".', + 'errPopup' : 'Browserul tău a prevenit deschiderea ferestrei popup. Pentru a deschide fișierul permite deschidere ferestrei.', + 'errMkdir' : 'Nu am putut crea dosarul "$1".', + 'errMkfile' : 'Nu am putut crea fișierul "$1".', + 'errRename' : 'Nu am putut redenumi "$1".', + 'errCopyFrom' : 'Copierea fișierelor de pe volumul "$1" este interzisă.', + 'errCopyTo' : 'Copierea fișierelor către volumul "$1" este interzisă.', + 'errMkOutLink' : 'Nu am putut crea linkul în afara volumului rădăcină.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Eroare de upload.', // old name - errUploadCommon + 'errUploadFile' : 'Nu am putut urca "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Nu am găsit fișiere pentru a le urca.', + 'errUploadTotalSize' : 'Datele depâșest limita maximă de mărime.', // old name - errMaxSize + 'errUploadFileSize' : 'Fișierul este prea mare.', // old name - errFileMaxSize + 'errUploadMime' : 'Acest tip de fișier nu este permis.', + 'errUploadTransfer' : 'Eroare la transferarea "$1".', + 'errUploadTemp' : 'Nu am putut crea fișierul temporar pentru upload.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Obiectul "$1" există deja în acest loc și nu poate fi înlocuit de un obiect de alt tip.', // new + 'errReplace' : 'Nu am putut înlocui "$1".', + 'errSave' : 'Nu am putut salva "$1".', + 'errCopy' : 'Nu am putut copia "$1".', + 'errMove' : 'Nu am putut muta "$1".', + 'errCopyInItself' : 'Nu am putut copia "$1" în el însuși.', + 'errRm' : 'Nu am putut șterge "$1".', + 'errRmSrc' : 'Nu am putut șterge fișierul sursă.', + 'errExtract' : 'Nu am putut extrage fișierele din "$1".', + 'errArchive' : 'Nu am putut crea arhiva.', + 'errArcType' : 'Arhiva este de un tip nesuportat.', + 'errNoArchive' : 'Fișierul nu este o arhiva sau este o arhivă de un tip necunoscut.', + 'errCmdNoSupport' : 'Backend-ul nu suportă această comandă.', + 'errReplByChild' : 'Dosarul “$1” nu poate fi înlocuit de un element pe care el îl conține.', + 'errArcSymlinks' : 'Din motive de securitate, arhiva nu are voie să conțină symlinks sau fișiere cu nume interzise.', // edited 24.06.2012 + 'errArcMaxSize' : 'Fișierul arhivei depășește mărimea maximă permisă.', + 'errResize' : 'Nu am putut redimensiona "$1".', + 'errResizeDegree' : 'Grad de rotație nevalid.', // added 7.3.2013 + 'errResizeRotate' : 'Imaginea nu a fost rotită.', // added 7.3.2013 + 'errResizeSize' : 'Mărimea imaginii este nevalidă.', // added 7.3.2013 + 'errResizeNoChange' : 'Mărimea imaginii nu a fost schimbată.', // added 7.3.2013 + 'errUsupportType' : 'Tipul acesta de fișier nu este suportat.', + 'errNotUTF8Content' : 'Fișierul "$1" nu folosește UTF-8 și nu poate fi editat.', // added 9.11.2011 + 'errNetMount' : 'Nu am putut încărca "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protocol nesuportat.', // added 17.04.2012 + 'errNetMountFailed' : 'Încărcare eșuată.', // added 17.04.2012 + 'errNetMountHostReq' : 'Gazda este necesară.', // added 18.04.2012 + 'errSessionExpires' : 'Sesiunea a expirat datorită lipsei de activitate.', + 'errCreatingTempDir' : 'Nu am putut crea fișierul temporar: "$1"', + 'errFtpDownloadFile' : 'Nu am putut descarca fișierul de pe FTP: "$1"', + 'errFtpUploadFile' : 'Nu am putut încărca fișierul pe FTP: "$1"', + 'errFtpMkdir' : 'Nu am putut crea acest dosar pe FTP: "$1"', + 'errArchiveExec' : 'Eroare la arhivarea fișierelor: "$1"', + 'errExtractExec' : 'Eroare la dezarhivarea fișierelor: "$1"', + 'errNetUnMount' : 'Nu am putut elimina volumul', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Nu poate fi convertit la UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Pentru a urca dosare încearcă Google Chrome.', // from v2.1 added 26.6.2015 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Creeaza arhivă', + 'cmdback' : 'Înapoi', + 'cmdcopy' : 'Copiază', + 'cmdcut' : 'Taie', + 'cmddownload' : 'Descarcă', + 'cmdduplicate' : 'Creează duplicat', + 'cmdedit' : 'Modifică fișier', + 'cmdextract' : 'Extrage fișierele din arhivă', + 'cmdforward' : 'Înainte', + 'cmdgetfile' : 'Alege fișiere', + 'cmdhelp' : 'Despre acest software', + 'cmdhome' : 'Acasă', + 'cmdinfo' : 'Informații', + 'cmdmkdir' : 'Dosar nou', + 'cmdmkfile' : 'Fișier nou', + 'cmdopen' : 'Deschide', + 'cmdpaste' : 'Lipește', + 'cmdquicklook' : 'Previzualizează', + 'cmdreload' : 'Reîncarcă', + 'cmdrename' : 'Redenumește', + 'cmdrm' : 'Șterge', + 'cmdsearch' : 'Găsește fișiere', + 'cmdup' : 'Mergi la dosarul părinte', + 'cmdupload' : 'Urcă fișiere', + 'cmdview' : 'Vezi', + 'cmdresize' : 'Redimensionează & rotește', + 'cmdsort' : 'Sortează', + 'cmdnetmount' : 'Încarcă volum din rețea', // added 18.04.2012 + 'cmdnetunmount': 'Elimină volum', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'La Locuri', // added 28.12.2014 + 'cmdchmod' : 'Schimbă mod', // from v2.1 added 20.6.2015 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Închide', + 'btnSave' : 'Salvează', + 'btnRm' : 'Șterge', + 'btnApply' : 'Aplică', + 'btnCancel' : 'Anulează', + 'btnNo' : 'Nu', + 'btnYes' : 'Da', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Încarcă', // added 18.04.2012 + 'btnApprove': 'Mergi la $1 și aprobă', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Elimină volum', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convertește', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Aici', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volum', // from v2.1 added 22.5.2015 + 'btnAll' : 'Toate', // from v2.1 added 22.5.2015 + 'btnMime' : 'Tipuri MIME', // from v2.1 added 22.5.2015 + 'btnFileName':'Nume fișier', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Salvează și închide', // from v2.1 added 12.6.2015 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Deschide dosar', + 'ntffile' : 'Deschide fișier', + 'ntfreload' : 'Actualizează conținutul dosarului', + 'ntfmkdir' : 'Se creează dosarul', + 'ntfmkfile' : 'Se creează fișierele', + 'ntfrm' : 'Șterge fișiere', + 'ntfcopy' : 'Copiază fișiere', + 'ntfmove' : 'Mută fișiere', + 'ntfprepare' : 'Pregătește copierea fișierelor', + 'ntfrename' : 'Redenumește fișiere', + 'ntfupload' : 'Se urcă fișierele', + 'ntfdownload' : 'Se descarcă fișierele', + 'ntfsave' : 'Salvează fișiere', + 'ntfarchive' : 'Se creează arhiva', + 'ntfextract' : 'Se extrag fișierele din arhivă', + 'ntfsearch' : 'Se caută fișierele', + 'ntfresize' : 'Se redimnesionează imaginile', + 'ntfsmth' : 'Se întamplă ceva', + 'ntfloadimg' : 'Se încarcă imaginea', + 'ntfnetmount' : 'Se încarcă volumul din rețea', // added 18.04.2012 + 'ntfnetunmount': 'Se elimină volumul din rețea', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Se preiau dimensiunile imaginii', // added 20.05.2013 + 'ntfreaddir' : 'Se citesc informațiile dosarului', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Se preia URL-ul din link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Se schimba modul de fișier', // from v2.1 added 20.6.2015 + + /************************************ dates **********************************/ + 'dateUnknown' : 'necunoscută', + 'Today' : 'Astăzi', + 'Yesterday' : 'Ieri', + 'msJan' : 'Ian', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Mai', + 'msJun' : 'Iun', + 'msJul' : 'Iul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Oct', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Ianuarie', + 'February' : 'Februarie', + 'March' : 'Martie', + 'April' : 'Aprilie', + 'May' : 'Mai', + 'June' : 'Iunie', + 'July' : 'Iulie', + 'August' : 'August', + 'September' : 'Septembrie', + 'October' : 'Octombrie', + 'November' : 'Noiembrie', + 'December' : 'Decembrie', + 'Sunday' : 'Duminică', + 'Monday' : 'Luni', + 'Tuesday' : 'Marți', + 'Wednesday' : 'Miercuri', + 'Thursday' : 'Joi', + 'Friday' : 'Vineri', + 'Saturday' : 'Sâmbătă', + 'Sun' : 'Du', + 'Mon' : 'Lu', + 'Tue' : 'Ma', + 'Wed' : 'Mi', + 'Thu' : 'Jo', + 'Fri' : 'Vi', + 'Sat' : 'Sâ', + + /******************************** sort variants ********************************/ + 'sortname' : 'după nume', + 'sortkind' : 'după tip', + 'sortsize' : 'după mărime', + 'sortdate' : 'după dată', + 'sortFoldersFirst' : 'Dosarele primele', + + /********************************** new items **********************************/ + 'untitled file.txt' : 'FisierNou.txt', // added 10.11.2015 + 'untitled folder' : 'DosarNou', // added 10.11.2015 + 'Archive' : 'ArhivaNoua', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'Este necesară confirmare', + 'confirmRm' : 'Ești sigur că vrei să ștergi fișierele?
                      Acțiunea este ireversibilă!', + 'confirmRepl' : 'Înlocuiește fișierul vechi cu cel nou?', + 'confirmConvUTF8' : 'Nu este în UTF-8
                      Convertim la UTF-8?
                      Conținutul devine UTF-8 după salvarea conversiei.', // from v2.1 added 08.04.2014 + 'confirmNotSave' : 'Au avut loc modificări.
                      Dacă nu salvezi se vor pierde modificările.', // from v2.1 added 15.7.2015 + 'apllyAll' : 'Aplică pentru toate', + 'name' : 'Nume', + 'size' : 'Mărime', + 'perms' : 'Permisiuni', + 'modify' : 'Modificat la', + 'kind' : 'Tip', + 'read' : 'citire', + 'write' : 'scriere', + 'noaccess' : 'acces interzis', + 'and' : 'și', + 'unknown' : 'necunoscut', + 'selectall' : 'Alege toate fișierele', + 'selectfiles' : 'Alege fișier(e)', + 'selectffile' : 'Alege primul fișier', + 'selectlfile' : 'Alege ultimul fișier', + 'viewlist' : 'Vezi ca listă', + 'viewicons' : 'Vezi ca icoane', + 'places' : 'Locuri', + 'calc' : 'Calculează', + 'path' : 'Cale', + 'aliasfor' : 'Alias pentru', + 'locked' : 'Securizat', + 'dim' : 'Dimensiuni', + 'files' : 'Fișiere', + 'folders' : 'Dosare', + 'items' : 'Elemente', + 'yes' : 'da', + 'no' : 'nu', + 'link' : 'Link', + 'searcresult' : 'Rezultatele căutării', + 'selected' : 'elemente alese', + 'about' : 'Despre', + 'shortcuts' : 'Scurtături', + 'help' : 'Ajutor', + 'webfm' : 'Manager web pentru fișiere', + 'ver' : 'Versiune', + 'protocolver' : 'versiune protocol', + 'homepage' : 'Pagina proiectului', + 'docs' : 'Documentație', + 'github' : 'Fork nou pe Github', + 'twitter' : 'Urmărește-ne pe twitter', + 'facebook' : 'Alătura-te pe facebook', + 'team' : 'Echipa', + 'chiefdev' : 'chief developer', + 'developer' : 'developer', + 'contributor' : 'contributor', + 'maintainer' : 'maintainer', + 'translator' : 'translator', + 'icons' : 'Icoane', + 'dontforget' : 'și nu uita să-ți iei prosopul', + 'shortcutsof' : 'Scurtăturile sunt dezactivate', + 'dropFiles' : 'Dă drumul fișierelor aici', + 'or' : 'sau', + 'selectForUpload' : 'Alege fișiere pentru a le urca', + 'moveFiles' : 'Mută fișiere', + 'copyFiles' : 'Copiază fișiere', + 'rmFromPlaces' : 'Șterge din locuri', + 'aspectRatio' : 'Aspect ratio', + 'scale' : 'Scală', + 'width' : 'Lățime', + 'height' : 'Înălțime', + 'resize' : 'Redimensionează', + 'crop' : 'Decupează', + 'rotate' : 'Rotește', + 'rotate-cw' : 'Rotește cu 90° în sensul ceasului', + 'rotate-ccw' : 'Rotește cu 90° în sensul invers ceasului', + 'degree' : '°', + 'netMountDialogTitle' : 'Încarcă volum din rețea', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Gazdă', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Utilizator', // added 18.04.2012 + 'pass' : 'Parolă', // added 18.04.2012 + 'confirmUnmount' : 'Vrei să elimini volumul $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Drag&drop sau lipește din browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Drag&drop sau lipește fișiere aici', // from v2.1 added 07.04.2014 + 'encoding' : 'Encodare', // from v2.1 added 19.12.2014 + 'locale' : 'Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Țintă: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Caută după tipul MIME', // from v2.1 added 22.5.2015 + 'owner' : 'Owner', // from v2.1 added 20.6.2015 + 'group' : 'Group', // from v2.1 added 20.6.2015 + 'other' : 'Other', // from v2.1 added 20.6.2015 + 'execute' : 'Execute', // from v2.1 added 20.6.2015 + 'perm' : 'Permission', // from v2.1 added 20.6.2015 + 'mode' : 'Mod', // from v2.1 added 20.6.2015 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Necunoscut', + 'kindFolder' : 'Dosar', + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Alias stricat', + // applications + 'kindApp' : 'Aplicație', + 'kindPostscript' : 'Document Postscript', + 'kindMsOffice' : 'Document Microsoft Office', + 'kindMsWord' : 'Document Microsoft Word', + 'kindMsExcel' : 'Document Microsoft Excel', + 'kindMsPP' : 'Prezentare Microsoft Powerpoint', + 'kindOO' : 'Document Open Office', + 'kindAppFlash' : 'Aplicație Flash', + 'kindPDF' : 'Document Portabil (PDF)', + 'kindTorrent' : 'Fișier Bittorrent', + 'kind7z' : 'Arhivă 7z', + 'kindTAR' : 'Arhivă TAR', + 'kindGZIP' : 'Arhivă GZIP', + 'kindBZIP' : 'Arhivă BZIP', + 'kindXZ' : 'Arhivă XZ', + 'kindZIP' : 'Arhivă ZIP', + 'kindRAR' : 'Arhivă RAR', + 'kindJAR' : 'Fișier Java JAR', + 'kindTTF' : 'Font True Type', + 'kindOTF' : 'Font Open Type', + 'kindRPM' : 'Pachet RPM', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'Font SFNT', + 'kindEOT' : 'Font Embedded Open Type', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Document text', + 'kindTextPlain' : 'Text simplu', + 'kindPHP' : 'Sursă PHP', + 'kindCSS' : 'Fișier de stil (CSS)', + 'kindHTML' : 'Document HTML', + 'kindJS' : 'Sursă Javascript', + 'kindRTF' : 'Text formatat (rich text)', + 'kindC' : 'Sursă C', + 'kindCHeader' : 'Sursă C header', + 'kindCPP' : 'Sursă C++', + 'kindCPPHeader' : 'Sursă C++ header', + 'kindShell' : 'Script terminal Unix', + 'kindPython' : 'Sursă Python', + 'kindJava' : 'Sursă Java', + 'kindRuby' : 'Sursă Ruby', + 'kindPerl' : 'Script Perl', + 'kindSQL' : 'Sursă SQL', + 'kindXML' : 'Document XML', + 'kindAWK' : 'Sursă AWK', + 'kindCSV' : 'Valori separate de virgulă (CSV)', + 'kindDOCBOOK' : 'Document Docbook XML', + 'kindMarkdown' : 'Text Markdown', // added 20.7.2015 + // images + 'kindImage' : 'Imagine', + 'kindBMP' : 'Imagine BMP', + 'kindJPEG' : 'Imagine JPEG', + 'kindGIF' : 'Imagine GIF', + 'kindPNG' : 'Imagine PNG', + 'kindTIFF' : 'Imagine TIFF', + 'kindTGA' : 'Imagine TGA', + 'kindPSD' : 'Imagine Adobe Photoshop', + 'kindXBITMAP' : 'Imagine X bitmap', + 'kindPXM' : 'Imagine Pixelmator', + // media + 'kindAudio' : 'Audio', + 'kindAudioMPEG' : 'Audio MPEG', + 'kindAudioMPEG4' : 'Audio MPEG-4', + 'kindAudioMIDI' : 'Audio MIDI', + 'kindAudioOGG' : 'Audio Ogg Vorbis', + 'kindAudioWAV' : 'Audio WAV', + 'AudioPlaylist' : 'Playlist MP3', + 'kindVideo' : 'Video', + 'kindVideoDV' : 'Video DV', + 'kindVideoMPEG' : 'Video MPEG', + 'kindVideoMPEG4' : 'Video MPEG-4', + 'kindVideoAVI' : 'Video AVI', + 'kindVideoMOV' : 'Video Quick Time', + 'kindVideoWM' : 'Video Windows Media', + 'kindVideoFlash' : 'Video Flash', + 'kindVideoMKV' : 'Video Matroska', + 'kindVideoOGG' : 'Video Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ru.js b/lib/redactor/elfinder/js/i18n/elfinder.ru.js new file mode 100644 index 0000000..22d8c31 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ru.js @@ -0,0 +1,590 @@ +/** + * Русский язык translation + * @author Dmitry "dio" Levashov + * @author Andrew Berezovsky + * @author Alex Yashkin + * @author Aleev Ruslan + * @version 2024-11-05 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ru = { + translator : 'Dmitry "dio" Levashov <dio@std42.ru>, Andrew Berezovsky <andrew.berezovsky@gmail.com>, Alex Yashkin <alex@yashkin.by>, Aleev Ruslan <info@cat-art.ru>', + language : 'Русский язык', + direction : 'ltr', + dateFormat : 'd M Y H:i', // will show like: 05 Ноя 2024 21:08 + fancyDateFormat : '$1 H:i', // will show like: Сегодня 21:08 + nonameDateFormat : 'ymd-His', // noname upload will show like: 241105-210850 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Ошибка', + 'errUnknown' : 'Неизвестная ошибка.', + 'errUnknownCmd' : 'Неизвестная команда.', + 'errJqui' : 'Отсутствуют необходимые компоненты jQuery UI - selectable, draggable и droppable.', + 'errNode' : 'Отсутствует DOM элемент для инициализации elFinder.', + 'errURL' : 'Неверная конфигурация elFinder! Не указан URL.', + 'errAccess' : 'Доступ запрещен.', + 'errConnect' : 'Не удалось соединиться с сервером.', + 'errAbort' : 'Соединение прервано.', + 'errTimeout' : 'Таймаут соединения.', + 'errNotFound' : 'Сервер не найден.', + 'errResponse' : 'Некорректный ответ сервера.', + 'errConf' : 'Некорректная настройка сервера.', + 'errJSON' : 'Модуль PHP JSON не установлен.', + 'errNoVolumes' : 'Отсутствуют корневые директории достуные для чтения.', + 'errCmdParams' : 'Некорректные параметры команды "$1".', + 'errDataNotJSON' : 'Данные не в формате JSON.', + 'errDataEmpty' : 'Данные отсутствуют.', + 'errCmdReq' : 'Для запроса к серверу необходимо указать имя команды.', + 'errOpen' : 'Не удалось открыть "$1".', + 'errNotFolder' : 'Объект не является папкой.', + 'errNotFile' : 'Объект не является файлом.', + 'errRead' : 'Ошибка чтения "$1".', + 'errWrite' : 'Ошибка записи в "$1".', + 'errPerm' : 'Доступ запрещен.', + 'errLocked' : '"$1" защищен и не может быть переименован, перемещен или удален.', + 'errExists' : 'В папке уже существует файл с именем "$1".', + 'errInvName' : 'Недопустимое имя файла.', + 'errInvDirname' : 'Недопустимое имя папки.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Папка не найдена.', + 'errFileNotFound' : 'Файл не найден.', + 'errTrgFolderNotFound' : 'Целевая папка "$1" не найдена.', + 'errPopup' : 'Браузер заблокировал открытие нового окна. Чтобы открыть файл, измените настройки браузера.', + 'errMkdir' : 'Ошибка создания папки "$1".', + 'errMkfile' : 'Ошибка создания файла "$1".', + 'errRename' : 'Ошибка переименования "$1".', + 'errCopyFrom' : 'Копирование файлов из директории "$1" запрещено.', + 'errCopyTo' : 'Копирование файлов в директорию "$1" запрещено.', + 'errMkOutLink' : 'Невозможно создать ссылку вне корня раздела.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Ошибка загрузки.', // old name - errUploadCommon + 'errUploadFile' : 'Невозможно загрузить "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Нет файлов для загрузки.', + 'errUploadTotalSize' : 'Превышен допустимый размер загружаемых данных.', // old name - errMaxSize + 'errUploadFileSize' : 'Размер файла превышает допустимый.', // old name - errFileMaxSize + 'errUploadMime' : 'Недопустимый тип файла.', + 'errUploadTransfer' : 'Ошибка передачи файла "$1".', + 'errUploadTemp' : 'Невозможно создать временный файл для загрузки.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Объект "$1" по этому адресу уже существует и не может быть заменен объектом другого типа.', // new + 'errReplace' : 'Невозможно заменить "$1".', + 'errSave' : 'Невозможно сохранить "$1".', + 'errCopy' : 'Невозможно скопировать "$1".', + 'errMove' : 'Невозможно переместить "$1".', + 'errCopyInItself' : 'Невозможно скопировать "$1" в самого себя.', + 'errRm' : 'Невозможно удалить "$1".', + 'errTrash' : 'Невозможно переместить в корзину.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Невозможно удалить файлы источника.', + 'errExtract' : 'Невозможно извлечь фалы из "$1".', + 'errArchive' : 'Невозможно создать архив.', + 'errArcType' : 'Неподдерживаемый тип архива.', + 'errNoArchive' : 'Файл не является архивом или неподдерживаемый тип архива.', + 'errCmdNoSupport' : 'Сервер не поддерживает эту команду.', + 'errReplByChild' : 'Невозможно заменить папку "$1" содержащимся в ней объектом.', + 'errArcSymlinks' : 'По соображениям безопасности запрещена распаковка архивов, содержащих ссылки (symlinks) или файлы с недопустимыми именами.', // edited 24.06.2012 + 'errArcMaxSize' : 'Размер файлов в архиве превышает максимально разрешенный.', + 'errResize' : 'Не удалось изменить размер "$1".', + 'errResizeDegree' : 'Некорректный градус поворота.', // added 7.3.2013 + 'errResizeRotate' : 'Невозможно повернуть изображение.', // added 7.3.2013 + 'errResizeSize' : 'Некорректный размер изображения.', // added 7.3.2013 + 'errResizeNoChange' : 'Размер изображения не изменился.', // added 7.3.2013 + 'errUsupportType' : 'Неподдерживаемый тип файла.', + 'errNotUTF8Content' : 'Файл "$1" содержит текст в кодировке отличной от UTF-8 и не может быть отредактирован.', // added 9.11.2011 + 'errNetMount' : 'Невозможно подключить "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Неподдерживаемый протокол.', // added 17.04.2012 + 'errNetMountFailed' : 'Ошибка монтирования.', // added 17.04.2012 + 'errNetMountHostReq' : 'Требуется указать хост.', // added 18.04.2012 + 'errSessionExpires' : 'Сессия была завершена так как превышено время отсутствия активности.', + 'errCreatingTempDir' : 'Невозможно создать временную директорию: "$1"', + 'errFtpDownloadFile' : 'Невозможно скачать файл с FTP: "$1"', + 'errFtpUploadFile' : 'Невозможно загрузить файл на FTP: "$1"', + 'errFtpMkdir' : 'Невозможно создать директорию на FTP: "$1"', + 'errArchiveExec' : 'Ошибка при выполнении архивации: "$1"', + 'errExtractExec' : 'Ошибка при выполнении распаковки: "$1"', + 'errNetUnMount' : 'Невозможно отключить', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Не конвертируется в UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Если вы хотите загружать папки, попробуйте Google Chrome.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Превышено время ожидания при поиске "$1". Результаты поиска частичные.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Требуется повторная авторизация.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Максимальное число выбираемых файлов: $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Невозможно восстановить из корзины. Не удалось определить путь для восстановления.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Не найден редактор для этого типа файлов.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Возникла ошибка на стороне сервера.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Невозможно очистить папку "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Еще ошибок: $1', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'Вы можете создать за один раз папок: $1.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Создать архив', + 'cmdback' : 'Назад', + 'cmdcopy' : 'Копировать', + 'cmdcut' : 'Вырезать', + 'cmddownload' : 'Скачать', + 'cmdduplicate' : 'Сделать копию', + 'cmdedit' : 'Редактировать файл', + 'cmdextract' : 'Распаковать архив', + 'cmdforward' : 'Вперед', + 'cmdgetfile' : 'Выбрать файлы', + 'cmdhelp' : 'О программе', + 'cmdhome' : 'Домой', + 'cmdinfo' : 'Свойства', + 'cmdmkdir' : 'Новая папка', + 'cmdmkdirin' : 'В новую папку', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Новый файл', + 'cmdopen' : 'Открыть', + 'cmdpaste' : 'Вставить', + 'cmdquicklook' : 'Быстрый просмотр', + 'cmdreload' : 'Обновить', + 'cmdrename' : 'Переименовать', + 'cmdrm' : 'Удалить', + 'cmdtrash' : 'Переместить в корзину', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Восстановить', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Поиск файлов', + 'cmdup' : 'Наверх', + 'cmdupload' : 'Загрузить файлы', + 'cmdview' : 'Вид', + 'cmdresize' : 'Изменить размер и повернуть', + 'cmdsort' : 'Сортировать', + 'cmdnetmount' : 'Подключить сетевой раздел', // added 18.04.2012 + 'cmdnetunmount': 'Отключить', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'В избранное', // added 28.12.2014 + 'cmdchmod' : 'Изменить права доступа', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Открыть папку', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Сбросить ширину колонок', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Полный экран', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Переместить', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Очистить папку', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Отменить', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Вернуть', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Настройки', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Выбрать все', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Отменить выбор', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Инвертировать выбор', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Открыть в новом окне', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Скрыть (персонально)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Закрыть', + 'btnSave' : 'Сохранить', + 'btnRm' : 'Удалить', + 'btnApply' : 'Применить', + 'btnCancel' : 'Отмена', + 'btnNo' : 'Нет', + 'btnYes' : 'Да', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Подключить', // added 18.04.2012 + 'btnApprove': 'Перейти в $1 и применить', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Отключить', // from v2.1 added 30.04.2012 + 'btnConv' : 'Конвертировать', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Здесь', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Раздел', // from v2.1 added 22.5.2015 + 'btnAll' : 'Все', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME тип', // from v2.1 added 22.5.2015 + 'btnFileName':'Имя файла', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Сохранить и закрыть', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Резервная копия', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Переименовать', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Переименовать (все)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Пред. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'След. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Сохранить как', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Открыть папку', + 'ntffile' : 'Открыть файл', + 'ntfreload' : 'Обновить текущую папку', + 'ntfmkdir' : 'Создание папки', + 'ntfmkfile' : 'Создание файлов', + 'ntfrm' : 'Удалить файлы', + 'ntfcopy' : 'Скопировать файлы', + 'ntfmove' : 'Переместить файлы', + 'ntfprepare' : 'Подготовка к копированию файлов', + 'ntfrename' : 'Переименовать файлы', + 'ntfupload' : 'Загрузка файлов', + 'ntfdownload' : 'Скачивание файлов', + 'ntfsave' : 'Сохранить файлы', + 'ntfarchive' : 'Создание архива', + 'ntfextract' : 'Распаковка архива', + 'ntfsearch' : 'Поиск файлов', + 'ntfresize' : 'Изменение размеров изображений', + 'ntfsmth' : 'Занят важным делом', + 'ntfloadimg' : 'Загрузка изображения', + 'ntfnetmount' : 'Подключение сетевого диска', // added 18.04.2012 + 'ntfnetunmount': 'Отключение сетевого диска', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Получение размеров изображения', // added 20.05.2013 + 'ntfreaddir' : 'Чтение информации о папке', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Получение URL ссылки', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Изменение прав доступа к файлу', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Проверка измени загруженного файла', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Создание файла для скачки', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Получение информации о пути', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Обработка загруженного файла', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Перемещение в корзину', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Восстановление из корзины', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Проверка папки назначения', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Отмена предыдущей операции', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Восстановление предыдущей операции', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Проверка содержимого', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Корзина', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'неизвестно', + 'Today' : 'Сегодня', + 'Yesterday' : 'Вчера', + 'msJan' : 'Янв', + 'msFeb' : 'Фев', + 'msMar' : 'Мар', + 'msApr' : 'Апр', + 'msMay' : 'Май', + 'msJun' : 'Июн', + 'msJul' : 'Июл', + 'msAug' : 'Авг', + 'msSep' : 'Сен', + 'msOct' : 'Окт', + 'msNov' : 'Ноя', + 'msDec' : 'Дек', + 'January' : 'Январь', + 'February' : 'Февраль', + 'March' : 'Март', + 'April' : 'Апрель', + 'May' : 'Май', + 'June' : 'Июнь', + 'July' : 'Июль', + 'August' : 'Август', + 'September' : 'Сентябрь', + 'October' : 'Октябрь', + 'November' : 'Ноябрь', + 'December' : 'Декабрь', + 'Sunday' : 'Воскресенье', + 'Monday' : 'Понедельник', + 'Tuesday' : 'Вторник', + 'Wednesday' : 'Среда', + 'Thursday' : 'Четверг', + 'Friday' : 'Пятница', + 'Saturday' : 'Суббота', + 'Sun' : 'Вск', + 'Mon' : 'Пнд', + 'Tue' : 'Втр', + 'Wed' : 'Срд', + 'Thu' : 'Чтв', + 'Fri' : 'Птн', + 'Sat' : 'Сбт', + + /******************************** sort variants ********************************/ + 'sortname' : 'по имени', + 'sortkind' : 'по типу', + 'sortsize' : 'по размеру', + 'sortdate' : 'по дате', + 'sortFoldersFirst' : 'Папки в начале', + 'sortperm' : 'по разрешениям', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'по режиму', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'по владельцу', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'по группе', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Также и дерево каталогов', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'НовыйФайл.txt', // added 10.11.2015 + 'untitled folder' : 'НоваяПапка', // added 10.11.2015 + 'Archive' : 'НовыйАрхив', // from v2.1 added 10.11.2015 + 'untitled file' : 'НовыйФайл.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1 Файл', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Необходимо подтверждение', + 'confirmRm' : 'Вы уверены, что хотите удалить файлы?
                      Действие необратимо!', + 'confirmRepl' : 'Заменить старый файл новым?', + 'confirmRest' : 'Заменить существующий файл файлом из корзины?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Не UTF-8
                      Сконвертировать в UTF-8?
                      Данные станут UTF-8 при сохранении после конвертации.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Невозможно определить кодировку файла. Необходима предварительная конвертация файла в UTF-8 для дальнейшего редактирования.
                      Выберите кодировку файла.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Произошли изменения.
                      Если не сохраните изменения, то потеряете их.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Вы уверены, что хотите переместить файлы в корзину?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Вы уверены, что хотите переместить файлы в "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Применить для всех', + 'name' : 'Имя', + 'size' : 'Размер', + 'perms' : 'Доступ', + 'modify' : 'Изменен', + 'kind' : 'Тип', + 'read' : 'чтение', + 'write' : 'запись', + 'noaccess' : 'нет доступа', + 'and' : 'и', + 'unknown' : 'неизвестно', + 'selectall' : 'Выбрать все файлы', + 'selectfiles' : 'Выбрать файл(ы)', + 'selectffile' : 'Выбрать первый файл', + 'selectlfile' : 'Выбрать последний файл', + 'viewlist' : 'В виде списка', + 'viewicons' : 'В виде иконок', + 'viewSmall' : 'Маленькие иконки', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Средние иконки', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Большие иконки', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Очень большие иконки', // from v2.1.39 added 22.5.2018 + 'places' : 'Избранное', + 'calc' : 'Вычислить', + 'path' : 'Путь', + 'aliasfor' : 'Указывает на', + 'locked' : 'Защита', + 'dim' : 'Размеры', + 'files' : 'Файлы', + 'folders' : 'Папки', + 'items' : 'Объекты', + 'yes' : 'да', + 'no' : 'нет', + 'link' : 'Ссылка', + 'searcresult' : 'Результаты поиска', + 'selected' : 'выбрано', + 'about' : 'О программе', + 'shortcuts' : 'Горячие клавиши', + 'help' : 'Помощь', + 'webfm' : 'Файловый менеджер для Web', + 'ver' : 'Версия', + 'protocolver' : 'версия протокола', + 'homepage' : 'Сайт проекта', + 'docs' : 'Документация', + 'github' : 'Форкните на GitHub', + 'twitter' : 'Следите в Twitter', + 'facebook' : 'Присоединяйтесь на Facebook', + 'team' : 'Команда', + 'chiefdev' : 'ведущий разработчик', + 'developer' : 'разработчик', + 'contributor' : 'участник', + 'maintainer' : 'сопровождение проекта', + 'translator' : 'переводчик', + 'icons' : 'Иконки', + 'dontforget' : 'и не забудьте взять своё полотенце', + 'shortcutsof' : 'Горячие клавиши отключены', + 'dropFiles' : 'Перетащите файлы сюда', + 'or' : 'или', + 'selectForUpload' : 'Выбрать файлы для загрузки', + 'moveFiles' : 'Переместить файлы', + 'copyFiles' : 'Скопировать файлы', + 'restoreFiles' : 'Восстановить файлы', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Удалить из избранного', + 'aspectRatio' : 'Соотношение сторон', + 'scale' : 'Масштаб', + 'width' : 'Ширина', + 'height' : 'Высота', + 'resize' : 'Изменить размер', + 'crop' : 'Обрезать', + 'rotate' : 'Повернуть', + 'rotate-cw' : 'Повернуть на 90 градусов по часовой стрелке', + 'rotate-ccw' : 'Повернуть на 90 градусов против часовой стрелке', + 'degree' : '°', + 'netMountDialogTitle' : 'Подключить сетевой диск', // added 18.04.2012 + 'protocol' : 'Протокол', // added 18.04.2012 + 'host' : 'Хост', // added 18.04.2012 + 'port' : 'Порт', // added 18.04.2012 + 'user' : 'Пользователь', // added 18.04.2012 + 'pass' : 'Пароль', // added 18.04.2012 + 'confirmUnmount' : 'Вы хотите отключить $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Перетащите или вставьте файлы из браузера', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Перетащите или вставьте файлы и ссылки сюда', // from v2.1 added 07.04.2014 + 'encoding' : 'Кодировка', // from v2.1 added 19.12.2014 + 'locale' : 'Локаль', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Цель: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Поиск по введенному MIME типу', // from v2.1 added 22.5.2015 + 'owner' : 'Владелец', // from v2.1 added 20.6.2015 + 'group' : 'Группа', // from v2.1 added 20.6.2015 + 'other' : 'Остальные', // from v2.1 added 20.6.2015 + 'execute' : 'Исполнить', // from v2.1 added 20.6.2015 + 'perm' : 'Разрешение', // from v2.1 added 20.6.2015 + 'mode' : 'Режим', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Папка пуста', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Папка пуста\\A Перетащите чтобы добавить', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Папка пуста\\A Долгое нажатие чтобы добавить', // from v2.1.6 added 30.12.2015 + 'quality' : 'Качество', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Авто синхронизация', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Передвинуть вверх', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Получить URL ссылку', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Выбранные объекты ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID папки', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Позволить автономный доступ', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Авторизоваться повторно', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Загружается...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Открыть несколько файлов', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Вы пытаетесь открыть $1 файл(а/ов). Вы уверены, что хотите открыть их в браузере?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Ничего не найдено', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Это редактируемый файл.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Вы выбрали $1 файл(-ов).', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'У вас $1 файл(-ов) в буфере обмена.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Инкрементный поиск возможен только из текущего вида.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Восстановить', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 завершен', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Контекстное меню', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Переключение страницы', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Корни томов', // from v2.1.16 added 16.9.2016 + 'reset' : 'Сбросить', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Фоновый цвет', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Выбор цвета', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px сетка', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Включено', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Отключено', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Ничего не найдено в текущем виде.\\AНажмите [Enter] для развертывания цели поиска.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Поиск по первому символу не дал результатов в текущем виде.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Текстовая метка', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 минут осталось', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Переоткрыть с выбранной кодировкой', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Сохранить с выбранной кодировкой', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Выбрать папку', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Поиск по первому символу', // from v2.1.23 added 24.3.2017 + 'presets' : 'Пресеты', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Слишком много файлов для перемещения в корзину.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Текстовая область', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Очистить папку "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Нет файлов в паке "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Настройка', // from v2.1.26 added 28.6.2017 + 'language' : 'Язык', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Сбросить настройки для этого браузера', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Настройки панели', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... еще символов: $1.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... еще строк: $1.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Общий размер', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Приблизительный размер файла', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Фокус на элементе диалога при наведении мыши', // from v2.1.30 added 2.11.2017 + 'select' : 'Выбрать', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Действие при выборе файла', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Открывать в редакторе, выбранном в прошлый раз', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Выбрать элементы с инвертированием', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Переименовать выбранные элементы ($1 шт.) в $2?
                      Действие нельзя отменить!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Групповое переименование', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Число', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Добавить префикс', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Добавить суффикс', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Изменить расширение', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Настройки колонок (для просмотра в виде списка)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Все изменения будут немедленно отражены в архиве.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Изменения не вступят в силу до тех пор, пока вы не размонтируете этот том.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Тома, смонтированные на этом томе, также будут размонтированы. Вы хотите отключить его?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Свойства', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Алгоритмы для отображения хеш-сумм файлов', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Элементы в панели свойств', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Нажмите снова для выхода.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Панель', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Рабочая область', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Диалог', // from v2.1.38 added 4.4.2018 + 'all' : 'Все', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Размер иконок (В виде иконок)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Открывать редактор в развернутом виде', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Так как конвертация с помощью API недоступно, произведите конвертацию на веб-сайте.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'После конвертации вы должны загрузить скачанный файл, чтобы сохранить его.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Конвертировать на сайте $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Интеграции', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Менеджер elFinder интегрирован со следующими внешними сервисами. Ознакомьтесь с правилами пользования, политиками безопасности и др. перед их использованием.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Показать скрытые элементы', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Скрыть скрытые элементы', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Показать/скрыть скрытые элементы', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Типы файлов в меню "Новый файл"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Тип текстового файла', // from v2.1.41 added 7.8.2018 + 'add' : 'Добавить', // from v2.1.41 added 7.8.2018 + 'theme' : 'Тема', // from v2.1.43 added 19.10.2018 + 'default' : 'По умолчанию', // from v2.1.43 added 19.10.2018 + 'description' : 'Описание', // from v2.1.43 added 19.10.2018 + 'website' : 'Веб-сайт', // from v2.1.43 added 19.10.2018 + 'author' : 'Автор', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'Лицензия', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Невозможно сохранить файл. Чтобы не потерять изменения, экспортируйте их на свой ПК.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Двойной клик по файлу для его выбора.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Использовать полноэкранный режим', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Неизвестный', + 'kindRoot' : 'Корень тома', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Папка', + 'kindSelects' : 'Выбор', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Ссылка', + 'kindAliasBroken' : 'Битая ссылка', + // applications + 'kindApp' : 'Приложение', + 'kindPostscript' : 'Документ Postscript', + 'kindMsOffice' : 'Документ Microsoft Office', + 'kindMsWord' : 'Документ Microsoft Word', + 'kindMsExcel' : 'Документ Microsoft Excel', + 'kindMsPP' : 'Презентация Microsoft Powerpoint', + 'kindOO' : 'Документ Open Office', + 'kindAppFlash' : 'Приложение Flash', + 'kindPDF' : 'Документ PDF', + 'kindTorrent' : 'Файл Bittorrent', + 'kind7z' : 'Архив 7z', + 'kindTAR' : 'Архив TAR', + 'kindGZIP' : 'Архив GZIP', + 'kindBZIP' : 'Архив BZIP', + 'kindXZ' : 'Архив XZ', + 'kindZIP' : 'Архив ZIP', + 'kindRAR' : 'Архив RAR', + 'kindJAR' : 'Файл Java JAR', + 'kindTTF' : 'Шрифт True Type', + 'kindOTF' : 'Шрифт Open Type', + 'kindRPM' : 'Пакет RPM', + // fonts + 'kindFont' : 'Шрифт', + 'kindSFNT' : 'Шрифт SFNT', + 'kindEOT' : 'Шрифт Embedded Open Type', + 'kindWOFF' : 'Шрифт Web Open Font Format', + 'kindWOFF2' : 'Шрифт Web Open Font Format 2', + // texts + 'kindText' : 'Текстовый документ', + 'kindTextPlain' : 'Простой текст', + 'kindPHP' : 'Исходник PHP', + 'kindCSS' : 'Таблицы стилей CSS', + 'kindHTML' : 'Документ HTML', + 'kindJS' : 'Исходник Javascript', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'Исходник C', + 'kindCHeader' : 'Заголовочный файл C', + 'kindCPP' : 'Исходник C++', + 'kindCPPHeader' : 'Заголовочный файл C++', + 'kindShell' : 'Скрипт Unix shell', + 'kindPython' : 'Исходник Python', + 'kindJava' : 'Исходник Java', + 'kindRuby' : 'Исходник Ruby', + 'kindPerl' : 'Исходник Perl', + 'kindSQL' : 'Исходник SQL', + 'kindXML' : 'Документ XML', + 'kindAWK' : 'Исходник AWK', + 'kindCSV' : 'Текст с разделителями', + 'kindDOCBOOK' : 'Документ Docbook XML', + 'kindMarkdown' : 'Текст Markdown', // added 20.7.2015 + // images + 'kindImage' : 'Изображение', + 'kindBMP' : 'Изображение BMP', + 'kindJPEG' : 'Изображение JPEG', + 'kindGIF' : 'Изображение GIF', + 'kindPNG' : 'Изображение PNG', + 'kindTIFF' : 'Изображение TIFF', + 'kindTGA' : 'Изображение TGA', + 'kindPSD' : 'Изображение Adobe Photoshop', + 'kindXBITMAP' : 'Изображение X bitmap', + 'kindPXM' : 'Изображение Pixelmator', + // media + 'kindAudio' : 'Аудио файл', + 'kindAudioMPEG' : 'Аудио MPEG', + 'kindAudioMPEG4' : 'Аудио MPEG-4', + 'kindAudioMIDI' : 'Аудио MIDI', + 'kindAudioOGG' : 'Аудио Ogg Vorbis', + 'kindAudioWAV' : 'Аудио WAV', + 'AudioPlaylist' : 'Плейлист MP3', + 'kindVideo' : 'Видео файл', + 'kindVideoDV' : 'Видео DV', + 'kindVideoMPEG' : 'Видео MPEG', + 'kindVideoMPEG4' : 'Видео MPEG-4', + 'kindVideoAVI' : 'Видео AVI', + 'kindVideoMOV' : 'Видео Quick Time', + 'kindVideoWM' : 'Видео Windows Media', + 'kindVideoFlash' : 'Видео Flash', + 'kindVideoMKV' : 'Видео Matroska', + 'kindVideoOGG' : 'Видео Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.si.js b/lib/redactor/elfinder/js/i18n/elfinder.si.js new file mode 100644 index 0000000..8c6ca42 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.si.js @@ -0,0 +1,544 @@ +/** + * Sinhala translation + * @author CodeLyokoXtEAM + * @version 2018-03-26 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.si = { + translator : 'CodeLyokoXtEAM <XcodeLyokoTEAM@gmail.com>', + language : 'Sinhala', + direction : 'ltr', + dateFormat : 'Y.m.d h:i A', // Mar 13, 2012 05:27 PM + fancyDateFormat : '$1 h:i A', // will produce smth like: Today 12:25 PM + nonameDateFormat : 'Ymd-His', // to apply if upload file is noname: 120513172700 + messages : { + + /********************************** errors **********************************/ + 'error' : 'දෝෂයකි.', + 'errUnknown' : 'නොදන්නා දෝෂයකි.', + 'errUnknownCmd' : 'නොදන්නා විධානයකි.', + 'errJqui' : 'වලංගු නොවන jQuery UI සැකැස්මකි. තේරිය හැකි, ඇදගෙන යාම සහ ඇද දැමිය හැකි කොටස් ඇතුළත් කළ යුතුය.', + 'errNode' : 'ElFinder විසින් DOM Element නිර්මාණය කිරීමට අවශ්‍යව අැත.', + 'errURL' : 'වලංගු නොවන elFinder සැකැස්මකි! URL විකල්පය සැකසා නැත.', + 'errAccess' : 'භාවිතය අත්හිටුවා ඇත.', + 'errConnect' : 'පසුබිම(Backend) වෙත සම්බන්ධ වීමට නොහැකිය.', + 'errAbort' : 'සම්බන්ධතාවය වසාදමා ඇත.', + 'errTimeout' : 'සම්බන්ධතා කල් ඉකුත්වී ඇත.', + 'errNotFound' : 'පසුබිම(Backend) සොයාගත නොහැකි විය.', + 'errResponse' : 'වලංගු නොවන පසුබිම(Backend) ප්‍රතිචාරය.', + 'errConf' : 'වලංගු නොවන Backend සැකැස්මකි.', + 'errJSON' : 'PHP JSON මොඩියුලය ස්ථාපනය කර නැත.', + 'errNoVolumes' : 'කියවිය හැකි එ්කක(volumes) නොමැත.', + 'errCmdParams' : '"$1" නම් විධානය වලංගු නොවන පරාමිතියකි.', + 'errDataNotJSON' : 'JSON දත්ත නොවේ.', + 'errDataEmpty' : 'හිස් දත්තයකි.', + 'errCmdReq' : 'Backend සඳහා ඉල්ලන ලද විධානයේ නම අවශ්‍ය වේ.', + 'errOpen' : '"$1" විවෘත කළ නොහැක.', + 'errNotFolder' : 'අායිත්තම(object) ෆොල්ඩරයක් නොවේ.', + 'errNotFile' : 'අායිත්තම(object) ගොනුවක් නොවේ.', + 'errRead' : '"$1" කියවීමට නොහැක.', + 'errWrite' : '"$1" තුල ලිවීමට නොහැකිය.', + 'errPerm' : 'අවසරය නොමැත.', + 'errLocked' : '"$1" අගුළු දමා ඇති අතර එය නැවත නම් කිරීම, සම්පූර්ණයෙන් විස්ථාපනය කිරීම හෝ ඉවත් කිරීම කළ නොහැක.', + 'errExists' : '"$1" නම් ගොනුව දැනටමත් පවතී.', + 'errInvName' : 'ගොනු නම වලංගු නොවේ.', + 'errInvDirname' : 'ෆෝල්ඩර් නම වලංගු නොවේ.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'ෆෝල්ඩරය හමු නොවිණි.', + 'errFileNotFound' : 'ගොනුව හමු නොවිණි.', + 'errTrgFolderNotFound' : 'ඉලක්කගත ෆෝල්ඩරය "$1" හමු නොවිනි.', + 'errPopup' : 'බ්‍රවුසරය උත්පතන කවුළුව විවෘත කිරීම වළක්වයි. ගොනු විවෘත කිරීම සඳහා බ්‍රවුසරයේ විකල්ප තුළ එය සක්රිය කරන්න.', + 'errMkdir' : '"$1" ෆෝල්ඩරය සෑදීමට නොහැකිය.', + 'errMkfile' : '"$1" ගොනුව සෑදිය නොහැක.', + 'errRename' : '"$1" නැවත නම් කිරීමට නොහැකි විය.', + 'errCopyFrom' : '"$1" volume යෙන් ගොනු පිටපත් කිරීම තහනම්ය.', + 'errCopyTo' : '"$1" volume යට ගොනු පිටපත් කිරීම තහනම්ය.', + 'errMkOutLink' : 'volume root යෙන් පිටතට සබැඳිය(link) නිර්මාණය කිරීමට නොහැකි විය.', // from v2.1 added 03.10.2015 + 'errUpload' : 'උඩුගත(upload) කිරීමේ දෝෂයකි.', // old name - errUploadCommon + 'errUploadFile' : '"$1" උඩුගත(upload) කිරීමට නොහැකි විය.', // old name - errUpload + 'errUploadNoFiles' : 'උඩුගත(upload) කිරීම සඳහා ගොනු කිසිවක් සොයාගත නොහැකි විය.', + 'errUploadTotalSize' : 'දත්ත අවසර දී අැති උපරිම ප්‍රමාණය ඉක්මවා ඇත.', // old name - errMaxSize + 'errUploadFileSize' : 'ගොනු අවසර දී අැති උපරිම ප්‍රමාණය ඉක්මවා ඇත.', // old name - errFileMaxSize + 'errUploadMime' : 'ගොනු වර්ගයට අවසර නැත.', + 'errUploadTransfer' : '"$1" ව මාරු කිරීමේ දෝෂයකි.', + 'errUploadTemp' : 'upload කිරීම සඳහා තාවකාලික ගොනුව සෑදිය නොහැක.', // from v2.1 added 26.09.2015 + 'errNotReplace' : '"$1" අායිත්තම(object) දැනටමත් මෙම ස්ථානයේ පවතී, වෙනත් වර්ගයකිනි ප්‍රතිස්ථාපනය කළ නොහැක.', // new + 'errReplace' : '"$1" ප්‍රතිස්ථාපනය කළ නොහැක.', + 'errSave' : '"$1" සුරැකීමට නොහැක.', + 'errCopy' : '"$1" පිටපත් කිරීමට නොහැක.', + 'errMove' : '"$1" සම්පූර්ණයෙන් විස්ථාපනය කිරීමට නොහැක.', + 'errCopyInItself' : '"$1" තුලට පිටපත් කිරීමට නොහැක.', + 'errRm' : '"$1" ඉවත් කිරීමට නොහැකි විය.', + 'errTrash' : 'කුණු-කූඩය තුලට දැමීමට නොහැක.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'මූලාශ්‍රය ගොනු(ව) ඉවත් කළ නොහැක.', + 'errExtract' : '"$1" වෙතින් ගොනු දිග හැරීමට නොහැක.', + 'errArchive' : 'සංරක්ෂිතය සෑදීමට නොහැකි විය.', + 'errArcType' : 'නොගැලපෙන සංරක්ෂණ වර්ගයකි.', + 'errNoArchive' : 'ගොනුව නොගැලපෙන සංරක්ෂණ වර්ගයක් හෝ සංරක්ෂිතයක් නොවේ.', + 'errCmdNoSupport' : 'පසුබිම(Backend) මෙම විධානය නොදනී.', + 'errReplByChild' : '"$1" ෆෝල්ඩරය එහිම අඩංගු අයිතමයක් මගින් ප්‍රතිස්ථාපනය කළ නොහැක.', + 'errArcSymlinks' : 'ආරක්ෂිත හේතුව නිසා අනුමත නොකෙරෙන සබැඳි සම්බන්දතා හෝ ලිපිගොනු නම් අඩංගු බැවින් සංරක්ෂිතය දිග හැරීම කිරීමට ඉඩ නොදෙන.', // edited 24.06.2012 + 'errArcMaxSize' : 'සංරක්ෂිතය ලිපිගොනු උපරිම ප්‍රමාණය ඉක්මවා ඇත.', + 'errResize' : 'ප්‍රතිප්‍රමාණය කිරීමට නොහැකි විය.', + 'errResizeDegree' : 'වලංගු නොවන භ්‍රමණ කෝණයකි.', // added 7.3.2013 + 'errResizeRotate' : 'රූපය භ්‍රමණය කිරීමට නොහැකි විය.', // added 7.3.2013 + 'errResizeSize' : 'රූපයේ ප්‍රමාණය වලංගු නොවේ.', // added 7.3.2013 + 'errResizeNoChange' : 'රූපයේ ප්‍රමාණය වෙනස් නොවුණි.', // added 7.3.2013 + 'errUsupportType' : 'නොගැලපෙන ගොනු වර්ගයකි.', + 'errNotUTF8Content' : '"$1" ගොනුව UTF-8 හි නොමැති අතර සංස්කරණය කළ නොහැක.', // added 9.11.2011 + 'errNetMount' : '"$1" සවි(mount) කිරීමට නොහැක.', // added 17.04.2012 + 'errNetMountNoDriver' : 'ප්‍රොටොකෝලය(protocol) නොගැලපේ.', // added 17.04.2012 + 'errNetMountFailed' : 'සවි කිරීම(mount කිරීම) අසාර්ථක විය.', // added 17.04.2012 + 'errNetMountHostReq' : 'ධාරකය(Host) අවශ්‍ය වේ.', // added 18.04.2012 + 'errSessionExpires' : 'ඔබේ අක්‍රියතාව හේතුවෙන් සැසිය(session) කල් ඉකුත් වී ඇත.', + 'errCreatingTempDir' : 'තාවකාලික ඩිරෙක්ටරයක්(directory) ​​සෑදිය නොහැක: "$1"', + 'errFtpDownloadFile' : 'FTP වලින් ගොනුව බාගත(download) කිරීමට නොහැකි විය: "$1"', + 'errFtpUploadFile' : 'ගොනුව FTP වෙත උඩුගත(upload) කිරීමට නොහැකි විය: "$1"', + 'errFtpMkdir' : 'FTP මත දුරස්ථ නාමාවලියක්(remote directory) නිර්මාණය කිරීමට නොහැකි විය: "$1"', + 'errArchiveExec' : 'ගොනු සංරක්ෂණය(archiving) කිරීමේදී දෝෂයක් ඇතිවිය: "$1"', + 'errExtractExec' : 'ගොනු දිගහැරීමේදී(extracting) දෝෂයක් ඇතිවිය: "$1"', + 'errNetUnMount' : 'විසන්ධි කිරීමට(unmount) නොහැක.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'UTF-8 වෙත පරිවර්තනය කළ නොහැක.', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'ඔබ ෆෝල්ඩරය උඩුගත(upload) කිරීමට කැමති නම් නවීන බ්‍රවුසරයකින් උත්සාහ කරන්න.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '"$1" සෙවීම කල් ඉකුත්වී ඇත. සෙවුම් ප්‍රතිඵල අර්ධ වශයෙන් දිස්වේ.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'නැවත බලය(Re-authorization) ලබා දීම අවශ්‍ය වේ.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'තෝරා ගත හැකි උපරිම අයිතම සංඛ්‍යාව $1 ක් වේ.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'කුණු කූඩයෙන් නැවත ලබා ගත නොහැක. යළි පිහිටුවීමේ ගමනාන්තය(restore destination) හඳුනාගත නොහැක.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'මෙම ගොනු වර්ගයේ සංස්කාරකය හමු නොවිණි.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'සේවාදායකයේ පැත්තෙන්(server side) දෝශයක් ඇතිවිය.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : '"$1" ෆෝල්ඩරය හිස් කිරීමට නොහැක.', // from v2.1.25 added 22.6.2017 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'සංරක්ෂිතය(archive) නිර්මාණය කරන්න', + 'cmdback' : 'ආපසු', + 'cmdcopy' : 'පිටපත් කරන්න', + 'cmdcut' : 'මුළුමනින්ම පිටපත් කරන්න(Cut)', + 'cmddownload' : 'බාගත කරන්න(Download)', + 'cmdduplicate' : 'අනුපිටපත් කරන්න(Duplicate)', + 'cmdedit' : 'ගොනුව සංස්කරණය කරන්න', + 'cmdextract' : 'සංරක්ෂිතයේ ගොනු දිගහරින්න(Extract)', + 'cmdforward' : 'ඉදිරියට', + 'cmdgetfile' : 'ගොනු තෝරන්න', + 'cmdhelp' : 'මෙම මෘදුකාංගය පිළිබඳව', + 'cmdhome' : 'නිවහන(Home)', + 'cmdinfo' : 'තොරතුරු ලබාගන්න', + 'cmdmkdir' : 'අළුත් ෆෝල්ඩරයක්', + 'cmdmkdirin' : 'අළුත් ෆෝල්ඩරයක් තුළට', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'නව ගොනුවක්', + 'cmdopen' : 'විවෘත කරන්න', + 'cmdpaste' : 'දමන්න(Paste)', + 'cmdquicklook' : 'පූර්ව දර්ශනයක්(Preview)', + 'cmdreload' : 'නැවත අළුත් කරන්න(Reload)', + 'cmdrename' : 'නම වෙනස් කරන්න', + 'cmdrm' : 'මකන්න', + 'cmdtrash' : 'කුණු කූඩයට දමන්න', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'යළි පිහිටුවන්න(Restore)', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'ගොනු සොයන්න', + 'cmdup' : 'ප්‍ර්‍රධාන නාමාවලිය(parent directory) වෙත යන්න', + 'cmdupload' : 'ගොනු උඩුගත(Upload) කරන්න', + 'cmdview' : 'දර්ශනය(View)', + 'cmdresize' : 'ප්‍රථිප්‍රමාණය සහ භ්‍රමණය', + 'cmdsort' : 'වර්ගීකරණය කරන්න', + 'cmdnetmount' : 'ජාල එ්කකයක් සවි කරන්න(Mount network volume)', // added 18.04.2012 + 'cmdnetunmount': 'ගලවන්න(Unmount)', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'පහසු ස්ථානයට(To Places)', // added 28.12.2014 + 'cmdchmod' : 'ක්‍රමය වෙනස් කරන්න', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'ෆෝල්ඩරය විවෘත කරන්න', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'නැවත තීරු පළල පිහිටුවන්න', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'පුළුල් තිරය', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'මාරු කරන්න(Move)', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'ෆෝල්ඩරය හිස් කරන්න', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'නිෂ්ප්‍රභ කරන්න', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'නැවත කරන්න', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'අභිමතයන් (Preferences)', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'සියල්ල තෝරන්න', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'කිසිවක් තෝරන්න එපා', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'විරුද්ධ අාකාරයට තෝරන්න', // from v2.1.28 added 15.08.2017 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'වසන්න', + 'btnSave' : 'සුරකින්න', + 'btnRm' : 'ඉවත් කරන්න', + 'btnApply' : 'යොදන්න(Apply)', + 'btnCancel' : 'අවලංගු කරන්න', + 'btnNo' : 'නැත', + 'btnYes' : 'ඔව්', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'සවිකිරීම(Mount)', // added 18.04.2012 + 'btnApprove': 'කරුණාකර $1 අනුමත කරන්න', // from v2.1 added 26.04.2012 + 'btnUnmount': 'ගලවන්න(Unmount)', // from v2.1 added 30.04.2012 + 'btnConv' : 'පරිවර්තනය කරන්න', // from v2.1 added 08.04.2014 + 'btnCwd' : 'මෙතන', // from v2.1 added 22.5.2015 + 'btnVolume' : 'එ්කකය(Volume)', // from v2.1 added 22.5.2015 + 'btnAll' : 'සියල්ල', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME වර්ගය', // from v2.1 added 22.5.2015 + 'btnFileName':'ගොනුවේ නම', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'සුරකින්න සහ වසන්න', // from v2.1 added 12.6.2015 + 'btnBackup' : 'උපස්ථ(Backup) කරන්න', // fromv2.1 added 28.11.2015 + 'btnRename' : 'නම වෙනස් කරන්න', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'නම වෙනස් කරන්න(සියල්ල)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'පෙර ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'ඊළඟ ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'වෙනත් නමකින් සුරකිමින්(Save As)', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'ෆෝල්ඩරය විවෘත කරමින්', + 'ntffile' : 'ගොනුව විවෘත කරමින්', + 'ntfreload' : 'ෆෝල්ඩර් අන්තර්ගතය නැවත අළුත් කරමින්(Reloading)', + 'ntfmkdir' : 'ෆෝල්ඩරයක් නිර්මාණය කරමින්', + 'ntfmkfile' : 'ගොනුව නිර්මාණය කරමින්', + 'ntfrm' : 'අයිතමයන් මකමින්', + 'ntfcopy' : 'අයිතමයන් පිටපත් කරමින්', + 'ntfmove' : 'අයිතමයන් සම්පූර්ණයෙන් විස්ථාපනය කරමින්', + 'ntfprepare' : 'පවතින අයිතම පිරික්සමින්', + 'ntfrename' : 'ගොනු නැවත නම් කරමින්', + 'ntfupload' : 'ගොනු උඩුගත(uploading) කරමින්', + 'ntfdownload' : 'ගොනු බාගත(downloading) කරමින්', + 'ntfsave' : 'ගොනු සුරකිමින්', + 'ntfarchive' : 'සංරක්ෂණය(archive) සාදමින්', + 'ntfextract' : 'සංරක්ෂණයෙන්(archive) ගොනු දිගහරිමින්(Extracting)', + 'ntfsearch' : 'ගොනු සොයමින්', + 'ntfresize' : 'රූප ප්‍රමාණය වෙනස් කරමින්', + 'ntfsmth' : 'දෙයක් කරමින්', + 'ntfloadimg' : 'පින්තූරය පූරණය කරමින්(Loading)', + 'ntfnetmount' : 'ජාල එ්කකයක් සවිකරමින්(Mounting network volume)', // added 18.04.2012 + 'ntfnetunmount': 'ජාල එ්කකයක් ගලවමින්(Unmounting network volume)', // from v2.1 added 30.04.2012 + 'ntfdim' : 'පිංතූරයේ මානය(dimension) ලබාගනිමින්', // added 20.05.2013 + 'ntfreaddir' : 'ෆෝල්ඩරයේ තොරතුරු කියවමින්', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Getting URL of link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'ගොනු ආකරය වෙනස් කරමින්', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'උඩුගත(upload) කරන ලද ගොනු නාමය සත්‍යාපනය කරමින්(Verifying)', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'බාගත කරගැනීම(download) සඳහා ගොනුවක් නිර්මාණය කරමින්', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'මාර්ග(path) තොරතුරු ලබා ගනිමින්', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'උඩුගත කරන ලද(uploaded) ගොනුව සකසමින්', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'කුණු කූඩයට දමමින්', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'කුණු කූඩයට දැමීම යළි පිහිටුවමින්(Doing restore)', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'ගමනාන්ත(destination) ෆෝල්ඩරය පරීක්ෂා කරමින්', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'පෙර මෙහෙයුම(operation) ඉවත් කරමින්', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'පෙර ආපසු හැරවීම යළි සැකසමින්', // from v2.1.27 added 31.07.2017 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'කුණු කූඩය', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'නොදනී', + 'Today' : 'අද', + 'Yesterday' : 'ඊයේ', + 'msJan' : 'ජනවා.', + 'msFeb' : 'පෙබ.', + 'msMar' : 'මාර්.', + 'msApr' : 'අප්‍රේ.', + 'msMay' : 'මැයි', + 'msJun' : 'ජූනි', + 'msJul' : 'ජුලි', + 'msAug' : 'අගෝ.', + 'msSep' : 'සැප්.', + 'msOct' : 'ඔක්තෝ.', + 'msNov' : 'නොවැ.', + 'msDec' : 'දෙසැ.', + 'January' : 'ජනවාරි', + 'February' : 'පෙබරවාරි', + 'March' : 'මාර්තු', + 'April' : 'අප්‍රේල්', + 'May' : 'මැයි', + 'June' : 'ජූනි', + 'July' : 'ජුලි', + 'August' : 'අගෝස්තු', + 'September' : 'සැප්තැම්බර්', + 'October' : 'ඔක්තෝම්බර්', + 'November' : 'නොවැම්බර්', + 'December' : 'දෙසැම්බර්', + 'Sunday' : 'ඉරිදා', + 'Monday' : 'සඳුදා', + 'Tuesday' : 'අඟහරුවාදා', + 'Wednesday' : 'බදාදා', + 'Thursday' : 'බ්‍රහස්පතින්දා', + 'Friday' : 'සිකුරාදා', + 'Saturday' : 'සෙනසුරාදා', + 'Sun' : 'ඉරිදා', + 'Mon' : 'සඳු.', + 'Tue' : 'අඟහ.', + 'Wed' : 'බදාදා', + 'Thu' : 'බ්‍රහස්.', + 'Fri' : 'සිකු.', + 'Sat' : 'සෙන.', + + /******************************** sort variants ********************************/ + 'sortname' : 'නම අනුව', + 'sortkind' : 'වර්ගය අනුව', + 'sortsize' : 'ප්‍රමාණය අනුව', + 'sortdate' : 'දිනය අනුව', + 'sortFoldersFirst' : 'ෆෝල්ඩර වලට පළමු තැන', + 'sortperm' : 'අවසරය අනුව', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'අාකාරය අනුව', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'හිමිකරු අනුව', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'කණ්ඩායම අනුව', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'එලෙසටම රුක්සටහනත්(Treeview)', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NewFile.txt', // added 10.11.2015 + 'untitled folder' : 'නව ෆෝල්ඩරයක්', // added 10.11.2015 + 'Archive' : 'NewArchive', // from v2.1 added 10.11.2015 + + /********************************** messages **********************************/ + 'confirmReq' : 'තහවුරු කිරීම අවශ්‍යයි', + 'confirmRm' : 'අයිතමයන් සදහටම ඉවත් කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද?
                      මෙය අාපසු හැරවිය නොහැකිය!', + 'confirmRepl' : 'පැරණි අයිතමය නව එකක මගින් ප්‍රතිස්ථාපනය කරන්නද?', + 'confirmRest' : 'දැනට පවතින අයිතමය කුණු කූඩය තුළ පවතින අයිතමය මගින් ප්‍රතිස්ථාපනය කරන්නද?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'UTF-8 හි නොවේ
                      UTF-8 වෙත පරිවර්තනය කරන්න ද?
                      සුරැකීමෙන් පසු අන්තර්ගතය UTF-8 බවට පරිවර්තනය වේ.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'මෙම ගොනුවෙහි කේතන කේත(Character encoding) හඳුනාගත නොහැකි විය. සංස්කරණ කිරීමට එය තාවකාලිකව UTF-8 වෙත පරිවර්තනය කිරීම අවශ්‍ය වේ.
                      කරුණාකර මෙම ගොනුවෙහි අක්ෂර කේතන කේත(character encoding) තෝරන්න.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'මෙය වෙනස් කර ඇත.
                      ඔබට වෙනස්කම් සුරැකීමට නොහැකි නම් සිදු කරනු ලැබූ වෙනස්කම් අහිමි වේ.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'කුණු කූඩය තුලට අයිතමය යැවීමට ඔබට අවශ්‍ය ද?', //from v2.1.24 added 29.4.2017 + 'apllyAll' : 'සියල්ලටම යොදන්න', + 'name' : 'නම', + 'size' : 'ප්‍රමාණය', + 'perms' : 'අවසරය', + 'modify' : 'නවීකරණය කෙරුණ ලද්දේ', + 'kind' : 'ජාතිය', + 'read' : 'කියවන්න', + 'write' : 'ලියන්න', + 'noaccess' : 'ප්‍රවේශයක් නොමැත', + 'and' : 'සහ', + 'unknown' : 'නොහඳුනයි', + 'selectall' : 'සියලු ගොනු තෝරන්න', + 'selectfiles' : 'ගොනු(ව) තෝරන්න', + 'selectffile' : 'පළමු ගොනුව තෝරන්න', + 'selectlfile' : 'අවසාන ගොනුව තෝරන්න', + 'viewlist' : 'ලැයිස්තු අාකාරය', + 'viewicons' : 'අයිකන අාකාරය', + 'places' : 'Places', + 'calc' : 'ගණනය කරන්න', + 'path' : 'මාර්ගය', + 'aliasfor' : 'Alias for', + 'locked' : 'අගුළු දමා ඇත', + 'dim' : 'මාන(Dimensions)', + 'files' : 'ගොනු', + 'folders' : 'ෆෝල්ඩර', + 'items' : 'අයිතම(Items)', + 'yes' : 'ඔව්', + 'no' : 'නැත', + 'link' : 'සබැඳිය(Link)', + 'searcresult' : 'සෙවුම් ප්‍රතිඵල', + 'selected' : 'තෝරාගත් අයිතම', + 'about' : 'මේ ගැන', + 'shortcuts' : 'කෙටිමං', + 'help' : 'උදව්', + 'webfm' : 'වෙබ් ගොනු කළමනාකරු', + 'ver' : 'අනුවාදය(version)', + 'protocolver' : 'ප්‍රොටොකෝලය අනුවාදය(protocol version)', + 'homepage' : 'ව්‍යාපෘතිය නිවහන', + 'docs' : 'ලේඛනගත කිරීම', + 'github' : 'Github හරහා සංවාදයේ යෙදෙන්න', + 'twitter' : 'Twitter හරහා අපව සම්බන්ධ වන්න', + 'facebook' : 'Facebook හරහා අප සමඟ එකතු වන්න', + 'team' : 'කණ්ඩායම', + 'chiefdev' : 'ප්‍රධාන සංස්කරු(chief developer)', + 'developer' : 'සංස්කරු(developer)', + 'contributor' : 'දායකයා(contributor)', + 'maintainer' : 'නඩත්තු කරන්නා(maintainer)', + 'translator' : 'පරිවර්තකයා', + 'icons' : 'අයිකන', + 'dontforget' : 'and don\'t forget to take your towel', + 'shortcutsof' : 'කෙටිමං අක්‍රීය කර ඇත', + 'dropFiles' : 'ගොනු මෙතැනට ඇද දමන්න', + 'or' : 'හෝ', + 'selectForUpload' : 'ගොනු තෝරන්න', + 'moveFiles' : 'අායිත්තම සම්පූර්ණයෙන් විස්ථාපනය', + 'copyFiles' : 'අයිතමයන් පිටපත් කරන්න', + 'restoreFiles' : 'Restore items', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Remove from places', + 'aspectRatio' : 'දර්ශන අනුපාතය(Aspect ratio)', + 'scale' : 'පරිමාණය', + 'width' : 'පළල', + 'height' : 'උස', + 'resize' : 'ප්‍රතිප්‍රමානණය', + 'crop' : 'Crop', + 'rotate' : 'කැරකැවීම', + 'rotate-cw' : 'අංශක 90කින් කරකවන්න CW', + 'rotate-ccw' : 'අංශක 90කින් කරකවන්න CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'පරිශීලක', // added 18.04.2012 + 'pass' : 'මුරපදය', // added 18.04.2012 + 'confirmUnmount' : 'Are you unmount $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Drop or Paste files from browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Drop files, Paste URLs or images(clipboard) here', // from v2.1 added 07.04.2014 + 'encoding' : 'කේතීකරණය(Encoding)', // from v2.1 added 19.12.2014 + 'locale' : 'Locale', // from v2.1 added 19.12.2014 + 'searchTarget' : 'ඉලක්කය: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Search by input MIME Type', // from v2.1 added 22.5.2015 + 'owner' : 'හිමිකරු', // from v2.1 added 20.6.2015 + 'group' : 'සමූහය', // from v2.1 added 20.6.2015 + 'other' : 'වෙනත්', // from v2.1 added 20.6.2015 + 'execute' : 'ක්‍රයාත්මක කරන්න', // from v2.1 added 20.6.2015 + 'perm' : 'අවසරය', // from v2.1 added 20.6.2015 + 'mode' : 'Mode', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'ෆෝල්ඩරය හිස්', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'ෆාේල්ඩරය හිස්\\A අායිත්තම අතහැරීමෙන් අැතුලු කරන්න', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'ෆාේල්ඩරය හිස්\\A දිර්ඝ එබීමෙන් අායිත්තම අැතුලු කරන්න', // from v2.1.6 added 30.12.2015 + 'quality' : 'ගුණාත්මකභාවය', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Auto sync', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Move up', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Get URL link', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'තෝරාගත් අයිතම ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Folder ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Allow offline access', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'To re-authenticate', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Now loading...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'බහු ගොනු විවෘත කරන්න', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'ඔබ $1 ගොනු විවෘත කිරීමට උත්සාහ කරයි. බ්‍රව්සරයෙන් ඔබට විවෘත කිරීමට අවශ්‍ය බව ඔබට විශ්වාසද?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'සෙවුම් ඉලක්කයේ ගවේෂණ ප්‍රතිඵල නොමැත.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'එය ගොනුව සංස්කරණය කිරීමකි.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'ඔබ අයිතම $1 ප්‍රමාණයක් තෝරාගෙන ඇත.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'You have $1 items in the clipboard.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Incremental search is only from the current view.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'යථා තත්ත්වයට පත් කරන්න', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 සම්පූර්ණයි', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Context menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Page turning', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016 + 'reset' : 'යළි පිහිටුවන්න(Reset)', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'පසුබිම් වර්ණය', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Color picker', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'පික්සල් 8ක දැල', // from v2.1.16 added 4.10.2016 + 'enabled' : 'සක්‍රීයයි', // from v2.1.16 added 4.10.2016 + 'disabled' : 'අක්‍රීයයි', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'වර්තමාන දර්ශනය තුළ සෙවුම් ප්‍රතිපල හිස්ව ඇත. \\A සෙවුම් ඉලක්කය පුළුල් කිරීම සඳහා [Enter] යතුර ඔබන්න.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'වර්තමාන දර්ශනයේ පළමු අකුර සෙවුම් ප්‍රතිපල හිස්ව පවතී.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'ලේබල්වල නම්', // from v2.1.17 added 13.10.2016 + 'minsLeft' : 'විනාඩි $1 ක් ගතවේ', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'ෆෝල්ඩරය තෝරන්න', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'පළමු අකුරෙන් සෙවීම', // from v2.1.23 added 24.3.2017 + 'presets' : 'Presets', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'It\'s too many items so it can\'t into trash.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Empty the folder "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'There are no items in a folder "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preference', // from v2.1.26 added 28.6.2017 + 'language' : 'Language setting', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialize the settings saved in this browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Toolbar setting', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 ක් අකුරු ඉතිරිව පවතී', // from v2.1.29 added 30.8.2017 + 'sum' : 'එකතුව', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Rough file size', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focus on the element of dialog with mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'තෝරන්න', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'ගොනුවක් තේරූ විට සිදුකල යුතු දේ', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Open with the editor used last time', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'ප්‍රතිවිරුද්ධ අාකාරයට තෝරන්න', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Are you sure you want to rename $1 selected items like $2?
                      This cannot be undone!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch rename', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Number', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Add prefix', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Add suffix', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Change extention', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Columns settings (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'All changes will reflect immediately to the archive.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Any changes will not reflect until un-mount this volume.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'තෝරාගැනීම්වල තොරතුරු', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorithms to show the file hash', // from v2.1.33 added 10.3.2018 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'නොදන්නා', + 'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'ෆෝල්ඩරය', + 'kindSelects' : 'තේරීම්', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Broken alias', + // applications + 'kindApp' : 'Application', + 'kindPostscript' : 'Postscript ලේඛනය', + 'kindMsOffice' : 'Microsoft Office ලේඛනය', + 'kindMsWord' : 'Microsoft Word ලේඛනය', + 'kindMsExcel' : 'Microsoft Excel ලේඛනය', + 'kindMsPP' : 'Microsoft Powerpoint presentation', + 'kindOO' : 'Open Office ලේඛනය', + 'kindAppFlash' : 'Flash application', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent file', + 'kind7z' : '7z archive', + 'kindTAR' : 'TAR archive', + 'kindGZIP' : 'GZIP archive', + 'kindBZIP' : 'BZIP archive', + 'kindXZ' : 'XZ archive', + 'kindZIP' : 'ZIP archive', + 'kindRAR' : 'RAR archive', + 'kindJAR' : 'Java JAR file', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM package', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Text ලේඛනය', + 'kindTextPlain' : 'Plain text', + 'kindPHP' : 'PHP මූලාශ්‍රය', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML ලේඛනය', + 'kindJS' : 'Javascript මූලාශ්‍රය', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C මූලාශ්‍රය', + 'kindCHeader' : 'C header මූලාශ්‍රය', + 'kindCPP' : 'C++ මූලාශ්‍රය', + 'kindCPPHeader' : 'C++ header මූලාශ්‍රය', + 'kindShell' : 'Unix shell රචනයකි', + 'kindPython' : 'Python මූලාශ්‍රය', + 'kindJava' : 'Java මූලාශ්‍රය', + 'kindRuby' : 'Ruby මූලාශ්‍රය', + 'kindPerl' : 'Perl රචනයකි', + 'kindSQL' : 'SQL මූලාශ්‍රය', + 'kindXML' : 'XML ලේඛනය', + 'kindAWK' : 'AWK මූලාශ්‍රය', + 'kindCSV' : 'කොමාවන් වෙන් කළ අගයන්', + 'kindDOCBOOK' : 'Docbook XML ලේඛනය', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'පින්තූරය', + 'kindBMP' : 'BMP පින්තූරය', + 'kindJPEG' : 'JPEG පින්තූරය', + 'kindGIF' : 'GIF පින්තූරය', + 'kindPNG' : 'PNG පින්තූරය', + 'kindTIFF' : 'TIFF පින්තූරය', + 'kindTGA' : 'TGA පින්තූරය', + 'kindPSD' : 'Adobe Photoshop පින්තූරය', + 'kindXBITMAP' : 'X bitmap පින්තූරය', + 'kindPXM' : 'Pixelmator පින්තූරය', + // media + 'kindAudio' : 'ශබ්ධ මාධ්‍ය', + 'kindAudioMPEG' : 'MPEG ශබ්ධපටය', + 'kindAudioMPEG4' : 'MPEG-4 ශබ්ධපටය', + 'kindAudioMIDI' : 'MIDI ශබ්ධපටය', + 'kindAudioOGG' : 'Ogg Vorbis ශබ්ධපටය', + 'kindAudioWAV' : 'WAV ශබ්ධපටය', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video මාධ්‍ය', + 'kindVideoDV' : 'DV චිත්‍රපටය', + 'kindVideoMPEG' : 'MPEG චිත්‍රපටය', + 'kindVideoMPEG4' : 'MPEG-4 චිත්‍රපටය', + 'kindVideoAVI' : 'AVI චිත්‍රපටය', + 'kindVideoMOV' : 'Quick Time චිත්‍රපටය', + 'kindVideoWM' : 'Windows Media චිත්‍රපටය', + 'kindVideoFlash' : 'Flash චිත්‍රපටය', + 'kindVideoMKV' : 'Matroska චිත්‍රපටය', + 'kindVideoOGG' : 'Ogg චිත්‍රපටය' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.sk.js b/lib/redactor/elfinder/js/i18n/elfinder.sk.js new file mode 100644 index 0000000..9dd1f86 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.sk.js @@ -0,0 +1,588 @@ +/** + * Slovak translation + * @author RobiNN + * @author Jakub Ďuraš + * @version 2021-06-10 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.sk = { + translator : 'RobiNN <robo@kelcak.com>, Jakub Ďuraš <jkblmr@gmail.com>', + language : 'Slovenčina', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // will show like: 10.06.2021 23:35 + fancyDateFormat : '$1 H:i', // will show like: Dnes 23:35 + nonameDateFormat : 'ymd-His', // noname upload will show like: 210610-233522 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Chyba', + 'errUnknown' : 'Neznáma chyba.', + 'errUnknownCmd' : 'Neznámy príkaz.', + 'errJqui' : 'Nesprávna jQuery UI konfigurácia. Selectable, draggable a droppable musia byť načítané.', + 'errNode' : 'elFinder vyžaduje vytvorenie DOM elementu.', + 'errURL' : 'Nesprávna elFinder konfigurácia! URL nie je definovaná.', + 'errAccess' : 'Prístup zamietnutý.', + 'errConnect' : 'Nepodarilo sa pripojiť do backendu.', + 'errAbort' : 'Spojenie bolo prerušené.', + 'errTimeout' : 'Časový limit vypršal.', + 'errNotFound' : 'Backend nenájdený.', + 'errResponse' : 'Nesprávna backend odpoveď.', + 'errConf' : 'Nesprávna backend konfigurácia.', + 'errJSON' : 'PHP JSON modul nie je nainštalovaný.', + 'errNoVolumes' : 'Nie sú dostupné žiadne čitateľné média.', + 'errCmdParams' : 'Nesprávne parametre pre príkaz "$1".', + 'errDataNotJSON' : 'Dáta nie sú formátu JSON.', + 'errDataEmpty' : 'Prázdne dáta.', + 'errCmdReq' : 'Backend požiadavka požaduje názov príkazu.', + 'errOpen' : 'Nie je možné otvoriť "$1".', + 'errNotFolder' : 'Objekt nie je priečinok.', + 'errNotFile' : 'Objekt nie je súbor.', + 'errRead' : 'Nie je možné prečítať "$1".', + 'errWrite' : 'Nie je možné písať do "$1".', + 'errPerm' : 'Prístup zamietnutý.', + 'errLocked' : '"$1" je uzamknutý a nemôže byť premenovaný, presunutý alebo odstránený.', + 'errExists' : 'Položka s názvom "$1" už existuje.', + 'errInvName' : 'Neplatný názov súboru.', + 'errInvDirname' : 'Neplatný názov priečinka.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Priečinok nebol nájdený.', + 'errFileNotFound' : 'Súbor nenájdený.', + 'errTrgFolderNotFound' : 'Cieľový priečinok "$1" sa nenašiel.', + 'errPopup' : 'Prehliadač zabránil otvoreniu vyskakovacieho okna. Pre otvorenie súboru povoľte vyskakovacie okná.', + 'errMkdir' : 'Nepodarilo sa vytvoriť priečinok "$1".', + 'errMkfile' : 'Nepodarilo sa vytvoriť súbor "$1".', + 'errRename' : 'Nepodarilo sa premenovať "$1".', + 'errCopyFrom' : 'Kopírovanie súborov z média "$1" nie je povolené.', + 'errCopyTo' : 'Kopírovanie súborov na médium "$1" nie je povolené.', + 'errMkOutLink' : 'Nie je možné vytvoriť odkaz mimo koreňového zväzku.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Chyba pri nahrávaní.', // old name - errUploadCommon + 'errUploadFile' : 'Nepodarilo sa nahrať "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Neboli nájdené žiadne súbory na nahranie.', + 'errUploadTotalSize' : 'Dáta prekračujú maximálnu povolenú veľkosť.', // old name - errMaxSize + 'errUploadFileSize' : 'Súbor prekračuje maximálnu povolenú veľkosť.', // old name - errFileMaxSize + 'errUploadMime' : 'Nepovolený typ súboru.', + 'errUploadTransfer' : 'Problém s nahrávaním "$1".', + 'errUploadTemp' : 'Nepodarilo sa vytvoriť dočasný súbor na nahranie.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Objekt "$1" na tomto mieste už existuje a nemôže byť nahradený objektom iného typu.', // new + 'errReplace' : 'Nie je možné nahradiť "$1".', + 'errSave' : 'Nie je možné uložiť "$1".', + 'errCopy' : 'Nie je možné kopírovať "$1".', + 'errMove' : 'Nie je možné preniesť "$1".', + 'errCopyInItself' : 'Nie je možné kopírovať "$1" do seba.', + 'errRm' : 'Nie je možné vymazať "$1".', + 'errTrash' : 'Nie je možné presunúť do koša.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Nie je možné odstrániť zdrojový/é súbor/y.', + 'errExtract' : 'Nie je možné extrahovať súbory z "$1".', + 'errArchive' : 'Nie je možné vytvoriť archív.', + 'errArcType' : 'Nepodporovaný typ archívu.', + 'errNoArchive' : 'Súbor nie je archív alebo má nepodporovaný typ archívu.', + 'errCmdNoSupport' : 'Backend nepodporuje tento príkaz.', + 'errReplByChild' : 'Priečinok "$1" nemôže byť nahradený položkou, ktorú už obsahuje.', + 'errArcSymlinks' : 'Z bezpečnostných dôvodov bolo zakázané extrahovanie archívov obsahujúcich symlinky, alebo súborov s nepovolenými názvami.', // edited 24.06.2012 + 'errArcMaxSize' : 'Súbory archívu prekračujú maximálnu povolenú veľkosť.', + 'errResize' : 'Nie je možné zmeniť veľkosť "$1".', + 'errResizeDegree' : 'Neplatný stupeň otočenia.', // added 7.3.2013 + 'errResizeRotate' : 'Nie je možné otočiť obrázok.', // added 7.3.2013 + 'errResizeSize' : 'Neplatná veľkosť obrázka.', // added 7.3.2013 + 'errResizeNoChange' : 'Veľkosť obrázku sa nezmenila.', // added 7.3.2013 + 'errUsupportType' : 'Nepodporovaný typ súboru.', + 'errNotUTF8Content' : 'Súbor "$1" nie je v UTF-8 a nemôže byť upravený.', // added 9.11.2011 + 'errNetMount' : 'Nie je možné pripojiť "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Nepodporovaný protokol.', // added 17.04.2012 + 'errNetMountFailed' : 'Pripájanie zlyhalo.', // added 17.04.2012 + 'errNetMountHostReq' : 'Hosť je požadovaný.', // added 18.04.2012 + 'errSessionExpires' : 'Vaša relácia vypršala kvôli nečinnosti.', + 'errCreatingTempDir' : 'Nepodarilo sa vytvoriť dočasný adresár: "$1"', + 'errFtpDownloadFile' : 'Nie je možné stiahnuť súbor z FTP: "$1"', + 'errFtpUploadFile' : 'Nie je možné nahrať súbor na FTP: "$1"', + 'errFtpMkdir' : 'Nedá sa vytvoriť vzdialený adresár na FTP: "$1"', + 'errArchiveExec' : 'Chyba pri archivácii súborov: "$1"', + 'errExtractExec' : 'Chyba pri extrahovaní súborov: "$1"', + 'errNetUnMount' : 'Nepodarilo sa odpojiť', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Nie je prevoditeľný na UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Vyskúšajte moderný prehliadač, ak chcete nahrať priečinok.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Vypršal časový limit pri hľadaní "$1". Výsledok vyhľadávania je čiastočný.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Opätovné povolenie je potrebné.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Maximálny počet voliteľných položiek je $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Nepodarilo sa obnoviť z koša. Cieľ obnovenia nie je možné identifikovať.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Editor tohto typu súboru nebol nájdený.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Vyskytla sa chyba na strane servera.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Nepodarilo sa vyprázdniť priečinok "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Existujú ešte ďalšie $1 chyby.', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'Môžete vytvoriť až $1 priečinkov naraz.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Vytvoriť archív', + 'cmdback' : 'Späť', + 'cmdcopy' : 'Kopírovať', + 'cmdcut' : 'Vystrihnúť', + 'cmddownload' : 'Stiahnuť', + 'cmdduplicate' : 'Duplikovať', + 'cmdedit' : 'Upraviť súbor', + 'cmdextract' : 'Extrahovať súbory z archívu', + 'cmdforward' : 'Ďalej', + 'cmdgetfile' : 'Vybrať súbory', + 'cmdhelp' : 'O tomto softvéri', + 'cmdhome' : 'Domov', + 'cmdinfo' : 'Info', + 'cmdmkdir' : 'Nový priečinok', + 'cmdmkdirin' : 'Do novej zložky', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Nový súbor', + 'cmdopen' : 'Otvoriť', + 'cmdpaste' : 'Vložiť', + 'cmdquicklook' : 'Náhľad', + 'cmdreload' : 'Obnoviť', + 'cmdrename' : 'Premenovať', + 'cmdrm' : 'Vymazať', + 'cmdtrash' : 'Do koša', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Obnoviť', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Nájsť súbory', + 'cmdup' : 'Prejsť do nadradeného priečinka', + 'cmdupload' : 'Nahrať súbory', + 'cmdview' : 'Pozrieť', + 'cmdresize' : 'Zmeniť veľkosť obrázku', + 'cmdsort' : 'Zoradiť', + 'cmdnetmount' : 'Pripojiť sieťové médium', // added 18.04.2012 + 'cmdnetunmount': 'Odpojiť', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Do umiestnení', // added 28.12.2014 + 'cmdchmod' : 'Zmeniť režim', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Otvoriť priečinok', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Resetovať šírku stĺpca', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Celá obrazovka', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Posúvať', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Vyprázdniť priečinok', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Krok späť', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Vykonať znova', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferencie', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Vybrať všetko', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Nič nevyberať', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Invertovať výber', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Otvoriť v novom okne', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Skryť (Predvoľba)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Zavrieť', + 'btnSave' : 'Uložiť', + 'btnRm' : 'Vymazať', + 'btnApply' : 'Použiť', + 'btnCancel' : 'Zrušiť', + 'btnNo' : 'Nie', + 'btnYes' : 'Áno', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Pripojiť', // added 18.04.2012 + 'btnApprove': 'Ísť na $1 & schváliť', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Odpojiť', // from v2.1 added 30.04.2012 + 'btnConv' : 'Previesť', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Tu', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Médium', // from v2.1 added 22.5.2015 + 'btnAll' : 'Všetko', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME typ', // from v2.1 added 22.5.2015 + 'btnFileName':'Názov súboru', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Uložiť & zavrieť', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Zálohovať', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Premenovať', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Premenovať všetko', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Predchádzajúce ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Ďalšie ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Uložiť ako', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Otváranie priečinka', + 'ntffile' : 'Otváranie súboru', + 'ntfreload' : 'Znovu-načítanie obsahu priečinka', + 'ntfmkdir' : 'Vytváranie priečinka', + 'ntfmkfile' : 'Vytváranie súborov', + 'ntfrm' : 'Vymazanie položiek', + 'ntfcopy' : 'Kopírovanie položiek', + 'ntfmove' : 'Premiestnenie položiek', + 'ntfprepare' : 'Kontrola existujúcich položiek', + 'ntfrename' : 'Premenovanie súborov', + 'ntfupload' : 'Nahrávanie súborov', + 'ntfdownload' : 'Sťahovanie súborov', + 'ntfsave' : 'Uloženie súborov', + 'ntfarchive' : 'Vytváranie archívu', + 'ntfextract' : 'Extrahovanie súborov z archívu', + 'ntfsearch' : 'Vyhľadávanie súborov', + 'ntfresize' : 'Zmena veľkosti obrázkov', + 'ntfsmth' : 'Počkajte prosím...', + 'ntfloadimg' : 'Načítavanie obrázka', + 'ntfnetmount' : 'Pripájanie sieťového média', // added 18.04.2012 + 'ntfnetunmount': 'Odpájanie sieťového média', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Získanie rozmeru obrázka', // added 20.05.2013 + 'ntfreaddir' : 'Čítajú sa informácie o priečinku', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Získanie adresy URL odkazu', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Zmena súboru', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Overenie názvu nahravaného súboru', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Vytvorenie súboru na stiahnutie', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Získanie informácií o ceste', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Spracovanie nahraného súboru', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Vhadzovanie do koša', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Vykonávanie obnovy z koša', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Kontrola cieľového priečinka', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Zrušiť predchádzajúcu operáciu', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Obnovenie predchádzajúceho zrušenia', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Kontrola obsahu', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Kôš', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'neznámy', + 'Today' : 'Dnes', + 'Yesterday' : 'Včera', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Maj', + 'msJun' : 'Jun', + 'msJul' : 'Júl', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Január', + 'February' : 'Február', + 'March' : 'Marec', + 'April' : 'Apríl', + 'May' : 'Máj', + 'June' : 'Jún', + 'July' : 'Júl', + 'August' : 'August', + 'September' : 'September', + 'October' : 'Október', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Nedeľa', + 'Monday' : 'Pondelok', + 'Tuesday' : 'Utorok', + 'Wednesday' : 'Streda', + 'Thursday' : 'Štvrtok', + 'Friday' : 'Piatok', + 'Saturday' : 'Sobota', + 'Sun' : 'Ned', + 'Mon' : 'Pon', + 'Tue' : 'Ut', + 'Wed' : 'Str', + 'Thu' : 'Štv', + 'Fri' : 'Pia', + 'Sat' : 'Sob', + + /******************************** sort variants ********************************/ + 'sortname' : 'podľa názvu', + 'sortkind' : 'podľa druhu', + 'sortsize' : 'podľa veľkosti', + 'sortdate' : 'podľa dátumu', + 'sortFoldersFirst' : 'Najskôr priečinky', + 'sortperm' : 'podľa povolenia', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'podľa módu', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'podľa majiteľa', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'podľa skupiny', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Tiež stromové zobrazenie', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'Nový súbor.txt', // added 10.11.2015 + 'untitled folder' : 'Nový priečinok', // added 10.11.2015 + 'Archive' : 'Nový archív', // from v2.1 added 10.11.2015 + 'untitled file' : 'Nový súbor.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1 súbor', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Potrebné potvrdenie', + 'confirmRm' : 'Určite chcete vymazať súbory?
                      Nie je to možné vrátiť späť!', + 'confirmRepl' : 'Nahradiť starý súbor za nový? (Ak obsahuje priečinky, bude zlúčené. Ak chcete zálohovať a nahradiť, vyberte možnosť Zálohovať.)', + 'confirmRest' : 'Nahradiť existujúcu položku s položkou v koši?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Nie je v UTF-8
                      Previesť na UTF-8?
                      Obsah bude v UTF-8 po uložení konverzie.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Kódovanie tohto súboru nemohlo byť detekované. Pre úpravu dočasne potrebujete previesť na UTF-8 .
                      Prosím, vyberte kódovanie znakov tohto súboru.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Bol upravený.
                      Ak zmeny neuložíte, stratíte vykonanú prácu.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Naozaj chcete presunúť položky do koša?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Naozaj chcete presunúť položky do "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Použiť na všetky', + 'name' : 'Názov', + 'size' : 'Veľkosť', + 'perms' : 'Povolenia', + 'modify' : 'Zmenené', + 'kind' : 'Druh', + 'read' : 'čítať', + 'write' : 'zapisovať', + 'noaccess' : 'bez prístupu', + 'and' : 'a', + 'unknown' : 'neznámy', + 'selectall' : 'Vybrať všetky položky', + 'selectfiles' : 'Vybrať položku(y)', + 'selectffile' : 'Vybrať prvú položku', + 'selectlfile' : 'Vybrať poslednú položku', + 'viewlist' : 'Zoznam', + 'viewicons' : 'Ikony', + 'viewSmall' : 'Malé ikony', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Stredné ikony', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Veľké ikony', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Extra veľké ikony', // from v2.1.39 added 22.5.2018 + 'places' : 'Miesta', + 'calc' : 'Prepočítavanie', + 'path' : 'Cesta', + 'aliasfor' : 'Alias pre', + 'locked' : 'Uzamknuté', + 'dim' : 'Rozmery', + 'files' : 'Súbory', + 'folders' : 'Priečinky', + 'items' : 'Položky', + 'yes' : 'áno', + 'no' : 'nie', + 'link' : 'Odkaz', + 'searcresult' : 'Výsledky hľadania', + 'selected' : 'zvolené položky', + 'about' : 'O aplikácii', + 'shortcuts' : 'Skratky', + 'help' : 'Pomoc', + 'webfm' : 'Webový správca súborov', + 'ver' : 'Verzia', + 'protocolver' : 'verzia protokolu', + 'homepage' : 'Domovská stránka', + 'docs' : 'Dokumentácia', + 'github' : 'Pozri nás na Githube', + 'twitter' : 'Nasleduj nás na Twitteri', + 'facebook' : 'Pripoj sa k nám na Facebooku', + 'team' : 'Tím', + 'chiefdev' : 'Hlavný vývojár', + 'developer' : 'Vývojár', + 'contributor' : 'Prispievateľ', + 'maintainer' : 'Správca', + 'translator' : 'Prekladateľ', + 'icons' : 'Ikony', + 'dontforget' : 'a nezabudnite si plavky', + 'shortcutsof' : 'Skratky nie sú povolené', + 'dropFiles' : 'Sem pretiahnite súbory', + 'or' : 'alebo', + 'selectForUpload' : 'Vyberte súbory', + 'moveFiles' : 'Premiestniť súbory', + 'copyFiles' : 'Kopírovať súbory', + 'restoreFiles' : 'Obnoviť položky', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Odstrániť z umiestnení', + 'aspectRatio' : 'Pomer zobrazenia', + 'scale' : 'Mierka', + 'width' : 'Šírka', + 'height' : 'Výška', + 'resize' : 'Zmeniť veľkosť', + 'crop' : 'Orezať', + 'rotate' : 'Otočiť', + 'rotate-cw' : 'Otočiť o 90 stupňov (v smere h.r.)', + 'rotate-ccw' : 'Otočiť o 90 stupňov (proti smeru)', + 'degree' : '°', + 'netMountDialogTitle' : 'Pripojiť sieťové médium', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Hosť', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'Užívateľ', // added 18.04.2012 + 'pass' : 'Heslo', // added 18.04.2012 + 'confirmUnmount' : 'Naozaj chcete odpojiť $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Premiestnite alebo presuňte súbory z prehliadača', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Tu premiestnite alebo presuňte súbory a adresy URL', // from v2.1 added 07.04.2014 + 'encoding' : 'Kódovanie', // from v2.1 added 19.12.2014 + 'locale' : 'Lokalizácia', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Cieľ: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Vyhľadávanie podľa vstupného MIME typu', // from v2.1 added 22.5.2015 + 'owner' : 'Majiteľ', // from v2.1 added 20.6.2015 + 'group' : 'Skupina', // from v2.1 added 20.6.2015 + 'other' : 'Ostatné', // from v2.1 added 20.6.2015 + 'execute' : 'Spustiť', // from v2.1 added 20.6.2015 + 'perm' : 'Povolenie', // from v2.1 added 20.6.2015 + 'mode' : 'Režim', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Priečinok je prázdny', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Priečinok je prázdny\\A Premiestnite alebo presuňte položky', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Priečinok je prázdny\\A Dlhým kliknutím pridáte položky', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kvalita', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Automatická synchronizácia', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Posunúť nahor', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Získať URL odkaz', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Vybraté položky ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID priečinka', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Povoliť prístup v offline režime', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Znova overiť', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Práve načítava...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Otvorenie viacerých súborov', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Pokúšate sa otvoriť súbor $1. Naozaj ho chcete otvoriť v prehliadači?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Výsledky vyhľadávania sú prázdne v hľadanom cieli.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Je to úprava súboru.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Vybrali ste $1 položky.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Máte $1 položky v schránke.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Prírastkové hľadanie je iba z aktuálneho zobrazenia.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Obnovovanie', // from v2.1.15 added 3.8.2016 + 'complete' : '$1: kompletné', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Kontextové menu', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Otáčanie stránky', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Korene média', // from v2.1.16 added 16.9.2016 + 'reset' : 'Resetovať', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Farba pozadia', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Výber farby', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px mriežka', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Povolené', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Zakázané', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Výsledky vyhľadávania sú prázdne v aktuálnom zobrazení. Stlačením tlačidla [Enter] rozšírite vyhľadávanie cieľa.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Výsledky vyhľadávania prvého listu sú v aktuálnom zobrazení prázdne.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Nápis textu', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 minút ostáva', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Otvoriť s vybratým kódovaním', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Uložiť s vybratým kódovaním', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Vyberte priečinok', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Hľadanie prvého listu', // from v2.1.23 added 24.3.2017 + 'presets' : 'Presety', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Je to príliš veľa položiek, takže sa nemôže dostať do koša.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Textarea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Vyprázdniť priečinok "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'V priečinku "$1" nie sú žiadne položky.', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preferencie', // from v2.1.26 added 28.6.2017 + 'language' : 'Nastavenie jazyka', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Inicializujte nastavenia uložené v tomto prehliadači', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Nastavenie panela s nástrojmi', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '...$1 znakov ostáva.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '...$1 riadkov ostáva.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Súčet', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Hrubá veľkosť súboru', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Zameranie na prvok dialógu s mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Vybrať', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Akcia pri vybranom súbore', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Otvoriť pomocou naposledy použitého editora', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Invertovať výber položiek', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Naozaj chcete premenovať $1 vybraných položiek, ako napríklad $2
                      Nie je to možné vrátiť späť!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch premenovanie', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Číslo', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Pridať predponu', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Pridať príponu', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Zmeniť príponu', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Nastavenia stĺpcov (zoznamové zobrazenie)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Všetky zmeny sa okamžite premietnu do archívu.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Akékoľvek zmeny sa neodzrkadľujú, kým sa toto médium neodinštaluje.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Nasledujúce médium(a) pripojené v tomto médiu je tiež odpojené. Určite ho odpojiť?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Informácie o výbere', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algoritmy na zobrazenie hashu súborov', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Informačné položky (panel s informáciami o výbere)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Opätovným stlačením opustíte.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Panel nástrojov', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Pracovný priestor', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialóg', // from v2.1.38 added 4.4.2018 + 'all' : 'Všetko', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Veľkosť ikony (zobrazenie ikon)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Otvorte maximalizované okno editora', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Pretože konverzia podľa rozhrania API momentálne nie je k dispozícii, skonvertujte na webovej stránke.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Po konverzii musíte nahrať skonvertovaný súbor pomocou URL položky alebo stiahnutý súbor na uloženie skonvertovaného súboru.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Konvertovať na stránke $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrácie', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Tento elFinder má integrované nasledujúce externé služby. Pred použitím skontrolujte podmienky používania, zásady ochrany osobných údajov atď.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Zobraziť skryté položky', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Skryť skryté položky', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Zobraziť/skryť skryté položky', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Typy súborov, ktoré sa majú povoliť pomocou "Nový súbor"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Typ textového súboru', // from v2.1.41 added 7.8.2018 + 'add' : 'Pridať', // from v2.1.41 added 7.8.2018 + 'theme' : 'Téma', // from v2.1.43 added 19.10.2018 + 'default' : 'Predvolená', // from v2.1.43 added 19.10.2018 + 'description' : 'Popis', // from v2.1.43 added 19.10.2018 + 'website' : 'Stránka', // from v2.1.43 added 19.10.2018 + 'author' : 'Autor', // from v2.1.43 added 19.10.2018 + 'email' : 'E-mail', // from v2.1.43 added 19.10.2018 + 'license' : 'Licencia', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Túto položku nemožno uložiť. Ak chcete zabrániť strate úprav, musíte ju exportovať do počítača.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Dvakrát kliknite na súbor a vyberte ho.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Použiť režim celej obrazovky', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Neznámy', + 'kindRoot' : 'Koreň média', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Priečinok', + 'kindSelects' : 'Výbery', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Porušený alias', + // applications + 'kindApp' : 'Aplikácia', + 'kindPostscript' : 'Postscript dokument', + 'kindMsOffice' : 'Microsoft Office dokument', + 'kindMsWord' : 'Microsoft Word dokument', + 'kindMsExcel' : 'Microsoft Excel dokument', + 'kindMsPP' : 'Microsoft Powerpoint prezentácia', + 'kindOO' : 'Open Office dokument', + 'kindAppFlash' : 'Flashová aplikácia', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent súbor', + 'kind7z' : '7z archív', + 'kindTAR' : 'TAR archív', + 'kindGZIP' : 'GZIP archív', + 'kindBZIP' : 'BZIP archív', + 'kindXZ' : 'XZ archív', + 'kindZIP' : 'ZIP archív', + 'kindRAR' : 'RAR archív', + 'kindJAR' : 'Java JAR súbor', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM balík', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Textový document', + 'kindTextPlain' : 'Obyčajný text', + 'kindPHP' : 'PHP zdrojový kód', + 'kindCSS' : 'Cascading style sheet (CSS)', + 'kindHTML' : 'HTML dokument', + 'kindJS' : 'Javascript zdrojový kód', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C zdrojový kód', + 'kindCHeader' : 'C header zdrojový kód', + 'kindCPP' : 'C++ zdrojový kód', + 'kindCPPHeader' : 'C++ header zdrojový kód', + 'kindShell' : 'Unix shell skript', + 'kindPython' : 'Python zdrojový kód', + 'kindJava' : 'Java zdrojový kód', + 'kindRuby' : 'Ruby zdrojový kód', + 'kindPerl' : 'Perl zdrojový kód', + 'kindSQL' : 'SQL zdrojový kód', + 'kindXML' : 'XML dokument', + 'kindAWK' : 'AWK zdrojový kód', + 'kindCSV' : 'Čiarkou oddeľované hodnoty', + 'kindDOCBOOK' : 'Docbook XML dokument', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Obrázok', + 'kindBMP' : 'BMP obrázok', + 'kindJPEG' : 'JPEG obrázok', + 'kindGIF' : 'GIF obrázok', + 'kindPNG' : 'PNG obrázok', + 'kindTIFF' : 'TIFF obrázok', + 'kindTGA' : 'TGA obrázok', + 'kindPSD' : 'Adobe Photoshop obrázok', + 'kindXBITMAP' : 'X bitmap obrázok', + 'kindPXM' : 'Pixelmator obrázok', + // media + 'kindAudio' : 'Zvukový súbor', + 'kindAudioMPEG' : 'MPEG zvuk', + 'kindAudioMPEG4' : 'MPEG-4 zvuk', + 'kindAudioMIDI' : 'MIDI zvuk', + 'kindAudioOGG' : 'Ogg Vorbis zvuk', + 'kindAudioWAV' : 'WAV zvuk', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video súbor', + 'kindVideoDV' : 'DV video', + 'kindVideoMPEG' : 'MPEG video', + 'kindVideoMPEG4' : 'MPEG-4 video', + 'kindVideoAVI' : 'AVI video', + 'kindVideoMOV' : 'Quick Time video', + 'kindVideoWM' : 'Windows Media video', + 'kindVideoFlash' : 'Flash video', + 'kindVideoMKV' : 'Matroska video', + 'kindVideoOGG' : 'Ogg video' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.sl.js b/lib/redactor/elfinder/js/i18n/elfinder.sl.js new file mode 100644 index 0000000..3f3c24e --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.sl.js @@ -0,0 +1,381 @@ +/** + * Slovenian translation + * @author Damjan Rems + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.sl = { + translator : 'Damjan Rems <d_rems at yahoo.com>', + language : 'Slovenščina', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', + fancyDateFormat : '$1 H:i', + messages : { + + /********************************** errors **********************************/ + 'error' : 'Napaka', + 'errUnknown' : 'Neznana napaka.', + 'errUnknownCmd' : 'Neznan ukaz.', + 'errJqui' : 'Napačna jQuery UI nastavitev. Selectable, draggable in droppable dodatki morajo biti vključeni.', + 'errNode' : 'elFinder potrebuje "DOM Element".', + 'errURL' : 'Napačna nastavitev elFinder-ja! Manjka URL nastavitev.', + 'errAccess' : 'Dostop zavrnjen.', + 'errConnect' : 'Ne morem se priključiti na "backend".', + 'errAbort' : 'Povezava prekinjena (aborted).', + 'errTimeout' : 'Povezava potekla (timeout).', + 'errNotFound' : 'Nisem našel "backend-a".', + 'errResponse' : 'Napačni "backend" odgovor.', + 'errConf' : 'Napačna "backend" nastavitev.', + 'errJSON' : 'JSON modul ni instaliran.', + 'errNoVolumes' : 'Readable volumes not available.', + 'errCmdParams' : 'Napačni parametri za ukaz "$1".', + 'errDataNotJSON' : 'Podatki niso v JSON obliki.', + 'errDataEmpty' : 'Ni podatkov oz. so prazni.', + 'errCmdReq' : '"Backend" zahtevek potrebuje ime ukaza.', + 'errOpen' : '"$1" ni možno odpreti.', + 'errNotFolder' : 'Objekt ni mapa.', + 'errNotFile' : 'Objekt ni datoteka.', + 'errRead' : '"$1" ni možno brati.', + 'errWrite' : 'Ne morem pisati v "$1".', + 'errPerm' : 'Dostop zavrnjen.', + 'errLocked' : '"$1" je zaklenjen(a) in je ni možno preimenovati, premakniti ali izbrisati.', + 'errExists' : 'Datoteka z imenom "$1" že obstaja.', + 'errInvName' : 'Napačno ime datoteke.', + 'errFolderNotFound' : 'Mape nisem našel.', + 'errFileNotFound' : 'Datoteke nisem našel.', + 'errTrgFolderNotFound' : 'Ciljna mapa "$1" ne obstaja.', + 'errPopup' : 'Brskalnik je preprečil prikaz (popup) okna. Za vpogled datoteke omogočite nastavitev v vašem brskalniku.', + 'errMkdir' : 'Ni možno dodati mape "$1".', + 'errMkfile' : 'Ni možno dodati datoteke "$1".', + 'errRename' : 'Ni možno preimenovati "$1".', + 'errCopyFrom' : 'Kopiranje datotek iz "$1" ni dovoljeno.', + 'errCopyTo' : 'Kopiranje datotek na "$1" ni dovoljeno.', + 'errUpload' : 'Napaka pri prenosu.', + 'errUploadFile' : '"$1" ni možno naložiti (upload).', + 'errUploadNoFiles' : 'Ni datotek za nalaganje (upload).', + 'errUploadTotalSize' : 'Podatki presegajo največjo dovoljeno velikost.', + 'errUploadFileSize' : 'Datoteka presega največjo dovoljeno velikost.', + 'errUploadMime' : 'Datoteke s to končnico niso dovoljene.', + 'errUploadTransfer' : '"$1" napaka pri prenosu.', + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : '"$1" ni možno shraniti.', + 'errCopy' : '"$1" ni možno kopirati.', + 'errMove' : '"$1" ni možno premakniti.', + 'errCopyInItself' : '"$1" ni možno kopirati samo vase.', + 'errRm' : '"$1" ni možno izbrisati.', + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'Datotek iz "$1" ni možno odpakirati.', + 'errArchive' : 'Napaka pri delanju arhiva.', + 'errArcType' : 'Nepodprta vrsta arhiva.', + 'errNoArchive' : 'Datoteka ni arhiv ali vrsta arhiva ni podprta.', + 'errCmdNoSupport' : '"Backend" ne podpira tega ukaza.', + 'errReplByChild' : 'Mape “$1” ni možno zamenjati z vsebino mape.', + 'errArcSymlinks' : 'Zaradi varnostnih razlogov arhiva ki vsebuje "symlinks" ni možno odpakirati.', + 'errArcMaxSize' : 'Datoteke v arhivu presegajo največjo dovoljeno velikost.', + 'errResize' : '"$1" ni možno razširiti.', + 'errResizeDegree' : 'Invalid rotate degree.', + 'errResizeRotate' : 'Unable to rotate image.', + 'errResizeSize' : 'Invalid image size.', + 'errResizeNoChange' : 'Image size not changed.', + 'errUsupportType' : 'Nepodprta vrsta datoteke.', + 'errNotUTF8Content' : 'File "$1" is not in UTF-8 and cannot be edited.', // added 9.11.2011 + 'errNetMount' : 'Unable to mount "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Unsupported protocol.', // added 17.04.2012 + 'errNetMountFailed' : 'Mount failed.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host required.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Naredi arhiv', + 'cmdback' : 'Nazaj', + 'cmdcopy' : 'Kopiraj', + 'cmdcut' : 'Izreži', + 'cmddownload' : 'Poberi (download)', + 'cmdduplicate' : 'Podvoji', + 'cmdedit' : 'Uredi datoteko', + 'cmdextract' : 'Odpakiraj datoteke iz arhiva', + 'cmdforward' : 'Naprej', + 'cmdgetfile' : 'Izberi datoteke', + 'cmdhelp' : 'Več o', + 'cmdhome' : 'Domov', + 'cmdinfo' : 'Lastnosti', + 'cmdmkdir' : 'Nova mapa', + 'cmdmkfile' : 'Nova datoteka', + 'cmdopen' : 'Odpri', + 'cmdpaste' : 'Prilepi', + 'cmdquicklook' : 'Hitri ogled', + 'cmdreload' : 'Osveži', + 'cmdrename' : 'Preimenuj', + 'cmdrm' : 'Izbriši', + 'cmdsearch' : 'Poišči datoteke', + 'cmdup' : 'Mapa nazaj', + 'cmdupload' : 'Naloži (upload)', + 'cmdview' : 'Ogled', + 'cmdresize' : 'Povečaj (pomanjšaj) sliko', + 'cmdsort' : 'Razvrsti', + 'cmdnetmount' : 'Mount network volume', + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Zapri', + 'btnSave' : 'Shrani', + 'btnRm' : 'Izbriši', + 'btnApply' : 'Uporabi', + 'btnCancel' : 'Prekliči', + 'btnNo' : 'Ne', + 'btnYes' : 'Da', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', + + /******************************** notifications ********************************/ + 'ntfopen' : 'Odpri mapo', + 'ntffile' : 'Odpri datoteko', + 'ntfreload' : 'Osveži vsebino mape', + 'ntfmkdir' : 'Ustvarjam mapo', + 'ntfmkfile' : 'Ustvarjam datoteke', + 'ntfrm' : 'Brišem datoteke', + 'ntfcopy' : 'Kopiram datoteke', + 'ntfmove' : 'Premikam datoteke', + 'ntfprepare' : 'Pripravljam se na kopiranje datotek', + 'ntfrename' : 'Preimenujem datoteke', + 'ntfupload' : 'Nalagam (upload) datoteke', + 'ntfdownload' : 'Pobiram (download) datoteke', + 'ntfsave' : 'Shranjujem datoteke', + 'ntfarchive' : 'Ustvarjam arhiv', + 'ntfextract' : 'Razpakiram datoteke iz arhiva', + 'ntfsearch' : 'Iščem datoteke', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Počakaj delam >_<', + 'ntfloadimg' : 'Nalagam sliko', + 'ntfnetmount' : 'Mounting network volume', // added 18.04.2012 + 'ntfdim' : 'Acquiring image dimension', // added 20.05.2013 + + /************************************ dates **********************************/ + 'dateUnknown' : 'neznan', + 'Today' : 'Danes', + 'Yesterday' : 'Včeraj', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Maj', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Avg', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Januar', + 'February' : 'Februar', + 'March' : 'Marec', + 'April' : 'April', + 'May' : 'Maj', + 'June' : 'Junij', + 'July' : 'Julij', + 'August' : 'Avgust', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Nedelja', + 'Monday' : 'Ponedeljek', + 'Tuesday' : 'Torek', + 'Wednesday' : 'Sreda', + 'Thursday' : 'Četrtek', + 'Friday' : 'Petek', + 'Saturday' : 'Sobota', + 'Sun' : 'Ned', + 'Mon' : 'Pon', + 'Tue' : 'Tor', + 'Wed' : 'Sre', + 'Thu' : 'Čet', + 'Fri' : 'Pet', + 'Sat' : 'Sob', + + /******************************** sort variants ********************************/ + 'sortname' : 'po imenu', + 'sortkind' : 'po vrsti', + 'sortsize' : 'po velikosti', + 'sortdate' : 'po datumu', + 'sortFoldersFirst' : 'Folders first', + + /********************************** messages **********************************/ + 'confirmReq' : 'Zahtevana je potrditev', + 'confirmRm' : 'Ste prepričani, da želite izbrisati datoteko?
                      POZOR! Tega ukaza ni možno preklicati!', + 'confirmRepl' : 'Zamenjam staro datoteko z novo?', + 'apllyAll' : 'Uporabi pri vseh', + 'name' : 'Ime', + 'size' : 'Velikost', + 'perms' : 'Dovoljenja', + 'modify' : 'Spremenjeno', + 'kind' : 'Vrsta', + 'read' : 'beri', + 'write' : 'piši', + 'noaccess' : 'ni dostopa', + 'and' : 'in', + 'unknown' : 'neznan', + 'selectall' : 'Izberi vse datoteke', + 'selectfiles' : 'Izberi datotek(o)e', + 'selectffile' : 'Izberi prvo datoteko', + 'selectlfile' : 'Izberi zadnjo datoteko', + 'viewlist' : 'Seznam', + 'viewicons' : 'Ikone', + 'places' : 'Mesta (places)', + 'calc' : 'Izračun', + 'path' : 'Pot do', + 'aliasfor' : 'Sopomenka (alias) za', + 'locked' : 'Zaklenjeno', + 'dim' : 'Dimenzije', + 'files' : 'Datoteke', + 'folders' : 'Mape', + 'items' : 'Predmeti', + 'yes' : 'da', + 'no' : 'ne', + 'link' : 'Povezava', + 'searcresult' : 'Rezultati iskanja', + 'selected' : 'izbrani predmeti', + 'about' : 'Več o', + 'shortcuts' : 'Bližnjice', + 'help' : 'Pomoč', + 'webfm' : 'Spletni upravitelj datotek', + 'ver' : 'Verzija', + 'protocolver' : 'verzija protokola', + 'homepage' : 'Domača stran', + 'docs' : 'Dokumentacija', + 'github' : 'Fork us on Github', + 'twitter' : 'Sledi na twitterju', + 'facebook' : 'Pridruži se nam na facebook-u', + 'team' : 'Tim', + 'chiefdev' : 'Glavni razvijalec', + 'developer' : 'razvijalec', + 'contributor' : 'contributor', + 'maintainer' : 'vzdrževalec', + 'translator' : 'prevajalec', + 'icons' : 'Ikone', + 'dontforget' : 'In ne pozabi na brisačo', + 'shortcutsof' : 'Bližnjica onemogočena', + 'dropFiles' : 'Datoteke spusti tukaj', + 'or' : 'ali', + 'selectForUpload' : 'Izberi datoteke za nalaganje', + 'moveFiles' : 'Premakni datoteke', + 'copyFiles' : 'Kopiraj datoteke', + 'rmFromPlaces' : 'Izbriši iz mesta (places)', + 'aspectRatio' : 'Razmerje slike', + 'scale' : 'Razširi', + 'width' : 'Širina', + 'height' : 'Višina', + 'resize' : 'Povečaj', + 'crop' : 'Obreži', + 'rotate' : 'Zavrti', + 'rotate-cw' : 'Zavrti 90 st. v smeri ure', + 'rotate-ccw' : 'Zavrti 90 st. v obratni smeri ure', + 'degree' : 'Stopnja', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'User', // added 18.04.2012 + 'pass' : 'Password', // added 18.04.2012 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Neznan', + 'kindFolder' : 'Mapa', + 'kindAlias' : 'Sopomenka (alias)', + 'kindAliasBroken' : 'Nedelujoča sopomenka (alias)', + // applications + 'kindApp' : 'Program', + 'kindPostscript' : 'Postscript dokument', + 'kindMsOffice' : 'Microsoft Office dokument', + 'kindMsWord' : 'Microsoft Word dokument', + 'kindMsExcel' : 'Microsoft Excel dokument', + 'kindMsPP' : 'Microsoft Powerpoint predstavitev', + 'kindOO' : 'Open Office dokument', + 'kindAppFlash' : 'Flash program', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent datoteka', + 'kind7z' : '7z arhiv', + 'kindTAR' : 'TAR arhiv', + 'kindGZIP' : 'GZIP arhiv', + 'kindBZIP' : 'BZIP arhiv', + 'kindXZ' : 'XZ arhiv', + 'kindZIP' : 'ZIP arhiv', + 'kindRAR' : 'RAR arhiv', + 'kindJAR' : 'Java JAR datoteka', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM paket', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Tekst dokument', + 'kindTextPlain' : 'Samo tekst', + 'kindPHP' : 'PHP koda', + 'kindCSS' : 'Cascading style sheet (CSS)', + 'kindHTML' : 'HTML dokument', + 'kindJS' : 'Javascript koda', + 'kindRTF' : 'Rich Text Format (RTF)', + 'kindC' : 'C koda', + 'kindCHeader' : 'C header koda', + 'kindCPP' : 'C++ koda', + 'kindCPPHeader' : 'C++ header koda', + 'kindShell' : 'Unix shell skripta', + 'kindPython' : 'Python kdoa', + 'kindJava' : 'Java koda', + 'kindRuby' : 'Ruby koda', + 'kindPerl' : 'Perl skripta', + 'kindSQL' : 'SQL koda', + 'kindXML' : 'XML dokument', + 'kindAWK' : 'AWK koda', + 'kindCSV' : 'Besedilo ločeno z vejico (CSV)', + 'kindDOCBOOK' : 'Docbook XML dokument', + // images + 'kindImage' : 'Slika', + 'kindBMP' : 'BMP slika', + 'kindJPEG' : 'JPEG slika', + 'kindGIF' : 'GIF slika', + 'kindPNG' : 'PNG slika', + 'kindTIFF' : 'TIFF slika', + 'kindTGA' : 'TGA slika', + 'kindPSD' : 'Adobe Photoshop slika', + 'kindXBITMAP' : 'X bitmap slika', + 'kindPXM' : 'Pixelmator slika', + // media + 'kindAudio' : 'Avdio medija', + 'kindAudioMPEG' : 'MPEG zvok', + 'kindAudioMPEG4' : 'MPEG-4 zvok', + 'kindAudioMIDI' : 'MIDI zvok', + 'kindAudioOGG' : 'Ogg Vorbis zvok', + 'kindAudioWAV' : 'WAV zvok', + 'AudioPlaylist' : 'MP3 seznam', + 'kindVideo' : 'Video medija', + 'kindVideoDV' : 'DV film', + 'kindVideoMPEG' : 'MPEG film', + 'kindVideoMPEG4' : 'MPEG-4 film', + 'kindVideoAVI' : 'AVI film', + 'kindVideoMOV' : 'Quick Time film', + 'kindVideoWM' : 'Windows Media film', + 'kindVideoFlash' : 'Flash film', + 'kindVideoMKV' : 'Matroska film', + 'kindVideoOGG' : 'Ogg film' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.sr.js b/lib/redactor/elfinder/js/i18n/elfinder.sr.js new file mode 100644 index 0000000..a880d6e --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.sr.js @@ -0,0 +1,381 @@ + /** + * Serbian translation + * @author Momčilo m0k1 Mićanović + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.sr = { + translator : 'Momčilo m0k1 Mićanović <moki.forum@gmail.com>', + language : 'Srpski', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', + fancyDateFormat : '$1 H:i', + messages : { + + /********************************** errors **********************************/ + 'error' : 'Greška', + 'errUnknown' : 'Nepoznata greška.', + 'errUnknownCmd' : 'Nepoznata komanda.', + 'errJqui' : 'Neispravna konfiguracija jQuery UI. Komponente koje mogu da se odabiru, povlače, izbacuju moraju biti uključene.', + 'errNode' : 'elFinder zahteva DOM Element da bude kreiran.', + 'errURL' : 'Neispravna elFinder konfiguracija! URL opcija nije postavljena.', + 'errAccess' : 'Pristup odbijen.', + 'errConnect' : 'Nije moguće povezivanje s skriptom.', + 'errAbort' : 'Veza prekinuta.', + 'errTimeout' : 'Veza odbačena.', + 'errNotFound' : 'Skripta nije pronađena.', + 'errResponse' : 'Neispravan odgovor skripte.', + 'errConf' : 'Neispravna konfiguracija skripte.', + 'errJSON' : 'PHP JSON modul nije instaliran.', + 'errNoVolumes' : 'Vidljivi volumeni nisu dostupni.', + 'errCmdParams' : 'Nevažeći parametri za komandu "$1".', + 'errDataNotJSON' : 'Podaci nisu JSON.', + 'errDataEmpty' : 'Podaci nisu prazni.', + 'errCmdReq' : 'Skripta zahteva komandu.', + 'errOpen' : 'Nemoguće otvoriti "$1".', + 'errNotFolder' : 'Objekat nije folder.', + 'errNotFile' : 'Objekat nije datoteka.', + 'errRead' : 'Nemoguće pročitati "$1".', + 'errWrite' : 'Nemoguće pisati u "$1".', + 'errPerm' : 'Dozvola je odbijena.', + 'errLocked' : '"$1" je zaključan i nemože biti preimenovan, premešten ili obrisan.', + 'errExists' : 'Datoteka zvana "$1" već postoji.', + 'errInvName' : 'Neispravno ime datoteke.', + 'errFolderNotFound' : 'Folder nije pronađen.', + 'errFileNotFound' : 'Datoteka nije pronađena.', + 'errTrgFolderNotFound' : 'Izabrani folder "$1" nije pronađen.', + 'errPopup' : 'Pretraživač sprečava otvaranje iskačućih prozora. Da otvorite datoteku uključite iskačuće prozore u opcijama pretraživača.', + 'errMkdir' : 'Nemoguće kreirati folder "$1".', + 'errMkfile' : 'Nemoguće kreirati datoteku "$1".', + 'errRename' : 'Nemoguće preimenovati datoteku "$1".', + 'errCopyFrom' : 'Kopiranje datoteki sa "$1" nije dozvoljeno.', + 'errCopyTo' : 'Kopiranje datoteki na "$1" nije dozvoljeno.', + 'errUpload' : 'Greska pri slanju.', + 'errUploadFile' : 'Nemoguće poslati "$1".', + 'errUploadNoFiles' : 'Nisu pronađene datoteke za slanje.', + 'errUploadTotalSize' : 'Podaci premašuju najveću dopuštenu veličinu.', + 'errUploadFileSize' : 'Datoteka premašuje najveću dopuštenu veličinu.', + 'errUploadMime' : 'Vrsta datoteke nije dopuštena.', + 'errUploadTransfer' : '"$1" greška prilikom slanja.', + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : 'Nemožeš sačuvati "$1".', + 'errCopy' : 'Nemožeš kopirati "$1".', + 'errMove' : 'Nemožeš premestiti "$1".', + 'errCopyInItself' : 'Nemožeš kopirati "$1" na istu lokaciju.', + 'errRm' : 'Nemožeš obrisati "$1".', + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'Nemoguće izvaditi datoteke iz "$1".', + 'errArchive' : 'Nemoguće kreirati arhivu.', + 'errArcType' : 'Nepodržani tip arhive.', + 'errNoArchive' : 'Datoteka nije arhiva ili je nepodržani tip arhive.', + 'errCmdNoSupport' : 'Skripta nepodržava ovu komandu.', + 'errReplByChild' : 'Folder “$1” ne može biti zamenut stavkom koju sadrži.', + 'errArcSymlinks' : 'Zbog bezbednosnih razloga ne možete raspakovati arhive koje sadrže simboličke veze ili datoteke sa nedozvoljenim imenima.', + 'errArcMaxSize' : 'Arhiva je dostigla maksimalnu veličinu.', + 'errResize' : 'Nemoguće promeniti veličinu "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', + 'errResizeRotate' : 'Unable to rotate image.', + 'errResizeSize' : 'Invalid image size.', + 'errResizeNoChange' : 'Image size not changed.', + 'errUsupportType' : 'nepodržan tip datoteke.', + 'errNotUTF8Content' : 'Datoteka "$1" nije u UTF-8 formati i ne može biti izmenjena.', + 'errNetMount' : 'Nije moguće montirati "$1".', + 'errNetMountNoDriver' : 'Nepodržani protokol.', + 'errNetMountFailed' : 'Montiranje neuspelo.', + 'errNetMountHostReq' : 'Host je potreban.', + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Kreiraj arhivu', + 'cmdback' : 'Nazad', + 'cmdcopy' : 'Kopiraj', + 'cmdcut' : 'Iseci', + 'cmddownload' : 'Preuzmi', + 'cmdduplicate' : 'Dupliraj', + 'cmdedit' : 'Izmeni datoteku', + 'cmdextract' : 'Raspakuj arhivu', + 'cmdforward' : 'Napred', + 'cmdgetfile' : 'Izaberi datoteke', + 'cmdhelp' : 'O ovom softveru', + 'cmdhome' : 'Početna', + 'cmdinfo' : 'Proveri informacije', + 'cmdmkdir' : 'Novi folder', + 'cmdmkfile' : 'Nova datoteka', + 'cmdopen' : 'Otvori', + 'cmdpaste' : 'Zalepi', + 'cmdquicklook' : 'Pregledaj', + 'cmdreload' : 'Povno učitaj', + 'cmdrename' : 'Preimenuj', + 'cmdrm' : 'Obriši', + 'cmdsearch' : 'Pronađi datoteke', + 'cmdup' : 'Idi na nadređeni folder', + 'cmdupload' : 'Pošalji datoteke', + 'cmdview' : 'Pogledaj', + 'cmdresize' : 'Promeni veličinu slike', + 'cmdsort' : 'Sortiraj', + 'cmdnetmount' : 'Mount network volume', + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Zatvori', + 'btnSave' : 'Sačuvaj', + 'btnRm' : 'Obriši', + 'btnApply' : 'Potvrdi', + 'btnCancel' : 'Prekini', + 'btnNo' : 'Ne', + 'btnYes' : 'Da', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', + + /******************************** notifications ********************************/ + 'ntfopen' : 'Otvaranje foldera', + 'ntffile' : 'Otvaranje datoteke', + 'ntfreload' : 'Ponovo učitavanje sadržaja foldera', + 'ntfmkdir' : 'Kreiranje foldera', + 'ntfmkfile' : 'Kreiranje datoteke', + 'ntfrm' : 'Brisanje datoteke', + 'ntfcopy' : 'Kopiranje datoteke', + 'ntfmove' : 'Premeštanje datoteke', + 'ntfprepare' : 'Priprema za kopiranje dateoteke', + 'ntfrename' : 'Primenovanje datoteke', + 'ntfupload' : 'Slanje datoteke', + 'ntfdownload' : 'Preuzimanje datoteke', + 'ntfsave' : 'Čuvanje datoteke', + 'ntfarchive' : 'Kreiranje arhive', + 'ntfextract' : 'Izdvajanje datoteka iz arhive', + 'ntfsearch' : 'Pretraga datoteka', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Radim nešto >_<', + 'ntfloadimg' : 'Učitavanje slike', + 'ntfnetmount' : 'Montiranje mrežnog volumena', + 'ntfdim' : 'Acquiring image dimension', + + /************************************ dates **********************************/ + 'dateUnknown' : 'nepoznat', + 'Today' : 'Danas', + 'Yesterday' : 'Sutra', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Maj', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Avg', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Januar', + 'February' : 'Februar', + 'March' : 'Mart', + 'April' : 'April', + 'May' : 'Maj', + 'June' : 'Jun', + 'July' : 'Jul', + 'August' : 'Avgust', + 'September' : 'Septembar', + 'October' : 'Oktobar', + 'November' : 'Novembar', + 'December' : 'Decembar', + 'Sunday' : 'Nedelja', + 'Monday' : 'Ponedeljak', + 'Tuesday' : 'Utorak', + 'Wednesday' : 'Sreda', + 'Thursday' : 'Četvrtak', + 'Friday' : 'Petak', + 'Saturday' : 'Subota', + 'Sun' : 'Ned', + 'Mon' : 'Pon', + 'Tue' : 'Uto', + 'Wed' : 'Sre', + 'Thu' : 'Čet', + 'Fri' : 'Pet', + 'Sat' : 'Sub', + + /******************************** sort variants ********************************/ + 'sortname' : 'po imenu', + 'sortkind' : 'po vrsti', + 'sortsize' : 'po veličini', + 'sortdate' : 'po datumu', + 'sortFoldersFirst' : 'Prvo folderi', + + /********************************** messages **********************************/ + 'confirmReq' : 'Potrebna potvrda', + 'confirmRm' : 'Da li ste sigurni da želite da obrišete datoteke?
                      Ovo se ne može poništiti!', + 'confirmRepl' : 'Zameniti stare datoteke sa novima?', + 'apllyAll' : 'Potvrdi za sve', + 'name' : 'Ime', + 'size' : 'Veličina', + 'perms' : 'Dozvole', + 'modify' : 'Izmenjeno', + 'kind' : 'Vrsta', + 'read' : 'čitanje', + 'write' : 'pisanje', + 'noaccess' : 'bez pristupa', + 'and' : 'i', + 'unknown' : 'nepoznato', + 'selectall' : 'Izaberi sve datoteke', + 'selectfiles' : 'Izaberi datoteku(e)', + 'selectffile' : 'Izaberi prvu datoteku', + 'selectlfile' : 'Izaberi poslednju datoteku', + 'viewlist' : 'Popisni prikaz', + 'viewicons' : 'Pregled ikona', + 'places' : 'Mesta', + 'calc' : 'Izračunaj', + 'path' : 'Putanja', + 'aliasfor' : 'Nadimak za', + 'locked' : 'Zaključano', + 'dim' : 'Dimenzije', + 'files' : 'Datoteke', + 'folders' : 'Folderi', + 'items' : 'Stavke', + 'yes' : 'da', + 'no' : 'ne', + 'link' : 'Veza', + 'searcresult' : 'Rezultati pretrage', + 'selected' : 'odabrane stavke', + 'about' : 'O softveru', + 'shortcuts' : 'Prečice', + 'help' : 'Pomoć', + 'webfm' : 'Web menađer datoteka', + 'ver' : 'Verzija', + 'protocolver' : 'verzija protokla', + 'homepage' : 'Adresa projekta', + 'docs' : 'Dokumentacija', + 'github' : 'Forkuj nas na Github', + 'twitter' : 'Prati nas na twitter', + 'facebook' : 'Pridruži nam se na facebook', + 'team' : 'Tim', + 'chiefdev' : 'glavni programer', + 'developer' : 'programer', + 'contributor' : 'pomoćnik', + 'maintainer' : 'održavatelj', + 'translator' : 'prevodilac', + 'icons' : 'Ikone', + 'dontforget' : 'i ne zaboravite da ponesete peškir', + 'shortcutsof' : 'Prečice isključene', + 'dropFiles' : 'Prevucite datoteke ovde', + 'or' : 'ili', + 'selectForUpload' : 'Odaberite datoteke za slanje', + 'moveFiles' : 'Premesti datoteke', + 'copyFiles' : 'Kopiraj datoteke', + 'rmFromPlaces' : 'Ukloni iz mesta', + 'aspectRatio' : 'Omer širine i visine', + 'scale' : 'Razmera', + 'width' : 'Širina', + 'height' : 'Visina', + 'resize' : 'Promeni veličinu', + 'crop' : 'Iseci', + 'rotate' : 'Rotiraj', + 'rotate-cw' : 'Rotiraj 90 stepeni CW', + 'rotate-ccw' : 'Rotiraj 90 stepeni CCW', + 'degree' : 'Stepeni', + 'netMountDialogTitle' : 'Montiraj mrežni volumen', + 'protocol' : 'Protokol', + 'host' : 'Host', + 'port' : 'Port', + 'user' : 'Korisničko Ime', + 'pass' : 'Lozinka', + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Nepoznat', + 'kindFolder' : 'Folder', + 'kindAlias' : 'Nadimak', + 'kindAliasBroken' : 'Neispravan nadimak', + // applications + 'kindApp' : 'Aplikacija', + 'kindPostscript' : 'Postscript dokument', + 'kindMsOffice' : 'Microsoft Office dokument', + 'kindMsWord' : 'Microsoft Word dokument', + 'kindMsExcel' : 'Microsoft Excel dokument', + 'kindMsPP' : 'Microsoft Powerpoint prezentacija', + 'kindOO' : 'Open Office dokument', + 'kindAppFlash' : 'Flash aplikacija', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent datoteka', + 'kind7z' : '7z arhiva', + 'kindTAR' : 'TAR arhiva', + 'kindGZIP' : 'GZIP arhiva', + 'kindBZIP' : 'BZIP arhiva', + 'kindXZ' : 'XZ arhiva', + 'kindZIP' : 'ZIP arhiva', + 'kindRAR' : 'RAR arhiva', + 'kindJAR' : 'Java JAR datoteka', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM paket', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Teokstualni dokument', + 'kindTextPlain' : 'Čist tekst', + 'kindPHP' : 'PHP kod', + 'kindCSS' : 'CSS kod', + 'kindHTML' : 'HTML dokument', + 'kindJS' : 'Javascript kod', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C kod', + 'kindCHeader' : 'C header kod', + 'kindCPP' : 'C++ kod', + 'kindCPPHeader' : 'C++ header kod', + 'kindShell' : 'Unix shell skripta', + 'kindPython' : 'Python kod', + 'kindJava' : 'Java kod', + 'kindRuby' : 'Ruby kod', + 'kindPerl' : 'Perl skripta', + 'kindSQL' : 'SQL kod', + 'kindXML' : 'XML dokument', + 'kindAWK' : 'AWK kod', + 'kindCSV' : 'Comma separated values', + 'kindDOCBOOK' : 'Docbook XML dokument', + // images + 'kindImage' : 'Slika', + 'kindBMP' : 'BMP slika', + 'kindJPEG' : 'JPEG slika', + 'kindGIF' : 'GIF slika', + 'kindPNG' : 'PNG slika', + 'kindTIFF' : 'TIFF slika', + 'kindTGA' : 'TGA slika', + 'kindPSD' : 'Adobe Photoshop slika', + 'kindXBITMAP' : 'X bitmap slika', + 'kindPXM' : 'Pixelmator slika', + // media + 'kindAudio' : 'Zvuk', + 'kindAudioMPEG' : 'MPEG zvuk', + 'kindAudioMPEG4' : 'MPEG-4 zvuk', + 'kindAudioMIDI' : 'MIDI zvuk', + 'kindAudioOGG' : 'Ogg Vorbis zvuk', + 'kindAudioWAV' : 'WAV zvuk', + 'AudioPlaylist' : 'MP3 lista', + 'kindVideo' : 'Video', + 'kindVideoDV' : 'DV video', + 'kindVideoMPEG' : 'MPEG video', + 'kindVideoMPEG4' : 'MPEG-4 video', + 'kindVideoAVI' : 'AVI video', + 'kindVideoMOV' : 'Quick Time video', + 'kindVideoWM' : 'Windows Media video', + 'kindVideoFlash' : 'Flash video', + 'kindVideoMKV' : 'Matroska video', + 'kindVideoOGG' : 'Ogg video' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.sv.js b/lib/redactor/elfinder/js/i18n/elfinder.sv.js new file mode 100644 index 0000000..fad7031 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.sv.js @@ -0,0 +1,382 @@ +/** + * Swedish translation + * @author Gabriel Satzger + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.sv = { + translator : 'Gabriel Satzger <gabriel.satzger@sbg.se>', + language : 'Svenska', + direction : 'ltr', + dateFormat : 'Y-m-d H:i', + fancyDateFormat : '$1 H:i', + messages : { + + /********************************** errors **********************************/ + 'error' : 'Error', + 'errUnknown' : 'Okänt error.', + 'errUnknownCmd' : 'Okänt kommando.', + 'errJqui' : 'Felaktig jQuery UI konfiguration. Komponenterna selectable, draggable och droppable måste vara inkluderade.', + 'errNode' : 'elFinder kräver att DOM Elementen skapats.', + 'errURL' : 'Felaktig elFinder konfiguration! URL parametern är inte satt.', + 'errAccess' : 'Åtkomst nekad.', + 'errConnect' : 'Kan inte ansluta till backend.', + 'errAbort' : 'Anslutningen avbröts.', + 'errTimeout' : 'Anslutningen löpte ut.', + 'errNotFound' : 'Backend hittades inte.', + 'errResponse' : 'Ogiltig backend svar.', + 'errConf' : 'Ogiltig backend konfiguration.', + 'errJSON' : 'PHP JSON modul är inte installerad.', + 'errNoVolumes' : 'Läsbara volymer är inte tillgängliga.', + 'errCmdParams' : 'Ogiltiga parametrar för kommandot "$1".', + 'errDataNotJSON' : 'Datan är inte JSON.', + 'errDataEmpty' : 'Datan är tom.', + 'errCmdReq' : 'Backend begäran kräver kommandonamn.', + 'errOpen' : 'Kan inte öppna "$1".', + 'errNotFolder' : 'Objektet är inte en mapp.', + 'errNotFile' : 'Objektet är inte en fil.', + 'errRead' : 'Kan inte läsa "$1".', + 'errWrite' : 'Kan inte skriva till "$1".', + 'errPerm' : 'Tillstånd nekat.', + 'errLocked' : '"$1" är låst och kan inte döpas om, flyttas eller tas bort.', + 'errExists' : 'Fil med namn "$1" finns redan.', + 'errInvName' : 'Ogiltigt filnamn.', + 'errFolderNotFound' : 'Mappen hittades inte.', + 'errFileNotFound' : 'Filen hittades inte.', + 'errTrgFolderNotFound' : 'Målmappen "$1" hittades inte.', + 'errPopup' : 'Webbläsaren hindrade popup-fönstret att öppnas. Ändra i webbläsarens inställningar för att kunna öppna filen.', + 'errMkdir' : 'Kan inte skapa mappen "$1".', + 'errMkfile' : 'Kan inte skapa filen "$1".', + 'errRename' : 'Kan inte döpa om "$1".', + 'errCopyFrom' : 'Kopiera filer från volym "$1" tillåts inte.', + 'errCopyTo' : 'Kopiera filer till volym "$1" tillåts inte.', + 'errUpload' : 'Error vid uppladdningen.', + 'errUploadFile' : 'Kan inte ladda upp "$1".', + 'errUploadNoFiles' : 'Inga filer hittades för uppladdning.', + 'errUploadTotalSize' : 'Data överskrider den högsta tillåtna storleken.', + 'errUploadFileSize' : 'Filen överskrider den högsta tillåtna storleken.', + 'errUploadMime' : 'Otillåten filtyp.', + 'errUploadTransfer' : '"$1" överföringsfel.', + 'errNotReplace' : 'Object "$1" already exists at this location and can not be replaced by object with another type.', + 'errReplace' : 'Unable to replace "$1".', + 'errSave' : 'Kan inte spara "$1".', + 'errCopy' : 'Kan inte kopiera "$1".', + 'errMove' : 'Kan inte flytta "$1".', + 'errCopyInItself' : 'Kan inte flytta "$1" till sig själv.', + 'errRm' : 'Kan inte ta bort "$1".', + 'errRmSrc' : 'Unable remove source file(s).', + 'errExtract' : 'Kan inte packa upp filen från "$1".', + 'errArchive' : 'Kan inte skapa arkiv.', + 'errArcType' : 'Arkivtypen stöds inte.', + 'errNoArchive' : 'Filen är inte av typen arkiv.', + 'errCmdNoSupport' : 'Backend stöder inte detta kommando.', + 'errReplByChild' : 'Mappen “$1” kan inte ersättas av ett objekt den innehåller.', + 'errArcSymlinks' : 'Av säkerhetsskäl nekas arkivet att packas upp då det innehåller symboliska länkar eller filer med ej tillåtna namn.', // edited 24.06.2012 + 'errArcMaxSize' : 'Arkivfiler överskrider största tillåtna storlek.', + 'errResize' : 'Kan inte ändra storlek "$1".', + 'errResizeDegree' : 'Invalid rotate degree.', + 'errResizeRotate' : 'Unable to rotate image.', + 'errResizeSize' : 'Invalid image size.', + 'errResizeNoChange' : 'Image size not changed.', + 'errUsupportType' : 'Filtypen stöds inte.', + 'errNotUTF8Content' : 'Filen "$1" är inte i UTF-8 och kan inte redigeras.', // added 9.11.2011 + 'errNetMount' : 'Kan inte koppla "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Protokollet stöds inte.', // added 17.04.2012 + 'errNetMountFailed' : 'Kopplingen misslyckades.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host krävs.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Skapa arkiv', + 'cmdback' : 'Tillbaka', + 'cmdcopy' : 'Kopiera', + 'cmdcut' : 'Klipp ut', + 'cmddownload' : 'Ladda ned', + 'cmdduplicate' : 'Duplicera', + 'cmdedit' : 'Redigera fil', + 'cmdextract' : 'Extrahera filer från arkiv', + 'cmdforward' : 'Framåt', + 'cmdgetfile' : 'Välj filer', + 'cmdhelp' : 'Om denna programvara', + 'cmdhome' : 'Hem', + 'cmdinfo' : 'Visa info', + 'cmdmkdir' : 'Ny mapp', + 'cmdmkfile' : 'Ny fil', + 'cmdopen' : 'Öppna', + 'cmdpaste' : 'Klistra in', + 'cmdquicklook' : 'Förhandsgranska', + 'cmdreload' : 'Ladda om', + 'cmdrename' : 'Döp om', + 'cmdrm' : 'Radera', + 'cmdsearch' : 'Hitta filer', + 'cmdup' : 'Gå till överordnade katalog', + 'cmdupload' : 'Ladda upp filer', + 'cmdview' : 'Visa', + 'cmdresize' : 'Ändra bildstorlek', + 'cmdsort' : 'Sortera', + 'cmdnetmount' : 'Mount network volume', + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Stäng', + 'btnSave' : 'Spara', + 'btnRm' : 'Ta bort', + 'btnApply' : 'Verkställ', + 'btnCancel' : 'Ångra', + 'btnNo' : 'Nej', + 'btnYes' : 'Ja', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', + + /******************************** notifications ********************************/ + 'ntfopen' : 'Öppnar mapp', + 'ntffile' : 'Öppnar fil', + 'ntfreload' : 'Laddar om mappinnehållet', + 'ntfmkdir' : 'Skapar katalog', + 'ntfmkfile' : 'Skapar fil', + 'ntfrm' : 'Tar bort filer', + 'ntfcopy' : 'Kopierar filer', + 'ntfmove' : 'Flyttar filer', + 'ntfprepare' : 'Förbereder att flytta filer', + 'ntfrename' : 'Döper om filer', + 'ntfupload' : 'Laddar upp filer', + 'ntfdownload' : 'Laddar ner filer', + 'ntfsave' : 'Sparar filer', + 'ntfarchive' : 'Skapar arkiv', + 'ntfextract' : 'Extraherar filer från arkiv', + 'ntfsearch' : 'Söker filer', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Gör någonting >_<', + 'ntfloadimg' : 'Laddar bild', + 'ntfnetmount' : 'kopplar nätverksvolym', // added 18.04.2012 + 'ntfdim' : 'Acquiring image dimension', + + /************************************ dates **********************************/ + 'dateUnknown' : 'okänt', + 'Today' : 'Idag', + 'Yesterday' : 'Igår', + 'msJan' : 'Jan', + 'msFeb' : 'Feb', + 'msMar' : 'Mar', + 'msApr' : 'Apr', + 'msMay' : 'Maj', + 'msJun' : 'Jun', + 'msJul' : 'Jul', + 'msAug' : 'Aug', + 'msSep' : 'Sep', + 'msOct' : 'Okt', + 'msNov' : 'Nov', + 'msDec' : 'Dec', + 'January' : 'Januari', + 'February' : 'Februari', + 'March' : 'Mars', + 'April' : 'April', + 'May' : 'Maj', + 'June' : 'Juni', + 'July' : 'Juli', + 'August' : 'Augusti', + 'September' : 'September', + 'October' : 'Oktober', + 'November' : 'November', + 'December' : 'December', + 'Sunday' : 'Söndag', + 'Monday' : 'Måndag', + 'Tuesday' : 'Tisdag', + 'Wednesday' : 'Onsdag', + 'Thursday' : 'Torsdag', + 'Friday' : 'Fredag', + 'Saturday' : 'Lördag', + 'Sun' : 'Sön', + 'Mon' : 'Mån', + 'Tue' : 'Tis', + 'Wed' : 'Ons', + 'Thu' : 'Tor', + 'Fri' : 'Fre', + 'Sat' : 'Lör', + + /******************************** sort variants ********************************/ + 'sortname' : 'efter namn', + 'sortkind' : 'efter sort', + 'sortsize' : 'efter storlek', + 'sortdate' : 'efter datum', + 'sortFoldersFirst' : 'Mappar först', // added 22.06.2012 + + /********************************** messages **********************************/ + 'confirmReq' : 'Bekräftelse krävs', + 'confirmRm' : 'Är du säker på att du vill ta bort filer?
                      Detta kan inte ångras!', + 'confirmRepl' : 'Ersätt den gamla filen med en ny?', + 'apllyAll' : 'Använd för alla', + 'name' : 'Namn', + 'size' : 'Storlek', + 'perms' : 'Rättigheter', + 'modify' : 'Ändrad', + 'kind' : 'Sort', + 'read' : 'läs', + 'write' : 'skriv', + 'noaccess' : 'ingen åtkomst', + 'and' : 'och', + 'unknown' : 'okänd', + 'selectall' : 'Välj alla filer', + 'selectfiles' : 'Välj fil(er)', + 'selectffile' : 'Välj första filen', + 'selectlfile' : 'Välj sista filen', + 'viewlist' : 'Listvy', + 'viewicons' : 'Ikonvy', + 'places' : 'Platser', + 'calc' : 'Beräkna', + 'path' : 'Sökväg', + 'aliasfor' : 'Alias för', + 'locked' : 'Låst', + 'dim' : 'Dimensioner', + 'files' : 'Filer', + 'folders' : 'Mappar', + 'items' : 'Objekt', + 'yes' : 'ja', + 'no' : 'nej', + 'link' : 'Länk', + 'searcresult' : 'Sökresultat', + 'selected' : 'valda objekt', + 'about' : 'Om', + 'shortcuts' : 'Genväg', + 'help' : 'Hjälp', + 'webfm' : 'Webbfilhanterare', + 'ver' : 'Version', + 'protocolver' : 'protokolversion', + 'homepage' : 'Projekt hemsida', + 'docs' : 'Dokumentation', + 'github' : 'Forka oss på Github', + 'twitter' : 'Följ oss på twitter', + 'facebook' : 'Följ oss på facebook', + 'team' : 'Team', + 'chiefdev' : 'senior utvecklare', + 'developer' : 'utvecklare', + 'contributor' : 'bidragsgivare', + 'maintainer' : 'underhållare', + 'translator' : 'översättare', + 'icons' : 'Ikoner', + 'dontforget' : 'och glöm inte att ta med din handduk', + 'shortcutsof' : 'Genvägar avaktiverade', + 'dropFiles' : 'Släpp filerna här', + 'or' : 'eller', + 'selectForUpload' : 'Välj filer att ladda upp', + 'moveFiles' : 'Flytta filer', + 'copyFiles' : 'Kopiera filer', + 'rmFromPlaces' : 'Ta bort från platser', + 'aspectRatio' : 'Aspekt ratio', + 'scale' : 'Skala', + 'width' : 'Bredd', + 'height' : 'Höjd', + 'resize' : 'Ändra storlek', + 'crop' : 'Beskär', + 'rotate' : 'Rotera', + 'rotate-cw' : 'Rotera 90 grader medurs', + 'rotate-ccw' : 'Rotera 90 grader moturs', + 'degree' : 'Grader', + 'netMountDialogTitle' : 'Koppla nätverksvolym', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'användare', // added 18.04.2012 + 'pass' : 'Lösenord', // added 18.04.2012 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Okänd', + 'kindFolder' : 'Mapp', + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Trasigt alias', + // applications + 'kindApp' : 'Applikation', + 'kindPostscript' : 'Postscript', + 'kindMsOffice' : 'Microsoft Office', + 'kindMsWord' : 'Microsoft Word', + 'kindMsExcel' : 'Microsoft Excel', + 'kindMsPP' : 'Microsoft Powerpoint', + 'kindOO' : 'Open Office', + 'kindAppFlash' : 'Flash', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent', + 'kind7z' : '7z', + 'kindTAR' : 'TAR', + 'kindGZIP' : 'GZIP', + 'kindBZIP' : 'BZIP', + 'kindXZ' : 'XZ', + 'kindZIP' : 'ZIP', + 'kindRAR' : 'RAR', + 'kindJAR' : 'Java JAR', + 'kindTTF' : 'True Type', + 'kindOTF' : 'Open Type', + 'kindRPM' : 'RPM', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT', + 'kindEOT' : 'Embedded Open Type', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Text', + 'kindTextPlain' : 'Plain', + 'kindPHP' : 'PHP', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML', + 'kindJS' : 'Javascript', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C', + 'kindCHeader' : 'C header', + 'kindCPP' : 'C++', + 'kindCPPHeader' : 'C++ header', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python', + 'kindJava' : 'Java', + 'kindRuby' : 'Ruby', + 'kindPerl' : 'Perl', + 'kindSQL' : 'SQL', + 'kindXML' : 'XML', + 'kindAWK' : 'AWK', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Docbook XML', + // images + 'kindImage' : 'Bild', + 'kindBMP' : 'BMP', + 'kindJPEG' : 'JPEG', + 'kindGIF' : 'GIF', + 'kindPNG' : 'PNG', + 'kindTIFF' : 'TIFF', + 'kindTGA' : 'TGA', + 'kindPSD' : 'Adobe Photoshop', + 'kindXBITMAP' : 'X bitmap', + 'kindPXM' : 'Pixelmator', + // media + 'kindAudio' : 'Audio media', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video media', + 'kindVideoDV' : 'DV movie', + 'kindVideoMPEG' : 'MPEG movie', + 'kindVideoMPEG4' : 'MPEG-4 movie', + 'kindVideoAVI' : 'AVI movie', + 'kindVideoMOV' : 'Quick Time movie', + 'kindVideoWM' : 'Windows Media movie', + 'kindVideoFlash' : 'Flash movie', + 'kindVideoMKV' : 'Matroska movie', + 'kindVideoOGG' : 'Ogg movie' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.tr.js b/lib/redactor/elfinder/js/i18n/elfinder.tr.js new file mode 100644 index 0000000..3a6b6df --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.tr.js @@ -0,0 +1,591 @@ +/** + * Türkçe translation + * @author I.Taskinoglu & A.Kaya + * @author Abdullah ELEN + * @author Osman KAYAN + * @author alikayan95@gmail.com + * @author Cengiz AKCAN cengiz@vobo.company + * @author Ali KAYAN + * @version 2025-06-26 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.tr = { + translator : 'I.Taskinoglu & A.Kaya <alikaya@armsyazilim.com>, Abdullah ELEN <abdullahelen@msn.com>, Osman KAYAN <osmnkayan@gmail.com>, alikayan95@gmail.com, Cengiz AKCAN cengiz@vobo.company, Ali KAYAN <alikayan95@gmail.com>', + language : 'Türkçe', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // will show like: 26.06.2025 09:57 + fancyDateFormat : '$1 H:i', // will show like: Bugün 09:57 + nonameDateFormat : 'ymd-His', // noname upload will show like: 250626-095752 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Hata', + 'errUnknown' : 'Bilinmeyen hata.', + 'errUnknownCmd' : 'Bilinmeyen komut.', + 'errJqui' : 'Geçersiz jQuery UI yapılandırması. Seçilebilir, sürükle ve bırak bileşenlerini içermelidir.', + 'errNode' : 'elFinder yaratılması için DOM Element\'ine ihtiyacı vardır.', + 'errURL' : 'Geçersiz elFinder yapılandırması! URL seçeneği ayarlanmamış.', + 'errAccess' : 'Erişim reddedildi.', + 'errConnect' : 'Sunucu-Tarafı\'na bağlanılamıyor.', + 'errAbort' : 'Bağlantı iptal edildi.', + 'errTimeout' : 'Bağlantı zaman aşımı.', + 'errNotFound' : 'Sunucu-Tarafı bulunamadı.', + 'errResponse' : 'Geçersiz Sunucu-Tarafı yanıtı.', + 'errConf' : 'Geçersiz Sunucu-Tarafı yapılandırması.', + 'errJSON' : 'PHP JSON modülü kurulu değil.', + 'errNoVolumes' : 'Okunabilir birimler mevcut değil.', + 'errCmdParams' : '"$1" komutu için geçersiz parametre.', + 'errDataNotJSON' : 'Veri JSON formatında değil.', + 'errDataEmpty' : 'Veri boş.', + 'errCmdReq' : 'Sunucu-Tarafı isteği için komut adı gerekli.', + 'errOpen' : '"$1" açılamıyor.', + 'errNotFolder' : 'Nesne bir dizin değil.', + 'errNotFile' : 'Nesne bir dosya değil.', + 'errRead' : '"$1" okunamıyor.', + 'errWrite' : '"$1" yazılamıyor.', + 'errPerm' : 'İzin reddedildi.', + 'errLocked' : '"$1" kilitli. Bu nedenle taşıma, yeniden adlandırma veya kaldırma yapılamıyor.', + 'errExists' : '"$1" adında bir dosya zaten var.', + 'errInvName' : 'Geçersiz dosya ismi.', + 'errInvDirname' : 'Geçersiz dizin ismi.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Dizin bulunamadı.', + 'errFileNotFound' : 'Dosya bulunamadı.', + 'errTrgFolderNotFound' : 'Hedef dizin "$1" bulunamadı.', + 'errPopup' : 'Tarayıcı popup penceresi açmayı engelledi. Tarayıcı ayarlarından dosya açmayı aktif hale getirin.', + 'errMkdir' : 'Dizin oluşturulamıyor "$1".', + 'errMkfile' : '"$1" dosyası oluşturulamıyor.', + 'errRename' : '"$1" yeniden adlandırma yapılamıyor.', + 'errCopyFrom' : '"$1" biriminden dosya kopyalamaya izin verilmedi.', + 'errCopyTo' : '"$1" birimine dosya kopyalamaya izin verilmedi.', + 'errMkOutLink' : 'Birim kökü dışında bir bağlantı oluşturulamıyor', // from v2.1 added 03.10.2015 + 'errUpload' : 'Dosya yükleme hatası.', // old name - errUploadCommon + 'errUploadFile' : '"$1" dosyası yüklenemedi.', // old name - errUpload + 'errUploadNoFiles' : 'Yüklenecek dosya bulunamadı.', + 'errUploadTotalSize' : 'Veri izin verilen boyuttan büyük.', // old name - errMaxSize + 'errUploadFileSize' : 'Dosya izin verilen boyuttan büyük.', // old name - errFileMaxSize + 'errUploadMime' : 'Dosya türüne izin verilmiyor.', + 'errUploadTransfer' : '"$1" aktarma hatası.', + 'errUploadTemp' : 'Yükleme için geçici dosya yapılamıyor.', // from v2.1 added 26.09.2015 + 'errNotReplace' : '"$1" nesnesi bu konumda zaten var ve başka türde nesne ile değiştirilemez.', // new + 'errReplace' : 'Değişiklik yapılamıyor "$1".', + 'errSave' : '"$1" kaydedilemiyor.', + 'errCopy' : '"$1" kopyalanamıyor.', + 'errMove' : '"$1" taşınamıyor.', + 'errCopyInItself' : '"$1" kendi içine kopyalanamaz.', + 'errRm' : '"$1" kaldırılamıyor.', + 'errTrash' : 'Çöp kutusuna taşınamıyor.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Kaynak dosya(lar) kaldırılamıyor.', + 'errExtract' : '"$1" kaynağından dosyalar çıkartılamıyor.', + 'errArchive' : 'Arşiv oluşturulamıyor.', + 'errArcType' : 'Desteklenmeyen arşiv türü.', + 'errNoArchive' : 'Dosya arşiv değil veya desteklenmeyen arşiv türü.', + 'errCmdNoSupport' : 'Sunucu-Tarafı bu komutu desteklemiyor.', + 'errReplByChild' : '“$1” dizini, içerdiği bir öğe tarafından değiştirilemez.', + 'errArcSymlinks' : 'Sembolik bağlantıları içeren arşivlerin açılması güvenlik nedeniyle reddedildi.', // edited 24.06.2012 + 'errArcMaxSize' : 'Arşiv dosyaları izin verilen maksimum boyutu aştı.', + 'errResize' : '"$1" yeniden boyutlandırılamıyor.', + 'errResizeDegree' : 'Geçersiz döndürme derecesi.', // added 7.3.2013 + 'errResizeRotate' : 'Resim döndürülemiyor.', // added 7.3.2013 + 'errResizeSize' : 'Geçersiz resim boyutu.', // added 7.3.2013 + 'errResizeNoChange' : 'Resim boyutu değiştirilemez.', // added 7.3.2013 + 'errUsupportType' : 'Desteklenmeyen dosya türü.', + 'errNotUTF8Content' : 'Dosya "$1" UTF-8 olmadığından düzenlenemez.', // added 9.11.2011 + 'errNetMount' : '"$1" bağlanamadı.', // added 17.04.2012 + 'errNetMountNoDriver' : 'Desteklenmeyen protokol.', // added 17.04.2012 + 'errNetMountFailed' : 'Bağlama başarısız oldu.', // added 17.04.2012 + 'errNetMountHostReq' : 'Host gerekli.', // added 18.04.2012 + 'errSessionExpires' : 'Uzun süre işlem yapılmadığından oturumunuz sonlandı.', + 'errCreatingTempDir' : 'Geçici dizin oluşturulamıyor: "$1"', + 'errFtpDownloadFile' : 'Dosya FTP: "$1" adresinden indirilemiyor.', + 'errFtpUploadFile' : 'Dosya FTP: "$1" adresine yüklenemiyor.', + 'errFtpMkdir' : 'FTP: "$1" üzerinde uzak dizin oluşturulamıyor.', + 'errArchiveExec' : '"$1" Dosyalarında arşivlenirken hata oluştu.', + 'errExtractExec' : '"$1" Dosyaları arşivden çıkartılırken hata oluştu.', + 'errNetUnMount' : 'Bağlantı kaldırılamıyor.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'UTF-8\'e dönüştürülemez.', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Dizin yükleyebilmek için daha modern bir tarayıcıya ihtiyacınız var.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '"$1" aranırken zaman aşımına uğradı. Arama sonuçları kısmidir.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Yeniden yetkilendirme gerekiyor.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Maksimum seçilebilir öge sayısı $1 adettir.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Çöp kutusundan geri yüklenemiyor. Geri yükleme notkası belirlenemiyor.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Bu doya türü için düzenleyici bulunamadı.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Sunucu tarafında beklenilmeyen bir hata oluştu.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : '"$1" Dizini boşaltılamıyor.', // from v2.1.25 added 22.6.2017 + 'moreErrors' : '"$1" tane daha hata var.', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : 'Tek seferde en fazla 1$ dizin oluşturabilirsiniz.', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Arşiv oluştur', + 'cmdback' : 'Geri', + 'cmdcopy' : 'Kopyala', + 'cmdcut' : 'Kes', + 'cmddownload' : 'İndir', + 'cmdduplicate' : 'Kopyasını oluştur', + 'cmdedit' : 'Dosyayı düzenle', + 'cmdextract' : 'Arşivden dosyaları çıkart', + 'cmdforward' : 'İleri', + 'cmdgetfile' : 'Dosyaları seç', + 'cmdhelp' : 'Bu yazılım hakkında', + 'cmdhome' : 'Kök', + 'cmdinfo' : 'Bilgi göster', + 'cmdmkdir' : 'Yeni klasör', + 'cmdmkdirin' : 'Yeni Klasör / aç', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Yeni dosya', + 'cmdopen' : 'Aç', + 'cmdpaste' : 'Yapıştır', + 'cmdquicklook' : 'Önizleme', + 'cmdreload' : 'Geri Yükle', + 'cmdrename' : 'Yeniden Adlandır', + 'cmdrm' : 'Sil', + 'cmdtrash' : 'Çöpe at', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Geri yükle', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Dosyaları bul', + 'cmdup' : 'Üst dizine çık', + 'cmdupload' : 'Dosyaları yükle', + 'cmdview' : 'Görüntüle', + 'cmdresize' : 'Boyutlandır & Döndür', + 'cmdsort' : 'Sırala', + 'cmdnetmount' : 'Ağ birimi bağla', // added 18.04.2012 + 'cmdnetunmount': 'bağlantıyı kes', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'Yerlere', // added 28.12.2014 + 'cmdchmod' : 'Mod değiştir', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Bir Dizin Aç', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Sütun genişliğini sıfırla', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Tam Ekran', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Taşı', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Dizini boşalt', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Geri al', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Yinele', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Tercihler', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Tümünü seç', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Seçimi temizle', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Diğerlerini seç', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Yeni Sekmede aç', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Ögeyi Gizle', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Kapat', + 'btnSave' : 'Kaydet', + 'btnRm' : 'Kaldır', + 'btnApply' : 'Uygula', + 'btnCancel' : 'İptal', + 'btnNo' : 'Hayır', + 'btnYes' : 'Evet', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Bağla', // added 18.04.2012 + 'btnApprove': 'Git $1 & onayla', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Bağlantıyı kes', // from v2.1 added 30.04.2012 + 'btnConv' : 'Dönüştür', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Buraya', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Birim', // from v2.1 added 22.5.2015 + 'btnAll' : 'Hepsi', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Türü', // from v2.1 added 22.5.2015 + 'btnFileName':'Dosya adı', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Kaydet & Kapat', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Yedekle', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Yeniden adlandır', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Yeniden adlandır(Tümü)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Önceki ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Sonraki ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Farklı Kaydet', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Dizin Aç', + 'ntffile' : 'Dosya Aç', + 'ntfreload' : 'Dizin içeriğini yeniden yükle', + 'ntfmkdir' : 'Dizin oluşturuluyor', + 'ntfmkfile' : 'Dosyaları oluşturma', + 'ntfrm' : 'Öğeleri sil', + 'ntfcopy' : 'Öğeleri kopyala', + 'ntfmove' : 'Öğeleri taşı', + 'ntfprepare' : 'Varolan öğeler kontrol ediliyor', + 'ntfrename' : 'Dosyaları yeniden adlandır', + 'ntfupload' : 'Dosyalar yükleniyor', + 'ntfdownload' : 'Dosyalar indiriliyor', + 'ntfsave' : 'Dosyalar kaydediliyor', + 'ntfarchive' : 'Arşiv oluşturuluyor', + 'ntfextract' : 'Arşivden dosyalar çıkartılıyor', + 'ntfsearch' : 'Dosyalar aranıyor', + 'ntfresize' : 'Resimler boyutlandırılıyor', + 'ntfsmth' : 'İşlem yapılıyor', + 'ntfloadimg' : 'Resim yükleniyor', + 'ntfnetmount' : 'Ağ birimine bağlanılıyor', // added 18.04.2012 + 'ntfnetunmount': 'Ağ birimi bağlantısı kesiliyor', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Resim boyutu alınıyor', // added 20.05.2013 + 'ntfreaddir' : 'Dizin bilgisi okunuyor', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Bağlantının URL\'si alınıyor', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Dosya modu değiştiriliyor', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Yüklenen dosya ismi doğrulanıyor', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'İndirilecek dosya oluşturuluyor', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Dosya yolu bilgileri alınıyor', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Yüklenen dosya işleniyor', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Çöp kutusuna atma', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Çöp kutusundan geri yükle', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Hedef dizin kontrol ediliyor', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Önceki işlemi geri alma', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Önceki geri almayı tekrarlama', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'İçeriği kontrol ediniz', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Çöp', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Bilinmiyor', + 'Today' : 'Bugün', + 'Yesterday' : 'Dün', + 'msJan' : 'Oca', + 'msFeb' : 'Şub', + 'msMar' : 'Mar', + 'msApr' : 'Nis', + 'msMay' : 'May', + 'msJun' : 'Haz', + 'msJul' : 'Tem', + 'msAug' : 'Ağu', + 'msSep' : 'Eyl', + 'msOct' : 'Ekm', + 'msNov' : 'Kas', + 'msDec' : 'Ara', + 'January' : 'Ocak', + 'February' : 'Şubat', + 'March' : 'Mart', + 'April' : 'Nisan', + 'May' : 'Mayıs', + 'June' : 'Haziran', + 'July' : 'Temmuz', + 'August' : 'Ağustos', + 'September' : 'Eylül', + 'October' : 'Ekim', + 'November' : 'Kasım', + 'December' : 'Aralık', + 'Sunday' : 'Pazar', + 'Monday' : 'Pazartesi', + 'Tuesday' : 'Salı', + 'Wednesday' : 'Çarşamba', + 'Thursday' : 'Perşembe', + 'Friday' : 'Cuma', + 'Saturday' : 'Cumartesi', + 'Sun' : 'Paz', + 'Mon' : 'Pzt', + 'Tue' : 'Sal', + 'Wed' : 'Çar', + 'Thu' : 'Per', + 'Fri' : 'Cum', + 'Sat' : 'Cmt', + + /******************************** sort variants ********************************/ + 'sortname' : 'Ada göre', + 'sortkind' : 'Türe göre', + 'sortsize' : 'Boyuta göre', + 'sortdate' : 'Tarihe göre', + 'sortFoldersFirst' : 'Önce dizinler', + 'sortperm' : 'izinlere göre', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'moduna göre', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'sahibine göre', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'grubuna göre', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Ayrıca ağaç görünümü', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'YeniDosya.txt', // added 10.11.2015 + 'untitled folder' : 'YeniKlasor', // added 10.11.2015 + 'Archive' : 'YeniArsiv', // from v2.1 added 10.11.2015 + 'untitled file' : 'YeniDosya.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: Dosya', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Onay gerekli', + 'confirmRm' : 'Öğeleri kaldırmak istediğinden emin misin?
                      Bu işlem geri alınamaz!', + 'confirmRepl' : 'Eski dosya yenisi ile değiştirilsin mi?', + 'confirmRest' : 'Mevcut öge çöp kutusundaki ögeyle değiştirilsin mi?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'UTF-8 değil
                      UTF-8\'e dönüştürülsün mü?
                      Dönüştürme sonrası kaydedebilmek için içeriğin UTF-8 olması gerekir.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Bu dosyanın karakter kodlaması tespit edilemedi. Düzenleme için geçici olarak UTF-8\'e dönüştürülmesi gerekir.
                      Lütfen bu dosyanın karakter kodlamasını seçin.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Düzenlenmiş içerik.
                      Değişiklikleri kaydetmek istemiyorsanız son yapılanlar kaybolacak.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Öğeleri çöp kutusuna taşımak istediğinizden emin misiniz?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : '"$1" değiştirmek istediğinizden emin misiniz?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Tümüne uygula', + 'name' : 'İsim', + 'size' : 'Boyut', + 'perms' : 'Yetkiler', + 'modify' : 'Değiştirildi', + 'kind' : 'Tür', + 'read' : 'oku', + 'write' : 'yaz', + 'noaccess' : 'erişim yok', + 'and' : 've', + 'unknown' : 'bilinmeyen', + 'selectall' : 'Tüm öğeleri seç', + 'selectfiles' : 'Öğe(ler)i seç', + 'selectffile' : 'İlk öğeyi seç', + 'selectlfile' : 'Son öğeyi seç', + 'viewlist' : 'Liste görünümü', + 'viewicons' : 'Simge görünümü', + 'viewSmall' : 'Küçük simgeler', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Orta simgleler', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Büyük simgleler', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Çok büyük simgeler', // from v2.1.39 added 22.5.2018 + 'places' : 'Yerler', + 'calc' : 'Hesapla', + 'path' : 'Dosya Yolu', + 'aliasfor' : 'Takma adı', + 'locked' : 'Kilitli', + 'dim' : 'Ölçüler', + 'files' : 'Dosyalar', + 'folders' : 'Dizinler', + 'items' : 'Nesneler', + 'yes' : 'evet', + 'no' : 'hayır', + 'link' : 'Bağlantı', + 'searcresult' : 'Arama sonuçları', + 'selected' : 'Seçili öğeler', + 'about' : 'Hakkında', + 'shortcuts' : 'Kısayollar', + 'help' : 'Yardım', + 'webfm' : 'Web dosyası yöneticisi', + 'ver' : 'Sürüm', + 'protocolver' : 'protokol sürümü', + 'homepage' : 'Proje Anasayfası', + 'docs' : 'Belgeler', + 'github' : 'Github\'ta bizi takip edin', + 'twitter' : 'Twitter\'da bizi takip edin', + 'facebook' : 'Facebook\'ta bize katılın', + 'team' : 'Takım', + 'chiefdev' : 'geliştirici şefi', + 'developer' : 'geliştirici', + 'contributor' : 'iştirakçi', + 'maintainer' : 'bakıcı', + 'translator' : 'tercüman', + 'icons' : 'Simgeler', + 'dontforget' : 've havlunuzu almayı unutmayın', + 'shortcutsof' : 'Kısayollar devre dışı', + 'dropFiles' : 'Dosyaları buraya taşı', + 'or' : 'veya', + 'selectForUpload' : 'Yüklemek için dosyaları seçin', + 'moveFiles' : 'Öğeleri taşı', + 'copyFiles' : 'Öğeleri kopyala', + 'restoreFiles' : 'Öğeleri geri yükle', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Yerlerinden sil', + 'aspectRatio' : 'Görünüm oranı', + 'scale' : 'Ölçeklendir', + 'width' : 'Genişlik', + 'height' : 'Yükseklik', + 'resize' : 'Boyutlandır', + 'crop' : 'Kırp', + 'rotate' : 'Döndür', + 'rotate-cw' : '90 derece sağa döndür', + 'rotate-ccw' : '90 derece sola döndür', + 'degree' : '°', + 'netMountDialogTitle' : 'Bağlı (Mount) ağ birimi', // added 18.04.2012 + 'protocol' : 'Protokol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Kapı(Port)', // added 18.04.2012 + 'user' : 'Kullanıcı', // added 18.04.2012 + 'pass' : 'Şifre', // added 18.04.2012 + 'confirmUnmount' : 'Bağlantı kesilsin mi $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Dosyaları tarayıcıdan yapıştır veya bırak', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Dosyaları buraya yapıştır veya bırak', // from v2.1 added 07.04.2014 + 'encoding' : 'Kodlama', // from v2.1 added 19.12.2014 + 'locale' : 'Yerel', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Hedef: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Giriş MIME Türüne Göre Arama', // from v2.1 added 22.5.2015 + 'owner' : 'Sahibi', // from v2.1 added 20.6.2015 + 'group' : 'Grup', // from v2.1 added 20.6.2015 + 'other' : 'Diğer', // from v2.1 added 20.6.2015 + 'execute' : 'Çalıştır', // from v2.1 added 20.6.2015 + 'perm' : 'Yetki', // from v2.1 added 20.6.2015 + 'mode' : 'Mod', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Dizin boş', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Dizin boş\\Öğe eklemek için sürükleyin', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Dizin boş\\Öğe eklemek için basılı tutun', // from v2.1.6 added 30.12.2015 + 'quality' : 'Kalite', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Otomatik senkronizasyon', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Yukarı taşı', // from v2.1.6 added 18.1.2016 + 'getLink' : 'URL bağlantısı alın', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Seçili öğeler ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'Dizin kimliği', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Çevrimdışı erişime izin ver', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Yeniden kimlik doğrulaması için', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Şimdi yükleniyor...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Çoklu dosya aç', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': '$1 dosyalarını açmaya çalışıyorsunuz. Tarayıcıda açmak istediğinizden emin misiniz?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Arama hedefinde eşleşen sonuç bulunamadı.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Dosya düzenleniyor.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '$1 öğe seçtiniz.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'Panonuzda $1 öğeniz var.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Artan arama yalnızca geçerli görünümden yapılır.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Eski durumuna getir', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 tamamlandı', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Konteks menüsü', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Sayfa çevir', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Kök birimler', // from v2.1.16 added 16.9.2016 + 'reset' : 'Sıfırla', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Arkaplan rengi', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Renk seçici', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Izgara', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Etkin', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Engelli', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Geçerli görünümde arama sonucu bulunamadı. Arama sonucunu genişletmek için \\APress [Enter] yapın', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Geçerli görünümde ilk harf arama sonuçları boş.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Metin etiketi', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 dakika kaldı', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Seçilen kodlamayla yeniden aç', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Seçilen kodlamayla kaydet', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Dizin seç', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'İlk arama sayfası', // from v2.1.23 added 24.3.2017 + 'presets' : 'Hazır ayarlar', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'çok fazla öge var çöp kutusuna atılamaz.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'Metin alanı(TextArea)', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : '"$1" dizinini boşalt.', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : '"$1" dizininde öğe yok.', // from v2.1.25 added 22.6.2017 + 'preference' : 'Tercih', // from v2.1.26 added 28.6.2017 + 'language' : 'Dil ayarları', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Bu tarayıcıda kayıtlı ayarları başlat', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Araç çubuğu ayarları', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 karakter kaldı', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 satır kaldı.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Toplam', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Kaba dosya boyutu', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Fare ile üzerine gelince diyalog öğesi odaklansın', // from v2.1.30 added 2.11.2017 + 'select' : 'Seç', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Dosya seçildiğinde işleme al', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Geçen sefer kullanılan editörle aç', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Zıt seçim', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : '$1 seçilen öğeleri $2 gibi yeniden adlandırmak istediğinizden emin misiniz?
                      Bu geri alınamaz!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Yığın adını değiştir', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Sayı', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Ön ek kele', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Son ek ekle', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Uzantıyı değiştir', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Sütun ayarları (Liste görünümü)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Tüm değişiklikler hemen arşive yansıtılacaktır.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Herhangi bir değişiklik, bu birimi kaldırılıncaya kadar yansıtılmayacaktır.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Bağlatıyı kesmek istediğiniz birime bağlı şu birim(ler)\'in de bağlantısı kesilecek. Bağlantıyı kesmek istediğinize emin misiniz?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Seçim Bilgisi', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Dosya imza(hash) algoritmaları', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'öğelerin bilgisi (Seçim Bilgi Paneli)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Çıkmak için tekrar basın.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Araç Çubuğu', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Çalışma alanı', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Diyalog', // from v2.1.38 added 4.4.2018 + 'all' : 'Tümü', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Simge Boyutu (Simge Görünümü)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Maksimum düzenleyici penceresini aç', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'API ile dönüşüm şu anda mevcut olmadığından, lütfen web sitesinde dönüştürün.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Dönüştürmeden sonra, dönüştürülen dosyayı kaydetmek için öğe URL\'si veya indirilen bir dosya ile karşıya yüklemeniz gerekir.', //from v2.1.40 added 8.7.2018 + 'convertOn' : ' $1 site çevrildi', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Entegrasyonlar', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Bu elFinder aşağıdaki harici hizmetlere entegre edilmiştir. Lütfen kullanmadan önce kullanım koşullarını, gizlilik politikasını vb. Kontrol edin.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Gizli ögeleri aç.', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Gizli ögeleri kapat.', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Gizli ögeleri aç/kapat', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : '"Yeni dosya" ile etkinleştirilecek dosya türleri', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Text dosyası tipi.', // from v2.1.41 added 7.8.2018 + 'add' : 'Ekle', // from v2.1.41 added 7.8.2018 + 'theme' : 'Tema', // from v2.1.43 added 19.10.2018 + 'default' : 'Varsayılan', // from v2.1.43 added 19.10.2018 + 'description' : 'Açıklama', // from v2.1.43 added 19.10.2018 + 'website' : 'Websayfası', // from v2.1.43 added 19.10.2018 + 'author' : 'Yazar', // from v2.1.43 added 19.10.2018 + 'email' : 'E-mail', // from v2.1.43 added 19.10.2018 + 'license' : 'Lisans', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Bu öğe kaydedilemez. Düzenlemeleri kaybetmemek için PC\'nize aktarmanız gerekir.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Dosyayı seçmek için çift tıklayın.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Tam ekran modunu kullan', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Bilinmiyor', + 'kindRoot' : 'Birim Kök dizini', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Dizin', + 'kindSelects' : 'Seçim', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias (Takma ad)', + 'kindAliasBroken' : 'Bozuk alias', + // applications + 'kindApp' : 'Uygulama', + 'kindPostscript' : 'Postscript dosyası', + 'kindMsOffice' : 'Microsoft Office dosyası', + 'kindMsWord' : 'Microsoft Word dosyası', + 'kindMsExcel' : 'Microsoft Excel dosyası', + 'kindMsPP' : 'Microsoft Powerpoint sunumu', + 'kindOO' : 'Open Office dosyası', + 'kindAppFlash' : 'Flash uygulaması', + 'kindPDF' : 'PDF', + 'kindTorrent' : 'Bittorrent dosyası', + 'kind7z' : '7z arşivi', + 'kindTAR' : 'TAR arşivi', + 'kindGZIP' : 'GZIP arşivi', + 'kindBZIP' : 'BZIP arşivi', + 'kindXZ' : 'XZ arşivi', + 'kindZIP' : 'ZIP arşivi', + 'kindRAR' : 'RAR arşivi', + 'kindJAR' : 'Java JAR dosyası', + 'kindTTF' : 'True Type fontu', + 'kindOTF' : 'Open Type fontu', + 'kindRPM' : 'RPM paketi', + // fonts + 'kindFont' : 'Fontu', + 'kindSFNT' : 'SFNT fontu', + 'kindEOT' : 'Embedded Open Type fontu', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Metin dosyası', + 'kindTextPlain' : 'Düz metin', + 'kindPHP' : 'PHP kodu', + 'kindCSS' : 'CSS dosyası', + 'kindHTML' : 'HTML dosyası', + 'kindJS' : 'Javascript kodu', + 'kindRTF' : 'Zengin Metin Belgesi', + 'kindC' : 'C kodu', + 'kindCHeader' : 'C başlık kodu', + 'kindCPP' : 'C++ kodu', + 'kindCPPHeader' : 'C++ başlık kodu', + 'kindShell' : 'Unix shell scripti', + 'kindPython' : 'Python kodu', + 'kindJava' : 'Java kodu', + 'kindRuby' : 'Ruby kodu', + 'kindPerl' : 'Perl scripti', + 'kindSQL' : 'SQL kodu', + 'kindXML' : 'XML dosyası', + 'kindAWK' : 'AWK kodu', + 'kindCSV' : 'CSV', + 'kindDOCBOOK' : 'Docbook XML dosyası', + 'kindMarkdown' : 'Markdown dosyası', // added 20.7.2015 + // images + 'kindImage' : 'Resim', + 'kindBMP' : 'BMP dosyası', + 'kindJPEG' : 'JPEG dosyası', + 'kindGIF' : 'GIF dosyası', + 'kindPNG' : 'PNG dosyası', + 'kindTIFF' : 'TIFF dosyası', + 'kindTGA' : 'TGA dosyası', + 'kindPSD' : 'Adobe Photoshop dosyası', + 'kindXBITMAP' : 'X bitmap dosyası', + 'kindPXM' : 'Pixelmator dosyası', + // media + 'kindAudio' : 'Ses ortamı', + 'kindAudioMPEG' : 'MPEG ses', + 'kindAudioMPEG4' : 'MPEG-4 ses', + 'kindAudioMIDI' : 'MIDI ses', + 'kindAudioOGG' : 'Ogg Vorbis ses', + 'kindAudioWAV' : 'WAV ses', + 'AudioPlaylist' : 'MP3 listesi', + 'kindVideo' : 'Video ortamı', + 'kindVideoDV' : 'DV video', + 'kindVideoMPEG' : 'MPEG video', + 'kindVideoMPEG4' : 'MPEG-4 video', + 'kindVideoAVI' : 'AVI video', + 'kindVideoMOV' : 'Quick Time video', + 'kindVideoWM' : 'Windows Media video', + 'kindVideoFlash' : 'Flash video', + 'kindVideoMKV' : 'Matroska video', + 'kindVideoOGG' : 'Ogg video' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.ug_CN.js b/lib/redactor/elfinder/js/i18n/elfinder.ug_CN.js new file mode 100644 index 0000000..7fc592b --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.ug_CN.js @@ -0,0 +1,381 @@ +/** + * Uyghur translation + * @author Alim.Boyaq + * @version 2014-12-19 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.ug_CN = { + translator : 'تەرجىمە قىلغۇچى: ئۆتكۈر بىز شىركىتى info@otkur.biz', + language : 'ئ‍ۇيغۇرچە', + direction : 'rtl', + dateFormat : 'Y-m-d H:i', + fancyDateFormat : '$1 H:i', + messages : { + + /********************************** errors **********************************/ + 'error' : 'خاتالىق', + 'errUnknown' : 'كۈتۈلمىگەن خاتالىقكەن.', + 'errUnknownCmd' : 'كۈتۈلمىگەن بۇيرۇقكەن.', + 'errJqui' : 'jQuery UI تەڭشىكى توغرا بولمىغان. چوقۇم Selectable، draggable، droppabl قاتارلىق بۆلەكلەر بولۇشى كېرەك.', + 'errNode' : 'elFinder DOM ئېلىمىنتلىرىنى قۇرالىشى كېرەك.', + 'errURL' : 'elFinder تەڭشىكى توغرا بولمىغان! URL تەڭشىكى يېزىلمىغان.', + 'errAccess' : 'زىيارەت قىلىش چەكلەنگەن.', + 'errConnect' : 'ئارقا سۇپىغا ئۇلاش مەغلۇپ بولدى..', + 'errAbort' : 'ئارقا سۇپىغا توختىتىلدى.', + 'errTimeout' : 'ئارقا سۇپىغا بەلگىلەنگەن ۋاقىتتا ئۇلىيالمىدى.', + 'errNotFound' : 'ئارقا سۇپا تېپىلمىدى.', + 'errResponse' : 'ئارقا سۇپىدىن توغرا بولمىغان ئىنكاس قايتتى.', + 'errConf' : 'ئارقا سۇپا تەڭشىكى توغرا ئەمەس.', + 'errJSON' : 'PHP JSON بۆلىكى قاچىلانمىغان.', + 'errNoVolumes' : 'ئوقۇشقا بولىدىغان ھۈججەت خالتىسى يوق.', + 'errCmdParams' : 'پارامېتىر خاتا، بۇيرۇق: "$1".', + 'errDataNotJSON' : 'ئارقا سۇپا قايتۇرغان سانلىق مەلۇمات توغرا بولغان JSON ئەمەسكەن.', + 'errDataEmpty' : 'ئارقا سۇپا قايتۇرغان سانلىق مەلۇمات قۇرۇقكەن.', + 'errCmdReq' : 'ئارقا سۇپىدىكى بۇيرۇقنىڭ ئ‍سىمى تەمىنلىنىشى كېرەك.', + 'errOpen' : '"$1"نى ئاچالمىدى.', + 'errNotFolder' : 'ئوبىكىت مۇندەرىجە ئەمەسكەن.', + 'errNotFile' : 'ئوبىكىت ھۈججەت ئەمەسكەن.', + 'errRead' : '"$1"نى ئوقۇيالمىدى.', + 'errWrite' : '"$1"نى يازالمىدى.', + 'errPerm' : 'ھوقۇق يوق.', + 'errLocked' : '"$1" تاقالغان,ئۆزگەرتەلمەيسىز.', + 'errExists' : '"$1" ناملىق ھۈججەت باركەن.', + 'errInvName' : 'توغرا بولمىغان ھۈججەت قىسقۇچ ئىسمى.', + 'errFolderNotFound' : 'ھۈججەت قىسقۇچنى تاپالمىدى.', + 'errFileNotFound' : 'ھۈججەتنى تاپالمىدى.', + 'errTrgFolderNotFound' : '"$1" ناملىق ھۈججەت قىسقۇچنى تاپالمىدى.', + 'errPopup' : 'سەكرەپ چىققان يېڭى بەتنى تور كۆرگۈچ كۆرسەتمىدى، ئۈستىدىكى ئەسكەرتىشتىن تور كۆرگۈچنى كۆرسىتىشكە تەڭشەڭ.', + 'errMkdir' : '"$1" ناملىق ھۈججەت قىسقۇچنى قۇرالمىدى.', + 'errMkfile' : '"$1" ناملىق ھۈججەتنى قۇرالمىدى.', + 'errRename' : '"$1" ناملىق ھۈججەتنىڭ ئىسمىنى يېڭىلاش مەغلۇپ بولدى.', + 'errCopyFrom' : ' "$1" ناملىق ئورۇندىن ھۈججەت كۆچۈرۈش چەكلەنگەن.', + 'errCopyTo' : '"$1" ناملىق ئورۇنغا ھۈججەت كۆچۈرۈش چەكلەنگەن.', + 'errUpload' : 'يۈكلەشتە خاتالىق كۆرۈلدى.', + 'errUploadFile' : '"$1" ناملىق ھۈججەتنى يۈكلەشتە خاتالىق كۆرۈلدى.', + 'errUploadNoFiles' : 'يۈكلىمەكچى بولغان ھۈججەت تېپىلمىدى.', + 'errUploadTotalSize' : 'سانلىق مەلۇمات چوڭلىقى چەكلىمىدىن ئېشىپ كەتكەن..', + 'errUploadFileSize' : 'ھۈججەت چوڭلىقى چەكلىمىدىن ئېشىپ كەتكەن..', + 'errUploadMime' : 'چەكلەنگەن ھۈججەت شەكلى.', + 'errUploadTransfer' : '"$1" ناملىق ھۈججەتنى يوللاشتا خاتالىق كۆرۈلدى.', + 'errNotReplace' : '"$1" ناملىق ھۈججەت باركەن، ئالماشتۇرۇشقا بولمايدۇ.', // new + 'errReplace' : '"$1" ناملىق ھۈججەتنى ئالماشتۇرۇش مەغلۇپ بولدى.', + 'errSave' : '"$1" ناملىق ھۈججەتنى ساقلاش مەغلۇپ بولدى.', + 'errCopy' : '"$1" ناملىق ھۈججەتنى كۆچۈرۈش مەغلۇپ بولدى.', + 'errMove' : '"$1" ناملىق ھۈججەتنى يۆتكەش مەغلۇپ بولدى.', + 'errCopyInItself' : '"$1" ناملىق ھۈججەتنى ئەسلى ئورنىغا يۆتكەش مەغلۇپ بولدى.', + 'errRm' : '"$1" ناملىق ھۈججەتنى ئۆچۈرۈش مەغلۇپ بولدى.', + 'errRmSrc' : 'ئەسلى ھۈججەتنى ئۆچۈرۈش مەغلۇپ بولدى.', + 'errExtract' : ' "$1" ناملىق مەلۇماتتىن ھۈججەت ئايرىش مەغلۇپ بولدى..', + 'errArchive' : 'پىرىسلانغان ھۈججەت ھاسىللاش مەغلۇپ بولدى.', + 'errArcType' : 'بۇ خىل پىرىسلانغان ھۈججەت شەكلىنى سىستېما بىر تەرەپ قىلالمىدى.', + 'errNoArchive' : 'ھۈججەت پىرىسلانغان ھۈججەت ئەمەس، ياكى توغرا پىرىسلانمىغان.', + 'errCmdNoSupport' : 'بۇ خىل بۇيرۇقنى بىر تەرەپ قىلالمىدى.', + 'errReplByChild' : '“$1” ناملىق ھۈججەت قىسقۇچنى ئالماشۇتۇرۇشقا بولمايدۇ.', + 'errArcSymlinks' : 'بىخەتەرلىك ئۈچۈن بۇ مەشغۇلات ئەمەلدىن قالدۇرۇلدى..', + 'errArcMaxSize' : 'پىرىسلانغان ھۈججەتنىڭ چوڭلىقى چەكلىمىدىن ئېشىپ كەنكەن.', + 'errResize' : ' "$1" چوڭلۇقنى تەڭشەشكە بولمىدى.', + 'errResizeDegree' : 'توغرا بولمىغان پىقىرىتىش گىرادۇسى', + 'errResizeRotate' : 'رەسىمنى پىقىرىتىشقا بولمىدى.', + 'errResizeSize' : 'توغرا بولمىغان رەسىم چوڭلىقى.', + 'errResizeNoChange' : 'رەسىم چوڭلىقى ئۆزگەرمىگەن.', + 'errUsupportType' : 'قوللىمايدىغان ھۈججەت شەكلى.', + 'errNotUTF8Content' : '"$1" ناملىق ھۈججەتنىڭ كودى UTF-8ئەمەسكەن، تەھرىرلىگىلى بولمايدۇ.', // added 9.11.2011 + 'errNetMount' : ' "$1" نى يۈكلەشتە خاتلىق يۈز بەردى..', // added 17.04.2012 + 'errNetMountNoDriver' : 'بۇ خىل پروتوكول قوللانمىدى..', // added 17.04.2012 + 'errNetMountFailed' : 'يۈكلەش مەغلۇپ بولدى.', // added 17.04.2012 + 'errNetMountHostReq' : 'مۇلازىمىتىرنى كۆرسىتىپ بېرىڭ.', // added 18.04.2012 + 'errSessionExpires' : 'Your session has expired due to inactivity.', + 'errCreatingTempDir' : 'Unable to create temporary directory: "$1"', + 'errFtpDownloadFile' : 'Unable to download file from FTP: "$1"', + 'errFtpUploadFile' : 'Unable to upload file to FTP: "$1"', + 'errFtpMkdir' : 'Unable to create remote directory on FTP: "$1"', + 'errArchiveExec' : 'Error while archiving files: "$1"', + 'errExtractExec' : 'Error while extracting files: "$1"', + + /******************************* commands names ********************************/ + 'cmdarchive' : 'پىرىسلاش', + 'cmdback' : 'قايتىش', + 'cmdcopy' : 'كۆچۈرۈش', + 'cmdcut' : 'كېسىش', + 'cmddownload' : 'چۈشۈرۈش', + 'cmdduplicate' : 'نۇسخىلاش', + 'cmdedit' : 'تەھرىرلەش', + 'cmdextract' : 'پىرىستىن ھۈججەت چىقىرىش', + 'cmdforward' : 'ئ‍الدىغا مېڭىش', + 'cmdgetfile' : 'تاللاش', + 'cmdhelp' : 'ئەپ ھەققىدە', + 'cmdhome' : 'باش بەت', + 'cmdinfo' : 'ئۇچۇرلىرى', + 'cmdmkdir' : 'يېڭى ھۈججەت قىسقۇچ', + 'cmdmkfile' : 'يېڭى ھۈججەت', + 'cmdopen' : 'ئېچىش', + 'cmdpaste' : 'چاپلاش', + 'cmdquicklook' : 'كۆرۈش', + 'cmdreload' : 'يېڭىلاش', + 'cmdrename' : 'نام يېڭىلاش', + 'cmdrm' : 'ئۆچۈرۈش', + 'cmdsearch' : 'ھۈججەت ئىزدەش', + 'cmdup' : 'ئالدىنقى مۇندەرىجىگە بېرىش', + 'cmdupload' : 'يۈكلەش', + 'cmdview' : 'كۆرۈش', + 'cmdresize' : 'چوڭلىقىنى تەڭشەش', + 'cmdsort' : 'تەرتىپ', + 'cmdnetmount' : 'توردىن قوشۇش', // added 18.04.2012 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'تاقاش', + 'btnSave' : 'ساقلاش', + 'btnRm' : 'ئۆچۈرۈش', + 'btnApply' : 'ئىشلىتىش', + 'btnCancel' : 'بېكارلاش', + 'btnNo' : 'ياق', + 'btnYes' : 'ھەئە', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'يۈكلەش', // added 18.04.2012 + + /******************************** notifications ********************************/ + 'ntfopen' : 'قىسقۇچنى ئېچىش', + 'ntffile' : 'ھۈججەتنى ئېچىش', + 'ntfreload' : 'يېڭىلاش', + 'ntfmkdir' : 'قىسقۇچ قۇرۇش', + 'ntfmkfile' : 'ھۈججەت قۇرۇش', + 'ntfrm' : 'ئۆچۈرۈش', + 'ntfcopy' : 'كۆچۈرۈش', + 'ntfmove' : 'يۆتكەش', + 'ntfprepare' : 'كۆچۈرۈش تەييارلىقى', + 'ntfrename' : 'نام يېڭىلاش', + 'ntfupload' : 'يۈكلەش', + 'ntfdownload' : 'چۈشۈرۈش', + 'ntfsave' : 'ساقلاش', + 'ntfarchive' : 'پىرىسلاش', + 'ntfextract' : 'پىرىستىن يېشىش', + 'ntfsearch' : 'ئىزدەش', + 'ntfresize' : 'چوڭلىقى ئۆزگەرتىلىۋاتىدۇ', + 'ntfsmth' : 'ئالدىراش >_<', + 'ntfloadimg' : 'رەسىم ئېچىلىۋاتىدۇ', + 'ntfnetmount' : 'تور ھۈججىتى يۈكلىنىۋاتىدۇ', // added 18.04.2012 + 'ntfdim' : 'Acquiring image dimension', + + /************************************ dates **********************************/ + 'dateUnknown' : 'ئېنىق ئەمەس', + 'Today' : 'بۈگۈن', + 'Yesterday' : 'تۆنۈگۈن', + 'msJan' : '1-ئاي', + 'msFeb' : '2-ئاي', + 'msMar' : '3-ئاي', + 'msApr' : '4-ئاي', + 'msMay' : '5-ئاي', + 'msJun' : '6-ئاي', + 'msJul' : '7-ئاي', + 'msAug' : '8-ئاي', + 'msSep' : '9-ئ‍اي', + 'msOct' : '10-ئاي', + 'msNov' : '11-ئاي', + 'msDec' : '12-ئاي', + 'January' : '1-ئاي', + 'February' : '2-ئاي', + 'March' : '3-ئاي', + 'April' : '4-ئاي', + 'May' : '5-ئاي', + 'June' : '6-ئاي', + 'July' : '7-ئاي', + 'August' : '8-ئاي', + 'September' : '9-ئاي', + 'October' : '10-ئاي', + 'November' : '11-ئاي', + 'December' : '12-ئاي', + 'Sunday' : 'يەكشەنبە', + 'Monday' : 'دۈشەنبە', + 'Tuesday' : 'سەيشەنبە', + 'Wednesday' : 'چارشەنبە', + 'Thursday' : 'پەيشەنبە', + 'Friday' : 'جۈمە', + 'Saturday' : 'شەنبە', + 'Sun' : 'يە', + 'Mon' : 'دۈ', + 'Tue' : 'سە', + 'Wed' : 'چا', + 'Thu' : 'پە', + 'Fri' : 'جۈ', + 'Sat' : 'شە', + + /******************************** sort variants ********************************/ + 'sortname' : 'نامى ', + 'sortkind' : 'شەكلى ', + 'sortsize' : 'چوڭلىقى', + 'sortdate' : 'ۋاقتى', + 'sortFoldersFirst' : 'قىسقۇچلار باشتا', + + /********************************** messages **********************************/ + 'confirmReq' : 'مۇقىملاشتۇرۇڭ', + 'confirmRm' : 'راستىنلا ئۆچۈرەمسىز?
                      كەينىگە قايتۇرغىلى بولمايدۇ!', + 'confirmRepl' : 'ھازىرقى ھۈججەت بىلەن كونىسىنى ئالماشتۇرامسىز?', + 'apllyAll' : 'ھەممىسىگە ئىشلىتىش', + 'name' : 'نامى', + 'size' : 'چوڭلىقى', + 'perms' : 'ھوقۇق', + 'modify' : 'ئۆزگەرگەن ۋاقتى', + 'kind' : 'تۈرى', + 'read' : 'ئوقۇش', + 'write' : 'يېزىش', + 'noaccess' : 'ھوقۇق يوق', + 'and' : 'ھەم', + 'unknown' : 'ئېنىق ئەمەس', + 'selectall' : 'ھەممىنى تاللاش', + 'selectfiles' : 'تاللاش', + 'selectffile' : 'بىرىنچىسىنى تاللاش', + 'selectlfile' : 'ئەڭ ئاخىرقىسىنى تاللاش', + 'viewlist' : 'جەدۋەللىك كۆرىنىشى', + 'viewicons' : 'رەسىملىك كۆرىنىشى', + 'places' : 'ئورنى', + 'calc' : 'ھېسابلاش', + 'path' : 'ئورنى', + 'aliasfor' : 'باشقا نامى', + 'locked' : 'تاقالغان', + 'dim' : 'چوڭلىقى', + 'files' : 'ھۈججەت', + 'folders' : 'قىسقۇچ', + 'items' : 'تۈرلەر', + 'yes' : 'ھەئە', + 'no' : 'ياق', + 'link' : 'ئۇلىنىش', + 'searcresult' : 'ئىزدەش نەتىجىسى', + 'selected' : 'تاللانغان تۈرلەر', + 'about' : 'چۈشەنچە', + 'shortcuts' : 'تېز كونۇپكىلار', + 'help' : 'ياردەم', + 'webfm' : 'تور ھۈججەتلىرىنى باشقۇرۇش', + 'ver' : 'نەشرى', + 'protocolver' : 'پروتوكول نەشرى', + 'homepage' : 'تۈر باش بېتى', + 'docs' : 'ھۈججەت', + 'github' : 'Fork us on Github', + 'twitter' : 'Follow us on twitter', + 'facebook' : 'Join us on facebook', + 'team' : 'گۇرۇپپا', + 'chiefdev' : 'باش پىروگراممىر', + 'developer' : 'پىروگراممىر', + 'contributor' : 'تۆھپىكار', + 'maintainer' : 'ئاسرىغۇچى', + 'translator' : 'تەرجىمان', + 'icons' : 'سىنبەلگە', + 'dontforget' : 'تەرىڭىزنى سۈرتىدىغان قولياغلىقىڭىزنى ئۇنۇتماڭ جۇمۇ', + 'shortcutsof' : 'تېز كونۇپكىلار چەكلەنگەن', + 'dropFiles' : 'ھۈججەتنى موشۇ يەرگە تاشلاڭ', + 'or' : 'ياكى', + 'selectForUpload' : 'يۈكلىمەكچى بولغان ھۈججەتنى تاللاڭ', + 'moveFiles' : 'يۆتكەش', + 'copyFiles' : 'كۆچۈرۈش', + 'rmFromPlaces' : 'ھۈججەتلەرنى ئۆچۈرۈش', + 'aspectRatio' : 'نىسبىتىنى ساقلاش', + 'scale' : 'نىسبىتى', + 'width' : 'ئۇزۇنلىقى', + 'height' : 'ئىگىزلىكى', + 'resize' : 'چوڭلىقىنى تەڭشەش', + 'crop' : 'كېسىش', + 'rotate' : 'پىقىرىتىش', + 'rotate-cw' : 'سائەت ئىستىرىلكىسى بويىچە 90 گىرادۇس پىقىرىتىش', + 'rotate-ccw' : 'سائەت ئىستىرىلكىسىنى تەتۈر يۆنىلىشى بويىچە 90گىرادۇس پىقىرىتىش', + 'degree' : 'گىرادۇس', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'پىروتوكڭل', // added 18.04.2012 + 'host' : 'مۇلازىمىتىر', // added 18.04.2012 + 'port' : 'پورت', // added 18.04.2012 + 'user' : 'ئەزا', // added 18.04.2012 + 'pass' : 'ئىم', // added 18.04.2012 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'ئېنىق ئەمەس', + 'kindFolder' : 'ھۈججەت قىسقۇچ', + 'kindAlias' : 'باشقا نامى', + 'kindAliasBroken' : 'باشقا نامى خاتا', + // applications + 'kindApp' : 'كود ھۈججىتى', + 'kindPostscript' : 'Postscript ھۈججىتى', + 'kindMsOffice' : 'Microsoft Office ھۈججىتى', + 'kindMsWord' : 'Microsoft Word ھۈججىتى', + 'kindMsExcel' : 'Microsoft Excel ھۈججىتى', + 'kindMsPP' : 'Microsoft Powerpoint ھۈججىتى', + 'kindOO' : 'Open Office ھۈججىتى', + 'kindAppFlash' : 'Flash ھۈججىتى', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent ھۈججىتى', + 'kind7z' : '7z ھۈججىتى', + 'kindTAR' : 'TAR ھۈججىتى', + 'kindGZIP' : 'GZIP ھۈججىتى', + 'kindBZIP' : 'BZIP ھۈججىتى', + 'kindXZ' : 'XZ ھۈججىتى', + 'kindZIP' : 'ZIP ھۈججىتى', + 'kindRAR' : 'RAR ھۈججىتى', + 'kindJAR' : 'Java JAR ھۈججىتى', + 'kindTTF' : 'True Type فونت', + 'kindOTF' : 'Open Type فونت', + 'kindRPM' : 'RPM', + // fonts + 'kindFont' : 'فونت', + 'kindSFNT' : 'SFNT فونت', + 'kindEOT' : 'Embedded Open Type فونت', + 'kindWOFF' : 'Web Open Font Format فونت', + 'kindWOFF2' : 'Web Open Font Format 2 فونت', + // texts + 'kindText' : 'تېكىست', + 'kindTextPlain' : 'تېكىست', + 'kindPHP' : 'PHP ھۈججىتى', + 'kindCSS' : 'CSS ھۈججىتى', + 'kindHTML' : 'HTML ھۈججىتى', + 'kindJS' : 'Javascript ھۈججىتى', + 'kindRTF' : 'RTF ھۈججىتى', + 'kindC' : 'C ھۈججىتى', + 'kindCHeader' : 'C باش ھۈججىتى', + 'kindCPP' : 'C++ ھۈججىتى', + 'kindCPPHeader' : 'C++ باش ھۈججىتى', + 'kindShell' : 'Unix سىكىرىپت ھۈججىتى', + 'kindPython' : 'Python ھۈججىتى', + 'kindJava' : 'Java ھۈججىتى', + 'kindRuby' : 'Ruby ھۈججىتى', + 'kindPerl' : 'Perl ھۈججىتى', + 'kindSQL' : 'SQL ھۈججىتى', + 'kindXML' : 'XML ھۈججىتى', + 'kindAWK' : 'AWK ھۈججىتى', + 'kindCSV' : 'CSV ھۈججىتى', + 'kindDOCBOOK' : 'Docbook XML ھۈججىتى', + // images + 'kindImage' : 'رەسىم', + 'kindBMP' : 'BMP رەسىم', + 'kindJPEG' : 'JPEG رەسىم', + 'kindGIF' : 'GIF رەسىم', + 'kindPNG' : 'PNG رەسىم', + 'kindTIFF' : 'TIFF رەسىم', + 'kindTGA' : 'TGA رەسىم', + 'kindPSD' : 'Adobe Photoshop رەسىم', + 'kindXBITMAP' : 'X bitmap رەسىم', + 'kindPXM' : 'Pixelmator رەسىم', + // media + 'kindAudio' : 'ئاۋاز', + 'kindAudioMPEG' : 'MPEG ئاۋاز', + 'kindAudioMPEG4' : 'MPEG-4 ئاۋاز', + 'kindAudioMIDI' : 'MIDI ئاۋاز', + 'kindAudioOGG' : 'Ogg Vorbis ئاۋاز', + 'kindAudioWAV' : 'WAV ئاۋاز', + 'AudioPlaylist' : 'MP3 قويۇش تىزىملىكى', + 'kindVideo' : 'سىن', + 'kindVideoDV' : 'DV سىن', + 'kindVideoMPEG' : 'MPEG سىن', + 'kindVideoMPEG4' : 'MPEG-4 سىن', + 'kindVideoAVI' : 'AVI سىن', + 'kindVideoMOV' : 'Quick Time سىن', + 'kindVideoWM' : 'Windows Media سىن', + 'kindVideoFlash' : 'Flash سىن', + 'kindVideoMKV' : 'Matroska سىن', + 'kindVideoOGG' : 'Ogg سىن' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.uk.js b/lib/redactor/elfinder/js/i18n/elfinder.uk.js new file mode 100644 index 0000000..b02751a --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.uk.js @@ -0,0 +1,587 @@ +/** + * Українська мова translation + * @author ITLancer + * @author cjayho + * @version 2020-02-10 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.uk = { + translator : 'ITLancer, cjayho <cj.fooser@gmail.com>', + language : 'Українська мова', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // will show like: 10.02.2020 16:52 + fancyDateFormat : '$1 H:i', // will show like: сьогодні 16:52 + nonameDateFormat : 'ymd-His', // noname upload will show like: 200210-165246 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Помилка', + 'errUnknown' : 'Невідома помилка.', + 'errUnknownCmd' : 'Невідома команда.', + 'errJqui' : 'Неправильне налаштування jQuery UI. Відсутні компоненти: selectable, draggable, droppable.', + 'errNode' : 'Відсутній елемент DOM для створення elFinder.', + 'errURL' : 'Неправильне налаштування! Не вказана опція URL.', + 'errAccess' : 'Доступ заборонено.', + 'errConnect' : 'Не вдалося з’єднатися з backend.', + 'errAbort' : 'З’єднання розірване.', + 'errTimeout' : 'Тайм-аут з’єднання.', + 'errNotFound' : 'Не знайдено backend.', + 'errResponse' : 'Неправильна відповідь від backend.', + 'errConf' : 'Неправильне налаштування backend.', + 'errJSON' : 'Модуль PHP JSON не встановлено.', + 'errNoVolumes' : 'Немає доступних для читання директорій.', + 'errCmdParams' : 'Неправильні параметри для команди "$1".', + 'errDataNotJSON' : 'Дані не у форматі JSON.', + 'errDataEmpty' : 'Дані відсутні.', + 'errCmdReq' : 'Backend вимагає назву команди.', + 'errOpen' : 'Неможливо відкрити "$1".', + 'errNotFolder' : 'Об’єкт не є папкою.', + 'errNotFile' : 'Об’єкт не є файлом.', + 'errRead' : 'Неможливо прочитати "$1".', + 'errWrite' : 'Неможливо записати в "$1".', + 'errPerm' : 'Помилка доступу.', + 'errLocked' : 'Файл "$1" заблоковано і його неможливо перемістити, перейменувати чи вилучити.', + 'errExists' : 'Файл з назвою "$1" вже існує.', + 'errInvName' : 'Недійсна назва файла.', + 'errInvDirname' : 'Недійсна назва теки.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Теку не знайдено.', + 'errFileNotFound' : 'Файл не знайдено.', + 'errTrgFolderNotFound' : 'Цільову теку "$1" не знайдено.', + 'errPopup' : 'Браузер забороняє відкривати popup-вікно. Дозвольте у налаштування браузера, щоб відкрити файл.', + 'errMkdir' : 'Неможливо створити теку "$1".', + 'errMkfile' : 'Неможливо створити файл "$1".', + 'errRename' : 'Неможливо перейменувати файл "$1".', + 'errCopyFrom' : 'Копіювання файлів з тому "$1" не дозволено.', + 'errCopyTo' : 'Копіювання файлів на том "$1" не дозволено.', + 'errMkOutLink' : 'Неможливо створити посилання у місце за межами кореневої теки носія.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Помилка відвантаження.', // old name - errUploadCommon + 'errUploadFile' : 'Неможливо відвантажити файл "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Не знайдено файлів для відвантаження.', + 'errUploadTotalSize' : 'Об\'єм даних перевищив встановлений ліміт.', // old name - errMaxSize + 'errUploadFileSize' : 'Об\'єм файла перевищив встановлений ліміт.', // old name - errFileMaxSize + 'errUploadMime' : 'Файли цього типу заборонені.', + 'errUploadTransfer' : '"$1" : помилка передачі.', + 'errUploadTemp' : 'Неможливо створити тимчасовий файл для відвантаження.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Об\'єкт "$1" вже існує тут та не може бути заміненим на об\'єкт іншого типу.', // new + 'errReplace' : 'Неможливо замінити "$1".', + 'errSave' : 'Неможливо записати "$1".', + 'errCopy' : 'Неможливо скопіювати "$1".', + 'errMove' : 'Неможливо перенести "$1".', + 'errCopyInItself' : 'Неможливо скопіювати "$1" сам у себе.', + 'errRm' : 'Неможливо вилучити "$1".', + 'errTrash' : 'Неможливо пересунути до смітника.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Неможливо видалити оригінальний(і) файл(и).', + 'errExtract' : 'Неможливо розпакувати файли з "$1".', + 'errArchive' : 'Неможливо створити архів.', + 'errArcType' : 'Тип архіву не підтримується.', + 'errNoArchive' : 'Файл не є архівом, або є архівом, тип якого не підтримується.', + 'errCmdNoSupport' : 'Серверна частина не підтримує цієї команди.', + 'errReplByChild' : 'Папка “$1” не може бути замінена елементом, який вона містить.', + 'errArcSymlinks' : 'З міркувань безпеки заборонено розпаковувати архіви з символічними посиланнями.', // edited 24.06.2012 + 'errArcMaxSize' : 'Розмір файлів архіву перевищує допустиме значення.', + 'errResize' : 'Неможливо масштабувати "$1".', + 'errResizeDegree' : 'Недійсний кут обертання.', // added 7.3.2013 + 'errResizeRotate' : 'Неможливо повернути світлину.', // added 7.3.2013 + 'errResizeSize' : 'Недійсний розмір світлини.', // added 7.3.2013 + 'errResizeNoChange' : 'Розмір світлини не змінено.', // added 7.3.2013 + 'errUsupportType' : 'Непідтримуваний тип файла.', + 'errNotUTF8Content' : 'Файл "$1" не в UTF-8 і не може бути відредагований.', // added 9.11.2011 + 'errNetMount' : 'Неможливо змонтувати "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Непідтримуваний протокл.', // added 17.04.2012 + 'errNetMountFailed' : 'В процесі монтування сталася помилка.', // added 17.04.2012 + 'errNetMountHostReq' : 'Необхідно вказати хост.', // added 18.04.2012 + 'errSessionExpires' : 'Час сеансу минув через неактивність.', + 'errCreatingTempDir' : 'НЕможливо створити тимчасову директорію: "$1"', + 'errFtpDownloadFile' : 'Неможливо завантажити файл з FTP: "$1"', + 'errFtpUploadFile' : 'Неможливо завантажити файл на FTP: "$1"', + 'errFtpMkdir' : 'Неможливо створити віддалений каталог на FTP: "$1"', + 'errArchiveExec' : 'Помилка при архівації файлів: "$1"', + 'errExtractExec' : 'Помилка при розархівуванні файлів: "$1"', + 'errNetUnMount' : 'Неможливо демонтувати', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Неможливо конвертувати в UTF - 8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Використовуйте Google Chrome, якщо ви хочете завантажити папку', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Час пошуку "$1" вийшов. Результат пошуку частковий', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Необхідна повторна авторизація.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Максимальна кількість об\'єктів що можна обрати складає $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Неможливо відновити зі смітника: неможливо визначити місце куди відновлювати.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Для цього типу файлів не знайдено редактора.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Помилка на боці сервера.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Неможливо спорожнити теку "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Є також ще $1 помилок.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Архівувати', + 'cmdback' : 'Назад', + 'cmdcopy' : 'Копівати', + 'cmdcut' : 'Вирізати', + 'cmddownload' : 'Завантажити', + 'cmdduplicate' : 'Дублювати', + 'cmdedit' : 'Редагувати файл', + 'cmdextract' : 'Розпакувати файли з архіву', + 'cmdforward' : 'Вперед', + 'cmdgetfile' : 'Вибрати файли', + 'cmdhelp' : 'Про програму', + 'cmdhome' : 'Додому', + 'cmdinfo' : 'Інформація', + 'cmdmkdir' : 'Створити теку', + 'cmdmkdirin' : 'До нової теки', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Створити файл', + 'cmdopen' : 'Відкрити', + 'cmdpaste' : 'Вставити', + 'cmdquicklook' : 'Попередній перегляд', + 'cmdreload' : 'Перечитати', + 'cmdrename' : 'Перейменувати', + 'cmdrm' : 'Вилучити', + 'cmdtrash' : 'До смітника', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Відновити', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Шукати файли', + 'cmdup' : 'На 1 рівень вгору', + 'cmdupload' : 'Відвантажити файли', + 'cmdview' : 'Перегляд', + 'cmdresize' : 'Масштабувати зображення', + 'cmdsort' : 'Сортування', + 'cmdnetmount' : 'Змонтувати мережевий диск', // added 18.04.2012 + 'cmdnetunmount': 'Розмонтувати', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'До Місць', // added 28.12.2014 + 'cmdchmod' : 'Змінити права', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Відкрии директорію', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Скинути ширину стовпчика', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Повний екран', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Пересунути', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Спорожнити теку', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Скасувати', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Відновити', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Налаштування', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Вибрати усі', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Зняти вибір', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Інвертувати вибір', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Відкрити у новому вікні', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Сховати (Налаштування)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Закрити', + 'btnSave' : 'Зберегти', + 'btnRm' : 'Вилучити', + 'btnApply' : 'Застосувати', + 'btnCancel' : 'Скасувати', + 'btnNo' : 'Ні', + 'btnYes' : 'Так', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Підключити', // added 18.04.2012 + 'btnApprove': 'Перейти в $1 і прийняти', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Відключити', // from v2.1 added 30.04.2012 + 'btnConv' : 'Конвертувати', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Тут', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Розділ', // from v2.1 added 22.5.2015 + 'btnAll' : 'Всі', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME тип', // from v2.1 added 22.5.2015 + 'btnFileName':'Назва файла', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Зберегти і вийти', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Резервна копія', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Перейменувати', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Перейменуваті(Усі)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Попер. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Наступ. ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Зберегти як', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Відкрити теку', + 'ntffile' : 'Відкрити файл', + 'ntfreload' : 'Перечитати вміст теки', + 'ntfmkdir' : 'Створення теки', + 'ntfmkfile' : 'Створення файлів', + 'ntfrm' : 'Вилучити файли', + 'ntfcopy' : 'Копіювати файли', + 'ntfmove' : 'Перенести файли', + 'ntfprepare' : 'Підготовка до копіювання файлів', + 'ntfrename' : 'Перейменувати файли', + 'ntfupload' : 'Відвантажити файли', + 'ntfdownload' : 'Завантажити файли', + 'ntfsave' : 'Записати файли', + 'ntfarchive' : 'Створення архіву', + 'ntfextract' : 'Розпаковування архіву', + 'ntfsearch' : 'Пошук файлів', + 'ntfresize' : 'Зміна розміру світлини', + 'ntfsmth' : 'Виконуємо', + 'ntfloadimg' : 'Завантаження зображення', + 'ntfnetmount' : 'Монтування мережевого диска', // added 18.04.2012 + 'ntfnetunmount': 'Розмонтування мережевого диска', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Визначення розміру світлини', // added 20.05.2013 + 'ntfreaddir' : 'Читання інформації директорії', // from v2.1 added 01.07.2013 + 'ntfurl' : 'отримання URL посилання', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Зміна прав файлу', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Перевірка імені завантажуваного файла', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Створення файлу для завантаження', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Отримання інформації про шлях', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Обробка вивантаженого файлу', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Переміщуємо до смітника', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Відновлюємо зі смітника', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Перевіряємо теку призначення', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Скасування попередньої дії', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Повторення раніше скасованої дії', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Перевірка вмісту', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Смітник', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'невідомо', + 'Today' : 'сьогодні', + 'Yesterday' : 'вчора', + 'msJan' : 'Січ', + 'msFeb' : 'Лют', + 'msMar' : 'Бер', + 'msApr' : 'Кві', + 'msMay' : 'Тра', + 'msJun' : 'Чер', + 'msJul' : 'Лип', + 'msAug' : 'Сер', + 'msSep' : 'Вер', + 'msOct' : 'Жов', + 'msNov' : 'Лис', + 'msDec' : 'Гру', + 'January' : 'січня', + 'February' : 'лютого', + 'March' : 'березня', + 'April' : 'квітня', + 'May' : 'травня', + 'June' : 'червня', + 'July' : 'липня', + 'August' : 'серпня', + 'September' : 'вересня', + 'October' : 'жовтня', + 'November' : 'листопада', + 'December' : 'грудня', + 'Sunday' : 'Неділя', + 'Monday' : 'Понеділок', + 'Tuesday' : 'Вівторок', + 'Wednesday' : 'Середа', + 'Thursday' : 'Четвер', + 'Friday' : 'П’ятниця', + 'Saturday' : 'Субота', + 'Sun' : 'Нд', + 'Mon' : 'Пн', + 'Tue' : 'Вт', + 'Wed' : 'Ср', + 'Thu' : 'Чт', + 'Fri' : 'Пт', + 'Sat' : 'Сб', + + /******************************** sort variants ********************************/ + 'sortname' : 'за назвою', + 'sortkind' : 'за типом', + 'sortsize' : 'за розміром', + 'sortdate' : 'за датою', + 'sortFoldersFirst' : 'Список тек', + 'sortperm' : 'за дозволами', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'за режимом', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'за власником', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'за групою', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Також вигляд дерева', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'неназваний файл.txt', // added 10.11.2015 + 'untitled folder' : 'неназвана тека', // added 10.11.2015 + 'Archive' : 'НовийАрхів', // from v2.1 added 10.11.2015 + 'untitled file' : 'НовийФайл.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: Файл', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2 ', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Необхідне підтвердження', + 'confirmRm' : 'Ви справді хочете вилучити файли?
                      Операція незворотня!', + 'confirmRepl' : 'Замінити старий файл новим? (при наявності тек вони будуть об\'єднані. Для резервної копії та заміни оберіть Резервну Копію)', + 'confirmRest' : 'Замінити існуючий об\'єкт об\'єктом зі смітника?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Не у UTF-8
                      Конвертувати у UTF-8?
                      Вміст стане у UTF-8 збереженням після конвертації.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Кодування символів цього файлу неможливо визначити. Потрібно тимчасово конвертувати його у UTF-8 для редагування.
                      Оберіть кодування цього файлу.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'Було внесено зміни.
                      Якщо ії не зберегти, їх буде втрачено.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Ви точно бажаєте перемістити ці об\'єкти до смітника?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Ви точно бажаєте перемістити об\'єкти до "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Застосувати до всіх', + 'name' : 'Назва', + 'size' : 'Розмір', + 'perms' : 'Доступи', + 'modify' : 'Змінено', + 'kind' : 'Тип', + 'read' : 'читання', + 'write' : 'запис', + 'noaccess' : 'недоступно', + 'and' : 'і', + 'unknown' : 'невідомо', + 'selectall' : 'Вибрати всі файли', + 'selectfiles' : 'Вибрати файл(и)', + 'selectffile' : 'Вибрати перший файл', + 'selectlfile' : 'Вибрати останній файл', + 'viewlist' : 'Списком', + 'viewicons' : 'Значками', + 'viewSmall' : 'Маленькі значки', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Середні значки', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Великі значки', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Дуже великі значки', // from v2.1.39 added 22.5.2018 + 'places' : 'Розташування', + 'calc' : 'Вирахувати', + 'path' : 'Шлях', + 'aliasfor' : 'Аліас для', + 'locked' : 'Заблоковано', + 'dim' : 'Розміри', + 'files' : 'Файли', + 'folders' : 'теки', + 'items' : 'Елементи', + 'yes' : 'так', + 'no' : 'ні', + 'link' : 'Посилання', + 'searcresult' : 'Результати пошуку', + 'selected' : 'Вибрані елементи', + 'about' : 'Про', + 'shortcuts' : 'Ярлики', + 'help' : 'Допомога', + 'webfm' : 'Web-менеджер файлів', + 'ver' : 'Версія', + 'protocolver' : 'версія протоколу', + 'homepage' : 'Сторінка проекту', + 'docs' : 'Документація', + 'github' : 'Fork us on Github', + 'twitter' : 'Слідкуйте у Твітері', + 'facebook' : 'Приєднуйтесь у фейсбуці', + 'team' : 'Автори', + 'chiefdev' : 'головний розробник', + 'developer' : 'розробник', + 'contributor' : 'учасник', + 'maintainer' : 'супроводжувач', + 'translator' : 'перекладач', + 'icons' : 'Значки', + 'dontforget' : 'і не забудьте рушничок', + 'shortcutsof' : 'Створення посилань вимкнено', + 'dropFiles' : 'Кидайте файли сюди', + 'or' : 'або', + 'selectForUpload' : 'Виберіть файли для відвантаження', + 'moveFiles' : 'Перемістити файли', + 'copyFiles' : 'Копіювати файли', + 'restoreFiles' : 'Відновити об\'єкти', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Вилучити з розташувань', + 'aspectRatio' : 'Співвідношення', + 'scale' : 'Масштаб', + 'width' : 'Ширина', + 'height' : 'Висота', + 'resize' : 'Змінити розмір', + 'crop' : 'Обрізати', + 'rotate' : 'Повернути', + 'rotate-cw' : 'Повернути на 90 градусів за год. стр.', + 'rotate-ccw' : 'Повернути на 90 градусів проти год. стр.', + 'degree' : 'Градус', + 'netMountDialogTitle' : 'Змонтувати носій у мережі', // added 18.04.2012 + 'protocol' : 'версія протоколу', // added 18.04.2012 + 'host' : 'Хост', // added 18.04.2012 + 'port' : 'Порт', // added 18.04.2012 + 'user' : 'Логін', // added 18.04.2012 + 'pass' : 'Пароль', // added 18.04.2012 + 'confirmUnmount' : 'Ви відмонтовуєте $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Перетягніть або вставте файли з оглядача', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Перетягніть файли, Вставте URL або світлини (з буфера обміну) сюди', // from v2.1 added 07.04.2014 + 'encoding' : 'Кодування', // from v2.1 added 19.12.2014 + 'locale' : 'Локаль', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Призначення: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Пошук за введеним типом MIME', // from v2.1 added 22.5.2015 + 'owner' : 'Власник', // from v2.1 added 20.6.2015 + 'group' : 'Група', // from v2.1 added 20.6.2015 + 'other' : 'Інші', // from v2.1 added 20.6.2015 + 'execute' : 'Виконання', // from v2.1 added 20.6.2015 + 'perm' : 'Дозвіл', // from v2.1 added 20.6.2015 + 'mode' : 'Режим', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Тека порожня', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Тека порожня\\A Перетягніть об\'єкти для додавання', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Тека порожня\\A Для додавання об\'єктів торкніть та утримуйте', // from v2.1.6 added 30.12.2015 + 'quality' : 'Якість', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Авто синх.', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Пересунути вгору', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Отримати URL', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Обрані об\'єкти ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID теки', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Дозволити доступ офлайн', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Для реаутентифікації', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Зараз завантажуємо...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Відкрити декілька файлів', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'Ви намагаєтесь відкрити $1 файлів. Ви впевнені що хочете відкрити ії у оглядачі?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Пошук не дав результатів у обраному місці.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Редагує файл.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'Ви обрали $1 об\'єктів.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'У вас є $1 об\'єктів у буфері обміну.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Інкрементний пошук є тільки для поточного перегляду.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Відновити', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 виконано', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Контекстне меню', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Обертання сторінки', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Кореневі теки носіїв', // from v2.1.16 added 16.9.2016 + 'reset' : 'Обнулити', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Колір фону', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Обрати колір', // from v2.1.16 added 1.10.2016 + '8pxgrid' : 'сітка 8px', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Увімкнено', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Вимкнено', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Результати пошуку у поточному перегляді відсутні.\\AНатисніть [Enter] для розширення критеріїв пошуку.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Результати пошуку за першою літерою відсутні у поточному перегляді.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Текстова мітка', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 хв. залишилось', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Відкрити знову з обраним кодуванням', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Зберегти з обраним кодуванням', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Обрати теку', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'Пошук за першою літерою', // from v2.1.23 added 24.3.2017 + 'presets' : 'Шаблони', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Дуже багато об\'єктів для переміщення у смітник.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'ТекстовеПоле', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Спорожнити теку "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'Тека "$1" порожня.', // from v2.1.25 added 22.6.2017 + 'preference' : 'Налаштування', // from v2.1.26 added 28.6.2017 + 'language' : 'Мова', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Ініціювати налаштування збережені у цьому оглядачі', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Налаштування лотку інструментів', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 символів залишилось.', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... $1 рядків залишилось.', // from v2.1.52 added 16.1.2020 + 'sum' : 'Сума', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Приблизний розмір файу', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Фокусувати елемент діалога при наведенні курсора миші', // from v2.1.30 added 2.11.2017 + 'select' : 'Обрати', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Дія при виборі файла', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Відкрити редактором, що використовувався крайній раз.', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Інвертувати вибір', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Ви точно хочете перейменувати $1 обраних об\'єктів на кшталт $2?
                      Це незворотна дія!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Пакетне перейменування', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Число', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Додати префікс', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Додати суфікс', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Змінити розширення', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Налаштування стовпчиків (вигляд списку)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'Усі зміни будуть негайно застосовані у архіві.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Деякі зміни не буде видно до розмонтування носія.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'Наступний(і) носій(ї) на цьому носії також не змонтовані. Ви точно хочете відмонтувати носій?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Інформація про обране', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Алгоритми для показу хешу файла', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Інформаційні об\'єкти (Панель інформації про обране)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Натисніть знову для виходу.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Панель інструментів', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Робочий простір', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Діалог', // from v2.1.38 added 4.4.2018 + 'all' : 'Усі', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Розмір значків (вигляд значків)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Відкрити розгорнуте вікно редактора', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Через неможливість конвертування API, сконвертуйте на вебсайті.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'Після конвертування вам треба завантажити за допомогою URL або збереженого файу, для збереження конвертованого файлу.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Конвертувати сайт з $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Інтеграції', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'Цей elFinder має наступні інтегровані сервіси. Перевірте умови використання, політику приватності та інше перед використанням.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Показати приховані об\'єкти', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Сховати приховані об\'єкти', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Показати/Сховати приховані о\'єкти', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'Типи файлів, які можна створювати', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Тип текстового файлу', // from v2.1.41 added 7.8.2018 + 'add' : 'Додати', // from v2.1.41 added 7.8.2018 + 'theme' : 'Тема', // from v2.1.43 added 19.10.2018 + 'default' : 'Як зазвичай', // from v2.1.43 added 19.10.2018 + 'description' : 'Опис', // from v2.1.43 added 19.10.2018 + 'website' : 'Веб-сайт', // from v2.1.43 added 19.10.2018 + 'author' : 'Автор', // from v2.1.43 added 19.10.2018 + 'email' : 'E-mail', // from v2.1.43 added 19.10.2018 + 'license' : 'Ліцензія', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'Об\'єкт неможливо зберегти. Щоб уникнути втрати правок вам треба експортувати ії до себе у пристрій.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Двічі клацніть файл для вибору.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Використовувати повноекранний режим', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Невідомо', + 'kindRoot' : 'Коренева тека носія', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Папка', + 'kindSelects' : 'Вибір', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Аліас', + 'kindAliasBroken' : 'Пошкоджений аліас', + // applications + 'kindApp' : 'Програма', + 'kindPostscript' : 'Документ Postscript', + 'kindMsOffice' : 'Документ Microsoft Office', + 'kindMsWord' : 'Документ Microsoft Word', + 'kindMsExcel' : 'Документ Microsoft Excel', + 'kindMsPP' : 'Презентація Microsoft Powerpoint', + 'kindOO' : 'Документ Open Office', + 'kindAppFlash' : 'Flash-додаток', + 'kindPDF' : 'Портативний формат документів (PDF)', + 'kindTorrent' : 'Файл Bittorrent', + 'kind7z' : 'Архів 7z', + 'kindTAR' : 'Архів TAR', + 'kindGZIP' : 'Архів GZIP', + 'kindBZIP' : 'Архів BZIP', + 'kindXZ' : 'Архів XZ', + 'kindZIP' : 'Архів ZIP', + 'kindRAR' : 'Архів RAR', + 'kindJAR' : 'Файл Java JAR', + 'kindTTF' : 'Шрифт True Type', + 'kindOTF' : 'Шрифт Open Type', + 'kindRPM' : 'Пакунок RPM', + // fonts + 'kindFont' : 'Шрифт', + 'kindSFNT' : 'Шрифт SFNT', + 'kindEOT' : 'Шрифт Embedded Open Type', + 'kindWOFF' : 'Шрифт Web Open Font Format', + 'kindWOFF2' : 'Шрифт Web Open Font Format 2', + // texts + 'kindText' : 'Текстовий документ', + 'kindTextPlain' : 'Простий текст', + 'kindPHP' : 'Код PHP', + 'kindCSS' : 'Каскадна таблиця стилів (CSS)', + 'kindHTML' : 'Документ HTML', + 'kindJS' : 'Код Javascript', + 'kindRTF' : 'Файл RTF', + 'kindC' : 'Код C', + 'kindCHeader' : 'Заголовковий код C', + 'kindCPP' : 'Код C++', + 'kindCPPHeader' : 'Заголовковий код C++', + 'kindShell' : 'Скрипт Unix shell', + 'kindPython' : 'Код Python', + 'kindJava' : 'Код Java', + 'kindRuby' : 'Код Ruby', + 'kindPerl' : 'Код Perl', + 'kindSQL' : 'Код SQL', + 'kindXML' : 'Документ XML', + 'kindAWK' : 'Код AWK', + 'kindCSV' : 'Значення розділені комою (CSV)', + 'kindDOCBOOK' : 'Документ Docbook XML', + 'kindMarkdown' : 'Текст Markdown', // added 20.7.2015 + // images + 'kindImage' : 'Зображення', + 'kindBMP' : 'Зображення BMP', + 'kindJPEG' : 'Зображення JPEG', + 'kindGIF' : 'Зображення GIF', + 'kindPNG' : 'Зображення PNG', + 'kindTIFF' : 'Зображення TIFF', + 'kindTGA' : 'Зображення TGA', + 'kindPSD' : 'Зображення Adobe Photoshop', + 'kindXBITMAP' : 'Зображення X bitmap', + 'kindPXM' : 'Зображення Pixelmator', + // media + 'kindAudio' : 'Аудіо', + 'kindAudioMPEG' : 'Аудіо MPEG', + 'kindAudioMPEG4' : 'Аудіо MPEG-4', + 'kindAudioMIDI' : 'Аудіо MIDI', + 'kindAudioOGG' : 'Аудіо Ogg Vorbis', + 'kindAudioWAV' : 'Аудіо WAV', + 'AudioPlaylist' : 'Список відтворення MP3', + 'kindVideo' : 'Відео', + 'kindVideoDV' : 'Відео DV', + 'kindVideoMPEG' : 'Відео MPEG', + 'kindVideoMPEG4' : 'Відео MPEG-4', + 'kindVideoAVI' : 'Відео AVI', + 'kindVideoMOV' : 'Відео Quick Time', + 'kindVideoWM' : 'Відео Windows Media', + 'kindVideoFlash' : 'Відео Flash', + 'kindVideoMKV' : 'Відео Matroska', + 'kindVideoOGG' : 'Відео Ogg' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.vi.js b/lib/redactor/elfinder/js/i18n/elfinder.vi.js new file mode 100644 index 0000000..d53912f --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.vi.js @@ -0,0 +1,586 @@ +/** + * Ngôn ngữ Việt Nam translation + * @author Chung Thủy f + * @author Son Nguyen + * @author Nguyễn Trần Chung + * @version 2019-12-03 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.vi = { + translator : 'Chung Thủy f <chungthuyf@gmail.com>, Son Nguyen <son.nguyen@catalyst.net.nz>, Nguyễn Trần Chung <admin@chungnguyen.xyz>', + language : 'Ngôn ngữ Việt Nam', + direction : 'ltr', + dateFormat : 'd.m.Y H:i', // will show like: 03.12.2019 17:28 + fancyDateFormat : '$1 H:i', // will show like: Hôm nay 17:28 + nonameDateFormat : 'ymd-His', // noname upload will show like: 191203-172820 + messages : { + + /********************************** errors **********************************/ + 'error' : 'Lỗi', + 'errUnknown' : 'Lỗi không xác định được.', + 'errUnknownCmd' : 'Lỗi không rõ lệnh.', + 'errJqui' : 'Cấu hình jQueryUI không hợp lệ. Các thành phần lựa chọn, kéo và thả phải được bao gồm.', + 'errNode' : 'elFinder đòi hỏi phần tử DOM phải được tạo ra.', + 'errURL' : 'Cấu hình elFinder không hợp lệ! URL không được thiết lập tùy chọn.', + 'errAccess' : 'Truy cập bị từ chối.', + 'errConnect' : 'Không thể kết nối với backend.', + 'errAbort' : 'Kết nối bị hủy bỏ.', + 'errTimeout' : 'Thời gian chờ kết nối đã hết.', + 'errNotFound' : 'Backend không tìm thấy.', + 'errResponse' : 'Phản hồi backend không hợp lệ.', + 'errConf' : 'Cấu hình backend không hợp lệ.', + 'errJSON' : 'Mô-đun PHP JSON không được cài đặt.', + 'errNoVolumes' : 'Tập có thể đọc không có sẵn.', + 'errCmdParams' : 'Thông số không hợp lệ cho lệnh "$1".', + 'errDataNotJSON' : 'Dữ liệu không phải là JSON.', + 'errDataEmpty' : 'Dữ liệu trống.', + 'errCmdReq' : 'Backend đòi hỏi tên lệnh.', + 'errOpen' : 'Không thể mở "$1".', + 'errNotFolder' : 'Đối tượng không phải là một thư mục.', + 'errNotFile' : 'Đối tượng không phải là một tập tin.', + 'errRead' : 'Không thể đọc "$1".', + 'errWrite' : 'Không thể ghi vào "$1".', + 'errPerm' : 'Quyền bị từ chối.', + 'errLocked' : '"$1" đã bị khóa và không thể đổi tên, di chuyển hoặc loại bỏ.', + 'errExists' : 'Tập tin có tên "$1" đã tồn tại.', + 'errInvName' : 'Tên tập tin không hợp lệ.', + 'errInvDirname' : 'Tên thư mục không hợp lệ.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : 'Thư mục không tìm thấy.', + 'errFileNotFound' : 'Tập tin không tìm thấy.', + 'errTrgFolderNotFound' : 'Thư mục đích "$1" không được tìm thấy.', + 'errPopup' : 'Trình duyệt ngăn chặn mở cửa sổ popup.', + 'errMkdir' : 'Không thể tạo thư mục "$1".', + 'errMkfile' : 'Không thể tạo tập tin "$1".', + 'errRename' : 'Không thể đổi tên "$1".', + 'errCopyFrom' : 'Sao chép tập tin từ tập "$1" không được phép.', + 'errCopyTo' : 'Sao chép tập tin tới tập "$1" không được phép.', + 'errMkOutLink' : 'Không thể tạo liên kết ra bên ngoài volume root.', // from v2.1 added 03.10.2015 + 'errUpload' : 'Tải lên báo lỗi.', // old name - errUploadCommon + 'errUploadFile' : 'Không thể tải lên "$1".', // old name - errUpload + 'errUploadNoFiles' : 'Không thấy tập tin nào để tải lên.', + 'errUploadTotalSize' : 'Dữ liệu vượt quá kích thước tối đa cho phép.', // old name - errMaxSize + 'errUploadFileSize' : 'Tập tin vượt quá kích thước tối đa cho phép.', // old name - errFileMaxSize + 'errUploadMime' : 'Kiểu tập tin không được phép.', + 'errUploadTransfer' : 'Lỗi khi truyền "$1".', + 'errUploadTemp' : 'Không thể tạo thư mục tạm để tải lên.', // from v2.1 added 26.09.2015 + 'errNotReplace' : 'Đối tượng "$1" đã tồn tại ở vị trí này và không thể thay thế bằng đối tượng với loại khác.', // new + 'errReplace' : 'Không thể thay thế "$1".', + 'errSave' : 'Không thể lưu "$1".', + 'errCopy' : 'Không thể sao chép "$1".', + 'errMove' : 'Không thể chuyển "$1".', + 'errCopyInItself' : 'Không thể sao chép "$1" vào chính nó.', + 'errRm' : 'Không thể xóa "$1".', + 'errTrash' : 'Không thể cho vào thùng rác.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : 'Không thể xóa tệp nguồn.', + 'errExtract' : 'Không thể giải nén các tập tin từ"$1".', + 'errArchive' : 'Không thể tạo ra lưu trữ.', + 'errArcType' : 'Loại lưu trữ không được hỗ trợ.', + 'errNoArchive' : 'Tập tin không phải là lưu trữ hoặc có kiểu lưu trữ không được hỗ trợ.', + 'errCmdNoSupport' : 'Backend không hỗ trợ lệnh này.', + 'errReplByChild' : 'Thư mục "$1" không thể được thay thế bằng một mục con mà nó chứa.', + 'errArcSymlinks' : 'Vì lý do bảo mật, từ chối giải nén tập tin lưu trữ có chứa liên kết mềm.', // edited 24.06.2012 + 'errArcMaxSize' : 'Tập tin lưu trữ vượt quá kích thước tối đa cho phép.', + 'errResize' : 'Không thể thay đổi kích thước "$1".', + 'errResizeDegree' : 'Độ xoay không hợp lệ.', // added 7.3.2013 + 'errResizeRotate' : 'Không thể xoay hình ảnh.', // added 7.3.2013 + 'errResizeSize' : 'Kích thước hình ảnh không hợp lệ.', // added 7.3.2013 + 'errResizeNoChange' : 'Kích thước hình ảnh không thay đổi.', // added 7.3.2013 + 'errUsupportType' : 'Loại tập tin không được hỗ trợ.', + 'errNotUTF8Content' : 'Tệp "$1" không phải bộ ký tự UTF-8 nên không thể chỉnh sửa.', // added 9.11.2011 + 'errNetMount' : 'Không thể gắn kết "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : 'Giao thức không được hỗ trợ.', // added 17.04.2012 + 'errNetMountFailed' : 'Gắn (kết nối) thất bại.', // added 17.04.2012 + 'errNetMountHostReq' : 'Yêu cầu máy chủ.', // added 18.04.2012 + 'errSessionExpires' : 'Phiên của bạn đã hết hạn do không hoạt động.', + 'errCreatingTempDir' : 'Không thể tạo thư mục tạm thời: "$1"', + 'errFtpDownloadFile' : 'Không thể tải xuống tệp từ FTP: "$1"', + 'errFtpUploadFile' : 'Không thể tải tệp lên FTP: "$1"', + 'errFtpMkdir' : 'Không thể tạo thư mục từ xa trên FTP: "$1"', + 'errArchiveExec' : 'Lỗi trong khi lưu trữ tệp: "$1"', + 'errExtractExec' : 'Lỗi trong khi giải nén tập tin: "$1"', + 'errNetUnMount' : 'Không thể gỡ gắn (liên kết).', // from v2.1 added 30.04.2012 + 'errConvUTF8' : 'Không thể chuyển đổi thành UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : 'Hãy thử trình duyệt mới hơn (vì trình duyệt hiện tại có vẻ cũ nên không hỗ trợ tải lên thư mục).', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : 'Đã hết thời gian trong khi tìm kiếm "$1". Kết quả tìm kiếm là một phần.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : 'Cần ủy quyền lại.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : 'Số lượng tối đa của các mục có thể chọn là $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : 'Không thể khôi phục từ thùng rác. Không thể xác định đích khôi phục.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : 'Không tìm thấy trình chỉnh sửa cho loại tệp này.', // from v2.1.25 added 23.5.2017 + 'errServerError' : 'Lỗi xảy ra ở phía máy chủ.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : 'Không thể làm rỗng thư mục "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : 'Có thêm $1 lỗi.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : 'Tạo tập tin nén', + 'cmdback' : 'Trở lại', + 'cmdcopy' : 'Sao chép', + 'cmdcut' : 'Cắt', + 'cmddownload' : 'Tải về', + 'cmdduplicate' : 'Bản sao', + 'cmdedit' : 'Sửa tập tin', + 'cmdextract' : 'Giải nén tập tin', + 'cmdforward' : 'Trước', + 'cmdgetfile' : 'Chọn tập tin', + 'cmdhelp' : 'Giới thiệu phần mềm', + 'cmdhome' : 'Home', + 'cmdinfo' : 'Thông tin', + 'cmdmkdir' : 'Thư mục', + 'cmdmkdirin' : 'Vào thư mục mới', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : 'Tạo tập tin Text', + 'cmdopen' : 'Mở', + 'cmdpaste' : 'Dán', + 'cmdquicklook' : 'Xem trước', + 'cmdreload' : 'Nạp lại', + 'cmdrename' : 'Đổi tên', + 'cmdrm' : 'Xóa', + 'cmdtrash' : 'Vào thùng rác', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : 'Khôi phục', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : 'Tìm tập tin', + 'cmdup' : 'Go to parent directory', + 'cmdupload' : 'Tải tập tin lên', + 'cmdview' : 'Xem', + 'cmdresize' : 'Thay đổi kích thước và xoay', + 'cmdsort' : 'Sắp xếp', + 'cmdnetmount' : 'Mount network volume', // added 18.04.2012 + 'cmdnetunmount': 'Gỡ mount', // from v2.1 added 30.04.2012 + 'cmdplaces' : 'To Places', // added 28.12.2014 + 'cmdchmod' : 'Thay đổi chế độ', // from v2.1 added 20.6.2015 + 'cmdopendir' : 'Mở một thư mục', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : 'Đặt lại chiều rộng cột', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': 'Toàn màn hình', // from v2.1.15 added 03.08.2016 + 'cmdmove' : 'Di chuyển', // from v2.1.15 added 21.08.2016 + 'cmdempty' : 'Làm rỗng thư mục', // from v2.1.25 added 22.06.2017 + 'cmdundo' : 'Hủy bỏ (hoàn tác)', // from v2.1.27 added 31.07.2017 + 'cmdredo' : 'Làm lại', // from v2.1.27 added 31.07.2017 + 'cmdpreference': 'Preferences', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : 'Chọn tất cả', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': 'Không chọn gì', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': 'Chọn ngược lại', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : 'Mở trong cửa sổ mới', // from v2.1.38 added 3.4.2018 + 'cmdhide' : 'Ẩn (Preference)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : 'Đóng', + 'btnSave' : 'Lưu', + 'btnRm' : 'Gỡ bỏ', + 'btnApply' : 'Áp dụng', + 'btnCancel' : 'Hủy bỏ', + 'btnNo' : 'Không', + 'btnYes' : 'Đồng ý', + 'btnDiscard': 'Discard changes', + 'btnMount' : 'Mount', // added 18.04.2012 + 'btnApprove': 'Goto $1 & approve', // from v2.1 added 26.04.2012 + 'btnUnmount': 'Unmount', // from v2.1 added 30.04.2012 + 'btnConv' : 'Convert', // from v2.1 added 08.04.2014 + 'btnCwd' : 'Here', // from v2.1 added 22.5.2015 + 'btnVolume' : 'Volume', // from v2.1 added 22.5.2015 + 'btnAll' : 'All', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME Type', // from v2.1 added 22.5.2015 + 'btnFileName':'Filename', // from v2.1 added 22.5.2015 + 'btnSaveClose': 'Save & Close', // from v2.1 added 12.6.2015 + 'btnBackup' : 'Backup', // fromv2.1 added 28.11.2015 + 'btnRename' : 'Rename', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : 'Rename(All)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : 'Prev ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : 'Next ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : 'Save As', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : 'Mở thư mục', + 'ntffile' : 'Mở tập tin', + 'ntfreload' : 'Nạp lại nội dung thư mục', + 'ntfmkdir' : 'Tạo thư mục', + 'ntfmkfile' : 'Tạo tập tin', + 'ntfrm' : 'Xóa tập tin', + 'ntfcopy' : 'Sao chép tập tin', + 'ntfmove' : 'Di chuyển tập tin', + 'ntfprepare' : 'Chuẩn bị để sao chép các tập tin', + 'ntfrename' : 'Đổi tên tập tin', + 'ntfupload' : 'Tải tập tin lên', + 'ntfdownload' : 'Tải tập tin', + 'ntfsave' : 'Lưu tập tin', + 'ntfarchive' : 'Tạo tập tin nén', + 'ntfextract' : 'Giải nén tập tin', + 'ntfsearch' : 'Tìm kiếm tập tin', + 'ntfresize' : 'Resizing images', + 'ntfsmth' : 'Doing something >_<', + 'ntfloadimg' : 'Đang tải hình ảnh', + 'ntfnetmount' : 'Mounting network volume', // added 18.04.2012 + 'ntfnetunmount': 'Unmounting network volume', // from v2.1 added 30.04.2012 + 'ntfdim' : 'Acquiring image dimension', // added 20.05.2013 + 'ntfreaddir' : 'Reading folder infomation', // from v2.1 added 01.07.2013 + 'ntfurl' : 'Getting URL of link', // from v2.1 added 11.03.2014 + 'ntfchmod' : 'Changing file mode', // from v2.1 added 20.6.2015 + 'ntfpreupload': 'Verifying upload file name', // from v2.1 added 31.11.2015 + 'ntfzipdl' : 'Creating a file for download', // from v2.1.7 added 23.1.2016 + 'ntfparents' : 'Getting path infomation', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': 'Processing the uploaded file', // from v2.1.17 added 2.11.2016 + 'ntftrash' : 'Doing throw in the trash', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : 'Doing restore from the trash', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : 'Checking destination folder', // from v2.1.24 added 3.5.2017 + 'ntfundo' : 'Undoing previous operation', // from v2.1.27 added 31.07.2017 + 'ntfredo' : 'Redoing previous undone', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : 'Checking contents', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : 'Trash', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : 'Chưa biết', + 'Today' : 'Hôm nay', + 'Yesterday' : 'Hôm qua', + 'msJan' : 'Tháng 1', + 'msFeb' : 'Tháng 2', + 'msMar' : 'Tháng 3', + 'msApr' : 'Tháng 4', + 'msMay' : 'Tháng 5', + 'msJun' : 'Tháng 6', + 'msJul' : 'Tháng 7', + 'msAug' : 'Tháng 8', + 'msSep' : 'Tháng 9', + 'msOct' : 'Tháng 10', + 'msNov' : 'Tháng 11', + 'msDec' : 'Tháng 12', + 'January' : 'Tháng 1', + 'February' : 'Tháng 2', + 'March' : 'Tháng 3', + 'April' : 'Tháng 4', + 'May' : 'Tháng 5', + 'June' : 'Tháng 6', + 'July' : 'Tháng 7', + 'August' : 'Tháng 8', + 'September' : 'Tháng 9', + 'October' : 'Tháng 10', + 'November' : 'Tháng 11', + 'December' : 'Tháng 12', + 'Sunday' : 'Chủ nhật', + 'Monday' : 'Thứ 2', + 'Tuesday' : 'Thứ 3', + 'Wednesday' : 'Thứ 4', + 'Thursday' : 'Thứ 5', + 'Friday' : 'Thứ 6', + 'Saturday' : 'Thứ 7', + 'Sun' : 'Chủ nhật', + 'Mon' : 'Thứ 2', + 'Tue' : 'Thứ 3', + 'Wed' : 'Thứ 4', + 'Thu' : 'Thứ 5', + 'Fri' : 'Thứ 6', + 'Sat' : 'Thứ 7', + + /******************************** sort variants ********************************/ + 'sortname' : 'theo tên', + 'sortkind' : 'theo loại', + 'sortsize' : 'theo kích cỡ', + 'sortdate' : 'theo ngày', + 'sortFoldersFirst' : 'Thư mục đầu tiên', + 'sortperm' : 'theo quyền hạn', // from v2.1.13 added 13.06.2016 + 'sortmode' : 'theo chế độ', // from v2.1.13 added 13.06.2016 + 'sortowner' : 'theo người tạo', // from v2.1.13 added 13.06.2016 + 'sortgroup' : 'theo nhóm', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : 'Also Treeview', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : 'NewFile.txt', // added 10.11.2015 + 'untitled folder' : 'NewFolder', // added 10.11.2015 + 'Archive' : 'NewArchive', // from v2.1 added 10.11.2015 + 'untitled file' : 'NewFile.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: File', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : 'Yêu cầu xác nhận', + 'confirmRm' : 'Bạn có chắc chắn muốn xóa vĩnh viễn các mục?
                      Điều này không thể được hoàn tác!', + 'confirmRepl' : 'Thay tập tin cũ bằng tập tin mới? (Nếu nó chứa các thư mục, nó sẽ được hợp nhất. Để sao lưu và thay thế, chọn Sao lưu.)', + 'confirmRest' : 'Thay thế mục hiện có bằng một mục trong thùng rác?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : 'Not in UTF-8
                      Convert to UTF-8?
                      Contents become UTF-8 by saving after conversion.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : 'Character encoding of this file couldn\'t be detected. It need to temporarily convert to UTF-8 for editting.
                      Please select character encoding of this file.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : 'It has been modified.
                      Losing work if you do not save changes.', // from v2.1 added 15.7.2015 + 'confirmTrash' : 'Bạn có chắc chắn muốn chuyển các mục vào thùng rác?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : 'Bạn có chắc chắn muốn chuyển các mục vào "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : 'Áp dụng cho tất cả', + 'name' : 'Tên', + 'size' : 'Kích cỡ', + 'perms' : 'Quyền', + 'modify' : 'Sửa đổi', + 'kind' : 'Loại', + 'read' : 'đọc', + 'write' : 'viết', + 'noaccess' : 'không truy cập', + 'and' : 'và', + 'unknown' : 'không xác định', + 'selectall' : 'Chọn tất cả các mục', + 'selectfiles' : 'Chọn các mục', + 'selectffile' : 'Chọn mục đầu tiên', + 'selectlfile' : 'Chọn mục cuối cùng', + 'viewlist' : 'Hiển thị danh sách', + 'viewicons' : 'Hiển thị biểu tượng', + 'viewSmall' : 'Biểu tượng nhỏ', // from v2.1.39 added 22.5.2018 + 'viewMedium' : 'Biểu tượng vừa', // from v2.1.39 added 22.5.2018 + 'viewLarge' : 'Biểu tượng lớn', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : 'Biểu tượng cực lớn', // from v2.1.39 added 22.5.2018 + 'places' : 'Places', + 'calc' : 'Tính toán', + 'path' : 'Đường dẫn', + 'aliasfor' : 'Bí danh cho', + 'locked' : 'Đã khóa', + 'dim' : 'Kích thước', + 'files' : 'Tệp', + 'folders' : 'Thư mục', + 'items' : 'Items', + 'yes' : 'yes', + 'no' : 'no', + 'link' : 'Liên kết', + 'searcresult' : 'Kết quả tìm kiếm', + 'selected' : 'mục đã chọn', + 'about' : 'Về', + 'shortcuts' : 'Lối tắt', + 'help' : 'Giúp đỡ', + 'webfm' : 'Web file manager', + 'ver' : 'Phiên bản', + 'protocolver' : 'phiên bản protocol', + 'homepage' : 'Trang chủ dự án', + 'docs' : 'Tài liệu', + 'github' : 'Theo dõi chúng tôi trên GitHub', + 'twitter' : 'Theo dõi chúng tôi trên Twitter', + 'facebook' : 'Theo dõi chúng tôi trên Facebook', + 'team' : 'Đội ngũ', + 'chiefdev' : 'Trùm sò', + 'developer' : 'người phát triển', + 'contributor' : 'người đóng góp', + 'maintainer' : 'người bảo trì', + 'translator' : 'người dịch', + 'icons' : 'Icons', + 'dontforget' : 'and don\'t forget to take your towel', + 'shortcutsof' : 'Shortcuts disabled', + 'dropFiles' : 'Thả tệp vào đây', + 'or' : 'hoặc', + 'selectForUpload' : 'Chọn tệp', + 'moveFiles' : 'Di chuyển các mục', + 'copyFiles' : 'Sao chép các mục', + 'restoreFiles' : 'Khôi mục các mục', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : 'Remove from places', + 'aspectRatio' : 'Tỉ lệ khung hình', + 'scale' : 'Tỉ lệ', + 'width' : 'Rộng', + 'height' : 'Cao', + 'resize' : 'Thay đổi kích cỡ', + 'crop' : 'Cắt', + 'rotate' : 'Xoay', + 'rotate-cw' : 'Xoay 90 độ CW', + 'rotate-ccw' : 'Xoay 90 độ CCW', + 'degree' : '°', + 'netMountDialogTitle' : 'Mount network volume', // added 18.04.2012 + 'protocol' : 'Protocol', // added 18.04.2012 + 'host' : 'Host', // added 18.04.2012 + 'port' : 'Port', // added 18.04.2012 + 'user' : 'User', // added 18.04.2012 + 'pass' : 'Password', // added 18.04.2012 + 'confirmUnmount' : 'Are you unmount $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': 'Drop or Paste files from browser', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : 'Drop files, Paste URLs or images(clipboard) here', // from v2.1 added 07.04.2014 + 'encoding' : 'Mã hóa', // from v2.1 added 19.12.2014 + 'locale' : 'Địa phương', // from v2.1 added 19.12.2014 + 'searchTarget' : 'Mục tiêu: $1', // from v2.1 added 22.5.2015 + 'searchMime' : 'Tìm kiếm theo kiểu tệp (MIME)', // from v2.1 added 22.5.2015 + 'owner' : 'Chủ sở hữu', // from v2.1 added 20.6.2015 + 'group' : 'Nhóm', // from v2.1 added 20.6.2015 + 'other' : 'Khác', // from v2.1 added 20.6.2015 + 'execute' : 'Thực thi', // from v2.1 added 20.6.2015 + 'perm' : 'Quyền', // from v2.1 added 20.6.2015 + 'mode' : 'Chế độ', // from v2.1 added 20.6.2015 + 'emptyFolder' : 'Thư mục trống', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : 'Thư mục trống\\A Kéo thả vào đây để thêm các mục', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : 'Thư mục trống\\A Nhấn giữ để thêm các mục', // from v2.1.6 added 30.12.2015 + 'quality' : 'Chất lượng', // from v2.1.6 added 5.1.2016 + 'autoSync' : 'Tự động động bộ', // from v2.1.6 added 10.1.2016 + 'moveUp' : 'Di chuyển lên', // from v2.1.6 added 18.1.2016 + 'getLink' : 'Lấy liên kết URL', // from v2.1.7 added 9.2.2016 + 'selectedItems' : 'Các mục đã chọn ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : 'ID thư mục', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : 'Cho phép truy cập ngoại tuyến', // from v2.1.10 added 3.25.2016 + 'reAuth' : 'Xác thực lại', // from v2.1.10 added 3.25.2016 + 'nowLoading' : 'Đang tải...', // from v2.1.12 added 4.26.2016 + 'openMulti' : 'Mở nhiều tập tin', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': 'You are trying to open the $1 files. Are you sure you want to open in browser?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : 'Kết quả tìm kiếm trống trong mục tiêu tìm kiếm.', // from v2.1.12 added 5.16.2016 + 'editingFile' : 'Nó là một tập tin đang chỉnh sửa.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : 'You have selected $1 items.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : 'You have $1 items in the clipboard.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : 'Tìm kiếm gia tăng chỉ từ hiển thị hiện tại.', // from v2.1.13 added 6.30.2016 + 'reinstate' : 'Phục hồi', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 hoàn thành', // from v2.1.15 added 21.8.2016 + 'contextmenu' : 'Trình đơn ngữ cảnh', // from v2.1.15 added 9.9.2016 + 'pageTurning' : 'Chuyển trang', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : 'Volume roots', // from v2.1.16 added 16.9.2016 + 'reset' : 'Đặt lại', // from v2.1.16 added 1.10.2016 + 'bgcolor' : 'Màu nền', // from v2.1.16 added 1.10.2016 + 'colorPicker' : 'Chọn màu', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px Grid', // from v2.1.16 added 4.10.2016 + 'enabled' : 'Đã bật', // from v2.1.16 added 4.10.2016 + 'disabled' : 'Đã tắt', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : 'Search results is empty in current view.\\APress [Enter] to expand search target.', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : 'Kết quả tìm kiếm thư đầu tiên là trống trong chế độ xem hiện tại.', // from v2.1.23 added 24.3.2017 + 'textLabel' : 'Nhãn văn bản', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '$1 mins left', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : 'Reopen with selected encoding', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : 'Save with the selected encoding', // from v2.1.19 added 2.12.2016 + 'selectFolder' : 'Chọn thư mục', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': 'First letter search', // from v2.1.23 added 24.3.2017 + 'presets' : 'Đặt trước', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : 'Có quá nhiều mục vì vậy không thể cho vào thùng rác.', // from v2.1.25 added 9.6.2017 + 'TextArea' : 'TextArea', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : 'Empty the folder "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : 'There are no items in a folder "$1".', // from v2.1.25 added 22.6.2017 + 'preference' : 'Preference', // from v2.1.26 added 28.6.2017 + 'language' : 'Ngôn ngữ', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': 'Initialize the settings saved in this browser', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : 'Cài đặt thanh công cụ', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... $1 chars left.', // from v2.1.29 added 30.8.2017 + 'sum' : 'Sum', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : 'Rough file size', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : 'Focus on the element of dialog with mouseover', // from v2.1.30 added 2.11.2017 + 'select' : 'Select', // from v2.1.30 added 23.11.2017 + 'selectAction' : 'Action when select file', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : 'Open with the editor used last time', // from v2.1.30 added 23.11.2017 + 'selectinvert' : 'Invert selection', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : 'Are you sure you want to rename $1 selected items like $2?
                      This cannot be undone!', // from v2.1.31 added 4.12.2017 + 'batchRename' : 'Batch rename', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '+ Number', // from v2.1.31 added 8.12.2017 + 'asPrefix' : 'Thêm tiền tố', // from v2.1.31 added 8.12.2017 + 'asSuffix' : 'Thêm hậu tố', // from v2.1.31 added 8.12.2017 + 'changeExtention' : 'Thay đổi phần mở rộng', // from v2.1.31 added 8.12.2017 + 'columnPref' : 'Columns settings (List view)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : 'All changes will reflect immediately to the archive.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : 'Any changes will not reflect until un-mount this volume.', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : 'The following volume(s) mounted on this volume also unmounted. Are you sure to unmount it?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : 'Selection Info', // from v2.1.33 added 7.3.2018 + 'hashChecker' : 'Algorithms to show the file hash', // from v2.1.33 added 10.3.2018 + 'infoItems' : 'Info Items (Selection Info Panel)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': 'Nhấn một lần nữa để thoát.', // from v2.1.38 added 1.4.2018 + 'toolbar' : 'Toolbar', // from v2.1.38 added 4.4.2018 + 'workspace' : 'Work Space', // from v2.1.38 added 4.4.2018 + 'dialog' : 'Dialog', // from v2.1.38 added 4.4.2018 + 'all' : 'All', // from v2.1.38 added 4.4.2018 + 'iconSize' : 'Icon Size (Icons view)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : 'Open the maximized editor window', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : 'Because conversion by API is not currently available, please convert on the website.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : 'After conversion, you must be upload with the item URL or a downloaded file to save the converted file.', //from v2.1.40 added 8.7.2018 + 'convertOn' : 'Convert on the site of $1', // from v2.1.40 added 10.7.2018 + 'integrations' : 'Integrations', // from v2.1.40 added 11.7.2018 + 'integrationWith' : 'This elFinder has the following external services integrated. Please check the terms of use, privacy policy, etc. before using it.', // from v2.1.40 added 11.7.2018 + 'showHidden' : 'Show hidden items', // from v2.1.41 added 24.7.2018 + 'hideHidden' : 'Hide hidden items', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : 'Show/Hide hidden items', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : 'File types to enable with "New file"', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : 'Type of the Text file', // from v2.1.41 added 7.8.2018 + 'add' : 'Add', // from v2.1.41 added 7.8.2018 + 'theme' : 'Theme', // from v2.1.43 added 19.10.2018 + 'default' : 'Default', // from v2.1.43 added 19.10.2018 + 'description' : 'Description', // from v2.1.43 added 19.10.2018 + 'website' : 'Website', // from v2.1.43 added 19.10.2018 + 'author' : 'Author', // from v2.1.43 added 19.10.2018 + 'email' : 'Email', // from v2.1.43 added 19.10.2018 + 'license' : 'License', // from v2.1.43 added 19.10.2018 + 'exportToSave' : 'This item can\'t be saved. To avoid losing the edits you need to export to your PC.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': 'Double click on the file to select it.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : 'Use fullscreen mode', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : 'Unknown', + 'kindRoot' : 'Volume Root', // from v2.1.16 added 16.10.2016 + 'kindFolder' : 'Folder', + 'kindSelects' : 'Selections', // from v2.1.29 added 29.8.2017 + 'kindAlias' : 'Alias', + 'kindAliasBroken' : 'Broken alias', + // applications + 'kindApp' : 'Application', + 'kindPostscript' : 'Postscript document', + 'kindMsOffice' : 'Microsoft Office document', + 'kindMsWord' : 'Microsoft Word document', + 'kindMsExcel' : 'Microsoft Excel document', + 'kindMsPP' : 'Microsoft Powerpoint presentation', + 'kindOO' : 'Open Office document', + 'kindAppFlash' : 'Flash application', + 'kindPDF' : 'Portable Document Format (PDF)', + 'kindTorrent' : 'Bittorrent file', + 'kind7z' : '7z archive', + 'kindTAR' : 'TAR archive', + 'kindGZIP' : 'GZIP archive', + 'kindBZIP' : 'BZIP archive', + 'kindXZ' : 'XZ archive', + 'kindZIP' : 'ZIP archive', + 'kindRAR' : 'RAR archive', + 'kindJAR' : 'Java JAR file', + 'kindTTF' : 'True Type font', + 'kindOTF' : 'Open Type font', + 'kindRPM' : 'RPM package', + // fonts + 'kindFont' : 'Font', + 'kindSFNT' : 'SFNT font', + 'kindEOT' : 'Embedded Open Type font', + 'kindWOFF' : 'Web Open Font Format', + 'kindWOFF2' : 'Web Open Font Format 2', + // texts + 'kindText' : 'Text document', + 'kindTextPlain' : 'Plain text', + 'kindPHP' : 'PHP source', + 'kindCSS' : 'Cascading style sheet', + 'kindHTML' : 'HTML document', + 'kindJS' : 'Javascript source', + 'kindRTF' : 'Rich Text Format', + 'kindC' : 'C source', + 'kindCHeader' : 'C header source', + 'kindCPP' : 'C++ source', + 'kindCPPHeader' : 'C++ header source', + 'kindShell' : 'Unix shell script', + 'kindPython' : 'Python source', + 'kindJava' : 'Java source', + 'kindRuby' : 'Ruby source', + 'kindPerl' : 'Perl script', + 'kindSQL' : 'SQL source', + 'kindXML' : 'XML document', + 'kindAWK' : 'AWK source', + 'kindCSV' : 'Comma separated values', + 'kindDOCBOOK' : 'Docbook XML document', + 'kindMarkdown' : 'Markdown text', // added 20.7.2015 + // images + 'kindImage' : 'Image', + 'kindBMP' : 'BMP image', + 'kindJPEG' : 'JPEG image', + 'kindGIF' : 'GIF Image', + 'kindPNG' : 'PNG Image', + 'kindTIFF' : 'TIFF image', + 'kindTGA' : 'TGA image', + 'kindPSD' : 'Adobe Photoshop image', + 'kindXBITMAP' : 'X bitmap image', + 'kindPXM' : 'Pixelmator image', + // media + 'kindAudio' : 'Audio media', + 'kindAudioMPEG' : 'MPEG audio', + 'kindAudioMPEG4' : 'MPEG-4 audio', + 'kindAudioMIDI' : 'MIDI audio', + 'kindAudioOGG' : 'Ogg Vorbis audio', + 'kindAudioWAV' : 'WAV audio', + 'AudioPlaylist' : 'MP3 playlist', + 'kindVideo' : 'Video media', + 'kindVideoDV' : 'DV movie', + 'kindVideoMPEG' : 'MPEG movie', + 'kindVideoMPEG4' : 'MPEG-4 movie', + 'kindVideoAVI' : 'AVI movie', + 'kindVideoMOV' : 'Quick Time movie', + 'kindVideoWM' : 'Windows Media movie', + 'kindVideoFlash' : 'Flash movie', + 'kindVideoMKV' : 'Matroska movie', + 'kindVideoOGG' : 'Ogg movie' + } + }; +})); diff --git a/lib/redactor/elfinder/js/i18n/elfinder.zh_CN.js b/lib/redactor/elfinder/js/i18n/elfinder.zh_CN.js new file mode 100644 index 0000000..48b15cd --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.zh_CN.js @@ -0,0 +1,592 @@ +/** + * 简体中文 translation + * @author 翻译者 deerchao + * @author Andy Hu + * @author Max Wen + * @author Kejun Chang + * @author LDMING + * @author Andy Lee + * @author Cololi + * @version 2020-04-07 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.zh_CN = { + translator : '翻译者 deerchao <deerchao@gmail.com>, Andy Hu <andyhu7@yahoo.com.hk>, Max Wen<max.wen@qq.com>, Kejun Chang <changkejun@hotmail.com>, LDMING <china-live@live.cn>, Andy Lee <oraclei@126.com>, Cololi <i@cololi.moe>', + language : '简体中文', + direction : 'ltr', + dateFormat : 'Y-m-d H:i', // will show like: 2020-04-07 14:53 + fancyDateFormat : '$1 H:i', // will show like: 今天 14:53 + nonameDateFormat : 'ymd-His', // noname upload will show like: 200407-145300 + messages : { + + /********************************** errors **********************************/ + 'error' : '错误', + 'errUnknown' : '未知的错误.', + 'errUnknownCmd' : '未知的命令.', + 'errJqui' : '无效的 jQuery UI 配置,必须包含 Selectable、draggable 以及 droppable 组件.', + 'errNode' : 'elFinder 需要能创建 DOM 元素.', + 'errURL' : '无效的 elFinder 配置! URL 选项未配置.', + 'errAccess' : '访问被拒绝.', + 'errConnect' : '不能连接到服务器端.', + 'errAbort' : '连接中止.', + 'errTimeout' : '连接超时.', + 'errNotFound' : '未找到服务器端.', + 'errResponse' : '无效的服务器端响应.', + 'errConf' : '无效的服务器端配置.', + 'errJSON' : 'PHP JSON 模块未安装.', + 'errNoVolumes' : '无可读的卷.', + 'errCmdParams' : '无效的命令 "$1".', + 'errDataNotJSON' : '服务器返回的数据不符合 JSON 格式.', + 'errDataEmpty' : '服务器返回的数据为空.', + 'errCmdReq' : '服务器端请求需要命令名称.', + 'errOpen' : '无法打开 "$1".', + 'errNotFolder' : '对象不是文件夹.', + 'errNotFile' : '对象不是文件.', + 'errRead' : '无法读取 "$1".', + 'errWrite' : '无法写入 "$1".', + 'errPerm' : '没有权限.', + 'errLocked' : '"$1" 已被锁定,不能重命名, 移动或删除.', + 'errExists' : '文件 "$1" 已经存在.', + 'errInvName' : '无效的文件名.', + 'errInvDirname' : '无效的文件夹名.', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : '文件夹不存在.', + 'errFileNotFound' : '文件不存在.', + 'errTrgFolderNotFound' : '未找到目标文件夹 "$1".', + 'errPopup' : '浏览器拦截了弹出窗口. 请在选项中允许弹出窗口.', + 'errMkdir' : '不能创建文件夹 "$1".', + 'errMkfile' : '不能创建文件 "$1".', + 'errRename' : '不能重命名 "$1".', + 'errCopyFrom' : '不允许从卷 "$1" 复制.', + 'errCopyTo' : '不允许向卷 "$1" 复制.', + 'errMkOutLink' : '无法创建链接到卷根以外的链接.', // from v2.1 added 03.10.2015 + 'errUpload' : '上传出错.', // old name - errUploadCommon + 'errUploadFile' : '无法上传 "$1".', // old name - errUpload + 'errUploadNoFiles' : '未找到要上传的文件.', + 'errUploadTotalSize' : '数据超过了允许的最大大小.', // old name - errMaxSize + 'errUploadFileSize' : '文件超过了允许的最大大小.', // old name - errFileMaxSize + 'errUploadMime' : '不允许的文件类型.', + 'errUploadTransfer' : '"$1" 传输错误.', + 'errUploadTemp' : '无法为上传文件创建临时文件.', // from v2.1 added 26.09.2015 + 'errNotReplace' : ' "$1" 已存在, 不能被替换.', // new + 'errReplace' : '无法替换 "$1".', + 'errSave' : '无法保存 "$1".', + 'errCopy' : '无法复制 "$1".', + 'errMove' : '无法移动 "$1".', + 'errCopyInItself' : '不能移动 "$1" 到原有位置.', + 'errRm' : '无法删除 "$1".', + 'errTrash' : '无法移到回收站.', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : '不能删除源文件.', + 'errExtract' : '无法从 "$1" 提取文件.', + 'errArchive' : '无法创建压缩包.', + 'errArcType' : '不支持的压缩格式.', + 'errNoArchive' : '文件不是压缩包, 或者不支持该压缩格式.', + 'errCmdNoSupport' : '服务器端不支持该命令.', + 'errReplByChild' : '不能用文件夹 “$1” 下的项替换文件夹 “$1” 自身.', + 'errArcSymlinks' : '出于安全上的考虑,不允许解压包含符号链接的压缩包.', // edited 24.06.2012 + 'errArcMaxSize' : '压缩包文件超过最大允许文件大小范围.', + 'errResize' : '无法将调整大小到 "$1".', + 'errResizeDegree' : '无效的旋转角度.', // added 7.3.2013 + 'errResizeRotate' : '无法旋转图片.', // added 7.3.2013 + 'errResizeSize' : '无效的图片尺寸.', // added 7.3.2013 + 'errResizeNoChange' : '图片尺寸未改变.', // added 7.3.2013 + 'errUsupportType' : '不被支持的文件格式.', + 'errNotUTF8Content' : '文件 "$1" 不是 UTF-8 格式, 不能编辑.', // added 9.11.2011 + 'errNetMount' : '无法装载 "$1".', // added 17.04.2012 + 'errNetMountNoDriver' : '不支持该协议.', // added 17.04.2012 + 'errNetMountFailed' : '装载失败.', // added 17.04.2012 + 'errNetMountHostReq' : '需要指定主机.', // added 18.04.2012 + 'errSessionExpires' : '您的会话由于长时间未活动已过期.', + 'errCreatingTempDir' : '无法创建临时目录 "$1"', + 'errFtpDownloadFile' : '无法从FTP下载文件 "$1" ', + 'errFtpUploadFile' : '无法将文件 "$1" 上传至FTP', + 'errFtpMkdir' : '无法在FTP上创建远程目录 "$1"', + 'errArchiveExec' : '归档文件"$1"时出错.', + 'errExtractExec' : '解压文件"$1"时出错.', + 'errNetUnMount' : '无法卸载.', // from v2.1 added 30.04.2012 + 'errConvUTF8' : '未转换至UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : '如果您需要上传目录, 请尝试使用Google Chrome.', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '搜索 "$1" 超时,仅显示部分搜索结果.', // from v2.1 added 12.1.2016 + 'errReauthRequire' : '必需重新授权.', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : '最大可选择项目数为 $1.', // from v2.1.17 added 17.10.2016 + 'errRestore' : '无法从回收站中恢复,无法识别还原目的地.', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : '找不到这个文件的编辑器.', // from v2.1.25 added 23.5.2017 + 'errServerError' : '服务端发生错误.', // from v2.1.25 added 16.6.2017 + 'errEmpty' : '无法清空文件夹 "$1".', // from v2.1.25 added 22.6.2017 + 'moreErrors' : '存在 $1 多个错误.', // from v2.1.44 added 9.12.2018 + + /******************************* commands names ********************************/ + 'cmdarchive' : '创建压缩包', + 'cmdback' : '后退', + 'cmdcopy' : '复制', + 'cmdcut' : '剪切', + 'cmddownload' : '下载', + 'cmdduplicate' : '创建副本', + 'cmdedit' : '编辑文件', + 'cmdextract' : '从压缩包提取文件', + 'cmdforward' : '前进', + 'cmdgetfile' : '选择文件', + 'cmdhelp' : '关于', + 'cmdhome' : '首页', + 'cmdinfo' : '查看详情', + 'cmdmkdir' : '新建文件夹', + 'cmdmkdirin' : '至新文件夹', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : '新建文件', + 'cmdopen' : '打开', + 'cmdpaste' : '粘贴', + 'cmdquicklook' : '预览', + 'cmdreload' : '刷新', + 'cmdrename' : '重命名', + 'cmdrm' : '删除', + 'cmdtrash' : '至回收站', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : '恢复', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : '查找文件', + 'cmdup' : '转到上一级文件夹', + 'cmdupload' : '上传文件', + 'cmdview' : '查看', + 'cmdresize' : '调整大小&旋转', + 'cmdsort' : '排序', + 'cmdnetmount' : '装载网络卷', // added 18.04.2012 + 'cmdnetunmount': '卸载', // from v2.1 added 30.04.2012 + 'cmdplaces' : '添加到收藏夹', // added 28.12.2014 + 'cmdchmod' : '改变模式', // from v2.1 added 20.6.2015 + 'cmdopendir' : '打开文件夹', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : '设置列宽', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': '全屏显示', // from v2.1.15 added 03.08.2016 + 'cmdmove' : '移动', // from v2.1.15 added 21.08.2016 + 'cmdempty' : '清空文件夹', // from v2.1.25 added 22.06.2017 + 'cmdundo' : '撤消', // from v2.1.27 added 31.07.2017 + 'cmdredo' : '重做', // from v2.1.27 added 31.07.2017 + 'cmdpreference': '偏好', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : '全选', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': '全不选', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': '反向选择', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : '在新窗口打开', // from v2.1.38 added 3.4.2018 + 'cmdhide' : '隐藏 (偏好)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : '关闭', + 'btnSave' : '保存', + 'btnRm' : '删除', + 'btnApply' : '应用', + 'btnCancel' : '取消', + 'btnNo' : '否', + 'btnYes' : '是', + 'btnDiscard': 'Discard changes', + 'btnMount' : '装载', // added 18.04.2012 + 'btnApprove': '至 $1 并确认', // from v2.1 added 26.04.2012 + 'btnUnmount': '卸载', // from v2.1 added 30.04.2012 + 'btnConv' : '转换', // from v2.1 added 08.04.2014 + 'btnCwd' : '这里', // from v2.1 added 22.5.2015 + 'btnVolume' : '卷', // from v2.1 added 22.5.2015 + 'btnAll' : '全部', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME类型', // from v2.1 added 22.5.2015 + 'btnFileName':'文件名', // from v2.1 added 22.5.2015 + 'btnSaveClose': '保存并关闭', // from v2.1 added 12.6.2015 + 'btnBackup' : '备份', // fromv2.1 added 28.11.2015 + 'btnRename' : '重命名', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : '重命名(All)', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '向前 ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : '向后 ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : '另存为', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : '打开文件夹', + 'ntffile' : '打开文件', + 'ntfreload' : '刷新文件夹内容', + 'ntfmkdir' : '创建文件夹', + 'ntfmkfile' : '创建文件', + 'ntfrm' : '删除文件', + 'ntfcopy' : '复制文件', + 'ntfmove' : '移动文件', + 'ntfprepare' : '准备复制文件', + 'ntfrename' : '重命名文件', + 'ntfupload' : '上传文件', + 'ntfdownload' : '下载文件', + 'ntfsave' : '保存文件', + 'ntfarchive' : '创建压缩包', + 'ntfextract' : '从压缩包提取文件', + 'ntfsearch' : '搜索文件', + 'ntfresize' : '正在更改尺寸', + 'ntfsmth' : '正在忙 >_<', + 'ntfloadimg' : '正在加载图片', + 'ntfnetmount' : '正在装载网络卷', // added 18.04.2012 + 'ntfnetunmount': '卸载网络卷', // from v2.1 added 30.04.2012 + 'ntfdim' : '获取图像尺寸', // added 20.05.2013 + 'ntfreaddir' : '正在读取文件夹信息', // from v2.1 added 01.07.2013 + 'ntfurl' : '正在获取链接地址', // from v2.1 added 11.03.2014 + 'ntfchmod' : '正在改变文件模式', // from v2.1 added 20.6.2015 + 'ntfpreupload': '正在验证上传文件名', // from v2.1 added 31.11.2015 + 'ntfzipdl' : '正在创建一个下载文件', // from v2.1.7 added 23.1.2016 + 'ntfparents' : '正在取得路径信息', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': '正在处理上传文件', // from v2.1.17 added 2.11.2016 + 'ntftrash' : '移动到回收站', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : '从回收站恢复', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : '检查目标文件夹', // from v2.1.24 added 3.5.2017 + 'ntfundo' : '撤消上一个全局操作', // from v2.1.27 added 31.07.2017 + 'ntfredo' : '重做上一全局操作', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : '检查内容', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : '回收站', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : '未知', + 'Today' : '今天', + 'Yesterday' : '昨天', + 'msJan' : '一月', + 'msFeb' : '二月', + 'msMar' : '三月', + 'msApr' : '四月', + 'msMay' : '五月', + 'msJun' : '六月', + 'msJul' : '七月', + 'msAug' : '八月', + 'msSep' : '九月', + 'msOct' : '十月', + 'msNov' : '十一月', + 'msDec' : '十二月', + 'January' : '一月', + 'February' : '二月', + 'March' : '三月', + 'April' : '四月', + 'May' : '五月', + 'June' : '六月', + 'July' : '七月', + 'August' : '八月', + 'September' : '九月', + 'October' : '十月', + 'November' : '十一月', + 'December' : '十二月', + 'Sunday' : '星期日', + 'Monday' : '星期一', + 'Tuesday' : '星期二', + 'Wednesday' : '星期三', + 'Thursday' : '星期四', + 'Friday' : '星期五', + 'Saturday' : '星期六', + 'Sun' : '周日', + 'Mon' : '周一', + 'Tue' : '周二', + 'Wed' : '周三', + 'Thu' : '周四', + 'Fri' : '周五', + 'Sat' : '周六', + + /******************************** sort variants ********************************/ + 'sortname' : '按名称', + 'sortkind' : '按类型', + 'sortsize' : '按大小', + 'sortdate' : '按日期', + 'sortFoldersFirst' : '文件夹优先', + 'sortperm' : '按权限排序', // from v2.1.13 added 13.06.2016 + 'sortmode' : '按属性排序', // from v2.1.13 added 13.06.2016 + 'sortowner' : '按所有者排序', // from v2.1.13 added 13.06.2016 + 'sortgroup' : '按组排序', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : '同时刷新树状目录', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : '新文件.txt', // added 10.11.2015 + 'untitled folder' : '新文件夹', // added 10.11.2015 + 'Archive' : '新压缩包', // from v2.1 added 10.11.2015 + 'untitled file' : '新文件.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: 文件', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : '请确认', + 'confirmRm' : '确定要删除文件吗?
                      该操作不可撤销!', + 'confirmRepl' : '用新的文件替换原有文件?', + 'confirmRest' : '从回收站替换当前项?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : '文件不是UTF-8格式.
                      转换为UTF-8吗?
                      通过在转换后保存,内容变为UTF-8.', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : '无法检测到此文件的字符编码.需要暂时转换此文件为UTF-8编码以进行编辑.
                      请选择此文件的字符编码.', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : '文件已被编辑.
                      如果不保存直接关闭,将丢失编辑内容.', // from v2.1 added 15.7.2015 + 'confirmTrash' : '确定要将该项移动到回收站么?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : '确定要移动该项到 "$1"?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : '全部应用', + 'name' : '名称', + 'size' : '大小', + 'perms' : '权限', + 'modify' : '修改于', + 'kind' : '类别', + 'read' : '读取', + 'write' : '写入', + 'noaccess' : '无权限', + 'and' : '和', + 'unknown' : '未知', + 'selectall' : '选择所有文件', + 'selectfiles' : '选择文件', + 'selectffile' : '选择第一个文件', + 'selectlfile' : '选择最后一个文件', + 'viewlist' : '列表视图', + 'viewicons' : '图标视图', + 'viewSmall' : '小图标', // from v2.1.39 added 22.5.2018 + 'viewMedium' : '中图标', // from v2.1.39 added 22.5.2018 + 'viewLarge' : '大图标', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : '超大图标', // from v2.1.39 added 22.5.2018 + 'places' : '位置', + 'calc' : '计算', + 'path' : '路径', + 'aliasfor' : '别名', + 'locked' : '锁定', + 'dim' : '尺寸', + 'files' : '文件', + 'folders' : '文件夹', + 'items' : '项目', + 'yes' : '是', + 'no' : '否', + 'link' : '链接', + 'searcresult' : '搜索结果', + 'selected' : '选中的项目', + 'about' : '关于', + 'shortcuts' : '快捷键', + 'help' : '帮助', + 'webfm' : '网络文件管理器', + 'ver' : '版本', + 'protocolver' : '协议版本', + 'homepage' : '项目主页', + 'docs' : '文档', + 'github' : '复刻我们的github', + 'twitter' : '关注我们的twitter', + 'facebook' : '加入我们的facebook', + 'team' : '团队', + 'chiefdev' : '首席开发', + 'developer' : '开发', + 'contributor' : '贡献', + 'maintainer' : '维护', + 'translator' : '翻译', + 'icons' : '图标', + 'dontforget' : '别忘了带上你擦汗的毛巾', + 'shortcutsof' : '快捷键已禁用', + 'dropFiles' : '把文件拖到这里', + 'or' : '或者', + 'selectForUpload' : '选择要上传的文件', + 'moveFiles' : '移动文件', + 'copyFiles' : '复制文件', + 'restoreFiles' : '恢复文件', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : '从这里中删除', + 'aspectRatio' : '保持比例', + 'scale' : '缩放比例', + 'width' : '宽', + 'height' : '高', + 'resize' : '调整大小', + 'crop' : '裁切', + 'rotate' : '旋转', + 'rotate-cw' : '顺时针旋转90°', + 'rotate-ccw' : '逆时针旋转90°', + 'degree' : '°', + 'netMountDialogTitle' : '装载网络目录', // added 18.04.2012 + 'protocol' : '协议', // added 18.04.2012 + 'host' : '主机', // added 18.04.2012 + 'port' : '端口', // added 18.04.2012 + 'user' : '用户', // added 18.04.2012 + 'pass' : '密码', // added 18.04.2012 + 'confirmUnmount' : '确实要卸载 $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': '从浏览器中拖放或粘贴文件', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : '拖放文件,粘贴网址或剪贴板图像', // from v2.1 added 07.04.2014 + 'encoding' : '编码', // from v2.1 added 19.12.2014 + 'locale' : '语言环境', // from v2.1 added 19.12.2014 + 'searchTarget' : '目标: $1', // from v2.1 added 22.5.2015 + 'searchMime' : '按输入MIME类型搜索', // from v2.1 added 22.5.2015 + 'owner' : '所有者', // from v2.1 added 20.6.2015 + 'group' : '组', // from v2.1 added 20.6.2015 + 'other' : '其他', // from v2.1 added 20.6.2015 + 'execute' : '执行', // from v2.1 added 20.6.2015 + 'perm' : '许可', // from v2.1 added 20.6.2015 + 'mode' : '属性', // from v2.1 added 20.6.2015 + 'emptyFolder' : '文件夹是空的', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : '文件夹是空的\\A 拖放可追加项目', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : '文件夹是空的\\A 长按可添加项目', // from v2.1.6 added 30.12.2015 + 'quality' : '品质', // from v2.1.6 added 5.1.2016 + 'autoSync' : '自动同步', // from v2.1.6 added 10.1.2016 + 'moveUp' : '向上移动', // from v2.1.6 added 18.1.2016 + 'getLink' : '获取URL链接', // from v2.1.7 added 9.2.2016 + 'selectedItems' : '已选择项目 ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : '目录ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : '允许离线操作', // from v2.1.10 added 3.25.2016 + 'reAuth' : '重新验证', // from v2.1.10 added 3.25.2016 + 'nowLoading' : '正在加载...', // from v2.1.12 added 4.26.2016 + 'openMulti' : '打开多个文件', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': '您正在尝试打开$1文件.您确定要在浏览器中打开吗?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : '搜索目标中没有匹配结果', // from v2.1.12 added 5.16.2016 + 'editingFile' : '正在编辑文件.', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '已选择 $1 个项目.', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '剪贴板里有 $1 个项目.', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : '增量搜索仅来自当前视图.', // from v2.1.13 added 6.30.2016 + 'reinstate' : '恢复', // from v2.1.15 added 3.8.2016 + 'complete' : '$1 完成', // from v2.1.15 added 21.8.2016 + 'contextmenu' : '上下文菜单', // from v2.1.15 added 9.9.2016 + 'pageTurning' : '翻页', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : '根目录', // from v2.1.16 added 16.9.2016 + 'reset' : '重置', // from v2.1.16 added 1.10.2016 + 'bgcolor' : '背景色', // from v2.1.16 added 1.10.2016 + 'colorPicker' : '颜色选择器', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '步长(8px)', // from v2.1.16 added 4.10.2016 + 'enabled' : '启用', // from v2.1.16 added 4.10.2016 + 'disabled' : '关闭', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : '当前视图下没有匹配结果', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : '当前视图中的第一个字母搜索结果为空', // from v2.1.23 added 24.3.2017 + 'textLabel' : '文本标签', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '剩余 $1 分钟', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : '使用所选编码重新打开', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : '使用所选编码保存', // from v2.1.19 added 2.12.2016 + 'selectFolder' : '选择目录', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': '首字母搜索', // from v2.1.23 added 24.3.2017 + 'presets' : '预置', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : '项目太多,不能移动到回收站.', // from v2.1.25 added 9.6.2017 + 'TextArea' : '文本区域', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : '清空文件夹 "$1".', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : '文件夹 "$1" 为空.', // from v2.1.25 added 22.6.2017 + 'preference' : '偏好', // from v2.1.26 added 28.6.2017 + 'language' : '语言设置', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': '清除保存在此浏览器中的偏好设置', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : '工具栏设置', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... 剩余$1字符', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... 剩余$1行', // from v2.1.52 added 16.1.2020 + 'sum' : '总数', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : '粗略的文件大小', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : '鼠标悬停在对话框内可编辑区域时自动获得焦点', // from v2.1.30 added 2.11.2017 + 'select' : '选择', // from v2.1.30 added 23.11.2017 + 'selectAction' : '双击选择的文件时', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : '用上次使用的编辑器打开', // from v2.1.30 added 23.11.2017 + 'selectinvert' : '反向选择', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : '确定要重命名选定项 $1 为 $2 吗?
                      该操作不能撤消!', // from v2.1.31 added 4.12.2017 + 'batchRename' : '批量重命名', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '增加数量', // from v2.1.31 added 8.12.2017 + 'asPrefix' : '添加前缀', // from v2.1.31 added 8.12.2017 + 'asSuffix' : '添加后缀', // from v2.1.31 added 8.12.2017 + 'changeExtention' : '变化范围', // from v2.1.31 added 8.12.2017 + 'columnPref' : '列设置 (列表视图)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : '所有修改将立即反馈到文档.', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : '所有修改在卸载本卷之前不会反馈', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : '安装在本卷上的以下卷也会卸载.你确定要卸载吗?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : '选择信息', // from v2.1.33 added 7.3.2018 + 'hashChecker' : '显示文件散列值的算法', // from v2.1.33 added 10.3.2018 + 'infoItems' : '信息条目 (选择信息面板)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': '再按退出', // from v2.1.38 added 1.4.2018 + 'toolbar' : '工具条', // from v2.1.38 added 4.4.2018 + 'workspace' : '工作空间', // from v2.1.38 added 4.4.2018 + 'dialog' : '对话框', // from v2.1.38 added 4.4.2018 + 'all' : '全部', // from v2.1.38 added 4.4.2018 + 'iconSize' : '图标尺寸 (图标视图)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : '打开最大化编辑器窗口', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : '由于通过 API 转换功能当前不可用,请到网站上转换.', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : '转换后,必须上传条目URL或一个下载的文件,以保存转换后的文件.', //from v2.1.40 added 8.7.2018 + 'convertOn' : '在 $1 站点上转换', // from v2.1.40 added 10.7.2018 + 'integrations' : '集成', // from v2.1.40 added 11.7.2018 + 'integrationWith' : '本 elFinder 集成以下外部服务.使用前请检查使用条款、隐私政策等.', // from v2.1.40 added 11.7.2018 + 'showHidden' : '显示已隐藏的条目', // from v2.1.41 added 24.7.2018 + 'hideHidden' : '隐藏已隐藏的条目', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : '显示/隐藏已隐藏的条目', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : '允许"新文件"使用的文件类型', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : '文本文件类型', // from v2.1.41 added 7.8.2018 + 'add' : '添加', // from v2.1.41 added 7.8.2018 + 'theme' : '主题', // from v2.1.43 added 19.10.2018 + 'default' : '缺省', // from v2.1.43 added 19.10.2018 + 'description' : '描述', // from v2.1.43 added 19.10.2018 + 'website' : '网站', // from v2.1.43 added 19.10.2018 + 'author' : '作者', // from v2.1.43 added 19.10.2018 + 'email' : '邮箱', // from v2.1.43 added 19.10.2018 + 'license' : '许可证', // from v2.1.43 added 19.10.2018 + 'exportToSave' : '本条目不能保存. 为避免丢失编辑数据,须要导出到你的电脑.', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': '在文件上双击以选中它.', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : '使用全屏模式', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : '未知', + 'kindRoot' : '根目录', // from v2.1.16 added 16.10.2016 + 'kindFolder' : '文件夹', + 'kindSelects' : '选择', // from v2.1.29 added 29.8.2017 + 'kindAlias' : '别名', + 'kindAliasBroken' : '错误的别名', + // applications + 'kindApp' : '程序', + 'kindPostscript' : 'Postscript 文档', + 'kindMsOffice' : 'Microsoft Office 文档', + 'kindMsWord' : 'Microsoft Word 文档', + 'kindMsExcel' : 'Microsoft Excel 文档', + 'kindMsPP' : 'Microsoft Powerpoint 演示', + 'kindOO' : 'Open Office 文档', + 'kindAppFlash' : 'Flash 程序', + 'kindPDF' : 'PDF 文档', + 'kindTorrent' : 'Bittorrent 文件', + 'kind7z' : '7z 压缩包', + 'kindTAR' : 'TAR 压缩包', + 'kindGZIP' : 'GZIP 压缩包', + 'kindBZIP' : 'BZIP 压缩包', + 'kindXZ' : 'XZ 压缩包', + 'kindZIP' : 'ZIP 压缩包', + 'kindRAR' : 'RAR 压缩包', + 'kindJAR' : 'Java JAR 文件', + 'kindTTF' : 'True Type 字体', + 'kindOTF' : 'Open Type 字体', + 'kindRPM' : 'RPM 包', + // fonts + 'kindFont' : '字体', + 'kindSFNT' : 'SFNT 字体', + 'kindEOT' : 'Embedded Open Type 字体', + 'kindWOFF' : 'Web Open Font Format 字体', + 'kindWOFF2' : 'Web Open Font Format 2 字体', + // texts + 'kindText' : '文本文件', + 'kindTextPlain' : '纯文本', + 'kindPHP' : 'PHP 源代码', + 'kindCSS' : '层叠样式表(CSS)', + 'kindHTML' : 'HTML 文档', + 'kindJS' : 'Javascript 源代码', + 'kindRTF' : '富文本格式(RTF)', + 'kindC' : 'C 源代码', + 'kindCHeader' : 'C 头文件', + 'kindCPP' : 'C++ 源代码', + 'kindCPPHeader' : 'C++ 头文件', + 'kindShell' : 'Unix 外壳脚本', + 'kindPython' : 'Python 源代码', + 'kindJava' : 'Java 源代码', + 'kindRuby' : 'Ruby 源代码', + 'kindPerl' : 'Perl 源代码', + 'kindSQL' : 'SQL 脚本', + 'kindXML' : 'XML 文档', + 'kindAWK' : 'AWK 源代码', + 'kindCSV' : '逗号分隔值文件(CSV)', + 'kindDOCBOOK' : 'Docbook XML 文档', + 'kindMarkdown' : 'Markdown 文本', // added 20.7.2015 + // images + 'kindImage' : '图片', + 'kindBMP' : 'BMP 图片', + 'kindJPEG' : 'JPEG 图片', + 'kindGIF' : 'GIF 图片', + 'kindPNG' : 'PNG 图片', + 'kindTIFF' : 'TIFF 图片', + 'kindTGA' : 'TGA 图片', + 'kindPSD' : 'Adobe Photoshop 图片', + 'kindXBITMAP' : 'X bitmap 图片', + 'kindPXM' : 'Pixelmator 图片', + // media + 'kindAudio' : '音频', + 'kindAudioMPEG' : 'MPEG 音频', + 'kindAudioMPEG4' : 'MPEG-4 音频', + 'kindAudioMIDI' : 'MIDI 音频', + 'kindAudioOGG' : 'Ogg Vorbis 音频', + 'kindAudioWAV' : 'WAV 音频', + 'AudioPlaylist' : 'MP3 播放列表', + 'kindVideo' : '视频', + 'kindVideoDV' : 'DV 视频', + 'kindVideoMPEG' : 'MPEG 视频', + 'kindVideoMPEG4' : 'MPEG-4 视频', + 'kindVideoAVI' : 'AVI 视频', + 'kindVideoMOV' : 'Quick Time 视频', + 'kindVideoWM' : 'Windows Media 视频', + 'kindVideoFlash' : 'Flash 视频', + 'kindVideoMKV' : 'Matroska 视频', + 'kindVideoOGG' : 'Ogg 视频' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/elfinder.zh_TW.js b/lib/redactor/elfinder/js/i18n/elfinder.zh_TW.js new file mode 100644 index 0000000..2f575a0 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/elfinder.zh_TW.js @@ -0,0 +1,592 @@ +/** + * 繁體中文 translation + * @author Yuwei Chuang + * @author Danny Lin + * @author TCC + * @author Rick Jiang + * @author Alex Lion (阿力獅) + * @version 2023-12-18 + */ +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define(['elfinder'], factory); + } else if (typeof exports !== 'undefined') { + module.exports = factory(require('elfinder')); + } else { + factory(root.elFinder); + } +}(this, function(elFinder) { + elFinder.prototype.i18.zh_TW = { + translator : 'Yuwei Chuang <ywchuang.tw@gmail.com>, Danny Lin <danny0838@gmail.com>, TCC <john987john987@gmail.com>, Rick Jiang <rick.jiang@aol.com>, Banny Tai <cssf998811@gmail.com>, Alex Lion (阿力獅) <learnwithalex@gmail.com>', + language : '繁體中文', + direction : 'ltr', + dateFormat : 'Y/n/j H:i', // will show like: 2023/12/4 14:29 + fancyDateFormat : '$1 H:i', // will show like: 今天 14:29 + nonameDateFormat : 'ymd-His', // noname upload will show like: 231204-142932 + messages : { + + /********************************** errors **********************************/ + 'error' : '錯誤', + 'errUnknown' : '未知的錯誤。', + 'errUnknownCmd' : '未知的命令。', + 'errJqui' : '無效的 jQuery 使用者介面組態。必須包含 Selectable、draggable 及 droppable 元件。', + 'errNode' : '建立 elFinder 需要 DOM 元素。', + 'errURL' : '無效的 elFinder 組態。URL 選項尚未設定。', + 'errAccess' : '拒絕存取。', + 'errConnect' : '無法連線至後端。', + 'errAbort' : '連線中止。', + 'errTimeout' : '連線逾時。', + 'errNotFound' : '找不到後端。', + 'errResponse' : '無效的後端回應。', + 'errConf' : '無效的後端組態。', + 'errJSON' : 'PHP JSON 模組尚未安裝。', + 'errNoVolumes' : '沒有可供讀取的磁碟。', + 'errCmdParams' : '命令 $1 的無效參數。', + 'errDataNotJSON' : '資料不是 JSON 格式。', + 'errDataEmpty' : '資料為空白。', + 'errCmdReq' : '後端要求需要命令名稱。', + 'errOpen' : '無法開啟 [$1]。', + 'errNotFolder' : '物件不是資料夾。', + 'errNotFile' : '物件不是檔案。', + 'errRead' : '無法讀取 [$1]。', + 'errWrite' : '無法寫入 [$1]。', + 'errPerm' : '沒有使用權限。', + 'errLocked' : '由於 [$1] 已鎖定,因此無法重新命名、移動或移除。', + 'errExists' : '名稱為 [$1] 的項目已存在。', + 'errInvName' : '無效的檔案名稱。', + 'errInvDirname' : '無效的資料夾名稱。', // from v2.1.24 added 12.4.2017 + 'errFolderNotFound' : '找不到資料夾。', + 'errFileNotFound' : '找不到檔案。', + 'errTrgFolderNotFound' : '找不到目標資料夾 [$1]。', + 'errPopup' : '瀏覽器阻擋了彈出式訊息視窗。如需開啟檔案,請允許瀏覽器開啟彈出式訊息視窗。', + 'errMkdir' : '無法建立資料夾 [$1]。', + 'errMkfile' : '無法建立檔案 [$1]。', + 'errRename' : '無法重新命名 [$1]。', + 'errCopyFrom' : '不允許從磁碟 $1 複製檔案。', + 'errCopyTo' : '不允許將檔案複製至磁碟 $1。', + 'errMkOutLink' : '無法建立磁碟根目錄以外的連結。', // from v2.1 added 03.10.2015 + 'errUpload' : '上傳時發生錯誤。', // old name - errUploadCommon + 'errUploadFile' : '無法上傳 [$1]。', // old name - errUpload + 'errUploadNoFiles' : '找不到要上傳的檔案。', + 'errUploadTotalSize' : '資料超過允許的大小上限。', // old name - errMaxSize + 'errUploadFileSize' : '檔案超過允許的大小上限。', // old name - errFileMaxSize + 'errUploadMime' : '不允許的檔案類型。', + 'errUploadTransfer' : '傳輸 [$1] 時發生錯誤。', + 'errUploadTemp' : '無法產生用於上傳時所需的暫存檔案。', // from v2.1 added 26.09.2015 + 'errNotReplace' : '物件 [$1] 已存在於這個位置,且無法尤其他類型物件取代。', // new + 'errReplace' : '無法取代 [$1]。', + 'errSave' : '無法儲存 [$1]。', + 'errCopy' : '無法複製 [$1]。', + 'errMove' : '無法移動 [$1]。', + 'errCopyInItself' : '無法將 [$1] 移動至現有位置。', + 'errRm' : '無法移除 [$1]。', + 'errTrash' : '無法移至回收桶。', // from v2.1.24 added 30.4.2017 + 'errRmSrc' : '無法移除來源檔案。', + 'errExtract' : '無法解壓縮 [$1] 中的檔案。', + 'errArchive' : '無法建立壓縮檔。', + 'errArcType' : '不支援的壓縮檔格式。', + 'errNoArchive' : '檔案不是壓縮檔,或是不支援的壓縮檔格式。', + 'errCmdNoSupport' : '後端不支援這個命令。', + 'errReplByChild' : '資料夾 [$1] 無法由它所包含的項目取代。', + 'errArcSymlinks' : '基於安全性考量,拒絕解壓縮包含符號連結或含有不符規定名稱的檔案的壓縮檔。', // edited 24.06.2012 + 'errArcMaxSize' : '壓縮檔大小超過上限。', + 'errResize' : '無法調整 [$1] 的大小。', + 'errResizeDegree' : '無效的旋轉角度。', // added 7.3.2013 + 'errResizeRotate' : '無法旋轉圖片。', // added 7.3.2013 + 'errResizeSize' : '無效的圖片尺寸。', // added 7.3.2013 + 'errResizeNoChange' : '圖片尺寸沒有變更。', // added 7.3.2013 + 'errUsupportType' : '不支援的檔案類型。', + 'errNotUTF8Content' : '檔案 [$1] 不是 UTF-8 編碼且無法編輯。', // added 9.11.2011 + 'errNetMount' : '無法掛接 $1。', // added 17.04.2012 + 'errNetMountNoDriver' : '不支援的通訊協定。', // added 17.04.2012 + 'errNetMountFailed' : '無法掛接磁碟。', // added 17.04.2012 + 'errNetMountHostReq' : '需要設定主機名稱。', // added 18.04.2012 + 'errSessionExpires' : '由於非使用狀態時間過長,因此目前的工作階段已到期。', + 'errCreatingTempDir' : '無法建立暫存目錄: $1', + 'errFtpDownloadFile' : '無法從 FTP 下載檔案: $1', + 'errFtpUploadFile' : '無法上傳檔案至 FTP: $1', + 'errFtpMkdir' : '無法透過 FTP 建立遠端目錄: $1', + 'errArchiveExec' : '壓縮檔案時發生錯誤: $1', + 'errExtractExec' : '解壓縮檔案時發生錯誤: $1', + 'errNetUnMount' : '無法卸載磁碟。', // from v2.1 added 30.04.2012 + 'errConvUTF8' : '無法轉換為 UTF-8', // from v2.1 added 08.04.2014 + 'errFolderUpload' : '如需上傳資料夾,請使用新式瀏覽器。', // from v2.1 added 26.6.2015 + 'errSearchTimeout' : '搜尋「$1」逾時,因此僅列出部分搜尋結果。', // from v2.1 added 12.1.2016 + 'errReauthRequire' : '必須重新驗證。', // from v2.1.10 added 24.3.2016 + 'errMaxTargets' : '可選取的項目數量上限為 $1。', // from v2.1.17 added 17.10.2016 + 'errRestore' : '無法從 [回收桶] 還原。無法識別還原目標位置。', // from v2.1.24 added 3.5.2017 + 'errEditorNotFound' : '找不到與這個檔案類型關聯的編輯器。', // from v2.1.25 added 23.5.2017 + 'errServerError' : '伺服器端發生錯誤。', // from v2.1.25 added 16.6.2017 + 'errEmpty' : '無法清空資料夾 [$1]。', // from v2.1.25 added 22.6.2017 + 'moreErrors' : '有超過 $1 個錯誤。', // from v2.1.44 added 9.12.2018 + 'errMaxMkdirs' : '最多可以同時建立 $1 個資料夾。', // from v2.1.58 added 20.6.2021 + + /******************************* commands names ********************************/ + 'cmdarchive' : '建立壓縮檔', + 'cmdback' : '返回', + 'cmdcopy' : '複製', + 'cmdcut' : '剪下', + 'cmddownload' : '下載', + 'cmdduplicate' : '再製', + 'cmdedit' : '編輯檔案', + 'cmdextract' : '將壓縮檔解壓縮', + 'cmdforward' : '往前', + 'cmdgetfile' : '選取檔案', + 'cmdhelp' : '關於這個軟體', + 'cmdhome' : '根目錄', + 'cmdinfo' : '取得項目資訊', + 'cmdmkdir' : '新增資料夾', + 'cmdmkdirin' : '移至新資料夾', // from v2.1.7 added 19.2.2016 + 'cmdmkfile' : '新增檔案', + 'cmdopen' : '開啟', + 'cmdpaste' : '貼上', + 'cmdquicklook' : '預覽', + 'cmdreload' : '重新載入', + 'cmdrename' : '重新命名', + 'cmdrm' : '刪除', + 'cmdtrash' : '移至 [回收桶]', //from v2.1.24 added 29.4.2017 + 'cmdrestore' : '還原', //from v2.1.24 added 3.5.2017 + 'cmdsearch' : '尋找檔案', + 'cmdup' : '前往上一層資料夾', + 'cmdupload' : '上傳檔案', + 'cmdview' : '檢視', + 'cmdresize' : '調整大小及旋轉', + 'cmdsort' : '排序方式', + 'cmdnetmount' : '掛接網路磁碟', // added 18.04.2012 + 'cmdnetunmount': '卸載', // from v2.1 added 30.04.2012 + 'cmdplaces' : '加入起始位置', // added 28.12.2014 + 'cmdchmod' : '變更權限', // from v2.1 added 20.6.2015 + 'cmdopendir' : '開啟資料夾', // from v2.1 added 13.1.2016 + 'cmdcolwidth' : '重設欄位寬度', // from v2.1.13 added 12.06.2016 + 'cmdfullscreen': '全螢幕', // from v2.1.15 added 03.08.2016 + 'cmdmove' : '移動', // from v2.1.15 added 21.08.2016 + 'cmdempty' : '清空資料夾', // from v2.1.25 added 22.06.2017 + 'cmdundo' : '復原', // from v2.1.27 added 31.07.2017 + 'cmdredo' : '取消復原', // from v2.1.27 added 31.07.2017 + 'cmdpreference': '偏好設定', // from v2.1.27 added 03.08.2017 + 'cmdselectall' : '全部選取', // from v2.1.28 added 15.08.2017 + 'cmdselectnone': '全部不選', // from v2.1.28 added 15.08.2017 + 'cmdselectinvert': '反向選取', // from v2.1.28 added 15.08.2017 + 'cmdopennew' : '在新視窗中開啟', // from v2.1.38 added 3.4.2018 + 'cmdhide' : '隱藏 (偏好設定)', // from v2.1.41 added 24.7.2018 + + /*********************************** buttons ***********************************/ + 'btnClose' : '關閉', + 'btnSave' : '儲存', + 'btnRm' : '移除', + 'btnApply' : '套用', + 'btnCancel' : '取消', + 'btnNo' : '否', + 'btnYes' : '是', + 'btnDiscard': 'Discard changes', + 'btnMount' : '掛接', // added 18.04.2012 + 'btnApprove': '前往 $1 並核准', // from v2.1 added 26.04.2012 + 'btnUnmount': '卸載', // from v2.1 added 30.04.2012 + 'btnConv' : '轉換', // from v2.1 added 08.04.2014 + 'btnCwd' : '目前位置', // from v2.1 added 22.5.2015 + 'btnVolume' : '磁碟', // from v2.1 added 22.5.2015 + 'btnAll' : '全部', // from v2.1 added 22.5.2015 + 'btnMime' : 'MIME 類型', // from v2.1 added 22.5.2015 + 'btnFileName':'檔案名稱', // from v2.1 added 22.5.2015 + 'btnSaveClose': '儲存並關閉', // from v2.1 added 12.6.2015 + 'btnBackup' : '備份', // fromv2.1 added 28.11.2015 + 'btnRename' : '重新命名', // from v2.1.24 added 6.4.2017 + 'btnRenameAll' : '全部重新命名', // from v2.1.24 added 6.4.2017 + 'btnPrevious' : '上一頁 ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnNext' : '下一頁 ($1/$2)', // from v2.1.24 added 11.5.2017 + 'btnSaveAs' : '另存新檔', // from v2.1.25 added 24.5.2017 + + /******************************** notifications ********************************/ + 'ntfopen' : '開啟資料夾', + 'ntffile' : '開啟檔案', + 'ntfreload' : '重新載入資料夾內容', + 'ntfmkdir' : '正在建立資料夾', + 'ntfmkfile' : '正在建立檔案', + 'ntfrm' : '刪除項目', + 'ntfcopy' : '複製項目', + 'ntfmove' : '移動項目', + 'ntfprepare' : '正在檢查現有項目', + 'ntfrename' : '重新命名檔案', + 'ntfupload' : '正在上傳檔案', + 'ntfdownload' : '正在下載檔案', + 'ntfsave' : '儲存檔案', + 'ntfarchive' : '正在建立壓縮檔', + 'ntfextract' : '正在從壓縮檔解壓縮檔案', + 'ntfsearch' : '正在搜尋檔案', + 'ntfresize' : '正在調整圖片尺寸', + 'ntfsmth' : '正在處理', + 'ntfloadimg' : '正在載入圖片', + 'ntfnetmount' : '正在掛接網路磁碟', // added 18.04.2012 + 'ntfnetunmount': '正在卸載網路磁碟', // from v2.1 added 30.04.2012 + 'ntfdim' : '正在擷取圖片尺寸', // added 20.05.2013 + 'ntfreaddir' : '正在讀取資料夾資訊', // from v2.1 added 01.07.2013 + 'ntfurl' : '正在取得連結的網址', // from v2.1 added 11.03.2014 + 'ntfchmod' : '正在變更檔案權限', // from v2.1 added 20.6.2015 + 'ntfpreupload': '正在驗證上傳檔案名稱', // from v2.1 added 31.11.2015 + 'ntfzipdl' : '正在建立可供下載的檔案', // from v2.1.7 added 23.1.2016 + 'ntfparents' : '正在取得路徑資訊', // from v2.1.17 added 2.11.2016 + 'ntfchunkmerge': '正在處理上傳的檔案', // from v2.1.17 added 2.11.2016 + 'ntftrash' : '正在移至 [回收桶]', // from v2.1.24 added 2.5.2017 + 'ntfrestore' : '正在從 [回收桶] 還原', // from v2.1.24 added 3.5.2017 + 'ntfchkdir' : '正在檢查目標資料夾', // from v2.1.24 added 3.5.2017 + 'ntfundo' : '正在復原之前的操作', // from v2.1.27 added 31.07.2017 + 'ntfredo' : '正在取消復原之前的復原操作', // from v2.1.27 added 31.07.2017 + 'ntfchkcontent' : '正在檢查內容', // from v2.1.41 added 3.8.2018 + + /*********************************** volumes *********************************/ + 'volume_Trash' : '回收桶', //from v2.1.24 added 29.4.2017 + + /************************************ dates **********************************/ + 'dateUnknown' : '未知', + 'Today' : '今天', + 'Yesterday' : '昨天', + 'msJan' : '1 月', + 'msFeb' : '2 月', + 'msMar' : '3 月', + 'msApr' : '4 月', + 'msMay' : '5 月', + 'msJun' : '6 月', + 'msJul' : '7 月', + 'msAug' : '8 月', + 'msSep' : '9 月', + 'msOct' : '10 月', + 'msNov' : '11 月', + 'msDec' : '12 月', + 'January' : '1 月', + 'February' : '2 月', + 'March' : '3 月', + 'April' : '4 月', + 'May' : '5 月', + 'June' : '6 月', + 'July' : '7 月', + 'August' : '8 月', + 'September' : '9 月', + 'October' : '10 月', + 'November' : '11 月', + 'December' : '12 月', + 'Sunday' : '星期日', + 'Monday' : '星期一', + 'Tuesday' : '星期二', + 'Wednesday' : '星期三', + 'Thursday' : '星期四', + 'Friday' : '星期五', + 'Saturday' : '星期六', + 'Sun' : '週日', + 'Mon' : '週一', + 'Tue' : '週二', + 'Wed' : '週三', + 'Thu' : '週四', + 'Fri' : '週五', + 'Sat' : '週六', + + /******************************** sort variants ********************************/ + 'sortname' : '依據名稱', + 'sortkind' : '依據類型', + 'sortsize' : '依據大小', + 'sortdate' : '依據日期', + 'sortFoldersFirst' : '先顯示資料夾', + 'sortperm' : '依據權限', // from v2.1.13 added 13.06.2016 + 'sortmode' : '依據權限', // from v2.1.13 added 13.06.2016 + 'sortowner' : '依據擁有者', // from v2.1.13 added 13.06.2016 + 'sortgroup' : '依據群組', // from v2.1.13 added 13.06.2016 + 'sortAlsoTreeview' : '同時套用於樹狀檢視', // from v2.1.15 added 01.08.2016 + + /********************************** new items **********************************/ + 'untitled file.txt' : '新增檔案.txt', // added 10.11.2015 + 'untitled folder' : '新增資料夾', // added 10.11.2015 + 'Archive' : '新增壓縮檔', // from v2.1 added 10.11.2015 + 'untitled file' : '新增檔案.$1', // from v2.1.41 added 6.8.2018 + 'extentionfile' : '$1: 檔案', // from v2.1.41 added 6.8.2018 + 'extentiontype' : '$1: $2', // from v2.1.43 added 17.10.2018 + + /********************************** messages **********************************/ + 'confirmReq' : '操作確認要求', + 'confirmRm' : '確定要永久移除項目?
                      這項操作無法復原!', + 'confirmRepl' : '是否要以新的項目取代舊的項目?(如果項目包含資料夾,資料夾會合併。如需備份後才取代,請點擊 [備份]。)', + 'confirmRest' : '是否要以 [回收桶] 內的項目取代目前項目?', // fromv2.1.24 added 5.5.2017 + 'confirmConvUTF8' : '不是 UTF-8 編碼
                      轉換至 UTF-8 編碼?
                      轉換後儲存會將內容變更為 UTF-8 編碼。', // from v2.1 added 08.04.2014 + 'confirmNonUTF8' : '無法偵測這個檔案的字元編碼方式。這個檔案需要暫時轉換至 UTF-8 編碼以進行編輯。
                      請選取這個檔案的字元編碼方式。', // from v2.1.19 added 28.11.2016 + 'confirmNotSave' : '項目已修改。
                      如果不儲存變更,便會失去之前的工作成果。', // from v2.1 added 15.7.2015 + 'confirmTrash' : '確定要將項目移至 [回收桶]?', //from v2.1.24 added 29.4.2017 + 'confirmMove' : '確定要將項目移至 [$1]?', //from v2.1.50 added 27.7.2019 + 'apllyAll' : '全部套用', + 'name' : '名稱', + 'size' : '大小', + 'perms' : '權限', + 'modify' : '修改日期', + 'kind' : '類型', + 'read' : '讀取', + 'write' : '寫入', + 'noaccess' : '沒有存取權限', + 'and' : '及', + 'unknown' : '未知', + 'selectall' : '選取全部項目', + 'selectfiles' : '選取項目', + 'selectffile' : '選取第一個項目', + 'selectlfile' : '選取最後一個項目', + 'viewlist' : '清單檢視', + 'viewicons' : '圖示檢視', + 'viewSmall' : '小型圖示', // from v2.1.39 added 22.5.2018 + 'viewMedium' : '中型圖示', // from v2.1.39 added 22.5.2018 + 'viewLarge' : '大型圖示', // from v2.1.39 added 22.5.2018 + 'viewExtraLarge' : '超大型圖示', // from v2.1.39 added 22.5.2018 + 'places' : '起始位置', + 'calc' : '計算', + 'path' : '路徑', + 'aliasfor' : '別名', + 'locked' : '鎖定', + 'dim' : '尺寸', + 'files' : '檔案', + 'folders' : '資料夾', + 'items' : '項目', + 'yes' : '是', + 'no' : '否', + 'link' : '連結', + 'searcresult' : '搜尋結果', + 'selected' : '選取的項目', + 'about' : '關於', + 'shortcuts' : '快速鍵', + 'help' : '使用說明', + 'webfm' : '網頁檔案管理功能', + 'ver' : '版本', + 'protocolver' : '通訊協定版本', + 'homepage' : '專案名稱', + 'docs' : '線上說明', + 'github' : '在 GitHub 上進行分支開發', + 'twitter' : '在 Twitter 上跟隨我們', + 'facebook' : '在 Facebook 加入我們', + 'team' : '團隊', + 'chiefdev' : '首席開發者', + 'developer' : '開發者', + 'contributor' : '參與者', + 'maintainer' : '維護者', + 'translator' : '本地化人員', + 'icons' : '圖示', + 'dontforget' : '請記得宣傳這個程式', + 'shortcutsof' : '快速鍵已停用', + 'dropFiles' : '將檔案拖放至這裡', + 'or' : '或', + 'selectForUpload' : '選取檔案', + 'moveFiles' : '移動項目', + 'copyFiles' : '複製項目', + 'restoreFiles' : '還原項目', // from v2.1.24 added 5.5.2017 + 'rmFromPlaces' : '從起始位置移除', + 'aspectRatio' : '外觀比例', + 'scale' : '縮放', + 'width' : '寬度', + 'height' : '高度', + 'resize' : '調整大小', + 'crop' : '裁剪', + 'rotate' : '旋轉', + 'rotate-cw' : '順時針旋轉 90 度', + 'rotate-ccw' : '逆時針旋轉 90 度', + 'degree' : '°', + 'netMountDialogTitle' : '掛接網路磁碟', // added 18.04.2012 + 'protocol' : '通訊協定', // added 18.04.2012 + 'host' : '主機名稱', // added 18.04.2012 + 'port' : '通訊埠', // added 18.04.2012 + 'user' : '使用者', // added 18.04.2012 + 'pass' : '密碼', // added 18.04.2012 + 'confirmUnmount' : '確定要卸載 $1?', // from v2.1 added 30.04.2012 + 'dropFilesBrowser': '從瀏覽器拖放檔案或貼上檔案', // from v2.1 added 30.05.2012 + 'dropPasteFiles' : '拖放檔案、貼上網址或圖片至這裡', // from v2.1 added 07.04.2014 + 'encoding' : '編碼方式', // from v2.1 added 19.12.2014 + 'locale' : '地區語言', // from v2.1 added 19.12.2014 + 'searchTarget' : '目標: $1', // from v2.1 added 22.5.2015 + 'searchMime' : '依據輸入的 MIME 類型搜尋', // from v2.1 added 22.5.2015 + 'owner' : '擁有者', // from v2.1 added 20.6.2015 + 'group' : '群組', // from v2.1 added 20.6.2015 + 'other' : '其他', // from v2.1 added 20.6.2015 + 'execute' : '執行', // from v2.1 added 20.6.2015 + 'perm' : '權限', // from v2.1 added 20.6.2015 + 'mode' : '權限', // from v2.1 added 20.6.2015 + 'emptyFolder' : '資料夾為空', // from v2.1.6 added 30.12.2015 + 'emptyFolderDrop' : '資料夾為空\\A拖放以新增項目', // from v2.1.6 added 30.12.2015 + 'emptyFolderLTap' : '資料夾為空\\A長按以新增項目', // from v2.1.6 added 30.12.2015 + 'quality' : '品質', // from v2.1.6 added 5.1.2016 + 'autoSync' : '自動同步', // from v2.1.6 added 10.1.2016 + 'moveUp' : '上移', // from v2.1.6 added 18.1.2016 + 'getLink' : '取得網址連結', // from v2.1.7 added 9.2.2016 + 'selectedItems' : '選取的項目 ($1)', // from v2.1.7 added 2.19.2016 + 'folderId' : '資料夾 ID', // from v2.1.10 added 3.25.2016 + 'offlineAccess' : '允許離線存取', // from v2.1.10 added 3.25.2016 + 'reAuth' : '重新驗證', // from v2.1.10 added 3.25.2016 + 'nowLoading' : '正在載入...', // from v2.1.12 added 4.26.2016 + 'openMulti' : '開啟多個檔案', // from v2.1.12 added 5.14.2016 + 'openMultiConfirm': '目前正在嘗試開啟 $1 個檔案。確定要在瀏覽器中開啟?', // from v2.1.12 added 5.14.2016 + 'emptySearch' : '搜尋目標的搜尋結果為空。', // from v2.1.12 added 5.16.2016 + 'editingFile' : '目前正在編輯檔案。', // from v2.1.13 added 6.3.2016 + 'hasSelected' : '已選取 $1 個項目。', // from v2.1.13 added 6.3.2016 + 'hasClipboard' : '剪貼簿中有 $1 個項目。', // from v2.1.13 added 6.3.2016 + 'incSearchOnly' : '僅能在目前的檢視方式中進行累加搜尋。', // from v2.1.13 added 6.30.2016 + 'reinstate' : '還原', // from v2.1.15 added 3.8.2016 + 'complete' : '$1已完成', // from v2.1.15 added 21.8.2016 + 'contextmenu' : '操作功能表', // from v2.1.15 added 9.9.2016 + 'pageTurning' : '換頁', // from v2.1.15 added 10.9.2016 + 'volumeRoots' : '磁碟根目錄', // from v2.1.16 added 16.9.2016 + 'reset' : '重設', // from v2.1.16 added 1.10.2016 + 'bgcolor' : '背景色彩', // from v2.1.16 added 1.10.2016 + 'colorPicker' : '色彩選擇器', // from v2.1.16 added 1.10.2016 + '8pxgrid' : '8px 格狀排列', // from v2.1.16 added 4.10.2016 + 'enabled' : '啟用', // from v2.1.16 added 4.10.2016 + 'disabled' : '停用', // from v2.1.16 added 4.10.2016 + 'emptyIncSearch' : '在目前的檢視方式中搜尋結果為空。\\A按下 Enter 以擴大搜尋目標。', // from v2.1.16 added 5.10.2016 + 'emptyLetSearch' : '在目前的檢視方式中首個字母搜尋的搜尋結果為空。', // from v2.1.23 added 24.3.2017 + 'textLabel' : '文字標籤', // from v2.1.17 added 13.10.2016 + 'minsLeft' : '剩下 $1 分鐘', // from v2.1.17 added 13.11.2016 + 'openAsEncoding' : '以選取的編碼方式重新開啟', // from v2.1.19 added 2.12.2016 + 'saveAsEncoding' : '以選取的編碼方式儲存', // from v2.1.19 added 2.12.2016 + 'selectFolder' : '選取資料夾', // from v2.1.20 added 13.12.2016 + 'firstLetterSearch': '首個字母搜尋', // from v2.1.23 added 24.3.2017 + 'presets' : '預設集', // from v2.1.25 added 26.5.2017 + 'tooManyToTrash' : '由於要移除的檔案數量超過上限,因此無法移至 [回收桶]。', // from v2.1.25 added 9.6.2017 + 'TextArea' : '文字區域', // from v2.1.25 added 14.6.2017 + 'folderToEmpty' : '清空資料夾 [$1]。', // from v2.1.25 added 22.6.2017 + 'filderIsEmpty' : '資料夾 $1 中沒有任何項目。', // from v2.1.25 added 22.6.2017 + 'preference' : '偏好設定', // from v2.1.26 added 28.6.2017 + 'language' : '介面語言', // from v2.1.26 added 28.6.2017 + 'clearBrowserData': '初始化這個瀏覽器中已儲存的設定', // from v2.1.26 added 28.6.2017 + 'toolbarPref' : '工具列設定', // from v2.1.27 added 2.8.2017 + 'charsLeft' : '... 剩下 $1 個字元。', // from v2.1.29 added 30.8.2017 + 'linesLeft' : '... 剩下 $1 行。', // from v2.1.52 added 16.1.2020 + 'sum' : '總計', // from v2.1.29 added 28.9.2017 + 'roughFileSize' : '檔案概略大小', // from v2.1.30 added 2.11.2017 + 'autoFocusDialog' : '聚焦於游標暫留對話方塊的元素', // from v2.1.30 added 2.11.2017 + 'select' : '選取', // from v2.1.30 added 23.11.2017 + 'selectAction' : '選取檔案後的動作', // from v2.1.30 added 23.11.2017 + 'useStoredEditor' : '使用上次的編輯器開啟', // from v2.1.30 added 23.11.2017 + 'selectinvert' : '反向選取', // from v2.1.30 added 25.11.2017 + 'renameMultiple' : '確定要將選取的項目 $1 重新命名為 $2?
                      這項操作無法復原!', // from v2.1.31 added 4.12.2017 + 'batchRename' : '批次重新命名', // from v2.1.31 added 8.12.2017 + 'plusNumber' : '增加數值', // from v2.1.31 added 8.12.2017 + 'asPrefix' : '新增前置詞', // from v2.1.31 added 8.12.2017 + 'asSuffix' : '新增後置詞', // from v2.1.31 added 8.12.2017 + 'changeExtention' : '變更副檔名', // from v2.1.31 added 8.12.2017 + 'columnPref' : '欄位設定 (清單檢視)', // from v2.1.32 added 6.2.2018 + 'reflectOnImmediate' : '全部變更會立即影響壓縮檔。', // from v2.1.33 added 2.3.2018 + 'reflectOnUnmount' : '在卸載這個磁碟前,任何變更均不會生效。', // from v2.1.33 added 2.3.2018 + 'unmountChildren' : '掛接在這個磁碟的下列磁碟無法卸載。確定要卸載這個磁碟?', // from v2.1.33 added 5.3.2018 + 'selectionInfo' : '選取項目資訊', // from v2.1.33 added 7.3.2018 + 'hashChecker' : '用於顯示檔案雜湊值的演算法', // from v2.1.33 added 10.3.2018 + 'infoItems' : '資訊項目 (用於選取項目的資訊面板)', // from v2.1.38 added 28.3.2018 + 'pressAgainToExit': '再按一下以離開。', // from v2.1.38 added 1.4.2018 + 'toolbar' : '工具列', // from v2.1.38 added 4.4.2018 + 'workspace' : '工作區', // from v2.1.38 added 4.4.2018 + 'dialog' : '對話方塊', // from v2.1.38 added 4.4.2018 + 'all' : '全部', // from v2.1.38 added 4.4.2018 + 'iconSize' : '圖示尺寸 (圖示檢視)', // from v2.1.39 added 7.5.2018 + 'editorMaximized' : '開啟最大化編輯器視窗', // from v2.1.40 added 30.6.2018 + 'editorConvNoApi' : '由於轉換 API 目前無法使用,請在網站上進行轉換。', //from v2.1.40 added 8.7.2018 + 'editorConvNeedUpload' : '完成轉換後,必須使用項目的網址上傳或下載檔案以儲存轉換後的檔案。', //from v2.1.40 added 8.7.2018 + 'convertOn' : '在 $1 的網站上轉換', // from v2.1.40 added 10.7.2018 + 'integrations' : '整合項目', // from v2.1.40 added 11.7.2018 + 'integrationWith' : '這裡會列出 elFinder 整合的外部服務。請在使用 elFinder 前先查看這些整合項目的使用條款、隱私權政策等內容。', // from v2.1.40 added 11.7.2018 + 'showHidden' : '顯示隱藏項目', // from v2.1.41 added 24.7.2018 + 'hideHidden' : '隱藏隱藏項目', // from v2.1.41 added 24.7.2018 + 'toggleHidden' : '顯示/隱藏隱藏項目', // from v2.1.41 added 24.7.2018 + 'makefileTypes' : '新增檔案可以新增的檔案類型', // from v2.1.41 added 7.8.2018 + 'typeOfTextfile' : '文字檔案類型', // from v2.1.41 added 7.8.2018 + 'add' : '新增', // from v2.1.41 added 7.8.2018 + 'theme' : '佈景主題', // from v2.1.43 added 19.10.2018 + 'default' : '預設', // from v2.1.43 added 19.10.2018 + 'description' : '內容說明', // from v2.1.43 added 19.10.2018 + 'website' : '網站', // from v2.1.43 added 19.10.2018 + 'author' : '開發者', // from v2.1.43 added 19.10.2018 + 'email' : '電子郵件地址', // from v2.1.43 added 19.10.2018 + 'license' : '授權方式', // from v2.1.43 added 19.10.2018 + 'exportToSave' : '這個項目無法儲存。為避免遺失編輯資料,必須將資料匯出至個人裝置。', // from v2.1.44 added 1.12.2018 + 'dblclickToSelect': '按兩下檔案以選取。', // from v2.1.47 added 22.1.2019 + 'useFullscreen' : '使用全螢幕模式', // from v2.1.47 added 19.2.2019 + + /********************************** mimetypes **********************************/ + 'kindUnknown' : '未知', + 'kindRoot' : '磁碟根目錄', // from v2.1.16 added 16.10.2016 + 'kindFolder' : '資料夾', + 'kindSelects' : 'Selections', // from v2.1.29 added 29.8.2017 + 'kindAlias' : '別名', + 'kindAliasBroken' : '中斷的別名', + // applications + 'kindApp' : '應用程式', + 'kindPostscript' : 'PostScript 文件', + 'kindMsOffice' : 'Microsoft Office 文件', + 'kindMsWord' : 'Microsoft Word 文件', + 'kindMsExcel' : 'Microsoft Excel 試算表', + 'kindMsPP' : 'Microsoft Powerpoint 簡報', + 'kindOO' : 'Open Office 文件', + 'kindAppFlash' : 'Flash 應用程式', + 'kindPDF' : 'PDF 文件', + 'kindTorrent' : 'Bittorrent 檔案', + 'kind7z' : '7z 壓縮檔', + 'kindTAR' : 'TAR 壓縮檔', + 'kindGZIP' : 'GZIP 壓縮檔', + 'kindBZIP' : 'BZIP 壓縮檔', + 'kindXZ' : 'XZ 壓縮檔', + 'kindZIP' : 'ZIP 壓縮檔', + 'kindRAR' : 'RAR 壓縮檔', + 'kindJAR' : 'Java JAR 檔案', + 'kindTTF' : 'True Type 字型', + 'kindOTF' : 'Open Type 字型', + 'kindRPM' : 'RPM 封裝檔案', + // fonts + 'kindFont' : '字型', + 'kindSFNT' : 'SFNT 字型', + 'kindEOT' : 'Embedded Open Type 字型', + 'kindWOFF' : 'Web Open Font Format 字型', + 'kindWOFF2' : 'Web Open Font Format 2 字型', + // texts + 'kindText' : '文字檔案', + 'kindTextPlain' : '純文字', + 'kindPHP' : 'PHP 原始程式碼', + 'kindCSS' : '階層式樣式表 (CSS)', + 'kindHTML' : 'HTML 文件', + 'kindJS' : 'JavaScript 原始程式碼', + 'kindRTF' : 'RTF 格式', + 'kindC' : 'C 原始程式碼', + 'kindCHeader' : 'C 標頭原始程式碼', + 'kindCPP' : 'C++ 原始程式碼', + 'kindCPPHeader' : 'C++ 標頭原始程式碼', + 'kindShell' : 'Unix 殼層指令碼', + 'kindPython' : 'Python 原始程式碼', + 'kindJava' : 'Java 原始程式碼', + 'kindRuby' : 'Ruby 原始程式碼', + 'kindPerl' : 'Perl 指令碼', + 'kindSQL' : 'SQL 原始程式碼', + 'kindXML' : 'XML 文件', + 'kindAWK' : 'AWK 原始程式碼', + 'kindCSV' : '逗點分隔值 (CSV)', + 'kindDOCBOOK' : 'Docbook XML 文件', + 'kindMarkdown' : 'Markdown 文字', // added 20.7.2015 + // images + 'kindImage' : '圖片', + 'kindBMP' : 'BMP 圖片', + 'kindJPEG' : 'JPEG 圖片', + 'kindGIF' : 'GIF 圖片', + 'kindPNG' : 'PNG 圖片', + 'kindTIFF' : 'TIFF 圖片', + 'kindTGA' : 'TGA 圖片', + 'kindPSD' : 'Adobe Photoshop 圖片', + 'kindXBITMAP' : 'X bitmap 圖片', + 'kindPXM' : 'Pixelmator 圖片', + // media + 'kindAudio' : '音訊', + 'kindAudioMPEG' : 'MPEG 音訊', + 'kindAudioMPEG4' : 'MPEG-4 音訊', + 'kindAudioMIDI' : 'MIDI 音訊', + 'kindAudioOGG' : 'Ogg Vorbis 音訊', + 'kindAudioWAV' : 'WAV 音訊', + 'AudioPlaylist' : 'MP3 播放清單', + 'kindVideo' : '視訊', + 'kindVideoDV' : 'DV 影片', + 'kindVideoMPEG' : 'MPEG 影片', + 'kindVideoMPEG4' : 'MPEG-4 影片', + 'kindVideoAVI' : 'AVI 影片', + 'kindVideoMOV' : 'Quick Time 影片', + 'kindVideoWM' : 'Windows Media 影片', + 'kindVideoFlash' : 'Flash 影片', + 'kindVideoMKV' : 'Matroska 影片', + 'kindVideoOGG' : 'Ogg 影片' + } + }; +})); + diff --git a/lib/redactor/elfinder/js/i18n/help/cs.html.js b/lib/redactor/elfinder/js/i18n/help/cs.html.js new file mode 100644 index 0000000..fd39f48 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/cs.html.js @@ -0,0 +1,10 @@ +

                      Tipy na obsluhu

                      +

                      Obsluha na uživatelském rozhraní je podobná standardnímu správci souborů operačního systému. Drag and Drop však není možné používat s mobilními prohlížeči.

                      +
                        +
                      • Kliknutím pravým tlačítkem nebo dlouhým klepnutím zobrazíte kontextové menu.
                      • +
                      • Přetáhněte do stromu složek nebo do aktuálního pracovního prostoru a přetáhněte / kopírujte položky.
                      • +
                      • Výběr položky v pracovním prostoru můžete rozšířit pomocí kláves Shift nebo Alt (Možnost).
                      • +
                      • Přemístěte soubory a složky do cílové složky nebo do pracovního prostoru.
                      • +
                      • Dialog předávání může přijímat data schránky nebo seznamy adres URL a přitáhnout a odejít z jiných prohlížečů nebo správců souborů.
                      • +
                      • Zatažením spusťte stisknutím klávesy Alt (Možnost) přetáhněte do vnějšího prohlížeče. Tato funkce se převezme pomocí prohlížeče Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/de.html.js b/lib/redactor/elfinder/js/i18n/help/de.html.js new file mode 100644 index 0000000..41cc3b9 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/de.html.js @@ -0,0 +1,15 @@ +

                      Anwendungstipps

                      +

                      Die Verwendung dieser Anwendung ist ähnlich der einer lokalen Dateiverwaltung.
                      Hinweis: auf mobilen Geräten ist das Ziehen und Ablegen (Drag and Drop) von Dateien nicht möglich.

                      +
                        +
                      • Rechtsklick auf ein Element oder länger darauf zeigen öffnet das Kontextmenü
                      • +
                      • Um Elemente in andere Ordner oder aktuellen Arbeitsbereich zu kopieren oder verschieben diese Ziehen und Ablegen
                      • +
                      • Elementauswahl im Arbeitsbereich kann mit der Hochstell- oder ALT-TAste erweitert werden
                      • +
                      • Um lokale Ordner und Dateien in den Zielorder oder -arbeitsbereich zu kopieren diese Ziehen und Ablegen
                      • +
                      • Der Uploaddialog erlaubt Daten aus dem Clipboard (Zwischenspeicher), eine URL und Ziehen und Ablegen aus anderen Browsern und Dateiverwaltungsoberflächen
                      • +
                      • Ziehen mit gedrückter ALT-Taste erlaubt einen einfachen Dateidownload (nur Google Chrome)
                      • +
                      • Ordner und Dateien können ausgeblendet (versteckt) werden. Um sie wieder dauerhaft sichtbar zu machen, über die Menüleiste das "Icon Einstellungen" anklicken, dort unter Arbeitsplatz "Zeige versteckte Elemente" den Button "Neustart" anklicken
                      • +
                      • Das Kontextmenü (rechte Maustaste) zeigt je nach ausgewählten Element diverse Aktionen an
                      • +
                      • Je nach Art des Elements kann der Inhalt entweder mit dem integrierten Editor bearbeitet werden (z.B. .php, .txt, .ini usw.) oder wenn ein Bild dieses gedreht sowie die Größe geändert werden
                      • +
                      • Zum verbinden externer Speicherorte (FTP, Dropbox, Box, GoogleDrive, OneDrive) sowie Onlineeditor Zoho Office Editor oder Konvertierungsdienst Online-Convert müssen diese Anwendungen freigeschaltet als auch die entsprechenden API-Daten zum Abrufen je Dienst definiert sein.
                        Sollten diese Dienste nicht verfügbar sein, müssen diese entweder selbständig dazu programmiert werden, oder einen Entwickler des Vertrauens damit beauftragen (z.B. OSWorX)
                      • +
                      • In den Einstellungen "Menü Icon Einstellungen" kann der gesamte Arbeitsbereich, die Menüleiste sowie etliche weitere Aktionen definiert werden
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/en.html b/lib/redactor/elfinder/js/i18n/help/en.html new file mode 100644 index 0000000..eae309e --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/en.html @@ -0,0 +1,10 @@ +

                      Operation Tips

                      +

                      Operation on the UI is similar to operating system's standard file manager. However, Drag and Drop is not possible with mobile browsers.

                      +
                        +
                      • Right click or long tap to show the context menu.
                      • +
                      • Drag and drop into the folder tree or the current workspace to move/copy items.
                      • +
                      • Item selection in the workspace can be extended selection with Shift or Alt (Option) key.
                      • +
                      • Drag and Drop to the destination folder or workspace to upload files and folders.
                      • +
                      • The upload dialog can accept paste/drop clipboard data or URL lists and Drag and Drop from other browser or file managers etc.
                      • +
                      • Drag start with pressing Alt(Option) key to drag out to outside browser. It will became download operation with Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/en.html.js b/lib/redactor/elfinder/js/i18n/help/en.html.js new file mode 100644 index 0000000..eae309e --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/en.html.js @@ -0,0 +1,10 @@ +

                      Operation Tips

                      +

                      Operation on the UI is similar to operating system's standard file manager. However, Drag and Drop is not possible with mobile browsers.

                      +
                        +
                      • Right click or long tap to show the context menu.
                      • +
                      • Drag and drop into the folder tree or the current workspace to move/copy items.
                      • +
                      • Item selection in the workspace can be extended selection with Shift or Alt (Option) key.
                      • +
                      • Drag and Drop to the destination folder or workspace to upload files and folders.
                      • +
                      • The upload dialog can accept paste/drop clipboard data or URL lists and Drag and Drop from other browser or file managers etc.
                      • +
                      • Drag start with pressing Alt(Option) key to drag out to outside browser. It will became download operation with Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/es.html.js b/lib/redactor/elfinder/js/i18n/help/es.html.js new file mode 100644 index 0000000..dc37910 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/es.html.js @@ -0,0 +1,10 @@ +

                      Consejos de operación

                      +

                      Operar en la Interfaz del Usuario es similar al administrador de archivos estandar del sistema operativo. Sin embargo, Arrastrar y soltar no es posible con los navegadores móviles.

                      +
                        +
                      • Click derecho o un tap largo para mostrar el menú de contexto.
                      • +
                      • Arrastrar y soltar dentro del árbol de carpetas o el espacio de trabajo actual para mover/copiar elementos.
                      • +
                      • La selección de elementos en el espacio de trabajo puede ampliarse con la tecla Shift o Alt (Opción).
                      • +
                      • Arrastrar y soltar a la carpeta de destino o área de trabajo para cargar archivos y carpetas.
                      • +
                      • El cuadro de diálogo de carga puede aceptar pegar/soltar datos del portapapeles o listas de URL y arrastrar y soltar desde otro navegador o administrador de archivos, etc.
                      • +
                      • Iniciar a arrastrar presionando la tecla Alt (Opción) para arrastrar fuera del navegador. Se convertirá en una operación de descarga con Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/fr.html.js b/lib/redactor/elfinder/js/i18n/help/fr.html.js new file mode 100644 index 0000000..26a87a0 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/fr.html.js @@ -0,0 +1,10 @@ +

                      Conseils d'utilisation

                      +

                      Le fonctionnement sur l'interface utilisateur est similaire à celui du gestionnaire de fichiers standard du système d'exploitation. Cependant, le glisser-déposer n'est pas possible avec les navigateurs mobiles.

                      +
                        +
                      • Cliquez avec le bouton droit ou appuyez longuement pour afficher le menu contextuel.
                      • +
                      • Faites glisser et déposez dans l'arborescence des dossiers ou dans l'espace de travail actuel pour déplacer/copier des éléments.
                      • +
                      • La sélection d'éléments dans l'espace de travail peut être une sélection étendue avec la touche Maj ou Alt (Option).
                      • +
                      • Faites glisser et déposez vers le dossier ou l'espace de travail de destination pour télécharger des fichiers et des dossiers.
                      • +
                      • La boîte de dialogue de téléchargement peut accepter le collage/déplacement de données du presse-papiers ou de listes d'URL, ainsi que le glisser-déposer depuis d'autres navigateurs ou gestionnaires de fichiers, etc.
                      • +
                      • Faites glisser le début en appuyant sur la touche Alt (Option) pour le faire glisser vers l'extérieur du navigateur. Cela deviendra une opération de téléchargement avec Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/ja.html.js b/lib/redactor/elfinder/js/i18n/help/ja.html.js new file mode 100644 index 0000000..555d4c8 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/ja.html.js @@ -0,0 +1,10 @@ +

                      操作のヒント

                      +

                      UIの操作は、オペレーティングシステムの標準ファイルマネージャにほぼ準拠しています。ただし、モバイルブラウザではドラッグ&ドロップはできません。

                      +
                        +
                      • 右クリックまたはロングタップでコンテキストメニューを表示します。
                      • +
                      • アイテムを移動/コピーするには、フォルダツリーまたはワークスペースにドラッグ&ドロップします。
                      • +
                      • ワークスペース内のアイテムの選択は、ShiftキーまたはAltキー(Optionキー)で選択範囲を拡張できます。
                      • +
                      • コピー先のフォルダまたはワークスペースにドラッグアンドドロップして、ファイルとフォルダをアップロードします。
                      • +
                      • アップロードダイアログでは、クリップボードのデータやURLリストのペースト/ドロップ、他のブラウザやファイルマネージャからのドラッグ&ドロップなどを受け入れることができます。
                      • +
                      • Altキー(Optionキー)を押しながらドラッグすると、ブラウザの外にドラッグできます。Google Chromeでダウンロード操作になります。
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/jp.html b/lib/redactor/elfinder/js/i18n/help/jp.html new file mode 100644 index 0000000..555d4c8 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/jp.html @@ -0,0 +1,10 @@ +

                      操作のヒント

                      +

                      UIの操作は、オペレーティングシステムの標準ファイルマネージャにほぼ準拠しています。ただし、モバイルブラウザではドラッグ&ドロップはできません。

                      +
                        +
                      • 右クリックまたはロングタップでコンテキストメニューを表示します。
                      • +
                      • アイテムを移動/コピーするには、フォルダツリーまたはワークスペースにドラッグ&ドロップします。
                      • +
                      • ワークスペース内のアイテムの選択は、ShiftキーまたはAltキー(Optionキー)で選択範囲を拡張できます。
                      • +
                      • コピー先のフォルダまたはワークスペースにドラッグアンドドロップして、ファイルとフォルダをアップロードします。
                      • +
                      • アップロードダイアログでは、クリップボードのデータやURLリストのペースト/ドロップ、他のブラウザやファイルマネージャからのドラッグ&ドロップなどを受け入れることができます。
                      • +
                      • Altキー(Optionキー)を押しながらドラッグすると、ブラウザの外にドラッグできます。Google Chromeでダウンロード操作になります。
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/ko.html.js b/lib/redactor/elfinder/js/i18n/help/ko.html.js new file mode 100644 index 0000000..7656f92 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/ko.html.js @@ -0,0 +1,10 @@ +

                      사용 팁

                      +

                      UI 조작은 운영체제의 표준 파일 관리자를 사용하는 방법과 비슷합니다. 하지만 모바일 브라우저에서는 드래그앤드롭을 사용할 수 없습니다.

                      +
                        +
                      • 오른쪽 클릭하거나 길게 누르면 컨텍스트 메뉴가 나타납니다.
                      • +
                      • 이동/복사하려면 폴더 트리 또는 원하는 폴더로 드래그앤드롭하십시오.
                      • +
                      • 작업공간에서 항목을 선택하려면 Shift또는 Alt(Option) 키를 사용하여 선택 영역을 넓힐 수 있습니다.
                      • +
                      • 업로드 대상 폴더 또는 작업 영역으로 파일및 폴더를 드래그앤드롭하여 업로드할 수 있습니다.
                      • +
                      • 다른 브라우저 또는 파일관리자등에서 드래그앤드롭하거나, 클립보드를 통해 데이터또는 URL을 복사/붙여넣어 업로드할 수 있습니다.
                      • +
                      • 크롬브라우저의 경우, Alt(Option) 키를 누른 상태에서 브라우저 밖으로 드래그앤드롭하면 다운로드가 가능합니다.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/pl.html.js b/lib/redactor/elfinder/js/i18n/help/pl.html.js new file mode 100644 index 0000000..27b6f7c --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/pl.html.js @@ -0,0 +1,10 @@ +

                      Wskazówki Obsługi

                      +

                      Działanie w interfejsie użytkownika jest podobne do standardowego menedżera plików systemu operacyjnego. Jednak Przeciąganie i Upuszczanie nie jest możliwe w przeglądarkach mobilnych.

                      +
                        +
                      • Kliknij prawym przyciskiem myszy lub dłużej, aby wyświetlić menu kontekstowe.
                      • +
                      • Przeciągnij i upuść w drzewie folderów lub bieżącym obszarze roboczym, aby przenieść/kopiować elementy.
                      • +
                      • Wybór elementu w obszarze roboczym można rozszerzyć wybór z klawiszem Shift lub Alt(Opcja).
                      • +
                      • Przeciągnij i Upuść do folderu docelowego lub obszaru roboczego, aby przesłać pliki i foldery.
                      • +
                      • W oknie dialogowym przesyłania można zaakceptować wklejanie/upuszczanie danych schowka lub listy adresów URL, i Przeciągnij i Upuść z innych przeglądarek lub menedżerów plików, itp.
                      • +
                      • Rozpocznij Przeciąganie naciskając Alt (Opcja), aby przeciągnąć na zewnątrz przeglądarki. Stanie się operacją pobierania z Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/ru.html b/lib/redactor/elfinder/js/i18n/help/ru.html new file mode 100644 index 0000000..eae309e --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/ru.html @@ -0,0 +1,10 @@ +

                      Operation Tips

                      +

                      Operation on the UI is similar to operating system's standard file manager. However, Drag and Drop is not possible with mobile browsers.

                      +
                        +
                      • Right click or long tap to show the context menu.
                      • +
                      • Drag and drop into the folder tree or the current workspace to move/copy items.
                      • +
                      • Item selection in the workspace can be extended selection with Shift or Alt (Option) key.
                      • +
                      • Drag and Drop to the destination folder or workspace to upload files and folders.
                      • +
                      • The upload dialog can accept paste/drop clipboard data or URL lists and Drag and Drop from other browser or file managers etc.
                      • +
                      • Drag start with pressing Alt(Option) key to drag out to outside browser. It will became download operation with Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/ru.html.js b/lib/redactor/elfinder/js/i18n/help/ru.html.js new file mode 100644 index 0000000..d33e3da --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/ru.html.js @@ -0,0 +1,10 @@ +

                      Советы по работе

                      +

                      Работа с пользовательским интерфейсом похожа на стандартный файловый менеджер операционной системы. Однако перетаскивание в мобильных браузерах невозможно.

                      +
                        +
                      • Щелкните правой кнопкой мыши или используйте «длинный тап», чтобы отобразить контекстное меню.
                      • +
                      • Перетащите в дерево папок или текущую рабочую область для перемещения / копирования элементов.
                      • +
                      • Выбор элемента в рабочей области может быть расширен с помощью клавиши Shift или Alt (Option).
                      • +
                      • Перетащите в папку назначения или рабочую область для загрузки файлов и папок.
                      • +
                      • В диалоговом окне загрузки можно использовать вставку данных или списков URL-адресов из буфера обмена, а также перетаскивать из других браузеров или файловых менеджеров и т.д.
                      • +
                      • Начните перетаскивание, нажав Alt (Option), чтобы перетащить за пределы браузера. Это запустить процесс скачивания в Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/sk.html.js b/lib/redactor/elfinder/js/i18n/help/sk.html.js new file mode 100644 index 0000000..7a1542b --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/sk.html.js @@ -0,0 +1,10 @@ +

                      Tipy na obsluhu

                      +

                      Obsluha na používateľskom rozhraní je podobná štandardnému správcovi súborov operačného systému. Drag and Drop však nie je možné používať s mobilnými prehliadačmi.

                      +
                        +
                      • Kliknutím pravým tlačidlom alebo dlhým klepnutím zobrazíte kontextové menu.
                      • +
                      • Presuňte myšou do stromu priečinkov alebo do aktuálneho pracovného priestoru a presuňte / kopírujte položky.
                      • +
                      • Výber položky v pracovnom priestore môžete rozšíriť pomocou klávesov Shift alebo Alt (Možnosť).
                      • +
                      • Premiestnite súbory a priečinky do cieľovej zložky alebo do pracovného priestoru.
                      • +
                      • Dialog odovzdávania môže prijímať dáta schránky alebo zoznamy adries URL a pritiahnuť a odísť z iných prehliadačov alebo správcov súborov.
                      • +
                      • Potiahnutím spustite stlačením klávesu Alt (Možnosť) pretiahnite do vonkajšieho prehliadača. Táto funkcia sa prevezme pomocou prehliadača Google Chrome.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/tr.html.js b/lib/redactor/elfinder/js/i18n/help/tr.html.js new file mode 100644 index 0000000..8803d17 --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/tr.html.js @@ -0,0 +1,10 @@ +

                      İşlem İpuçları

                      +

                      Kullanıcı arayüzündeki işlem, işletim sisteminin standart dosya yöneticisine benzer. Ancak Sürükle ve Bırak özelliği mobil tarayıcılarda mümkün değildir.

                      +
                        +
                      • Bağlam menüsünü göstermek için sağ tıklayın veya uzun dokunun.
                      • +
                      • Öğeleri taşımak/kopyalamak için klasör ağacına veya geçerli çalışma alanına sürükleyip bırakın.
                      • +
                      • Çalışma alanındaki öğe seçimi Shift veya Alt (Seçenek) tuşuyla genişletilebilir.
                      • +
                      • Dosya ve klasör yüklemek için hedef klasöre veya çalışma alanına sürükleyip bırakın.
                      • +
                      • Yükleme iletişim kutusu, pano verilerini veya URL listelerini yapıştırma/bırakma ve diğer tarayıcı veya dosya yöneticilerinden Sürükle ve Bırak vb.
                      • +
                      • Dış tarayıcıya sürüklemek için Alt (Seçenek) tuşuna basarak sürükleyin. Google Chrome ile indirme işlemi olacak.
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/zh_CN.html.js b/lib/redactor/elfinder/js/i18n/help/zh_CN.html.js new file mode 100644 index 0000000..347f5ab --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/zh_CN.html.js @@ -0,0 +1,10 @@ +

                      操作提示

                      +

                      在UI上的操作类似于操作系统的标准文件管理器。 但是在移动设备浏览器不能进行拖放。

                      +
                        +
                      • 右键单击或长按显示上下文菜单。
                      • +
                      • 将文件拖放到树状文件夹或目前工作区便能移动/复制文件。
                      • +
                      • 工作空间中的文件选择可以通过Shift或Alt(Option)键进行多选。
                      • +
                      • 拖放到目标文件夹或工作区上开始上传文件和文件夹。
                      • +
                      • 上传对话框可以粘贴/拖放剪贴板数据或URL列表,以及从其他浏览器或文件管理器拖放的文件。
                      • +
                      • 拖动从按下Alt(Option)键开始拖动到外部浏览器,会变成 Google Chrome 的下载操作。
                      • +
                      diff --git a/lib/redactor/elfinder/js/i18n/help/zh_TW.html.js b/lib/redactor/elfinder/js/i18n/help/zh_TW.html.js new file mode 100644 index 0000000..86110db --- /dev/null +++ b/lib/redactor/elfinder/js/i18n/help/zh_TW.html.js @@ -0,0 +1,10 @@ +

                      操作使用提示

                      +

                      介面的操作類似作業系統中的標準檔案管理功能,但是在行動裝置瀏覽器中無法進行拖放操作。

                      +
                        +
                      • 點擊右鍵或長按便會顯示操作功能表
                      • +
                      • 將項目拖放至樹狀資料夾或目前工作區便能移動/複製項目。
                      • +
                      • 搭配使用 Shift 或 Alt (Option) 鍵,便能在工作區對項目進行延伸選取。
                      • +
                      • 從儲存裝置拖放項目至目標資料夾或工作區,便能上傳檔案及資料夾。
                      • +
                      • 上傳對話方塊可以貼上/拖放剪貼簿資料或網址清單,以及從其他瀏覽器或檔案管理程式拖放的檔案。
                      • +
                      • 按住 Alt (Option) 鍵將選取的項目拖放至瀏覽器,會成為 Google Chrome 的下載操作。
                      • +
                      diff --git a/lib/redactor/elfinder/js/proxy/elFinderSupportVer1.js b/lib/redactor/elfinder/js/proxy/elFinderSupportVer1.js new file mode 100644 index 0000000..d9fb3fb --- /dev/null +++ b/lib/redactor/elfinder/js/proxy/elFinderSupportVer1.js @@ -0,0 +1,408 @@ +/** + * elFinder transport to support old protocol. + * + * @example + * $('selector').elfinder({ + * .... + * transport : new elFinderSupportVer1() + * }) + * + * @author Dmitry (dio) Levashov + **/ +window.elFinderSupportVer1 = function(upload) { + "use strict"; + var self = this, + dateObj, today, yesterday, + getDateString = function(date) { + return date.replace('Today', today).replace('Yesterday', yesterday); + }; + + dateObj = new Date(); + today = dateObj.getFullYear() + '/' + (dateObj.getMonth() + 1) + '/' + dateObj.getDate(); + dateObj = new Date(Date.now() - 86400000); + yesterday = dateObj.getFullYear() + '/' + (dateObj.getMonth() + 1) + '/' + dateObj.getDate(); + + this.upload = upload || 'auto'; + + this.init = function(fm) { + this.fm = fm; + this.fm.parseUploadData = function(text) { + var data; + + if (!$.trim(text)) { + return {error : ['errResponse', 'errDataEmpty']}; + } + + try { + data = JSON.parse(text); + } catch (e) { + return {error : ['errResponse', 'errDataNotJSON']}; + } + + return self.normalize('upload', data); + }; + }; + + + this.send = function(opts) { + var self = this, + fm = this.fm, + dfrd = $.Deferred(), + cmd = opts.data.cmd, + args = [], + _opts = {}, + data, + xhr; + + dfrd.abort = function() { + if (xhr.state() == 'pending') { + xhr.quiet = true; + xhr.abort(); + } + }; + + switch (cmd) { + case 'open': + opts.data.tree = 1; + break; + case 'parents': + case 'tree': + return dfrd.resolve({tree : []}); + case 'get': + opts.data.cmd = 'read'; + opts.data.current = fm.file(opts.data.target).phash; + break; + case 'put': + opts.data.cmd = 'edit'; + opts.data.current = fm.file(opts.data.target).phash; + break; + case 'archive': + case 'rm': + opts.data.current = fm.file(opts.data.targets[0]).phash; + break; + case 'extract': + case 'rename': + case 'resize': + opts.data.current = fm.file(opts.data.target).phash; + break; + case 'duplicate': + _opts = $.extend(true, {}, opts); + + $.each(opts.data.targets, function(i, hash) { + $.ajax(Object.assign(_opts, {data : {cmd : 'duplicate', target : hash, current : fm.file(hash).phash}})) + .fail(function(error) { + fm.error(fm.res('error', 'connect')); + }) + .done(function(data) { + data = self.normalize('duplicate', data); + if (data.error) { + fm.error(data.error); + } else if (data.added) { + fm.trigger('add', {added : data.added}); + } + }); + }); + return dfrd.resolve({}); + + case 'mkdir': + case 'mkfile': + opts.data.current = opts.data.target; + break; + case 'paste': + opts.data.current = opts.data.dst; + if (! opts.data.tree) { + $.each(opts.data.targets, function(i, h) { + if (fm.file(h) && fm.file(h).mime === 'directory') { + opts.data.tree = '1'; + return false; + } + }); + } + break; + + case 'size': + return dfrd.resolve({error : fm.res('error', 'cmdsupport')}); + case 'search': + return dfrd.resolve({error : fm.res('error', 'cmdsupport')}); + + case 'file': + opts.data.cmd = 'open'; + opts.data.current = fm.file(opts.data.target).phash; + break; + } + // cmd = opts.data.cmd + + xhr = $.ajax(opts) + .fail(function(error) { + dfrd.reject(error); + }) + .done(function(raw) { + data = self.normalize(cmd, raw); + dfrd.resolve(data); + }); + + return dfrd; + }; + + // fix old connectors errors messages as possible + // this.errors = { + // 'Unknown command' : 'Unknown command.', + // 'Invalid backend configuration' : 'Invalid backend configuration.', + // 'Access denied' : 'Access denied.', + // 'PHP JSON module not installed' : 'PHP JSON module not installed.', + // 'File not found' : 'File not found.', + // 'Invalid name' : 'Invalid file name.', + // 'File or folder with the same name already exists' : 'File named "$1" already exists in this location.', + // 'Not allowed file type' : 'Not allowed file type.', + // 'File exceeds the maximum allowed filesize' : 'File exceeds maximum allowed size.', + // 'Unable to copy into itself' : 'Unable to copy "$1" into itself.', + // 'Unable to create archive' : 'Unable to create archive.', + // 'Unable to extract files from archive' : 'Unable to extract files from "$1".' + // } + + this.normalize = function(cmd, data) { + var self = this, + fm = this.fm, + files = {}, + filter = function(file) { return file && file.hash && file.name && file.mime ? file : null; }, + getDirs = function(items) { + return $.grep(items, function(i) { + return i && i.mime && i.mime === 'directory'? true : false; + }); + }, + getTreeDiff = function(files) { + var dirs = getDirs(files); + treeDiff = fm.diff(dirs, null, ['date', 'ts']); + if (treeDiff.added.length) { + treeDiff.added = getDirs(treeDiff.added); + } + if (treeDiff.changed.length) { + treeDiff.changed = getDirs(treeDiff.changed); + } + if (treeDiff.removed.length) { + var removed = []; + $.each(treeDiff.removed, function(i, h) { + var item; + if ((item = fm.file(h)) && item.mime === 'directory') { + removed.push(h); + } + }); + treeDiff.removed = removed; + } + return treeDiff; + }, + phash, diff, isCwd, treeDiff; + + if ((cmd == 'tmb' || cmd == 'get')) { + return data; + } + + // if (data.error) { + // $.each(data.error, function(i, msg) { + // if (self.errors[msg]) { + // data.error[i] = self.errors[msg]; + // } + // }); + // } + + if (cmd == 'upload' && data.error && data.cwd) { + data.warning = Object.assign({}, data.error); + data.error = false; + } + + + if (data.error) { + return data; + } + + if (cmd == 'put') { + + phash = fm.file(data.target.hash).phash; + return {changed : [this.normalizeFile(data.target, phash)]}; + } + + phash = data.cwd.hash; + + isCwd = (phash == fm.cwd().hash); + + if (data.tree) { + $.each(this.normalizeTree(data.tree), function(i, file) { + files[file.hash] = file; + }); + } + + $.each(data.cdc||[], function(i, file) { + var hash = file.hash, + mcts; + + if (files[hash]) { + if (file.date) { + mcts = Date.parse(getDateString(file.date)); + if (mcts && !isNaN(mcts)) { + files[hash].ts = Math.floor(mcts / 1000); + } else { + files[hash].date = file.date || fm.formatDate(file); + } + } + files[hash].locked = file.hash == phash ? true : file.rm === void(0) ? false : !file.rm; + } else { + files[hash] = self.normalizeFile(file, phash, data.tmb); + } + }); + + if (!data.tree) { + $.each(fm.files(), function(hash, file) { + if (!files[hash] && file.phash != phash && file.mime == 'directory') { + files[hash] = file; + } + }); + } + + if (cmd == 'open') { + return { + cwd : files[phash] || this.normalizeFile(data.cwd), + files : $.map(files, function(f) { return f; }), + options : self.normalizeOptions(data), + init : !!data.params, + debug : data.debug + }; + } + + if (isCwd) { + diff = fm.diff($.map(files, filter)); + } else { + if (data.tree && cmd !== 'paste') { + diff = getTreeDiff(files); + } else { + diff = { + added : [], + removed : [], + changed : [] + }; + if (cmd === 'paste') { + diff.sync = true; + } + } + } + + return Object.assign({ + current : data.cwd.hash, + error : data.error, + warning : data.warning, + options : {tmb : !!data.tmb} + }, diff); + + }; + + /** + * Convert old api tree into plain array of dirs + * + * @param Object root dir + * @return Array + */ + this.normalizeTree = function(root) { + var self = this, + result = [], + traverse = function(dirs, phash) { + var i, dir; + + for (i = 0; i < dirs.length; i++) { + dir = dirs[i]; + result.push(self.normalizeFile(dir, phash)); + dir.dirs.length && traverse(dir.dirs, dir.hash); + } + }; + + traverse([root]); + + return result; + }; + + /** + * Convert file info from old api format into new one + * + * @param Object file + * @param String parent dir hash + * @return Object + */ + this.normalizeFile = function(file, phash, tmb) { + var mime = file.mime || 'directory', + size = mime == 'directory' && !file.linkTo ? 0 : file.size, + mcts = file.date? Date.parse(getDateString(file.date)) : void 0, + info = { + url : file.url, + hash : file.hash, + phash : phash, + name : file.name, + mime : mime, + ts : file.ts, + size : size, + read : file.read, + write : file.write, + locked : !phash ? true : file.rm === void(0) ? false : !file.rm + }; + + if (! info.ts) { + if (mcts && !isNaN(mcts)) { + info.ts = Math.floor(mcts / 1000); + } else { + info.date = file.date || this.fm.formatDate(file); + } + } + + if (file.mime == 'application/x-empty' || file.mime == 'inode/x-empty') { + info.mime = 'text/plain'; + } + + if (file.linkTo) { + info.alias = file.linkTo; + } + + if (file.linkTo) { + info.linkTo = file.linkTo; + } + + if (file.tmb) { + info.tmb = file.tmb; + } else if (info.mime.indexOf('image/') === 0 && tmb) { + info.tmb = 1; + + } + + if (file.dirs && file.dirs.length) { + info.dirs = true; + } + if (file.dim) { + info.dim = file.dim; + } + if (file.resize) { + info.resize = file.resize; + } + return info; + }; + + this.normalizeOptions = function(data) { + var opts = { + path : data.cwd.rel, + disabled : $.merge((data.disabled || []), [ 'search', 'netmount', 'zipdl' ]), + tmb : !!data.tmb, + copyOverwrite : true + }; + + if (data.params) { + opts.api = 1; + opts.url = data.params.url; + opts.archivers = { + create : data.params.archives || [], + extract : data.params.extract || [] + }; + } + + if (opts.path.indexOf('/') !== -1) { + opts.separator = '/'; + } else if (opts.path.indexOf('\\') !== -1) { + opts.separator = '\\'; + } + return opts; + }; +}; diff --git a/lib/redactor/elfinder/js/worker/calcfilehash.js b/lib/redactor/elfinder/js/worker/calcfilehash.js new file mode 100644 index 0000000..5b414c2 --- /dev/null +++ b/lib/redactor/elfinder/js/worker/calcfilehash.js @@ -0,0 +1,20 @@ +var type = self.data.type, + bin = self.data.bin, + hashOpts = self.data.hashOpts; + +self.res = {}; +if (type === 'md5') { + let sp = new self.SparkMD5.ArrayBuffer(); + sp.append(bin); + self.res.hash = sp.end(); +} else { + let sha = new jsSHA('SHA' + (type.length === 5? type : ('-' + type)).toUpperCase(), 'ARRAYBUFFER'), + opts = {}; + if (type === 'ke128') { + opts.shakeLen = hashOpts.shake128len; + } else if (type === 'ke256') { + opts.shakeLen = hashOpts.shake256len; + } + sha.update(bin); + self.res.hash = sha.getHash('HEX', opts); +} diff --git a/lib/redactor/elfinder/js/worker/quicklook.tiff.js b/lib/redactor/elfinder/js/worker/quicklook.tiff.js new file mode 100644 index 0000000..7a994b9 --- /dev/null +++ b/lib/redactor/elfinder/js/worker/quicklook.tiff.js @@ -0,0 +1,10 @@ +if (self.data.memory) { + Tiff.initialize({ TOTAL_MEMORY: self.data.memory }); +} + +var tiff = new Tiff({ buffer: self.data.data }); +self.res = { + image: tiff.readRGBAImage(), + width: tiff.width(), + height: tiff.height() +}; diff --git a/lib/redactor/elfinder/js/worker/quicklook.unzip.js b/lib/redactor/elfinder/js/worker/quicklook.unzip.js new file mode 100644 index 0000000..a1a7d1a --- /dev/null +++ b/lib/redactor/elfinder/js/worker/quicklook.unzip.js @@ -0,0 +1,65 @@ +var type = self.data.type, + bin = new Uint8Array(self.data.bin), + unzipFiles = function() { + /** @type {Array.} */ + var filenameList = []; + /** @type {number} */ + var i; + /** @type {number} */ + var il; + /** @type {Array.} */ + var fileHeaderList; + // need check this.Y when update cdns.zlibUnzip + this.Y(); + fileHeaderList = this.i; + for (i = 0, il = fileHeaderList.length; i < il; ++i) { + // need check fileHeaderList[i].J when update cdns.zlibUnzip + filenameList[i] = fileHeaderList[i].filename + (fileHeaderList[i].J? ' ({formatSize(' + fileHeaderList[i].J + ')})' : ''); + } + return filenameList; + }, + tarFiles = function(tar) { + var filenames = [], + tarlen = tar.length, + offset = 0, + toStr = function(arr) { + return String.fromCharCode.apply(null, arr).replace(/\0+$/, ''); + }, + h, name, prefix, size, dbs; + while (offset < tarlen && tar[offset] !== 0) { + h = tar.subarray(offset, offset + 512); + name = toStr(h.subarray(0, 100)); + if (prefix = toStr(h.subarray(345, 500))) { + name = prefix + name; + } + size = parseInt(toStr(h.subarray(124, 136)), 8); + dbs = Math.ceil(size / 512) * 512; + if (name === '././@LongLink') { + name = toStr(tar.subarray(offset + 512, offset + 512 + dbs)); + } + (name !== 'pax_global_header') && filenames.push(name + (size? ' ({formatSize(' + size + ')})': '')); + offset = offset + 512 + dbs; + } + return filenames; + }; + +self.res = {}; + +switch (type) { + case 'tar': + self.res.files = tarFiles(bin); + break; + case 'zip': + self.res.files = unzipFiles.call(new Zlib.Unzip(bin)); + break; + case 'gzip': + self.res.files = tarFiles(new Zlib.Gunzip(bin).decompress()); + break; + case 'bzip2': + self.res.files = tarFiles(self.bzip2.simple(self.bzip2.array(bin))); + break; + default: + + break; +} + diff --git a/lib/redactor/elfinder/php/.tmp/.htaccess b/lib/redactor/elfinder/php/.tmp/.htaccess new file mode 100644 index 0000000..ff2beb8 --- /dev/null +++ b/lib/redactor/elfinder/php/.tmp/.htaccess @@ -0,0 +1,2 @@ +order deny,allow +deny from all diff --git a/lib/redactor/elfinder/php/MySQLStorage.sql b/lib/redactor/elfinder/php/MySQLStorage.sql new file mode 100644 index 0000000..205e9c3 --- /dev/null +++ b/lib/redactor/elfinder/php/MySQLStorage.sql @@ -0,0 +1,47 @@ +DROP TABLE IF EXISTS `elfinder_file`; +CREATE TABLE IF NOT EXISTS `elfinder_file` ( + `id` int(7) unsigned NOT NULL auto_increment, + `parent_id` int(7) unsigned NOT NULL, + `name` varchar(255) NOT NULL, + `content` longblob NOT NULL, + `size` int(10) unsigned NOT NULL default '0', + `mtime` int(10) unsigned NOT NULL default '0', + `mime` varchar(256) NOT NULL default 'unknown', + `read` enum('1', '0') NOT NULL default '1', + `write` enum('1', '0') NOT NULL default '1', + `locked` enum('1', '0') NOT NULL default '0', + `hidden` enum('1', '0') NOT NULL default '0', + `width` int(5) NOT NULL default '0', + `height` int(5) NOT NULL default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `parent_name` (`parent_id`, `name`), + KEY `parent_id` (`parent_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + +INSERT INTO `elfinder_file` +(`id`, `parent_id`, `name`, `content`, `size`, `mtime`, `mime`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES +('1' , '0', 'DATABASE', '', '0', '0','directory', '1', '1', '0', '0', '0', '0'); + +DROP TABLE IF EXISTS `elfinder_trash`; +CREATE TABLE IF NOT EXISTS `elfinder_trash` ( + `id` int(7) unsigned NOT NULL auto_increment, + `parent_id` int(7) unsigned NOT NULL, + `name` varchar(255) NOT NULL, + `content` longblob NOT NULL, + `size` int(10) unsigned NOT NULL default '0', + `mtime` int(10) unsigned NOT NULL default '0', + `mime` varchar(256) NOT NULL default 'unknown', + `read` enum('1', '0') NOT NULL default '1', + `write` enum('1', '0') NOT NULL default '1', + `locked` enum('1', '0') NOT NULL default '0', + `hidden` enum('1', '0') NOT NULL default '0', + `width` int(5) NOT NULL default '0', + `height` int(5) NOT NULL default '0', + PRIMARY KEY (`id`), + UNIQUE KEY `parent_name` (`parent_id`, `name`), + KEY `parent_id` (`parent_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci; + +INSERT INTO `elfinder_trash` +(`id`, `parent_id`, `name`, `content`, `size`, `mtime`, `mime`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES +('1' , '0', 'DB Trash', '', '0', '0','directory', '1', '1', '0', '0', '0', '0'); diff --git a/lib/redactor/elfinder/php/autoload.php b/lib/redactor/elfinder/php/autoload.php new file mode 100644 index 0000000..a72fcd7 --- /dev/null +++ b/lib/redactor/elfinder/php/autoload.php @@ -0,0 +1,56 @@ + 'elFinder.class.php', + 'elFinderConnector' => 'elFinderConnector.class.php', + 'elFinderEditor' => 'editors/editor.php', + 'elFinderLibGdBmp' => 'libs/GdBmp.php', + 'elFinderPlugin' => 'elFinderPlugin.php', + 'elFinderPluginAutoResize' => 'plugins/AutoResize/plugin.php', + 'elFinderPluginAutoRotate' => 'plugins/AutoRotate/plugin.php', + 'elFinderPluginNormalizer' => 'plugins/Normalizer/plugin.php', + 'elFinderPluginSanitizer' => 'plugins/Sanitizer/plugin.php', + 'elFinderPluginWatermark' => 'plugins/Watermark/plugin.php', + 'elFinderSession' => 'elFinderSession.php', + 'elFinderSessionInterface' => 'elFinderSessionInterface.php', + 'elFinderVolumeDriver' => 'elFinderVolumeDriver.class.php', + 'elFinderVolumeDropbox2' => 'elFinderVolumeDropbox2.class.php', + 'elFinderVolumeFTP' => 'elFinderVolumeFTP.class.php', + 'elFinderVolumeFlysystemGoogleDriveCache' => 'elFinderFlysystemGoogleDriveNetmount.php', + 'elFinderVolumeFlysystemGoogleDriveNetmount' => 'elFinderFlysystemGoogleDriveNetmount.php', + 'elFinderVolumeGoogleDrive' => 'elFinderVolumeGoogleDrive.class.php', + 'elFinderVolumeGroup' => 'elFinderVolumeGroup.class.php', + 'elFinderVolumeLocalFileSystem' => 'elFinderVolumeLocalFileSystem.class.php', + 'elFinderVolumeMySQL' => 'elFinderVolumeMySQL.class.php', + 'elFinderVolumeSFTPphpseclib' => 'elFinderVolumeSFTPphpseclib.class.php', + 'elFinderVolumeTrash' => 'elFinderVolumeTrash.class.php', + ); + if (isset($map[$name])) { + return include_once(ELFINDER_PHP_ROOT_PATH . '/' . $map[$name]); + } + $prefix = substr($name, 0, 14); + if (substr($prefix, 0, 8) === 'elFinder') { + if ($prefix === 'elFinderVolume') { + $file = ELFINDER_PHP_ROOT_PATH . '/' . $name . '.class.php'; + return (is_file($file) && include_once($file)); + } else if ($prefix === 'elFinderPlugin') { + $file = ELFINDER_PHP_ROOT_PATH . '/plugins/' . substr($name, 14) . '/plugin.php'; + return (is_file($file) && include_once($file)); + } else if ($prefix === 'elFinderEditor') { + $file = ELFINDER_PHP_ROOT_PATH . '/editors/' . substr($name, 14) . '/editor.php'; + return (is_file($file) && include_once($file)); + } + } + return false; +} + +if (version_compare(PHP_VERSION, '5.3', '<')) { + spl_autoload_register('elFinderAutoloader'); +} else { + spl_autoload_register('elFinderAutoloader', true, true); +} + diff --git a/lib/redactor/elfinder/php/connector.maximal.php-dist b/lib/redactor/elfinder/php/connector.maximal.php-dist new file mode 100644 index 0000000..ca6693b --- /dev/null +++ b/lib/redactor/elfinder/php/connector.maximal.php-dist @@ -0,0 +1,449 @@ +file = $path; + $dir = dirname($path); + if (!is_dir($dir)) { + mkdir($dir); + } + } + + /** + * Create log record + * + * @param string $cmd command name + * @param array $result command result + * @param array $args command arguments from client + * @param elFinder $elfinder elFinder instance + * @param elFinderVolumeDriver $volume current volume driver instance + * @return void|true + * @author Dmitry (dio) Levashov + **/ + public function log($cmd, $result, $args, $elfinder, $volume) + { + $log = $cmd.' ['.date('d.m H:s')."]\n"; + + if (!empty($result['error'])) { + $log .= "\tERROR: ".implode(' ', $result['error'])."\n"; + } + + if (!empty($result['warning'])) { + $log .= "\tWARNING: ".implode(' ', $result['warning'])."\n"; + } + + if (!empty($result['removed'])) { + foreach ($result['removed'] as $file) { + // removed file contain additional field "realpath" + $log .= "\tREMOVED: ".$file['realpath']."\n"; + } + } + + if (!empty($result['added'])) { + foreach ($result['added'] as $file) { + $log .= "\tADDED: ".$elfinder->realpath($file['hash'])."\n"; + } + } + + if (!empty($result['changed'])) { + foreach ($result['changed'] as $file) { + $log .= "\tCHANGED: ".$elfinder->realpath($file['hash'])."\n"; + } + } + + $this->write($log); + } + + /** + * Write log into file + * + * @param string $log log record + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function write($log) + { + + if (($fp = @fopen($this->file, 'a'))) { + fwrite($fp, $log."\n"); + fclose($fp); + } + } + +} // END class +// Make logger instance +$logger = new elFinderSimpleLogger('.log.txt'); + +// Documentation for connector options: +// https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options +$opts = array( + 'debug' => true, // enable debug mode + 'roots' => array( + // Items volume + array( + 'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED) + 'path' => '../files/', // path to files (REQUIRED) + 'URL' => dirname($_SERVER['PHP_SELF']) . '/../files/', // URL to files (REQUIRED) + 'trashHash' => 't1_Lw', // elFinder's hash of trash folder + 'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too + 'uploadDeny' => array('all'), // All Mimetypes not allowed to upload + 'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Mimetype `image` and `text/plain` allowed to upload + 'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only + 'accessControl' => 'access', // disable and hide dot starting files (OPTIONAL) + 'attributes' => array( // additional thumbnail directories + 'pattern' => '~^/\.tmb(?:Cloud|Netmount)$~', + 'read' => false, + 'write' => false, + 'locked' => true, + 'hidden' => true ), + ), + // Trash volume + array( + 'id' => '1', + 'driver' => 'Trash', + 'path' => '../files/.trash/', + 'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.trash/.tmb/', + 'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too + 'uploadDeny' => array('all'), // Recomend the same settings as the original volume that uses the trash + 'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Same as above + 'uploadOrder' => array('deny', 'allow'), // Same as above + 'accessControl' => 'access', // Same as above + ), + ), + // some bind functions + 'bind' => array( + // enable logger + // '*' => array($logger, 'log'), + 'mkdir mkfile rename duplicate upload rm paste' => array($logger, 'log'), + // enable plugins + 'archive.pre ls.pre mkdir.pre mkfile.pre rename.pre upload.pre' => array( + 'Plugin.Normalizer.cmdPreprocess', + 'Plugin.Sanitizer.cmdPreprocess' + ), + 'upload.presave' => array( + 'Plugin.AutoRotate.onUpLoadPreSave', + 'Plugin.AutoResize.onUpLoadPreSave', + 'Plugin.Watermark.onUpLoadPreSave', + 'Plugin.Normalizer.onUpLoadPreSave', + 'Plugin.Sanitizer.onUpLoadPreSave', + ), + ), + // volume options of netmount volumes + 'optionsNetVolumes' => array( + '*' => array( // "*" is all of netmount volumes + 'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.tmbNetmount/', + 'tmbPath' => '../files/.tmbNetmount', + 'tmbGcMaxlifeHour' => 1, // 1 hour + 'tmbGcPercentage' => 10, // 10 execute / 100 tmb querys + 'plugin' => array( + 'AutoResize' => array( + 'enable' => false + ), + 'Watermark' => array( + 'enable' => false + ), + 'Normalizer' => array( + 'enable' => false + ), + 'Sanitizer' => array( + 'enable' => false + ) + ), + ) + ), +); + +// Extended other volume types +// To get an access token or refresh token, see the elFinder wiki. +// https://github.com/Studio-42/elFinder/wiki/How-to-get-OAuth-token + +// Thumbnail settings for cloud volumes +$tmbConfig = array( + 'tmbPath' => '../files/.tmbCloud', + 'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.tmbCloud/', + 'tmbGcMaxlifeHour' => 2160, // 90 days + 'tmbGcPercentage' => 5, // 5 execute / 100 tmb querys +); + +// MySQL config +$mySqlConfig = array( + 'path' => 1, + 'host' => '127.0.0.1', + 'user' => '', // @String DB user name + 'pass' => '', // @String DB user password + 'db' => '', // @String Database name + 'uploadMaxSize' => '10M', // It should be less than "max_allowed_packet" value of MySQL setting +); +// MySQL volume +$opts['roots'][] = array_merge($tmbConfig, $mySqlConfig, array( + 'driver' => 'MySQL', + 'trashHash' => 'tm1_MQ', // set trash to MySQL trash (tm1_) 1 (MQ) + 'files_table' => 'elfinder_file', +)); +// MySQL trash volume +$opts['roots'][] = array_merge($tmbConfig, $mySqlConfig, array( + 'id' => '1', // volume id became "tm1_" + 'alias' => 'DB Trash', + 'driver' => 'TrashMySQL', + 'files_table' => 'elfinder_trash', +)); + +// Volume group +$opts['roots'][] = array( + 'id' => '1', // volume id became "g1_" + 'alias' => 'CloudVolumes', + 'driver' => 'Group', + 'rootCssClass' => 'elfinder-navbar-root-network' // set volume icon +); + +// FTP volume +$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'FTP', + 'host' => 'ftp.jaist.ac.jp', + 'user' => 'anonymous', + 'path' => '/', + 'owner' => false, +)); + +// To enable the following cloud volumes, first complete the steps +// for enabling each network-mounted volume described earlier in this file. + +// Box volume +// Require constant "ELFINDER_BOX_CLIENTID" and "ELFINDER_BOX_CLIENTSECRET" +$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'Box', + 'path' => '/', // or folder id as root + 'accessToken' => '', // @JSON String access token including refresh token +)); + +// Dropbox volume +// Require constant "ELFINDER_DROPBOX_APPKEY" and "ELFINDER_DROPBOX_APPSECRET" +$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'Dropbox2', + 'path' => '/', // or folder path as root + 'access_token' => '', // @String your access token +)); + +// GoogleDrive volume with refresh token +// Require constant "ELFINDER_GOOGLEDRIVE_CLIENTID" and "ELFINDER_GOOGLEDRIVE_CLIENTSECRET" +$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'GoogleDrive', + 'path' => '/', // or folder id as root + 'refresh_token' => '', // @String your refresh token +)); + +// GoogleDrive volume with service account +// Require constant "ELFINDER_GOOGLEDRIVE_CLIENTID" and "ELFINDER_GOOGLEDRIVE_CLIENTSECRET" +$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'GoogleDrive', + 'path' => '/', // or folder id as root + 'serviceAccountConfigFile' => '', // @String path to config json file +)); + +// OneDrive volume +// Require constant "ELFINDER_ONEDRIVE_CLIENTID" and "ELFINDER_ONEDRIVE_CLIENTSECRET" +$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'OneDrive', + 'path' => '/', // or folder id as root + 'accessToken' => '', // @JSON String access token including refresh token +)); + +// SFTP volume +// Require phpseclib 1 installed (http://phpseclib.sourceforge.net) +// pear install example: +//sudo pear channel-discover phpseclib.sourceforge.net +//sudo pear remote-list -c phpseclib +//sudo pear install phpseclib/Net_SFTP +/*$opts['roots'][] = array_merge($tmbConfig, array( + 'phash' => 'g1_Lw', // set parent to Volume group (g1_) root "/" (Lw) + 'driver' => 'SFTPphpseclib', + 'host' => '127.0.0.1', + 'path' => '/tmp', // or folder id as root + 'user' => 'test', // @JSON String access token including refresh token + 'pass' => 'test', +));*/ + + +// run elFinder +$connector = new elFinderConnector(new elFinder($opts)); +$connector->run(); + diff --git a/lib/redactor/elfinder/php/connector.minimal.php-dist b/lib/redactor/elfinder/php/connector.minimal.php-dist new file mode 100644 index 0000000..114f892 --- /dev/null +++ b/lib/redactor/elfinder/php/connector.minimal.php-dist @@ -0,0 +1,180 @@ + true, + 'roots' => array( + // Items volume + array( + 'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED) + 'path' => '../files/', // path to files (REQUIRED) + 'URL' => dirname($_SERVER['PHP_SELF']) . '/../files/', // URL to files (REQUIRED) + 'trashHash' => 't1_Lw', // elFinder's hash of trash folder + 'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too + 'uploadDeny' => array('all'), // All Mimetypes not allowed to upload + 'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Mimetype `image` and `text/plain` allowed to upload + 'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only + 'accessControl' => 'access' // disable and hide dot starting files (OPTIONAL) + ), + // Trash volume + array( + 'id' => '1', + 'driver' => 'Trash', + 'path' => '../files/.trash/', + 'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.trash/.tmb/', + 'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too + 'uploadDeny' => array('all'), // Recomend the same settings as the original volume that uses the trash + 'uploadAllow' => array('image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon', 'text/plain'), // Same as above + 'uploadOrder' => array('deny', 'allow'), // Same as above + 'accessControl' => 'access', // Same as above + ), + ) +); + +// run elFinder +$connector = new elFinderConnector(new elFinder($opts)); +$connector->run(); + diff --git a/lib/redactor/elfinder/php/connector.php b/lib/redactor/elfinder/php/connector.php new file mode 100644 index 0000000..d76550a --- /dev/null +++ b/lib/redactor/elfinder/php/connector.php @@ -0,0 +1,166 @@ + true, + 'roots' => array( + array( + 'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED) + 'path' => '../../../../' . UPLOAD_DIR, // path to files (REQUIRED) + 'URL' => '/'.UPLOAD_DIR.'/', // URL to files (REQUIRED) + 'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only + 'acceptedName' => 'validName', + 'uploadAllow' => array('all'), + 'uploadDeny' => array('all'), + 'uploadOverwrite' => false, + 'uploadMaxSize' => '256m', + 'accessControl' => 'access', // disable and hide dot starting files (OPTIONAL) + 'attributes' => array( + array( + 'pattern' => '/^\/\./', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => true + ), + array( + 'pattern' => '/.tmb/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/\.php$/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/.quarantine/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/\.htaccess$/', + 'write' => false, + 'locked' => false, + 'hidden' => true + ) + + ) + ) + ) +); + +// run elFinder +$connector = new elFinderConnector(new elFinder($opts)); +$connector->run(); \ No newline at end of file diff --git a/lib/redactor/elfinder/php/connector.php-dist b/lib/redactor/elfinder/php/connector.php-dist new file mode 100644 index 0000000..c06b36f --- /dev/null +++ b/lib/redactor/elfinder/php/connector.php-dist @@ -0,0 +1,128 @@ + true, + 'roots' => array( + // Items volume + array( + 'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED) + 'path' => '../files/', // path to files (REQUIRED) + 'URL' => dirname($_SERVER['PHP_SELF']) . '/../files/', // URL to files (REQUIRED) + 'trashHash' => 't1_Lw', // elFinder's hash of trash folder + 'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too + 'uploadDeny' => array('all'), // All Mimetypes not allowed to upload + 'uploadAllow' => array('image', 'text/plain'),// Mimetype `image` and `text/plain` allowed to upload + 'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only + 'accessControl' => 'access' // disable and hide dot starting files (OPTIONAL) + ), + // Trash volume + array( + 'id' => '1', + 'driver' => 'Trash', + 'path' => '../files/.trash/', + 'tmbURL' => dirname($_SERVER['PHP_SELF']) . '/../files/.trash/.tmb/', + 'winHashFix' => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too + 'uploadDeny' => array('all'), // Recomend the same settings as the original volume that uses the trash + 'uploadAllow' => array('image', 'text/plain'),// Same as above + 'uploadOrder' => array('deny', 'allow'), // Same as above + 'accessControl' => 'access', // Same as above + ) + ) +); + +// run elFinder +$connector = new elFinderConnector(new elFinder($opts)); +$connector->run(); + diff --git a/lib/redactor/elfinder/php/connector_template.php b/lib/redactor/elfinder/php/connector_template.php new file mode 100644 index 0000000..9fb16e6 --- /dev/null +++ b/lib/redactor/elfinder/php/connector_template.php @@ -0,0 +1,183 @@ + true, + 'roots' => array( + array( + 'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED) + 'path' => '../../../../templates/' . DEFAULT_THEME_FOLDER, // path to files (REQUIRED) + 'URL' => '/templates/' . DEFAULT_THEME_FOLDER . '/', // URL to files (REQUIRED) + 'accessControl' => 'access', // disable and hide dot starting files (OPTIONAL) + 'disabled' => array(), + 'acceptedName' => 'validName', + 'uploadAllow' => array('all'), + 'uploadDeny' => array('all'), + 'uploadOrder' => 'deny,allow', + 'uploadOverwrite' => false, + 'uploadMaxSize' => '256m', + 'copyOverwrite' => false, + 'copyJoin' => true, + 'mimeDetect' => 'internal', + 'tmbCrop' => false, + 'imgLib' => 'gd', + 'utf8fix' => true, + 'attributes' => array( + array( + 'pattern' => '/^\/\./', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => true + ), + array( + 'pattern' => '/.tmb/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/\.php$/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/.quarantine/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/\.htaccess$/', + 'write' => false, + 'locked' => false, + 'hidden' => true + ), + array( + 'pattern' => '/.uploader/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ), + array( + 'pattern' => '/.temp/', + 'read' => false, + 'write' => false, + 'hidden' => true, + 'locked' => false + ) + ) + ) + ) +); + +// run elFinder +$connector = new elFinderConnector(new elFinder($opts)); +$connector->run(); \ No newline at end of file diff --git a/lib/redactor/elfinder/php/editors/OnlineConvert/editor.php b/lib/redactor/elfinder/php/editors/OnlineConvert/editor.php new file mode 100644 index 0000000..62213e9 --- /dev/null +++ b/lib/redactor/elfinder/php/editors/OnlineConvert/editor.php @@ -0,0 +1,113 @@ + defined('ELFINDER_ONLINE_CONVERT_APIKEY') && ELFINDER_ONLINE_CONVERT_APIKEY && function_exists('curl_init')); + } + + public function api() + { + // return array('apires' => array('message' => 'Currently disabled for developping...')); + $endpoint = 'https://api2.online-convert.com/jobs'; + $category = $this->argValue('category'); + $convert = $this->argValue('convert'); + $options = $this->argValue('options'); + $source = $this->argValue('source'); + $filename = $this->argValue('filename'); + $mime = $this->argValue('mime'); + $jobid = $this->argValue('jobid'); + $string_method = ''; + $options = array(); + // Currently these converts are make error with API call. I don't know why. + $nonApi = array('android', 'blackberry', 'dpg', 'ipad', 'iphone', 'ipod', 'nintendo-3ds', 'nintendo-ds', 'ps3', 'psp', 'wii', 'xbox'); + if (in_array($convert, $nonApi)) { + return array('apires' => array()); + } + $ch = null; + if ($convert && $source) { + $request = array( + 'input' => array(array( + 'type' => 'remote', + 'source' => $source + )), + 'conversion' => array(array( + 'target' => $convert + )) + ); + + if ($filename !== '') { + $request['input'][0]['filename'] = $filename; + } + + if ($mime !== '') { + $request['input'][0]['content_type'] = $mime; + } + + if ($category) { + $request['conversion'][0]['category'] = $category; + } + + if ($options && $options !== 'null') { + $options = json_decode($options, true); + } + if (!is_array($options)) { + $options = array(); + } + if ($options) { + $request['conversion'][0]['options'] = $options; + } + + $ch = curl_init($endpoint); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($request)); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'X-Oc-Api-Key: ' . ELFINDER_ONLINE_CONVERT_APIKEY, + 'Content-Type: application/json', + 'cache-control: no-cache' + )); + } else if ($jobid) { + $ch = curl_init($endpoint . '/' . $jobid); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'X-Oc-Api-Key: ' . ELFINDER_ONLINE_CONVERT_APIKEY, + 'cache-control: no-cache' + )); + } + + if ($ch) { + $response = curl_exec($ch); + $info = curl_getinfo($ch); + $error = curl_error($ch); + curl_close($ch); + + if (!empty($error)) { + $res = array('error' => $error); + } else { + $data = json_decode($response, true); + if (isset($data['status']) && isset($data['status']['code']) && $data['status']['code'] === 'completed') { + /** @var elFinderSession $session */ + $session = $this->elfinder->getSession(); + $urlContentSaveIds = $session->get('urlContentSaveIds', array()); + $urlContentSaveIds['OnlineConvert-' . $data['id']] = true; + $session->set('urlContentSaveIds', $urlContentSaveIds); + } + $res = array('apires' => $data); + } + + return $res; + } else { + return array('error' => array('errCmdParams', 'editor.OnlineConvert.api')); + } + } +} diff --git a/lib/redactor/elfinder/php/editors/ZipArchive/editor.php b/lib/redactor/elfinder/php/editors/ZipArchive/editor.php new file mode 100644 index 0000000..bdaa4b7 --- /dev/null +++ b/lib/redactor/elfinder/php/editors/ZipArchive/editor.php @@ -0,0 +1,12 @@ + array( + 'unit' => 'mm', + 'view' => 'pageview' + ), + 'sheet' => array( + 'country' => 'US' + ), + 'show' => array() + ); + + private $urls = array( + 'writer' => 'https://api.office-integrator.com/writer/officeapi/v1/document', + 'sheet' => 'https://api.office-integrator.com/sheet/officeapi/v1/spreadsheet', + 'show' => 'https://api.office-integrator.com/show/officeapi/v1/presentation', + ); + + private $srvs = array( + 'application/msword' => 'writer', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'writer', + 'application/pdf' => 'writer', + 'application/vnd.oasis.opendocument.text' => 'writer', + 'application/rtf' => 'writer', + 'text/html' => 'writer', + 'application/vnd.ms-excel' => 'sheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'sheet', + 'application/vnd.oasis.opendocument.spreadsheet' => 'sheet', + 'application/vnd.sun.xml.calc' => 'sheet', + 'text/csv' => 'sheet', + 'text/tab-separated-values' => 'sheet', + 'application/vnd.ms-powerpoint' => 'show', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'show', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'show', + 'application/vnd.oasis.opendocument.presentation' => 'show', + 'application/vnd.sun.xml.impress' => 'show', + ); + + private $myName = ''; + + protected function extentionNormrize($extention, $srvsName) { + switch($srvsName) { + case 'writer': + if (!in_array($extention, array('zdoc', 'docx', 'rtf', 'odt', 'html', 'txt'))) { + $extention = 'docx'; + } + break; + case 'sheet': + if (!in_array($extention, array('zsheet', 'xls', 'xlsx', 'ods', 'csv', 'tsv'))) { + $extention = 'xlsx'; + } + break; + case 'show': + if (!in_array($extention, array('zslides', 'pptx', 'pps', 'ppsx', 'odp', 'sxi'))) { + $extention = 'pptx'; + } + break; + + } + return $extention; + } + + public function __construct($elfinder, $args) + { + parent::__construct($elfinder, $args); + $this->myName = preg_replace('/^elFinderEditor/i', '', get_class($this)); + } + + public function enabled() + { + return defined('ELFINDER_ZOHO_OFFICE_APIKEY') && ELFINDER_ZOHO_OFFICE_APIKEY && function_exists('curl_init'); + } + + public function init() + { + if (!defined('ELFINDER_ZOHO_OFFICE_APIKEY') || !function_exists('curl_init')) { + return array('error', array(elFinder::ERROR_CONF, '`ELFINDER_ZOHO_OFFICE_APIKEY` or curl extension')); + } + if (!empty($this->args['target'])) { + $fp = $cfile = null; + $hash = $this->args['target']; + /** @var elFinderVolumeDriver $srcVol */ + if (($srcVol = $this->elfinder->getVolume($hash)) && ($file = $srcVol->file($hash))) { + $cdata = empty($this->args['cdata']) ? '' : $this->args['cdata']; + $cookie = $this->elfinder->getFetchCookieFile(); + $save = false; + $ch = curl_init(); + $conUrl = elFinder::getConnectorUrl(); + curl_setopt($ch, CURLOPT_URL, $conUrl . (strpos($conUrl, '?') !== false? '&' : '?') . 'cmd=editor&name=' . $this->myName . '&method=chk&args[target]=' . rawurlencode($hash) . $cdata); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + if ($cookie) { + curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie); + curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); + } + $res = curl_exec($ch); + curl_close($ch); + if ($res) { + if ($data = json_decode($res, true)) { + $save = !empty($data['cansave']); + } + } + + if ($size = $file['size']) { + $src = $srcVol->open($hash); + $fp = tmpfile(); + stream_copy_to_stream($src, $fp); + $srcVol->close($src, $hash); + $info = stream_get_meta_data($fp); + if ($info && !empty($info['uri'])) { + $srcFile = $info['uri']; + if (class_exists('CURLFile')) { + $cfile = new CURLFile($srcFile); + $cfile->setPostFilename($file['name']); + $cfile->setMimeType($file['mime']); + } else { + $cfile = '@' . $srcFile; + } + } + } + //$srv = $this->args['service']; + $srvsName = $this->srvs[$file['mime']]; + $format = $this->extentionNormrize($srcVol->getExtentionByMime($file['mime']), $srvsName); + if (!$format) { + $format = substr($file['name'], strrpos($file['name'], '.') * -1); + } + $lang = $this->args['lang']; + if ($lang === 'jp') { + $lang = 'ja'; + } + $data = array( + 'apikey' => ELFINDER_ZOHO_OFFICE_APIKEY, + 'callback_settings' => array( + 'save_format' => $format, + 'save_url_params' => array( + 'hash' => $hash + ) + ), + 'editor_settings' => $this->editor_settings[$srvsName], + 'document_info' => array( + 'document_name' => substr($file['name'], 0, strlen($file['name']) - strlen($format)- 1) + ) + ); + $data['editor_settings']['language'] = $lang; + if ($save) { + $conUrl = elFinder::getConnectorUrl(); + $data['callback_settings']['save_url'] = $conUrl . (strpos($conUrl, '?') !== false? '&' : '?') . 'cmd=editor&name=' . $this->myName . '&method=save' . $cdata; + } + foreach($data as $_k => $_v) { + if (is_array($_v)){ + $data[$_k] = json_encode($_v); + } + } + if ($cfile) { + $data['document'] = $cfile; + } + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $this->urls[$srvsName]); + curl_setopt($ch, CURLOPT_TIMEOUT, self::$curlTimeout); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + $res = curl_exec($ch); + $error = curl_error($ch); + curl_close($ch); + + $fp && fclose($fp); + + if ($res && $res = @json_decode($res, true)) { + if (!empty($res['document_url'])) { + $ret = array('zohourl' => $res['document_url']); + if (!$save) { + $ret['warning'] = 'exportToSave'; + } + return $ret; + } else { + $error = $res; + } + } + + if ($error) { + return array('error' => is_string($error)? preg_split('/[\r\n]+/', $error) : 'Error code: ' . $error); + } + } + } + + return array('error' => array('errCmdParams', 'editor.' . $this->myName . '.init')); + } + + public function save() + { + if (!empty($_POST) && !empty($_POST['hash']) && !empty($_FILES) && !empty($_FILES['content'])) { + $hash = $_POST['hash']; + /** @var elFinderVolumeDriver $volume */ + if ($volume = $this->elfinder->getVolume($hash)) { + if ($content = file_get_contents($_FILES['content']['tmp_name'])) { + if ($volume->putContents($hash, $content)) { + return array('raw' => true, 'error' => '', 'header' => 'HTTP/1.1 200 OK'); + } + } + } + } + return array('raw' => true, 'error' => '', 'header' => 'HTTP/1.1 500 Internal Server Error'); + } + + public function chk() + { + $hash = $this->args['target']; + $res = false; + /** @var elFinderVolumeDriver $volume */ + if ($volume = $this->elfinder->getVolume($hash)) { + if ($file = $volume->file($hash)) { + $res = (bool)$file['write']; + } + } + return array('cansave' => $res); + } +} diff --git a/lib/redactor/elfinder/php/editors/editor.php b/lib/redactor/elfinder/php/editors/editor.php new file mode 100644 index 0000000..f2d41c2 --- /dev/null +++ b/lib/redactor/elfinder/php/editors/editor.php @@ -0,0 +1,79 @@ +elfinder = $elfinder; + $this->args = $args; + } + + /** + * Return boolean that this plugin is enabled. + * + * @return bool + */ + public function enabled() + { + return true; + } + + /** + * Return boolean that $name method is allowed. + * + * @param string $name + * + * @return bool + */ + public function isAllowedMethod($name) + { + $checker = array_flip($this->allowed); + + return isset($checker[$name]); + } + + /** + * Return $this->args value of the key + * + * @param string $key target key + * @param string $empty empty value + * + * @return mixed + */ + public function argValue($key, $empty = '') + { + return isset($this->args[$key]) ? $this->args[$key] : $empty; + } +} diff --git a/lib/redactor/elfinder/php/elFinder.class.php b/lib/redactor/elfinder/php/elFinder.class.php new file mode 100644 index 0000000..763b9a9 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinder.class.php @@ -0,0 +1,5428 @@ + array('id' => true), + 'archive' => array('targets' => true, 'type' => true, 'mimes' => false, 'name' => false), + 'callback' => array('node' => true, 'json' => false, 'bind' => false, 'done' => false), + 'chmod' => array('targets' => true, 'mode' => true), + 'dim' => array('target' => true, 'substitute' => false), + 'duplicate' => array('targets' => true, 'suffix' => false), + 'editor' => array('name' => true, 'method' => true, 'args' => false), + 'extract' => array('target' => true, 'mimes' => false, 'makedir' => false), + 'file' => array('target' => true, 'download' => false, 'cpath' => false, 'onetime' => false), + 'get' => array('target' => true, 'conv' => false), + 'info' => array('targets' => true, 'compare' => false), + 'ls' => array('target' => true, 'mimes' => false, 'intersect' => false), + 'mkdir' => array('target' => true, 'name' => false, 'dirs' => false), + 'mkfile' => array('target' => true, 'name' => true, 'mimes' => false), + 'netmount' => array('protocol' => true, 'host' => true, 'path' => false, 'port' => false, 'user' => false, 'pass' => false, 'alias' => false, 'options' => false), + 'open' => array('target' => false, 'tree' => false, 'init' => false, 'mimes' => false, 'compare' => false), + 'parents' => array('target' => true, 'until' => false), + 'paste' => array('dst' => true, 'targets' => true, 'cut' => false, 'mimes' => false, 'renames' => false, 'hashes' => false, 'suffix' => false), + 'put' => array('target' => true, 'content' => '', 'mimes' => false, 'encoding' => false), + 'rename' => array('target' => true, 'name' => true, 'mimes' => false, 'targets' => false, 'q' => false), + 'resize' => array('target' => true, 'width' => false, 'height' => false, 'mode' => false, 'x' => false, 'y' => false, 'degree' => false, 'quality' => false, 'bg' => false), + 'rm' => array('targets' => true), + 'search' => array('q' => true, 'mimes' => false, 'target' => false, 'type' => false), + 'size' => array('targets' => true), + 'subdirs' => array('targets' => true), + 'tmb' => array('targets' => true), + 'tree' => array('target' => true), + 'upload' => array('target' => true, 'FILES' => true, 'mimes' => false, 'html' => false, 'upload' => false, 'name' => false, 'upload_path' => false, 'chunk' => false, 'cid' => false, 'node' => false, 'renames' => false, 'hashes' => false, 'suffix' => false, 'mtime' => false, 'overwrite' => false, 'contentSaveId' => false), + 'url' => array('target' => true, 'options' => false), + 'zipdl' => array('targets' => true, 'download' => false) + ); + + /** + * Plugins instance + * + * @var array + **/ + protected $plugins = array(); + + /** + * Commands listeners + * + * @var array + **/ + protected $listeners = array(); + + /** + * script work time for debug + * + * @var string + **/ + protected $time = 0; + /** + * Is elFinder init correctly? + * + * @var bool + **/ + protected $loaded = false; + /** + * Send debug to client? + * + * @var string + **/ + protected $debug = false; + + /** + * Call `session_write_close()` before exec command? + * + * @var bool + */ + protected $sessionCloseEarlier = true; + + /** + * SESSION use commands @see __construct() + * + * @var array + */ + protected $sessionUseCmds = array(); + + /** + * session expires timeout + * + * @var int + **/ + protected $timeout = 0; + + /** + * Temp dir path for Upload + * + * @var string + */ + protected $uploadTempPath = ''; + + /** + * Max allowed archive files size (0 - no limit) + * + * @var integer + */ + protected $maxArcFilesSize = 0; + + /** + * undocumented class variable + * + * @var string + **/ + protected $uploadDebug = ''; + + /** + * Max allowed numbar of targets (0 - no limit) + * + * @var integer + */ + public $maxTargets = 1000; + + /** + * Errors from PHP + * + * @var array + **/ + public static $phpErrors = array(); + + /** + * Errors from not mounted volumes + * + * @var array + **/ + public $mountErrors = array(); + + + /** + * Archivers cache + * + * @var array + */ + public static $archivers = array(); + + /** + * URL for callback output window for CORS + * redirect to this URL when callback output + * + * @var string URL + */ + protected $callbackWindowURL = ''; + + /** + * hash of items to unlock on command completion + * + * @var array hashes + */ + protected $autoUnlocks = array(); + + /** + * Item locking expiration (seconds) + * Default: 3600 secs + * + * @var integer + */ + protected $itemLockExpire = 3600; + + /** + * Additional request querys + * + * @var array|null + */ + protected $customData = null; + + /** + * Ids to remove of session var "urlContentSaveIds" for contents uploading by URL + * + * @var array + */ + protected $removeContentSaveIds = array(); + + /** + * LAN class allowed when uploading via URL + * + * Array keys are 'local', 'private_a', 'private_b', 'private_c' and 'link' + * + * local: 127.0.0.0/8 + * private_a: 10.0.0.0/8 + * private_b: 172.16.0.0/12 + * private_c: 192.168.0.0/16 + * link: 169.254.0.0/16 + * + * @var array + */ + protected $uploadAllowedLanIpClasses = array(); + + /** + * Flag of throw Error on exec() + * + * @var boolean + */ + protected $throwErrorOnExec = false; + + /** + * Default params of toastParams + * + * @var array + */ + protected $toastParamsDefault = array( + 'mode' => 'warning', + 'prefix' => '' + ); + + /** + * Toast params of runtime notification + * + * @var array + */ + private $toastParams = array(); + + /** + * Toast messages of runtime notification + * + * @var array + */ + private $toastMessages = array(); + + /** + * Optional UTF-8 encoder + * + * @var callable || null + */ + private $utf8Encoder = null; + + /** + * Seekable URL file pointer ids - for getStreamByUrl() + * + * @var array + */ + private static $seekableUrlFps = array(); + + // Errors messages + const ERROR_ACCESS_DENIED = 'errAccess'; + const ERROR_ARC_MAXSIZE = 'errArcMaxSize'; + const ERROR_ARC_SYMLINKS = 'errArcSymlinks'; + const ERROR_ARCHIVE = 'errArchive'; + const ERROR_ARCHIVE_EXEC = 'errArchiveExec'; + const ERROR_ARCHIVE_TYPE = 'errArcType'; + const ERROR_CONF = 'errConf'; + const ERROR_CONF_NO_JSON = 'errJSON'; + const ERROR_CONF_NO_VOL = 'errNoVolumes'; + const ERROR_CONV_UTF8 = 'errConvUTF8'; + const ERROR_COPY = 'errCopy'; + const ERROR_COPY_FROM = 'errCopyFrom'; + const ERROR_COPY_ITSELF = 'errCopyInItself'; + const ERROR_COPY_TO = 'errCopyTo'; + const ERROR_CREATING_TEMP_DIR = 'errCreatingTempDir'; + const ERROR_DIR_NOT_FOUND = 'errFolderNotFound'; + const ERROR_EXISTS = 'errExists'; // 'File named "$1" already exists.' + const ERROR_EXTRACT = 'errExtract'; + const ERROR_EXTRACT_EXEC = 'errExtractExec'; + const ERROR_FILE_NOT_FOUND = 'errFileNotFound'; // 'File not found.' + const ERROR_FTP_DOWNLOAD_FILE = 'errFtpDownloadFile'; + const ERROR_FTP_MKDIR = 'errFtpMkdir'; + const ERROR_FTP_UPLOAD_FILE = 'errFtpUploadFile'; + const ERROR_INV_PARAMS = 'errCmdParams'; + const ERROR_INVALID_DIRNAME = 'errInvDirname'; // 'Invalid folder name.' + const ERROR_INVALID_NAME = 'errInvName'; // 'Invalid file name.' + const ERROR_LOCKED = 'errLocked'; // '"$1" is locked and can not be renamed, moved or removed.' + const ERROR_MAX_TARGTES = 'errMaxTargets'; // 'Max number of selectable items is $1.' + const ERROR_MKDIR = 'errMkdir'; + const ERROR_MKFILE = 'errMkfile'; + const ERROR_MKOUTLINK = 'errMkOutLink'; // 'Unable to create a link to outside the volume root.' + const ERROR_MOVE = 'errMove'; + const ERROR_NETMOUNT = 'errNetMount'; + const ERROR_NETMOUNT_FAILED = 'errNetMountFailed'; + const ERROR_NETMOUNT_NO_DRIVER = 'errNetMountNoDriver'; + const ERROR_NETUNMOUNT = 'errNetUnMount'; + const ERROR_NOT_ARCHIVE = 'errNoArchive'; + const ERROR_NOT_DIR = 'errNotFolder'; + const ERROR_NOT_FILE = 'errNotFile'; + const ERROR_NOT_REPLACE = 'errNotReplace'; // Object "$1" already exists at this location and can not be replaced with object of another type. + const ERROR_NOT_UTF8_CONTENT = 'errNotUTF8Content'; + const ERROR_OPEN = 'errOpen'; + const ERROR_PERM_DENIED = 'errPerm'; + const ERROR_REAUTH_REQUIRE = 'errReauthRequire'; // 'Re-authorization is required.' + const ERROR_RENAME = 'errRename'; + const ERROR_REPLACE = 'errReplace'; // 'Unable to replace "$1".' + const ERROR_RESIZE = 'errResize'; + const ERROR_RESIZESIZE = 'errResizeSize'; + const ERROR_RM = 'errRm'; // 'Unable to remove "$1".' + const ERROR_RM_SRC = 'errRmSrc'; // 'Unable remove source file(s)' + const ERROR_SAVE = 'errSave'; + const ERROR_SEARCH_TIMEOUT = 'errSearchTimeout'; // 'Timed out while searching "$1". Search result is partial.' + const ERROR_SESSION_EXPIRES = 'errSessionExpires'; + const ERROR_TRGDIR_NOT_FOUND = 'errTrgFolderNotFound'; // 'Target folder "$1" not found.' + const ERROR_UNKNOWN = 'errUnknown'; + const ERROR_UNKNOWN_CMD = 'errUnknownCmd'; + const ERROR_UNSUPPORT_TYPE = 'errUsupportType'; + const ERROR_UPLOAD = 'errUpload'; // 'Upload error.' + const ERROR_UPLOAD_FILE = 'errUploadFile'; // 'Unable to upload "$1".' + const ERROR_UPLOAD_FILE_MIME = 'errUploadMime'; // 'File type not allowed.' + const ERROR_UPLOAD_FILE_SIZE = 'errUploadFileSize'; // 'File exceeds maximum allowed size.' + const ERROR_UPLOAD_NO_FILES = 'errUploadNoFiles'; // 'No files found for upload.' + const ERROR_UPLOAD_TEMP = 'errUploadTemp'; // 'Unable to make temporary file for upload.' + const ERROR_UPLOAD_TOTAL_SIZE = 'errUploadTotalSize'; // 'Data exceeds the maximum allowed size.' + const ERROR_UPLOAD_TRANSFER = 'errUploadTransfer'; // '"$1" transfer error.' + const ERROR_MAX_MKDIRS = 'errMaxMkdirs'; // 'You can create up to $1 folders at one time.' + + /** + * Constructor + * + * @param array elFinder and roots configurations + * + * @author Dmitry (dio) Levashov + */ + public function __construct($opts) + { + // set default_charset + if (version_compare(PHP_VERSION, '5.6', '>=')) { + if (($_val = ini_get('iconv.internal_encoding')) && strtoupper($_val) !== 'UTF-8') { + ini_set('iconv.internal_encoding', ''); + } + if (($_val = ini_get('mbstring.internal_encoding')) && strtoupper($_val) !== 'UTF-8') { + ini_set('mbstring.internal_encoding', ''); + } + if (($_val = ini_get('internal_encoding')) && strtoupper($_val) !== 'UTF-8') { + ini_set('internal_encoding', ''); + } + } else { + if (function_exists('iconv_set_encoding') && strtoupper(iconv_get_encoding('internal_encoding')) !== 'UTF-8') { + iconv_set_encoding('internal_encoding', 'UTF-8'); + } + if (function_exists('mb_internal_encoding') && strtoupper(mb_internal_encoding()) !== 'UTF-8') { + mb_internal_encoding('UTF-8'); + } + } + ini_set('default_charset', 'UTF-8'); + + // define accept constant of server commands path + !defined('ELFINDER_TAR_PATH') && define('ELFINDER_TAR_PATH', 'tar'); + !defined('ELFINDER_GZIP_PATH') && define('ELFINDER_GZIP_PATH', 'gzip'); + !defined('ELFINDER_BZIP2_PATH') && define('ELFINDER_BZIP2_PATH', 'bzip2'); + !defined('ELFINDER_XZ_PATH') && define('ELFINDER_XZ_PATH', 'xz'); + !defined('ELFINDER_ZIP_PATH') && define('ELFINDER_ZIP_PATH', 'zip'); + !defined('ELFINDER_UNZIP_PATH') && define('ELFINDER_UNZIP_PATH', 'unzip'); + !defined('ELFINDER_RAR_PATH') && define('ELFINDER_RAR_PATH', 'rar'); + // Create archive in RAR4 format even when using RAR5 library (true or false) + !defined('ELFINDER_RAR_MA4') && define('ELFINDER_RAR_MA4', false); + !defined('ELFINDER_UNRAR_PATH') && define('ELFINDER_UNRAR_PATH', 'unrar'); + !defined('ELFINDER_7Z_PATH') && define('ELFINDER_7Z_PATH', (substr(PHP_OS, 0, 3) === 'WIN') ? '7z' : '7za'); + !defined('ELFINDER_CONVERT_PATH') && define('ELFINDER_CONVERT_PATH', 'convert'); + !defined('ELFINDER_IDENTIFY_PATH') && define('ELFINDER_IDENTIFY_PATH', 'identify'); + !defined('ELFINDER_EXIFTRAN_PATH') && define('ELFINDER_EXIFTRAN_PATH', 'exiftran'); + !defined('ELFINDER_JPEGTRAN_PATH') && define('ELFINDER_JPEGTRAN_PATH', 'jpegtran'); + !defined('ELFINDER_FFMPEG_PATH') && define('ELFINDER_FFMPEG_PATH', 'ffmpeg'); + + !defined('ELFINDER_DISABLE_ZIPEDITOR') && define('ELFINDER_DISABLE_ZIPEDITOR', false); + + // enable(true)/disable(false) handling postscript on ImageMagick + // Should be `false` as long as there is a Ghostscript vulnerability + // see https://artifex.com/news/ghostscript-security-resolved/ + !defined('ELFINDER_IMAGEMAGICK_PS') && define('ELFINDER_IMAGEMAGICK_PS', false); + + // for backward compat + $this->version = (string)self::$ApiVersion; + + // set error handler of WARNING, NOTICE + $errLevel = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR; + if (defined('E_DEPRECATED')) { + $errLevel |= E_DEPRECATED | E_USER_DEPRECATED; + } + // E_STRICT is deprecated; see https://wiki.php.net/rfc/deprecations_php_8_4#remove_e_strict_error_level_and_deprecate_e_strict_constant + if (defined('E_STRICT')) { + $errLevel |= @E_STRICT; + } + set_error_handler('elFinder::phpErrorHandler', $errLevel); + + // Associative array of file pointers to close at the end of script: ['temp file pointer' => true] + $GLOBALS['elFinderTempFps'] = array(); + // Associative array of files to delete at the end of script: ['temp file path' => true] + $GLOBALS['elFinderTempFiles'] = array(); + // Associative array of abort files to delete at the end of script: ['temp file path' => true] + $GLOBALS['elFinderAbortFiles'] = array(); + // regist Shutdown function + register_shutdown_function(array('elFinder', 'onShutdown')); + + // convert PATH_INFO to GET query + if (!empty($_SERVER['PATH_INFO'])) { + $_ps = explode('/', trim($_SERVER['PATH_INFO'], '/')); + if (!isset($_GET['cmd'])) { + $_cmd = $_ps[0]; + if (isset($this->commands[$_cmd])) { + $_GET['cmd'] = $_cmd; + $_i = 1; + foreach (array_keys($this->commands[$_cmd]) as $_k) { + if (isset($_ps[$_i])) { + if (!isset($_GET[$_k])) { + $_GET[$_k] = $_ps[$_i++]; + } + } else { + break; + } + } + } + } + } + + // set elFinder instance + elFinder::$instance = $this; + + // setup debug mode + $this->debug = (isset($opts['debug']) && $opts['debug'] ? true : false); + if ($this->debug) { + error_reporting(defined('ELFINDER_DEBUG_ERRORLEVEL') ? ELFINDER_DEBUG_ERRORLEVEL : -1); + ini_set('display_errors', '1'); + // clear output buffer and stop output filters + while (ob_get_level() && ob_end_clean()) { + } + } + + if (!interface_exists('elFinderSessionInterface')) { + include_once dirname(__FILE__) . '/elFinderSessionInterface.php'; + } + + // session handler + if (!empty($opts['session']) && $opts['session'] instanceof elFinderSessionInterface) { + $this->session = $opts['session']; + } else { + $sessionOpts = array( + 'base64encode' => !empty($opts['base64encodeSessionData']), + 'keys' => array( + 'default' => !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches', + 'netvolume' => !empty($opts['netVolumesSessionKey']) ? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes' + ) + ); + if (!class_exists('elFinderSession')) { + include_once dirname(__FILE__) . '/elFinderSession.php'; + } + $this->session = new elFinderSession($sessionOpts); + } + // try session start | restart + $this->session->start(); + + // 'netmount' added to handle requests synchronously on unmount + $sessionUseCmds = array('netmount'); + if (isset($opts['sessionUseCmds']) && is_array($opts['sessionUseCmds'])) { + $sessionUseCmds = array_merge($sessionUseCmds, $opts['sessionUseCmds']); + } + + // set self::$volumesCnt by HTTP header "X-elFinder-VolumesCntStart" + if (isset($_SERVER['HTTP_X_ELFINDER_VOLUMESCNTSTART']) && ($volumesCntStart = intval($_SERVER['HTTP_X_ELFINDER_VOLUMESCNTSTART']))) { + self::$volumesCnt = $volumesCntStart; + } + + $this->time = $this->utime(); + $this->sessionCloseEarlier = isset($opts['sessionCloseEarlier']) ? (bool)$opts['sessionCloseEarlier'] : true; + $this->sessionUseCmds = array_flip($sessionUseCmds); + $this->timeout = (isset($opts['timeout']) ? $opts['timeout'] : 0); + $this->uploadTempPath = (isset($opts['uploadTempPath']) ? $opts['uploadTempPath'] : ''); + $this->callbackWindowURL = (isset($opts['callbackWindowURL']) ? $opts['callbackWindowURL'] : ''); + $this->maxTargets = (isset($opts['maxTargets']) ? intval($opts['maxTargets']) : $this->maxTargets); + elFinder::$commonTempPath = (isset($opts['commonTempPath']) ? realpath($opts['commonTempPath']) : dirname(__FILE__) . '/.tmp'); + if (!is_writable(elFinder::$commonTempPath)) { + elFinder::$commonTempPath = sys_get_temp_dir(); + if (!is_writable(elFinder::$commonTempPath)) { + elFinder::$commonTempPath = ''; + } + } + if (isset($opts['connectionFlagsPath']) && is_writable($opts['connectionFlagsPath'] = realpath($opts['connectionFlagsPath']))) { + elFinder::$connectionFlagsPath = $opts['connectionFlagsPath']; + } else { + elFinder::$connectionFlagsPath = elFinder::$commonTempPath; + } + + if (!empty($opts['tmpLinkPath'])) { + elFinder::$tmpLinkPath = realpath($opts['tmpLinkPath']); + } + if (!empty($opts['tmpLinkUrl'])) { + elFinder::$tmpLinkUrl = $opts['tmpLinkUrl']; + } + if (!empty($opts['tmpLinkLifeTime'])) { + elFinder::$tmpLinkLifeTime = $opts['tmpLinkLifeTime']; + } + if (!empty($opts['textMimes']) && is_array($opts['textMimes'])) { + elfinder::$textMimes = $opts['textMimes']; + } + if (!empty($opts['urlUploadFilter'])) { + $this->urlUploadFilter = $opts['urlUploadFilter']; + } + $this->maxArcFilesSize = isset($opts['maxArcFilesSize']) ? intval($opts['maxArcFilesSize']) : 0; + $this->optionsNetVolumes = (isset($opts['optionsNetVolumes']) && is_array($opts['optionsNetVolumes'])) ? $opts['optionsNetVolumes'] : array(); + if (isset($opts['itemLockExpire'])) { + $this->itemLockExpire = intval($opts['itemLockExpire']); + } + + if (!empty($opts['uploadAllowedLanIpClasses'])) { + $this->uploadAllowedLanIpClasses = array_flip($opts['uploadAllowedLanIpClasses']); + } + + // deprecated settings + $this->netVolumesSessionKey = !empty($opts['netVolumesSessionKey']) ? $opts['netVolumesSessionKey'] : 'elFinderNetVolumes'; + self::$sessionCacheKey = !empty($opts['sessionCacheKey']) ? $opts['sessionCacheKey'] : 'elFinderCaches'; + + // check session cache + $_optsMD5 = md5(json_encode($opts['roots'])); + if ($this->session->get('_optsMD5') !== $_optsMD5) { + $this->session->set('_optsMD5', $_optsMD5); + } + + // setlocale and global locale regists to elFinder::locale + self::$locale = !empty($opts['locale']) ? $opts['locale'] : (substr(PHP_OS, 0, 3) === 'WIN' ? 'C' : 'en_US.UTF-8'); + if (false === setlocale(LC_ALL, self::$locale)) { + self::$locale = setlocale(LC_ALL, '0'); + } + + // set defaultMimefile + elFinder::$defaultMimefile = isset($opts['defaultMimefile']) ? $opts['defaultMimefile'] : ''; + + // set memoryLimitGD + elFinder::$memoryLimitGD = isset($opts['memoryLimitGD']) ? $opts['memoryLimitGD'] : 0; + + // set flag of throwErrorOnExec + // `true` need `try{}` block for `$connector->run();` + $this->throwErrorOnExec = !empty($opts['throwErrorOnExec']); + + // set archivers + elFinder::$archivers = isset($opts['archivers']) && is_array($opts['archivers']) ? $opts['archivers'] : array(); + + // set utf8Encoder + if (isset($opts['utf8Encoder']) && is_callable($opts['utf8Encoder'])) { + $this->utf8Encoder = $opts['utf8Encoder']; + } + + // for LocalFileSystem driver on Windows server + if (DIRECTORY_SEPARATOR !== '/') { + if (empty($opts['bind'])) { + $opts['bind'] = array(); + } + + $_key = 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre'; + if (!isset($opts['bind'][$_key])) { + $opts['bind'][$_key] = array(); + } + array_push($opts['bind'][$_key], 'Plugin.WinRemoveTailDots.cmdPreprocess'); + + $_key = 'upload.presave paste.copyfrom'; + if (!isset($opts['bind'][$_key])) { + $opts['bind'][$_key] = array(); + } + array_push($opts['bind'][$_key], 'Plugin.WinRemoveTailDots.onUpLoadPreSave'); + } + + // bind events listeners + if (!empty($opts['bind']) && is_array($opts['bind'])) { + $_req = $_SERVER["REQUEST_METHOD"] == 'POST' ? $_POST : $_GET; + $_reqCmd = isset($_req['cmd']) ? $_req['cmd'] : ''; + foreach ($opts['bind'] as $cmd => $handlers) { + $doRegist = (strpos($cmd, '*') !== false); + if (!$doRegist) { + $doRegist = ($_reqCmd && in_array($_reqCmd, array_map('elFinder::getCmdOfBind', explode(' ', $cmd)))); + } + if ($doRegist) { + // for backward compatibility + if (!is_array($handlers)) { + $handlers = array($handlers); + } else { + if (count($handlers) === 2 && is_callable($handlers)) { + $handlers = array($handlers); + } + } + foreach ($handlers as $handler) { + if ($handler) { + if (is_string($handler) && strpos($handler, '.')) { + list($_domain, $_name, $_method) = array_pad(explode('.', $handler), 3, ''); + if (strcasecmp($_domain, 'plugin') === 0) { + if ($plugin = $this->getPluginInstance($_name, isset($opts['plugin'][$_name]) ? $opts['plugin'][$_name] : array()) + and method_exists($plugin, $_method)) { + $this->bind($cmd, array($plugin, $_method)); + } + } + } else { + $this->bind($cmd, $handler); + } + } + } + } + } + } + + if (!isset($opts['roots']) || !is_array($opts['roots'])) { + $opts['roots'] = array(); + } + + // try to enable elFinderVolumeFlysystemZipArchiveNetmount to zip editing + if (empty(elFinder::$netDrivers['ziparchive'])) { + elFinder::$netDrivers['ziparchive'] = 'FlysystemZipArchiveNetmount'; + } + + // check for net volumes stored in session + $netVolumes = $this->getNetVolumes(); + foreach ($netVolumes as $key => $root) { + if (!isset($root['id'])) { + // given fixed unique id + if (!$root['id'] = $this->getNetVolumeUniqueId($netVolumes)) { + $this->mountErrors[] = 'Netmount Driver "' . $root['driver'] . '" : Could\'t given volume id.'; + continue; + } + } + $root['_isNetVolume'] = true; + $opts['roots'][$key] = $root; + } + + // "mount" volumes + foreach ($opts['roots'] as $i => $o) { + $class = 'elFinderVolume' . (isset($o['driver']) ? $o['driver'] : ''); + + if (class_exists($class)) { + /* @var elFinderVolumeDriver $volume */ + $volume = new $class(); + + try { + if ($this->maxArcFilesSize && (empty($o['maxArcFilesSize']) || $this->maxArcFilesSize < $o['maxArcFilesSize'])) { + $o['maxArcFilesSize'] = $this->maxArcFilesSize; + } + // pass session handler + $volume->setSession($this->session); + if (!$this->default) { + $volume->setNeedOnline(true); + } + if ($volume->mount($o)) { + // unique volume id (ends on "_") - used as prefix to files hash + $id = $volume->id(); + + $this->volumes[$id] = $volume; + if ((!$this->default || $volume->root() !== $volume->defaultPath()) && $volume->isReadable()) { + $this->default = $volume; + } + } else { + if (!empty($o['_isNetVolume'])) { + $this->removeNetVolume($i, $volume); + } + $this->mountErrors[] = 'Driver "' . $class . '" : ' . implode(' ', $volume->error()); + } + } catch (Exception $e) { + if (!empty($o['_isNetVolume'])) { + $this->removeNetVolume($i, $volume); + } + $this->mountErrors[] = 'Driver "' . $class . '" : ' . $e->getMessage(); + } + } else { + if (!empty($o['_isNetVolume'])) { + $this->removeNetVolume($i, $volume); + } + $this->mountErrors[] = 'Driver "' . $class . '" does not exist'; + } + } + + // if at least one readable volume - ii desu >_< + $this->loaded = !empty($this->default); + + // restore error handler for now + restore_error_handler(); + } + + /** + * Return elFinder session wrapper instance + * + * @return elFinderSessionInterface + **/ + public function getSession() + { + return $this->session; + } + + /** + * Return true if fm init correctly + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function loaded() + { + return $this->loaded; + } + + /** + * Return version (api) number + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function version() + { + return self::$ApiVersion; + } + + /** + * Return revision (api) number + * + * @return string + * @author Naoki Sawada + **/ + public function revision() + { + return self::$ApiRevision; + } + + /** + * Add handler to elFinder command + * + * @param string command name + * @param string|array callback name or array(object, method) + * + * @return elFinder + * @author Dmitry (dio) Levashov + **/ + public function bind($cmd, $handler) + { + $allCmds = array_keys($this->commands); + $cmds = array(); + foreach (explode(' ', $cmd) as $_cmd) { + if ($_cmd !== '') { + if ($all = strpos($_cmd, '*') !== false) { + list(, $sub) = array_pad(explode('.', $_cmd), 2, ''); + if ($sub) { + $sub = str_replace('\'', '\\\'', $sub); + $subs = array_fill(0, count($allCmds), $sub); + $cmds = array_merge($cmds, array_map(array('elFinder', 'addSubToBindName'), $allCmds, $subs)); + } else { + $cmds = array_merge($cmds, $allCmds); + } + } else { + $cmds[] = $_cmd; + } + } + } + $cmds = array_unique($cmds); + + foreach ($cmds as $cmd) { + if (!isset($this->listeners[$cmd])) { + $this->listeners[$cmd] = array(); + } + + if (is_callable($handler)) { + $this->listeners[$cmd][] = $handler; + } + } + + return $this; + } + + /** + * Remove event (command exec) handler + * + * @param string command name + * @param string|array callback name or array(object, method) + * + * @return elFinder + * @author Dmitry (dio) Levashov + **/ + public function unbind($cmd, $handler) + { + if (!empty($this->listeners[$cmd])) { + foreach ($this->listeners[$cmd] as $i => $h) { + if ($h === $handler) { + unset($this->listeners[$cmd][$i]); + return $this; + } + } + } + return $this; + } + + /** + * Trigger binded functions + * + * @param string $cmd binded command name + * @param array $vars variables to pass to listeners + * @param array $errors array into which the error is written + */ + public function trigger($cmd, $vars, &$errors) + { + if (!empty($this->listeners[$cmd])) { + foreach ($this->listeners[$cmd] as $handler) { + $_res = call_user_func_array($handler, $vars); + if ($_res && is_array($_res)) { + $_err = !empty($_res['error'])? $_res['error'] : (!empty($_res['warning'])? $_res['warning'] : null); + if ($_err) { + if (is_array($_err)) { + $errors = array_merge($errors, $_err); + } else { + $errors[] = (string)$_err; + } + if ($_res['error']) { + throw new elFinderTriggerException(); + } + } + } + } + } + } + + /** + * Return true if command exists + * + * @param string command name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function commandExists($cmd) + { + return $this->loaded && isset($this->commands[$cmd]) && method_exists($this, $cmd); + } + + /** + * Return root - file's owner (public func of volume()) + * + * @param string file hash + * + * @return elFinderVolumeDriver + * @author Naoki Sawada + */ + public function getVolume($hash) + { + return $this->volume($hash); + } + + /** + * Return command required arguments info + * + * @param string command name + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function commandArgsList($cmd) + { + if ($this->commandExists($cmd)) { + $list = $this->commands[$cmd]; + $list['reqid'] = false; + } else { + $list = array(); + } + return $list; + } + + private function session_expires() + { + + if (!$last = $this->session->get(':LAST_ACTIVITY')) { + $this->session->set(':LAST_ACTIVITY', time()); + return false; + } + + if (($this->timeout > 0) && (time() - $last > $this->timeout)) { + return true; + } + + $this->session->set(':LAST_ACTIVITY', time()); + return false; + } + + /** + * Exec command and return result + * + * @param string $cmd command name + * @param array $args command arguments + * + * @return array + * @throws elFinderAbortException|Exception + * @author Dmitry (dio) Levashov + **/ + public function exec($cmd, $args) + { + // set error handler of WARNING, NOTICE + set_error_handler('elFinder::phpErrorHandler', E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE); + + // set current request args + self::$currentArgs = $args; + + if (!$this->loaded) { + return array('error' => $this->error(self::ERROR_CONF, self::ERROR_CONF_NO_VOL)); + } + + if ($this->session_expires()) { + return array('error' => $this->error(self::ERROR_SESSION_EXPIRES)); + } + + if (!$this->commandExists($cmd)) { + return array('error' => $this->error(self::ERROR_UNKNOWN_CMD)); + } + + // check request id + $args['reqid'] = preg_replace('[^0-9a-fA-F]', '', !empty($args['reqid']) ? $args['reqid'] : (!empty($_SERVER['HTTP_X_ELFINDERREQID']) ? $_SERVER['HTTP_X_ELFINDERREQID'] : '')); + + // to abort this request + if ($cmd === 'abort') { + $this->abort($args); + return array('error' => 0); + } + + // make flag file and set self::$abortCheckFile + if ($args['reqid']) { + $this->abort(array('makeFile' => $args['reqid'])); + } + + if (!empty($args['mimes']) && is_array($args['mimes'])) { + foreach ($this->volumes as $id => $v) { + $this->volumes[$id]->setMimesFilter($args['mimes']); + } + } + + // regist shutdown function as fallback + register_shutdown_function(array($this, 'itemAutoUnlock')); + + // detect destination dirHash and volume + $dstVolume = false; + $dst = !empty($args['target']) ? $args['target'] : (!empty($args['dst']) ? $args['dst'] : ''); + if ($dst) { + $dstVolume = $this->volume($dst); + } else if (isset($args['targets']) && is_array($args['targets']) && isset($args['targets'][0])) { + $dst = $args['targets'][0]; + $dstVolume = $this->volume($dst); + if ($dstVolume && ($_stat = $dstVolume->file($dst)) && !empty($_stat['phash'])) { + $dst = $_stat['phash']; + } else { + $dst = ''; + } + } else if ($cmd === 'open') { + // for initial open without args `target` + $dstVolume = $this->default; + $dst = $dstVolume->defaultPath(); + } + + $result = null; + + // call pre handlers for this command + $args['sessionCloseEarlier'] = isset($this->sessionUseCmds[$cmd]) ? false : $this->sessionCloseEarlier; + if (!empty($this->listeners[$cmd . '.pre'])) { + foreach ($this->listeners[$cmd . '.pre'] as $handler) { + $_res = call_user_func_array($handler, array($cmd, &$args, $this, $dstVolume)); + if (is_array($_res)) { + if (!empty($_res['preventexec'])) { + $result = array('error' => true); + if ($cmd === 'upload' && !empty($args['node'])) { + $result['callback'] = array( + 'node' => $args['node'], + 'bind' => $cmd + ); + } + if (!empty($_res['results']) && is_array($_res['results'])) { + $result = array_merge($result, $_res['results']); + } + break; + } + } + } + } + + // unlock session data for multiple access + if ($this->sessionCloseEarlier && $args['sessionCloseEarlier']) { + $this->session->close(); + // deprecated property + elFinder::$sessionClosed = true; + } + + if (substr(PHP_OS, 0, 3) === 'WIN') { + // set time out + elFinder::extendTimeLimit(300); + } + + if (!is_array($result)) { + try { + $result = $this->$cmd($args); + } catch (elFinderAbortException $e) { + throw $e; + } catch (Exception $e) { + $result = array( + 'error' => htmlspecialchars($e->getMessage()), + 'sync' => true + ); + if ($this->throwErrorOnExec) { + throw $e; + } + } + } + + // check change dstDir + $changeDst = false; + if ($dst && $dstVolume && (!empty($result['added']) || !empty($result['removed']))) { + $changeDst = true; + } + + foreach ($this->volumes as $volume) { + $removed = $volume->removed(); + if (!empty($removed)) { + if (!isset($result['removed'])) { + $result['removed'] = array(); + } + $result['removed'] = array_merge($result['removed'], $removed); + if (!$changeDst && $dst && $dstVolume && $volume === $dstVolume) { + $changeDst = true; + } + } + $added = $volume->added(); + if (!empty($added)) { + if (!isset($result['added'])) { + $result['added'] = array(); + } + $result['added'] = array_merge($result['added'], $added); + if (!$changeDst && $dst && $dstVolume && $volume === $dstVolume) { + $changeDst = true; + } + } + $volume->resetResultStat(); + } + + // dstDir is changed + if ($changeDst) { + if ($dstDir = $dstVolume->dir($dst)) { + if (!isset($result['changed'])) { + $result['changed'] = array(); + } + $result['changed'][] = $dstDir; + } + } + + // call handlers for this command + if (!empty($this->listeners[$cmd])) { + foreach ($this->listeners[$cmd] as $handler) { + if (call_user_func_array($handler, array($cmd, &$result, $args, $this, $dstVolume))) { + // handler return true to force sync client after command completed + $result['sync'] = true; + } + } + } + + // replace removed files info with removed files hashes + if (!empty($result['removed'])) { + $removed = array(); + foreach ($result['removed'] as $file) { + $removed[] = $file['hash']; + } + $result['removed'] = array_unique($removed); + } + // remove hidden files and filter files by mimetypes + if (!empty($result['added'])) { + $result['added'] = $this->filter($result['added']); + } + // remove hidden files and filter files by mimetypes + if (!empty($result['changed'])) { + $result['changed'] = $this->filter($result['changed']); + } + // add toasts + if ($this->toastMessages) { + $result['toasts'] = array_merge(((isset($result['toasts']) && is_array($result['toasts']))? $result['toasts'] : array()), $this->toastMessages); + } + + if ($this->debug || !empty($args['debug'])) { + $result['debug'] = array( + 'connector' => 'php', + 'phpver' => PHP_VERSION, + 'time' => $this->utime() - $this->time, + 'memory' => (function_exists('memory_get_peak_usage') ? ceil(memory_get_peak_usage() / 1024) . 'Kb / ' : '') . ceil(memory_get_usage() / 1024) . 'Kb / ' . ini_get('memory_limit'), + 'upload' => $this->uploadDebug, + 'volumes' => array(), + 'mountErrors' => $this->mountErrors + ); + + foreach ($this->volumes as $id => $volume) { + $result['debug']['volumes'][] = $volume->debug(); + } + } + + // remove sesstion var 'urlContentSaveIds' + if ($this->removeContentSaveIds) { + $urlContentSaveIds = $this->session->get('urlContentSaveIds', array()); + foreach (array_keys($this->removeContentSaveIds) as $contentSaveId) { + if (isset($urlContentSaveIds[$contentSaveId])) { + unset($urlContentSaveIds[$contentSaveId]); + } + } + if ($urlContentSaveIds) { + $this->session->set('urlContentSaveIds', $urlContentSaveIds); + } else { + $this->session->remove('urlContentSaveIds'); + } + } + + foreach ($this->volumes as $volume) { + $volume->saveSessionCache(); + $volume->umount(); + } + + // unlock locked items + $this->itemAutoUnlock(); + + // custom data + if ($this->customData !== null) { + $result['customData'] = $this->customData ? json_encode($this->customData) : ''; + } + + if (!empty($result['debug'])) { + $result['debug']['backendErrors'] = elFinder::$phpErrors; + } + elFinder::$phpErrors = array(); + restore_error_handler(); + + if (!empty($result['callback'])) { + $result['callback']['json'] = json_encode($result); + $this->callback($result['callback']); + return array(); + } else { + return $result; + } + } + + /** + * Return file real path + * + * @param string $hash file hash + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function realpath($hash) + { + if (($volume = $this->volume($hash)) == false) { + return false; + } + return $volume->realpath($hash); + } + + /** + * Sets custom data(s). + * + * @param string|array $key The key or data array + * @param mixed $val The value + * + * @return self ( elFinder instance ) + */ + public function setCustomData($key, $val = null) + { + if (is_array($key)) { + foreach ($key as $k => $v) { + $this->customData[$k] = $v; + } + } else { + $this->customData[$key] = $val; + } + return $this; + } + + /** + * Removes a custom data. + * + * @param string $key The key + * + * @return self ( elFinder instance ) + */ + public function removeCustomData($key) + { + $this->customData[$key] = null; + return $this; + } + + /** + * Update sesstion value of a NetVolume option + * + * @param string $netKey + * @param string $optionKey + * @param mixed $val + * + * @return bool + */ + public function updateNetVolumeOption($netKey, $optionKey, $val) + { + $netVolumes = $this->getNetVolumes(); + if (is_string($netKey) && isset($netVolumes[$netKey]) && is_string($optionKey)) { + $netVolumes[$netKey][$optionKey] = $val; + $this->saveNetVolumes($netVolumes); + return true; + } + return false; + } + + /** + * remove of session var "urlContentSaveIds" + * + * @param string $id + */ + public function removeUrlContentSaveId($id) + { + $this->removeContentSaveIds[$id] = true; + } + + /** + * Return network volumes config. + * + * @return array + * @author Dmitry (dio) Levashov + */ + protected function getNetVolumes() + { + if ($data = $this->session->get('netvolume', array())) { + return $data; + } + return array(); + } + + /** + * Save network volumes config. + * + * @param array $volumes volumes config + * + * @return void + * @author Dmitry (dio) Levashov + */ + protected function saveNetVolumes($volumes) + { + $this->session->set('netvolume', $volumes); + } + + /** + * Remove netmount volume + * + * @param string $key netvolume key + * @param object $volume volume driver instance + * + * @return bool + */ + protected function removeNetVolume($key, $volume) + { + $netVolumes = $this->getNetVolumes(); + $res = true; + if (is_object($volume) && method_exists($volume, 'netunmount')) { + $res = $volume->netunmount($netVolumes, $key); + $volume->clearSessionCache(); + } + if ($res) { + if (is_string($key) && isset($netVolumes[$key])) { + unset($netVolumes[$key]); + $this->saveNetVolumes($netVolumes); + return true; + } + } + return false; + } + + /** + * Get plugin instance & set to $this->plugins + * + * @param string $name Plugin name (dirctory name) + * @param array $opts Plugin options (optional) + * + * @return object | bool Plugin object instance Or false + * @author Naoki Sawada + */ + protected function getPluginInstance($name, $opts = array()) + { + $key = strtolower($name); + if (!isset($this->plugins[$key])) { + $class = 'elFinderPlugin' . $name; + // to try auto load + if (!class_exists($class)) { + $p_file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'plugin.php'; + if (is_file($p_file)) { + include_once $p_file; + } + } + if (class_exists($class, false)) { + $this->plugins[$key] = new $class($opts); + } else { + $this->plugins[$key] = false; + } + } + return $this->plugins[$key]; + } + + /***************************************************************************/ + /* commands */ + /***************************************************************************/ + + /** + * Normalize error messages + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function error() + { + $errors = array(); + + foreach (func_get_args() as $msg) { + if (is_array($msg)) { + $errors = array_merge($errors, $msg); + } else { + $errors[] = $msg; + } + } + + return count($errors) ? $errors : array(self::ERROR_UNKNOWN); + } + + /** + * @param $args + * + * @return array + * @throws elFinderAbortException + */ + protected function netmount($args) + { + $options = array(); + $protocol = $args['protocol']; + $toast = ''; + + if ($protocol === 'netunmount') { + if (!empty($args['user']) && $volume = $this->volume($args['user'])) { + if ($this->removeNetVolume($args['host'], $volume)) { + return array('removed' => array(array('hash' => $volume->root()))); + } + } + return array('sync' => true, 'error' => $this->error(self::ERROR_NETUNMOUNT)); + } + + $driver = isset(self::$netDrivers[$protocol]) ? self::$netDrivers[$protocol] : ''; + $class = 'elFinderVolume' . $driver; + + if (!class_exists($class)) { + return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], self::ERROR_NETMOUNT_NO_DRIVER)); + } + + if (!$args['path']) { + $args['path'] = '/'; + } + + foreach ($args as $k => $v) { + if ($k != 'options' && $k != 'protocol' && $v) { + $options[$k] = $v; + } + } + + if (is_array($args['options'])) { + foreach ($args['options'] as $key => $value) { + $options[$key] = $value; + } + } + + /* @var elFinderVolumeDriver $volume */ + $volume = new $class(); + + // pass session handler + $volume->setSession($this->session); + + $volume->setNeedOnline(true); + + if (is_callable(array($volume, 'netmountPrepare'))) { + $options = $volume->netmountPrepare($options); + if (isset($options['exit'])) { + if ($options['exit'] === 'callback') { + $this->callback($options['out']); + } + return $options; + } + if (!empty($options['toast'])) { + $toast = $options['toast']; + unset($options['toast']); + } + } + + $netVolumes = $this->getNetVolumes(); + + if (!isset($options['id'])) { + // given fixed unique id + if (!$options['id'] = $this->getNetVolumeUniqueId($netVolumes)) { + return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], 'Could\'t given volume id.')); + } + } + + // load additional volume root options + if (!empty($this->optionsNetVolumes['*'])) { + $options = array_merge($this->optionsNetVolumes['*'], $options); + } + if (!empty($this->optionsNetVolumes[$protocol])) { + $options = array_merge($this->optionsNetVolumes[$protocol], $options); + } + + if (!$key = $volume->netMountKey) { + $key = md5($protocol . '-' . serialize($options)); + } + $options['netkey'] = $key; + + if (!isset($netVolumes[$key]) && $volume->mount($options)) { + // call post-process function of netmount + if (is_callable(array($volume, 'postNetmount'))) { + $volume->postNetmount($options); + } + $options['driver'] = $driver; + $netVolumes[$key] = $options; + $this->saveNetVolumes($netVolumes); + $rootstat = $volume->file($volume->root()); + $res = array('added' => array($rootstat)); + if ($toast) { + $res['toast'] = $toast; + } + return $res; + } else { + $this->removeNetVolume(null, $volume); + return array('error' => $this->error(self::ERROR_NETMOUNT, $args['host'], implode(' ', $volume->error()))); + } + } + + /** + * "Open" directory + * Return array with following elements + * - cwd - opened dir info + * - files - opened dir content [and dirs tree if $args[tree]] + * - api - api version (if $args[init]) + * - uplMaxSize - if $args[init] + * - error - on failed + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function open($args) + { + $target = $args['target']; + $init = !empty($args['init']); + $tree = !empty($args['tree']); + $volume = $this->volume($target); + $cwd = $volume ? $volume->dir($target) : false; + $hash = $init ? 'default folder' : '#' . $target; + $compare = ''; + + // on init request we can get invalid dir hash - + // dir which can not be opened now, but remembered by client, + // so open default dir + if ((!$cwd || !$cwd['read']) && $init) { + $volume = $this->default; + $target = $volume->defaultPath(); + $cwd = $volume->dir($target); + } + + if (!$cwd) { + return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_DIR_NOT_FOUND)); + } + if (!$cwd['read']) { + return array('error' => $this->error(self::ERROR_OPEN, $hash, self::ERROR_PERM_DENIED)); + } + + $files = array(); + + // get current working directory files list + if (($ls = $volume->scandir($cwd['hash'])) === false) { + return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error())); + } + + if (isset($cwd['dirs']) && $cwd['dirs'] != 1) { + $cwd = $volume->dir($target); + } + + // get other volume root + if ($tree) { + foreach ($this->volumes as $id => $v) { + $files[] = $v->file($v->root()); + } + } + + // long polling mode + if ($args['compare']) { + $sleep = max(1, (int)$volume->getOption('lsPlSleep')); + $standby = (int)$volume->getOption('plStandby'); + if ($standby > 0 && $sleep > $standby) { + $standby = $sleep; + } + $limit = max(0, floor($standby / $sleep)) + 1; + do { + elFinder::extendTimeLimit(30 + $sleep); + $_mtime = 0; + foreach ($ls as $_f) { + if (isset($_f['ts'])) { + $_mtime = max($_mtime, $_f['ts']); + } + } + $compare = strval(count($ls)) . ':' . strval($_mtime); + if ($compare !== $args['compare']) { + break; + } + if (--$limit) { + sleep($sleep); + $volume->clearstatcache(); + if (($ls = $volume->scandir($cwd['hash'])) === false) { + break; + } + } + } while ($limit); + if ($ls === false) { + return array('error' => $this->error(self::ERROR_OPEN, $cwd['name'], $volume->error())); + } + } + + if ($ls) { + if ($files) { + $files = array_merge($files, $ls); + } else { + $files = $ls; + } + } + + $result = array( + 'cwd' => $cwd, + 'options' => $volume->options($cwd['hash']), + 'files' => $files + ); + + if ($compare) { + $result['cwd']['compare'] = $compare; + } + + if (!empty($args['init'])) { + $result['api'] = sprintf('%.1F%03d', self::$ApiVersion, self::$ApiRevision); + $result['uplMaxSize'] = ini_get('upload_max_filesize'); + $result['uplMaxFile'] = ini_get('max_file_uploads'); + $result['netDrivers'] = array_keys(self::$netDrivers); + $result['maxTargets'] = $this->maxTargets; + if ($volume) { + $result['cwd']['root'] = $volume->root(); + } + if (elfinder::$textMimes) { + $result['textMimes'] = elfinder::$textMimes; + } + } + + return $result; + } + + /** + * Return dir files names list + * + * @param array command arguments + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function ls($args) + { + $target = $args['target']; + $intersect = isset($args['intersect']) ? $args['intersect'] : array(); + + if (($volume = $this->volume($target)) == false + || ($list = $volume->ls($target, $intersect)) === false) { + return array('error' => $this->error(self::ERROR_OPEN, '#' . $target)); + } + return array('list' => $list); + } + + /** + * Return subdirs for required directory + * + * @param array command arguments + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function tree($args) + { + $target = $args['target']; + + if (($volume = $this->volume($target)) == false + || ($tree = $volume->tree($target)) == false) { + return array('error' => $this->error(self::ERROR_OPEN, '#' . $target)); + } + + return array('tree' => $tree); + } + + /** + * Return parents dir for required directory + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function parents($args) + { + $target = $args['target']; + $until = $args['until']; + + if (($volume = $this->volume($target)) == false + || ($tree = $volume->parents($target, false, $until)) == false) { + return array('error' => $this->error(self::ERROR_OPEN, '#' . $target)); + } + + return array('tree' => $tree); + } + + /** + * Return new created thumbnails list + * + * @param array command arguments + * + * @return array + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function tmb($args) + { + + $result = array('images' => array()); + $targets = $args['targets']; + + foreach ($targets as $target) { + elFinder::checkAborted(); + + if (($volume = $this->volume($target)) != false + && (($tmb = $volume->tmb($target)) != false)) { + $result['images'][$target] = $tmb; + } + } + return $result; + } + + /** + * Download files/folders as an archive file + * 1st: Return srrsy contains download archive file info + * 2nd: Return array contains opened file pointer, root itself and required headers + * + * @param array command arguments + * + * @return array + * @throws Exception + * @author Naoki Sawada + */ + protected function zipdl($args) + { + $targets = $args['targets']; + $download = !empty($args['download']); + $h404 = 'HTTP/1.x 404 Not Found'; + $CriOS = isset($_SERVER['HTTP_USER_AGENT'])? (strpos($_SERVER['HTTP_USER_AGENT'], 'CriOS') !== false) : false; + + if (!$download) { + //1st: Return array contains download archive file info + $error = array(self::ERROR_ARCHIVE); + if (($volume = $this->volume($targets[0])) !== false) { + if ($dlres = $volume->zipdl($targets)) { + $path = $dlres['path']; + register_shutdown_function(array('elFinder', 'rmFileInDisconnected'), $path); + if (count($targets) === 1) { + $name = basename($volume->path($targets[0])); + } else { + $name = $dlres['prefix'] . '_Files'; + } + $name .= '.' . $dlres['ext']; + $uniqid = uniqid(); + $this->session->set('zipdl' . $uniqid, basename($path)); + $result = array( + 'zipdl' => array( + 'file' => $CriOS? basename($path) : $uniqid, + 'name' => $name, + 'mime' => $dlres['mime'] + ) + ); + return $result; + } + $error = array_merge($error, $volume->error()); + } + return array('error' => $error); + } else { + // 2nd: Return array contains opened file session key, root itself and required headers + + // Detect Chrome on iOS + // It has access twice on downloading + $CriOSinit = false; + if ($CriOS) { + $accept = isset($_SERVER['HTTP_ACCEPT'])? $_SERVER['HTTP_ACCEPT'] : ''; + if ($accept && $accept !== '*' && $accept !== '*/*') { + $CriOSinit = true; + } + } + // data check + if (count($targets) !== 4 || ($volume = $this->volume($targets[0])) == false || !($file = $CriOS? $targets[1] : $this->session->get('zipdl' . $targets[1]))) { + return array('error' => 'File not found', 'header' => $h404, 'raw' => true); + } + $path = $volume->getTempPath() . DIRECTORY_SEPARATOR . basename($file); + // remove session data of "zipdl..." + $this->session->remove('zipdl' . $targets[1]); + if (!$CriOSinit) { + // register auto delete on shutdown + $GLOBALS['elFinderTempFiles'][$path] = true; + } + if ($volume->commandDisabled('zipdl')) { + return array('error' => 'File not found', 'header' => $h404, 'raw' => true); + } + if (!is_readable($path) || !is_writable($path)) { + return array('error' => 'File not found', 'header' => $h404, 'raw' => true); + } + // for HTTP headers + $name = $targets[2]; + $mime = $targets[3]; + + $filenameEncoded = rawurlencode($name); + if (strpos($filenameEncoded, '%') === false) { // ASCII only + $filename = 'filename="' . $name . '"'; + } else { + $ua = $_SERVER['HTTP_USER_AGENT']; + if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987) + $filename = 'filename="' . $filenameEncoded . '"'; + } elseif (strpos($ua, 'Chrome') === false && strpos($ua, 'Safari') !== false && preg_match('#Version/[3-5]#', $ua)) { // Safari < 6 + $filename = 'filename="' . str_replace('"', '', $name) . '"'; + } else { // RFC 6266 (RFC 2231/RFC 5987) + $filename = 'filename*=UTF-8\'\'' . $filenameEncoded; + } + } + + $fp = fopen($path, 'rb'); + $file = fstat($fp); + $result = array( + 'pointer' => $fp, + 'header' => array( + 'Content-Type: ' . $mime, + 'Content-Disposition: attachment; ' . $filename, + 'Content-Transfer-Encoding: binary', + 'Content-Length: ' . $file['size'], + 'Accept-Ranges: none', + 'Connection: close' + ) + ); + // add cache control headers + if ($cacheHeaders = $volume->getOption('cacheHeaders')) { + $result['header'] = array_merge($result['header'], $cacheHeaders); + } + return $result; + } + } + + /** + * Required to output file in browser when volume URL is not set + * Return array contains opened file pointer, root itself and required headers + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function file($args) + { + $target = $args['target']; + $download = !empty($args['download']); + $onetime = !empty($args['onetime']); + //$h304 = 'HTTP/1.1 304 Not Modified'; + $h403 = 'HTTP/1.0 403 Access Denied'; + $a403 = array('error' => 'Access Denied', 'header' => $h403, 'raw' => true); + $h404 = 'HTTP/1.0 404 Not Found'; + $a404 = array('error' => 'File not found', 'header' => $h404, 'raw' => true); + + if ($onetime) { + $volume = null; + $tmpdir = elFinder::$commonTempPath; + if (!$tmpdir || !is_file($tmpf = $tmpdir . DIRECTORY_SEPARATOR . 'ELF' . basename($target))) { + return $a404; + } + $GLOBALS['elFinderTempFiles'][$tmpf] = true; + if ($file = json_decode(file_get_contents($tmpf), true)) { + $src = $tmpdir . DIRECTORY_SEPARATOR . basename(base64_decode($file['file'])); + if (!is_file($src) || !($fp = fopen($src, 'rb'))) { + return $a404; + } + $GLOBALS['elFinderTempFiles'][$src] = true; + + unset($file['file']); + $file['read'] = true; + $file['size'] = filesize($src); + } else { + return $a404; + } + } else { + if (($volume = $this->volume($target)) == false) { + return $a404; + } + + if ($volume->commandDisabled('file')) { + return $a403; + } + + if (($file = $volume->file($target)) == false) { + return $a404; + } + + if (!$file['read']) { + return $a404; + } + + $opts = array(); + if (!empty($_SERVER['HTTP_RANGE'])) { + $opts['httpheaders'] = array('Range: ' . $_SERVER['HTTP_RANGE']); + } + if (($fp = $volume->open($target, $opts)) == false) { + return $a404; + } + } + + // check aborted by user + elFinder::checkAborted(); + + // allow change MIME type by 'file.pre' callback functions + $mime = isset($args['mime']) ? $args['mime'] : $file['mime']; + if ($download || $onetime) { + $disp = 'attachment'; + } else { + $dispInlineRegex = $volume->getOption('dispInlineRegex'); + $inlineRegex = false; + if ($dispInlineRegex) { + $inlineRegex = '#' . str_replace('#', '\\#', $dispInlineRegex) . '#'; + try { + preg_match($inlineRegex, ''); + } catch (Exception $e) { + $inlineRegex = false; + } + } + if (!$inlineRegex) { + $inlineRegex = '#^(?:(?:image|text)|application/x-shockwave-flash$)#'; + } + $disp = preg_match($inlineRegex, $mime) ? 'inline' : 'attachment'; + } + + $filenameEncoded = rawurlencode($file['name']); + if (strpos($filenameEncoded, '%') === false) { // ASCII only + $filename = 'filename="' . $file['name'] . '"'; + } else { + $ua = isset($_SERVER['HTTP_USER_AGENT'])? $_SERVER['HTTP_USER_AGENT'] : ''; + if (preg_match('/MSIE [4-8]/', $ua)) { // IE < 9 do not support RFC 6266 (RFC 2231/RFC 5987) + $filename = 'filename="' . $filenameEncoded . '"'; + } elseif (strpos($ua, 'Chrome') === false && strpos($ua, 'Safari') !== false && preg_match('#Version/[3-5]#', $ua)) { // Safari < 6 + $filename = 'filename="' . str_replace('"', '', $file['name']) . '"'; + } else { // RFC 6266 (RFC 2231/RFC 5987) + $filename = 'filename*=UTF-8\'\'' . $filenameEncoded; + } + } + + if ($args['cpath'] && $args['reqid']) { + setcookie('elfdl' . $args['reqid'], '1', 0, $args['cpath']); + } + + $result = array( + 'volume' => $volume, + 'pointer' => $fp, + 'info' => $file, + 'header' => array( + 'Content-Type: ' . $mime, + 'Content-Disposition: ' . $disp . '; ' . $filename, + 'Content-Transfer-Encoding: binary', + 'Content-Length: ' . $file['size'], + 'Last-Modified: ' . gmdate('D, d M Y H:i:s T', $file['ts']), + 'Connection: close' + ) + ); + + if (!$onetime) { + // add cache control headers + if ($cacheHeaders = $volume->getOption('cacheHeaders')) { + $result['header'] = array_merge($result['header'], $cacheHeaders); + } + + // check 'xsendfile' + $xsendfile = $volume->getOption('xsendfile'); + $path = null; + if ($xsendfile) { + $info = stream_get_meta_data($fp); + if ($path = empty($info['uri']) ? null : $info['uri']) { + $basePath = rtrim($volume->getOption('xsendfilePath'), DIRECTORY_SEPARATOR); + if ($basePath) { + $root = rtrim($volume->getRootPath(), DIRECTORY_SEPARATOR); + if (strpos($path, $root) === 0) { + $path = $basePath . substr($path, strlen($root)); + } else { + $path = null; + } + } + } + } + if ($path) { + $result['header'][] = $xsendfile . ': ' . $path; + $result['info']['xsendfile'] = $xsendfile; + } + } + + // add "Content-Location" if file has url data + if (isset($file['url']) && $file['url'] && $file['url'] != 1) { + $result['header'][] = 'Content-Location: ' . $file['url']; + } + return $result; + } + + /** + * Count total files size + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function size($args) + { + $size = 0; + $files = 0; + $dirs = 0; + $itemCount = true; + $sizes = array(); + + foreach ($args['targets'] as $target) { + elFinder::checkAborted(); + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false + || !$file['read']) { + return array('error' => $this->error(self::ERROR_OPEN, '#' . $target)); + } + + $volRes = $volume->size($target); + if (is_array($volRes)) { + $sizeInfo = array('size' => 0, 'fileCnt' => 0, 'dirCnt' => 0); + if (!empty($volRes['size'])) { + $sizeInfo['size'] = $volRes['size']; + $size += $volRes['size']; + } + if (!empty($volRes['files'])) { + $sizeInfo['fileCnt'] = $volRes['files']; + } + if (!empty($volRes['dirs'])) { + $sizeInfo['dirCnt'] = $volRes['dirs']; + } + if ($itemCount) { + $files += $sizeInfo['fileCnt']; + $dirs += $sizeInfo['dirCnt']; + } + $sizes[$target] = $sizeInfo; + } else if (is_numeric($volRes)) { + $size += $volRes; + $files = $dirs = 'unknown'; + $itemCount = false; + } + } + return array('size' => $size, 'fileCnt' => $files, 'dirCnt' => $dirs, 'sizes' => $sizes); + } + + /** + * Create directory + * + * @param array command arguments + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function mkdir($args) + { + $target = $args['target']; + $name = $args['name']; + $dirs = $args['dirs']; + if ($name === '' && !$dirs) { + return array('error' => $this->error(self::ERROR_INV_PARAMS, 'mkdir')); + } + + if (($volume = $this->volume($target)) == false) { + return array('error' => $this->error(self::ERROR_MKDIR, $name, self::ERROR_TRGDIR_NOT_FOUND, '#' . $target)); + } + if ($dirs) { + $maxDirs = $volume->getOption('uploadMaxMkdirs'); + if ($maxDirs && $maxDirs < count($dirs)) { + return array('error' => $this->error(self::ERROR_MAX_MKDIRS, $maxDirs)); + } + sort($dirs); + $reset = null; + $mkdirs = array(); + foreach ($dirs as $dir) { + $tgt =& $mkdirs; + $_names = explode('/', trim($dir, '/')); + foreach ($_names as $_key => $_name) { + if (!isset($tgt[$_name])) { + $tgt[$_name] = array(); + } + $tgt =& $tgt[$_name]; + } + $tgt =& $reset; + } + $res = $this->ensureDirsRecursively($volume, $target, $mkdirs); + $ret = array( + 'added' => $res['stats'], + 'hashes' => $res['hashes'] + ); + if ($res['error']) { + $ret['warning'] = $this->error(self::ERROR_MKDIR, $res['error'][0], $volume->error()); + } + return $ret; + } else { + return ($dir = $volume->mkdir($target, $name)) == false + ? array('error' => $this->error(self::ERROR_MKDIR, $name, $volume->error())) + : array('added' => array($dir)); + } + } + + /** + * Create empty file + * + * @param array command arguments + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function mkfile($args) + { + $target = $args['target']; + $name = $args['name']; + + if (($volume = $this->volume($target)) == false) { + return array('error' => $this->error(self::ERROR_MKFILE, $name, self::ERROR_TRGDIR_NOT_FOUND, '#' . $target)); + } + + return ($file = $volume->mkfile($target, $args['name'])) == false + ? array('error' => $this->error(self::ERROR_MKFILE, $name, $volume->error())) + : array('added' => array($file)); + } + + /** + * Rename file, Accept multiple items >= API 2.1031 + * + * @param array $args + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function rename($args) + { + $target = $args['target']; + $name = $args['name']; + $query = (!empty($args['q']) && strpos($args['q'], '*') !== false) ? $args['q'] : ''; + $targets = !empty($args['targets'])? $args['targets'] : false; + $rms = array(); + $notfounds = array(); + $locked = array(); + $errs = array(); + $files = array(); + $removed = array(); + $res = array(); + $type = 'normal'; + + if (!($volume = $this->volume($target))) { + return array('error' => $this->error(self::ERROR_RENAME, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + } + + if ($targets) { + array_unshift($targets, $target); + foreach ($targets as $h) { + if ($rm = $volume->file($h)) { + if ($this->itemLocked($h)) { + $locked[] = $rm['name']; + } else { + $rm['realpath'] = $volume->realpath($h); + $rms[] = $rm; + } + } else { + $notfounds[] = '#' . $h; + } + } + if (!$rms) { + $res['error'] = array(); + if ($notfounds) { + $res['error'] = array(self::ERROR_RENAME, join(', ', $notfounds), self::ERROR_FILE_NOT_FOUND); + } + if ($locked) { + array_push($res['error'], self::ERROR_LOCKED, join(', ', $locked)); + } + return $res; + } + + $res['warning'] = array(); + if ($notfounds) { + array_push($res['warning'], self::ERROR_RENAME, join(', ', $notfounds), self::ERROR_FILE_NOT_FOUND); + } + if ($locked) { + array_push($res['warning'], self::ERROR_LOCKED, join(', ', $locked)); + } + + if ($query) { + // batch rename + $splits = elFinder::splitFileExtention($query); + if ($splits[1] && $splits[0] === '*') { + $type = 'extention'; + $name = $splits[1]; + } else if (strlen($splits[0]) > 1) { + if (substr($splits[0], -1) === '*') { + $type = 'prefix'; + $name = substr($splits[0], 0, strlen($splits[0]) - 1); + } else if (substr($splits[0], 0, 1) === '*') { + $type = 'suffix'; + $name = substr($splits[0], 1); + } + } + if ($type !== 'normal') { + if (!empty($this->listeners['rename.pre'])) { + $_args = array('name' => $name); + foreach ($this->listeners['rename.pre'] as $handler) { + $_res = call_user_func_array($handler, array('rename', &$_args, $this, $volume)); + if (!empty($_res['preventexec'])) { + break; + } + } + $name = $_args['name']; + } + } + } + foreach ($rms as $rm) { + if ($type === 'normal') { + $rname = $volume->uniqueName($volume->realpath($rm['phash']), $name, '', false); + } else { + $rname = $name; + if ($type === 'extention') { + $splits = elFinder::splitFileExtention($rm['name']); + $rname = $splits[0] . '.' . $name; + } else if ($type === 'prefix') { + $rname = $name . $rm['name']; + } else if ($type === 'suffix') { + $splits = elFinder::splitFileExtention($rm['name']); + $rname = $splits[0] . $name . ($splits[1] ? ('.' . $splits[1]) : ''); + } + $rname = $volume->uniqueName($volume->realpath($rm['phash']), $rname, '', true); + } + if ($file = $volume->rename($rm['hash'], $rname)) { + $files[] = $file; + $removed[] = $rm; + } else { + $errs[] = $rm['name']; + } + } + + if (!$files) { + $res['error'] = $this->error(self::ERROR_RENAME, join(', ', $errs), $volume->error()); + if (!$res['warning']) { + unset($res['warning']); + } + return $res; + } + if ($errs) { + array_push($res['warning'], self::ERROR_RENAME, join(', ', $errs), $volume->error()); + } + if (!$res['warning']) { + unset($res['warning']); + } + $res['added'] = $files; + $res['removed'] = $removed; + return $res; + } else { + if (!($rm = $volume->file($target))) { + return array('error' => $this->error(self::ERROR_RENAME, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + } + if ($this->itemLocked($target)) { + return array('error' => $this->error(self::ERROR_LOCKED, $rm['name'])); + } + $rm['realpath'] = $volume->realpath($target); + + $file = $volume->rename($target, $name); + if ($file === false) { + return array('error' => $this->error(self::ERROR_RENAME, $rm['name'], $volume->error())); + } else { + if ($file['hash'] !== $rm['hash']) { + return array('added' => array($file), 'removed' => array($rm)); + } else { + return array('changed' => array($file)); + } + } + } + } + + /** + * Duplicate file - create copy with "copy %d" suffix + * + * @param array $args command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function duplicate($args) + { + $targets = is_array($args['targets']) ? $args['targets'] : array(); + $result = array(); + $suffix = empty($args['suffix']) ? 'copy' : $args['suffix']; + + $this->itemLock($targets); + + foreach ($targets as $target) { + elFinder::checkAborted(); + + if (($volume = $this->volume($target)) == false + || ($src = $volume->file($target)) == false) { + $result['warning'] = $this->error(self::ERROR_COPY, '#' . $target, self::ERROR_FILE_NOT_FOUND); + break; + } + + if (($file = $volume->duplicate($target, $suffix)) == false) { + $result['warning'] = $this->error($volume->error()); + break; + } + } + + return $result; + } + + /** + * Remove dirs/files + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function rm($args) + { + $targets = is_array($args['targets']) ? $args['targets'] : array(); + $result = array('removed' => array()); + + foreach ($targets as $target) { + elFinder::checkAborted(); + + if (($volume = $this->volume($target)) == false) { + $result['warning'] = $this->error(self::ERROR_RM, '#' . $target, self::ERROR_FILE_NOT_FOUND); + break; + } + + if ($this->itemLocked($target)) { + $rm = $volume->file($target); + $result['warning'] = $this->error(self::ERROR_LOCKED, $rm['name']); + break; + } + + if (!$volume->rm($target)) { + $result['warning'] = $this->error($volume->error()); + break; + } + } + + return $result; + } + + /** + * Return has subdirs + * + * @param array command arguments + * + * @return array + * @author Dmitry Naoki Sawada + **/ + protected function subdirs($args) + { + + $result = array('subdirs' => array()); + $targets = $args['targets']; + + foreach ($targets as $target) { + if (($volume = $this->volume($target)) !== false) { + $result['subdirs'][$target] = $volume->subdirs($target) ? 1 : 0; + } + } + return $result; + } + + /** + * Gateway for custom contents editor + * + * @param array $args command arguments + * + * @return array + * @author Naoki Sawada + */ + protected function editor($args = array()) + { + /* @var elFinderEditor $editor */ + $name = $args['name']; + if (is_array($name)) { + $res = array(); + foreach ($name as $c) { + $class = 'elFinderEditor' . $c; + if (class_exists($class)) { + $editor = new $class($this, $args['args']); + $res[$c] = $editor->enabled(); + } else { + $res[$c] = 0; + } + } + return $res; + } else { + $class = 'elFinderEditor' . $name; + $method = ''; + if (class_exists($class)) { + $editor = new $class($this, $args['args']); + $method = $args['method']; + if ($editor->isAllowedMethod($method) && method_exists($editor, $method)) { + return $editor->$method(); + } + } + return array('error', $this->error(self::ERROR_UNKNOWN_CMD, 'editor.' . $name . '.' . $method)); + } + } + + /** + * Abort current request and make flag file to running check + * + * @param array $args + * + * @return void + */ + protected function abort($args = array()) + { + if (!elFinder::$connectionFlagsPath || $_SERVER['REQUEST_METHOD'] === 'HEAD') { + return; + } + $flagFile = elFinder::$connectionFlagsPath . DIRECTORY_SEPARATOR . 'elfreq%s'; + if (!empty($args['makeFile'])) { + self::$abortCheckFile = sprintf($flagFile, self::filenameDecontaminate($args['makeFile'])); + touch(self::$abortCheckFile); + $GLOBALS['elFinderAbortFiles'][self::$abortCheckFile] = true; + return; + } + + $file = !empty($args['id']) ? sprintf($flagFile, self::filenameDecontaminate($args['id'])) : self::$abortCheckFile; + $file && is_file($file) && unlink($file); + } + + /** + * Validate an URL to prevent SSRF attacks. + * + * To prevent any risk of DNS rebinding, always use the IP address resolved by + * this method, as returned in the array entry `ip`. + * + * @param string $url + * + * @return false|array + */ + protected function validate_address($url) + { + $info = parse_url($url); + $host = trim(strtolower($info['host']), '.'); + // do not support IPv6 address + if (preg_match('/^\[.*\]$/', $host)) { + return false; + } + // do not support non dot host + if (strpos($host, '.') === false) { + return false; + } + // do not support URL-encoded host + if (strpos($host, '%') !== false) { + return false; + } + // disallow including "localhost" and "localdomain" + if (preg_match('/\b(?:localhost|localdomain)\b/', $host)) { + return false; + } + // check IPv4 local loopback, private network and link local + $ip = gethostbyname($host); + if (preg_match('/^0x[0-9a-f]+|[0-9]+(?:\.(?:0x[0-9a-f]+|[0-9]+)){1,3}$/', $ip, $m)) { + $long = (int)sprintf('%u', ip2long($ip)); + if (!$long) { + return false; + } + $local = (int)sprintf('%u', ip2long('127.255.255.255')) >> 24; + $prv1 = (int)sprintf('%u', ip2long('10.255.255.255')) >> 24; + $prv2 = (int)sprintf('%u', ip2long('172.31.255.255')) >> 20; + $prv3 = (int)sprintf('%u', ip2long('192.168.255.255')) >> 16; + $link = (int)sprintf('%u', ip2long('169.254.255.255')) >> 16; + + if (!isset($this->uploadAllowedLanIpClasses['local']) && $long >> 24 === $local) { + return false; + } + if (!isset($this->uploadAllowedLanIpClasses['private_a']) && $long >> 24 === $prv1) { + return false; + } + if (!isset($this->uploadAllowedLanIpClasses['private_b']) && $long >> 20 === $prv2) { + return false; + } + if (!isset($this->uploadAllowedLanIpClasses['private_c']) && $long >> 16 === $prv3) { + return false; + } + if (!isset($this->uploadAllowedLanIpClasses['link']) && $long >> 16 === $link) { + return false; + } + $info['ip'] = long2ip($long); + if (!isset($info['port'])) { + $info['port'] = $info['scheme'] === 'https' ? 443 : 80; + } + if (!isset($info['path'])) { + $info['path'] = '/'; + } + return $info; + } else { + return false; + } + } + + /** + * Get remote contents + * + * @param string $url target url + * @param int $timeout timeout (sec) + * @param int $redirect_max redirect max count + * @param string $ua + * @param resource $fp + * + * @return string, resource or bool(false) + * @retval string contents + * @retval resource conttents + * @rettval false error + * @author Naoki Sawada + **/ + protected function get_remote_contents(&$url, $timeout = 30, $redirect_max = 5, $ua = 'Mozilla/5.0', $fp = null) + { + if (preg_match('~^(?:ht|f)tps?://[-_.!\~*\'()a-z0-9;/?:\@&=+\$,%#\*\[\]]+~i', $url)) { + $info = $this->validate_address($url); + if ($info === false) { + return false; + } + // dose not support 'user' and 'pass' for security reasons + $url = $info['scheme'].'://'.$info['host'].(!empty($info['port'])? (':'.$info['port']) : '').$info['path'].(!empty($info['query'])? ('?'.$info['query']) : '').(!empty($info['fragment'])? ('#'.$info['fragment']) : ''); + // check by URL upload filter + if ($this->urlUploadFilter && is_callable($this->urlUploadFilter)) { + if (!call_user_func_array($this->urlUploadFilter, array($url, $this))) { + return false; + } + } + $method = (function_exists('curl_exec')) ? 'curl_get_contents' : 'fsock_get_contents'; + return $this->$method($url, $timeout, $redirect_max, $ua, $fp, $info); + } + return false; + } + + /** + * Get remote contents with cURL + * + * @param string $url target url + * @param int $timeout timeout (sec) + * @param int $redirect_max redirect max count + * @param string $ua + * @param resource $outfp + * + * @return string, resource or bool(false) + * @retval string contents + * @retval resource conttents + * @retval false error + * @author Naoki Sawada + **/ + protected function curl_get_contents(&$url, $timeout, $redirect_max, $ua, $outfp, $info) + { + if ($redirect_max == 0) { + return false; + } + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_HEADER, false); + if ($outfp) { + curl_setopt($ch, CURLOPT_FILE, $outfp); + } else { + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + } + curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, 1); + curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, $timeout); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt($ch, CURLOPT_USERAGENT, $ua); + curl_setopt($ch, CURLOPT_RESOLVE, array($info['host'] . ':' . $info['port'] . ':' . $info['ip'])); + $result = curl_exec($ch); + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($http_code == 301 || $http_code == 302) { + $new_url = curl_getinfo($ch, CURLINFO_REDIRECT_URL); + $info = $this->validate_address($new_url); + if ($info === false) { + return false; + } + return $this->curl_get_contents($new_url, $timeout, $redirect_max - 1, $ua, $outfp, $info); + } + curl_close($ch); + return $outfp ? $outfp : $result; + } + + /** + * Get remote contents with fsockopen() + * + * @param string $url url + * @param int $timeout timeout (sec) + * @param int $redirect_max redirect max count + * @param string $ua + * @param resource $outfp + * + * @return string, resource or bool(false) + * @retval string contents + * @retval resource conttents + * @retval false error + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function fsock_get_contents(&$url, $timeout, $redirect_max, $ua, $outfp, $info) + { + $connect_timeout = 3; + $connect_try = 3; + $method = 'GET'; + $readsize = 4096; + $ssl = ''; + + $getSize = null; + $headers = ''; + + $arr = $info; + if ($arr['scheme'] === 'https') { + $ssl = 'ssl://'; + } + + // query + $arr['query'] = isset($arr['query']) ? '?' . $arr['query'] : ''; + + $url_base = $arr['scheme'] . '://' . $info['host'] . ':' . $info['port']; + $url_path = isset($arr['path']) ? $arr['path'] : '/'; + $uri = $url_path . $arr['query']; + + $query = $method . ' ' . $uri . " HTTP/1.0\r\n"; + $query .= "Host: " . $arr['host'] . "\r\n"; + $query .= "Accept: */*\r\n"; + $query .= "Connection: close\r\n"; + if (!empty($ua)) $query .= "User-Agent: " . $ua . "\r\n"; + if (!is_null($getSize)) $query .= 'Range: bytes=0-' . ($getSize - 1) . "\r\n"; + + $query .= $headers; + + $query .= "\r\n"; + + $fp = $connect_try_count = 0; + while (!$fp && $connect_try_count < $connect_try) { + + $errno = 0; + $errstr = ""; + $fp = fsockopen( + $ssl . $arr['host'], + $arr['port'], + $errno, $errstr, $connect_timeout); + if ($fp) break; + $connect_try_count++; + if (connection_aborted()) { + throw new elFinderAbortException(); + } + sleep(1); // wait 1sec + } + + if (!$fp) { + return false; + } + + $fwrite = 0; + for ($written = 0; $written < strlen($query); $written += $fwrite) { + $fwrite = fwrite($fp, substr($query, $written)); + if (!$fwrite) { + break; + } + } + + if ($timeout) { + socket_set_timeout($fp, $timeout); + } + + $_response = ''; + $header = ''; + while ($_response !== "\r\n") { + $_response = fgets($fp, $readsize); + $header .= $_response; + }; + + $rccd = array_pad(explode(' ', $header, 2), 2, ''); // array('HTTP/1.1','200') + $rc = (int)$rccd[1]; + + $ret = false; + // Redirect + switch ($rc) { + case 307: // Temporary Redirect + case 303: // See Other + case 302: // Moved Temporarily + case 301: // Moved Permanently + $matches = array(); + if (preg_match('/^Location: (.+?)(#.+)?$/im', $header, $matches) && --$redirect_max > 0) { + $_url = $url; + $url = trim($matches[1]); + if (!preg_match('/^https?:\//', $url)) { // no scheme + if ($url[0] != '/') { // Relative path + // to Absolute path + $url = substr($url_path, 0, strrpos($url_path, '/')) . '/' . $url; + } + // add sheme,host + $url = $url_base . $url; + } + if ($_url === $url) { + sleep(1); + } + fclose($fp); + $info = $this->validate_address($url); + if ($info === false) { + return false; + } + return $this->fsock_get_contents($url, $timeout, $redirect_max, $ua, $outfp, $info); + } + break; + case 200: + $ret = true; + } + if (!$ret) { + fclose($fp); + return false; + } + + $body = ''; + if (!$outfp) { + $outfp = fopen('php://temp', 'rwb'); + $body = true; + } + while (fwrite($outfp, fread($fp, $readsize))) { + if ($timeout) { + $_status = socket_get_status($fp); + if ($_status['timed_out']) { + fclose($outfp); + fclose($fp); + return false; // Request Time-out + } + } + } + if ($body) { + rewind($outfp); + $body = stream_get_contents($outfp); + fclose($outfp); + $outfp = null; + } + + fclose($fp); + + return $outfp ? $outfp : $body; // Data + } + + /** + * Parse Data URI scheme + * + * @param string $str + * @param array $extTable + * @param array $args + * + * @return array + * @author Naoki Sawada + */ + protected function parse_data_scheme($str, $extTable, $args = null) + { + $data = $name = $mime = ''; + // Scheme 'data://' require `allow_url_fopen` and `allow_url_include` + if ($fp = fopen('data://' . substr($str, 5), 'rb')) { + if ($data = stream_get_contents($fp)) { + $meta = stream_get_meta_data($fp); + $mime = $meta['mediatype']; + } + fclose($fp); + } else if (preg_match('~^data:(.+?/.+?)?(?:;charset=.+?)?;base64,~', substr($str, 0, 128), $m)) { + $data = base64_decode(substr($str, strlen($m[0]))); + if ($m[1]) { + $mime = $m[1]; + } + } + if ($data) { + $ext = ($mime && isset($extTable[$mime])) ? '.' . $extTable[$mime] : ''; + // Set name if name eq 'image.png' and $args has 'name' array, e.g. clipboard data + if (is_array($args['name']) && isset($args['name'][0])) { + $name = $args['name'][0]; + if ($ext) { + $name = preg_replace('/\.[^.]*$/', '', $name); + } + } else { + $name = substr(md5($data), 0, 8); + } + $name .= $ext; + } else { + $data = $name = ''; + } + return array($data, $name); + } + + /** + * Detect file MIME Type by local path + * + * @param string $path Local path + * + * @return string file MIME Type + * @author Naoki Sawada + */ + protected function detectMimeType($path) + { + static $type, $finfo; + if (!$type) { + if (class_exists('finfo', false)) { + $tmpFileInfo = explode(';', finfo_file(finfo_open(FILEINFO_MIME), __FILE__)); + } else { + $tmpFileInfo = false; + } + $regexp = '/text\/x\-(php|c\+\+)/'; + if ($tmpFileInfo && preg_match($regexp, array_shift($tmpFileInfo))) { + $type = 'finfo'; + $finfo = finfo_open(FILEINFO_MIME); + } elseif (function_exists('mime_content_type') + && ($_ctypes = explode(';', mime_content_type(__FILE__))) + && preg_match($regexp, array_shift($_ctypes))) { + $type = 'mime_content_type'; + } elseif (function_exists('getimagesize')) { + $type = 'getimagesize'; + } else { + $type = 'none'; + } + } + + $mime = ''; + if ($type === 'finfo') { + $mime = finfo_file($finfo, $path); + } elseif ($type === 'mime_content_type') { + $mime = mime_content_type($path); + } elseif ($type === 'getimagesize') { + if ($img = getimagesize($path)) { + $mime = $img['mime']; + } + } + + if ($mime) { + $mime = explode(';', $mime); + $mime = trim($mime[0]); + + if (in_array($mime, array('application/x-empty', 'inode/x-empty'))) { + // finfo return this mime for empty files + $mime = 'text/plain'; + } elseif ($mime == 'application/x-zip') { + // http://elrte.org/redmine/issues/163 + $mime = 'application/zip'; + } + } + + return $mime ? $mime : 'unknown'; + } + + /** + * Detect file type extension by local path + * + * @param object $volume elFinderVolumeDriver instance + * @param string $path Local path + * @param string $name Filename to save + * + * @return string file type extension with dot + * @author Naoki Sawada + */ + protected function detectFileExtension($volume, $path, $name) + { + $mime = $this->detectMimeType($path); + if ($mime === 'unknown') { + $mime = 'application/octet-stream'; + } + $ext = $volume->getExtentionByMime($volume->mimeTypeNormalize($mime, $name)); + return $ext ? ('.' . $ext) : ''; + } + + /** + * Get temporary directory path + * + * @param string $volumeTempPath + * + * @return string + * @author Naoki Sawada + */ + private function getTempDir($volumeTempPath = null) + { + $testDirs = array(); + if ($this->uploadTempPath) { + $testDirs[] = rtrim(realpath($this->uploadTempPath), DIRECTORY_SEPARATOR); + } + if ($volumeTempPath) { + $testDirs[] = rtrim(realpath($volumeTempPath), DIRECTORY_SEPARATOR); + } + if (elFinder::$commonTempPath) { + $testDirs[] = elFinder::$commonTempPath; + } + $tempDir = ''; + foreach ($testDirs as $testDir) { + if (!$testDir || !is_dir($testDir)) continue; + if (is_writable($testDir)) { + $tempDir = $testDir; + $gc = time() - 3600; + foreach (glob($tempDir . DIRECTORY_SEPARATOR . 'ELF*') as $cf) { + if (filemtime($cf) < $gc) { + unlink($cf); + } + } + break; + } + } + return $tempDir; + } + + /** + * chmod + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author David Bartle + */ + protected function chmod($args) + { + $targets = $args['targets']; + $mode = intval((string)$args['mode'], 8); + + if (!is_array($targets)) { + $targets = array($targets); + } + + $result = array(); + + if (($volume = $this->volume($targets[0])) == false) { + $result['error'] = $this->error(self::ERROR_CONF_NO_VOL); + return $result; + } + + $this->itemLock($targets); + + $files = array(); + $errors = array(); + foreach ($targets as $target) { + elFinder::checkAborted(); + + $file = $volume->chmod($target, $mode); + if ($file) { + $files = array_merge($files, is_array($file) ? $file : array($file)); + } else { + $errors = array_merge($errors, $volume->error()); + } + } + + if ($files) { + $result['changed'] = $files; + if ($errors) { + $result['warning'] = $this->error($errors); + } + } else { + $result['error'] = $this->error($errors); + } + + return $result; + } + + /** + * Check chunked upload files + * + * @param string $tmpname uploaded temporary file path + * @param string $chunk uploaded chunk file name + * @param string $cid uploaded chunked file id + * @param string $tempDir temporary dirctroy path + * @param null $volume + * + * @return array|null + * @throws elFinderAbortException + * @author Naoki Sawada + */ + private function checkChunkedFile($tmpname, $chunk, $cid, $tempDir, $volume = null) + { + /* @var elFinderVolumeDriver $volume */ + if (preg_match('/^(.+)(\.\d+_(\d+))\.part$/s', $chunk, $m)) { + $fname = $m[1]; + $encname = md5($cid . '_' . $fname); + $base = $tempDir . DIRECTORY_SEPARATOR . 'ELF' . $encname; + $clast = intval($m[3]); + if (is_null($tmpname)) { + ignore_user_abort(true); + // chunked file upload fail + foreach (glob($base . '*') as $cf) { + unlink($cf); + } + ignore_user_abort(false); + return null; + } + + $range = isset($_POST['range']) ? trim($_POST['range']) : ''; + if ($range && preg_match('/^(\d+),(\d+),(\d+)$/', $range, $ranges)) { + $start = $ranges[1]; + $len = $ranges[2]; + $size = $ranges[3]; + $tmp = $base . '.part'; + $csize = filesize($tmpname); + + $tmpExists = is_file($tmp); + if (!$tmpExists) { + // check upload max size + $uploadMaxSize = $volume ? $volume->getUploadMaxSize() : 0; + if ($uploadMaxSize > 0 && $size > $uploadMaxSize) { + return array(self::ERROR_UPLOAD_FILE_SIZE, false); + } + // make temp file + $ok = false; + if ($fp = fopen($tmp, 'wb')) { + flock($fp, LOCK_EX); + $ok = ftruncate($fp, $size); + flock($fp, LOCK_UN); + fclose($fp); + touch($base); + } + if (!$ok) { + unlink($tmp); + return array(self::ERROR_UPLOAD_TEMP, false); + } + } else { + // wait until makeing temp file (for anothor session) + $cnt = 1200; // Time limit 120 sec + while (!is_file($base) && --$cnt) { + usleep(100000); // wait 100ms + } + if (!$cnt) { + return array(self::ERROR_UPLOAD_TEMP, false); + } + } + + // check size info + if ($len != $csize || $start + $len > $size || ($tmpExists && $size != filesize($tmp))) { + return array(self::ERROR_UPLOAD_TEMP, false); + } + + // write chunk data + $src = fopen($tmpname, 'rb'); + $fp = fopen($tmp, 'cb'); + fseek($fp, $start); + $writelen = stream_copy_to_stream($src, $fp, $len); + fclose($fp); + fclose($src); + + try { + // to check connection is aborted + elFinder::checkAborted(); + } catch (elFinderAbortException $e) { + unlink($tmpname); + is_file($tmp) && unlink($tmp); + is_file($base) && unlink($base); + throw $e; + } + + if ($writelen != $len) { + return array(self::ERROR_UPLOAD_TEMP, false); + } + + // write counts + file_put_contents($base, "\0", FILE_APPEND | LOCK_EX); + + if (filesize($base) >= $clast + 1) { + // Completion + unlink($base); + return array($tmp, $fname); + } + } else { + // old way + $part = $base . $m[2]; + if (move_uploaded_file($tmpname, $part)) { + chmod($part, 0600); + if ($clast < count(glob($base . '*'))) { + $parts = array(); + for ($i = 0; $i <= $clast; $i++) { + $name = $base . '.' . $i . '_' . $clast; + if (is_readable($name)) { + $parts[] = $name; + } else { + $parts = null; + break; + } + } + if ($parts) { + if (!is_file($base)) { + touch($base); + if ($resfile = tempnam($tempDir, 'ELF')) { + $target = fopen($resfile, 'wb'); + foreach ($parts as $f) { + $fp = fopen($f, 'rb'); + while (!feof($fp)) { + fwrite($target, fread($fp, 8192)); + } + fclose($fp); + unlink($f); + } + fclose($target); + unlink($base); + return array($resfile, $fname); + } + unlink($base); + } + } + } + } + } + } + return array('', ''); + } + + /** + * Save uploaded files + * + * @param array + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function upload($args) + { + $ngReg = '/[\/\\?*:|"<>]/'; + $target = $args['target']; + $volume = $this->volume($target); + $files = isset($args['FILES']['upload']) && is_array($args['FILES']['upload']) ? $args['FILES']['upload'] : array(); + $header = empty($args['html']) ? array() : array('header' => 'Content-Type: text/html; charset=utf-8'); + $result = array_merge(array('added' => array()), $header); + $paths = $args['upload_path'] ? $args['upload_path'] : array(); + $chunk = $args['chunk'] ? $args['chunk'] : ''; + $cid = $args['cid'] ? (int)$args['cid'] : ''; + $mtimes = $args['mtime'] ? $args['mtime'] : array(); + $tmpfname = ''; + + if (!$volume) { + return array_merge(array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, '#' . $target)), $header); + } + + // check $chunk + if (strpos($chunk, '/') !== false || strpos($chunk, '\\') !== false) { + return array('error' => $this->error(self::ERROR_UPLOAD)); + } + + if ($args['overwrite'] !== '') { + $volume->setUploadOverwrite($args['overwrite']); + } + + $renames = $hashes = array(); + $suffix = '~'; + if ($args['renames'] && is_array($args['renames'])) { + $renames = array_flip($args['renames']); + if (is_string($args['suffix']) && !preg_match($ngReg, $args['suffix'])) { + $suffix = $args['suffix']; + } + } + if ($args['hashes'] && is_array($args['hashes'])) { + $hashes = array_flip($args['hashes']); + } + + $this->itemLock($target); + + // file extentions table by MIME + $extTable = array_flip(array_unique($volume->getMimeTable())); + + if (empty($files)) { + if (isset($args['upload']) && is_array($args['upload']) && ($tempDir = $this->getTempDir($volume->getTempPath()))) { + $names = array(); + foreach ($args['upload'] as $i => $url) { + // check chunked file upload commit + if ($chunk) { + if ($url === 'chunkfail' && $args['mimes'] === 'chunkfail') { + $this->checkChunkedFile(null, $chunk, $cid, $tempDir); + if (preg_match('/^(.+)(\.\d+_(\d+))\.part$/s', $chunk, $m)) { + $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $m[1], self::ERROR_UPLOAD_TEMP); + } + return $result; + } else { + $tmpfname = $tempDir . '/' . $chunk; + $files['tmp_name'][$i] = $tmpfname; + $files['name'][$i] = $url; + $files['error'][$i] = 0; + $GLOBALS['elFinderTempFiles'][$tmpfname] = true; + break; + } + } + + $tmpfname = $tempDir . DIRECTORY_SEPARATOR . 'ELF_FATCH_' . md5($url . microtime(true)); + $GLOBALS['elFinderTempFiles'][$tmpfname] = true; + + $_name = ''; + // check is data: + if (substr($url, 0, 5) === 'data:') { + list($data, $args['name'][$i]) = $this->parse_data_scheme($url, $extTable, $args); + } else { + $fp = fopen($tmpfname, 'wb'); + if ($data = $this->get_remote_contents($url, 30, 5, 'Mozilla/5.0', $fp)) { + // to check connection is aborted + try { + elFinder::checkAborted(); + } catch(elFinderAbortException $e) { + fclose($fp); + throw $e; + } + if (strpos($url, '%') !== false) { + $url = rawurldecode($url); + } + if (is_callable('mb_convert_encoding') && is_callable('mb_detect_encoding')) { + $url = mb_convert_encoding($url, 'UTF-8', mb_detect_encoding($url)); + } + $url = iconv('UTF-8', 'UTF-8//IGNORE', $url); + $_name = preg_replace('~^.*?([^/#?]+)(?:\?.*)?(?:#.*)?$~', '$1', $url); + // Check `Content-Disposition` response header + if (($headers = get_headers($url, true)) && !empty($headers['Content-Disposition'])) { + if (preg_match('/filename\*=(?:([a-zA-Z0-9_-]+?)\'\')"?([a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) { + $_name = rawurldecode($m[2]); + if ($m[1] && strtoupper($m[1]) !== 'UTF-8' && function_exists('mb_convert_encoding')) { + $_name = mb_convert_encoding($_name, 'UTF-8', $m[1]); + } + } else if (preg_match('/filename="?([ a-z0-9_.~%-]+)"?/i', $headers['Content-Disposition'], $m)) { + $_name = rawurldecode($m[1]); + } + } + } else { + fclose($fp); + } + } + if ($data) { + if (isset($args['name'][$i])) { + $_name = $args['name'][$i]; + } + if ($_name) { + $_ext = ''; + if (preg_match('/(\.[a-z0-9]{1,7})$/', $_name, $_match)) { + $_ext = $_match[1]; + } + if ((is_resource($data) && fclose($data)) || file_put_contents($tmpfname, $data)) { + $GLOBALS['elFinderTempFiles'][$tmpfname] = true; + $_name = preg_replace($ngReg, '_', $_name); + list($_a, $_b) = array_pad(explode('.', $_name, 2), 2, ''); + if ($_b === '') { + if ($_ext) { + rename($tmpfname, $tmpfname . $_ext); + $tmpfname = $tmpfname . $_ext; + } + $_b = $this->detectFileExtension($volume, $tmpfname, $_name); + $_name = $_a . $_b; + } else { + $_b = '.' . $_b; + } + if (isset($names[$_name])) { + $_name = $_a . '_' . $names[$_name]++ . $_b; + } else { + $names[$_name] = 1; + } + $files['tmp_name'][$i] = $tmpfname; + $files['name'][$i] = $_name; + $files['error'][$i] = 0; + // set to auto rename + $volume->setUploadOverwrite(false); + } else { + unlink($tmpfname); + } + } + } + } + } + if (empty($files)) { + return array_merge(array('error' => $this->error(self::ERROR_UPLOAD, self::ERROR_UPLOAD_NO_FILES)), $header); + } + } + + $addedDirs = array(); + $errors = array(); + foreach ($files['name'] as $i => $name) { + if (($error = $files['error'][$i]) > 0) { + $result['warning'] = $this->error(self::ERROR_UPLOAD_FILE, $name, $error == UPLOAD_ERR_INI_SIZE || $error == UPLOAD_ERR_FORM_SIZE ? self::ERROR_UPLOAD_FILE_SIZE : self::ERROR_UPLOAD_TRANSFER, $error); + $this->uploadDebug = 'Upload error code: ' . $error; + break; + } + + $tmpname = $files['tmp_name'][$i]; + $thash = ($paths && isset($paths[$i])) ? $paths[$i] : $target; + $mtime = isset($mtimes[$i]) ? $mtimes[$i] : 0; + if ($name === 'blob') { + if ($chunk) { + if ($tempDir = $this->getTempDir($volume->getTempPath())) { + list($tmpname, $name) = $this->checkChunkedFile($tmpname, $chunk, $cid, $tempDir, $volume); + if ($tmpname) { + if ($name === false) { + preg_match('/^(.+)(\.\d+_(\d+))\.part$/s', $chunk, $m); + $result['error'] = $this->error(self::ERROR_UPLOAD_FILE, $m[1], $tmpname); + $result['_chunkfailure'] = true; + $this->uploadDebug = 'Upload error: ' . $tmpname; + } else if ($name) { + $result['_chunkmerged'] = basename($tmpname); + $result['_name'] = $name; + $result['_mtime'] = $mtime; + } + } + } else { + $result['error'] = $this->error(self::ERROR_UPLOAD_FILE, $chunk, self::ERROR_UPLOAD_TEMP); + $this->uploadDebug = 'Upload error: unable open tmp file'; + } + return $result; + } else { + // for form clipboard with Google Chrome or Opera + $name = 'image.png'; + } + } + + // Set name if name eq 'image.png' and $args has 'name' array, e.g. clipboard data + if (strtolower(substr($name, 0, 5)) === 'image' && is_array($args['name']) && isset($args['name'][$i])) { + $type = $files['type'][$i]; + $name = $args['name'][$i]; + $ext = isset($extTable[$type]) ? '.' . $extTable[$type] : ''; + if ($ext) { + $name = preg_replace('/\.[^.]*$/', '', $name); + } + $name .= $ext; + } + + // do hook function 'upload.presave' + try { + $this->trigger('upload.presave', array(&$thash, &$name, $tmpname, $this, $volume), $errors); + } catch (elFinderTriggerException $e) { + if (!is_uploaded_file($tmpname) && unlink($tmpname) && $tmpfname) { + unset($GLOBALS['elFinderTempFiles'][$tmpfname]); + } + continue; + } + + clearstatcache(); + if ($mtime && is_file($tmpname)) { + // for keep timestamp option in the LocalFileSystem volume + touch($tmpname, $mtime); + } + + $fp = null; + if (!is_file($tmpname) || ($fp = fopen($tmpname, 'rb')) === false) { + $errors = array_merge($errors, array(self::ERROR_UPLOAD_FILE, $name, ($fp === false? self::ERROR_UPLOAD_TEMP : self::ERROR_UPLOAD_TRANSFER))); + $this->uploadDebug = 'Upload error: unable open tmp file'; + if (!is_uploaded_file($tmpname)) { + if (unlink($tmpname) && $tmpfname) unset($GLOBALS['elFinderTempFiles'][$tmpfname]); + continue; + } + break; + } + $rnres = array(); + if ($thash !== '' && $thash !== $target) { + if ($dir = $volume->dir($thash)) { + $_target = $thash; + if (!isset($addedDirs[$thash])) { + $addedDirs[$thash] = true; + $result['added'][] = $dir; + // to support multi-level directory creation + $_phash = isset($dir['phash']) ? $dir['phash'] : null; + while ($_phash && !isset($addedDirs[$_phash]) && $_phash !== $target) { + if ($_dir = $volume->dir($_phash)) { + $addedDirs[$_phash] = true; + $result['added'][] = $_dir; + $_phash = isset($_dir['phash']) ? $_dir['phash'] : null; + } else { + break; + } + } + } + } else { + $result['error'] = $this->error(self::ERROR_UPLOAD, self::ERROR_TRGDIR_NOT_FOUND, 'hash@' . $thash); + break; + } + } else { + $_target = $target; + // file rename for backup + if (isset($renames[$name])) { + $dir = $volume->realpath($_target); + if (isset($hashes[$name])) { + $hash = $hashes[$name]; + } else { + $hash = $volume->getHash($dir, $name); + } + $rnres = $this->rename(array('target' => $hash, 'name' => $volume->uniqueName($dir, $name, $suffix, true, 0))); + if (!empty($rnres['error'])) { + $result['warning'] = $rnres['error']; + if (!is_array($rnres['error'])) { + $errors = array_push($errors, $rnres['error']); + } else { + $errors = array_merge($errors, $rnres['error']); + } + continue; + } + } + } + if (!$_target || ($file = $volume->upload($fp, $_target, $name, $tmpname, ($_target === $target) ? $hashes : array())) === false) { + $errors = array_merge($errors, $this->error(self::ERROR_UPLOAD_FILE, $name, $volume->error())); + fclose($fp); + if (!is_uploaded_file($tmpname) && unlink($tmpname)) { + unset($GLOBALS['elFinderTempFiles'][$tmpname]); + } + continue; + } + + is_resource($fp) && fclose($fp); + if (!is_uploaded_file($tmpname)) { + clearstatcache(); + if (!is_file($tmpname) || unlink($tmpname)) { + unset($GLOBALS['elFinderTempFiles'][$tmpname]); + } + } + $result['added'][] = $file; + if ($rnres) { + $result = array_merge_recursive($result, $rnres); + } + } + + if ($errors) { + $result['warning'] = $errors; + } + + if ($GLOBALS['elFinderTempFiles']) { + foreach (array_keys($GLOBALS['elFinderTempFiles']) as $_temp) { + is_file($_temp) && is_writable($_temp) && unlink($_temp); + } + } + $result['removed'] = $volume->removed(); + + if (!empty($args['node'])) { + $result['callback'] = array( + 'node' => $args['node'], + 'bind' => 'upload' + ); + } + return $result; + } + + /** + * Copy/move files into new destination + * + * @param array command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function paste($args) + { + $dst = $args['dst']; + $targets = is_array($args['targets']) ? $args['targets'] : array(); + $cut = !empty($args['cut']); + $error = $cut ? self::ERROR_MOVE : self::ERROR_COPY; + $result = array('changed' => array(), 'added' => array(), 'removed' => array(), 'warning' => array()); + + if (($dstVolume = $this->volume($dst)) == false) { + return array('error' => $this->error($error, '#' . $targets[0], self::ERROR_TRGDIR_NOT_FOUND, '#' . $dst)); + } + + $this->itemLock($dst); + + $hashes = $renames = array(); + $suffix = '~'; + if (!empty($args['renames'])) { + $renames = array_flip($args['renames']); + if (is_string($args['suffix']) && !preg_match('/[\/\\?*:|"<>]/', $args['suffix'])) { + $suffix = $args['suffix']; + } + } + if (!empty($args['hashes'])) { + $hashes = array_flip($args['hashes']); + } + + foreach ($targets as $target) { + elFinder::checkAborted(); + + if (($srcVolume = $this->volume($target)) == false) { + $result['warning'] = array_merge($result['warning'], $this->error($error, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + continue; + } + + $rnres = array(); + if ($renames) { + $file = $srcVolume->file($target); + if (isset($renames[$file['name']])) { + $dir = $dstVolume->realpath($dst); + $dstName = $file['name']; + if ($srcVolume !== $dstVolume) { + $errors = array(); + try { + $this->trigger('paste.copyfrom', array(&$dst, &$dstName, '', $this, $dstVolume), $errors); + } catch (elFinderTriggerException $e) { + $result['warning'] = array_merge($result['warning'], $errors); + continue; + } + } + if (isset($hashes[$file['name']])) { + $hash = $hashes[$file['name']]; + } else { + $hash = $dstVolume->getHash($dir, $dstName); + } + $rnres = $this->rename(array('target' => $hash, 'name' => $dstVolume->uniqueName($dir, $dstName, $suffix, true, 0))); + if (!empty($rnres['error'])) { + $result['warning'] = array_merge($result['warning'], $rnres['error']); + continue; + } + } + } + + if ($cut && $this->itemLocked($target)) { + $rm = $srcVolume->file($target); + $result['warning'] = array_merge($result['warning'], $this->error(self::ERROR_LOCKED, $rm['name'])); + continue; + } + + if (($file = $dstVolume->paste($srcVolume, $target, $dst, $cut, $hashes)) == false) { + $result['warning'] = array_merge($result['warning'], $this->error($dstVolume->error())); + continue; + } + + if ($error = $dstVolume->error()) { + $result['warning'] = array_merge($result['warning'], $this->error($error)); + } + + if ($rnres) { + $result = array_merge_recursive($result, $rnres); + } + } + if (count($result['warning']) < 1) { + unset($result['warning']); + } else { + $result['sync'] = true; + } + + return $result; + } + + /** + * Return file content + * + * @param array $args command arguments + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function get($args) + { + $target = $args['target']; + $volume = $this->volume($target); + $enc = false; + + if (!$volume || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_OPEN, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + } + + if ($volume->commandDisabled('get')) { + return array('error' => $this->error(self::ERROR_OPEN, '#' . $target, self::ERROR_ACCESS_DENIED)); + } + + if (($content = $volume->getContents($target)) === false) { + return array('error' => $this->error(self::ERROR_OPEN, $volume->path($target), $volume->error())); + } + + $mime = isset($file['mime']) ? $file['mime'] : ''; + if ($mime && (strtolower(substr($mime, 0, 4)) === 'text' || in_array(strtolower($mime), self::$textMimes))) { + $enc = ''; + if ($content !== '') { + if (!$args['conv'] || $args['conv'] == '1') { + // detect encoding + if (function_exists('mb_detect_encoding')) { + if ($enc = mb_detect_encoding($content, mb_detect_order(), true)) { + $encu = strtoupper($enc); + if ($encu === 'UTF-8' || $encu === 'ASCII') { + $enc = ''; + } + } else { + $enc = 'unknown'; + } + } else if (!preg_match('//u', $content)) { + $enc = 'unknown'; + } + if ($enc === 'unknown') { + $enc = $volume->getOption('encoding'); + if (!$enc || strtoupper($enc) === 'UTF-8') { + $enc = 'unknown'; + } + } + // call callbacks 'get.detectencoding' + if (!empty($this->listeners['get.detectencoding'])) { + foreach ($this->listeners['get.detectencoding'] as $handler) { + call_user_func_array($handler, array('get', &$enc, array_merge($args, array('content' => $content)), $this, $volume)); + } + } + if ($enc && $enc !== 'unknown') { + $errlev = error_reporting(); + error_reporting($errlev ^ E_NOTICE); + $utf8 = iconv($enc, 'UTF-8', $content); + if ($utf8 === false && function_exists('mb_convert_encoding')) { + error_reporting($errlev ^ E_WARNING); + $utf8 = mb_convert_encoding($content, 'UTF-8', $enc); + if (mb_convert_encoding($utf8, $enc, 'UTF-8') !== $content) { + $enc = 'unknown'; + } + } else { + if ($utf8 === false || iconv('UTF-8', $enc, $utf8) !== $content) { + $enc = 'unknown'; + } + } + error_reporting($errlev); + if ($enc !== 'unknown') { + $content = $utf8; + } + } + if ($enc) { + if ($args['conv'] == '1') { + $args['conv'] = ''; + if ($enc === 'unknown') { + $content = false; + } + } else if ($enc === 'unknown') { + return array('doconv' => $enc); + } + } + if ($args['conv'] == '1') { + $args['conv'] = ''; + } + } + if ($args['conv']) { + $enc = $args['conv']; + if (strtoupper($enc) !== 'UTF-8') { + $_content = $content; + $errlev = error_reporting(); + $this->setToastErrorHandler(array( + 'prefix' => 'Notice: ' + )); + error_reporting($errlev | E_NOTICE | E_WARNING); + $content = iconv($enc, 'UTF-8//TRANSLIT', $content); + if ($content === false && function_exists('mb_convert_encoding')) { + $content = mb_convert_encoding($_content, 'UTF-8', $enc); + } + error_reporting($errlev); + $this->setToastErrorHandler(false); + } else { + $enc = ''; + } + } + } + } else { + $content = 'data:' . ($mime ? $mime : 'application/octet-stream') . ';base64,' . base64_encode($content); + } + + if ($enc !== false) { + $json = false; + if ($content !== false) { + $json = json_encode($content); + } + if ($content === false || $json === false || strlen($json) < strlen($content)) { + return array('doconv' => 'unknown'); + } + } + + $res = array( + 'header' => array( + 'Content-Type: application/json' + ), + 'content' => $content + ); + + // add cache control headers + if ($cacheHeaders = $volume->getOption('cacheHeaders')) { + $res['header'] = array_merge($res['header'], $cacheHeaders); + } + + if ($enc) { + $res['encoding'] = $enc; + } + return $res; + } + + /** + * Save content into text file + * + * @param $args + * + * @return array + * @author Dmitry (dio) Levashov + */ + protected function put($args) + { + $target = $args['target']; + $encoding = isset($args['encoding']) ? $args['encoding'] : ''; + + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_SAVE, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + } + + $this->itemLock($target); + + if ($encoding === 'scheme') { + if (preg_match('~^https?://~i', $args['content'])) { + /** @var resource $fp */ + $fp = $this->get_remote_contents($args['content'], 30, 5, 'Mozilla/5.0', $volume->tmpfile()); + if (!$fp) { + return array('error' => self::ERROR_SAVE, $args['content'], self::ERROR_FILE_NOT_FOUND); + } + $fmeta = stream_get_meta_data($fp); + $mime = $this->detectMimeType($fmeta['uri']); + if ($mime === 'unknown') { + $mime = 'application/octet-stream'; + } + $mime = $volume->mimeTypeNormalize($mime, $file['name']); + $args['content'] = 'data:' . $mime . ';base64,' . base64_encode(file_get_contents($fmeta['uri'])); + } + $encoding = ''; + $args['content'] = "\0" . $args['content']; + } else if ($encoding === 'hash') { + $_hash = $args['content']; + if ($_src = $this->getVolume($_hash)) { + if ($_file = $_src->file($_hash)) { + if ($_data = $_src->getContents($_hash)) { + $args['content'] = 'data:' . $file['mime'] . ';base64,' . base64_encode($_data); + } + } + } + $encoding = ''; + $args['content'] = "\0" . $args['content']; + } + if ($encoding) { + $content = iconv('UTF-8', $encoding, $args['content']); + if ($content === false && function_exists('mb_detect_encoding')) { + $content = mb_convert_encoding($args['content'], $encoding, 'UTF-8'); + } + if ($content !== false) { + $args['content'] = $content; + } + } + if (($file = $volume->putContents($target, $args['content'])) == false) { + return array('error' => $this->error(self::ERROR_SAVE, $volume->path($target), $volume->error())); + } + + return array('changed' => array($file)); + } + + /** + * Extract files from archive + * + * @param array $args command arguments + * + * @return array + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function extract($args) + { + $target = $args['target']; + $makedir = isset($args['makedir']) ? (bool)$args['makedir'] : null; + + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_EXTRACT, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + } + + $res = array(); + if ($file = $volume->extract($target, $makedir)) { + $res['added'] = isset($file['read']) ? array($file) : $file; + if ($err = $volume->error()) { + $res['warning'] = $err; + } + } else { + $res['error'] = $this->error(self::ERROR_EXTRACT, $volume->path($target), $volume->error()); + } + return $res; + } + + /** + * Create archive + * + * @param array $args command arguments + * + * @return array + * @throws Exception + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function archive($args) + { + $targets = isset($args['targets']) && is_array($args['targets']) ? $args['targets'] : array(); + $name = isset($args['name']) ? $args['name'] : ''; + + $targets = array_filter($targets, array($this, 'volume')); + if (!$targets || ($volume = $this->volume($targets[0])) === false) { + return $this->error(self::ERROR_ARCHIVE, self::ERROR_TRGDIR_NOT_FOUND); + } + + foreach ($targets as $target) { + $this->itemLock($target); + } + + return ($file = $volume->archive($targets, $args['type'], $name)) + ? array('added' => array($file)) + : array('error' => $this->error(self::ERROR_ARCHIVE, $volume->error())); + } + + /** + * Search files + * + * @param array $args command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry Levashov + */ + protected function search($args) + { + $q = trim($args['q']); + $mimes = !empty($args['mimes']) && is_array($args['mimes']) ? $args['mimes'] : array(); + $target = !empty($args['target']) ? $args['target'] : null; + $type = !empty($args['type']) ? $args['type'] : null; + $result = array(); + $errors = array(); + + if ($target) { + if ($volume = $this->volume($target)) { + $result = $volume->search($q, $mimes, $target, $type); + $errors = array_merge($errors, $volume->error()); + } + } else { + foreach ($this->volumes as $volume) { + $result = array_merge($result, $volume->search($q, $mimes, null, $type)); + $errors = array_merge($errors, $volume->error()); + } + } + + $result = array('files' => $result); + if ($errors) { + $result['warning'] = $errors; + } + return $result; + } + + /** + * Return file info (used by client "places" ui) + * + * @param array $args command arguments + * + * @return array + * @throws elFinderAbortException + * @author Dmitry Levashov + */ + protected function info($args) + { + $files = array(); + $compare = null; + // long polling mode + if ($args['compare'] && count($args['targets']) === 1) { + $compare = intval($args['compare']); + $hash = $args['targets'][0]; + if ($volume = $this->volume($hash)) { + $standby = (int)$volume->getOption('plStandby'); + $_compare = false; + if (($syncCheckFunc = $volume->getOption('syncCheckFunc')) && is_callable($syncCheckFunc)) { + $_compare = call_user_func_array($syncCheckFunc, array($volume->realpath($hash), $standby, $compare, $volume, $this)); + } + if ($_compare !== false) { + $compare = $_compare; + } else { + $sleep = max(1, (int)$volume->getOption('tsPlSleep')); + $limit = max(1, $standby / $sleep) + 1; + do { + elFinder::extendTimeLimit(30 + $sleep); + $volume->clearstatcache(); + if (($info = $volume->file($hash)) != false) { + if ($info['ts'] != $compare) { + $compare = $info['ts']; + break; + } + } else { + $compare = 0; + break; + } + if (--$limit) { + sleep($sleep); + } + } while ($limit); + } + } + } else { + foreach ($args['targets'] as $hash) { + elFinder::checkAborted(); + if (($volume = $this->volume($hash)) != false + && ($info = $volume->file($hash)) != false) { + $info['path'] = $volume->path($hash); + $files[] = $info; + } + } + } + + $result = array('files' => $files); + if (!is_null($compare)) { + $result['compare'] = strval($compare); + } + return $result; + } + + /** + * Return image dimensions + * + * @param array $args command arguments + * + * @return array + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function dim($args) + { + $res = array(); + $target = $args['target']; + + if (($volume = $this->volume($target)) != false) { + if ($dim = $volume->dimensions($target, $args)) { + if (is_array($dim) && isset($dim['dim'])) { + $res = $dim; + } else { + $res = array('dim' => $dim); + if ($subImgLink = $volume->getSubstituteImgLink($target, explode('x', $dim))) { + $res['url'] = $subImgLink; + } + } + } + } + + return $res; + } + + /** + * Resize image + * + * @param array command arguments + * + * @return array + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + protected function resize($args) + { + $target = $args['target']; + $width = (int)$args['width']; + $height = (int)$args['height']; + $x = (int)$args['x']; + $y = (int)$args['y']; + $mode = $args['mode']; + $bg = $args['bg']; + $degree = (int)$args['degree']; + $quality = (int)$args['quality']; + + if (($volume = $this->volume($target)) == false + || ($file = $volume->file($target)) == false) { + return array('error' => $this->error(self::ERROR_RESIZE, '#' . $target, self::ERROR_FILE_NOT_FOUND)); + } + + if ($mode !== 'rotate' && ($width < 1 || $height < 1)) { + return array('error' => $this->error(self::ERROR_RESIZESIZE)); + } + return ($file = $volume->resize($target, $width, $height, $x, $y, $mode, $bg, $degree, $quality)) + ? (!empty($file['losslessRotate']) ? $file : array('changed' => array($file))) + : array('error' => $this->error(self::ERROR_RESIZE, $volume->path($target), $volume->error())); + } + + /** + * Return content URL + * + * @param array $args command arguments + * + * @return array + * @author Naoki Sawada + **/ + protected function url($args) + { + $target = $args['target']; + $options = isset($args['options']) ? $args['options'] : array(); + if (($volume = $this->volume($target)) != false) { + if (!$volume->commandDisabled('url')) { + $url = $volume->getContentUrl($target, $options); + return $url ? array('url' => $url) : array(); + } + } + return array(); + } + + /** + * Output callback result with JavaScript that control elFinder + * or HTTP redirect to callbackWindowURL + * + * @param array command arguments + * + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function callback($args) + { + $checkReg = '/[^a-zA-Z0-9;._-]/'; + $node = (isset($args['node']) && !preg_match($checkReg, $args['node'])) ? $args['node'] : ''; + $json = (isset($args['json']) && json_decode($args['json'])) ? $args['json'] : '{}'; + $bind = (isset($args['bind']) && !preg_match($checkReg, $args['bind'])) ? $args['bind'] : ''; + $done = (!empty($args['done'])); + + while (ob_get_level()) { + if (!ob_end_clean()) { + break; + } + } + + if ($done || !$this->callbackWindowURL) { + $script = ''; + if ($node) { + if ($bind) { + $trigger = 'elf.trigger(\'' . $bind . '\', data);'; + $triggerdone = 'elf.trigger(\'' . $bind . 'done\');'; + $triggerfail = 'elf.trigger(\'' . $bind . 'fail\', data);'; + } else { + $trigger = $triggerdone = $triggerfail = ''; + } + $origin = isset($_SERVER['HTTP_ORIGIN'])? str_replace('\'', '\\\'', $_SERVER['HTTP_ORIGIN']) : '*'; + $script .= ' +var go = function() { + var w = window.opener || window.parent || window, + close = function(){ + window.open("about:blank","_self").close(); + return false; + }; + try { + var elf = w.document.getElementById(\'' . $node . '\').elfinder; + if (elf) { + var data = ' . $json . '; + if (data.error) { + ' . $triggerfail . ' + elf.error(data.error); + } else { + data.warning && elf.error(data.warning); + data.removed && data.removed.length && elf.remove(data); + data.added && data.added.length && elf.add(data); + data.changed && data.changed.length && elf.change(data); + ' . $trigger . ' + ' . $triggerdone . ' + data.sync && elf.sync(); + } + } + } catch(e) { + // for CORS + w.postMessage && w.postMessage(JSON.stringify({type:\'io.studio-42.github\',bind:\'' . $bind . '\',data:' . $json . '}), \'' . $origin . '\'); + } + close(); + setTimeout(function() { + var msg = document.getElementById(\'msg\'); + msg.style.display = \'inline\'; + msg.onclick = close; + }, 100); +}; +'; + } + + $out = ''; + + header('Content-Type: text/html; charset=utf-8'); + header('Content-Length: ' . strlen($out)); + header('Cache-Control: private'); + header('Pragma: no-cache'); + + echo $out; + + } else { + $url = $this->callbackWindowURL; + $url .= ((strpos($url, '?') === false) ? '?' : '&') + . '&node=' . rawurlencode($node) + . (($json !== '{}') ? ('&json=' . rawurlencode($json)) : '') + . ($bind ? ('&bind=' . rawurlencode($bind)) : '') + . '&done=1'; + + header('Location: ' . $url); + + } + throw new elFinderAbortException(); + } + + /** + * Error handler for send toast message to client side + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * + * @return boolean + */ + protected function toastErrorHandler($errno, $errstr, $errfile, $errline) + { + $proc = false; + if (!(error_reporting() & $errno)) { + return $proc; + } + $toast = array(); + $toast['mode'] = $this->toastParams['mode']; + $toast['msg'] = $this->toastParams['prefix'] . $errstr; + $this->toastMessages[] = $toast; + return true; + } + + /** + * PHP error handler, catch error types only E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * + * @return boolean + */ + public static function phpErrorHandler($errno, $errstr, $errfile, $errline) + { + static $base = null; + + $proc = false; + + if (is_null($base)) { + $base = dirname(__FILE__) . DIRECTORY_SEPARATOR; + } + + if (!(error_reporting() & $errno)) { + return $proc; + } + + // Do not report real path + if (strpos($errfile, $base) === 0) { + $errfile = str_replace($base, '', $errfile); + } else if ($pos = strrpos($errfile, '/vendor/')) { + $errfile = substr($errfile, $pos + 1); + } else { + $errfile = basename($errfile); + } + + switch ($errno) { + case E_WARNING: + case E_USER_WARNING: + elFinder::$phpErrors[] = "WARNING: $errstr in $errfile line $errline."; + $proc = true; + break; + + case E_NOTICE: + case E_USER_NOTICE: + elFinder::$phpErrors[] = "NOTICE: $errstr in $errfile line $errline."; + $proc = true; + break; + + case E_RECOVERABLE_ERROR: + elFinder::$phpErrors[] = "RECOVERABLE_ERROR: $errstr in $errfile line $errline."; + $proc = true; + break; + } + + // E_STRICT is deprecated; see https://wiki.php.net/rfc/deprecations_php_8_4#remove_e_strict_error_level_and_deprecate_e_strict_constant + if (defined('E_STRICT') && $errno === @E_STRICT) { + elFinder::$phpErrors[] = "STRICT: $errstr in $errfile line $errline."; + $proc = true; + } + + if (defined('E_DEPRECATED')) { + switch ($errno) { + case E_DEPRECATED: + case E_USER_DEPRECATED: + elFinder::$phpErrors[] = "DEPRECATED: $errstr in $errfile line $errline."; + $proc = true; + break; + } + } + + return $proc; + } + + /***************************************************************************/ + /* utils */ + /***************************************************************************/ + + /** + * Return root - file's owner + * + * @param string file hash + * + * @return elFinderVolumeDriver|boolean (false) + * @author Dmitry (dio) Levashov + **/ + protected function volume($hash) + { + foreach ($this->volumes as $id => $v) { + if (strpos('' . $hash, $id) === 0) { + return $this->volumes[$id]; + } + } + return false; + } + + /** + * Return files info array + * + * @param array $data one file info or files info + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function toArray($data) + { + return isset($data['hash']) || !is_array($data) ? array($data) : $data; + } + + /** + * Return fils hashes list + * + * @param array $files files info + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function hashes($files) + { + $ret = array(); + foreach ($files as $file) { + $ret[] = $file['hash']; + } + return $ret; + } + + /** + * Remove from files list hidden files and files with required mime types + * + * @param array $files files info + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function filter($files) + { + $exists = array(); + foreach ($files as $i => $file) { + if (isset($file['hash'])) { + if (isset($exists[$file['hash']]) || !empty($file['hidden']) || !$this->default->mimeAccepted($file['mime'])) { + unset($files[$i]); + } + $exists[$file['hash']] = true; + } + } + return array_values($files); + } + + protected function utime() + { + $time = explode(" ", microtime()); + return (double)$time[1] + (double)$time[0]; + } + + /** + * Return Network mount volume unique ID + * + * @param array $netVolumes Saved netvolumes array + * @param string $prefix Id prefix + * + * @return string|false + * @author Naoki Sawada + **/ + protected function getNetVolumeUniqueId($netVolumes = null, $prefix = 'nm') + { + if (is_null($netVolumes)) { + $netVolumes = $this->getNetVolumes(); + } + $ids = array(); + foreach ($netVolumes as $vOps) { + if (isset($vOps['id']) && strpos($vOps['id'], $prefix) === 0) { + $ids[$vOps['id']] = true; + } + } + if (!$ids) { + $id = $prefix . '1'; + } else { + $i = 0; + while (isset($ids[$prefix . ++$i]) && $i < 10000) ; + $id = $prefix . $i; + if (isset($ids[$id])) { + $id = false; + } + } + return $id; + } + + /** + * Is item locked? + * + * @param string $hash + * + * @return boolean + */ + protected function itemLocked($hash) + { + if (!elFinder::$commonTempPath) { + return false; + } + $lock = elFinder::$commonTempPath . DIRECTORY_SEPARATOR . self::filenameDecontaminate($hash) . '.lock'; + if (file_exists($lock)) { + if (filemtime($lock) + $this->itemLockExpire < time()) { + unlink($lock); + return false; + } + return true; + } + + return false; + } + + /** + * Do lock target item + * + * @param array|string $hashes + * @param boolean $autoUnlock + * + * @return void + */ + protected function itemLock($hashes, $autoUnlock = true) + { + if (!elFinder::$commonTempPath) { + return; + } + if (!is_array($hashes)) { + $hashes = array($hashes); + } + foreach ($hashes as $hash) { + $lock = elFinder::$commonTempPath . DIRECTORY_SEPARATOR . self::filenameDecontaminate($hash) . '.lock'; + if ($this->itemLocked($hash)) { + $cnt = file_get_contents($lock) + 1; + } else { + $cnt = 1; + } + if (file_put_contents($lock, $cnt, LOCK_EX)) { + if ($autoUnlock) { + $this->autoUnlocks[] = $hash; + } + } + } + } + + /** + * Do unlock target item + * + * @param string $hash + * + * @return boolean + */ + protected function itemUnlock($hash) + { + if (!$this->itemLocked($hash)) { + return true; + } + $lock = elFinder::$commonTempPath . DIRECTORY_SEPARATOR . $hash . '.lock'; + $cnt = file_get_contents($lock); + if (--$cnt < 1) { + unlink($lock); + return true; + } else { + file_put_contents($lock, $cnt, LOCK_EX); + return false; + } + } + + /** + * unlock locked items on command completion + * + * @return void + */ + public function itemAutoUnlock() + { + if ($this->autoUnlocks) { + foreach ($this->autoUnlocks as $hash) { + $this->itemUnlock($hash); + } + $this->autoUnlocks = array(); + } + } + + /** + * Ensure directories recursively + * + * @param object $volume Volume object + * @param string $target Target hash + * @param array $dirs Array of directory tree to ensure + * @param string $path Relative path form target hash + * + * @return array|false array('stats' => array([stat of maked directory]), 'hashes' => array('[path]' => '[hash]'), 'makes' => array([New directory hashes]), 'error' => array([Error name])) + * @author Naoki Sawada + **/ + protected function ensureDirsRecursively($volume, $target, $dirs, $path = '') + { + $res = array('stats' => array(), 'hashes' => array(), 'makes' => array(), 'error' => array()); + foreach ($dirs as $name => $sub) { + $name = (string)$name; + $dir = $newDir = null; + if ((($parent = $volume->realpath($target)) && ($dir = $volume->dir($volume->getHash($parent, $name)))) || ($newDir = $volume->mkdir($target, $name))) { + $_path = $path . '/' . $name; + if ($newDir) { + $res['makes'][] = $newDir['hash']; + $dir = $newDir; + } + $res['stats'][] = $dir; + $res['hashes'][$_path] = $dir['hash']; + if (count($sub)) { + $res = array_merge_recursive($res, $this->ensureDirsRecursively($volume, $dir['hash'], $sub, $_path)); + } + } else { + $res['error'][] = $name; + } + } + return $res; + } + + /** + * Sets the toast error handler. + * + * @param array $opts The options + */ + public function setToastErrorHandler($opts) + { + $this->toastParams = $this->toastParamsDefault; + if (!$opts) { + restore_error_handler(); + } else { + $this->toastParams = array_merge($this->toastParams, $opts); + set_error_handler(array($this, 'toastErrorHandler')); + } + } + + /** + * String encode convert to UTF-8 + * + * @param string $str Input string + * + * @return string UTF-8 string + */ + public function utf8Encode($str) + { + static $mbencode = null; + $str = (string) $str; + if (@iconv('utf-8', 'utf-8//IGNORE', $str) === $str) { + return $str; + } + + if ($this->utf8Encoder) { + return $this->utf8Encoder($str); + } + + if ($mbencode === null) { + $mbencode = function_exists('mb_convert_encoding') && function_exists('mb_detect_encoding'); + } + + if ($mbencode) { + if ($enc = mb_detect_encoding($str, mb_detect_order(), true)) { + $_str = mb_convert_encoding($str, 'UTF-8', $enc); + if (@iconv('utf-8', 'utf-8//IGNORE', $_str) === $_str) { + return $_str; + } + } + } + return utf8_encode($str); + } + + /***************************************************************************/ + /* static utils */ + /***************************************************************************/ + + /** + * Return full version of API that this connector supports all functions + * + * @return string + */ + public static function getApiFullVersion() + { + return (string)self::$ApiVersion . '.' . (string)self::$ApiRevision; + } + + /** + * Return self::$commonTempPath + * + * @return string The common temporary path. + */ + public static function getCommonTempPath() + { + return self::$commonTempPath; + } + + /** + * Return Is Animation Gif + * + * @param string $path server local path of target image + * + * @return bool + */ + public static function isAnimationGif($path) + { + list(, , $type) = getimagesize($path); + switch ($type) { + case IMAGETYPE_GIF: + break; + default: + return false; + } + + $imgcnt = 0; + $fp = fopen($path, 'rb'); + fread($fp, 4); + $c = fread($fp, 1); + if (ord($c) != 0x39) { // GIF89a + return false; + } + + while (!feof($fp)) { + do { + $c = fread($fp, 1); + } while (ord($c) != 0x21 && !feof($fp)); + + if (feof($fp)) { + break; + } + + $c2 = fread($fp, 2); + if (bin2hex($c2) == "f904") { + $imgcnt++; + if ($imgcnt === 2) { + break; + } + } + + if (feof($fp)) { + break; + } + } + + if ($imgcnt > 1) { + return true; + } else { + return false; + } + } + + /** + * Return Is Animation Png + * + * @param string $path server local path of target image + * + * @return bool + */ + public static function isAnimationPng($path) + { + list(, , $type) = getimagesize($path); + switch ($type) { + case IMAGETYPE_PNG: + break; + default: + return false; + } + + $fp = fopen($path, 'rb'); + $img_bytes = fread($fp, 1024); + fclose($fp); + if ($img_bytes) { + if (strpos(substr($img_bytes, 0, strpos($img_bytes, 'IDAT')), 'acTL') !== false) { + return true; + } + } + return false; + } + + /** + * Return Is seekable stream resource + * + * @param resource $resource + * + * @return bool + */ + public static function isSeekableStream($resource) + { + $metadata = stream_get_meta_data($resource); + return $metadata['seekable']; + } + + /** + * Rewind stream resource + * + * @param resource $resource + * + * @return void + */ + public static function rewind($resource) + { + self::isSeekableStream($resource) && rewind($resource); + } + + /** + * Determines whether the specified resource is seekable url. + * + * @param $resource The resource + * + * @return boolean True if the specified resource is seekable url, False otherwise. + */ + public static function isSeekableUrl($resource) + { + $id = (int)$resource; + if (isset(elFinder::$seekableUrlFps[$id])) { + return elFinder::$seekableUrlFps[$id]; + } + return null; + } + + /** + * serialize and base64_encode of session data (If needed) + * + * @deprecated + * + * @param mixed $var target variable + * + * @author Naoki Sawada + * @return mixed|string + */ + public static function sessionDataEncode($var) + { + if (self::$base64encodeSessionData) { + $var = base64_encode(serialize($var)); + } + return $var; + } + + /** + * base64_decode and unserialize of session data (If needed) + * + * @deprecated + * + * @param mixed $var target variable + * @param bool $checkIs data type for check (array|string|object|int) + * + * @author Naoki Sawada + * @return bool|mixed + */ + public static function sessionDataDecode(&$var, $checkIs = null) + { + if (self::$base64encodeSessionData) { + $data = unserialize(base64_decode($var)); + } else { + $data = $var; + } + $chk = true; + if ($checkIs) { + switch ($checkIs) { + case 'array': + $chk = is_array($data); + break; + case 'string': + $chk = is_string($data); + break; + case 'object': + $chk = is_object($data); + break; + case 'int': + $chk = is_int($data); + break; + } + } + if (!$chk) { + unset($var); + return false; + } + return $data; + } + + /** + * Call session_write_close() if session is restarted + * + * @deprecated + * @return void + */ + public static function sessionWrite() + { + if (session_id()) { + session_write_close(); + } + } + + /** + * Return elFinder static variable + * + * @param $key + * + * @return mixed|null + */ + public static function getStaticVar($key) + { + return isset(elFinder::$$key) ? elFinder::$$key : null; + } + + /** + * Extend PHP execution time limit and also check connection is aborted + * + * @param Int $time + * + * @return void + * @throws elFinderAbortException + */ + public static function extendTimeLimit($time = null) + { + static $defLimit = null; + if (!self::aborted()) { + if (is_null($defLimit)) { + $defLimit = ini_get('max_execution_time'); + } + if ($defLimit != 0) { + $time = is_null($time) ? $defLimit : max($defLimit, $time); + set_time_limit($time); + } + } else { + throw new elFinderAbortException(); + } + } + + /** + * Check connection is aborted + * Script stop immediately if connection aborted + * + * @return void + * @throws elFinderAbortException + */ + public static function checkAborted() + { + elFinder::extendTimeLimit(); + } + + /** + * Return bytes from php.ini value + * + * @param string $iniName + * @param string $val + * + * @return number + */ + public static function getIniBytes($iniName = '', $val = '') + { + if ($iniName !== '') { + $val = ini_get($iniName); + if ($val === false) { + return 0; + } + } + $val = trim($val, "bB \t\n\r\0\x0B"); + $last = strtolower($val[strlen($val) - 1]); + $val = sprintf('%u', $val); + switch ($last) { + case 'y': + $val = elFinder::xKilobyte($val); + case 'z': + $val = elFinder::xKilobyte($val); + case 'e': + $val = elFinder::xKilobyte($val); + case 'p': + $val = elFinder::xKilobyte($val); + case 't': + $val = elFinder::xKilobyte($val); + case 'g': + $val = elFinder::xKilobyte($val); + case 'm': + $val = elFinder::xKilobyte($val); + case 'k': + $val = elFinder::xKilobyte($val); + } + return $val; + } + + /** + * Return X 1KByte + * + * @param integer|string $val The value + * + * @return number + */ + public static function xKilobyte($val) + { + if (strpos((string)$val * 1024, 'E') !== false) { + if (strpos((string)$val * 1.024, 'E') === false) { + $val *= 1.024; + } + $val .= '000'; + } else { + $val *= 1024; + } + return $val; + } + + /** + * Get script url. + * + * @return string full URL + * @author Naoki Sawada + */ + public static function getConnectorUrl() + { + if (defined('ELFINDER_CONNECTOR_URL')) { + return ELFINDER_CONNECTOR_URL; + } + + $https = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off'); + $url = ($https ? 'https://' : 'http://') + . $_SERVER['SERVER_NAME'] // host + . ((empty($_SERVER['SERVER_PORT']) || (!$https && $_SERVER['SERVER_PORT'] == 80) || ($https && $_SERVER['SERVER_PORT'] == 443)) ? '' : (':' . $_SERVER['SERVER_PORT'])) // port + . $_SERVER['REQUEST_URI']; // path & query + list($url) = explode('?', $url); + + return $url; + } + + /** + * Get stream resource pointer by URL + * + * @param array $data array('target'=>'URL', 'headers' => array()) + * @param int $redirectLimit + * + * @return resource|boolean + * @author Naoki Sawada + */ + public static function getStreamByUrl($data, $redirectLimit = 5) + { + if (isset($data['target'])) { + $data = array( + 'cnt' => 0, + 'url' => $data['target'], + 'headers' => isset($data['headers']) ? $data['headers'] : array(), + 'postData' => isset($data['postData']) ? $data['postData'] : array(), + 'cookies' => array(), + ); + } + if ($data['cnt'] > $redirectLimit) { + return false; + } + $dlurl = $data['url']; + $data['url'] = ''; + $headers = $data['headers']; + + if ($dlurl) { + $url = parse_url($dlurl); + $ports = array( + 'http' => '80', + 'https' => '443', + 'ftp' => '21' + ); + $url['scheme'] = strtolower($url['scheme']); + if (!isset($url['port']) && isset($ports[$url['scheme']])) { + $url['port'] = $ports[$url['scheme']]; + } + if (!isset($url['port'])) { + return false; + } + $cookies = array(); + if ($data['cookies']) { + foreach ($data['cookies'] as $d => $c) { + if (strpos($url['host'], $d) !== false) { + $cookies[] = $c; + } + } + } + + $transport = ($url['scheme'] === 'https') ? 'ssl' : 'tcp'; + $query = isset($url['query']) ? '?' . $url['query'] : ''; + if (!($stream = stream_socket_client($transport . '://' . $url['host'] . ':' . $url['port']))) { + return false; + } + + $body = ''; + if (!empty($data['postData'])) { + $method = 'POST'; + if (is_array($data['postData'])) { + $body = http_build_query($data['postData']); + } else { + $body = $data['postData']; + } + } else { + $method = 'GET'; + } + + $sends = array(); + $sends[] = "$method {$url['path']}{$query} HTTP/1.1"; + $sends[] = "Host: {$url['host']}"; + foreach ($headers as $header) { + $sends[] = trim($header, "\r\n"); + } + $sends[] = 'Connection: Close'; + if ($cookies) { + $sends[] = 'Cookie: ' . implode('; ', $cookies); + } + if ($method === 'POST') { + $sends[] = 'Content-Type: application/x-www-form-urlencoded'; + $sends[] = 'Content-Length: ' . strlen($body); + } + $sends[] = "\r\n" . $body; + + stream_set_timeout($stream, 300); + fputs($stream, join("\r\n", $sends) . "\r\n"); + + while (($res = trim(fgets($stream))) !== '') { + // find redirect + if (preg_match('/^Location: (.+)$/i', $res, $m)) { + $data['url'] = $m[1]; + } + // fetch cookie + if (strpos($res, 'Set-Cookie:') === 0) { + $domain = $url['host']; + if (preg_match('/^Set-Cookie:(.+)(?:domain=\s*([^ ;]+))?/i', $res, $c1)) { + if (!empty($c1[2])) { + $domain = trim($c1[2]); + } + if (preg_match('/([^ ]+=[^;]+)/', $c1[1], $c2)) { + $data['cookies'][$domain] = $c2[1]; + } + } + } + // is seekable url + if (preg_match('/^(Accept-Ranges|Content-Range): bytes/i', $res)) { + elFinder::$seekableUrlFps[(int)$stream] = true; + } + } + if ($data['url']) { + ++$data['cnt']; + fclose($stream); + + return self::getStreamByUrl($data, $redirectLimit); + } + + return $stream; + } + + return false; + } + + /** + * Gets the fetch cookie file for curl. + * + * @return string The fetch cookie file. + */ + public function getFetchCookieFile() + { + $file = ''; + if ($tmpDir = $this->getTempDir()) { + $file = $tmpDir . '/.elFinderAnonymousCookie'; + } + return $file; + } + + /** + * Call curl_exec() with supported redirect on `safe_mode` or `open_basedir` + * + * @param resource $curl + * @param array $options + * @param array $headers + * @param array $postData + * + * @throws \Exception + * @return mixed + * @author Naoki Sawada + */ + public static function curlExec($curl, $options = array(), $headers = array(), $postData = array()) + { + $followLocation = (!ini_get('safe_mode') && !ini_get('open_basedir')); + if ($followLocation) { + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + } + + if ($options) { + curl_setopt_array($curl, $options); + } + + if ($headers) { + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + } + + $result = curl_exec($curl); + + if (!$followLocation && $redirect = curl_getinfo($curl, CURLINFO_REDIRECT_URL)) { + if ($stream = self::getStreamByUrl(array('target' => $redirect, 'headers' => $headers, 'postData' => $postData))) { + $result = stream_get_contents($stream); + } + } + + if ($result === false) { + if (curl_errno($curl)) { + throw new \Exception('curl_exec() failed: ' . curl_error($curl)); + } else { + throw new \Exception('curl_exec(): empty response'); + } + } + + curl_close($curl); + + return $result; + } + + /** + * Return bool that current request was aborted by client side + * + * @return boolean + */ + public static function aborted() + { + if ($file = self::$abortCheckFile) { + (version_compare(PHP_VERSION, '5.3.0') >= 0) ? clearstatcache(true, $file) : clearstatcache(); + if (!is_file($file)) { + // GC (expire 12h) + list($ptn) = explode('elfreq', $file); + self::GlobGC($ptn . 'elfreq*', 43200); + return true; + } + } + return false; + } + + /** + * Return array ["name without extention", "extention"] by filename + * + * @param string $name + * + * @return array + */ + public static function splitFileExtention($name) + { + if (preg_match('/^(.+?)?\.((?:tar\.(?:gz|bz|bz2|z|lzo))|cpio\.gz|ps\.gz|xcf\.(?:gz|bz2)|[a-z0-9]{1,10})$/i', $name, $m)) { + return array((string)$m[1], $m[2]); + } else { + return array($name, ''); + } + } + + /** + * Gets the memory size by imageinfo. + * + * @param array $imgInfo array that result of getimagesize() + * + * @return integer The memory size by imageinfo. + */ + public static function getMemorySizeByImageInfo($imgInfo) + { + $width = $imgInfo[0]; + $height = $imgInfo[1]; + $bits = isset($imgInfo['bits']) ? $imgInfo['bits'] : 24; + $channels = isset($imgInfo['channels']) ? $imgInfo['channels'] : 3; + return round(($width * $height * $bits * $channels / 8 + Pow(2, 16)) * 1.65); + } + + /** + * Auto expand memory for GD processing + * + * @param array $imgInfos The image infos + */ + public static function expandMemoryForGD($imgInfos) + { + if (elFinder::$memoryLimitGD != 0 && $imgInfos && is_array($imgInfos)) { + if (!is_array($imgInfos[0])) { + $imgInfos = array($imgInfos); + } + $limit = self::getIniBytes('', elFinder::$memoryLimitGD); + $memLimit = self::getIniBytes('memory_limit'); + $needs = 0; + foreach ($imgInfos as $info) { + $needs += self::getMemorySizeByImageInfo($info); + } + $needs += memory_get_usage(); + if ($needs > $memLimit && ($limit == -1 || $limit > $needs)) { + ini_set('memory_limit', $needs); + } + } + } + + /** + * Decontaminate of filename + * + * @param String $name The name + * + * @return String Decontaminated filename + */ + public static function filenameDecontaminate($name) + { + // Directory traversal defense + if (DIRECTORY_SEPARATOR === '\\') { + $name = str_replace('\\', '/', $name); + } + $parts = explode('/', trim($name, '/')); + $name = array_pop($parts); + return $name; + } + + /** + * Execute shell command + * + * @param string $command command line + * @param string $output stdout strings + * @param int $return_var process exit code + * @param string $error_output stderr strings + * @param null $cwd cwd + * + * @return int exit code + * @throws elFinderAbortException + * @author Alexey Sukhotin + */ + public static function procExec($command, &$output = '', &$return_var = -1, &$error_output = '', $cwd = null) + { + + static $allowed = null; + + if ($allowed === null) { + if ($allowed = function_exists('proc_open')) { + if ($disabled = ini_get('disable_functions')) { + $funcs = array_map('trim', explode(',', $disabled)); + $allowed = !in_array('proc_open', $funcs); + } + } + } + + if (!$allowed) { + $return_var = -1; + return $return_var; + } + + if (!$command) { + $return_var = 0; + return $return_var; + } + + $descriptorspec = array( + 0 => array("pipe", "r"), // stdin + 1 => array("pipe", "w"), // stdout + 2 => array("pipe", "w") // stderr + ); + + $process = proc_open($command, $descriptorspec, $pipes, $cwd, null); + + if (is_resource($process)) { + stream_set_blocking($pipes[1], 0); + stream_set_blocking($pipes[2], 0); + + fclose($pipes[0]); + + $tmpout = ''; + $tmperr = ''; + while (feof($pipes[1]) === false || feof($pipes[2]) === false) { + elFinder::extendTimeLimit(); + $read = array($pipes[1], $pipes[2]); + $write = null; + $except = null; + $ret = stream_select($read, $write, $except, 1); + if ($ret === false) { + // error + break; + } else if ($ret === 0) { + // timeout + continue; + } else { + foreach ($read as $sock) { + if ($sock === $pipes[1]) { + $tmpout .= fread($sock, 4096); + } else if ($sock === $pipes[2]) { + $tmperr .= fread($sock, 4096); + } + } + } + } + + fclose($pipes[1]); + fclose($pipes[2]); + + $output = $tmpout; + $error_output = $tmperr; + $return_var = proc_close($process); + + } else { + $return_var = -1; + } + + return $return_var; + + } + + /***************************************************************************/ + /* callbacks */ + /***************************************************************************/ + + /** + * Get command name of binded "commandName.subName" + * + * @param string $cmd + * + * @return string + */ + protected static function getCmdOfBind($cmd) + { + list($ret) = explode('.', $cmd); + return trim($ret); + } + + /** + * Add subName to commandName + * + * @param string $cmd + * @param string $sub + * + * @return string + */ + protected static function addSubToBindName($cmd, $sub) + { + return $cmd . '.' . trim($sub); + } + + /** + * Remove a file if connection is disconnected + * + * @param string $file + */ + public static function rmFileInDisconnected($file) + { + (connection_aborted() || connection_status() !== CONNECTION_NORMAL) && is_file($file) && unlink($file); + } + + /** + * Call back function on shutdown + * - delete files in $GLOBALS['elFinderTempFiles'] + */ + public static function onShutdown() + { + self::$abortCheckFile = null; + if (!empty($GLOBALS['elFinderTempFps'])) { + foreach (array_keys($GLOBALS['elFinderTempFps']) as $fp) { + is_resource($fp) && fclose($fp); + } + } + //Delete temp file paths + if (!empty($GLOBALS['elFinderTempFiles'])) { + foreach (array_keys($GLOBALS['elFinderTempFiles']) as $f) { + //Make sure paths are safe before deleting them + $tf = elFinder::$commonTempPath . DIRECTORY_SEPARATOR . basename($f); + is_file($tf) && is_writable($tf) && unlink($tf); + } + unset($f); + } + + //Delete abort file paths + if(!empty($GLOBALS['elFinderAbortFiles'])) { + foreach (array_keys($GLOBALS['elFinderAbortFiles']) as $f) { + //Make sure paths are safe before deleting them + $tf = elFinder::$connectionFlagsPath . DIRECTORY_SEPARATOR . basename($f); + is_file($tf) && is_writable($tf) && unlink($tf); + } + unset($f); + } + + } + + /** + * Garbage collection with glob + * + * @param string $pattern + * @param integer $time + */ + public static function GlobGC($pattern, $time) + { + $now = time(); + foreach (glob($pattern) as $file) { + (filemtime($file) < ($now - $time)) && unlink($file); + } + } + +} // END class + +/** + * Custom exception class for aborting request + */ +class elFinderAbortException extends Exception +{ +} + +class elFinderTriggerException extends Exception +{ +} diff --git a/lib/redactor/elfinder/php/elFinderConnector.class.php b/lib/redactor/elfinder/php/elFinderConnector.class.php new file mode 100644 index 0000000..dbbb27e --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderConnector.class.php @@ -0,0 +1,380 @@ +elFinder = $elFinder; + $this->reqMethod = strtoupper($_SERVER["REQUEST_METHOD"]); + if ($debug) { + self::$contentType = 'Content-Type: text/plain; charset=utf-8'; + } + } + + /** + * Execute elFinder command and output result + * + * @return void + * @throws Exception + * @author Dmitry (dio) Levashov + */ + public function run() + { + $isPost = $this->reqMethod === 'POST'; + $src = $isPost ? array_merge($_GET, $_POST) : $_GET; + $maxInputVars = (!$src || isset($src['targets'])) ? ini_get('max_input_vars') : null; + if ((!$src || $maxInputVars) && $rawPostData = file_get_contents('php://input')) { + // for max_input_vars and supports IE XDomainRequest() + $parts = explode('&', $rawPostData); + if (!$src || $maxInputVars < count($parts)) { + $src = array(); + foreach ($parts as $part) { + list($key, $value) = array_pad(explode('=', $part), 2, ''); + $key = rawurldecode($key); + if (preg_match('/^(.+?)\[([^\[\]]*)\]$/', $key, $m)) { + $key = $m[1]; + $idx = $m[2]; + if (!isset($src[$key])) { + $src[$key] = array(); + } + if ($idx) { + $src[$key][$idx] = rawurldecode($value); + } else { + $src[$key][] = rawurldecode($value); + } + } else { + $src[$key] = rawurldecode($value); + } + } + $_POST = $this->input_filter($src); + $_REQUEST = $this->input_filter(array_merge_recursive($src, $_REQUEST)); + } + } + + if (isset($src['targets']) && $this->elFinder->maxTargets && count($src['targets']) > $this->elFinder->maxTargets) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_MAX_TARGTES))); + } + + $cmd = isset($src['cmd']) ? $src['cmd'] : ''; + $args = array(); + + if (!function_exists('json_encode')) { + $error = $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_JSON); + $this->output(array('error' => '{"error":["' . implode('","', $error) . '"]}', 'raw' => true)); + } + + if (!$this->elFinder->loaded()) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_CONF, elFinder::ERROR_CONF_NO_VOL), 'debug' => $this->elFinder->mountErrors)); + } + + // telepat_mode: on + if (!$cmd && $isPost) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UPLOAD, elFinder::ERROR_UPLOAD_TOTAL_SIZE), 'header' => 'Content-Type: text/html')); + } + // telepat_mode: off + + if (!$this->elFinder->commandExists($cmd)) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_UNKNOWN_CMD))); + } + + // collect required arguments to exec command + $hasFiles = false; + foreach ($this->elFinder->commandArgsList($cmd) as $name => $req) { + if ($name === 'FILES') { + if (isset($_FILES)) { + $hasFiles = true; + } elseif ($req) { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd))); + } + } else { + $arg = isset($src[$name]) ? $src[$name] : ''; + + if (!is_array($arg) && $req !== '') { + $arg = trim($arg); + } + if ($req && $arg === '') { + $this->output(array('error' => $this->elFinder->error(elFinder::ERROR_INV_PARAMS, $cmd))); + } + $args[$name] = $arg; + } + } + + $args['debug'] = isset($src['debug']) ? !!$src['debug'] : false; + + $args = $this->input_filter($args); + if ($hasFiles) { + $args['FILES'] = $_FILES; + } + + try { + $this->output($this->elFinder->exec($cmd, $args)); + } catch (elFinderAbortException $e) { + // connection aborted + // unlock session data for multiple access + $this->elFinder->getSession()->close(); + // HTTP response code + header('HTTP/1.0 204 No Content'); + // clear output buffer + while (ob_get_level() && ob_end_clean()) { + } + exit(); + } + } + + /** + * Sets the header. + * + * @param array|string $value HTTP header(s) + */ + public function setHeader($value) + { + $this->header = $value; + } + + /** + * Output json + * + * @param array data to output + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function output(array $data) + { + // unlock session data for multiple access + $this->elFinder->getSession()->close(); + // client disconnect should abort + ignore_user_abort(false); + + if ($this->header) { + self::sendHeader($this->header); + } + + if (isset($data['pointer'])) { + // set time limit to 0 + elFinder::extendTimeLimit(0); + + // send optional header + if (!empty($data['header'])) { + self::sendHeader($data['header']); + } + + // clear output buffer + while (ob_get_level() && ob_end_clean()) { + } + + $toEnd = true; + $fp = $data['pointer']; + $sendData = !($this->reqMethod === 'HEAD' || !empty($data['info']['xsendfile'])); + $psize = null; + if (($this->reqMethod === 'GET' || !$sendData) + && (elFinder::isSeekableStream($fp) || elFinder::isSeekableUrl($fp)) + && (array_search('Accept-Ranges: none', headers_list()) === false)) { + header('Accept-Ranges: bytes'); + if (!empty($_SERVER['HTTP_RANGE'])) { + $size = $data['info']['size']; + $end = $size - 1; + if (preg_match('/bytes=(\d*)-(\d*)(,?)/i', $_SERVER['HTTP_RANGE'], $matches)) { + if (empty($matches[3])) { + if (empty($matches[1]) && $matches[1] !== '0') { + $start = $size - $matches[2]; + } else { + $start = intval($matches[1]); + if (!empty($matches[2])) { + $end = intval($matches[2]); + if ($end >= $size) { + $end = $size - 1; + } + $toEnd = ($end == ($size - 1)); + } + } + $psize = $end - $start + 1; + + header('HTTP/1.1 206 Partial Content'); + header('Content-Length: ' . $psize); + header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size); + + // Apache mod_xsendfile dose not support range request + if (isset($data['info']['xsendfile']) && strtolower($data['info']['xsendfile']) === 'x-sendfile') { + if (function_exists('header_remove')) { + header_remove($data['info']['xsendfile']); + } else { + header($data['info']['xsendfile'] . ':'); + } + unset($data['info']['xsendfile']); + if ($this->reqMethod !== 'HEAD') { + $sendData = true; + } + } + + $sendData && !elFinder::isSeekableUrl($fp) && fseek($fp, $start); + } + } + } + if ($sendData && is_null($psize)) { + elFinder::rewind($fp); + } + } else { + header('Accept-Ranges: none'); + if (isset($data['info']) && !$data['info']['size']) { + if (function_exists('header_remove')) { + header_remove('Content-Length'); + } else { + header('Content-Length:'); + } + } + } + + if ($sendData) { + if ($toEnd || elFinder::isSeekableUrl($fp)) { + // PHP < 5.6 has a bug of fpassthru + // see https://bugs.php.net/bug.php?id=66736 + if (version_compare(PHP_VERSION, '5.6', '<')) { + file_put_contents('php://output', $fp); + } else { + fpassthru($fp); + } + } else { + $out = fopen('php://output', 'wb'); + stream_copy_to_stream($fp, $out, $psize); + fclose($out); + } + } + + if (!empty($data['volume'])) { + $data['volume']->close($fp, $data['info']['hash']); + } else { + fclose($fp); + } + exit(); + } else { + self::outputJson($data); + exit(0); + } + } + + /** + * Remove null & stripslashes applies on "magic_quotes_gpc" + * + * @param mixed $args + * + * @return mixed + * @author Naoki Sawada + */ + protected function input_filter($args) + { + static $magic_quotes_gpc = NULL; + + if ($magic_quotes_gpc === NULL) + $magic_quotes_gpc = (version_compare(PHP_VERSION, '5.4', '<') && get_magic_quotes_gpc()); + + if (is_array($args)) { + return array_map(array(& $this, 'input_filter'), $args); + } + $res = str_replace("\0", '', $args); + $magic_quotes_gpc && ($res = stripslashes($res)); + return $res; + } + + /** + * Send HTTP header + * + * @param string|array $header optional header + */ + protected static function sendHeader($header = null) + { + if ($header) { + if (is_array($header)) { + foreach ($header as $h) { + header($h); + } + } else { + header($header); + } + } + } + + /** + * Output JSON + * + * @param array $data + */ + public static function outputJson($data) + { + // send header + $header = isset($data['header']) ? $data['header'] : self::$contentType; + self::sendHeader($header); + + unset($data['header']); + + if (!empty($data['raw']) && isset($data['error'])) { + $out = $data['error']; + } else { + if (isset($data['debug']) && isset($data['debug']['backendErrors'])) { + $data['debug']['backendErrors'] = array_merge($data['debug']['backendErrors'], elFinder::$phpErrors); + } + $out = json_encode($data); + } + + // clear output buffer + while (ob_get_level() && ob_end_clean()) { + } + + header('Content-Length: ' . strlen($out)); + + echo $out; + + flush(); + } +}// END class diff --git a/lib/redactor/elfinder/php/elFinderFlysystemGoogleDriveNetmount.php b/lib/redactor/elfinder/php/elFinderFlysystemGoogleDriveNetmount.php new file mode 100644 index 0000000..b3345cd --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderFlysystemGoogleDriveNetmount.php @@ -0,0 +1,380 @@ + '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#', + 'rootCssClass' => 'elfinder-navbar-root-googledrive', + 'gdAlias' => '%s@GDrive', + 'gdCacheDir' => __DIR__ . '/.tmp', + 'gdCachePrefix' => 'gd-', + 'gdCacheExpire' => 600 + ); + + $this->options = array_merge($this->options, $opts); + } + + /** + * Prepare driver before mount volume. + * Return true if volume is ready. + * + * @return bool + **/ + protected function init() + { + if (empty($this->options['icon'])) { + $this->options['icon'] = true; + } + if ($res = parent::init()) { + if ($this->options['icon'] === true) { + unset($this->options['icon']); + } + // enable command archive + $this->options['useRemoteArchive'] = true; + } + return $res; + } + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount() + * + * @param $options + * + * @return Array + * @author Naoki Sawada + */ + public function netmountPrepare($options) + { + if (empty($options['client_id']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTID')) { + $options['client_id'] = ELFINDER_GOOGLEDRIVE_CLIENTID; + } + if (empty($options['client_secret']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTSECRET')) { + $options['client_secret'] = ELFINDER_GOOGLEDRIVE_CLIENTSECRET; + } + + if (!isset($options['pass'])) { + $options['pass'] = ''; + } + + try { + $client = new \Google_Client(); + $client->setClientId($options['client_id']); + $client->setClientSecret($options['client_secret']); + + if ($options['pass'] === 'reauth') { + $options['pass'] = ''; + $this->session->set('GoogleDriveAuthParams', [])->set('GoogleDriveTokens', []); + } else if ($options['pass'] === 'googledrive') { + $options['pass'] = ''; + } + + $options = array_merge($this->session->get('GoogleDriveAuthParams', []), $options); + + if (!isset($options['access_token'])) { + $options['access_token'] = $this->session->get('GoogleDriveTokens', []); + $this->session->remove('GoogleDriveTokens'); + } + $aToken = $options['access_token']; + + $rootObj = $service = null; + if ($aToken) { + try { + $client->setAccessToken($aToken); + if ($client->isAccessTokenExpired()) { + $aToken = array_merge($aToken, $client->fetchAccessTokenWithRefreshToken()); + $client->setAccessToken($aToken); + } + $service = new \Google_Service_Drive($client); + $rootObj = $service->files->get('root'); + + $options['access_token'] = $aToken; + $this->session->set('GoogleDriveAuthParams', $options); + + } catch (Exception $e) { + $aToken = []; + $options['access_token'] = []; + if ($options['user'] !== 'init') { + $this->session->set('GoogleDriveAuthParams', $options); + return array('exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE); + } + } + + } + + $itpCare = isset($options['code']); + $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : ''); + if ($code || $options['user'] === 'init') { + if (empty($options['url'])) { + $options['url'] = elFinder::getConnectorUrl(); + } + + if (isset($options['id'])) { + $callback = $options['url'] . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']); + $client->setRedirectUri($callback); + } + + if (!$aToken && empty($code)) { + $client->setScopes([Google_Service_Drive::DRIVE]); + if (!empty($options['offline'])) { + $client->setApprovalPrompt('force'); + $client->setAccessType('offline'); + } + $url = $client->createAuthUrl(); + + $html = ''; + $html .= ''; + if (empty($options['pass']) && $options['host'] !== '1') { + $options['pass'] = 'return'; + $this->session->set('GoogleDriveAuthParams', $options); + return array('exit' => true, 'body' => $html); + } else { + $out = array( + 'node' => $options['id'], + 'json' => '{"protocol": "googledrive", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}', + 'bind' => 'netmount' + ); + return array('exit' => 'callback', 'out' => $out); + } + } else { + if ($code) { + if (!empty($options['id'])) { + $aToken = $client->fetchAccessTokenWithAuthCode($code); + $options['access_token'] = $aToken; + unset($options['code']); + $this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options); + $out = array( + 'node' => $options['id'], + 'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}', + 'bind' => 'netmount' + ); + } else { + $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host']; + $out = array( + 'node' => $nodeid, + 'json' => json_encode(array( + 'protocol' => 'googledrive', + 'host' => $nodeid, + 'mode' => 'redirect', + 'options' => array( + 'id' => $nodeid, + 'code'=> $code + ) + )), + 'bind' => 'netmount' + ); + } + if (!$itpCare) { + return array('exit' => 'callback', 'out' => $out); + } else { + return array('exit' => true, 'body' => $out['json']); + } + } + $folders = []; + foreach ($service->files->listFiles([ + 'pageSize' => 1000, + 'q' => 'trashed = false and mimeType = "application/vnd.google-apps.folder"' + ]) as $f) { + $folders[$f->getId()] = $f->getName(); + } + natcasesort($folders); + $folders = ['root' => $rootObj->getName()] + $folders; + $folders = json_encode($folders); + $json = '{"protocol": "googledrive", "mode": "done", "folders": ' . $folders . '}'; + $options['pass'] = 'return'; + $html = 'Google.com'; + $html .= ''; + $this->session->set('GoogleDriveAuthParams', $options); + return array('exit' => true, 'body' => $html); + } + } + } catch (Exception $e) { + $this->session->remove('GoogleDriveAuthParams')->remove('GoogleDriveTokens'); + if (empty($options['pass'])) { + return array('exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage()); + } else { + return array('exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]); + } + } + + if (!$aToken) { + return array('exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE); + } + + if ($options['path'] === '/') { + $options['path'] = 'root'; + } + + try { + $file = $service->files->get($options['path']); + $options['alias'] = sprintf($this->options['gdAlias'], $file->getName()); + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } catch (Google_Service_Exception $e) { + $err = json_decode($e->getMessage(), true); + if (isset($err['error']) && $err['error']['code'] == 404) { + return array('exit' => true, 'error' => [elFinder::ERROR_TRGDIR_NOT_FOUND, $options['path']]); + } else { + return array('exit' => true, 'error' => $e->getMessage()); + } + } catch (Exception $e) { + return array('exit' => true, 'error' => $e->getMessage()); + } + + foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) { + unset($options[$key]); + } + + return $options; + } + + /** + * process of on netunmount + * Drop table `dropbox` & rm thumbs + * + * @param $netVolumes + * @param $key + * + * @return bool + * @internal param array $options + */ + public function netunmount($netVolumes, $key) + { + $cache = $this->options['gdCacheDir'] . DIRECTORY_SEPARATOR . $this->options['gdCachePrefix'] . $this->netMountKey; + if (file_exists($cache) && is_writeable($cache)) { + unlink($cache); + } + if ($tmbs = glob($this->tmbPath . DIRECTORY_SEPARATOR . $this->netMountKey . '*')) { + foreach ($tmbs as $file) { + unlink($file); + } + } + return true; + } + + /** + * "Mount" volume. + * Return true if volume available for read or write, + * false - otherwise + * + * @param array $opts + * + * @return bool + * @author Naoki Sawada + */ + public function mount(array $opts) + { + $creds = null; + if (isset($opts['access_token'])) { + $this->netMountKey = md5(join('-', array('googledrive', $opts['path'], (isset($opts['access_token']['refresh_token']) ? $opts['access_token']['refresh_token'] : $opts['access_token']['access_token'])))); + } + + $client = new \Google_Client(); + $client->setClientId($opts['client_id']); + $client->setClientSecret($opts['client_secret']); + + if (!empty($opts['access_token'])) { + $client->setAccessToken($opts['access_token']); + } + if ($this->needOnline && $client->isAccessTokenExpired()) { + try { + $creds = $client->fetchAccessTokenWithRefreshToken(); + } catch (LogicException $e) { + $this->session->remove('GoogleDriveAuthParams'); + throw $e; + } + } + + $service = new \Google_Service_Drive($client); + + // If path is not set, use the root + if (!isset($opts['path']) || $opts['path'] === '') { + $opts['path'] = 'root'; + } + + $googleDrive = new GoogleDriveAdapter($service, $opts['path'], ['useHasDir' => true]); + + $opts['fscache'] = null; + if ($this->options['gdCacheDir'] && is_writeable($this->options['gdCacheDir'])) { + if ($this->options['gdCacheExpire']) { + $opts['fscache'] = new elFinderVolumeFlysystemGoogleDriveCache(new Local($this->options['gdCacheDir']), $this->options['gdCachePrefix'] . $this->netMountKey, $this->options['gdCacheExpire']); + } + } + if ($opts['fscache']) { + $filesystem = new Filesystem(new CachedAdapter($googleDrive, $opts['fscache'])); + } else { + $filesystem = new Filesystem($googleDrive); + } + + $opts['driver'] = 'FlysystemExt'; + $opts['filesystem'] = $filesystem; + $opts['separator'] = '/'; + $opts['checkSubfolders'] = true; + if (!isset($opts['alias'])) { + $opts['alias'] = 'GoogleDrive'; + } + + if ($res = parent::mount($opts)) { + // update access_token of session data + if ($creds) { + $netVolumes = $this->session->get('netvolume'); + $netVolumes[$this->netMountKey]['access_token'] = array_merge($netVolumes[$this->netMountKey]['access_token'], $creds); + $this->session->set('netvolume', $netVolumes); + } + } + + return $res; + } + + /** + * @inheritdoc + */ + protected function tmbname($stat) + { + return $this->netMountKey . substr(substr($stat['hash'], strlen($this->id)), -38) . $stat['ts'] . '.png'; + } + + /** + * Return debug info for client. + * + * @return array + **/ + public function debug() + { + $res = parent::debug(); + if (!empty($this->options['netkey']) && empty($this->options['refresh_token']) && $this->options['access_token'] && isset($this->options['access_token']['refresh_token'])) { + $res['refresh_token'] = $this->options['access_token']['refresh_token']; + } + + return $res; + } +} diff --git a/lib/redactor/elfinder/php/elFinderPlugin.php b/lib/redactor/elfinder/php/elFinderPlugin.php new file mode 100644 index 0000000..2bc85c7 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderPlugin.php @@ -0,0 +1,113 @@ +opts; + if (is_object($volume)) { + $volOpts = $volume->getOptionsPlugin($name); + if (is_array($volOpts)) { + $opts = array_merge($opts, $volOpts); + } + } + return $opts; + } + + /** + * Is enabled with options + * + * @param array $opts + * @param elFinder $elfinder + * + * @return boolean + */ + protected function iaEnabled($opts, $elfinder = null) + { + if (!$opts['enable']) { + return false; + } + + // check post var 'contentSaveId' to disable this plugin + if ($elfinder && !empty($opts['disableWithContentSaveId'])) { + $session = $elfinder->getSession(); + $urlContentSaveIds = $session->get('urlContentSaveIds', array()); + if (!empty(elFinder::$currentArgs['contentSaveId']) && ($contentSaveId = elFinder::$currentArgs['contentSaveId'])) { + if (!empty($urlContentSaveIds[$contentSaveId])) { + $elfinder->removeUrlContentSaveId($contentSaveId); + return false; + } + } + } + + if (isset($opts['onDropWith']) && !is_null($opts['onDropWith'])) { + // plugin disabled by default, enabled only if given key is pressed + if (isset($_REQUEST['dropWith']) && $_REQUEST['dropWith']) { + $onDropWith = $opts['onDropWith']; + $action = (int)$_REQUEST['dropWith']; + if (!is_array($onDropWith)) { + $onDropWith = array($onDropWith); + } + foreach ($onDropWith as $key) { + $key = (int)$key; + if (($action & $key) === $key) { + return true; + } + } + } + return false; + } + + if (isset($opts['offDropWith']) && !is_null($opts['offDropWith']) && isset($_REQUEST['dropWith'])) { + // plugin enabled by default, disabled only if given key is pressed + $offDropWith = $opts['offDropWith']; + $action = (int)$_REQUEST['dropWith']; + if (!is_array($offDropWith)) { + $offDropWith = array($offDropWith); + } + $res = true; + foreach ($offDropWith as $key) { + $key = (int)$key; + if ($key === 0) { + if ($action === 0) { + $res = false; + break; + } + } else { + if (($action & $key) === $key) { + $res = false; + break; + } + } + } + if (!$res) { + return false; + } + } + + return true; + } +} diff --git a/lib/redactor/elfinder/php/elFinderSession.php b/lib/redactor/elfinder/php/elFinderSession.php new file mode 100644 index 0000000..680c5a5 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderSession.php @@ -0,0 +1,335 @@ + false, + 'keys' => array( + 'default' => 'elFinderCaches', + 'netvolume' => 'elFinderNetVolumes' + ), + 'cookieParams' => array() + ); + + /** + * Constractor + * + * @param array $opts The options + * + * @return self Instanse of this class + */ + public function __construct($opts) + { + $this->opts = array_merge($this->opts, $opts); + $this->base64encode = !empty($this->opts['base64encode']); + $this->keys = $this->opts['keys']; + if (function_exists('apache_get_version') || $this->opts['cookieParams']) { + $this->fixCookieRegist = true; + } + } + + /** + * {@inheritdoc} + */ + public function get($key, $empty = null) + { + $closed = false; + if (!$this->started) { + $closed = true; + $this->start(); + } + + $data = null; + + if ($this->started) { + $session =& $this->getSessionRef($key); + $data = $session; + if ($data && $this->base64encode) { + $data = $this->decodeData($data); + } + } + + $checkFn = null; + if (!is_null($empty)) { + if (is_string($empty)) { + $checkFn = 'is_string'; + } elseif (is_array($empty)) { + $checkFn = 'is_array'; + } elseif (is_object($empty)) { + $checkFn = 'is_object'; + } elseif (is_float($empty)) { + $checkFn = 'is_float'; + } elseif (is_int($empty)) { + $checkFn = 'is_int'; + } + } + + if (is_null($data) || ($checkFn && !$checkFn($data))) { + $session = $data = $empty; + } + + if ($closed) { + $this->close(); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function start() + { + set_error_handler(array($this, 'session_start_error'), E_NOTICE | E_WARNING); + + // apache2 SAPI has a bug of session cookie register + // see https://bugs.php.net/bug.php?id=75554 + // see https://github.com/php/php-src/pull/3231 + if ($this->fixCookieRegist === true) { + if ((int)ini_get('session.use_cookies') === 1) { + if (ini_set('session.use_cookies', 0) === false) { + $this->fixCookieRegist = false; + } + } + } + + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + if (session_status() !== PHP_SESSION_ACTIVE) { + session_start(); + } + } else { + session_start(); + } + $this->started = session_id() ? true : false; + + restore_error_handler(); + + return $this; + } + + /** + * Get variable reference of $_SESSION + * + * @param string $key key of $_SESSION array + * + * @return mixed|null + */ + protected function & getSessionRef($key) + { + $session = null; + if ($this->started) { + list($cat, $name) = array_pad(explode('.', $key, 2), 2, null); + if (is_null($name)) { + if (!isset($this->keys[$cat])) { + $name = $cat; + $cat = 'default'; + } + } + if (isset($this->keys[$cat])) { + $cat = $this->keys[$cat]; + } else { + $name = $cat . '.' . $name; + $cat = $this->keys['default']; + } + if (is_null($name)) { + if (!isset($_SESSION[$cat])) { + $_SESSION[$cat] = null; + } + $session =& $_SESSION[$cat]; + } else { + if (!isset($_SESSION[$cat]) || !is_array($_SESSION[$cat])) { + $_SESSION[$cat] = array(); + } + if (!isset($_SESSION[$cat][$name])) { + $_SESSION[$cat][$name] = null; + } + $session =& $_SESSION[$cat][$name]; + } + } + return $session; + } + + /** + * base64 decode of session val + * + * @param $data + * + * @return bool|mixed|string|null + */ + protected function decodeData($data) + { + if ($this->base64encode) { + if (is_string($data)) { + if (($data = base64_decode($data)) !== false) { + $data = unserialize($data); + } else { + $data = null; + } + } else { + $data = null; + } + } + return $data; + } + + /** + * {@inheritdoc} + */ + public function close() + { + if ($this->started) { + if ($this->fixCookieRegist === true) { + // regist cookie only once for apache2 SAPI + $cParm = session_get_cookie_params(); + if ($this->opts['cookieParams'] && is_array($this->opts['cookieParams'])) { + $cParm = array_merge($cParm, $this->opts['cookieParams']); + } + if (version_compare(PHP_VERSION, '7.3', '<')) { + setcookie(session_name(), session_id(), 0, $cParm['path'] . (!empty($cParm['SameSite'])? '; SameSite=' . $cParm['SameSite'] : ''), $cParm['domain'], $cParm['secure'], $cParm['httponly']); + } else { + $allows = array('expires' => true, 'path' => true, 'domain' => true, 'secure' => true, 'httponly' => true, 'samesite' => true); + foreach(array_keys($cParm) as $_k) { + if (!isset($allows[$_k])) { + unset($cParm[$_k]); + } + } + setcookie(session_name(), session_id(), $cParm); + } + $this->fixCookieRegist = false; + } + session_write_close(); + } + $this->started = false; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function set($key, $data) + { + $closed = false; + if (!$this->started) { + $closed = true; + $this->start(); + } + $session =& $this->getSessionRef($key); + if ($this->base64encode) { + $data = $this->encodeData($data); + } + $session = $data; + + if ($closed) { + $this->close(); + } + + return $this; + } + + /** + * base64 encode for session val + * + * @param $data + * + * @return string + */ + protected function encodeData($data) + { + if ($this->base64encode) { + $data = base64_encode(serialize($data)); + } + return $data; + } + + /** + * {@inheritdoc} + */ + public function remove($key) + { + $closed = false; + if (!$this->started) { + $closed = true; + $this->start(); + } + + list($cat, $name) = array_pad(explode('.', $key, 2), 2, null); + if (is_null($name)) { + if (!isset($this->keys[$cat])) { + $name = $cat; + $cat = 'default'; + } + } + if (isset($this->keys[$cat])) { + $cat = $this->keys[$cat]; + } else { + $name = $cat . '.' . $name; + $cat = $this->keys['default']; + } + if (is_null($name)) { + unset($_SESSION[$cat]); + } else { + if (isset($_SESSION[$cat]) && is_array($_SESSION[$cat])) { + unset($_SESSION[$cat][$name]); + } + } + + if ($closed) { + $this->close(); + } + + return $this; + } + + /** + * sessioin error handler (Only for suppression of error at session start) + * + * @param $errno + * @param $errstr + */ + protected function session_start_error($errno, $errstr) + { + } +} diff --git a/lib/redactor/elfinder/php/elFinderSessionInterface.php b/lib/redactor/elfinder/php/elFinderSessionInterface.php new file mode 100644 index 0000000..ff90332 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderSessionInterface.php @@ -0,0 +1,57 @@ + '', + 'client_secret' => '', + 'accessToken' => '', + 'root' => 'Box.com', + 'path' => '/', + 'separator' => '/', + 'tmbPath' => '', + 'tmbURL' => '', + 'tmpPath' => '', + 'acceptedName' => '#^[^\\\/]+$#', + 'rootCssClass' => 'elfinder-navbar-root-box', + ); + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /*********************************************************************/ + /* ORIGINAL FUNCTIONS */ + /*********************************************************************/ + + /** + * Get Parent ID, Item ID, Parent Path as an array from path. + * + * @param string $path + * + * @return array + */ + protected function _bd_splitPath($path) + { + $path = trim($path, '/'); + $pid = ''; + if ($path === '') { + $id = '0'; + $parent = ''; + } else { + $paths = explode('/', trim($path, '/')); + $id = array_pop($paths); + if ($paths) { + $parent = '/' . implode('/', $paths); + $pid = array_pop($paths); + } else { + $pid = '0'; + $parent = '/'; + } + } + + return array($pid, $id, $parent); + } + + /** + * Obtains a new access token from OAuth. This token is valid for one hour. + * + * @param string $clientSecret The Box client secret + * @param string $code The code returned by Box after + * successful log in + * @param string $redirectUri Must be the same as the redirect URI passed + * to LoginUrl + * + * @return bool|object + * @throws \Exception Thrown if this Client instance's clientId is not set + * @throws \Exception Thrown if the redirect URI of this Client instance's + * state is not set + */ + protected function _bd_obtainAccessToken($client_id, $client_secret, $code) + { + if (null === $client_id) { + return $this->setError('The client ID must be set to call obtainAccessToken()'); + } + + if (null === $client_secret) { + return $this->setError('The client Secret must be set to call obtainAccessToken()'); + } + + if (null === $code) { + return $this->setError('Authorization code must be set to call obtainAccessToken()'); + } + + $url = self::TOKEN_URL; + + $curl = curl_init(); + + $fields = http_build_query( + array( + 'client_id' => $client_id, + 'client_secret' => $client_secret, + 'code' => $code, + 'grant_type' => 'authorization_code', + ) + ); + + curl_setopt_array($curl, array( + // General options. + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $fields, + CURLOPT_URL => $url, + )); + + $decoded = $this->_bd_curlExec($curl, true, array('Content-Length: ' . strlen($fields))); + + $res = (object)array( + 'expires' => time() + $decoded->expires_in - 30, + 'initialToken' => '', + 'data' => $decoded + ); + if (!empty($decoded->refresh_token)) { + $res->initialToken = md5($client_id . $decoded->refresh_token); + } + return $res; + } + + /** + * Get token and auto refresh. + * + * @return true|string error message + * @throws Exception + */ + protected function _bd_refreshToken() + { + if (!property_exists($this->token, 'expires') || $this->token->expires < time()) { + if (!$this->options['client_id']) { + $this->options['client_id'] = ELFINDER_BOX_CLIENTID; + } + + if (!$this->options['client_secret']) { + $this->options['client_secret'] = ELFINDER_BOX_CLIENTSECRET; + } + + if (empty($this->token->data->refresh_token)) { + throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE); + } else { + $refresh_token = $this->token->data->refresh_token; + $initialToken = $this->_bd_getInitialToken(); + } + + $lock = ''; + $aTokenFile = $this->aTokenFile? $this->aTokenFile : $this->_bd_getATokenFile(); + if ($aTokenFile && is_file($aTokenFile)) { + $lock = $aTokenFile . '.lock'; + if (file_exists($lock)) { + // Probably updating on other instance + return true; + } + touch($lock); + $GLOBALS['elFinderTempFiles'][$lock] = true; + } + + $postData = array( + 'client_id' => $this->options['client_id'], + 'client_secret' => $this->options['client_secret'], + 'grant_type' => 'refresh_token', + 'refresh_token' => $refresh_token + ); + + $url = self::TOKEN_URL; + + $curl = curl_init(); + + curl_setopt_array($curl, array( + // General options. + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, // i am sending post data + CURLOPT_POSTFIELDS => http_build_query($postData), + CURLOPT_URL => $url, + )); + + $decoded = $error = ''; + try { + $decoded = $this->_bd_curlExec($curl, true, array(), $postData); + } catch (Exception $e) { + $error = $e->getMessage(); + } + if (!$decoded && !$error) { + $error = 'Tried to renew the access token, but did not get a response from the Box server.'; + } + if ($error) { + $lock && unlink($lock); + throw new \Exception('Box access token update failed. ('.$error.') If this message appears repeatedly, please notify the administrator.'); + } + + if (empty($decoded->access_token)) { + if ($aTokenFile) { + if (is_file($aTokenFile)) { + unlink($aTokenFile); + } + } + $err = property_exists($decoded, 'error')? ' ' . $decoded->error : ''; + $err .= property_exists($decoded, 'error_description')? ' ' . $decoded->error_description : ''; + throw new \Exception($err? $err : elFinder::ERROR_REAUTH_REQUIRE); + } + + $token = (object)array( + 'expires' => time() + $decoded->expires_in - 300, + 'initialToken' => $initialToken, + 'data' => $decoded, + ); + + $this->token = $token; + $json = json_encode($token); + + if (!empty($decoded->refresh_token)) { + if (empty($this->options['netkey']) && $aTokenFile) { + file_put_contents($aTokenFile, json_encode($token), LOCK_EX); + $this->options['accessToken'] = $json; + } else if (!empty($this->options['netkey'])) { + // OAuth2 refresh token can be used only once, + // so update it if it is the same as the token file + if ($aTokenFile && is_file($aTokenFile)) { + if ($_token = json_decode(file_get_contents($aTokenFile))) { + if ($_token->data->refresh_token === $refresh_token) { + file_put_contents($aTokenFile, $json, LOCK_EX); + } + } + } + $this->options['accessToken'] = $json; + // update session value + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $json); + $this->session->set('BoxTokens', $token); + } else { + throw new \Exception(ERROR_CREATING_TEMP_DIR); + } + } + $lock && unlink($lock); + } + + return true; + } + + /** + * Creates a base cURL object which is compatible with the Box.com API. + * + * @param array $options cURL options + * + * @return resource A compatible cURL object + */ + protected function _bd_prepareCurl($options = array()) + { + $curl = curl_init(); + + $defaultOptions = array( + // General options. + CURLOPT_RETURNTRANSFER => true, + ); + + curl_setopt_array($curl, $options + $defaultOptions); + + return $curl; + } + + /** + * Creates a base cURL object which is compatible with the Box.com API. + * + * @param $url + * @param bool $contents + * + * @return boolean|array + * @throws Exception + */ + protected function _bd_fetch($url, $contents = false) + { + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + + if ($contents) { + return $this->_bd_curlExec($curl, false); + } else { + $result = $this->_bd_curlExec($curl); + + if (isset($result->entries)) { + $res = $result->entries; + $cnt = count($res); + $total = $result->total_count; + $offset = $result->offset; + $single = ($result->limit == 1) ? true : false; + if (!$single && $total > ($offset + $cnt)) { + $offset = $offset + $cnt; + if (strpos($url, 'offset=') === false) { + $url .= '&offset=' . $offset; + } else { + $url = preg_replace('/^(.+?offset=)\d+(.*)$/', '${1}' . $offset . '$2', $url); + } + $more = $this->_bd_fetch($url); + if (is_array($more)) { + $res = array_merge($res, $more); + } + } + + return $res; + } else { + if (isset($result->type) && $result->type === 'error') { + return false; + } else { + return $result; + } + } + } + } + + /** + * Call curl_exec(). + * + * @param resource $curl + * @param bool|string $decodeOrParent + * @param array $headers + * + * @throws \Exception + * @return mixed + */ + protected function _bd_curlExec($curl, $decodeOrParent = true, $headers = array(), $postData = array()) + { + if ($this->token) { + $headers = array_merge(array( + 'Authorization: Bearer ' . $this->token->data->access_token, + ), $headers); + } + + $result = elFinder::curlExec($curl, array(), $headers, $postData); + + if (!$decodeOrParent) { + return $result; + } + + $decoded = json_decode($result); + + if ($error = !empty($decoded->error_code)) { + $errmsg = $decoded->error_code; + if (!empty($decoded->message)) { + $errmsg .= ': ' . $decoded->message; + } + throw new \Exception($errmsg); + } else if ($error = !empty($decoded->error)) { + $errmsg = $decoded->error; + if (!empty($decoded->error_description)) { + $errmsg .= ': ' . $decoded->error_description; + } + throw new \Exception($errmsg); + } + + // make catch + if ($decodeOrParent && $decodeOrParent !== true) { + $raws = null; + if (isset($decoded->entries)) { + $raws = $decoded->entries; + } elseif (isset($decoded->id)) { + $raws = array($decoded); + } + if ($raws) { + foreach ($raws as $raw) { + if (isset($raw->id)) { + $stat = $this->_bd_parseRaw($raw); + $itemPath = $this->_joinPath($decodeOrParent, $raw->id); + $this->updateCache($itemPath, $stat); + } + } + } + } + + return $decoded; + } + + /** + * Drive query and fetchAll. + * + * @param $itemId + * @param bool $fetch_self + * @param bool $recursive + * + * @return bool|object + * @throws Exception + */ + protected function _bd_query($itemId, $fetch_self = false, $recursive = false) + { + $result = []; + + if (null === $itemId) { + $itemId = '0'; + } + + if ($fetch_self) { + $path = '/folders/' . $itemId . '?fields=' . self::FETCHFIELDS; + } else { + $path = '/folders/' . $itemId . '/items?limit=1000&fields=' . self::FETCHFIELDS; + } + + $url = self::API_URL . $path; + + if ($recursive) { + foreach ($this->_bd_fetch($url) as $file) { + if ($file->type == 'folder') { + $result[] = $file; + $result = array_merge($result, $this->_bd_query($file->id, $fetch_self = false, $recursive = true)); + } elseif ($file->type == 'file') { + $result[] = $file; + } + } + } else { + $result = $this->_bd_fetch($url); + if ($fetch_self && !$result) { + $path = '/files/' . $itemId . '?fields=' . self::FETCHFIELDS; + $url = self::API_URL . $path; + $result = $this->_bd_fetch($url); + } + } + + return $result; + } + + /** + * Get dat(box metadata) from Box.com. + * + * @param string $path + * + * @return object box metadata + * @throws Exception + */ + protected function _bd_getRawItem($path) + { + if ($path == '/') { + return $this->_bd_query('0', $fetch_self = true); + } + + list(, $itemId) = $this->_bd_splitPath($path); + + try { + return $this->_bd_query($itemId, $fetch_self = true); + } catch (Exception $e) { + $empty = new stdClass; + return $empty; + } + } + + /** + * Parse line from box metadata output and return file stat (array). + * + * @param object $raw line from ftp_rawlist() output + * + * @return array + * @author Dmitry Levashov + **/ + protected function _bd_parseRaw($raw) + { + $stat = array(); + + $stat['rev'] = isset($raw->id) ? $raw->id : 'root'; + $stat['name'] = $raw->name; + if (!empty($raw->modified_at)) { + $stat['ts'] = strtotime($raw->modified_at); + } + + if ($raw->type === 'folder') { + $stat['mime'] = 'directory'; + $stat['size'] = 0; + $stat['dirs'] = -1; + } else { + $stat['size'] = (int)$raw->size; + if (!empty($raw->shared_link->url) && $raw->shared_link->access == 'open') { + if ($url = $this->getSharedWebContentLink($raw)) { + $stat['url'] = $url; + } + } elseif (!$this->disabledGetUrl) { + $stat['url'] = '1'; + } + } + + return $stat; + } + + /** + * Get thumbnail from Box.com. + * + * @param string $path + * @param string $size + * + * @return string | boolean + */ + protected function _bd_getThumbnail($path) + { + list(, $itemId) = $this->_bd_splitPath($path); + + try { + $url = self::API_URL . '/files/' . $itemId . '/thumbnail.png?min_height=' . $this->tmbSize . '&min_width=' . $this->tmbSize; + + $contents = $this->_bd_fetch($url, true); + return $contents; + } catch (Exception $e) { + return false; + } + } + + /** + * Remove item. + * + * @param string $path file path + * + * @return bool + **/ + protected function _bd_unlink($path, $type = null) + { + try { + list(, $itemId) = $this->_bd_splitPath($path); + + if ($type == 'folders') { + $url = self::API_URL . '/' . $type . '/' . $itemId . '?recursive=true'; + } else { + $url = self::API_URL . '/' . $type . '/' . $itemId; + } + + $curl = $this->_bd_prepareCurl(array( + CURLOPT_URL => $url, + CURLOPT_CUSTOMREQUEST => 'DELETE', + )); + + //unlink or delete File or Folder in the Parent + $this->_bd_curlExec($curl); + } catch (Exception $e) { + return $this->setError('Box error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Get AccessToken file path + * + * @return string ( description_of_the_return_value ) + */ + protected function _bd_getATokenFile() + { + $tmp = $aTokenFile = ''; + if (!empty($this->token->data->refresh_token)) { + if (!$this->tmp) { + $tmp = elFinder::getStaticVar('commonTempPath'); + if (!$tmp) { + $tmp = $this->getTempPath(); + } + $this->tmp = $tmp; + } + if ($tmp) { + $aTokenFile = $tmp . DIRECTORY_SEPARATOR . $this->_bd_getInitialToken() . '.btoken'; + } + } + return $aTokenFile; + } + + /** + * Get Initial Token (MD5 hash) + * + * @return string + */ + protected function _bd_getInitialToken() + { + return (empty($this->token->initialToken)? md5($this->options['client_id'] . (!empty($this->token->data->refresh_token)? $this->token->data->refresh_token : $this->token->data->access_token)) : $this->token->initialToken); + } + + /*********************************************************************/ + /* OVERRIDE FUNCTIONS */ + /*********************************************************************/ + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount(). + * + * @return array + * @author Naoki Sawada + * @author Raja Sharma updating for Box + **/ + public function netmountPrepare($options) + { + if (empty($options['client_id']) && defined('ELFINDER_BOX_CLIENTID')) { + $options['client_id'] = ELFINDER_BOX_CLIENTID; + } + if (empty($options['client_secret']) && defined('ELFINDER_BOX_CLIENTSECRET')) { + $options['client_secret'] = ELFINDER_BOX_CLIENTSECRET; + } + + if (isset($options['pass']) && $options['pass'] === 'reauth') { + $options['user'] = 'init'; + $options['pass'] = ''; + $this->session->remove('BoxTokens'); + } + + if (isset($options['id'])) { + $this->session->set('nodeId', $options['id']); + } else if ($_id = $this->session->get('nodeId')) { + $options['id'] = $_id; + $this->session->set('nodeId', $_id); + } + + if (!empty($options['tmpPath'])) { + if ((is_dir($options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($options['tmpPath'])) { + $this->tmp = $options['tmpPath']; + } + } + + try { + if (empty($options['client_id']) || empty($options['client_secret'])) { + return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}'); + } + + $itpCare = isset($options['code']); + $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : ''); + if ($code) { + try { + if (!empty($options['id'])) { + // Obtain the token using the code received by the Box.com API + $this->session->set('BoxTokens', + $this->_bd_obtainAccessToken($options['client_id'], $options['client_secret'], $code)); + + $out = array( + 'node' => $options['id'], + 'json' => '{"protocol": "box", "mode": "done", "reset": 1}', + 'bind' => 'netmount' + ); + } else { + $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host']; + $out = array( + 'node' => $nodeid, + 'json' => json_encode(array( + 'protocol' => 'box', + 'host' => $nodeid, + 'mode' => 'redirect', + 'options' => array( + 'id' => $nodeid, + 'code'=> $code + ) + )), + 'bind' => 'netmount' + ); + } + if (!$itpCare) { + return array('exit' => 'callback', 'out' => $out); + } else { + return array('exit' => true, 'body' => $out['json']); + } + } catch (Exception $e) { + $out = array( + 'node' => $options['id'], + 'json' => json_encode(array('error' => $e->getMessage())), + ); + + return array('exit' => 'callback', 'out' => $out); + } + } elseif (!empty($_GET['error'])) { + $out = array( + 'node' => $options['id'], + 'json' => json_encode(array('error' => elFinder::ERROR_ACCESS_DENIED)), + ); + + return array('exit' => 'callback', 'out' => $out); + } + + if ($options['user'] === 'init') { + $this->token = $this->session->get('BoxTokens'); + + if ($this->token) { + try { + $this->_bd_refreshToken(); + } catch (Exception $e) { + $this->setError($e->getMessage()); + $this->token = null; + $this->session->remove('BoxTokens'); + } + } + + if (empty($this->token)) { + $result = false; + } else { + $path = $options['path']; + if ($path === '/' || $path === 'root') { + $path = '0'; + } + $result = $this->_bd_query($path, $fetch_self = false, $recursive = false); + } + + if ($result === false) { + $redirect = elFinder::getConnectorUrl(); + $redirect .= (strpos($redirect, '?') !== false? '&' : '?') . 'cmd=netmount&protocol=box&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']); + + try { + $this->session->set('BoxTokens', (object)array('token' => null)); + $url = self::AUTH_URL . '?' . http_build_query(array('response_type' => 'code', 'client_id' => $options['client_id'], 'redirect_uri' => $redirect)); + } catch (Exception $e) { + return array('exit' => true, 'body' => '{msg:errAccess}'); + } + + $html = ''; + $html .= ''; + + return array('exit' => true, 'body' => $html); + } else { + $folders = []; + + if ($result) { + foreach ($result as $res) { + if ($res->type == 'folder') { + $folders[$res->id . ' '] = $res->name; + } + } + natcasesort($folders); + } + + if ($options['pass'] === 'folders') { + return ['exit' => true, 'folders' => $folders]; + } + + $folders = ['root' => 'My Box'] + $folders; + $folders = json_encode($folders); + + $expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0; + $mnt2res = empty($this->token->data->refresh_token) ? '' : ', "mnt2res": 1'; + $json = '{"protocol": "box", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res . '}'; + $html = 'Box.com'; + $html .= ''; + + return array('exit' => true, 'body' => $html); + } + } + } catch (Exception $e) { + return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}'); + } + + if ($_aToken = $this->session->get('BoxTokens')) { + $options['accessToken'] = json_encode($_aToken); + if ($this->options['path'] === 'root' || !$this->options['path']) { + $this->options['path'] = '/'; + } + } else { + $this->session->remove('BoxTokens'); + $this->setError(elFinder::ERROR_NETMOUNT, $options['host'], implode(' ', $this->error())); + + return array('exit' => true, 'error' => $this->error()); + } + + $this->session->remove('nodeId'); + unset($options['user'], $options['pass'], $options['id']); + + return $options; + } + + /** + * process of on netunmount + * Drop `box` & rm thumbs. + * + * @param $netVolumes + * @param $key + * + * @return bool + */ + public function netunmount($netVolumes, $key) + { + if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->tmbPrefix . '*.png')) { + foreach ($tmbs as $file) { + unlink($file); + } + } + + return true; + } + + /** + * Return debug info for client. + * + * @return array + **/ + public function debug() + { + $res = parent::debug(); + if (!empty($this->options['netkey']) && !empty($this->options['accessToken'])) { + $res['accessToken'] = $this->options['accessToken']; + } + + return $res; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare FTP connection + * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn. + * + * @return bool + * @throws Exception + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + */ + protected function init() + { + if (!$this->options['accessToken']) { + return $this->setError('Required option `accessToken` is undefined.'); + } + + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } + } + + $error = false; + try { + $this->token = json_decode($this->options['accessToken']); + if (!is_object($this->token)) { + throw new Exception('Required option `accessToken` is invalid JSON.'); + } + + // make net mount key + if (empty($this->options['netkey'])) { + $this->netMountKey = $this->_bd_getInitialToken(); + } else { + $this->netMountKey = $this->options['netkey']; + } + + if ($this->aTokenFile = $this->_bd_getATokenFile()) { + if (empty($this->options['netkey'])) { + if ($this->aTokenFile) { + if (is_file($this->aTokenFile)) { + $this->token = json_decode(file_get_contents($this->aTokenFile)); + if (!is_object($this->token)) { + unlink($this->aTokenFile); + throw new Exception('Required option `accessToken` is invalid JSON.'); + } + } else { + file_put_contents($this->aTokenFile, json_encode($this->token), LOCK_EX); + } + } + } else if (is_file($this->aTokenFile)) { + // If the refresh token is the same as the permanent volume + $this->token = json_decode(file_get_contents($this->aTokenFile)); + } + } + + $this->needOnline && $this->_bd_refreshToken(); + } catch (Exception $e) { + $this->token = null; + $error = true; + $this->setError($e->getMessage()); + } + + if ($this->netMountKey) { + $this->tmbPrefix = 'box' . base_convert($this->netMountKey, 16, 32); + } + + if ($error) { + if (empty($this->options['netkey']) && $this->tmbPrefix) { + // for delete thumbnail + $this->netunmount(null, null); + } + return false; + } + + // normalize root path + if ($this->options['path'] == 'root') { + $this->options['path'] = '/'; + } + + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + $this->options['root'] = ($this->options['root'] == '')? 'Box.com' : $this->options['root']; + + if (empty($this->options['alias'])) { + if ($this->needOnline) { + list(, $itemId) = $this->_bd_splitPath($this->options['path']); + $this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] : + $this->_bd_query($itemId, $fetch_self = true)->name . '@Box'; + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } else { + $this->options['alias'] = $this->options['root']; + } + } + + $this->rootName = $this->options['alias']; + + // This driver dose not support `syncChkAsTs` + $this->options['syncChkAsTs'] = false; + + // 'lsPlSleep' minmum 10 sec + $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']); + + // enable command archive + $this->options['useRemoteArchive'] = true; + + return true; + } + + /** + * Configure after successfull mount. + * + * @author Dmitry (dio) Levashov + * @throws elFinderAbortException + */ + protected function configure() + { + parent::configure(); + + // fallback of $this->tmp + if (!$this->tmp && $this->tmbPathWritable) { + $this->tmp = $this->tmbPath; + } + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection. + * + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + } + + /** + * Return fileinfo based on filename + * For item ID based path file system + * Please override if needed on each drivers. + * + * @param string $path file cache + * + * @return array|boolean + * @throws elFinderAbortException + */ + protected function isNameExists($path) + { + list(, $name, $parent) = $this->_bd_splitPath($path); + + // We can not use it because the search of Box.com there is a time lag. + // ref. https://docs.box.com/reference#searching-for-content + // > Note: If an item is added to Box then it becomes accessible through the search endpoint after ten minutes. + + /*** + * $url = self::API_URL.'/search?limit=1&offset=0&content_types=name&ancestor_folder_ids='.rawurlencode($pid) + * .'&query='.rawurlencode('"'.$name.'"') + * .'fields='.self::FETCHFIELDS; + * $raw = $this->_bd_fetch($url); + * if (is_array($raw) && count($raw)) { + * return $this->_bd_parseRaw($raw); + * } + ***/ + + $phash = $this->encode($parent); + + // do not recursive search + $searchExDirReg = $this->options['searchExDirReg']; + $this->options['searchExDirReg'] = '/.*/'; + $search = $this->search($name, array(), $phash); + $this->options['searchExDirReg'] = $searchExDirReg; + + if ($search) { + $f = false; + foreach($search as $f) { + if ($f['name'] !== $name) { + $f = false; + } + if ($f) { + break; + } + } + return $f; + } + + return false; + } + + /** + * Cache dir contents. + * + * @param string $path dir path + * + * @return + * @throws Exception + * @author Dmitry Levashov + */ + protected function cacheDir($path) + { + $this->dirsCache[$path] = array(); + $hasDir = false; + + if ($path == '/') { + $items = $this->_bd_query('0', $fetch_self = true); // get root directory with folder & files + $itemId = $items->id; + } else { + list(, $itemId) = $this->_bd_splitPath($path); + } + + $res = $this->_bd_query($itemId); + + if ($res) { + foreach ($res as $raw) { + if ($stat = $this->_bd_parseRaw($raw)) { + $itemPath = $this->_joinPath($path, $raw->id); + $stat = $this->updateCache($itemPath, $stat); + if (empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $itemPath; + } + } + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + + return $this->dirsCache[$path]; + } + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * + * @return string|false + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + **/ + protected function copy($src, $dst, $name) + { + if ($res = $this->_copy($src, $dst, $name)) { + $this->added[] = $this->stat($res); + return $res; + } else { + return $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + } + + /** + * Remove file/ recursive remove dir. + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function remove($path, $force = false) + { + $stat = $this->stat($path); + $stat['realpath'] = $path; + $this->rmTmb($stat); + $this->clearcache(); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path)); + } + + if ($stat['mime'] == 'directory') { + if (!$this->_rmdir($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } else { + if (!$this->_unlink($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } + + $this->removed[] = $stat; + + return true; + } + + /** + * Create thumnbnail and return it's URL on success. + * + * @param string $path file path + * @param $stat + * + * @return string|false + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function createTmb($path, $stat) + { + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name; + + // copy image into tmbPath so some drivers does not store files on local fs + if (!$data = $this->_bd_getThumbnail($path)) { + // try get full contents as fallback + if (!$data = $this->_getContents($path)) { + return false; + } + } + if (!file_put_contents($tmb, $data)) { + return false; + } + + $tmbSize = $this->tmbSize; + + if (($s = getimagesize($tmb)) == false) { + return false; + } + + $result = true; + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } else { + if ($this->options['tmbCrop']) { + + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if ($result && ($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0; + $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png'); + } + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); + } + + if ($result) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } + } + + if (!$result) { + unlink($tmb); + + return false; + } + + return $name; + } + + /** + * Return thumbnail file name for required file. + * + * @param array $stat file stat + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function tmbname($stat) + { + return $this->tmbPrefix . $stat['rev'] . $stat['ts'] . '.png'; + } + + /** + * Return content URL. + * + * @param object $raw data + * + * @return string + * @author Naoki Sawada + **/ + protected function getSharedWebContentLink($raw) + { + if ($raw->shared_link->url) { + return sprintf('https://app.box.com/index.php?rm=box_download_shared_file&shared_name=%s&file_id=f_%s', basename($raw->shared_link->url), $raw->id); + } elseif ($raw->shared_link->download_url) { + return $raw->shared_link->download_url; + } + + return false; + } + + /** + * Return content URL. + * + * @param string $hash file hash + * @param array $options options + * + * @return string + * @throws Exception + * @author Naoki Sawada + */ + public function getContentUrl($hash, $options = array()) + { + if (!empty($options['onetime']) && $this->options['onetimeUrl']) { + return parent::getContentUrl($hash, $options); + } + if (!empty($options['temporary'])) { + // try make temporary file + $url = parent::getContentUrl($hash, $options); + if ($url) { + return $url; + } + } + if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) { + $path = $this->decode($hash); + + list(, $itemId) = $this->_bd_splitPath($path); + $params['shared_link']['access'] = 'open'; //open|company|collaborators + + $url = self::API_URL . '/files/' . $itemId; + + $curl = $this->_bd_prepareCurl(array( + CURLOPT_URL => $url, + CURLOPT_CUSTOMREQUEST => 'PUT', + CURLOPT_POSTFIELDS => json_encode($params), + )); + $res = $this->_bd_curlExec($curl, true, array( + // The data is sent as JSON as per Box documentation. + 'Content-Type: application/json', + )); + + if ($url = $this->getSharedWebContentLink($res)) { + return $url; + } + } + + return ''; + } + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) + { + list(, , $dirname) = $this->_bd_splitPath($path); + + return $dirname; + } + + /** + * Return file name. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) + { + list(, $basename) = $this->_bd_splitPath($path); + + return $basename; + } + + /** + * Join dir name and file name and retur full path. + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + if (strval($dir) === '0') { + $dir = ''; + } + + return $this->_normpath($dir . '/' . $name); + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python. + * + * @param string $path path + * + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) + { + if (DIRECTORY_SEPARATOR !== '/') { + $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); + } + $path = '/' . ltrim($path, '/'); + + return $path; + } + + /** + * Return file path related to root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + return $path; + } + + /** + * Convert path related to root dir into real path. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) + { + return $path; + } + + /** + * Return fake path started from root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) + { + return $this->rootName . $this->_normpath(substr($path, strlen($this->root))); + } + + /** + * Return true if $path is children of $parent. + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) + { + return $path == $parent || strpos($path, $parent . '/') === 0; + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally. + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @throws Exception + * @author Dmitry (dio) Levashov + */ + protected function _stat($path) + { + if ($raw = $this->_bd_getRawItem($path)) { + return $this->_bd_parseRaw($raw); + } + + return false; + } + + /** + * Return true if path is dir and has at least one childs directory. + * + * @param string $path dir path + * + * @return bool + * @throws Exception + * @author Dmitry (dio) Levashov + */ + protected function _subdirs($path) + { + list(, $itemId) = $this->_bd_splitPath($path); + + $path = '/folders/' . $itemId . '/items?limit=1&offset=0&fields=' . self::FETCHFIELDS; + + $url = self::API_URL . $path; + + if ($res = $this->_bd_fetch($url)) { + if ($res[0]->type == 'folder') { + return true; + } + } + + return false; + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _dimensions($path, $mime) + { + if (strpos($mime, 'image') !== 0) { + return ''; + } + + $ret = ''; + if ($work = $this->getWorkFile($path)) { + if ($size = @getimagesize($work)) { + $cache['width'] = $size[0]; + $cache['height'] = $size[1]; + $ret = array('dim' => $size[0] . 'x' . $size[1]); + $srcfp = fopen($work, 'rb'); + $target = isset(elFinder::$currentArgs['target'])? elFinder::$currentArgs['target'] : ''; + if ($subImgLink = $this->getSubstituteImgLink($target, $size, $srcfp)) { + $ret['url'] = $subImgLink; + } + } + } + is_file($work) && @unlink($work); + + return $ret; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @throws Exception + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + */ + protected function _scandir($path) + { + return isset($this->dirsCache[$path]) + ? $this->dirsCache[$path] + : $this->cacheDir($path); + } + + /** + * Open file and return file pointer. + * + * @param string $path file path + * @param string $mode + * + * @return resource|false + * @author Dmitry (dio) Levashov + */ + protected function _fopen($path, $mode = 'rb') + { + if ($mode === 'rb' || $mode === 'r') { + list(, $itemId) = $this->_bd_splitPath($path); + $data = array( + 'target' => self::API_URL . '/files/' . $itemId . '/content', + 'headers' => array('Authorization: Bearer ' . $this->token->data->access_token), + ); + + // to support range request + if (func_num_args() > 2) { + $opts = func_get_arg(2); + } else { + $opts = array(); + } + if (!empty($opts['httpheaders'])) { + $data['headers'] = array_merge($opts['httpheaders'], $data['headers']); + } + + return elFinder::getStreamByUrl($data); + } + + return false; + } + + /** + * Close opened file. + * + * @param resource $fp file pointer + * @param string $path + * + * @return void + * @author Dmitry (dio) Levashov + */ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + if ($path) { + unlink($this->getTempFile($path)); + } + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed. + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + try { + list(, $parentId) = $this->_bd_splitPath($path); + $params = array('name' => $name, 'parent' => array('id' => $parentId)); + + $url = self::API_URL . '/folders'; + + $curl = $this->_bd_prepareCurl(array( + CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($params), + )); + + //create the Folder in the Parent + $folder = $this->_bd_curlExec($curl, $path); + + return $this->_joinPath($path, $folder->id); + } catch (Exception $e) { + return $this->setError('Box error: ' . $e->getMessage()); + } + } + + /** + * Create file and return it's path or false on failed. + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) + { + return $this->_save($this->tmpfile(), $path, $name, array()); + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _symlink($target, $path, $name) + { + return false; + } + + /** + * Copy file into another file. + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) + { + try { + //Set the Parent id + list(, $parentId) = $this->_bd_splitPath($targetDir); + list(, $srcId) = $this->_bd_splitPath($source); + + $srcItem = $this->_bd_getRawItem($source); + + $properties = array('name' => $name, 'parent' => array('id' => $parentId)); + $data = (object)$properties; + + $type = ($srcItem->type === 'folder') ? 'folders' : 'files'; + $url = self::API_URL . '/' . $type . '/' . $srcId . '/copy'; + + $curl = $this->_bd_prepareCurl(array( + CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($data), + )); + + //copy File in the Parent + $result = $this->_bd_curlExec($curl, $targetDir); + + if (isset($result->id)) { + if ($type === 'folders' && isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$targetDir] = true; + } + + return $this->_joinPath($targetDir, $result->id); + } + + return false; + } catch (Exception $e) { + return $this->setError('Box error: ' . $e->getMessage()); + } + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param string $target target dir path + * @param string $name file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _move($source, $targetDir, $name) + { + try { + //moving and renaming a file or directory + //Set new Parent and remove old parent + list(, $parentId) = $this->_bd_splitPath($targetDir); + list(, $itemId) = $this->_bd_splitPath($source); + + $srcItem = $this->_bd_getRawItem($source); + + //rename or move file or folder in destination target + $properties = array('name' => $name, 'parent' => array('id' => $parentId)); + + $type = ($srcItem->type === 'folder') ? 'folders' : 'files'; + $url = self::API_URL . '/' . $type . '/' . $itemId; + $data = (object)$properties; + + $curl = $this->_bd_prepareCurl(array( + CURLOPT_URL => $url, + CURLOPT_CUSTOMREQUEST => 'PUT', + CURLOPT_POSTFIELDS => json_encode($data), + )); + + $result = $this->_bd_curlExec($curl, $targetDir, array( + // The data is sent as JSON as per Box documentation. + 'Content-Type: application/json', + )); + + if ($result && isset($result->id)) { + return $this->_joinPath($targetDir, $result->id); + } + + return false; + } catch (Exception $e) { + return $this->setError('Box error: ' . $e->getMessage()); + } + } + + /** + * Remove file. + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + return $this->_bd_unlink($path, 'files'); + } + + /** + * Remove dir. + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + return $this->_bd_unlink($path, 'folders'); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + protected function _save($fp, $path, $name, $stat) + { + $itemId = ''; + if ($name === '') { + list($parentId, $itemId, $parent) = $this->_bd_splitPath($path); + } else { + if ($stat) { + if (isset($stat['name'])) { + $name = $stat['name']; + } + if (isset($stat['rev']) && strpos($stat['hash'], $this->id) === 0) { + $itemId = $stat['rev']; + } + } + list(, $parentId) = $this->_bd_splitPath($path); + $parent = $path; + } + + try { + //Create or Update a file + $metaDatas = stream_get_meta_data($fp); + $tmpFilePath = isset($metaDatas['uri']) ? $metaDatas['uri'] : ''; + // remote contents + if (!$tmpFilePath || empty($metaDatas['seekable'])) { + $tmpHandle = $this->tmpfile(); + stream_copy_to_stream($fp, $tmpHandle); + $metaDatas = stream_get_meta_data($tmpHandle); + $tmpFilePath = $metaDatas['uri']; + } + + if ($itemId === '') { + //upload or create new file in destination target + $properties = array('name' => $name, 'parent' => array('id' => $parentId)); + $url = self::UPLOAD_URL . '/files/content'; + } else { + //update existing file in destination target + $properties = array('name' => $name); + $url = self::UPLOAD_URL . '/files/' . $itemId . '/content'; + } + + if (class_exists('CURLFile')) { + $cfile = new CURLFile($tmpFilePath); + } else { + $cfile = '@' . $tmpFilePath; + } + $params = array('attributes' => json_encode($properties), 'file' => $cfile); + $curl = $this->_bd_prepareCurl(array( + CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params, + )); + + $file = $this->_bd_curlExec($curl, $parent); + + return $this->_joinPath($parent, $file->entries[0]->id); + } catch (Exception $e) { + return $this->setError('Box error: ' . $e->getMessage()); + } + } + + /** + * Get file contents. + * + * @param string $path file path + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) + { + try { + list(, $itemId) = $this->_bd_splitPath($path); + $url = self::API_URL . '/files/' . $itemId . '/content'; + + $contents = $this->_bd_fetch($url, true); + } catch (Exception $e) { + return $this->setError('Box error: ' . $e->getMessage()); + } + + return $contents; + } + + /** + * Write a string to a file. + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + $res = false; + + if ($local = $this->getTempFile($path)) { + if (file_put_contents($local, $content, LOCK_EX) !== false + && ($fp = fopen($local, 'rb'))) { + clearstatcache(); + $res = $this->_save($fp, $path, '', array()); + fclose($fp); + } + file_exists($local) && unlink($local); + } + + return $res; + } + + /** + * Detect available archivers. + **/ + protected function _checkArchivers() + { + // die('Not yet implemented. (_checkArchivers)'); + return array(); + } + + /** + * chmod implementation. + * + * @return bool + **/ + protected function _chmod($path, $mode) + { + return false; + } + + /** + * Extract files from archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return true + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _extract($path, $arc) + { + die('Not yet implemented. (_extract)'); + } + + /** + * Create archive and return its path. + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) + { + die('Not yet implemented. (_archive)'); + } +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeDriver.class.php b/lib/redactor/elfinder/php/elFinderVolumeDriver.class.php new file mode 100644 index 0000000..7df8d25 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeDriver.class.php @@ -0,0 +1,7666 @@ + array(), + 'extract' => array() + ); + + /** + * Static var of $this->options['maxArcFilesSize'] + * + * @var int|string + */ + protected static $maxArcFilesSize; + + /** + * Server character encoding + * + * @var string or null + **/ + protected $encoding = null; + + /** + * How many subdirs levels return for tree + * + * @var int + **/ + protected $treeDeep = 1; + + /** + * Errors from last failed action + * + * @var array + **/ + protected $error = array(); + + /** + * Today 24:00 timestamp + * + * @var int + **/ + protected $today = 0; + + /** + * Yesterday 24:00 timestamp + * + * @var int + **/ + protected $yesterday = 0; + + /** + * Force make dirctory on extract + * + * @var int + **/ + protected $extractToNewdir = 'auto'; + + /** + * Object configuration + * + * @var array + **/ + protected $options = array( + // Driver ID (Prefix of volume ID), Normally, the value specified for each volume driver is used. + 'driverId' => '', + // Id (Suffix of volume ID), Normally, the number incremented according to the specified number of volumes is used. + 'id' => '', + // revision id of root directory that uses for caching control of root stat + 'rootRev' => '', + // driver type it uses volume root's CSS class name. e.g. 'group' -> Adds 'elfinder-group' to CSS class name. + 'type' => '', + // root directory path + 'path' => '', + // Folder hash value on elFinder to be the parent of this volume + 'phash' => '', + // Folder hash value on elFinder to trash bin of this volume, it require 'copyJoin' to true + 'trashHash' => '', + // open this path on initial request instead of root path + 'startPath' => '', + // how many subdirs levels return per request + 'treeDeep' => 1, + // root url, not set to URL via the connector. If you want to hide the file URL, do not set this value. (replacement for old "fileURL" option) + 'URL' => '', + // enable onetime URL to a file - (true, false, 'auto' (true if a temporary directory is available) or callable (A function that return onetime URL)) + 'onetimeUrl' => 'auto', + // directory link url to own manager url with folder hash (`true`, `false`, `'hide'`(No show) or default `'auto'`: URL is empty then `true` else `false`) + 'dirUrlOwn' => 'auto', + // directory separator. required by client to show paths correctly + 'separator' => DIRECTORY_SEPARATOR, + // Use '/' as directory separator when the path hash encode/decode on the Windows server too + 'winHashFix' => false, + // Server character encoding (default is '': UTF-8) + 'encoding' => '', + // for convert character encoding (default is '': Not change locale) + 'locale' => '', + // URL of volume icon image + 'icon' => '', + // CSS Class of volume root in tree + 'rootCssClass' => '', + // Items to disable session caching + 'noSessionCache' => array(), + // enable i18n folder name that convert name to elFinderInstance.messages['folder_'+name] + 'i18nFolderName' => false, + // Search timeout (sec) + 'searchTimeout' => 30, + // Search exclusion directory regex pattern (require demiliter e.g. '#/path/to/exclude_directory#i') + 'searchExDirReg' => '', + // library to crypt/uncrypt files names (not implemented) + 'cryptLib' => '', + // how to detect files mimetypes. (auto/internal/finfo/mime_content_type) + 'mimeDetect' => 'auto', + // mime.types file path (for mimeDetect==internal) + 'mimefile' => '', + // Static extension/MIME of general server side scripts to security issues + 'staticMineMap' => array( + 'php:*' => 'text/x-php', + 'pht:*' => 'text/x-php', + 'php3:*' => 'text/x-php', + 'php4:*' => 'text/x-php', + 'php5:*' => 'text/x-php', + 'php7:*' => 'text/x-php', + 'php8:*' => 'text/x-php', + 'php9:*' => 'text/x-php', + 'phtml:*' => 'text/x-php', + 'phar:*' => 'text/x-php', + 'cgi:*' => 'text/x-httpd-cgi', + 'pl:*' => 'text/x-perl', + 'asp:*' => 'text/x-asap', + 'aspx:*' => 'text/x-asap', + 'py:*' => 'text/x-python', + 'rb:*' => 'text/x-ruby', + 'jsp:*' => 'text/x-jsp' + ), + // mime type normalize map : Array '[ext]:[detected mime type]' => '[normalized mime]' + 'mimeMap' => array( + 'md:application/x-genesis-rom' => 'text/x-markdown', + 'md:text/plain' => 'text/x-markdown', + 'markdown:text/plain' => 'text/x-markdown', + 'css:text/x-asm' => 'text/css', + 'css:text/plain' => 'text/css', + 'csv:text/plain' => 'text/csv', + 'java:text/x-c' => 'text/x-java-source', + 'json:text/plain' => 'application/json', + 'sql:text/plain' => 'text/x-sql', + 'rtf:text/rtf' => 'application/rtf', + 'rtfd:text/rtfd' => 'application/rtfd', + 'ico:image/vnd.microsoft.icon' => 'image/x-icon', + 'svg:text/plain' => 'image/svg+xml', + 'pxd:application/octet-stream' => 'image/x-pixlr-data', + 'dng:image/tiff' => 'image/x-adobe-dng', + 'sketch:application/zip' => 'image/x-sketch', + 'sketch:application/octet-stream' => 'image/x-sketch', + 'xcf:application/octet-stream' => 'image/x-xcf', + 'amr:application/octet-stream' => 'audio/amr', + 'm4a:video/mp4' => 'audio/mp4', + 'oga:application/ogg' => 'audio/ogg', + 'ogv:application/ogg' => 'video/ogg', + 'zip:application/x-zip' => 'application/zip', + 'm3u8:text/plain' => 'application/x-mpegURL', + 'mpd:text/plain' => 'application/dash+xml', + 'mpd:application/xml' => 'application/dash+xml', + '*:application/x-dosexec' => 'application/x-executable', + 'doc:application/vnd.ms-office' => 'application/msword', + 'xls:application/vnd.ms-office' => 'application/vnd.ms-excel', + 'ppt:application/vnd.ms-office' => 'application/vnd.ms-powerpoint', + 'yml:text/plain' => 'text/x-yaml', + 'ai:application/pdf' => 'application/postscript', + 'cgm:text/plain' => 'image/cgm', + 'dxf:text/plain' => 'image/vnd.dxf', + 'dds:application/octet-stream' => 'image/vnd-ms.dds', + 'hpgl:text/plain' => 'application/vnd.hp-hpgl', + 'igs:text/plain' => 'model/iges', + 'iges:text/plain' => 'model/iges', + 'plt:application/octet-stream' => 'application/plt', + 'plt:text/plain' => 'application/plt', + 'sat:text/plain' => 'application/sat', + 'step:text/plain' => 'application/step', + 'stp:text/plain' => 'application/step' + ), + // An option to add MimeMap to the `mimeMap` option + // Array '[ext]:[detected mime type]' => '[normalized mime]' + 'additionalMimeMap' => array(), + // MIME-Type of filetype detected as unknown + 'mimeTypeUnknown' => 'application/octet-stream', + // MIME regex of send HTTP header "Content-Disposition: inline" or allow preview in quicklook + // '.' is allow inline of all of MIME types + // '$^' is not allow inline of all of MIME types + 'dispInlineRegex' => '^(?:(?:video|audio)|image/(?!.+\+xml)|application/(?:ogg|x-mpegURL|dash\+xml)|(?:text/plain|application/pdf)$)', + // temporary content URL's base path + 'tmpLinkPath' => '', + // temporary content URL's base URL + 'tmpLinkUrl' => '', + // directory for thumbnails + 'tmbPath' => '.tmb', + // mode to create thumbnails dir + 'tmbPathMode' => 0777, + // thumbnails dir URL. Set it if store thumbnails outside root directory + 'tmbURL' => '', + // thumbnails size (px) + 'tmbSize' => 48, + // thumbnails crop (true - crop, false - scale image to fit thumbnail size) + 'tmbCrop' => true, + // thumbnail URL require custom data as the GET query + 'tmbReqCustomData' => false, + // thumbnails background color (hex #rrggbb or 'transparent') + 'tmbBgColor' => 'transparent', + // image rotate fallback background color (hex #rrggbb) + 'bgColorFb' => '#ffffff', + // image manipulations library (imagick|gd|convert|auto|none, none - Does not check the image library at all.) + 'imgLib' => 'auto', + // Fallback self image to thumbnail (nothing imgLib) + 'tmbFbSelf' => true, + // Video to Image converters ['TYPE or MIME' => ['func' => function($file){ /* Converts $file to Image */ return true; }, 'maxlen' => (int)TransferLength]] + 'imgConverter' => array(), + // Max length of transfer to image converter + 'tmbVideoConvLen' => 10000000, + // Captre point seccond + 'tmbVideoConvSec' => 6, + // Life time (hour) for thumbnail garbage collection ("0" means no GC) + 'tmbGcMaxlifeHour' => 0, + // Percentage of garbage collection executed for thumbnail creation command ("1" means "1%") + 'tmbGcPercentage' => 1, + // Resource path of fallback icon images defailt: php/resouces + 'resourcePath' => '', + // Jpeg image saveing quality + 'jpgQuality' => 100, + // Save as progressive JPEG on image editing + 'jpgProgressive' => true, + // enable to get substitute image with command `dim` + 'substituteImg' => true, + // on paste file - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext + 'copyOverwrite' => true, + // if true - join new and old directories content on paste + 'copyJoin' => true, + // on upload - if true - old file will be replaced with new one, if false new file get name - original_name-number.ext + 'uploadOverwrite' => true, + // mimetypes allowed to upload + 'uploadAllow' => array(), + // mimetypes not allowed to upload + 'uploadDeny' => array(), + // order to process uploadAllow and uploadDeny options + 'uploadOrder' => array('deny', 'allow'), + // maximum upload file size. NOTE - this is size for every uploaded files + 'uploadMaxSize' => 0, + // Maximum number of folders that can be created at one time. (0: unlimited) + 'uploadMaxMkdirs' => 0, + // maximum number of chunked upload connection. `-1` to disable chunked upload + 'uploadMaxConn' => 3, + // maximum get file size. NOTE - Maximum value is 50% of PHP memory_limit + 'getMaxSize' => 0, + // files dates format + 'dateFormat' => 'j M Y H:i', + // files time format + 'timeFormat' => 'H:i', + // if true - every folder will be check for children folders, -1 - every folder will be check asynchronously, false - all folders will be marked as having subfolders + 'checkSubfolders' => true, // true, false or -1 + // allow to copy from this volume to other ones? + 'copyFrom' => true, + // allow to copy from other volumes to this one? + 'copyTo' => true, + // cmd duplicate suffix format e.g. '_%s_' to without spaces + 'duplicateSuffix' => ' %s ', + // unique name numbar format e.g. '(%d)' to (1), (2)... + 'uniqueNumFormat' => '%d', + // list of commands disabled on this root + 'disabled' => array(), + // enable file owner, group & mode info, `false` to inactivate "chmod" command. + 'statOwner' => false, + // allow exec chmod of read-only files + 'allowChmodReadOnly' => false, + // regexp or function name to validate new file name + 'acceptedName' => '/^[^\.].*/', // Notice: overwritten it in some volume drivers contractor + // regexp or function name to validate new directory name + 'acceptedDirname' => '', // used `acceptedName` if empty value + // function/class method to control files permissions + 'accessControl' => null, + // some data required by access control + 'accessControlData' => null, + // root stat that return without asking the system when mounted and not the current volume. Query to the system with false. array|false + 'rapidRootStat' => array( + 'read' => true, + 'write' => true, + 'locked' => false, + 'hidden' => false, + 'size' => 0, // Unknown + 'ts' => 0, // Unknown + 'dirs' => -1, // Check on demand for subdirectories + 'mime' => 'directory' + ), + // default permissions. + 'defaults' => array( + 'read' => true, + 'write' => true, + 'locked' => false, + 'hidden' => false + ), + // files attributes + 'attributes' => array(), + // max allowed archive files size (0 - no limit) + 'maxArcFilesSize' => '2G', + // Allowed archive's mimetypes to create. Leave empty for all available types. + 'archiveMimes' => array(), + // Manual config for archivers. See example below. Leave empty for auto detect + 'archivers' => array(), + // Use Archive function for remote volume + 'useRemoteArchive' => false, + // plugin settings + 'plugin' => array(), + // Is support parent directory time stamp update on add|remove|rename item + // Default `null` is auto detection that is LocalFileSystem, FTP or Dropbox are `true` + 'syncChkAsTs' => null, + // Long pooling sync checker function for syncChkAsTs is true + // Calls with args (TARGET DIRCTORY PATH, STAND-BY(sec), OLD TIMESTAMP, VOLUME DRIVER INSTANCE, ELFINDER INSTANCE) + // This function must return the following values. Changed: New Timestamp or Same: Old Timestamp or Error: false + // Default `null` is try use elFinderVolumeLocalFileSystem::localFileSystemInotify() on LocalFileSystem driver + // another driver use elFinder stat() checker + 'syncCheckFunc' => null, + // Long polling sync stand-by time (sec) + 'plStandby' => 30, + // Sleep time (sec) for elFinder stat() checker (syncChkAsTs is true) + 'tsPlSleep' => 10, + // Sleep time (sec) for elFinder ls() checker (syncChkAsTs is false) + 'lsPlSleep' => 30, + // Client side sync interval minimum (ms) + // Default `null` is auto set to ('tsPlSleep' or 'lsPlSleep') * 1000 + // `0` to disable auto sync + 'syncMinMs' => null, + // required to fix bug on macos + // However, we recommend to use the Normalizer plugin instead this option + 'utf8fix' => false, + // й ё Й Ё Ø Å + 'utf8patterns' => array("\u0438\u0306", "\u0435\u0308", "\u0418\u0306", "\u0415\u0308", "\u00d8A", "\u030a"), + 'utf8replace' => array("\u0439", "\u0451", "\u0419", "\u0401", "\u00d8", "\u00c5"), + // cache control HTTP headers for commands `file` and `get` + 'cacheHeaders' => array( + 'Cache-Control: max-age=3600', + 'Expires:', + 'Pragma:' + ), + // Header to use to accelerate sending local files to clients (e.g. 'X-Sendfile', 'X-Accel-Redirect') + 'xsendfile' => '', + // Root path to xsendfile target. Probably, this is required for 'X-Accel-Redirect' on Nginx. + 'xsendfilePath' => '' + ); + + /** + * Defaults permissions + * + * @var array + **/ + protected $defaults = array( + 'read' => true, + 'write' => true, + 'locked' => false, + 'hidden' => false + ); + + /** + * Access control function/class + * + * @var mixed + **/ + protected $attributes = array(); + + /** + * Access control function/class + * + * @var mixed + **/ + protected $access = null; + + /** + * Mime types allowed to upload + * + * @var array + **/ + protected $uploadAllow = array(); + + /** + * Mime types denied to upload + * + * @var array + **/ + protected $uploadDeny = array(); + + /** + * Order to validate uploadAllow and uploadDeny + * + * @var array + **/ + protected $uploadOrder = array(); + + /** + * Maximum allowed upload file size. + * Set as number or string with unit - "10M", "500K", "1G" + * + * @var int|string + **/ + protected $uploadMaxSize = 0; + + /** + * Run time setting of overwrite items on upload + * + * @var string + */ + protected $uploadOverwrite = true; + + /** + * Maximum allowed get file size. + * Set as number or string with unit - "10M", "500K", "1G" + * + * @var int|string + **/ + protected $getMaxSize = -1; + + /** + * Mimetype detect method + * + * @var string + **/ + protected $mimeDetect = 'auto'; + + /** + * Flag - mimetypes from externail file was loaded + * + * @var bool + **/ + private static $mimetypesLoaded = false; + + /** + * Finfo resource for mimeDetect == 'finfo' + * + * @var resource + **/ + protected $finfo = null; + + /** + * List of disabled client's commands + * + * @var array + **/ + protected $disabled = array(); + + /** + * overwrite extensions/mimetypes to mime.types + * + * @var array + **/ + protected static $mimetypes = array( + // applications + 'exe' => 'application/x-executable', + 'jar' => 'application/x-jar', + // archives + 'gz' => 'application/x-gzip', + 'tgz' => 'application/x-gzip', + 'tbz' => 'application/x-bzip2', + 'rar' => 'application/x-rar', + // texts + 'php' => 'text/x-php', + 'js' => 'text/javascript', + 'rtfd' => 'application/rtfd', + 'py' => 'text/x-python', + 'rb' => 'text/x-ruby', + 'sh' => 'text/x-shellscript', + 'pl' => 'text/x-perl', + 'xml' => 'text/xml', + 'c' => 'text/x-csrc', + 'h' => 'text/x-chdr', + 'cpp' => 'text/x-c++src', + 'hh' => 'text/x-c++hdr', + 'md' => 'text/x-markdown', + 'markdown' => 'text/x-markdown', + 'yml' => 'text/x-yaml', + // images + 'bmp' => 'image/x-ms-bmp', + 'tga' => 'image/x-targa', + 'xbm' => 'image/xbm', + 'pxm' => 'image/pxm', + //audio + 'wav' => 'audio/wav', + // video + 'dv' => 'video/x-dv', + 'wm' => 'video/x-ms-wmv', + 'ogm' => 'video/ogg', + 'm2ts' => 'video/MP2T', + 'mts' => 'video/MP2T', + 'ts' => 'video/MP2T', + 'm3u8' => 'application/x-mpegURL', + 'mpd' => 'application/dash+xml' + ); + + /** + * Directory separator - required by client + * + * @var string + **/ + protected $separator = DIRECTORY_SEPARATOR; + + /** + * Directory separator for decode/encode hash + * + * @var string + **/ + protected $separatorForHash = ''; + + /** + * System Root path (Unix like: '/', Windows: '\', 'C:\' or 'D:\'...) + * + * @var string + **/ + protected $systemRoot = DIRECTORY_SEPARATOR; + + /** + * Mimetypes allowed to display + * + * @var array + **/ + protected $onlyMimes = array(); + + /** + * Store files moved or overwrited files info + * + * @var array + **/ + protected $removed = array(); + + /** + * Store files added files info + * + * @var array + **/ + protected $added = array(); + + /** + * Cache storage + * + * @var array + **/ + protected $cache = array(); + + /** + * Cache by folders + * + * @var array + **/ + protected $dirsCache = array(); + + /** + * You should use `$this->sessionCache['subdirs']` instead + * + * @var array + * @deprecated + */ + protected $subdirsCache = array(); + + /** + * This volume session cache + * + * @var array + */ + protected $sessionCache; + + /** + * Session caching item list + * + * @var array + */ + protected $sessionCaching = array('rootstat' => true, 'subdirs' => true); + + /** + * elFinder session wrapper object + * + * @var elFinderSessionInterface + */ + protected $session; + + /** + * Search start time + * + * @var int + */ + protected $searchStart; + + /** + * Current query word on doSearch + * + * @var array + **/ + protected $doSearchCurrentQuery = array(); + + /** + * Is root modified (for clear root stat cache) + * + * @var bool + */ + protected $rootModified = false; + + /** + * Is disable of command `url` + * + * @var string + */ + protected $disabledGetUrl = false; + + /** + * Accepted filename validator + * + * @var string | callable + */ + protected $nameValidator; + + /** + * Accepted dirname validator + * + * @var string | callable + */ + protected $dirnameValidator; + + /** + * This request require online state + * + * @var boolean + */ + protected $needOnline; + + /*********************************************************************/ + /* INITIALIZATION */ + /*********************************************************************/ + + /** + * Sets the need online. + * + * @param boolean $state The state + */ + public function setNeedOnline($state = null) + { + if ($state !== null) { + $this->needOnline = (bool)$state; + return; + } + + $need = false; + $arg = $this->ARGS; + $id = $this->id; + + $target = !empty($arg['target'])? $arg['target'] : (!empty($arg['dst'])? $arg['dst'] : ''); + $targets = !empty($arg['targets'])? $arg['targets'] : array(); + if (!is_array($targets)) { + $targets = array($targets); + } + + if ($target && strpos($target, $id) === 0) { + $need = true; + } else if ($targets) { + foreach($targets as $t) { + if ($t && strpos($t, $id) === 0) { + $need = true; + break; + } + } + } + + $this->needOnline = $need; + } + + /** + * Prepare driver before mount volume. + * Return true if volume is ready. + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function init() + { + return true; + } + + /** + * Configure after successfull mount. + * By default set thumbnails path and image manipulation library. + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function configure() + { + // set thumbnails path + $path = $this->options['tmbPath']; + if ($path) { + if (!file_exists($path)) { + if (mkdir($path)) { + chmod($path, $this->options['tmbPathMode']); + } else { + $path = ''; + } + } + + if (is_dir($path) && is_readable($path)) { + $this->tmbPath = $path; + $this->tmbPathWritable = is_writable($path); + } + } + // set resouce path + if (!is_dir($this->options['resourcePath'])) { + $this->options['resourcePath'] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'resources'; + } + + // set image manipulation library + $type = preg_match('/^(imagick|gd|convert|auto|none)$/i', $this->options['imgLib']) + ? strtolower($this->options['imgLib']) + : 'auto'; + + if ($type === 'none') { + $this->imgLib = ''; + } else { + if (($type === 'imagick' || $type === 'auto') && extension_loaded('imagick')) { + $this->imgLib = 'imagick'; + } else if (($type === 'gd' || $type === 'auto') && function_exists('gd_info')) { + $this->imgLib = 'gd'; + } else { + $convertCache = 'imgLibConvert'; + if (($convertCmd = $this->session->get($convertCache, false)) !== false) { + $this->imgLib = $convertCmd; + } else { + $this->imgLib = ($this->procExec(ELFINDER_CONVERT_PATH . ' -version') === 0) ? 'convert' : ''; + $this->session->set($convertCache, $this->imgLib); + } + } + if ($type !== 'auto' && $this->imgLib === '') { + // fallback + $this->imgLib = extension_loaded('imagick') ? 'imagick' : (function_exists('gd_info') ? 'gd' : ''); + } + } + + // check video to img converter + if (!empty($this->options['imgConverter']) && is_array($this->options['imgConverter'])) { + foreach ($this->options['imgConverter'] as $_type => $_converter) { + if (isset($_converter['func'])) { + $this->imgConverter[strtolower($_type)] = $_converter; + } + } + } + if (!isset($this->imgConverter['video'])) { + $videoLibCache = 'videoLib'; + if (($videoLibCmd = $this->session->get($videoLibCache, false)) === false) { + $videoLibCmd = ($this->procExec(ELFINDER_FFMPEG_PATH . ' -version') === 0) ? 'ffmpeg' : ''; + $this->session->set($videoLibCache, $videoLibCmd); + } + if ($videoLibCmd) { + $this->imgConverter['video'] = array( + 'func' => array($this, $videoLibCmd . 'ToImg'), + 'maxlen' => $this->options['tmbVideoConvLen'] + ); + } + } + + // check onetimeUrl + if (strtolower($this->options['onetimeUrl']) === 'auto') { + $this->options['onetimeUrl'] = elFinder::getStaticVar('commonTempPath')? true : false; + } + + // check archivers + if (empty($this->archivers['create'])) { + $this->disabled[] = 'archive'; + } + if (empty($this->archivers['extract'])) { + $this->disabled[] = 'extract'; + } + $_arc = $this->getArchivers(); + if (empty($_arc['create'])) { + $this->disabled[] = 'zipdl'; + } + + if ($this->options['maxArcFilesSize']) { + $this->options['maxArcFilesSize'] = elFinder::getIniBytes('', $this->options['maxArcFilesSize']); + } + self::$maxArcFilesSize = $this->options['maxArcFilesSize']; + + // check 'statOwner' for command `chmod` + if (empty($this->options['statOwner'])) { + $this->disabled[] = 'chmod'; + } + + // check 'mimeMap' + if (!is_array($this->options['mimeMap'])) { + $this->options['mimeMap'] = array(); + } + if (is_array($this->options['staticMineMap']) && $this->options['staticMineMap']) { + $this->options['mimeMap'] = array_merge($this->options['mimeMap'], $this->options['staticMineMap']); + } + if (is_array($this->options['additionalMimeMap']) && $this->options['additionalMimeMap']) { + $this->options['mimeMap'] = array_merge($this->options['mimeMap'], $this->options['additionalMimeMap']); + } + + // check 'url' in disabled commands + if (in_array('url', $this->disabled)) { + $this->disabledGetUrl = true; + } + + // set run time setting uploadOverwrite + $this->uploadOverwrite = $this->options['uploadOverwrite']; + } + + /** + * @deprecated + */ + protected function sessionRestart() + { + $this->sessionCache = $this->session->start()->get($this->id, array()); + return true; + } + + /*********************************************************************/ + /* PUBLIC API */ + /*********************************************************************/ + + /** + * Return driver id. Used as a part of volume id. + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function driverId() + { + return $this->driverId; + } + + /** + * Return volume id + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function id() + { + return $this->id; + } + + /** + * Assign elFinder session wrapper object + * + * @param $session elFinderSessionInterface + */ + public function setSession($session) + { + $this->session = $session; + } + + /** + * Get elFinder sesson wrapper object + * + * @return object The session object + */ + public function getSession() + { + return $this->session; + } + + /** + * Save session cache data + * Calls this function before umount this volume on elFinder::exec() + * + * @return void + */ + public function saveSessionCache() + { + $this->session->set($this->id, $this->sessionCache); + } + + /** + * Return debug info for client + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function debug() + { + return array( + 'id' => $this->id(), + 'name' => strtolower(substr(get_class($this), strlen('elfinderdriver'))), + 'mimeDetect' => $this->mimeDetect, + 'imgLib' => $this->imgLib + ); + } + + /** + * chmod a file or folder + * + * @param string $hash file or folder hash to chmod + * @param string $mode octal string representing new permissions + * + * @return array|false + * @author David Bartle + **/ + public function chmod($hash, $mode) + { + if ($this->commandDisabled('chmod')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!($file = $this->file($hash))) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$this->options['allowChmodReadOnly']) { + if (!$this->attr($this->decode($hash), 'write', null, ($file['mime'] === 'directory'))) { + return $this->setError(elFinder::ERROR_PERM_DENIED, $file['name']); + } + } + + $path = $this->decode($hash); + $write = $file['write']; + + if ($this->convEncOut(!$this->_chmod($this->convEncIn($path), $mode))) { + return $this->setError(elFinder::ERROR_PERM_DENIED, $file['name']); + } + + $this->clearstatcache(); + if ($path == $this->root) { + $this->rootModified = true; + } + + if ($file = $this->stat($path)) { + $files = array($file); + if ($file['mime'] === 'directory' && $write !== $file['write']) { + foreach ($this->getScandir($path) as $stat) { + if ($this->mimeAccepted($stat['mime'])) { + $files[] = $stat; + } + } + } + return $files; + } else { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + } + + /** + * stat a file or folder for elFinder cmd exec + * + * @param string $hash file or folder hash to chmod + * + * @return array + * @author Naoki Sawada + **/ + public function fstat($hash) + { + $path = $this->decode($hash); + return $this->stat($path); + } + + /** + * Clear PHP stat cache & all of inner stat caches + */ + public function clearstatcache() + { + clearstatcache(); + $this->clearcache(); + } + + /** + * Clear inner stat caches for target hash + * + * @param string $hash + */ + public function clearcaches($hash = null) + { + if ($hash === null) { + $this->clearcache(); + } else { + $path = $this->decode($hash); + unset($this->cache[$path], $this->dirsCache[$path]); + } + } + + /** + * "Mount" volume. + * Return true if volume available for read or write, + * false - otherwise + * + * @param array $opts + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + public function mount(array $opts) + { + $this->options = array_merge($this->options, $opts); + + if (!isset($this->options['path']) || $this->options['path'] === '') { + return $this->setError('Path undefined.'); + } + + if (!$this->session) { + return $this->setError('Session wrapper dose not set. Need to `$volume->setSession(elFinderSessionInterface);` before mount.'); + } + if (!($this->session instanceof elFinderSessionInterface)) { + return $this->setError('Session wrapper instance must be "elFinderSessionInterface".'); + } + + // set driverId + if (!empty($this->options['driverId'])) { + $this->driverId = $this->options['driverId']; + } + + $this->id = $this->driverId . (!empty($this->options['id']) ? $this->options['id'] : elFinder::$volumesCnt++) . '_'; + $this->root = $this->normpathCE($this->options['path']); + $this->separator = isset($this->options['separator']) ? $this->options['separator'] : DIRECTORY_SEPARATOR; + if (!empty($this->options['winHashFix'])) { + $this->separatorForHash = ($this->separator !== '/') ? '/' : ''; + } + $this->systemRoot = isset($this->options['systemRoot']) ? $this->options['systemRoot'] : $this->separator; + + // set ARGS + $this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST' ? $_POST : $_GET; + + $argInit = !empty($this->ARGS['init']); + + // set $this->needOnline + if (!is_bool($this->needOnline)) { + $this->setNeedOnline(); + } + + // session cache + if ($argInit) { + $this->session->set($this->id, array()); + } + $this->sessionCache = $this->session->get($this->id, array()); + + // default file attribute + $this->defaults = array( + 'read' => isset($this->options['defaults']['read']) ? !!$this->options['defaults']['read'] : true, + 'write' => isset($this->options['defaults']['write']) ? !!$this->options['defaults']['write'] : true, + 'locked' => isset($this->options['defaults']['locked']) ? !!$this->options['defaults']['locked'] : false, + 'hidden' => isset($this->options['defaults']['hidden']) ? !!$this->options['defaults']['hidden'] : false + ); + + // root attributes + $this->attributes[] = array( + 'pattern' => '~^' . preg_quote($this->separator) . '$~', + 'locked' => true, + 'hidden' => false + ); + // set files attributes + if (!empty($this->options['attributes']) && is_array($this->options['attributes'])) { + + foreach ($this->options['attributes'] as $a) { + // attributes must contain pattern and at least one rule + if (!empty($a['pattern']) || (is_array($a) && count($a) > 1)) { + $this->attributes[] = $a; + } + } + } + + if (!empty($this->options['accessControl']) && is_callable($this->options['accessControl'])) { + $this->access = $this->options['accessControl']; + } + + $this->today = mktime(0, 0, 0, date('m'), date('d'), date('Y')); + $this->yesterday = $this->today - 86400; + + if (!$this->init()) { + return false; + } + + // set server encoding + if (!empty($this->options['encoding']) && strtoupper($this->options['encoding']) !== 'UTF-8') { + $this->encoding = $this->options['encoding']; + } else { + $this->encoding = null; + } + + // check some options is arrays + $this->uploadAllow = isset($this->options['uploadAllow']) && is_array($this->options['uploadAllow']) + ? $this->options['uploadAllow'] + : array(); + + $this->uploadDeny = isset($this->options['uploadDeny']) && is_array($this->options['uploadDeny']) + ? $this->options['uploadDeny'] + : array(); + + $this->options['uiCmdMap'] = (isset($this->options['uiCmdMap']) && is_array($this->options['uiCmdMap'])) + ? $this->options['uiCmdMap'] + : array(); + + if (is_string($this->options['uploadOrder'])) { // telephat_mode on, compatibility with 1.x + $parts = explode(',', isset($this->options['uploadOrder']) ? $this->options['uploadOrder'] : 'deny,allow'); + $this->uploadOrder = array(trim($parts[0]), trim($parts[1])); + } else { // telephat_mode off + $this->uploadOrder = !empty($this->options['uploadOrder']) ? $this->options['uploadOrder'] : array('deny', 'allow'); + } + + if (!empty($this->options['uploadMaxSize'])) { + $this->uploadMaxSize = elFinder::getIniBytes('', $this->options['uploadMaxSize']); + } + // Set maximum to PHP_INT_MAX + if (!defined('PHP_INT_MAX')) { + define('PHP_INT_MAX', 2147483647); + } + if ($this->uploadMaxSize < 1 || $this->uploadMaxSize > PHP_INT_MAX) { + $this->uploadMaxSize = PHP_INT_MAX; + } + + // Set to get maximum size to 50% of memory_limit + $memLimit = elFinder::getIniBytes('memory_limit') / 2; + if ($memLimit > 0) { + $this->getMaxSize = empty($this->options['getMaxSize']) ? $memLimit : min($memLimit, elFinder::getIniBytes('', $this->options['getMaxSize'])); + } else { + $this->getMaxSize = -1; + } + + $this->disabled = isset($this->options['disabled']) && is_array($this->options['disabled']) + ? array_values(array_diff($this->options['disabled'], array('open'))) // 'open' is required + : array(); + + $this->cryptLib = $this->options['cryptLib']; + $this->mimeDetect = $this->options['mimeDetect']; + + // find available mimetype detect method + $regexp = '/text\/x\-(php|c\+\+)/'; + $auto_types = array(); + + if (class_exists('finfo', false)) { + $tmpFileInfo = explode(';', finfo_file(finfo_open(FILEINFO_MIME), __FILE__)); + if ($tmpFileInfo && preg_match($regexp, array_shift($tmpFileInfo))) { + $auto_types[] = 'finfo'; + } + } + + if (function_exists('mime_content_type')) { + $_mimetypes = explode(';', mime_content_type(__FILE__)); + if (preg_match($regexp, array_shift($_mimetypes))) { + $auto_types[] = 'mime_content_type'; + } + } + + $auto_types[] = 'internal'; + + $type = strtolower($this->options['mimeDetect']); + if (!in_array($type, $auto_types)) { + $type = 'auto'; + } + + if ($type == 'auto') { + $type = array_shift($auto_types); + } + + $this->mimeDetect = $type; + + if ($this->mimeDetect == 'finfo') { + $this->finfo = finfo_open(FILEINFO_MIME); + } else if ($this->mimeDetect == 'internal' && !elFinderVolumeDriver::$mimetypesLoaded) { + // load mimes from external file for mimeDetect == 'internal' + // based on Alexey Sukhotin idea and patch: http://elrte.org/redmine/issues/163 + // file must be in file directory or in parent one + elFinderVolumeDriver::loadMimeTypes(!empty($this->options['mimefile']) ? $this->options['mimefile'] : ''); + } + $this->rootName = empty($this->options['alias']) ? $this->basenameCE($this->root) : $this->options['alias']; + + // This get's triggered if $this->root == '/' and alias is empty. + // Maybe modify _basename instead? + if ($this->rootName === '') $this->rootName = $this->separator; + + $this->_checkArchivers(); + + $root = $this->stat($this->root); + + if (!$root) { + return $this->setError('Root folder does not exist.'); + } + if (!$root['read'] && !$root['write']) { + return $this->setError('Root folder has not read and write permissions.'); + } + + if ($root['read']) { + if ($argInit) { + // check startPath - path to open by default instead of root + $startPath = $this->options['startPath'] ? $this->normpathCE($this->options['startPath']) : ''; + if ($startPath) { + $start = $this->stat($startPath); + if (!empty($start) + && $start['mime'] == 'directory' + && $start['read'] + && empty($start['hidden']) + && $this->inpathCE($startPath, $this->root)) { + $this->startPath = $startPath; + if (substr($this->startPath, -1, 1) == $this->options['separator']) { + $this->startPath = substr($this->startPath, 0, -1); + } + } + } + } + } else { + $this->options['URL'] = ''; + $this->options['tmbURL'] = ''; + $this->options['tmbPath'] = ''; + // read only volume + array_unshift($this->attributes, array( + 'pattern' => '/.*/', + 'read' => false + )); + } + $this->treeDeep = $this->options['treeDeep'] > 0 ? (int)$this->options['treeDeep'] : 1; + $this->tmbSize = $this->options['tmbSize'] > 0 ? (int)$this->options['tmbSize'] : 48; + $this->URL = $this->options['URL']; + if ($this->URL && preg_match("|[^/?&=]$|", $this->URL)) { + $this->URL .= '/'; + } + + $dirUrlOwn = strtolower($this->options['dirUrlOwn']); + if ($dirUrlOwn === 'auto') { + $this->options['dirUrlOwn'] = $this->URL ? false : true; + } else if ($dirUrlOwn === 'hide') { + $this->options['dirUrlOwn'] = 'hide'; + } else { + $this->options['dirUrlOwn'] = (bool)$this->options['dirUrlOwn']; + } + + $this->tmbURL = !empty($this->options['tmbURL']) ? $this->options['tmbURL'] : ''; + if ($this->tmbURL && $this->tmbURL !== 'self' && preg_match("|[^/?&=]$|", $this->tmbURL)) { + $this->tmbURL .= '/'; + } + + $this->nameValidator = !empty($this->options['acceptedName']) && (is_string($this->options['acceptedName']) || is_callable($this->options['acceptedName'])) + ? $this->options['acceptedName'] + : ''; + + $this->dirnameValidator = !empty($this->options['acceptedDirname']) && (is_callable($this->options['acceptedDirname']) || (is_string($this->options['acceptedDirname']) && preg_match($this->options['acceptedDirname'], '') !== false)) + ? $this->options['acceptedDirname'] + : $this->nameValidator; + + // enabling archivers['create'] with options['useRemoteArchive'] + if ($this->options['useRemoteArchive'] && empty($this->archivers['create']) && $this->getTempPath()) { + $_archivers = $this->getArchivers(); + $this->archivers['create'] = $_archivers['create']; + } + + // manual control archive types to create + if (!empty($this->options['archiveMimes']) && is_array($this->options['archiveMimes'])) { + foreach ($this->archivers['create'] as $mime => $v) { + if (!in_array($mime, $this->options['archiveMimes'])) { + unset($this->archivers['create'][$mime]); + } + } + } + + // manualy add archivers + if (!empty($this->options['archivers']['create']) && is_array($this->options['archivers']['create'])) { + foreach ($this->options['archivers']['create'] as $mime => $conf) { + if (strpos($mime, 'application/') === 0 + && !empty($conf['cmd']) + && isset($conf['argc']) + && !empty($conf['ext']) + && !isset($this->archivers['create'][$mime])) { + $this->archivers['create'][$mime] = $conf; + } + } + } + + if (!empty($this->options['archivers']['extract']) && is_array($this->options['archivers']['extract'])) { + foreach ($this->options['archivers']['extract'] as $mime => $conf) { + if (strpos($mime, 'application/') === 0 + && !empty($conf['cmd']) + && isset($conf['argc']) + && !empty($conf['ext']) + && !isset($this->archivers['extract'][$mime])) { + $this->archivers['extract'][$mime] = $conf; + } + } + } + + if (!empty($this->options['noSessionCache']) && is_array($this->options['noSessionCache'])) { + foreach ($this->options['noSessionCache'] as $_key) { + $this->sessionCaching[$_key] = false; + unset($this->sessionCache[$_key]); + } + } + if ($this->sessionCaching['subdirs']) { + if (!isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'] = array(); + } + } + + + $this->configure(); + + // Normalize disabled (array_merge`for type array of JSON) + $this->disabled = array_values(array_unique($this->disabled)); + + // fix sync interval + if ($this->options['syncMinMs'] !== 0) { + $this->options['syncMinMs'] = max($this->options[$this->options['syncChkAsTs'] ? 'tsPlSleep' : 'lsPlSleep'] * 1000, intval($this->options['syncMinMs'])); + } + + // ` copyJoin` is required for the trash function + if ($this->options['trashHash'] && empty($this->options['copyJoin'])) { + $this->options['trashHash'] = ''; + } + + // set tmpLinkPath + if (elFinder::$tmpLinkPath && !$this->options['tmpLinkPath']) { + if (is_writeable(elFinder::$tmpLinkPath)) { + $this->options['tmpLinkPath'] = elFinder::$tmpLinkPath; + } else { + elFinder::$tmpLinkPath = ''; + } + } + if ($this->options['tmpLinkPath'] && is_writable($this->options['tmpLinkPath'])) { + $this->tmpLinkPath = realpath($this->options['tmpLinkPath']); + } else if (!$this->tmpLinkPath && $this->tmbURL && $this->tmbPath) { + $this->tmpLinkPath = $this->tmbPath; + $this->options['tmpLinkUrl'] = $this->tmbURL; + } else if (!$this->options['URL'] && is_writable('../files/.tmb')) { + $this->tmpLinkPath = realpath('../files/.tmb'); + $this->options['tmpLinkUrl'] = ''; + if (!elFinder::$tmpLinkPath) { + elFinder::$tmpLinkPath = $this->tmpLinkPath; + elFinder::$tmpLinkUrl = ''; + } + } + + // set tmpLinkUrl + if (elFinder::$tmpLinkUrl && !$this->options['tmpLinkUrl']) { + $this->options['tmpLinkUrl'] = elFinder::$tmpLinkUrl; + } + if ($this->options['tmpLinkUrl']) { + $this->tmpLinkUrl = $this->options['tmpLinkUrl']; + } + if ($this->tmpLinkPath && !$this->tmpLinkUrl) { + $cur = realpath('./'); + $i = 0; + while ($cur !== $this->systemRoot && strpos($this->tmpLinkPath, $cur) !== 0) { + $i++; + $cur = dirname($cur); + } + list($req) = explode('?', $_SERVER['REQUEST_URI']); + $reqs = explode('/', dirname($req)); + $uri = join('/', array_slice($reqs, 0, count($reqs) - 1)) . substr($this->tmpLinkPath, strlen($cur)); + $https = (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off'); + $this->tmpLinkUrl = ($https ? 'https://' : 'http://') + . $_SERVER['SERVER_NAME'] // host + . (((!$https && $_SERVER['SERVER_PORT'] == 80) || ($https && $_SERVER['SERVER_PORT'] == 443)) ? '' : (':' . $_SERVER['SERVER_PORT'])) // port + . $uri; + if (!elFinder::$tmpLinkUrl) { + elFinder::$tmpLinkUrl = $this->tmpLinkUrl; + } + } + + // remove last '/' + if ($this->tmpLinkPath) { + $this->tmpLinkPath = rtrim($this->tmpLinkPath, '/'); + } + if ($this->tmpLinkUrl) { + $this->tmpLinkUrl = rtrim($this->tmpLinkUrl, '/'); + } + + // to update options cache + if (isset($this->sessionCache['rootstat'])) { + unset($this->sessionCache['rootstat'][$this->getRootstatCachekey()]); + } + $this->updateCache($this->root, $root); + + return $this->mounted = true; + } + + /** + * Some "unmount" stuffs - may be required by virtual fs + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + } + + /** + * Remove session cache of this volume + */ + public function clearSessionCache() + { + $this->sessionCache = array(); + } + + /** + * Return error message from last failed action + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function error() + { + return $this->error; + } + + /** + * Return is uploadable that given file name + * + * @param string $name file name + * @param bool $allowUnknown + * + * @return bool + * @author Naoki Sawada + **/ + public function isUploadableByName($name, $allowUnknown = false) + { + $mimeByName = $this->mimetype($name, true); + return (($allowUnknown && $mimeByName === 'unknown') || $this->allowPutMime($mimeByName)); + } + + /** + * Return Extention/MIME Table (elFinderVolumeDriver::$mimetypes) + * + * @return array + * @author Naoki Sawada + */ + public function getMimeTable() + { + // load mime.types + if (!elFinderVolumeDriver::$mimetypesLoaded) { + elFinderVolumeDriver::loadMimeTypes(); + } + return elFinderVolumeDriver::$mimetypes; + } + + /** + * Return file extention detected by MIME type + * + * @param string $mime MIME type + * @param string $suffix Additional suffix + * + * @return string + * @author Naoki Sawada + */ + public function getExtentionByMime($mime, $suffix = '') + { + static $extTable = null; + + if (is_null($extTable)) { + $extTable = array_flip(array_unique($this->getMimeTable())); + foreach ($this->options['mimeMap'] as $pair => $_mime) { + list($ext) = explode(':', $pair); + if ($ext !== '*' && !isset($extTable[$_mime])) { + $extTable[$_mime] = $ext; + } + } + } + + if ($mime && isset($extTable[$mime])) { + return $suffix ? ($extTable[$mime] . $suffix) : $extTable[$mime]; + } + return ''; + } + + /** + * Set mimetypes allowed to display to client + * + * @param array $mimes + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function setMimesFilter($mimes) + { + if (is_array($mimes)) { + $this->onlyMimes = $mimes; + } + } + + /** + * Return root folder hash + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function root() + { + return $this->encode($this->root); + } + + /** + * Return root path + * + * @return string + * @author Naoki Sawada + **/ + public function getRootPath() + { + return $this->root; + } + + /** + * Return target path hash + * + * @param string $path + * @param string $name + * + * @author Naoki Sawada + * @return string + */ + public function getHash($path, $name = '') + { + if ($name !== '') { + $path = $this->joinPathCE($path, $name); + } + return $this->encode($path); + } + + /** + * Return decoded path of target hash + * This method do not check the stat of target + * Use method `realpath()` to do check of the stat of target + * + * @param string $hash + * + * @author Naoki Sawada + * @return string + */ + public function getPath($hash) + { + return $this->decode($hash); + } + + /** + * Return root or startPath hash + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function defaultPath() + { + return $this->encode($this->startPath ? $this->startPath : $this->root); + } + + /** + * Return volume options required by client: + * + * @param $hash + * + * @return array + * @author Dmitry (dio) Levashov + */ + public function options($hash) + { + $create = $createext = array(); + if (isset($this->archivers['create']) && is_array($this->archivers['create'])) { + foreach ($this->archivers['create'] as $m => $v) { + $create[] = $m; + $createext[$m] = $v['ext']; + } + } + $opts = array( + 'path' => $hash ? $this->path($hash) : '', + 'url' => $this->URL, + 'tmbUrl' => (!$this->imgLib && $this->options['tmbFbSelf']) ? 'self' : $this->tmbURL, + 'disabled' => $this->disabled, + 'separator' => $this->separator, + 'copyOverwrite' => intval($this->options['copyOverwrite']), + 'uploadOverwrite' => intval($this->options['uploadOverwrite']), + 'uploadMaxSize' => intval($this->uploadMaxSize), + 'uploadMaxConn' => intval($this->options['uploadMaxConn']), + 'uploadMime' => array( + 'firstOrder' => isset($this->uploadOrder[0]) ? $this->uploadOrder[0] : 'deny', + 'allow' => $this->uploadAllow, + 'deny' => $this->uploadDeny + ), + 'dispInlineRegex' => $this->options['dispInlineRegex'], + 'jpgQuality' => intval($this->options['jpgQuality']), + 'archivers' => array( + 'create' => $create, + 'extract' => isset($this->archivers['extract']) && is_array($this->archivers['extract']) ? array_keys($this->archivers['extract']) : array(), + 'createext' => $createext + ), + 'uiCmdMap' => (isset($this->options['uiCmdMap']) && is_array($this->options['uiCmdMap'])) ? $this->options['uiCmdMap'] : array(), + 'syncChkAsTs' => intval($this->options['syncChkAsTs']), + 'syncMinMs' => intval($this->options['syncMinMs']), + 'i18nFolderName' => intval($this->options['i18nFolderName']), + 'tmbCrop' => intval($this->options['tmbCrop']), + 'tmbReqCustomData' => (bool)$this->options['tmbReqCustomData'], + 'substituteImg' => (bool)$this->options['substituteImg'], + 'onetimeUrl' => (bool)$this->options['onetimeUrl'], + ); + if (!empty($this->options['trashHash'])) { + $opts['trashHash'] = $this->options['trashHash']; + } + if ($hash === null) { + // call from getRootStatExtra() + if (!empty($this->options['icon'])) { + $opts['icon'] = $this->options['icon']; + } + if (!empty($this->options['rootCssClass'])) { + $opts['csscls'] = $this->options['rootCssClass']; + } + if (isset($this->options['netkey'])) { + $opts['netkey'] = $this->options['netkey']; + } + } + return $opts; + } + + /** + * Get option value of this volume + * + * @param string $name target option name + * + * @return NULL|mixed target option value + * @author Naoki Sawada + */ + public function getOption($name) + { + return isset($this->options[$name]) ? $this->options[$name] : null; + } + + /** + * Get plugin values of this options + * + * @param string $name Plugin name + * + * @return NULL|array Plugin values + * @author Naoki Sawada + */ + public function getOptionsPlugin($name = '') + { + if ($name) { + return isset($this->options['plugin'][$name]) ? $this->options['plugin'][$name] : array(); + } else { + return $this->options['plugin']; + } + } + + /** + * Return true if command disabled in options + * + * @param string $cmd command name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function commandDisabled($cmd) + { + return in_array($cmd, $this->disabled); + } + + /** + * Return true if mime is required mimes list + * + * @param string $mime mime type to check + * @param array $mimes allowed mime types list or not set to use client mimes list + * @param bool|null $empty what to return on empty list + * + * @return bool|null + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ + public function mimeAccepted($mime, $mimes = null, $empty = true) + { + $mimes = is_array($mimes) ? $mimes : $this->onlyMimes; + if (empty($mimes)) { + return $empty; + } + return $mime == 'directory' + || in_array('all', $mimes) + || in_array('All', $mimes) + || in_array($mime, $mimes) + || in_array(substr($mime, 0, strpos($mime, '/')), $mimes); + } + + /** + * Return true if voume is readable. + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function isReadable() + { + $stat = $this->stat($this->root); + return $stat['read']; + } + + /** + * Return true if copy from this volume allowed + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + public function copyFromAllowed() + { + return !!$this->options['copyFrom']; + } + + /** + * Return file path related to root with convert encoging + * + * @param string $hash file hash + * + * @return string + * @author Dmitry (dio) Levashov + **/ + public function path($hash) + { + return $this->convEncOut($this->_path($this->convEncIn($this->decode($hash)))); + } + + /** + * Return file real path if file exists + * + * @param string $hash file hash + * + * @return string | false + * @author Dmitry (dio) Levashov + **/ + public function realpath($hash) + { + $path = $this->decode($hash); + return $this->stat($path) ? $path : false; + } + + /** + * Return list of moved/overwrited files + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function removed() + { + if ($this->removed) { + $unsetSubdir = isset($this->sessionCache['subdirs']) ? true : false; + foreach ($this->removed as $item) { + if ($item['mime'] === 'directory') { + $path = $this->decode($item['hash']); + if ($unsetSubdir) { + unset($this->sessionCache['subdirs'][$path]); + } + if ($item['phash'] !== '') { + $parent = $this->decode($item['phash']); + unset($this->cache[$parent]); + if ($this->root === $parent) { + $this->sessionCache['rootstat'] = array(); + } + if ($unsetSubdir) { + unset($this->sessionCache['subdirs'][$parent]); + } + } + } + } + $this->removed = array_values($this->removed); + } + return $this->removed; + } + + /** + * Return list of added files + * + * @deprecated + * @return array + * @author Naoki Sawada + **/ + public function added() + { + return $this->added; + } + + /** + * Clean removed files list + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function resetRemoved() + { + $this->resetResultStat(); + } + + /** + * Clean added/removed files list + * + * @return void + **/ + public function resetResultStat() + { + $this->removed = array(); + $this->added = array(); + } + + /** + * Return file/dir hash or first founded child hash with required attr == $val + * + * @param string $hash file hash + * @param string $attr attribute name + * @param bool $val attribute value + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + public function closest($hash, $attr, $val) + { + return ($path = $this->closestByAttr($this->decode($hash), $attr, $val)) ? $this->encode($path) : false; + } + + /** + * Return file info or false on error + * + * @param string $hash file hash + * + * @return array|false + * @internal param bool $realpath add realpath field to file info + * @author Dmitry (dio) Levashov + */ + public function file($hash) + { + $file = $this->stat($this->decode($hash)); + + return ($file) ? $file : $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + /** + * Return folder info + * + * @param string $hash folder hash + * @param bool $resolveLink + * + * @return array|false + * @internal param bool $hidden return hidden file info + * @author Dmitry (dio) Levashov + */ + public function dir($hash, $resolveLink = false) + { + if (($dir = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_DIR_NOT_FOUND); + } + + if ($resolveLink && !empty($dir['thash'])) { + $dir = $this->file($dir['thash']); + } + + return $dir && $dir['mime'] == 'directory' && empty($dir['hidden']) + ? $dir + : $this->setError(elFinder::ERROR_NOT_DIR); + } + + /** + * Return directory content or false on error + * + * @param string $hash file hash + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function scandir($hash) + { + if (($dir = $this->dir($hash)) == false) { + return false; + } + + $path = $this->decode($hash); + if ($res = $dir['read'] + ? $this->getScandir($path) + : $this->setError(elFinder::ERROR_PERM_DENIED)) { + + $dirs = null; + if ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$path])) { + $dirs = $this->sessionCache['subdirs'][$path]; + } + if ($dirs !== null || (isset($dir['dirs']) && $dir['dirs'] != 1)) { + $_dir = $dir; + if ($dirs || $this->subdirs($hash)) { + $dir['dirs'] = 1; + } else { + unset($dir['dirs']); + } + if ($dir !== $_dir) { + $this->updateCache($path, $dir); + } + } + } + + return $res; + } + + /** + * Return dir files names list + * + * @param string $hash file hash + * @param null $intersect + * + * @return array|false + * @author Dmitry (dio) Levashov + */ + public function ls($hash, $intersect = null) + { + if (($dir = $this->dir($hash)) == false || !$dir['read']) { + return false; + } + + $list = array(); + $path = $this->decode($hash); + + $check = array(); + if ($intersect) { + $check = array_flip($intersect); + } + + foreach ($this->getScandir($path) as $stat) { + if (empty($stat['hidden']) && (!$check || isset($check[$stat['name']])) && $this->mimeAccepted($stat['mime'])) { + $list[$stat['hash']] = $stat['name']; + } + } + + return $list; + } + + /** + * Return subfolders for required folder or false on error + * + * @param string $hash folder hash or empty string to get tree from root folder + * @param int $deep subdir deep + * @param string $exclude dir hash which subfolders must be exluded from result, required to not get stat twice on cwd subfolders + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function tree($hash = '', $deep = 0, $exclude = '') + { + $path = $hash ? $this->decode($hash) : $this->root; + + if (($dir = $this->stat($path)) == false || $dir['mime'] != 'directory') { + return false; + } + + $dirs = $this->gettree($path, $deep > 0 ? $deep - 1 : $this->treeDeep - 1, $exclude ? $this->decode($exclude) : null); + array_unshift($dirs, $dir); + return $dirs; + } + + /** + * Return part of dirs tree from required dir up to root dir + * + * @param string $hash directory hash + * @param bool|null $lineal only lineal parents + * + * @return array|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function parents($hash, $lineal = false) + { + if (($current = $this->dir($hash)) == false) { + return false; + } + + $args = func_get_args(); + // checks 3rd param `$until` (elFinder >= 2.1.24) + $until = ''; + if (isset($args[2])) { + $until = $args[2]; + } + + $path = $this->decode($hash); + $tree = array(); + + while ($path && $path != $this->root) { + elFinder::checkAborted(); + $path = $this->dirnameCE($path); + if (!($stat = $this->stat($path)) || !empty($stat['hidden']) || !$stat['read']) { + return false; + } + + array_unshift($tree, $stat); + if (!$lineal) { + foreach ($this->gettree($path, 0) as $dir) { + elFinder::checkAborted(); + if (!isset($tree[$dir['hash']])) { + $tree[$dir['hash']] = $dir; + } + } + } + + if ($until && $until === $this->encode($path)) { + break; + } + } + + return $tree ? array_values($tree) : array($current); + } + + /** + * Create thumbnail for required file and return its name or false on failed + * + * @param $hash + * + * @return false|string + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function tmb($hash) + { + $path = $this->decode($hash); + $stat = $this->stat($path); + + if (isset($stat['tmb'])) { + $res = $stat['tmb'] == "1" ? $this->createTmb($path, $stat) : $stat['tmb']; + if (!$res) { + list($type) = explode('/', $stat['mime']); + $fallback = $this->options['resourcePath'] . DIRECTORY_SEPARATOR . strtolower($type) . '.png'; + if (is_file($fallback)) { + $res = $this->tmbname($stat); + if (!copy($fallback, $this->tmbPath . DIRECTORY_SEPARATOR . $res)) { + $res = false; + } + } + } + // tmb garbage collection + if ($res && $this->options['tmbGcMaxlifeHour'] && $this->options['tmbGcPercentage'] > 0) { + $rand = mt_rand(1, 10000); + if ($rand <= $this->options['tmbGcPercentage'] * 100) { + register_shutdown_function(array('elFinder', 'GlobGC'), $this->tmbPath . DIRECTORY_SEPARATOR . '*.png', $this->options['tmbGcMaxlifeHour'] * 3600); + } + } + return $res; + } + return false; + } + + /** + * Return file size / total directory size + * + * @param string file hash + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function size($hash) + { + return $this->countSize($this->decode($hash)); + } + + /** + * Open file for reading and return file pointer + * + * @param string file hash + * + * @return Resource|false + * @author Dmitry (dio) Levashov + **/ + public function open($hash) + { + if (($file = $this->file($hash)) == false + || $file['mime'] == 'directory') { + return false; + } + // check extra option for network stream pointer + if (func_num_args() > 1) { + $opts = func_get_arg(1); + } else { + $opts = array(); + } + return $this->fopenCE($this->decode($hash), 'rb', $opts); + } + + /** + * Close file pointer + * + * @param Resource $fp file pointer + * @param string $hash file hash + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function close($fp, $hash) + { + $this->fcloseCE($fp, $this->decode($hash)); + } + + /** + * Create directory and return dir info + * + * @param string $dsthash destination directory hash + * @param string $name directory name + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function mkdir($dsthash, $name) + { + if ($this->commandDisabled('mkdir')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name, true)) { + return $this->setError(elFinder::ERROR_INVALID_DIRNAME); + } + + if (($dir = $this->dir($dsthash)) == false) { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#' . $dsthash); + } + + $path = $this->decode($dsthash); + + if (!$dir['write'] || !$this->allowCreate($path, $name, true)) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $dst = $this->joinPathCE($path, $name); + $stat = $this->isNameExists($dst); + if (!empty($stat)) { + return $this->setError(elFinder::ERROR_EXISTS, $name); + } + $this->clearcache(); + + $mkpath = $this->convEncOut($this->_mkdir($this->convEncIn($path), $this->convEncIn($name))); + if ($mkpath) { + $this->clearstatcache(); + $this->updateSubdirsCache($path, true); + $this->updateSubdirsCache($mkpath, false); + } + + return $mkpath ? $this->stat($mkpath) : false; + } + + /** + * Create empty file and return its info + * + * @param string $dst destination directory + * @param string $name file name + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function mkfile($dst, $name) + { + if ($this->commandDisabled('mkfile')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name, false)) { + return $this->setError(elFinder::ERROR_INVALID_NAME); + } + + $mimeByName = $this->mimetype($name, true); + if ($mimeByName && !$this->allowPutMime($mimeByName)) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $name); + } + + if (($dir = $this->dir($dst)) == false) { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#' . $dst); + } + + $path = $this->decode($dst); + + if (!$dir['write'] || !$this->allowCreate($path, $name, false)) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if ($this->isNameExists($this->joinPathCE($path, $name))) { + return $this->setError(elFinder::ERROR_EXISTS, $name); + } + + $this->clearcache(); + $res = false; + if ($path = $this->convEncOut($this->_mkfile($this->convEncIn($path), $this->convEncIn($name)))) { + $this->clearstatcache(); + $res = $this->stat($path); + } + return $res; + } + + /** + * Rename file and return file info + * + * @param string $hash file hash + * @param string $name new file name + * + * @return array|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function rename($hash, $name) + { + if ($this->commandDisabled('rename')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!($file = $this->file($hash))) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if ($name === $file['name']) { + return $file; + } + + if (!empty($this->options['netkey']) && !empty($file['isroot'])) { + // change alias of netmount root + $rootKey = $this->getRootstatCachekey(); + // delete old cache data + if ($this->sessionCaching['rootstat']) { + unset($this->sessionCaching['rootstat'][$rootKey]); + } + if (elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $name)) { + $this->clearcache(); + $this->rootName = $this->options['alias'] = $name; + return $this->stat($this->root); + } else { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, $name); + } + } + + if (!empty($file['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $file['name']); + } + + $isDir = ($file['mime'] === 'directory'); + + if (!$this->nameAccepted($name, $isDir)) { + return $this->setError($isDir ? elFinder::ERROR_INVALID_DIRNAME : elFinder::ERROR_INVALID_NAME); + } + + if (!$isDir) { + $mimeByName = $this->mimetype($name, true); + if ($mimeByName && !$this->allowPutMime($mimeByName)) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, $name); + } + } + + $path = $this->decode($hash); + $dir = $this->dirnameCE($path); + $stat = $this->isNameExists($this->joinPathCE($dir, $name)); + if ($stat) { + return $this->setError(elFinder::ERROR_EXISTS, $name); + } + + if (!$this->allowCreate($dir, $name, ($file['mime'] === 'directory'))) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $this->rmTmb($file); // remove old name tmbs, we cannot do this after dir move + + + if ($path = $this->convEncOut($this->_move($this->convEncIn($path), $this->convEncIn($dir), $this->convEncIn($name)))) { + $this->clearcache(); + return $this->stat($path); + } + return false; + } + + /** + * Create file copy with suffix "copy number" and return its info + * + * @param string $hash file hash + * @param string $suffix suffix to add to file name + * + * @return array|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function duplicate($hash, $suffix = 'copy') + { + if ($this->commandDisabled('duplicate')) { + return $this->setError(elFinder::ERROR_COPY, '#' . $hash, elFinder::ERROR_PERM_DENIED); + } + + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_COPY, elFinder::ERROR_FILE_NOT_FOUND); + } + + $path = $this->decode($hash); + $dir = $this->dirnameCE($path); + $name = $this->uniqueName($dir, $file['name'], sprintf($this->options['duplicateSuffix'], $suffix)); + + if (!$this->allowCreate($dir, $name, ($file['mime'] === 'directory'))) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + return ($path = $this->copy($path, $dir, $name)) == false + ? false + : $this->stat($path); + } + + /** + * Save uploaded file. + * On success return array with new file stat and with removed file hash (if existed file was replaced) + * + * @param Resource $fp file pointer + * @param string $dst destination folder hash + * @param $name + * @param string $tmpname file tmp name - required to detect mime type + * @param array $hashes exists files hash array with filename as key + * + * @return array|false + * @throws elFinderAbortException + * @internal param string $src file name + * @author Dmitry (dio) Levashov + */ + public function upload($fp, $dst, $name, $tmpname, $hashes = array()) + { + if ($this->commandDisabled('upload')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (($dir = $this->dir($dst)) == false) { + return $this->setError(elFinder::ERROR_TRGDIR_NOT_FOUND, '#' . $dst); + } + + if (empty($dir['write'])) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (!$this->nameAccepted($name, false)) { + return $this->setError(elFinder::ERROR_INVALID_NAME); + } + + $mimeByName = ''; + if ($this->mimeDetect === 'internal') { + $mime = $this->mimetype($tmpname, $name); + } else { + $mime = $this->mimetype($tmpname, $name); + $mimeByName = $this->mimetype($name, true); + if ($mime === 'unknown') { + $mime = $mimeByName; + } + } + + if (!$this->allowPutMime($mime) || ($mimeByName && !$this->allowPutMime($mimeByName))) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME, '(' . $mime . ')'); + } + + $tmpsize = (int)sprintf('%u', filesize($tmpname)); + if ($this->uploadMaxSize > 0 && $tmpsize > $this->uploadMaxSize) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE); + } + + $dstpath = $this->decode($dst); + if (isset($hashes[$name])) { + $test = $this->decode($hashes[$name]); + $file = $this->stat($test); + } else { + $test = $this->joinPathCE($dstpath, $name); + $file = $this->isNameExists($test); + } + + $this->clearcache(); + + if ($file && $file['name'] === $name) { // file exists and check filename for item ID based filesystem + if ($this->uploadOverwrite) { + if (!$file['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } elseif ($file['mime'] == 'directory') { + return $this->setError(elFinder::ERROR_NOT_REPLACE, $name); + } + $this->remove($test); + } else { + $name = $this->uniqueName($dstpath, $name, '-', false); + } + } + + $stat = array( + 'mime' => $mime, + 'width' => 0, + 'height' => 0, + 'size' => $tmpsize); + + // $w = $h = 0; + if (strpos($mime, 'image') === 0 && ($s = getimagesize($tmpname))) { + $stat['width'] = $s[0]; + $stat['height'] = $s[1]; + } + // $this->clearcache(); + if (($path = $this->saveCE($fp, $dstpath, $name, $stat)) == false) { + return false; + } + + $stat = $this->stat($path); + // Try get URL + if (empty($stat['url']) && ($url = $this->getContentUrl($stat['hash']))) { + $stat['url'] = $url; + } + + return $stat; + } + + /** + * Paste files + * + * @param Object $volume source volume + * @param $src + * @param string $dst destination dir hash + * @param bool $rmSrc remove source after copy? + * @param array $hashes + * + * @return array|false + * @throws elFinderAbortException + * @internal param string $source file hash + * @author Dmitry (dio) Levashov + */ + public function paste($volume, $src, $dst, $rmSrc = false, $hashes = array()) + { + $err = $rmSrc ? elFinder::ERROR_MOVE : elFinder::ERROR_COPY; + + if ($this->commandDisabled('paste')) { + return $this->setError($err, '#' . $src, elFinder::ERROR_PERM_DENIED); + } + + if (($file = $volume->file($src, $rmSrc)) == false) { + return $this->setError($err, '#' . $src, elFinder::ERROR_FILE_NOT_FOUND); + } + + $name = $file['name']; + $errpath = $volume->path($file['hash']); + + if (($dir = $this->dir($dst)) == false) { + return $this->setError($err, $errpath, elFinder::ERROR_TRGDIR_NOT_FOUND, '#' . $dst); + } + + if (!$dir['write'] || !$file['read']) { + return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); + } + + $destination = $this->decode($dst); + + if (($test = $volume->closest($src, $rmSrc ? 'locked' : 'read', $rmSrc))) { + return $rmSrc + ? $this->setError($err, $errpath, elFinder::ERROR_LOCKED, $volume->path($test)) + : $this->setError($err, $errpath, empty($file['thash']) ? elFinder::ERROR_PERM_DENIED : elFinder::ERROR_MKOUTLINK); + } + + if (isset($hashes[$name])) { + $test = $this->decode($hashes[$name]); + $stat = $this->stat($test); + } else { + $test = $this->joinPathCE($destination, $name); + $stat = $this->isNameExists($test); + } + $this->clearcache(); + $dstDirExists = false; + if ($stat && $stat['name'] === $name) { // file exists and check filename for item ID based filesystem + if ($this->options['copyOverwrite']) { + // do not replace file with dir or dir with file + if (!$this->isSameType($file['mime'], $stat['mime'])) { + return $this->setError(elFinder::ERROR_NOT_REPLACE, $this->path($stat['hash'])); + } + // existed file is not writable + if (empty($stat['write'])) { + return $this->setError($err, $errpath, elFinder::ERROR_PERM_DENIED); + } + if ($this->options['copyJoin']) { + if (!empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash'])); + } + } else { + // existed file locked or has locked child + if (($locked = $this->closestByAttr($test, 'locked', true))) { + $stat = $this->stat($locked); + return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash'])); + } + } + // target is entity file of alias + if ($volume === $this && ((isset($file['target']) && $test == $file['target']) || $test == $this->decode($src))) { + return $this->setError(elFinder::ERROR_REPLACE, $errpath); + } + // remove existed file + if (!$this->options['copyJoin'] || $stat['mime'] !== 'directory') { + if (!$this->remove($test)) { + return $this->setError(elFinder::ERROR_REPLACE, $this->path($stat['hash'])); + } + } else if ($stat['mime'] === 'directory') { + $dstDirExists = true; + } + } else { + $name = $this->uniqueName($destination, $name, ' ', false); + } + } + + // copy/move inside current volume + if ($volume === $this) { // changing == operand to === fixes issue #1285 - Paul Canning 24/03/2016 + $source = $this->decode($src); + // do not copy into itself + if ($this->inpathCE($destination, $source)) { + return $this->setError(elFinder::ERROR_COPY_ITSELF, $errpath); + } + $rmDir = false; + if ($rmSrc) { + if ($dstDirExists) { + $rmDir = true; + $method = 'copy'; + } else { + $method = 'move'; + } + } else { + $method = 'copy'; + } + $this->clearcache(); + if ($res = ($path = $this->$method($source, $destination, $name)) ? $this->stat($path) : false) { + if ($rmDir) { + $this->remove($source); + } + } else { + return false; + } + } else { + // copy/move from another volume + if (!$this->options['copyTo'] || !$volume->copyFromAllowed()) { + return $this->setError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED); + } + + $this->error = array(); + if (($path = $this->copyFrom($volume, $src, $destination, $name)) == false) { + return false; + } + + if ($rmSrc && !$this->error()) { + if (!$volume->rm($src)) { + if ($volume->file($src)) { + $this->addError(elFinder::ERROR_RM_SRC); + } else { + $this->removed[] = $file; + } + } + } + $res = $this->stat($path); + } + return $res; + } + + /** + * Return path info array to archive of target items + * + * @param array $hashes + * + * @return array|false + * @throws Exception + * @author Naoki Sawada + */ + public function zipdl($hashes) + { + if ($this->commandDisabled('zipdl')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $archivers = $this->getArchivers(); + $cmd = null; + if (!$archivers || empty($archivers['create'])) { + return false; + } + $archivers = $archivers['create']; + if (!$archivers) { + return false; + } + $file = $mime = ''; + foreach (array('zip', 'tgz') as $ext) { + $mime = $this->mimetype('file.' . $ext, true); + if (isset($archivers[$mime])) { + $cmd = $archivers[$mime]; + break; + } + } + if (!$cmd) { + $cmd = array_shift($archivers); + if (!empty($ext)) { + $mime = $this->mimetype('file.' . $ext, true); + } + } + $ext = $cmd['ext']; + $res = false; + $mixed = false; + $hashes = array_values($hashes); + $dirname = dirname(str_replace($this->separator, DIRECTORY_SEPARATOR, $this->path($hashes[0]))); + $cnt = count($hashes); + if ($cnt > 1) { + for ($i = 1; $i < $cnt; $i++) { + if ($dirname !== dirname(str_replace($this->separator, DIRECTORY_SEPARATOR, $this->path($hashes[$i])))) { + $mixed = true; + break; + } + } + } + if ($mixed || $this->root == $this->dirnameCE($this->decode($hashes[0]))) { + $prefix = $this->rootName; + } else { + $prefix = basename($dirname); + } + if ($dir = $this->getItemsInHand($hashes)) { + $tmppre = (substr(PHP_OS, 0, 3) === 'WIN') ? 'zd-' : 'elfzdl-'; + $pdir = dirname($dir); + // garbage collection (expire 2h) + register_shutdown_function(array('elFinder', 'GlobGC'), $pdir . DIRECTORY_SEPARATOR . $tmppre . '*', 7200); + $files = self::localScandir($dir); + if ($files && ($arc = tempnam($dir, $tmppre))) { + unlink($arc); + $arc = $arc . '.' . $ext; + $name = basename($arc); + if ($arc = $this->makeArchive($dir, $files, $name, $cmd)) { + $file = tempnam($pdir, $tmppre); + unlink($file); + $res = rename($arc, $file); + $this->rmdirRecursive($dir); + } + } + } + return $res ? array('path' => $file, 'ext' => $ext, 'mime' => $mime, 'prefix' => $prefix) : false; + } + + /** + * Return file contents + * + * @param string $hash file hash + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + public function getContents($hash) + { + $file = $this->file($hash); + + if (!$file) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if ($file['mime'] == 'directory') { + return $this->setError(elFinder::ERROR_NOT_FILE); + } + + if (!$file['read']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if ($this->getMaxSize > 0 && $file['size'] > $this->getMaxSize) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE); + } + + return $file['size'] ? $this->_getContents($this->convEncIn($this->decode($hash), true)) : ''; + } + + /** + * Put content in text file and return file info. + * + * @param string $hash file hash + * @param string $content new file content + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + public function putContents($hash, $content) + { + if ($this->commandDisabled('edit')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $path = $this->decode($hash); + + if (!($file = $this->file($hash))) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$file['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + // check data cheme + if (preg_match('~^\0data:(.+?/.+?);base64,~', $content, $m)) { + $dMime = $m[1]; + if ($file['size'] > 0 && $dMime !== $file['mime']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + $content = base64_decode(substr($content, strlen($m[0]))); + } + + // check MIME + $name = $this->basenameCE($path); + $mime = ''; + $mimeByName = $this->mimetype($name, true); + if ($this->mimeDetect !== 'internal') { + if ($tp = $this->tmpfile()) { + fwrite($tp, $content); + $info = stream_get_meta_data($tp); + $filepath = $info['uri']; + $mime = $this->mimetype($filepath, $name); + fclose($tp); + } + } + if (!$this->allowPutMime($mimeByName) || ($mime && !$this->allowPutMime($mime))) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_MIME); + } + + $this->clearcache(); + $res = false; + if ($this->convEncOut($this->_filePutContents($this->convEncIn($path), $content))) { + $this->rmTmb($file); + $this->clearstatcache(); + $res = $this->stat($path); + } + return $res; + } + + /** + * Extract files from archive + * + * @param string $hash archive hash + * @param null $makedir + * + * @return array|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + public function extract($hash, $makedir = null) + { + if ($this->commandDisabled('extract')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + $archiver = isset($this->archivers['extract'][$file['mime']]) + ? $this->archivers['extract'][$file['mime']] + : array(); + + if (!$archiver) { + return $this->setError(elFinder::ERROR_NOT_ARCHIVE); + } + + $path = $this->decode($hash); + $parent = $this->stat($this->dirnameCE($path)); + + if (!$file['read'] || !$parent['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + $this->clearcache(); + $this->extractToNewdir = is_null($makedir) ? 'auto' : (bool)$makedir; + + if ($path = $this->convEncOut($this->_extract($this->convEncIn($path), $archiver))) { + if (is_array($path)) { + foreach ($path as $_k => $_p) { + $path[$_k] = $this->stat($_p); + } + } else { + $path = $this->stat($path); + } + return $path; + } else { + return false; + } + } + + /** + * Add files to archive + * + * @param $hashes + * @param $mime + * @param string $name + * + * @return array|bool + * @throws Exception + */ + public function archive($hashes, $mime, $name = '') + { + if ($this->commandDisabled('archive')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if ($name !== '' && !$this->nameAccepted($name, false)) { + return $this->setError(elFinder::ERROR_INVALID_NAME); + } + + $archiver = isset($this->archivers['create'][$mime]) + ? $this->archivers['create'][$mime] + : array(); + + if (!$archiver) { + return $this->setError(elFinder::ERROR_ARCHIVE_TYPE); + } + + $files = array(); + $useRemoteArchive = !empty($this->options['useRemoteArchive']); + + $dir = ''; + foreach ($hashes as $hash) { + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND, '#' . $hash); + } + if (!$file['read']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + $path = $this->decode($hash); + if ($dir === '') { + $dir = $this->dirnameCE($path); + $stat = $this->stat($dir); + if (!$stat['write']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + } + + $files[] = $useRemoteArchive ? $hash : $this->basenameCE($path); + } + + if ($name === '') { + $name = count($files) == 1 ? $files[0] : 'Archive'; + } else { + $name = str_replace(array('/', '\\'), '_', preg_replace('/\.' . preg_quote($archiver['ext'], '/') . '$/i', '', $name)); + } + $name .= '.' . $archiver['ext']; + $name = $this->uniqueName($dir, $name, ''); + $this->clearcache(); + if ($useRemoteArchive) { + return ($path = $this->remoteArchive($files, $name, $archiver)) ? $this->stat($path) : false; + } else { + return ($path = $this->convEncOut($this->_archive($this->convEncIn($dir), $this->convEncIn($files), $this->convEncIn($name), $archiver))) ? $this->stat($path) : false; + } + } + + /** + * Create an archive from remote items + * + * @param array $hashes files hashes list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|boolean path of created archive + * @throws Exception + */ + protected function remoteArchive($hashes, $name, $arc) + { + $resPath = false; + $file0 = $this->file($hashes[0]); + if ($file0 && ($dir = $this->getItemsInHand($hashes))) { + $files = self::localScandir($dir); + if ($files) { + if ($arc = $this->makeArchive($dir, $files, $name, $arc)) { + if ($fp = fopen($arc, 'rb')) { + $fstat = stat($arc); + $stat = array( + 'size' => $fstat['size'], + 'ts' => $fstat['mtime'], + 'mime' => $this->mimetype($arc, $name) + ); + $path = $this->decode($file0['phash']); + $resPath = $this->saveCE($fp, $path, $name, $stat); + fclose($fp); + } + } + } + $this->rmdirRecursive($dir); + } + return $resPath; + } + + /** + * Resize image + * + * @param string $hash image file + * @param int $width new width + * @param int $height new height + * @param int $x X start poistion for crop + * @param int $y Y start poistion for crop + * @param string $mode action how to mainpulate image + * @param string $bg background color + * @param int $degree rotete degree + * @param int $jpgQuality JEPG quality (1-100) + * + * @return array|false + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + * @author nao-pon + * @author Troex Nevelin + */ + public function resize($hash, $width, $height, $x, $y, $mode = 'resize', $bg = '', $degree = 0, $jpgQuality = null) + { + if ($this->commandDisabled('resize')) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if ($mode === 'rotate' && $degree == 0) { + return array('losslessRotate' => ($this->procExec(ELFINDER_EXIFTRAN_PATH . ' -h') === 0 || $this->procExec(ELFINDER_JPEGTRAN_PATH . ' -version') === 0)); + } + + if (($file = $this->file($hash)) == false) { + return $this->setError(elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$file['write'] || !$file['read']) { + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + $path = $this->decode($hash); + + $work_path = $this->getWorkFile($this->encoding ? $this->convEncIn($path, true) : $path); + + if (!$work_path || !is_writable($work_path)) { + if ($work_path && $path !== $work_path && is_file($work_path)) { + unlink($work_path); + } + return $this->setError(elFinder::ERROR_PERM_DENIED); + } + + if ($this->imgLib !== 'imagick' && $this->imgLib !== 'convert') { + if (elFinder::isAnimationGif($work_path)) { + return $this->setError(elFinder::ERROR_UNSUPPORT_TYPE); + } + } + + if (elFinder::isAnimationPng($work_path)) { + return $this->setError(elFinder::ERROR_UNSUPPORT_TYPE); + } + + switch ($mode) { + + case 'propresize': + $result = $this->imgResize($work_path, $width, $height, true, true, null, $jpgQuality); + break; + + case 'crop': + $result = $this->imgCrop($work_path, $width, $height, $x, $y, null, $jpgQuality); + break; + + case 'fitsquare': + $result = $this->imgSquareFit($work_path, $width, $height, 'center', 'middle', ($bg ? $bg : $this->options['tmbBgColor']), null, $jpgQuality); + break; + + case 'rotate': + $result = $this->imgRotate($work_path, $degree, ($bg ? $bg : $this->options['bgColorFb']), null, $jpgQuality); + break; + + default: + $result = $this->imgResize($work_path, $width, $height, false, true, null, $jpgQuality); + break; + } + + $ret = false; + if ($result) { + $this->rmTmb($file); + $this->clearstatcache(); + $fstat = stat($work_path); + $imgsize = getimagesize($work_path); + if ($path !== $work_path) { + $file['size'] = $fstat['size']; + $file['ts'] = $fstat['mtime']; + if ($imgsize) { + $file['width'] = $imgsize[0]; + $file['height'] = $imgsize[1]; + } + if ($fp = fopen($work_path, 'rb')) { + $ret = $this->saveCE($fp, $this->dirnameCE($path), $this->basenameCE($path), $file); + fclose($fp); + } + } else { + $ret = true; + } + if ($ret) { + $this->clearcache(); + $ret = $this->stat($path); + if ($imgsize) { + $ret['width'] = $imgsize[0]; + $ret['height'] = $imgsize[1]; + } + } + } + if ($path !== $work_path) { + is_file($work_path) && unlink($work_path); + } + + return $ret; + } + + /** + * Remove file/dir + * + * @param string $hash file hash + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function rm($hash) + { + return $this->commandDisabled('rm') + ? $this->setError(elFinder::ERROR_PERM_DENIED) + : $this->remove($this->decode($hash)); + } + + /** + * Search files + * + * @param string $q search string + * @param array $mimes + * @param null $hash + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + public function search($q, $mimes, $hash = null) + { + $res = array(); + $matchMethod = null; + $args = func_get_args(); + if (!empty($args[3])) { + $matchMethod = 'searchMatch' . $args[3]; + if (!is_callable(array($this, $matchMethod))) { + return array(); + } + } + + $dir = null; + if ($hash) { + $dir = $this->decode($hash); + $stat = $this->stat($dir); + if (!$stat || $stat['mime'] !== 'directory' || !$stat['read']) { + $q = ''; + } + } + if ($mimes && $this->onlyMimes) { + $mimes = array_intersect($mimes, $this->onlyMimes); + if (!$mimes) { + $q = ''; + } + } + $this->searchStart = time(); + + $qs = preg_split('/"([^"]+)"| +/', $q, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $query = $excludes = array(); + foreach ($qs as $_q) { + $_q = trim($_q); + if ($_q !== '') { + if ($_q[0] === '-') { + if (isset($_q[1])) { + $excludes[] = substr($_q, 1); + } + } else { + $query[] = $_q; + } + } + } + if (!$query) { + $q = ''; + } else { + $q = join(' ', $query); + $this->doSearchCurrentQuery = array( + 'q' => $q, + 'excludes' => $excludes, + 'matchMethod' => $matchMethod + ); + } + + if ($q === '' || $this->commandDisabled('search')) { + return $res; + } + + // valided regex $this->options['searchExDirReg'] + if ($this->options['searchExDirReg']) { + if (false === preg_match($this->options['searchExDirReg'], '')) { + $this->options['searchExDirReg'] = ''; + } + } + + // check the leaf root too + if (!$mimes && (is_null($dir) || $dir == $this->root)) { + $rootStat = $this->stat($this->root); + if (!empty($rootStat['phash'])) { + if ($this->stripos($rootStat['name'], $q) !== false) { + $res = array($rootStat); + } + } + } + + return array_merge($res, $this->doSearch(is_null($dir) ? $this->root : $dir, $q, $mimes)); + } + + /** + * Return image dimensions + * + * @param string $hash file hash + * + * @return array|string + * @author Dmitry (dio) Levashov + **/ + public function dimensions($hash) + { + if (($file = $this->file($hash)) == false) { + return false; + } + // Throw additional parameters for some drivers + if (func_num_args() > 1) { + $args = func_get_arg(1); + } else { + $args = array(); + } + return $this->convEncOut($this->_dimensions($this->convEncIn($this->decode($hash)), $file['mime'], $args)); + } + + /** + * Return has subdirs + * + * @param string $hash file hash + * + * @return bool + * @author Naoki Sawada + **/ + public function subdirs($hash) + { + return (bool)$this->subdirsCE($this->decode($hash)); + } + + /** + * Return content URL (for netmout volume driver) + * If file.url == 1 requests from JavaScript client with XHR + * + * @param string $hash file hash + * @param array $options options array + * + * @return boolean|string + * @author Naoki Sawada + */ + public function getContentUrl($hash, $options = array()) + { + if (($file = $this->file($hash)) === false) { + return false; + } + if (!empty($options['onetime']) && $this->options['onetimeUrl']) { + if (is_callable($this->options['onetimeUrl'])) { + return call_user_func_array($this->options['onetimeUrl'], array($file, $options, $this)); + } else { + $ret = false; + if ($tmpdir = elFinder::getStaticVar('commonTempPath')) { + if ($source = $this->open($hash)) { + if ($_dat = tempnam($tmpdir, 'ELF')) { + $token = md5($_dat . session_id()); + $dat = $tmpdir . DIRECTORY_SEPARATOR . 'ELF' . $token; + if (rename($_dat, $dat)) { + $info = stream_get_meta_data($source); + if (!empty($info['uri'])) { + $tmp = $info['uri']; + } else { + $tmp = tempnam($tmpdir, 'ELF'); + if ($dest = fopen($tmp, 'wb')) { + if (!stream_copy_to_stream($source, $dest)) { + $tmp = false; + } + fclose($dest); + } + } + $this->close($source, $hash); + if ($tmp) { + $info = array( + 'file' => base64_encode($tmp), + 'name' => $file['name'], + 'mime' => $file['mime'], + 'ts' => $file['ts'] + ); + if (file_put_contents($dat, json_encode($info))) { + $conUrl = elFinder::getConnectorUrl(); + $ret = $conUrl . (strpos($conUrl, '?') !== false? '&' : '?') . 'cmd=file&onetime=1&target=' . $token; + + } + } + if (!$ret) { + unlink($dat); + } + } else { + unlink($_dat); + } + } + } + } + return $ret; + } + } + if (empty($file['url']) && $this->URL) { + $path = str_replace($this->separator, '/', substr($this->decode($hash), strlen(trim($this->root, '/' . $this->separator)))); + if ($this->encoding) { + $path = $this->convEncIn($path, true); + } + $path = str_replace('%2F', '/', rawurlencode($path)); + return $this->URL . $path; + } else { + $ret = false; + if (!empty($file['url']) && $file['url'] != 1) { + return $file['url']; + } else if (!empty($options['temporary']) && ($tempInfo = $this->getTempLinkInfo('temp_' . md5($hash . session_id())))) { + if (is_readable($tempInfo['path'])) { + touch($tempInfo['path']); + $ret = $tempInfo['url'] . '?' . rawurlencode($file['name']); + } else if ($source = $this->open($hash)) { + if ($dest = fopen($tempInfo['path'], 'wb')) { + if (stream_copy_to_stream($source, $dest)) { + $ret = $tempInfo['url'] . '?' . rawurlencode($file['name']); + } + fclose($dest); + } + $this->close($source, $hash); + } + } + return $ret; + } + } + + /** + * Get temporary contents link infomation + * + * @param string $name + * + * @return boolean|array + * @author Naoki Sawada + */ + public function getTempLinkInfo($name = null) + { + if ($this->tmpLinkPath) { + if (!$name) { + $name = 'temp_' . md5($_SERVER['REMOTE_ADDR'] . (string)microtime(true)); + } else if (substr($name, 0, 5) !== 'temp_') { + $name = 'temp_' . $name; + } + register_shutdown_function(array('elFinder', 'GlobGC'), $this->tmpLinkPath . DIRECTORY_SEPARATOR . 'temp_*', elFinder::$tmpLinkLifeTime); + return array( + 'path' => $path = $this->tmpLinkPath . DIRECTORY_SEPARATOR . $name, + 'url' => $this->tmpLinkUrl . '/' . rawurlencode($name) + ); + } + return false; + } + + /** + * Get URL of substitute image by request args `substitute` or 4th argument $maxSize + * + * @param string $target Target hash + * @param array $srcSize Size info array [width, height] + * @param resource $srcfp Source file file pointer + * @param integer $maxSize Maximum pixel of substitute image + * + * @return boolean + * @throws ImagickException + * @throws elFinderAbortException + */ + public function getSubstituteImgLink($target, $srcSize, $srcfp = null, $maxSize = null) + { + $url = false; + $file = $this->file($target); + $force = !in_array($file['mime'], array('image/jpeg', 'image/png', 'image/gif')); + if (!$maxSize) { + $args = elFinder::$currentArgs; + if (!empty($args['substitute'])) { + $maxSize = $args['substitute']; + } + } + if ($maxSize && $srcSize[0] && $srcSize[1]) { + if ($this->getOption('substituteImg')) { + $maxSize = intval($maxSize); + $zoom = min(($maxSize / $srcSize[0]), ($maxSize / $srcSize[1])); + if ($force || $zoom < 1) { + $width = round($srcSize[0] * $zoom); + $height = round($srcSize[1] * $zoom); + $jpgQuality = 50; + $preserveExif = false; + $unenlarge = true; + $checkAnimated = true; + $destformat = $file['mime'] === 'image/jpeg'? null : 'png'; + if (!$srcfp) { + elFinder::checkAborted(); + $srcfp = $this->open($target); + } + if ($srcfp && ($tempLink = $this->getTempLinkInfo())) { + elFinder::checkAborted(); + $dest = fopen($tempLink['path'], 'wb'); + if ($dest && stream_copy_to_stream($srcfp, $dest)) { + fclose($dest); + if ($this->imageUtil('resize', $tempLink['path'], compact('width', 'height', 'jpgQuality', 'preserveExif', 'unenlarge', 'checkAnimated', 'destformat'))) { + $url = $tempLink['url']; + // set expire to 1 min left + touch($tempLink['path'], time() - elFinder::$tmpLinkLifeTime + 60); + } else { + unlink($tempLink['path']); + } + } + $this->close($srcfp, $target); + } + } + } + } + + return $url; + } + + /** + * Return temp path + * + * @return string + * @author Naoki Sawada + */ + public function getTempPath() + { + $tempPath = null; + if (isset($this->tmpPath) && $this->tmpPath && is_writable($this->tmpPath)) { + $tempPath = $this->tmpPath; + } else if (isset($this->tmp) && $this->tmp && is_writable($this->tmp)) { + $tempPath = $this->tmp; + } else if (elFinder::getStaticVar('commonTempPath') && is_writable(elFinder::getStaticVar('commonTempPath'))) { + $tempPath = elFinder::getStaticVar('commonTempPath'); + } else if (function_exists('sys_get_temp_dir')) { + $tempPath = sys_get_temp_dir(); + } + + if ($tempPath && DIRECTORY_SEPARATOR !== '/') { + $tempPath = str_replace('/', DIRECTORY_SEPARATOR, $tempPath); + } + return $tempPath; + } + + /** + * (Make &) Get upload taget dirctory hash + * + * @param string $baseTargetHash + * @param string $path + * @param array $result + * + * @return boolean|string + * @author Naoki Sawada + */ + public function getUploadTaget($baseTargetHash, $path, & $result) + { + $base = $this->decode($baseTargetHash); + $targetHash = $baseTargetHash; + $path = ltrim($path, $this->separator); + $dirs = explode($this->separator, $path); + array_pop($dirs); + foreach ($dirs as $dir) { + $targetPath = $this->joinPathCE($base, $dir); + if (!$_realpath = $this->realpath($this->encode($targetPath))) { + if ($stat = $this->mkdir($targetHash, $dir)) { + $result['added'][] = $stat; + $targetHash = $stat['hash']; + $base = $this->decode($targetHash); + } else { + return false; + } + } else { + $targetHash = $this->encode($_realpath); + if ($this->dir($targetHash)) { + $base = $this->decode($targetHash); + } else { + return false; + } + } + } + return $targetHash; + } + + /** + * Return this uploadMaxSize value + * + * @return integer + * @author Naoki Sawada + */ + public function getUploadMaxSize() + { + return $this->uploadMaxSize; + } + + public function setUploadOverwrite($var) + { + $this->uploadOverwrite = (bool)$var; + } + + /** + * Image file utility + * + * @param string $mode 'resize', 'rotate', 'propresize', 'crop', 'fitsquare' + * @param string $src Image file local path + * @param array $options excute options + * + * @return bool + * @throws ImagickException + * @throws elFinderAbortException + * @author Naoki Sawada + */ + public function imageUtil($mode, $src, $options = array()) + { + if (!isset($options['jpgQuality'])) { + $options['jpgQuality'] = intval($this->options['jpgQuality']); + } + if (!isset($options['bgcolor'])) { + $options['bgcolor'] = '#ffffff'; + } + if (!isset($options['bgColorFb'])) { + $options['bgColorFb'] = $this->options['bgColorFb']; + } + $destformat = !empty($options['destformat'])? $options['destformat'] : null; + + // check 'width' ,'height' + if (in_array($mode, array('resize', 'propresize', 'crop', 'fitsquare'))) { + if (empty($options['width']) || empty($options['height'])) { + return false; + } + } + + if (!empty($options['checkAnimated'])) { + if ($this->imgLib !== 'imagick' && $this->imgLib !== 'convert') { + if (elFinder::isAnimationGif($src)) { + return false; + } + } + if (elFinder::isAnimationPng($src)) { + return false; + } + } + + switch ($mode) { + case 'rotate': + if (empty($options['degree'])) { + return true; + } + return (bool)$this->imgRotate($src, $options['degree'], $options['bgColorFb'], $destformat, $options['jpgQuality']); + + case 'resize': + return (bool)$this->imgResize($src, $options['width'], $options['height'], false, true, $destformat, $options['jpgQuality'], $options); + + case 'propresize': + return (bool)$this->imgResize($src, $options['width'], $options['height'], true, true, $destformat, $options['jpgQuality'], $options); + + case 'crop': + if (isset($options['x']) && isset($options['y'])) { + return (bool)$this->imgCrop($src, $options['width'], $options['height'], $options['x'], $options['y'], $destformat, $options['jpgQuality']); + } + break; + + case 'fitsquare': + return (bool)$this->imgSquareFit($src, $options['width'], $options['height'], 'center', 'middle', $options['bgcolor'], $destformat, $options['jpgQuality']); + + } + return false; + } + + /** + * Convert Video To Image by ffmpeg + * + * @param string $file video source file path + * @param array $stat file stat array + * @param object $self volume driver object + * @param int $ss start seconds + * + * @return bool + * @throws elFinderAbortException + * @author Naoki Sawada + */ + public function ffmpegToImg($file, $stat, $self, $ss = null) + { + $name = basename($file); + $path = dirname($file); + $tmp = $path . DIRECTORY_SEPARATOR . md5($name); + // register auto delete on shutdown + $GLOBALS['elFinderTempFiles'][$tmp] = true; + if (rename($file, $tmp)) { + if ($ss === null) { + // specific start time by file name (xxx^[sec].[extention] - video^3.mp4) + if (preg_match('/\^(\d+(?:\.\d+)?)\.[^.]+$/', $stat['name'], $_m)) { + $ss = $_m[1]; + } else { + $ss = $this->options['tmbVideoConvSec']; + } + } + $cmd = sprintf(ELFINDER_FFMPEG_PATH . ' -i %s -ss 00:00:%.3f -vframes 1 -f image2 -- %s', escapeshellarg($tmp), $ss, escapeshellarg($file)); + $r = ($this->procExec($cmd) === 0); + clearstatcache(); + if ($r && $ss > 0 && !file_exists($file)) { + // Retry by half of $ss + $ss = max(intval($ss / 2), 0); + rename($tmp, $file); + $r = $this->ffmpegToImg($file, $stat, $self, $ss); + } else { + unlink($tmp); + } + return $r; + } + return false; + } + + /** + * Creates a temporary file and return file pointer + * + * @return resource|boolean + */ + public function tmpfile() + { + if ($tmp = $this->getTempFile()) { + return fopen($tmp, 'wb'); + } + return false; + } + + /** + * Save error message + * + * @param array error + * + * @return boolean false + * @author Naoki Sawada + **/ + protected function setError() + { + $this->error = array(); + $this->addError(func_get_args()); + return false; + } + + /** + * Add error message + * + * @param array error + * + * @return false + * @author Dmitry(dio) Levashov + **/ + protected function addError() + { + foreach (func_get_args() as $err) { + if (is_array($err)) { + foreach($err as $er) { + $this->addError($er); + } + } else { + $this->error[] = (string)$err; + } + } + return false; + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /***************** server encoding support *******************/ + + /** + * Return parent directory path (with convert encoding) + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function dirnameCE($path) + { + $dirname = (!$this->encoding) ? $this->_dirname($path) : $this->convEncOut($this->_dirname($this->convEncIn($path))); + // check to infinite loop prevention + return ($dirname != $path) ? $dirname : ''; + } + + /** + * Return file name (with convert encoding) + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function basenameCE($path) + { + return (!$this->encoding) ? $this->_basename($path) : $this->convEncOut($this->_basename($this->convEncIn($path))); + } + + /** + * Join dir name and file name and return full path. (with convert encoding) + * Some drivers (db) use int as path - so we give to concat path to driver itself + * + * @param string $dir dir path + * @param string $name file name + * + * @return string + * @author Naoki Sawada + **/ + protected function joinPathCE($dir, $name) + { + return (!$this->encoding) ? $this->_joinPath($dir, $name) : $this->convEncOut($this->_joinPath($this->convEncIn($dir), $this->convEncIn($name))); + } + + /** + * Return normalized path (with convert encoding) + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function normpathCE($path) + { + return (!$this->encoding) ? $this->_normpath($path) : $this->convEncOut($this->_normpath($this->convEncIn($path))); + } + + /** + * Return file path related to root dir (with convert encoding) + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function relpathCE($path) + { + return (!$this->encoding) ? $this->_relpath($path) : $this->convEncOut($this->_relpath($this->convEncIn($path))); + } + + /** + * Convert path related to root dir into real path (with convert encoding) + * + * @param string $path rel file path + * + * @return string + * @author Naoki Sawada + **/ + protected function abspathCE($path) + { + return (!$this->encoding) ? $this->_abspath($path) : $this->convEncOut($this->_abspath($this->convEncIn($path))); + } + + /** + * Return true if $path is children of $parent (with convert encoding) + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Naoki Sawada + **/ + protected function inpathCE($path, $parent) + { + return (!$this->encoding) ? $this->_inpath($path, $parent) : $this->convEncOut($this->_inpath($this->convEncIn($path), $this->convEncIn($parent))); + } + + /** + * Open file and return file pointer (with convert encoding) + * + * @param string $path file path + * @param string $mode + * + * @return false|resource + * @internal param bool $write open file for writing + * @author Naoki Sawada + */ + protected function fopenCE($path, $mode = 'rb') + { + // check extra option for network stream pointer + if (func_num_args() > 2) { + $opts = func_get_arg(2); + } else { + $opts = array(); + } + return (!$this->encoding) ? $this->_fopen($path, $mode, $opts) : $this->convEncOut($this->_fopen($this->convEncIn($path), $mode, $opts)); + } + + /** + * Close opened file (with convert encoding) + * + * @param resource $fp file pointer + * @param string $path file path + * + * @return bool + * @author Naoki Sawada + **/ + protected function fcloseCE($fp, $path = '') + { + return (!$this->encoding) ? $this->_fclose($fp, $path) : $this->convEncOut($this->_fclose($fp, $this->convEncIn($path))); + } + + /** + * Create new file and write into it from file pointer. (with convert encoding) + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Naoki Sawada + **/ + protected function saveCE($fp, $dir, $name, $stat) + { + $res = (!$this->encoding) ? $this->_save($fp, $dir, $name, $stat) : $this->convEncOut($this->_save($fp, $this->convEncIn($dir), $this->convEncIn($name), $this->convEncIn($stat))); + if ($res !== false) { + $this->clearstatcache(); + } + return $res; + } + + /** + * Return true if path is dir and has at least one childs directory (with convert encoding) + * + * @param string $path dir path + * + * @return bool + * @author Naoki Sawada + **/ + protected function subdirsCE($path) + { + if ($this->sessionCaching['subdirs']) { + if (isset($this->sessionCache['subdirs'][$path]) && !$this->isMyReload()) { + return $this->sessionCache['subdirs'][$path]; + } + } + $hasdir = (bool)((!$this->encoding) ? $this->_subdirs($path) : $this->convEncOut($this->_subdirs($this->convEncIn($path)))); + $this->updateSubdirsCache($path, $hasdir); + return $hasdir; + } + + /** + * Return files list in directory (with convert encoding) + * + * @param string $path dir path + * + * @return array + * @author Naoki Sawada + **/ + protected function scandirCE($path) + { + return (!$this->encoding) ? $this->_scandir($path) : $this->convEncOut($this->_scandir($this->convEncIn($path))); + } + + /** + * Create symlink (with convert encoding) + * + * @param string $source file to link to + * @param string $targetDir folder to create link in + * @param string $name symlink name + * + * @return bool + * @author Naoki Sawada + **/ + protected function symlinkCE($source, $targetDir, $name) + { + return (!$this->encoding) ? $this->_symlink($source, $targetDir, $name) : $this->convEncOut($this->_symlink($this->convEncIn($source), $this->convEncIn($targetDir), $this->convEncIn($name))); + } + + /***************** paths *******************/ + + /** + * Encode path into hash + * + * @param string file path + * + * @return string + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ + protected function encode($path) + { + if ($path !== '') { + + // cut ROOT from $path for security reason, even if hacker decodes the path he will not know the root + $p = $this->relpathCE($path); + // if reqesting root dir $path will be empty, then assign '/' as we cannot leave it blank for crypt + if ($p === '') { + $p = $this->separator; + } + // change separator + if ($this->separatorForHash) { + $p = str_replace($this->separator, $this->separatorForHash, $p); + } + // TODO crypt path and return hash + $hash = $this->crypt($p); + // hash is used as id in HTML that means it must contain vaild chars + // make base64 html safe and append prefix in begining + $hash = strtr(base64_encode($hash), '+/=', '-_.'); + // remove dots '.' at the end, before it was '=' in base64 + $hash = rtrim($hash, '.'); + // append volume id to make hash unique + return $this->id . $hash; + } + //TODO: Add return statement here + } + + /** + * Decode path from hash + * + * @param string file hash + * + * @return string + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ + protected function decode($hash) + { + if (strpos($hash, $this->id) === 0) { + // cut volume id after it was prepended in encode + $h = substr($hash, strlen($this->id)); + // replace HTML safe base64 to normal + $h = base64_decode(strtr($h, '-_.', '+/=')); + // TODO uncrypt hash and return path + $path = $this->uncrypt($h); + // change separator + if ($this->separatorForHash) { + $path = str_replace($this->separatorForHash, $this->separator, $path); + } + // append ROOT to path after it was cut in encode + return $this->abspathCE($path);//$this->root.($path === $this->separator ? '' : $this->separator.$path); + } + return ''; + } + + /** + * Return crypted path + * Not implemented + * + * @param string path + * + * @return mixed + * @author Dmitry (dio) Levashov + **/ + protected function crypt($path) + { + return $path; + } + + /** + * Return uncrypted path + * Not implemented + * + * @param mixed hash + * + * @return mixed + * @author Dmitry (dio) Levashov + **/ + protected function uncrypt($hash) + { + return $hash; + } + + /** + * Validate file name based on $this->options['acceptedName'] regexp or function + * + * @param string $name file name + * @param bool $isDir + * + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function nameAccepted($name, $isDir = false) + { + if (json_encode($name) === false) { + return false; + } + $nameValidator = $isDir ? $this->dirnameValidator : $this->nameValidator; + if ($nameValidator) { + if (is_callable($nameValidator)) { + $res = call_user_func($nameValidator, $name); + return $res; + } + if (preg_match($nameValidator, '') !== false) { + return preg_match($nameValidator, $name); + } + } + return true; + } + + /** + * Return session rootstat cache key + * + * @return string + */ + protected function getRootstatCachekey() + { + return md5($this->root . (isset($this->options['alias']) ? $this->options['alias'] : '')); + } + + /** + * Return new unique name based on file name and suffix + * + * @param $dir + * @param $name + * @param string $suffix suffix append to name + * @param bool $checkNum + * @param int $start + * + * @return string + * @internal param string $path file path + * @author Dmitry (dio) Levashov + */ + public function uniqueName($dir, $name, $suffix = ' copy', $checkNum = true, $start = 1) + { + static $lasts = null; + + if ($lasts === null) { + $lasts = array(); + } + + $ext = ''; + + $splits = elFinder::splitFileExtention($name); + if ($splits[1]) { + $ext = '.' . $splits[1]; + $name = $splits[0]; + } + + if ($checkNum && preg_match('/(' . preg_quote($suffix, '/') . ')(\d*)$/i', $name, $m)) { + $i = (int)$m[2]; + $name = substr($name, 0, strlen($name) - strlen($m[2])); + } else { + $i = $start; + $name .= $suffix; + } + $max = $i + 100000; + + if (isset($lasts[$name])) { + $i = max($i, $lasts[$name]); + } + + while ($i <= $max) { + $n = $name . ($i > 0 ? sprintf($this->options['uniqueNumFormat'], $i) : '') . $ext; + + if (!$this->isNameExists($this->joinPathCE($dir, $n))) { + $this->clearcache(); + $lasts[$name] = ++$i; + return $n; + } + $i++; + } + return $name . md5($dir) . $ext; + } + + /** + * Converts character encoding from UTF-8 to server's one + * + * @param mixed $var target string or array var + * @param bool $restoreLocale do retore global locale, default is false + * @param string $unknown replaces character for unknown + * + * @return mixed + * @author Naoki Sawada + */ + public function convEncIn($var = null, $restoreLocale = false, $unknown = '_') + { + return (!$this->encoding) ? $var : $this->convEnc($var, 'UTF-8', $this->encoding, $this->options['locale'], $restoreLocale, $unknown); + } + + /** + * Converts character encoding from server's one to UTF-8 + * + * @param mixed $var target string or array var + * @param bool $restoreLocale do retore global locale, default is true + * @param string $unknown replaces character for unknown + * + * @return mixed + * @author Naoki Sawada + */ + public function convEncOut($var = null, $restoreLocale = true, $unknown = '_') + { + return (!$this->encoding) ? $var : $this->convEnc($var, $this->encoding, 'UTF-8', $this->options['locale'], $restoreLocale, $unknown); + } + + /** + * Converts character encoding (base function) + * + * @param mixed $var target string or array var + * @param string $from from character encoding + * @param string $to to character encoding + * @param string $locale local locale + * @param $restoreLocale + * @param string $unknown replaces character for unknown + * + * @return mixed + */ + protected function convEnc($var, $from, $to, $locale, $restoreLocale, $unknown = '_') + { + if (strtoupper($from) !== strtoupper($to)) { + if ($locale) { + setlocale(LC_ALL, $locale); + } + if (is_array($var)) { + $_ret = array(); + foreach ($var as $_k => $_v) { + $_ret[$_k] = $this->convEnc($_v, $from, $to, '', false, $unknown = '_'); + } + $var = $_ret; + } else { + $_var = false; + if (is_string($var)) { + $_var = $var; + $errlev = error_reporting(); + error_reporting($errlev ^ E_NOTICE); + if (false !== ($_var = iconv($from, $to . '//TRANSLIT', $_var))) { + $_var = str_replace('?', $unknown, $_var); + } + error_reporting($errlev); + } + if ($_var !== false) { + $var = $_var; + } + } + if ($restoreLocale) { + setlocale(LC_ALL, elFinder::$locale); + } + } + return $var; + } + + /** + * Normalize MIME-Type by options['mimeMap'] + * + * @param string $type MIME-Type + * @param string $name Filename + * @param string $ext File extention without first dot (optional) + * + * @return string Normalized MIME-Type + */ + public function mimeTypeNormalize($type, $name, $ext = '') + { + if ($ext === '') { + $ext = (false === $pos = strrpos($name, '.')) ? '' : substr($name, $pos + 1); + } + $_checkKey = strtolower($ext . ':' . $type); + if ($type === '') { + $_keylen = strlen($_checkKey); + foreach ($this->options['mimeMap'] as $_key => $_type) { + if (substr($_key, 0, $_keylen) === $_checkKey) { + $type = $_type; + break; + } + } + } else if (isset($this->options['mimeMap'][$_checkKey])) { + $type = $this->options['mimeMap'][$_checkKey]; + } else { + $_checkKey = strtolower($ext . ':*'); + if (isset($this->options['mimeMap'][$_checkKey])) { + $type = $this->options['mimeMap'][$_checkKey]; + } else { + $_checkKey = strtolower('*:' . $type); + if (isset($this->options['mimeMap'][$_checkKey])) { + $type = $this->options['mimeMap'][$_checkKey]; + } + } + } + return $type; + } + + /*********************** util mainly for inheritance class *********************/ + + /** + * Get temporary filename. Tempfile will be removed when after script execution finishes or exit() is called. + * When needing the unique file to a path, give $path to parameter. + * + * @param string $path for get unique file to a path + * + * @return string|false + * @author Naoki Sawada + */ + protected function getTempFile($path = '') + { + static $cache = array(); + + $key = ''; + if ($path !== '') { + $key = $this->id . '#' . $path; + if (isset($cache[$key])) { + return $cache[$key]; + } + } + + if ($tmpdir = $this->getTempPath()) { + $name = tempnam($tmpdir, 'ELF'); + if ($key) { + $cache[$key] = $name; + } + // register auto delete on shutdown + $GLOBALS['elFinderTempFiles'][$name] = true; + return $name; + } + + return false; + } + + /** + * File path of local server side work file path + * + * @param string $path path need convert encoding to server encoding + * + * @return string + * @author Naoki Sawada + */ + protected function getWorkFile($path) + { + if ($wfp = $this->tmpfile()) { + if ($fp = $this->_fopen($path)) { + while (!feof($fp)) { + fwrite($wfp, fread($fp, 8192)); + } + $info = stream_get_meta_data($wfp); + fclose($wfp); + if ($info && !empty($info['uri'])) { + return $info['uri']; + } + } + } + return false; + } + + /** + * Get image size array with `dimensions` + * + * @param string $path path need convert encoding to server encoding + * @param string $mime file mime type + * + * @return array|false + * @throws ImagickException + * @throws elFinderAbortException + */ + public function getImageSize($path, $mime = '') + { + $size = false; + if ($mime === '' || strtolower(substr($mime, 0, 5)) === 'image') { + if ($work = $this->getWorkFile($path)) { + if ($size = getimagesize($work)) { + $size['dimensions'] = $size[0] . 'x' . $size[1]; + $srcfp = fopen($work, 'rb'); + $cArgs = elFinder::$currentArgs; + if (!empty($cArgs['target']) && $subImgLink = $this->getSubstituteImgLink($cArgs['target'], $size, $srcfp)) { + $size['url'] = $subImgLink; + } + } + } + is_file($work) && unlink($work); + } + return $size; + } + + /** + * Delete dirctory trees + * + * @param string $localpath path need convert encoding to server encoding + * + * @return boolean + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function delTree($localpath) + { + foreach ($this->_scandir($localpath) as $p) { + elFinder::checkAborted(); + $stat = $this->stat($this->convEncOut($p)); + $this->convEncIn(); + ($stat['mime'] === 'directory') ? $this->delTree($p) : $this->_unlink($p); + } + $res = $this->_rmdir($localpath); + $res && $this->clearstatcache(); + return $res; + } + + /** + * Copy items to a new temporary directory on the local server + * + * @param array $hashes target hashes + * @param string $dir destination directory (for recurcive) + * @param string $canLink it can use link() (for recurcive) + * + * @return string|false saved path name + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function getItemsInHand($hashes, $dir = null, $canLink = null) + { + static $banChrs = null; + static $totalSize = 0; + + if (is_null($banChrs)) { + $banChrs = DIRECTORY_SEPARATOR !== '/'? array('\\', '/', ':', '*', '?', '"', '<', '>', '|') : array('\\', '/'); + } + + if (is_null($dir)) { + $totalSize = 0; + if (!$tmpDir = $this->getTempPath()) { + return false; + } + $dir = tempnam($tmpDir, 'elf'); + if (!unlink($dir) || !mkdir($dir, 0700, true)) { + return false; + } + register_shutdown_function(array($this, 'rmdirRecursive'), $dir); + } + if (is_null($canLink)) { + $canLink = ($this instanceof elFinderVolumeLocalFileSystem); + } + elFinder::checkAborted(); + $res = true; + $files = array(); + foreach ($hashes as $hash) { + if (($file = $this->file($hash)) == false) { + continue; + } + if (!$file['read']) { + continue; + } + + $name = $file['name']; + // remove ctrl characters + $name = preg_replace('/[[:cntrl:]]+/', '', $name); + // replace ban characters + $name = str_replace($banChrs, '_', $name); + + // for call from search results + if (isset($files[$name])) { + $name = preg_replace('/^(.*?)(\..*)?$/', '$1_' . $files[$name]++ . '$2', $name); + } else { + $files[$name] = 1; + } + $target = $dir . DIRECTORY_SEPARATOR . $name; + + if ($file['mime'] === 'directory') { + $chashes = array(); + $_files = $this->scandir($hash); + foreach ($_files as $_file) { + if ($file['read']) { + $chashes[] = $_file['hash']; + } + } + if (($res = mkdir($target, 0700, true)) && $chashes) { + $res = $this->getItemsInHand($chashes, $target, $canLink); + } + if (!$res) { + break; + } + !empty($file['ts']) && touch($target, $file['ts']); + } else { + $path = $this->decode($hash); + if (!$canLink || !($canLink = $this->localFileSystemSymlink($path, $target))) { + if (file_exists($target)) { + unlink($target); + } + if ($fp = $this->fopenCE($path)) { + if ($tfp = fopen($target, 'wb')) { + $totalSize += stream_copy_to_stream($fp, $tfp); + fclose($tfp); + } + !empty($file['ts']) && touch($target, $file['ts']); + $this->fcloseCE($fp, $path); + } + } else { + $totalSize += filesize($path); + } + if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $totalSize) { + $res = $this->setError(elFinder::ERROR_ARC_MAXSIZE); + } + } + } + return $res ? $dir : false; + } + + /*********************** file stat *********************/ + + /** + * Check file attribute + * + * @param string $path file path + * @param string $name attribute name (read|write|locked|hidden) + * @param bool $val attribute value returned by file system + * @param bool $isDir path is directory (true: directory, false: file) + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function attr($path, $name, $val = null, $isDir = null) + { + if (!isset($this->defaults[$name])) { + return false; + } + + $relpath = $this->relpathCE($path); + if ($this->separator !== '/') { + $relpath = str_replace($this->separator, '/', $relpath); + } + $relpath = '/' . $relpath; + + $perm = null; + + if ($this->access) { + $perm = call_user_func($this->access, $name, $path, $this->options['accessControlData'], $this, $isDir, $relpath); + if ($perm !== null) { + return !!$perm; + } + } + + foreach ($this->attributes as $attrs) { + if (isset($attrs[$name]) && isset($attrs['pattern']) && preg_match($attrs['pattern'], $relpath)) { + $perm = $attrs[$name]; + break; + } + } + + return $perm === null ? (is_null($val) ? $this->defaults[$name] : $val) : !!$perm; + } + + /** + * Return true if file with given name can be created in given folder. + * + * @param string $dir parent dir path + * @param string $name new file name + * @param null $isDir + * + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function allowCreate($dir, $name, $isDir = null) + { + return $this->attr($this->joinPathCE($dir, $name), 'write', true, $isDir); + } + + /** + * Return true if file MIME type can save with check uploadOrder config. + * + * @param string $mime + * + * @return boolean + */ + protected function allowPutMime($mime) + { + // logic based on http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order + $allow = $this->mimeAccepted($mime, $this->uploadAllow, null); + $deny = $this->mimeAccepted($mime, $this->uploadDeny, null); + if (strtolower($this->uploadOrder[0]) == 'allow') { // array('allow', 'deny'), default is to 'deny' + $res = false; // default is deny + if (!$deny && ($allow === true)) { // match only allow + $res = true; + }// else (both match | no match | match only deny) { deny } + } else { // array('deny', 'allow'), default is to 'allow' - this is the default rule + $res = true; // default is allow + if (($deny === true) && !$allow) { // match only deny + $res = false; + } // else (both match | no match | match only allow) { allow } + } + return $res; + } + + /** + * Return fileinfo + * + * @param string $path file cache + * + * @return array|bool + * @author Dmitry (dio) Levashov + **/ + protected function stat($path) + { + if ($path === false || is_null($path)) { + return false; + } + $is_root = ($path == $this->root); + if ($is_root) { + $rootKey = $this->getRootstatCachekey(); + if ($this->sessionCaching['rootstat'] && !isset($this->sessionCache['rootstat'])) { + $this->sessionCache['rootstat'] = array(); + } + if (!isset($this->cache[$path]) && !$this->isMyReload()) { + // need $path as key for netmount/netunmount + if ($this->sessionCaching['rootstat'] && isset($this->sessionCache['rootstat'][$rootKey])) { + if ($ret = $this->sessionCache['rootstat'][$rootKey]) { + if ($this->options['rootRev'] === $ret['rootRev']) { + if (isset($this->options['phash'])) { + $ret['isroot'] = 1; + $ret['phash'] = $this->options['phash']; + } + return $ret; + } + } + } + } + } + $rootSessCache = false; + if (isset($this->cache[$path])) { + $ret = $this->cache[$path]; + } else { + if ($is_root && !empty($this->options['rapidRootStat']) && is_array($this->options['rapidRootStat']) && !$this->needOnline) { + $ret = $this->updateCache($path, $this->options['rapidRootStat'], true); + } else { + $ret = $this->updateCache($path, $this->convEncOut($this->_stat($this->convEncIn($path))), true); + if ($is_root && !empty($rootKey) && $this->sessionCaching['rootstat']) { + $rootSessCache = true; + } + } + } + if ($is_root) { + if ($ret) { + $this->rootModified = false; + if ($rootSessCache) { + $this->sessionCache['rootstat'][$rootKey] = $ret; + } + if (isset($this->options['phash'])) { + $ret['isroot'] = 1; + $ret['phash'] = $this->options['phash']; + } + } else if (!empty($rootKey) && $this->sessionCaching['rootstat']) { + unset($this->sessionCache['rootstat'][$rootKey]); + } + } + return $ret; + } + + /** + * Get root stat extra key values + * + * @return array stat extras + * @author Naoki Sawada + */ + protected function getRootStatExtra() + { + $stat = array(); + if ($this->rootName) { + $stat['name'] = $this->rootName; + } + $stat['rootRev'] = $this->options['rootRev']; + $stat['options'] = $this->options(null); + return $stat; + } + + /** + * Return fileinfo based on filename + * For item ID based path file system + * Please override if needed on each drivers + * + * @param string $path file cache + * + * @return array + */ + protected function isNameExists($path) + { + return $this->stat($path); + } + + /** + * Put file stat in cache and return it + * + * @param string $path file path + * @param array $stat file stat + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function updateCache($path, $stat) + { + if (empty($stat) || !is_array($stat)) { + return $this->cache[$path] = array(); + } + + if (func_num_args() > 2) { + $fromStat = func_get_arg(2); + } else { + $fromStat = false; + } + + $stat['hash'] = $this->encode($path); + + $root = $path == $this->root; + $parent = ''; + + if ($root) { + $stat = array_merge($stat, $this->getRootStatExtra()); + } else { + if (!isset($stat['name']) || $stat['name'] === '') { + $stat['name'] = $this->basenameCE($path); + } + if (empty($stat['phash'])) { + $parent = $this->dirnameCE($path); + $stat['phash'] = $this->encode($parent); + } else { + $parent = $this->decode($stat['phash']); + } + } + + // name check + if (isset($stat['name']) && !$jeName = json_encode($stat['name'])) { + return $this->cache[$path] = array(); + } + // fix name if required + if ($this->options['utf8fix'] && $this->options['utf8patterns'] && $this->options['utf8replace']) { + $stat['name'] = json_decode(str_replace($this->options['utf8patterns'], $this->options['utf8replace'], $jeName)); + } + + if (!isset($stat['size'])) { + $stat['size'] = 'unknown'; + } + + $mime = isset($stat['mime']) ? $stat['mime'] : ''; + if ($isDir = ($mime === 'directory')) { + $stat['volumeid'] = $this->id; + } else { + if (empty($stat['mime']) || $stat['size'] == 0) { + $stat['mime'] = $this->mimetype($stat['name'], true, $stat['size'], $mime); + } else { + $stat['mime'] = $this->mimeTypeNormalize($stat['mime'], $stat['name']); + } + } + + $stat['read'] = intval($this->attr($path, 'read', isset($stat['read']) ? !!$stat['read'] : null, $isDir)); + $stat['write'] = intval($this->attr($path, 'write', isset($stat['write']) ? !!$stat['write'] : null, $isDir)); + if ($root) { + $stat['locked'] = 1; + if ($this->options['type'] !== '') { + $stat['type'] = $this->options['type']; + } + } else { + // lock when parent directory is not writable + if (!isset($stat['locked'])) { + $pstat = $this->stat($parent); + if (isset($pstat['write']) && !$pstat['write']) { + $stat['locked'] = true; + } + } + if ($this->attr($path, 'locked', isset($stat['locked']) ? !!$stat['locked'] : null, $isDir)) { + $stat['locked'] = 1; + } else { + unset($stat['locked']); + } + } + + if ($root) { + unset($stat['hidden']); + } elseif ($this->attr($path, 'hidden', isset($stat['hidden']) ? !!$stat['hidden'] : null, $isDir) + || !$this->mimeAccepted($stat['mime'])) { + $stat['hidden'] = 1; + } else { + unset($stat['hidden']); + } + + if ($stat['read'] && empty($stat['hidden'])) { + + if ($isDir) { + // caching parent's subdirs + if ($parent) { + $this->updateSubdirsCache($parent, true); + } + // for dir - check for subdirs + if ($this->options['checkSubfolders']) { + if (!isset($stat['dirs']) && intval($this->options['checkSubfolders']) === -1) { + $stat['dirs'] = -1; + } + if (isset($stat['dirs'])) { + if ($stat['dirs']) { + if ($stat['dirs'] == -1) { + $stat['dirs'] = ($this->sessionCaching['subdirs'] && isset($this->sessionCache['subdirs'][$path])) ? (int)$this->sessionCache['subdirs'][$path] : -1; + } else { + $stat['dirs'] = 1; + } + } else { + unset($stat['dirs']); + } + } elseif (!empty($stat['alias']) && !empty($stat['target'])) { + $stat['dirs'] = isset($this->cache[$stat['target']]) + ? intval(isset($this->cache[$stat['target']]['dirs'])) + : $this->subdirsCE($stat['target']); + + } elseif ($this->subdirsCE($path)) { + $stat['dirs'] = 1; + } + } else { + $stat['dirs'] = 1; + } + if ($this->options['dirUrlOwn'] === true) { + // Set `null` to use the client option `commandsOptions.info.nullUrlDirLinkSelf = true` + $stat['url'] = null; + } else if ($this->options['dirUrlOwn'] === 'hide') { + // to hide link in info dialog of the elFinder client + $stat['url'] = ''; + } + } else { + // for files - check for thumbnails + $p = isset($stat['target']) ? $stat['target'] : $path; + if ($this->tmbURL && !isset($stat['tmb']) && $this->canCreateTmb($p, $stat)) { + $tmb = $this->gettmb($p, $stat); + $stat['tmb'] = $tmb ? $tmb : 1; + } + + } + if (!isset($stat['url']) && $this->URL && $this->encoding) { + $_path = str_replace($this->separator, '/', substr($path, strlen($this->root) + 1)); + $stat['url'] = rtrim($this->URL, '/') . '/' . str_replace('%2F', '/', rawurlencode((substr(PHP_OS, 0, 3) === 'WIN') ? $_path : $this->convEncIn($_path, true))); + } + } else { + if ($isDir) { + unset($stat['dirs']); + } + } + + if (!empty($stat['alias']) && !empty($stat['target'])) { + $stat['thash'] = $this->encode($stat['target']); + //$this->cache[$stat['target']] = $stat; + unset($stat['target']); + } + + $this->cache[$path] = $stat; + + if (!$fromStat && $root && $this->sessionCaching['rootstat']) { + // to update session cache + $this->stat($path); + } + + return $stat; + } + + /** + * Get stat for folder content and put in cache + * + * @param string $path + * + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function cacheDir($path) + { + $this->dirsCache[$path] = array(); + $hasDir = false; + + foreach ($this->scandirCE($path) as $p) { + if (($stat = $this->stat($p)) && empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $p; + } + } + + $this->updateSubdirsCache($path, $hasDir); + } + + /** + * Clean cache + * + * @return void + * @author Dmitry (dio) Levashov + **/ + protected function clearcache() + { + $this->cache = $this->dirsCache = array(); + } + + /** + * Return file mimetype + * + * @param string $path file path + * @param string|bool $name + * @param integer $size + * @param string $mime was notified from the volume driver + * + * @return string + * @author Dmitry (dio) Levashov + */ + protected function mimetype($path, $name = '', $size = null, $mime = null) + { + $type = ''; + $nameCheck = false; + + if ($name === '') { + $name = $path; + } else if ($name === true) { + $name = $path; + $nameCheck = true; + } + if (!$this instanceof elFinderVolumeLocalFileSystem) { + $nameCheck = true; + } + $ext = (false === $pos = strrpos($name, '.')) ? '' : strtolower(substr($name, $pos + 1)); + if (!$nameCheck && $size === null) { + $size = file_exists($path) ? filesize($path) : -1; + } + if (!$nameCheck && is_readable($path) && $size > 0) { + // detecting by contents + if ($this->mimeDetect === 'finfo') { + $type = finfo_file($this->finfo, $path); + } else if ($this->mimeDetect === 'mime_content_type') { + $type = mime_content_type($path); + } + if ($type) { + $type = explode(';', $type); + $type = trim($type[0]); + if ($ext && preg_match('~^application/(?:octet-stream|(?:x-)?zip|xml)$~', $type)) { + // load default MIME table file "mime.types" + if (!elFinderVolumeDriver::$mimetypesLoaded) { + elFinderVolumeDriver::loadMimeTypes(); + } + if (isset(elFinderVolumeDriver::$mimetypes[$ext])) { + $type = elFinderVolumeDriver::$mimetypes[$ext]; + } + } else if ($ext === 'js' && preg_match('~^text/~', $type)) { + $type = 'text/javascript'; + } + } + } + if (!$type) { + // detecting by filename + $type = elFinderVolumeDriver::mimetypeInternalDetect($name); + if ($type === 'unknown') { + if ($mime) { + $type = $mime; + } else { + $type = ($size == 0) ? 'text/plain' : $this->options['mimeTypeUnknown']; + } + } + } + + // mime type normalization + $type = $this->mimeTypeNormalize($type, $name, $ext); + + return $type; + } + + /** + * Load file of mime.types + * + * @param string $mimeTypesFile The mime types file + */ + static protected function loadMimeTypes($mimeTypesFile = '') + { + if (!elFinderVolumeDriver::$mimetypesLoaded) { + elFinderVolumeDriver::$mimetypesLoaded = true; + $file = false; + if (!empty($mimeTypesFile) && file_exists($mimeTypesFile)) { + $file = $mimeTypesFile; + } elseif (elFinder::$defaultMimefile && file_exists(elFinder::$defaultMimefile)) { + $file = elFinder::$defaultMimefile; + } elseif (file_exists(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mime.types')) { + $file = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mime.types'; + } elseif (file_exists(dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'mime.types')) { + $file = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'mime.types'; + } + + if ($file && file_exists($file)) { + $mimecf = file($file); + + foreach ($mimecf as $line_num => $line) { + if (!preg_match('/^\s*#/', $line)) { + $mime = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY); + for ($i = 1, $size = count($mime); $i < $size; $i++) { + if (!isset(self::$mimetypes[$mime[$i]])) { + self::$mimetypes[$mime[$i]] = $mime[0]; + } + } + } + } + } + } + } + + /** + * Detect file mimetype using "internal" method or Loading mime.types with $path = '' + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + static protected function mimetypeInternalDetect($path = '') + { + // load default MIME table file "mime.types" + if (!elFinderVolumeDriver::$mimetypesLoaded) { + elFinderVolumeDriver::loadMimeTypes(); + } + $ext = ''; + if ($path) { + $pinfo = pathinfo($path); + $ext = isset($pinfo['extension']) ? strtolower($pinfo['extension']) : ''; + } + $res = ($ext && isset(elFinderVolumeDriver::$mimetypes[$ext])) ? elFinderVolumeDriver::$mimetypes[$ext] : 'unknown'; + // Recursive check if MIME type is unknown with multiple extensions + if ($res === 'unknown' && strpos($pinfo['filename'], '.')) { + return elFinderVolumeDriver::mimetypeInternalDetect($pinfo['filename']); + } else { + return $res; + } + } + + /** + * Return file/total directory size infomation + * + * @param string $path file path + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function countSize($path) + { + + elFinder::checkAborted(); + + $result = array('size' => 0, 'files' => 0, 'dirs' => 0); + $stat = $this->stat($path); + + if (empty($stat) || !$stat['read'] || !empty($stat['hidden'])) { + $result['size'] = 'unknown'; + return $result; + } + + if ($stat['mime'] !== 'directory') { + $result['size'] = intval($stat['size']); + $result['files'] = 1; + return $result; + } + + $result['dirs'] = 1; + $subdirs = $this->options['checkSubfolders']; + $this->options['checkSubfolders'] = true; + foreach ($this->getScandir($path) as $stat) { + if ($isDir = ($stat['mime'] === 'directory' && $stat['read'])) { + ++$result['dirs']; + } else { + ++$result['files']; + } + $res = $isDir + ? $this->countSize($this->decode($stat['hash'])) + : (isset($stat['size']) ? array('size' => intval($stat['size'])) : array()); + if (!empty($res['size']) && is_numeric($res['size'])) { + $result['size'] += $res['size']; + } + if (!empty($res['files']) && is_numeric($res['files'])) { + $result['files'] += $res['files']; + } + if (!empty($res['dirs']) && is_numeric($res['dirs'])) { + $result['dirs'] += $res['dirs']; + --$result['dirs']; + } + } + $this->options['checkSubfolders'] = $subdirs; + return $result; + } + + /** + * Return true if all mimes is directory or files + * + * @param string $mime1 mimetype + * @param string $mime2 mimetype + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function isSameType($mime1, $mime2) + { + return ($mime1 == 'directory' && $mime1 == $mime2) || ($mime1 != 'directory' && $mime2 != 'directory'); + } + + /** + * If file has required attr == $val - return file path, + * If dir has child with has required attr == $val - return child path + * + * @param string $path file path + * @param string $attr attribute name + * @param bool $val attribute value + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function closestByAttr($path, $attr, $val) + { + $stat = $this->stat($path); + + if (empty($stat)) { + return false; + } + + $v = isset($stat[$attr]) ? $stat[$attr] : false; + + if ($v == $val) { + return $path; + } + + return $stat['mime'] == 'directory' + ? $this->childsByAttr($path, $attr, $val) + : false; + } + + /** + * Return first found children with required attr == $val + * + * @param string $path file path + * @param string $attr attribute name + * @param bool $val attribute value + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function childsByAttr($path, $attr, $val) + { + foreach ($this->scandirCE($path) as $p) { + if (($_p = $this->closestByAttr($p, $attr, $val)) != false) { + return $_p; + } + } + return false; + } + + protected function isMyReload($target = '', $ARGtarget = '') + { + if ($this->rootModified || (!empty($this->ARGS['cmd']) && $this->ARGS['cmd'] === 'parents')) { + return true; + } + if (!empty($this->ARGS['reload'])) { + if ($ARGtarget === '') { + $ARGtarget = isset($this->ARGS['target']) ? $this->ARGS['target'] + : ((isset($this->ARGS['targets']) && is_array($this->ARGS['targets']) && count($this->ARGS['targets']) === 1) ? + $this->ARGS['targets'][0] : ''); + } + if ($ARGtarget !== '') { + $ARGtarget = strval($ARGtarget); + if ($target === '') { + return (strpos($ARGtarget, $this->id) === 0); + } else { + $target = strval($target); + return ($target === $ARGtarget); + } + } + } + return false; + } + + /** + * Update subdirs cache data + * + * @param string $path + * @param bool $subdirs + * + * @return void + */ + protected function updateSubdirsCache($path, $subdirs) + { + if (isset($this->cache[$path])) { + if ($subdirs) { + $this->cache[$path]['dirs'] = 1; + } else { + unset($this->cache[$path]['dirs']); + } + } + if ($this->sessionCaching['subdirs']) { + $this->sessionCache['subdirs'][$path] = $subdirs; + } + if ($this->sessionCaching['rootstat'] && $path == $this->root) { + unset($this->sessionCache['rootstat'][$this->getRootstatCachekey()]); + } + } + + /***************** get content *******************/ + + /** + * Return required dir's files info. + * If onlyMimes is set - return only dirs and files of required mimes + * + * @param string $path dir path + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function getScandir($path) + { + $files = array(); + + !isset($this->dirsCache[$path]) && $this->cacheDir($path); + + foreach ($this->dirsCache[$path] as $p) { + if (($stat = $this->stat($p)) && empty($stat['hidden'])) { + $files[] = $stat; + } + } + + return $files; + } + + + /** + * Return subdirs tree + * + * @param string $path parent dir path + * @param int $deep tree deep + * @param string $exclude + * + * @return array + * @author Dmitry (dio) Levashov + */ + protected function gettree($path, $deep, $exclude = '') + { + $dirs = array(); + + !isset($this->dirsCache[$path]) && $this->cacheDir($path); + + foreach ($this->dirsCache[$path] as $p) { + $stat = $this->stat($p); + + if ($stat && empty($stat['hidden']) && $p != $exclude && $stat['mime'] == 'directory') { + $dirs[] = $stat; + if ($deep > 0 && !empty($stat['dirs'])) { + $dirs = array_merge($dirs, $this->gettree($p, $deep - 1)); + } + } + } + + return $dirs; + } + + /** + * Recursive files search + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function doSearch($path, $q, $mimes) + { + $result = array(); + $matchMethod = empty($this->doSearchCurrentQuery['matchMethod']) ? 'searchMatchName' : $this->doSearchCurrentQuery['matchMethod']; + $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; + if ($timeout && $timeout < time()) { + $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); + return $result; + } + + foreach ($this->scandirCE($path) as $p) { + elFinder::extendTimeLimit($this->options['searchTimeout'] + 30); + + if ($timeout && ($this->error || $timeout < time())) { + !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); + break; + } + + + $stat = $this->stat($p); + + if (!$stat) { // invalid links + continue; + } + + if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) { + continue; + } + + $name = $stat['name']; + + if ($this->doSearchCurrentQuery['excludes']) { + foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) { + if ($this->stripos($name, $exclude) !== false) { + continue 2; + } + } + } + + if ((!$mimes || $stat['mime'] !== 'directory') && $this->$matchMethod($name, $q, $p) !== false) { + $stat['path'] = $this->path($stat['hash']); + if ($this->URL && !isset($stat['url'])) { + $path = str_replace($this->separator, '/', substr($p, strlen($this->root) + 1)); + if ($this->encoding) { + $path = str_replace('%2F', '/', rawurlencode($this->convEncIn($path, true))); + } else { + $path = str_replace('%2F', '/', rawurlencode($path)); + } + $stat['url'] = $this->URL . $path; + } + + $result[] = $stat; + } + if ($stat['mime'] == 'directory' && $stat['read'] && !isset($stat['alias'])) { + if (!$this->options['searchExDirReg'] || !preg_match($this->options['searchExDirReg'], $p)) { + $result = array_merge($result, $this->doSearch($p, $q, $mimes)); + } + } + } + + return $result; + } + + /********************** manuipulations ******************/ + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function copy($src, $dst, $name) + { + + elFinder::checkAborted(); + + $srcStat = $this->stat($src); + + if (!empty($srcStat['thash'])) { + $target = $this->decode($srcStat['thash']); + if (!$this->inpathCE($target, $this->root)) { + return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash']), elFinder::ERROR_MKOUTLINK); + } + $stat = $this->stat($target); + $this->clearcache(); + return $stat && $this->symlinkCE($target, $dst, $name) + ? $this->joinPathCE($dst, $name) + : $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash'])); + } + + if ($srcStat['mime'] === 'directory') { + $testStat = $this->isNameExists($this->joinPathCE($dst, $name)); + $this->clearcache(); + + if (($testStat && $testStat['mime'] !== 'directory') || (!$testStat && !$testStat = $this->mkdir($this->encode($dst), $name))) { + return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash'])); + } + + $dst = $this->decode($testStat['hash']); + + // start time + $stime = microtime(true); + foreach ($this->getScandir($src) as $stat) { + if (empty($stat['hidden'])) { + // current time + $ctime = microtime(true); + if (($ctime - $stime) > 2) { + $stime = $ctime; + elFinder::checkAborted(); + } + $name = $stat['name']; + $_src = $this->decode($stat['hash']); + if (!$this->copy($_src, $dst, $name)) { + $this->remove($dst, true); // fall back + return $this->setError($this->error, elFinder::ERROR_COPY, $this->_path($src)); + } + } + } + + $this->added[] = $testStat; + + return $dst; + } + + if ($this->options['copyJoin']) { + $test = $this->joinPathCE($dst, $name); + if ($this->isNameExists($test)) { + $this->remove($test); + } + } + if ($res = $this->convEncOut($this->_copy($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name)))) { + $path = is_string($res) ? $res : $this->joinPathCE($dst, $name); + $this->clearstatcache(); + $this->added[] = $this->stat($path); + return $path; + } + + return $this->setError(elFinder::ERROR_COPY, $this->path($srcStat['hash'])); + } + + /** + * Move file + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function move($src, $dst, $name) + { + $stat = $this->stat($src); + $stat['realpath'] = $src; + $this->rmTmb($stat); // can not do rmTmb() after _move() + $this->clearcache(); + + $res = $this->convEncOut($this->_move($this->convEncIn($src), $this->convEncIn($dst), $this->convEncIn($name))); + // if moving it didn't work try to copy / delete + if (!$res) { + if ($this->copy($src, $dst, $name)) { + $res = $this->remove($src); + } + } + + if ($res) { + $this->clearstatcache(); + if ($stat['mime'] === 'directory') { + $this->updateSubdirsCache($dst, true); + } + $path = is_string($res) ? $res : $this->joinPathCE($dst, $name); + $this->added[] = $this->stat($path); + $this->removed[] = $stat; + return $path; + } + + return $this->setError(elFinder::ERROR_MOVE, $this->path($stat['hash'])); + } + + /** + * Copy file from another volume. + * Return new file path or false. + * + * @param Object $volume source volume + * @param string $src source file hash + * @param string $destination destination dir path + * @param string $name file name + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function copyFrom($volume, $src, $destination, $name) + { + + elFinder::checkAborted(); + + if (($source = $volume->file($src)) == false) { + return $this->addError(elFinder::ERROR_COPY, '#' . $src, $volume->error()); + } + + $srcIsDir = ($source['mime'] === 'directory'); + + $errpath = $volume->path($source['hash']); + + $errors = array(); + try { + $thash = $this->encode($destination); + elFinder::$instance->trigger('paste.copyfrom', array(&$thash, &$name, '', elFinder::$instance, $this), $errors); + } catch (elFinderTriggerException $e) { + return $this->addError(elFinder::ERROR_COPY, $name, $errors); + } + + if (!$this->nameAccepted($name, $srcIsDir)) { + return $this->addError(elFinder::ERROR_COPY, $name, $srcIsDir ? elFinder::ERROR_INVALID_DIRNAME : elFinder::ERROR_INVALID_NAME); + } + + if (!$this->allowCreate($destination, $name, $srcIsDir)) { + return $this->addError(elFinder::ERROR_COPY, $name, elFinder::ERROR_PERM_DENIED); + } + + if (!$source['read']) { + return $this->addError(elFinder::ERROR_COPY, $errpath, elFinder::ERROR_PERM_DENIED); + } + + if ($srcIsDir) { + $test = $this->isNameExists($this->joinPathCE($destination, $name)); + $this->clearcache(); + + if (($test && $test['mime'] != 'directory') || (!$test && !$test = $this->mkdir($this->encode($destination), $name))) { + return $this->addError(elFinder::ERROR_COPY, $errpath); + } + + //$path = $this->joinPathCE($destination, $name); + $path = $this->decode($test['hash']); + + foreach ($volume->scandir($src) as $entr) { + $this->copyFrom($volume, $entr['hash'], $path, $entr['name']); + } + + $this->added[] = $test; + } else { + // size check + if (!isset($source['size']) || $source['size'] > $this->uploadMaxSize) { + return $this->setError(elFinder::ERROR_UPLOAD_FILE_SIZE); + } + + // MIME check + $mimeByName = $this->mimetype($source['name'], true); + if ($source['mime'] === $mimeByName) { + $mimeByName = ''; + } + if (!$this->allowPutMime($source['mime']) || ($mimeByName && !$this->allowPutMime($mimeByName))) { + return $this->addError(elFinder::ERROR_UPLOAD_FILE_MIME, $errpath); + } + + if (strpos($source['mime'], 'image') === 0 && ($dim = $volume->dimensions($src))) { + if (is_array($dim)) { + $dim = isset($dim['dim']) ? $dim['dim'] : null; + } + if ($dim) { + $s = explode('x', $dim); + $source['width'] = $s[0]; + $source['height'] = $s[1]; + } + } + + if (($fp = $volume->open($src)) == false + || ($path = $this->saveCE($fp, $destination, $name, $source)) == false) { + $fp && $volume->close($fp, $src); + return $this->addError(elFinder::ERROR_COPY, $errpath); + } + $volume->close($fp, $src); + + $this->added[] = $this->stat($path);; + } + + return $path; + } + + /** + * Remove file/ recursive remove dir + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function remove($path, $force = false) + { + $stat = $this->stat($path); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->relpathCE($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + $stat['realpath'] = $path; + $this->rmTmb($stat); + $this->clearcache(); + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->path($stat['hash'])); + } + + if ($stat['mime'] == 'directory' && empty($stat['thash'])) { + $ret = $this->delTree($this->convEncIn($path)); + $this->convEncOut(); + if (!$ret) { + return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash'])); + } + } else { + if ($this->convEncOut(!$this->_unlink($this->convEncIn($path)))) { + return $this->setError(elFinder::ERROR_RM, $this->path($stat['hash'])); + } + $this->clearstatcache(); + } + + $this->removed[] = $stat; + return true; + } + + + /************************* thumbnails **************************/ + + /** + * Return thumbnail file name for required file + * + * @param array $stat file stat + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function tmbname($stat) + { + $name = $stat['hash'] . (isset($stat['ts']) ? $stat['ts'] : '') . '.png'; + if (strlen($name) > 255) { + $name = $this->id . md5($stat['hash']) . $stat['ts'] . '.png'; + } + return $name; + } + + /** + * Return thumnbnail name if exists + * + * @param string $path file path + * @param array $stat file stat + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function gettmb($path, $stat) + { + if ($this->tmbURL && $this->tmbPath) { + // file itself thumnbnail + if (strpos($path, $this->tmbPath) === 0) { + return basename($path); + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name; + if (file_exists($tmb)) { + if ($this->options['tmbGcMaxlifeHour'] && $this->options['tmbGcPercentage'] > 0) { + touch($tmb); + } + return $name; + } + } + return false; + } + + /** + * Return true if thumnbnail for required file can be created + * + * @param string $path thumnbnail path + * @param array $stat file stat + * @param bool $checkTmbPath + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function canCreateTmb($path, $stat, $checkTmbPath = true) + { + static $gdMimes = null; + static $imgmgPS = null; + if ($gdMimes === null) { + $_mimes = array('image/jpeg', 'image/png', 'image/gif', 'image/x-ms-bmp'); + if (function_exists('imagecreatefromwebp')) { + $_mimes[] = 'image/webp'; + } + $gdMimes = array_flip($_mimes); + $imgmgPS = array_flip(array('application/postscript', 'application/pdf')); + } + if ((!$checkTmbPath || $this->tmbPathWritable) + && (!$this->tmbPath || strpos($path, $this->tmbPath) === false) // do not create thumnbnail for thumnbnail + ) { + $mime = strtolower($stat['mime']); + list($type) = explode('/', $mime); + if (!empty($this->imgConverter)) { + if (isset($this->imgConverter[$mime])) { + return true; + } + if (isset($this->imgConverter[$type])) { + return true; + } + } + return $this->imgLib + && ( + ($type === 'image' && ($this->imgLib === 'gd' ? isset($gdMimes[$stat['mime']]) : true)) + || + (ELFINDER_IMAGEMAGICK_PS && isset($imgmgPS[$stat['mime']]) && $this->imgLib !== 'gd') + ); + } + return false; + } + + /** + * Return true if required file can be resized. + * By default - the same as canCreateTmb + * + * @param string $path thumnbnail path + * @param array $stat file stat + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function canResize($path, $stat) + { + return $this->canCreateTmb($path, $stat, false); + } + + /** + * Create thumnbnail and return it's URL on success + * + * @param string $path file path + * @param $stat + * + * @return false|string + * @internal param string $mime file mime type + * @throws elFinderAbortException + * @throws ImagickException + * @author Dmitry (dio) Levashov + */ + protected function createTmb($path, $stat) + { + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name; + + $maxlength = -1; + $imgConverter = null; + + // check imgConverter + $mime = strtolower($stat['mime']); + list($type) = explode('/', $mime); + if (isset($this->imgConverter[$mime])) { + $imgConverter = $this->imgConverter[$mime]['func']; + if (!empty($this->imgConverter[$mime]['maxlen'])) { + $maxlength = intval($this->imgConverter[$mime]['maxlen']); + } + } else if (isset($this->imgConverter[$type])) { + $imgConverter = $this->imgConverter[$type]['func']; + if (!empty($this->imgConverter[$type]['maxlen'])) { + $maxlength = intval($this->imgConverter[$type]['maxlen']); + } + } + if ($imgConverter && !is_callable($imgConverter)) { + return false; + } + + // copy image into tmbPath so some drivers does not store files on local fs + if (($src = $this->fopenCE($path, 'rb')) == false) { + return false; + } + + if (($trg = fopen($tmb, 'wb')) == false) { + $this->fcloseCE($src, $path); + return false; + } + + stream_copy_to_stream($src, $trg, $maxlength); + + $this->fcloseCE($src, $path); + fclose($trg); + + // call imgConverter + if ($imgConverter) { + if (!call_user_func_array($imgConverter, array($tmb, $stat, $this))) { + file_exists($tmb) && unlink($tmb); + return false; + } + } + + $result = false; + + $tmbSize = $this->tmbSize; + + if ($this->imgLib === 'imagick') { + try { + $imagickTest = new imagick($tmb . '[0]'); + $imagickTest->clear(); + $imagickTest = true; + } catch (Exception $e) { + $imagickTest = false; + } + } + + if (($this->imgLib === 'imagick' && !$imagickTest) || ($s = getimagesize($tmb)) === false) { + if ($this->imgLib === 'imagick') { + $bgcolor = $this->options['tmbBgColor']; + if ($bgcolor === 'transparent') { + $bgcolor = 'rgba(255, 255, 255, 0.0)'; + } + try { + $imagick = new imagick(); + $imagick->setBackgroundColor(new ImagickPixel($bgcolor)); + $imagick->readImage($this->getExtentionByMime($stat['mime'], ':') . $tmb . '[0]'); + try { + $imagick->trimImage(0); + } catch (Exception $e) { + } + $imagick->setImageFormat('png'); + $imagick->writeImage($tmb); + $imagick->clear(); + if (($s = getimagesize($tmb)) !== false) { + $result = true; + } + } catch (Exception $e) { + } + } else if ($this->imgLib === 'convert') { + $convParams = $this->imageMagickConvertPrepare($tmb, 'png', 100, array(), $stat['mime']); + $cmd = sprintf('%s -colorspace sRGB -trim -- %s %s', ELFINDER_CONVERT_PATH, $convParams['quotedPath'], $convParams['quotedDstPath']); + $result = false; + if ($this->procExec($cmd) === 0) { + if (($s = getimagesize($tmb)) !== false) { + $result = true; + } + } + } + if (!$result) { + // fallback imgLib to GD + if (function_exists('gd_info') && ($s = getimagesize($tmb))) { + $this->imgLib = 'gd'; + } else { + file_exists($tmb) && unlink($tmb); + return false; + } + } + } + + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } else { + + if ($this->options['tmbCrop']) { + + $result = $tmb; + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if ($result && ($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0; + $result = $this->imgCrop($result, $tmbSize, $tmbSize, $x, $y, 'png'); + } else { + $result = false; + } + + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); + } + + if ($result) { + if ($s = getimagesize($tmb)) { + if ($s[0] !== $tmbSize || $s[1] !== $tmbSize) { + $result = $this->imgSquareFit($result, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } + } + } + } + + if (!$result) { + unlink($tmb); + return false; + } + + return $name; + } + + /** + * Resize image + * + * @param string $path image file + * @param int $width new width + * @param int $height new height + * @param bool $keepProportions crop image + * @param bool $resizeByBiggerSide resize image based on bigger side if true + * @param string $destformat image destination format + * @param int $jpgQuality JEPG quality (1-100) + * @param array $options Other extra options + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + protected function imgResize($path, $width, $height, $keepProportions = false, $resizeByBiggerSide = true, $destformat = null, $jpgQuality = null, $options = array()) + { + if (($s = getimagesize($path)) == false) { + return false; + } + + if (!$jpgQuality) { + $jpgQuality = $this->options['jpgQuality']; + } + + list($orig_w, $orig_h) = array($s[0], $s[1]); + list($size_w, $size_h) = array($width, $height); + + if (empty($options['unenlarge']) || $orig_w > $size_w || $orig_h > $size_h) { + if ($keepProportions == true) { + /* Resizing by biggest side */ + if ($resizeByBiggerSide) { + if ($orig_w > $orig_h) { + $size_h = round($orig_h * $width / $orig_w); + $size_w = $width; + } else { + $size_w = round($orig_w * $height / $orig_h); + $size_h = $height; + } + } else { + if ($orig_w > $orig_h) { + $size_w = round($orig_w * $height / $orig_h); + $size_h = $height; + } else { + $size_h = round($orig_h * $width / $orig_w); + $size_w = $width; + } + } + } + } else { + $size_w = $orig_w; + $size_h = $orig_h; + } + + elFinder::extendTimeLimit(300); + switch ($this->imgLib) { + case 'imagick': + + try { + $img = new imagick($path); + } catch (Exception $e) { + return false; + } + + // Imagick::FILTER_BOX faster than FILTER_LANCZOS so use for createTmb + // resize bench: http://app-mgng.rhcloud.com/9 + // resize sample: http://www.dylanbeattie.net/magick/filters/result.html + $filter = ($destformat === 'png' /* createTmb */) ? Imagick::FILTER_BOX : Imagick::FILTER_LANCZOS; + + $ani = ($img->getNumberImages() > 1); + if ($ani && is_null($destformat)) { + $img = $img->coalesceImages(); + do { + $img->resizeImage($size_w, $size_h, $filter, 1); + } while ($img->nextImage()); + $img->optimizeImageLayers(); + $result = $img->writeImages($path, true); + } else { + if ($ani) { + $img->setFirstIterator(); + } + if (strtoupper($img->getImageFormat()) === 'JPEG') { + $img->setImageCompression(imagick::COMPRESSION_JPEG); + $img->setImageCompressionQuality($jpgQuality); + if (isset($options['preserveExif']) && !$options['preserveExif']) { + try { + $orientation = $img->getImageOrientation(); + } catch (ImagickException $e) { + $orientation = 0; + } + $img->stripImage(); + if ($orientation) { + $img->setImageOrientation($orientation); + } + } + if ($this->options['jpgProgressive']) { + $img->setInterlaceScheme(Imagick::INTERLACE_PLANE); + } + } + $img->resizeImage($size_w, $size_h, $filter, true); + if ($destformat) { + $result = $this->imagickImage($img, $path, $destformat, $jpgQuality); + } else { + $result = $img->writeImage($path); + } + } + + $img->clear(); + + return $result ? $path : false; + + break; + + case 'convert': + extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); + /** + * @var string $ani + * @var string $index + * @var string $coalesce + * @var string $deconstruct + * @var string $jpgQuality + * @var string $quotedPath + * @var string $quotedDstPath + * @var string $interlace + */ + $filter = ($destformat === 'png' /* createTmb */) ? '-filter Box' : '-filter Lanczos'; + $strip = (isset($options['preserveExif']) && !$options['preserveExif']) ? ' -strip' : ''; + $cmd = sprintf('%s %s%s%s%s%s %s -geometry %dx%d! %s %s', ELFINDER_CONVERT_PATH, $quotedPath, $coalesce, $jpgQuality, $strip, $interlace, $filter, $size_w, $size_h, $deconstruct, $quotedDstPath); + + $result = false; + if ($this->procExec($cmd) === 0) { + $result = true; + } + return $result ? $path : false; + + break; + + case 'gd': + elFinder::expandMemoryForGD(array($s, array($size_w, $size_h))); + $img = $this->gdImageCreate($path, $s['mime']); + + if ($img && false != ($tmp = imagecreatetruecolor($size_w, $size_h))) { + + $bgNum = false; + if ($s[2] === IMAGETYPE_GIF && (!$destformat || $destformat === 'gif')) { + $bgIdx = imagecolortransparent($img); + if ($bgIdx !== -1) { + $c = imagecolorsforindex($img, $bgIdx); + $bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']); + imagefill($tmp, 0, 0, $bgNum); + imagecolortransparent($tmp, $bgNum); + } + } + if ($bgNum === false) { + $this->gdImageBackground($tmp, 'transparent'); + } + + if (!imagecopyresampled($tmp, $img, 0, 0, 0, 0, $size_w, $size_h, $s[0], $s[1])) { + return false; + } + + $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); + + imagedestroy($img); + imagedestroy($tmp); + + return $result ? $path : false; + + } + break; + } + + return false; + } + + /** + * Crop image + * + * @param string $path image file + * @param int $width crop width + * @param int $height crop height + * @param bool $x crop left offset + * @param bool $y crop top offset + * @param string $destformat image destination format + * @param int $jpgQuality JEPG quality (1-100) + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + protected function imgCrop($path, $width, $height, $x, $y, $destformat = null, $jpgQuality = null) + { + if (($s = getimagesize($path)) == false) { + return false; + } + + if (!$jpgQuality) { + $jpgQuality = $this->options['jpgQuality']; + } + + elFinder::extendTimeLimit(300); + switch ($this->imgLib) { + case 'imagick': + + try { + $img = new imagick($path); + } catch (Exception $e) { + return false; + } + + $ani = ($img->getNumberImages() > 1); + if ($ani && is_null($destformat)) { + $img = $img->coalesceImages(); + do { + $img->setImagePage($s[0], $s[1], 0, 0); + $img->cropImage($width, $height, $x, $y); + $img->setImagePage($width, $height, 0, 0); + } while ($img->nextImage()); + $img->optimizeImageLayers(); + $result = $img->writeImages($path, true); + } else { + if ($ani) { + $img->setFirstIterator(); + } + $img->setImagePage($s[0], $s[1], 0, 0); + $img->cropImage($width, $height, $x, $y); + $img->setImagePage($width, $height, 0, 0); + $result = $this->imagickImage($img, $path, $destformat, $jpgQuality); + } + + $img->clear(); + + return $result ? $path : false; + + break; + + case 'convert': + extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); + /** + * @var string $ani + * @var string $index + * @var string $coalesce + * @var string $deconstruct + * @var string $jpgQuality + * @var string $quotedPath + * @var string $quotedDstPath + * @var string $interlace + */ + $cmd = sprintf('%s %s%s%s%s -crop %dx%d+%d+%d%s %s', ELFINDER_CONVERT_PATH, $quotedPath, $coalesce, $jpgQuality, $interlace, $width, $height, $x, $y, $deconstruct, $quotedDstPath); + + $result = false; + if ($this->procExec($cmd) === 0) { + $result = true; + } + return $result ? $path : false; + + break; + + case 'gd': + elFinder::expandMemoryForGD(array($s, array($width, $height))); + $img = $this->gdImageCreate($path, $s['mime']); + + if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { + + $bgNum = false; + if ($s[2] === IMAGETYPE_GIF && (!$destformat || $destformat === 'gif')) { + $bgIdx = imagecolortransparent($img); + if ($bgIdx !== -1) { + $c = imagecolorsforindex($img, $bgIdx); + $bgNum = imagecolorallocate($tmp, $c['red'], $c['green'], $c['blue']); + imagefill($tmp, 0, 0, $bgNum); + imagecolortransparent($tmp, $bgNum); + } + } + if ($bgNum === false) { + $this->gdImageBackground($tmp, 'transparent'); + } + + $size_w = $width; + $size_h = $height; + + if ($s[0] < $width || $s[1] < $height) { + $size_w = $s[0]; + $size_h = $s[1]; + } + + if (!imagecopy($tmp, $img, 0, 0, $x, $y, $size_w, $size_h)) { + return false; + } + + $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); + + imagedestroy($img); + imagedestroy($tmp); + + return $result ? $path : false; + + } + break; + } + + return false; + } + + /** + * Put image to square + * + * @param string $path image file + * @param int $width square width + * @param int $height square height + * @param int|string $align reserved + * @param int|string $valign reserved + * @param string $bgcolor square background color in #rrggbb format + * @param string $destformat image destination format + * @param int $jpgQuality JEPG quality (1-100) + * + * @return false|string + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + protected function imgSquareFit($path, $width, $height, $align = 'center', $valign = 'middle', $bgcolor = '#0000ff', $destformat = null, $jpgQuality = null) + { + if (($s = getimagesize($path)) == false) { + return false; + } + + $result = false; + + /* Coordinates for image over square aligning */ + $y = ceil(abs($height - $s[1]) / 2); + $x = ceil(abs($width - $s[0]) / 2); + + if (!$jpgQuality) { + $jpgQuality = $this->options['jpgQuality']; + } + + elFinder::extendTimeLimit(300); + switch ($this->imgLib) { + case 'imagick': + try { + $img = new imagick($path); + } catch (Exception $e) { + return false; + } + + if ($bgcolor === 'transparent') { + $bgcolor = 'rgba(255, 255, 255, 0.0)'; + } + $ani = ($img->getNumberImages() > 1); + if ($ani && is_null($destformat)) { + $img1 = new Imagick(); + $img1->setFormat('gif'); + $img = $img->coalesceImages(); + do { + $gif = new Imagick(); + $gif->newImage($width, $height, new ImagickPixel($bgcolor)); + $gif->setImageColorspace($img->getImageColorspace()); + $gif->setImageFormat('gif'); + $gif->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); + $gif->setImageDelay($img->getImageDelay()); + $gif->setImageIterations($img->getImageIterations()); + $img1->addImage($gif); + $gif->clear(); + } while ($img->nextImage()); + $img1->optimizeImageLayers(); + $result = $img1->writeImages($path, true); + } else { + if ($ani) { + $img->setFirstIterator(); + } + $img1 = new Imagick(); + $img1->newImage($width, $height, new ImagickPixel($bgcolor)); + $img1->setImageColorspace($img->getImageColorspace()); + $img1->compositeImage($img, imagick::COMPOSITE_OVER, $x, $y); + $result = $this->imagickImage($img1, $path, $destformat, $jpgQuality); + } + + $img1->clear(); + $img->clear(); + return $result ? $path : false; + + break; + + case 'convert': + extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); + /** + * @var string $ani + * @var string $index + * @var string $coalesce + * @var string $deconstruct + * @var string $jpgQuality + * @var string $quotedPath + * @var string $quotedDstPath + * @var string $interlace + */ + if ($bgcolor === 'transparent') { + $bgcolor = 'rgba(255, 255, 255, 0.0)'; + } + $cmd = sprintf('%s -size %dx%d "xc:%s" png:- | convert%s%s%s png:- %s -geometry +%d+%d -compose over -composite%s %s', ELFINDER_CONVERT_PATH, $width, $height, $bgcolor, $coalesce, $jpgQuality, $interlace, $quotedPath, $x, $y, $deconstruct, $quotedDstPath); + + $result = false; + if ($this->procExec($cmd) === 0) { + $result = true; + } + return $result ? $path : false; + + break; + + case 'gd': + elFinder::expandMemoryForGD(array($s, array($width, $height))); + $img = $this->gdImageCreate($path, $s['mime']); + + if ($img && false != ($tmp = imagecreatetruecolor($width, $height))) { + + $this->gdImageBackground($tmp, $bgcolor); + if ($bgcolor === 'transparent' && ($destformat === 'png' || $s[2] === IMAGETYPE_PNG)) { + $bgNum = imagecolorallocatealpha($tmp, 255, 255, 255, 127); + imagefill($tmp, 0, 0, $bgNum); + } + + if (!imagecopy($tmp, $img, $x, $y, 0, 0, $s[0], $s[1])) { + return false; + } + + $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); + + imagedestroy($img); + imagedestroy($tmp); + + return $result ? $path : false; + } + break; + } + + return false; + } + + /** + * Rotate image + * + * @param string $path image file + * @param int $degree rotete degrees + * @param string $bgcolor square background color in #rrggbb format + * @param string $destformat image destination format + * @param int $jpgQuality JEPG quality (1-100) + * + * @return string|false + * @throws elFinderAbortException + * @author nao-pon + * @author Troex Nevelin + */ + protected function imgRotate($path, $degree, $bgcolor = '#ffffff', $destformat = null, $jpgQuality = null) + { + if (($s = getimagesize($path)) == false || $degree % 360 === 0) { + return false; + } + + $result = false; + + // try lossless rotate + if ($degree % 90 === 0 && in_array($s[2], array(IMAGETYPE_JPEG, IMAGETYPE_JPEG2000))) { + $count = ($degree / 90) % 4; + $exiftran = array( + 1 => '-9', + 2 => '-1', + 3 => '-2' + ); + $jpegtran = array( + 1 => '90', + 2 => '180', + 3 => '270' + ); + $quotedPath = escapeshellarg($path); + $cmds = array(); + if ($this->procExec(ELFINDER_EXIFTRAN_PATH . ' -h') === 0) { + $cmds[] = ELFINDER_EXIFTRAN_PATH . ' -i ' . $exiftran[$count] . ' -- ' . $quotedPath; + } + if ($this->procExec(ELFINDER_JPEGTRAN_PATH . ' -version') === 0) { + $cmds[] = ELFINDER_JPEGTRAN_PATH . ' -rotate ' . $jpegtran[$count] . ' -copy all -outfile ' . $quotedPath . ' -- ' . $quotedPath; + } + foreach ($cmds as $cmd) { + if ($this->procExec($cmd) === 0) { + $result = true; + break; + } + } + if ($result) { + return $path; + } + } + + if (!$jpgQuality) { + $jpgQuality = $this->options['jpgQuality']; + } + + elFinder::extendTimeLimit(300); + switch ($this->imgLib) { + case 'imagick': + try { + $img = new imagick($path); + } catch (Exception $e) { + return false; + } + + if ($s[2] === IMAGETYPE_GIF || $s[2] === IMAGETYPE_PNG) { + $bgcolor = 'rgba(255, 255, 255, 0.0)'; + } + if ($img->getNumberImages() > 1) { + $img = $img->coalesceImages(); + do { + $img->rotateImage(new ImagickPixel($bgcolor), $degree); + } while ($img->nextImage()); + $img->optimizeImageLayers(); + $result = $img->writeImages($path, true); + } else { + $img->rotateImage(new ImagickPixel($bgcolor), $degree); + $result = $this->imagickImage($img, $path, $destformat, $jpgQuality); + } + $img->clear(); + return $result ? $path : false; + + break; + + case 'convert': + extract($this->imageMagickConvertPrepare($path, $destformat, $jpgQuality, $s)); + /** + * @var string $ani + * @var string $index + * @var string $coalesce + * @var string $deconstruct + * @var string $jpgQuality + * @var string $quotedPath + * @var string $quotedDstPath + * @var string $interlace + */ + if ($s[2] === IMAGETYPE_GIF || $s[2] === IMAGETYPE_PNG) { + $bgcolor = 'rgba(255, 255, 255, 0.0)'; + } + $cmd = sprintf('%s%s%s%s -background "%s" -rotate %d%s -- %s %s', ELFINDER_CONVERT_PATH, $coalesce, $jpgQuality, $interlace, $bgcolor, $degree, $deconstruct, $quotedPath, $quotedDstPath); + + $result = false; + if ($this->procExec($cmd) === 0) { + $result = true; + } + return $result ? $path : false; + + break; + + case 'gd': + elFinder::expandMemoryForGD(array($s, $s)); + $img = $this->gdImageCreate($path, $s['mime']); + + $degree = 360 - $degree; + + $bgNum = -1; + $bgIdx = false; + if ($s[2] === IMAGETYPE_GIF) { + $bgIdx = imagecolortransparent($img); + if ($bgIdx !== -1) { + $c = imagecolorsforindex($img, $bgIdx); + $w = imagesx($img); + $h = imagesy($img); + $newImg = imagecreatetruecolor($w, $h); + imagepalettecopy($newImg, $img); + $bgNum = imagecolorallocate($newImg, $c['red'], $c['green'], $c['blue']); + imagefill($newImg, 0, 0, $bgNum); + imagecolortransparent($newImg, $bgNum); + imagecopy($newImg, $img, 0, 0, 0, 0, $w, $h); + imagedestroy($img); + $img = $newImg; + $newImg = null; + } + } else if ($s[2] === IMAGETYPE_PNG) { + $bgNum = imagecolorallocatealpha($img, 255, 255, 255, 127); + } + if ($bgNum === -1) { + list($r, $g, $b) = sscanf($bgcolor, "#%02x%02x%02x"); + $bgNum = imagecolorallocate($img, $r, $g, $b); + } + + $tmp = imageRotate($img, $degree, $bgNum); + if ($bgIdx !== -1) { + imagecolortransparent($tmp, $bgNum); + } + + $result = $this->gdImage($tmp, $path, $destformat, $s['mime'], $jpgQuality); + + imageDestroy($img); + imageDestroy($tmp); + + return $result ? $path : false; + + break; + } + + return false; + } + + /** + * Execute shell command + * + * @param string $command command line + * @param string $output stdout strings + * @param int $return_var process exit code + * @param string $error_output stderr strings + * + * @return int exit code + * @throws elFinderAbortException + * @author Alexey Sukhotin + */ + protected function procExec($command, &$output = '', &$return_var = -1, &$error_output = '', $cwd = null) + { + return elFinder::procExec($command, $output, $return_var, $error_output); + } + + /** + * Remove thumbnail, also remove recursively if stat is directory + * + * @param array $stat file stat + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + * @author Troex Nevelin + */ + protected function rmTmb($stat) + { + if ($this->tmbPathWritable) { + if ($stat['mime'] === 'directory') { + foreach ($this->scandirCE($this->decode($stat['hash'])) as $p) { + elFinder::extendTimeLimit(30); + $name = $this->basenameCE($p); + $name != '.' && $name != '..' && $this->rmTmb($this->stat($p)); + } + } else if (!empty($stat['tmb']) && $stat['tmb'] != "1") { + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . rawurldecode($stat['tmb']); + file_exists($tmb) && unlink($tmb); + clearstatcache(); + } + } + } + + /** + * Create an gd image according to the specified mime type + * + * @param string $path image file + * @param string $mime + * + * @return resource|false GD image resource identifier + */ + protected function gdImageCreate($path, $mime) + { + switch ($mime) { + case 'image/jpeg': + return imagecreatefromjpeg($path); + + case 'image/png': + return imagecreatefrompng($path); + + case 'image/gif': + return imagecreatefromgif($path); + + case 'image/x-ms-bmp': + if (!function_exists('imagecreatefrombmp')) { + include_once dirname(__FILE__) . '/libs/GdBmp.php'; + } + return imagecreatefrombmp($path); + + case 'image/xbm': + return imagecreatefromxbm($path); + + case 'image/xpm': + return imagecreatefromxpm($path); + + case 'image/webp': + return imagecreatefromwebp($path); + } + return false; + } + + /** + * Output gd image to file + * + * @param resource $image gd image resource + * @param string $filename The path to save the file to. + * @param string $destformat The Image type to use for $filename + * @param string $mime The original image mime type + * @param int $jpgQuality JEPG quality (1-100) + * + * @return bool + */ + protected function gdImage($image, $filename, $destformat, $mime, $jpgQuality = null) + { + + if (!$jpgQuality) { + $jpgQuality = $this->options['jpgQuality']; + } + if ($destformat) { + switch ($destformat) { + case 'jpg': + $mime = 'image/jpeg'; + break; + case 'gif': + $mime = 'image/gif'; + break; + case 'png': + default: + $mime = 'image/png'; + break; + } + } + switch ($mime) { + case 'image/gif': + return imagegif($image, $filename); + case 'image/jpeg': + if ($this->options['jpgProgressive']) { + imageinterlace($image, true); + } + return imagejpeg($image, $filename, $jpgQuality); + case 'image/wbmp': + return imagewbmp($image, $filename); + case 'image/png': + default: + return imagepng($image, $filename); + } + } + + /** + * Output imagick image to file + * + * @param imagick $img imagick image resource + * @param string $filename The path to save the file to. + * @param string $destformat The Image type to use for $filename + * @param int $jpgQuality JEPG quality (1-100) + * + * @return bool + */ + protected function imagickImage($img, $filename, $destformat, $jpgQuality = null) + { + + if (!$jpgQuality) { + $jpgQuality = $this->options['jpgQuality']; + } + + try { + if ($destformat) { + if ($destformat === 'gif') { + $img->setImageFormat('gif'); + } else if ($destformat === 'png') { + $img->setImageFormat('png'); + } else if ($destformat === 'jpg') { + $img->setImageFormat('jpeg'); + } + } + if (strtoupper($img->getImageFormat()) === 'JPEG') { + $img->setImageCompression(imagick::COMPRESSION_JPEG); + $img->setImageCompressionQuality($jpgQuality); + if ($this->options['jpgProgressive']) { + $img->setInterlaceScheme(Imagick::INTERLACE_PLANE); + } + try { + $orientation = $img->getImageOrientation(); + } catch (ImagickException $e) { + $orientation = 0; + } + $img->stripImage(); + if ($orientation) { + $img->setImageOrientation($orientation); + } + } + $result = $img->writeImage($filename); + } catch (Exception $e) { + $result = false; + } + + return $result; + } + + /** + * Assign the proper background to a gd image + * + * @param resource $image gd image resource + * @param string $bgcolor background color in #rrggbb format + */ + protected function gdImageBackground($image, $bgcolor) + { + + if ($bgcolor === 'transparent') { + imagealphablending($image, false); + imagesavealpha($image, true); + } else { + list($r, $g, $b) = sscanf($bgcolor, "#%02x%02x%02x"); + $bgcolor1 = imagecolorallocate($image, $r, $g, $b); + imagefill($image, 0, 0, $bgcolor1); + } + } + + /** + * Prepare variables for exec convert of ImageMagick + * + * @param string $path + * @param string $destformat + * @param int $jpgQuality + * @param array $imageSize + * @param null $mime + * + * @return array + * @throws elFinderAbortException + */ + protected function imageMagickConvertPrepare($path, $destformat, $jpgQuality, $imageSize = null, $mime = null) + { + if (is_null($imageSize)) { + $imageSize = getimagesize($path); + } + if (is_null($mime)) { + $mime = $this->mimetype($path); + } + $srcType = $this->getExtentionByMime($mime, ':'); + $ani = false; + if (preg_match('/^(?:gif|png|ico)/', $srcType)) { + $cmd = ELFINDER_IDENTIFY_PATH . ' -- ' . escapeshellarg($srcType . $path); + if ($this->procExec($cmd, $o) === 0) { + $ani = preg_split('/(?:\r\n|\n|\r)/', trim($o)); + if (count($ani) < 2) { + $ani = false; + } + } + } + $coalesce = $index = $interlace = ''; + $deconstruct = ' +repage'; + if ($ani && $destformat !== 'png'/* not createTmb */) { + if (is_null($destformat)) { + $coalesce = ' -coalesce -repage 0x0'; + $deconstruct = ' +repage -deconstruct -layers optimize'; + } else if ($imageSize) { + if ($srcType === 'ico:') { + $index = '[0]'; + foreach ($ani as $_i => $_info) { + if (preg_match('/ (\d+)x(\d+) /', $_info, $m)) { + if ($m[1] == $imageSize[0] && $m[2] == $imageSize[1]) { + $index = '[' . $_i . ']'; + break; + } + } + } + } + } + } else { + $index = '[0]'; + } + if ($imageSize && ($imageSize[2] === IMAGETYPE_JPEG || $imageSize[2] === IMAGETYPE_JPEG2000)) { + $jpgQuality = ' -quality ' . $jpgQuality; + if ($this->options['jpgProgressive']) { + $interlace = ' -interlace Plane'; + } + } else { + $jpgQuality = ''; + } + $quotedPath = escapeshellarg($srcType . $path . $index); + $quotedDstPath = escapeshellarg(($destformat ? ($destformat . ':') : $srcType) . $path); + return compact('ani', 'index', 'coalesce', 'deconstruct', 'jpgQuality', 'quotedPath', 'quotedDstPath', 'interlace'); + } + + /*********************** misc *************************/ + + /** + * Find position of first occurrence of string in a string with multibyte support + * + * @param string $haystack The string being checked. + * @param string $needle The string to find in haystack. + * @param int $offset The search offset. If it is not specified, 0 is used. + * + * @return int|bool + * @author Alexey Sukhotin + **/ + protected function stripos($haystack, $needle, $offset = 0) + { + if (function_exists('mb_stripos')) { + return mb_stripos($haystack, $needle, $offset, 'UTF-8'); + } else if (function_exists('mb_strtolower') && function_exists('mb_strpos')) { + return mb_strpos(mb_strtolower($haystack, 'UTF-8'), mb_strtolower($needle, 'UTF-8'), $offset); + } + return stripos($haystack, $needle, $offset); + } + + /** + * Default serach match method (name match) + * + * @param String $name Item name + * @param String $query Query word + * @param String $path Item path + * + * @return bool @return bool + */ + protected function searchMatchName($name, $query, $path) + { + return $this->stripos($name, $query) !== false; + } + + /** + * Get server side available archivers + * + * @param bool $use_cache + * + * @return array + * @throws elFinderAbortException + */ + protected function getArchivers($use_cache = true) + { + $sessionKey = 'archivers'; + if ($use_cache) { + if (isset($this->options['archivers']) && is_array($this->options['archivers']) && $this->options['archivers']) { + $cache = $this->options['archivers']; + } else { + $cache = elFinder::$archivers; + } + if ($cache) { + return $cache; + } else { + if ($cache = $this->session->get($sessionKey, array())) { + return elFinder::$archivers = $cache; + } + } + } + + $arcs = array( + 'create' => array(), + 'extract' => array() + ); + + if ($this->procExec('') === 0) { + + $this->procExec(ELFINDER_TAR_PATH . ' --version', $o, $ctar); + + if ($ctar == 0) { + $arcs['create']['application/x-tar'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-chf', 'ext' => 'tar'); + $arcs['extract']['application/x-tar'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-xf', 'ext' => 'tar', 'toSpec' => '-C ', 'getsize' => array('argc' => '-xvf', 'toSpec' => '--to-stdout|wc -c', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]*([0-9]+)[^\r\n]*$/s', 'replace' => '$1')); + unset($o); + $this->procExec(ELFINDER_GZIP_PATH . ' --version', $o, $c); + if ($c == 0) { + $arcs['create']['application/x-gzip'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-czhf', 'ext' => 'tgz'); + $arcs['extract']['application/x-gzip'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-xzf', 'ext' => 'tgz', 'toSpec' => '-C ', 'getsize' => array('argc' => '-xvf', 'toSpec' => '--to-stdout|wc -c', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]*([0-9]+)[^\r\n]*$/s', 'replace' => '$1')); + } + unset($o); + $this->procExec(ELFINDER_BZIP2_PATH . ' --version', $o, $c); + if ($c == 0) { + $arcs['create']['application/x-bzip2'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-cjhf', 'ext' => 'tbz'); + $arcs['extract']['application/x-bzip2'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-xjf', 'ext' => 'tbz', 'toSpec' => '-C ', 'getsize' => array('argc' => '-xvf', 'toSpec' => '--to-stdout|wc -c', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]*([0-9]+)[^\r\n]*$/s', 'replace' => '$1')); + } + unset($o); + $this->procExec(ELFINDER_XZ_PATH . ' --version', $o, $c); + if ($c == 0) { + $arcs['create']['application/x-xz'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-cJhf', 'ext' => 'xz'); + $arcs['extract']['application/x-xz'] = array('cmd' => ELFINDER_TAR_PATH, 'argc' => '-xJf', 'ext' => 'xz', 'toSpec' => '-C ', 'getsize' => array('argc' => '-xvf', 'toSpec' => '--to-stdout|wc -c', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]*([0-9]+)[^\r\n]*$/s', 'replace' => '$1')); + } + } + unset($o); + $this->procExec(ELFINDER_ZIP_PATH . ' -h', $o, $c); + if ($c == 0) { + $arcs['create']['application/zip'] = array('cmd' => ELFINDER_ZIP_PATH, 'argc' => '-r9 -q', 'ext' => 'zip'); + } + unset($o); + $this->procExec(ELFINDER_UNZIP_PATH . ' --help', $o, $c); + if ($c == 0) { + $arcs['extract']['application/zip'] = array('cmd' => ELFINDER_UNZIP_PATH, 'argc' => '-q', 'ext' => 'zip', 'toSpec' => '-d ', 'getsize' => array('argc' => '-Z -t', 'regex' => '/^.+?,\s?([0-9]+).+$/', 'replace' => '$1')); + } + unset($o); + $this->procExec(ELFINDER_RAR_PATH, $o, $c); + if ($c == 0 || $c == 7) { + $arcs['create']['application/x-rar'] = array('cmd' => ELFINDER_RAR_PATH, 'argc' => 'a -inul' . (defined('ELFINDER_RAR_MA4') && ELFINDER_RAR_MA4? ' -ma4' : '') . ' --', 'ext' => 'rar'); + } + unset($o); + $this->procExec(ELFINDER_UNRAR_PATH, $o, $c); + if ($c == 0 || $c == 7) { + $arcs['extract']['application/x-rar'] = array('cmd' => ELFINDER_UNRAR_PATH, 'argc' => 'x -y', 'ext' => 'rar', 'toSpec' => '', 'getsize' => array('argc' => 'l', 'regex' => '/^.+(?:\r\n|\n|\r)(?:(?:[^\r\n0-9]+[0-9]+[^\r\n0-9]+([0-9]+)[^\r\n]+)|(?:[^\r\n0-9]+([0-9]+)[^\r\n0-9]+[0-9]+[^\r\n]*))$/s', 'replace' => '$1')); + } + unset($o); + $this->procExec(ELFINDER_7Z_PATH, $o, $c); + if ($c == 0) { + $arcs['create']['application/x-7z-compressed'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'a --', 'ext' => '7z'); + $arcs['extract']['application/x-7z-compressed'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'x -y', 'ext' => '7z', 'toSpec' => '-o', 'getsize' => array('argc' => 'l', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]+([0-9]+)[^\r\n]+$/s', 'replace' => '$1')); + + if (empty($arcs['create']['application/zip'])) { + $arcs['create']['application/zip'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'a -tzip --', 'ext' => 'zip'); + } + if (empty($arcs['extract']['application/zip'])) { + $arcs['extract']['application/zip'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'x -tzip -y', 'ext' => 'zip', 'toSpec' => '-o', 'getsize' => array('argc' => 'l', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]+([0-9]+)[^\r\n]+$/s', 'replace' => '$1')); + } + if (empty($arcs['create']['application/x-tar'])) { + $arcs['create']['application/x-tar'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'a -ttar --', 'ext' => 'tar'); + } + if (empty($arcs['extract']['application/x-tar'])) { + $arcs['extract']['application/x-tar'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'x -ttar -y', 'ext' => 'tar', 'toSpec' => '-o', 'getsize' => array('argc' => 'l', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]+([0-9]+)[^\r\n]+$/s', 'replace' => '$1')); + } + if (substr(PHP_OS, 0, 3) === 'WIN' && empty($arcs['extract']['application/x-rar'])) { + $arcs['extract']['application/x-rar'] = array('cmd' => ELFINDER_7Z_PATH, 'argc' => 'x -trar -y', 'ext' => 'rar', 'toSpec' => '-o', 'getsize' => array('argc' => 'l', 'regex' => '/^.+(?:\r\n|\n|\r)[^\r\n0-9]+([0-9]+)[^\r\n]+$/s', 'replace' => '$1')); + } + } + + } + + // Use PHP ZipArchive Class + if (class_exists('ZipArchive', false)) { + if (empty($arcs['create']['application/zip'])) { + $arcs['create']['application/zip'] = array('cmd' => 'phpfunction', 'argc' => array('self', 'zipArchiveZip'), 'ext' => 'zip'); + } + if (empty($arcs['extract']['application/zip'])) { + $arcs['extract']['application/zip'] = array('cmd' => 'phpfunction', 'argc' => array('self', 'zipArchiveUnzip'), 'ext' => 'zip'); + } + } + + $this->session->set($sessionKey, $arcs); + return elFinder::$archivers = $arcs; + } + + /** + * Resolve relative / (Unix-like)absolute path + * + * @param string $path target path + * @param string $base base path + * + * @return string + */ + protected function getFullPath($path, $base) + { + $separator = $this->separator; + $systemroot = $this->systemRoot; + $base = (string)$base; + + if ($base[0] === $separator && substr($base, 0, strlen($systemroot)) !== $systemroot) { + $base = $systemroot . substr($base, 1); + } + if ($base !== $systemroot) { + $base = rtrim($base, $separator); + } + + $sepquoted = preg_quote($separator, '#'); + + // normalize `//` to `/` + $path = preg_replace('#' . $sepquoted . '+#', $separator, $path); // '#/+#' + + // remove `./` + $path = preg_replace('#(?<=^|' . $sepquoted . ')\.' . $sepquoted . '#', '', $path); // '#(?<=^|/)\./#' + + // 'Here' + if ($path === '') return $base; + + // join $base to $path if $path start `../` + if (substr($path, 0, 3) === '..' . $separator) { + $path = $base . $separator . $path; + } + + // normalize `/../` + $normreg = '#(' . $sepquoted . ')[^' . $sepquoted . ']+' . $sepquoted . '\.\.' . $sepquoted . '#'; // '#(/)[^\/]+/\.\./#' + while (preg_match($normreg, $path)) { + $path = preg_replace($normreg, '$1', $path, 1); + } + if ($path !== $systemroot) { + $path = rtrim($path, $separator); + } + + // discard the surplus `../` + $path = str_replace('..' . $separator, '', $path); + + // Absolute path + if ($path[0] === $separator || strpos($path, $systemroot) === 0) { + return $path; + } + + $preg_separator = '#' . $sepquoted . '#'; + + // Relative path from 'Here' + if (substr($path, 0, 2) === '.' . $separator || $path[0] !== '.') { + $arrn = preg_split($preg_separator, $path, -1, PREG_SPLIT_NO_EMPTY); + if ($arrn[0] !== '.') { + array_unshift($arrn, '.'); + } + $arrn[0] = rtrim($base, $separator); + return join($separator, $arrn); + } + + return $path; + } + + /** + * Remove directory recursive on local file system + * + * @param string $dir Target dirctory path + * + * @return boolean + * @throws elFinderAbortException + * @author Naoki Sawada + */ + public function rmdirRecursive($dir) + { + return self::localRmdirRecursive($dir); + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + * @author Naoki Sawada + */ + protected function makeArchive($dir, $files, $name, $arc) + { + if ($arc['cmd'] === 'phpfunction') { + if (is_callable($arc['argc'])) { + call_user_func_array($arc['argc'], array($dir, $files, $name)); + } + } else { + $cwd = getcwd(); + if (chdir($dir)) { + foreach ($files as $i => $file) { + $files[$i] = '.' . DIRECTORY_SEPARATOR . basename($file); + } + $files = array_map('escapeshellarg', $files); + $prefix = $switch = ''; + // The zip command accepts the "-" at the beginning of the file name as a command switch, + // and can't use '--' before archive name, so add "./" to name for security reasons. + if ($arc['ext'] === 'zip' && strpos($arc['argc'], '-tzip') === false) { + $prefix = './'; + $switch = '-- '; + } + $cmd = $arc['cmd'] . ' ' . $arc['argc'] . ' ' . $prefix . escapeshellarg($name) . ' ' . $switch . implode(' ', $files); + $err_out = ''; + $this->procExec($cmd, $o, $c, $err_out, $dir); + chdir($cwd); + } else { + return false; + } + } + $path = $dir . DIRECTORY_SEPARATOR . $name; + return file_exists($path) ? $path : false; + } + + /** + * Unpack archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * @param bool|string $mode bool: remove archive ( unlink($path) ) | string: extract to directory + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + * @author Naoki Sawada + */ + protected function unpackArchive($path, $arc, $mode = true) + { + if (is_string($mode)) { + $dir = $mode; + $chdir = null; + $remove = false; + } else { + $dir = dirname($path); + $chdir = $dir; + $remove = $mode; + } + $dir = realpath($dir); + $path = realpath($path); + if ($arc['cmd'] === 'phpfunction') { + if (is_callable($arc['argc'])) { + call_user_func_array($arc['argc'], array($path, $dir)); + } + } else { + $cwd = getcwd(); + if (!$chdir || chdir($dir)) { + if (!empty($arc['getsize'])) { + // Check total file size after extraction + $getsize = $arc['getsize']; + if (is_array($getsize) && !empty($getsize['regex']) && !empty($getsize['replace'])) { + $cmd = $arc['cmd'] . ' ' . $getsize['argc'] . ' ' . escapeshellarg($path) . (!empty($getsize['toSpec'])? (' ' . $getsize['toSpec']): ''); + $this->procExec($cmd, $o, $c); + if ($o) { + $size = preg_replace($getsize['regex'], $getsize['replace'], trim($o)); + $comp = function_exists('bccomp')? 'bccomp' : 'strnatcmp'; + if (!empty($this->options['maxArcFilesSize'])) { + if ($comp($size, (string)$this->options['maxArcFilesSize']) > 0) { + throw new Exception(elFinder::ERROR_ARC_MAXSIZE); + } + } + } + unset($o, $c); + } + } + if ($chdir) { + $cmd = $arc['cmd'] . ' ' . $arc['argc'] . ' ' . escapeshellarg(basename($path)); + } else { + $cmd = $arc['cmd'] . ' ' . $arc['argc'] . ' ' . escapeshellarg($path) . ' ' . $arc['toSpec'] . escapeshellarg($dir); + } + $this->procExec($cmd, $o, $c); + $chdir && chdir($cwd); + } + } + $remove && unlink($path); + } + + /** + * Check and filter the extracted items + * + * @param string $path target local path + * @param array $checks types to check default: ['symlink', 'name', 'writable', 'mime'] + * + * @return array ['symlinks' => [], 'names' => [], 'writables' => [], 'mimes' => [], 'rmNames' => [], 'totalSize' => 0] + * @throws elFinderAbortException + * @throws Exception + * @author Naoki Sawada + */ + protected function checkExtractItems($path, $checks = null) + { + if (is_null($checks) || !is_array($checks)) { + $checks = array('symlink', 'name', 'writable', 'mime'); + } + $chkSymlink = in_array('symlink', $checks); + $chkName = in_array('name', $checks); + $chkWritable = in_array('writable', $checks); + $chkMime = in_array('mime', $checks); + + $res = array( + 'symlinks' => array(), + 'names' => array(), + 'writables' => array(), + 'mimes' => array(), + 'rmNames' => array(), + 'totalSize' => 0 + ); + + if (is_dir($path)) { + $files = self::localScandir($path); + } else { + $files = array(basename($path)); + $path = dirname($path); + } + + foreach ($files as $name) { + $p = $path . DIRECTORY_SEPARATOR . $name; + $utf8Name = elFinder::$instance->utf8Encode($name); + if ($name !== $utf8Name) { + $fsSame = false; + if ($this->encoding) { + // test as fs encoding + $_utf8 = @iconv($this->encoding, 'utf-8//IGNORE', $name); + if (@iconv('utf-8', $this->encoding.'//IGNORE', $_utf8) === $name) { + $fsSame = true; + $utf8Name = $_utf8; + } else { + $_name = $this->convEncIn($utf8Name, true); + } + } else { + $_name = $utf8Name; + } + if (!$fsSame && rename($p, $path . DIRECTORY_SEPARATOR . $_name)) { + $name = $_name; + $p = $path . DIRECTORY_SEPARATOR . $name; + } + } + if (!is_readable($p)) { + // Perhaps a symbolic link to open_basedir restricted location + self::localRmdirRecursive($p); + $res['symlinks'][] = $p; + $res['rmNames'][] = $utf8Name; + continue; + } + if ($chkSymlink && is_link($p)) { + self::localRmdirRecursive($p); + $res['symlinks'][] = $p; + $res['rmNames'][] = $utf8Name; + continue; + } + $isDir = is_dir($p); + if ($chkName && !$this->nameAccepted($name, $isDir)) { + self::localRmdirRecursive($p); + $res['names'][] = $p; + $res['rmNames'][] = $utf8Name; + continue; + } + if ($chkWritable && !$this->attr($p, 'write', null, $isDir)) { + self::localRmdirRecursive($p); + $res['writables'][] = $p; + $res['rmNames'][] = $utf8Name; + continue; + } + if ($isDir) { + $cRes = $this->checkExtractItems($p, $checks); + foreach ($cRes as $k => $v) { + if (is_array($v)) { + $res[$k] = array_merge($res[$k], $cRes[$k]); + } else { + $res[$k] += $cRes[$k]; + } + } + } else { + if ($chkMime && ($mimeByName = elFinderVolumeDriver::mimetypeInternalDetect($name)) && !$this->allowPutMime($mimeByName)) { + self::localRmdirRecursive($p); + $res['mimes'][] = $p; + $res['rmNames'][] = $utf8Name; + continue; + } + $res['totalSize'] += (int)sprintf('%u', filesize($p)); + } + } + $res['rmNames'] = array_unique($res['rmNames']); + + return $res; + } + + /** + * Return files of target directory that is dotfiles excludes. + * + * @param string $dir target directory path + * + * @return array + * @throws Exception + * @author Naoki Sawada + */ + protected static function localScandir($dir) + { + // PHP function scandir() is not work well in specific environment. I dont know why. + // ref. https://github.com/Studio-42/elFinder/issues/1248 + $files = array(); + if ($dh = opendir($dir)) { + while (false !== ($file = readdir($dh))) { + if ($file !== '.' && $file !== '..') { + $files[] = $file; + } + } + closedir($dh); + } else { + throw new Exception('Can not open local directory.'); + } + return $files; + } + + /** + * Remove directory recursive on local file system + * + * @param string $dir Target dirctory path + * + * @return boolean + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected static function localRmdirRecursive($dir) + { + // try system command + if (is_callable('exec')) { + $o = ''; + $r = 1; + if (substr(PHP_OS, 0, 3) === 'WIN') { + if (!is_link($dir) && is_dir($dir)) { + exec('rd /S /Q ' . escapeshellarg($dir), $o, $r); + } else { + exec('del /F /Q ' . escapeshellarg($dir), $o, $r); + } + } else { + exec('rm -rf ' . escapeshellarg($dir), $o, $r); + } + if ($r === 0) { + return true; + } + } + if (!is_link($dir) && is_dir($dir)) { + chmod($dir, 0777); + if ($handle = opendir($dir)) { + while (false !== ($file = readdir($handle))) { + if ($file === '.' || $file === '..') { + continue; + } + elFinder::extendTimeLimit(30); + $path = $dir . DIRECTORY_SEPARATOR . $file; + if (!is_link($dir) && is_dir($path)) { + self::localRmdirRecursive($path); + } else { + chmod($path, 0666); + unlink($path); + } + } + closedir($handle); + } + return rmdir($dir); + } else { + chmod($dir, 0666); + return unlink($dir); + } + } + + /** + * Move item recursive on local file system + * + * @param string $src + * @param string $target + * @param bool $overWrite + * @param bool $copyJoin + * + * @return boolean + * @throws elFinderAbortException + * @throws Exception + * @author Naoki Sawada + */ + protected static function localMoveRecursive($src, $target, $overWrite = true, $copyJoin = true) + { + $res = false; + if (!file_exists($target)) { + return rename($src, $target); + } + if (!$copyJoin || !is_dir($target)) { + if ($overWrite) { + if (is_dir($target)) { + $del = self::localRmdirRecursive($target); + } else { + $del = unlink($target); + } + if ($del) { + return rename($src, $target); + } + } + } else { + foreach (self::localScandir($src) as $item) { + $res |= self::localMoveRecursive($src . DIRECTORY_SEPARATOR . $item, $target . DIRECTORY_SEPARATOR . $item, $overWrite, $copyJoin); + } + } + return (bool)$res; + } + + /** + * Create Zip archive using PHP class ZipArchive + * + * @param string $dir target dir + * @param array $files files names list + * @param string|object $zipPath Zip archive name + * + * @return bool + * @author Naoki Sawada + */ + protected static function zipArchiveZip($dir, $files, $zipPath) + { + try { + if ($start = is_string($zipPath)) { + $zip = new ZipArchive(); + if ($zip->open($dir . DIRECTORY_SEPARATOR . $zipPath, ZipArchive::CREATE) !== true) { + $zip = false; + } + } else { + $zip = $zipPath; + } + if ($zip) { + foreach ($files as $file) { + $path = $dir . DIRECTORY_SEPARATOR . $file; + if (is_dir($path)) { + $zip->addEmptyDir($file); + $_files = array(); + if ($handle = opendir($path)) { + while (false !== ($entry = readdir($handle))) { + if ($entry !== "." && $entry !== "..") { + $_files[] = $file . DIRECTORY_SEPARATOR . $entry; + } + } + closedir($handle); + } + if ($_files) { + self::zipArchiveZip($dir, $_files, $zip); + } + } else { + $zip->addFile($path, $file); + } + } + $start && $zip->close(); + } + } catch (Exception $e) { + return false; + } + return true; + } + + /** + * Unpack Zip archive using PHP class ZipArchive + * + * @param string $zipPath Zip archive name + * @param string $toDir Extract to path + * + * @return bool + * @author Naoki Sawada + */ + protected static function zipArchiveUnzip($zipPath, $toDir) + { + try { + $zip = new ZipArchive(); + if ($zip->open($zipPath) === true) { + // Check total file size after extraction + $num = $zip->numFiles; + $size = 0; + $maxSize = empty(self::$maxArcFilesSize)? '' : (string)self::$maxArcFilesSize; + $comp = function_exists('bccomp')? 'bccomp' : 'strnatcmp'; + for ($i = 0; $i < $num; $i++) { + $stat = $zip->statIndex($i); + $size += $stat['size']; + if (strpos((string)$size, 'E') !== false) { + // Cannot handle values exceeding PHP_INT_MAX + throw new Exception(elFinder::ERROR_ARC_MAXSIZE); + } + if (!$maxSize) { + if ($comp($size, $maxSize) > 0) { + throw new Exception(elFinder::ERROR_ARC_MAXSIZE); + } + } + } + // do extract + $zip->extractTo($toDir); + $zip->close(); + } + } catch (Exception $e) { + throw $e; + } + return true; + } + + /** + * Recursive symlinks search + * + * @param string $path file/dir path + * + * @return bool + * @throws Exception + * @author Dmitry (dio) Levashov + */ + protected static function localFindSymlinks($path) + { + if (is_link($path)) { + return true; + } + + if (is_dir($path)) { + foreach (self::localScandir($path) as $name) { + $p = $path . DIRECTORY_SEPARATOR . $name; + if (is_link($p)) { + return true; + } + if (is_dir($p) && self::localFindSymlinks($p)) { + return true; + } + } + } + + return false; + } + + /**==================================* abstract methods *====================================**/ + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _dirname($path); + + /** + * Return file name + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _basename($path); + + /** + * Join dir name and file name and return full path. + * Some drivers (db) use int as path - so we give to concat path to driver itself + * + * @param string $dir dir path + * @param string $name file name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _joinPath($dir, $name); + + /** + * Return normalized path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _normpath($path); + + /** + * Return file path related to root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _relpath($path); + + /** + * Convert path related to root dir into real path + * + * @param string $path rel file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _abspath($path); + + /** + * Return fake path started from root dir. + * Required to show path on client side. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _path($path); + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _inpath($path, $parent); + + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + abstract protected function _stat($path); + + + /***************** file stat ********************/ + + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _subdirs($path); + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _dimensions($path, $mime); + + /******************** file/dir content *********************/ + + /** + * Return files list in directory + * + * @param string $path dir path + * + * @return array + * @author Dmitry (dio) Levashov + **/ + abstract protected function _scandir($path); + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param string $mode open mode + * + * @return resource|false + * @author Dmitry (dio) Levashov + **/ + abstract protected function _fopen($path, $mode = "rb"); + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _fclose($fp, $path = ''); + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _mkdir($path, $name); + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _mkfile($path, $name); + + /** + * Create symlink + * + * @param string $source file to link to + * @param string $targetDir folder to create link in + * @param string $name symlink name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _symlink($source, $targetDir, $name); + + /** + * Copy file into another file (only inside one volume) + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + abstract protected function _copy($source, $targetDir, $name); + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + abstract protected function _move($source, $targetDir, $name); + + /** + * Remove file + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _unlink($path); + + /** + * Remove dir + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _rmdir($path); + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + abstract protected function _save($fp, $dir, $name, $stat); + + /** + * Get file contents + * + * @param string $path file path + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + abstract protected function _getContents($path); + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + abstract protected function _filePutContents($path, $content); + + /** + * Extract files from archive + * + * @param string $path file path + * @param array $arc archiver options + * + * @return bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + abstract protected function _extract($path, $arc); + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + abstract protected function _archive($dir, $files, $name, $arc); + + /** + * Detect available archivers + * + * @return void + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + abstract protected function _checkArchivers(); + + /** + * Change file mode (chmod) + * + * @param string $path file path + * @param string $mode octal string such as '0755' + * + * @return bool + * @author David Bartle, + **/ + abstract protected function _chmod($path, $mode); + + +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeDropbox.class.php b/lib/redactor/elfinder/php/elFinderVolumeDropbox.class.php new file mode 100644 index 0000000..0a0d138 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeDropbox.class.php @@ -0,0 +1,1464 @@ +dropbox_phpFound = class_exists('Dropbox_API'); + + if (! $this->dropbox_phpFound) { + // check with pear + if (include_once 'Dropbox/autoload.php') { + $this->dropbox_phpFound = in_array('Dropbox_autoload', spl_autoload_functions()); + } + } + + $opts = array( + 'consumerKey' => '', + 'consumerSecret' => '', + 'accessToken' => '', + 'accessTokenSecret' => '', + 'dropboxUid' => '', + 'root' => 'dropbox', + 'path' => '/', + 'separator' => '/', + 'PDO_DSN' => '', // if empty use 'sqlite:(metaCachePath|tmbPath)/elFinder_dropbox_db_(hash:dropboxUid+consumerSecret)' + 'PDO_User' => '', + 'PDO_Pass' => '', + 'PDO_Options' => array(), + 'PDO_DBName' => 'dropbox', + 'treeDeep' => 0, + 'tmbPath' => '', + 'tmbURL' => '', + 'tmpPath' => '', + 'getTmbSize' => 'large', // small: 32x32, medium or s: 64x64, large or m: 128x128, l: 640x480, xl: 1024x768 + 'metaCachePath' => '', + 'metaCacheTime' => '600', // 10m + 'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#', + 'rootCssClass' => 'elfinder-navbar-root-dropbox' + ); + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount() + * + * @param $options + * @return Array + * @author Naoki Sawada + */ + public function netmountPrepare($options) { + if (empty($options['consumerKey']) && defined('ELFINDER_DROPBOX_CONSUMERKEY')) $options['consumerKey'] = ELFINDER_DROPBOX_CONSUMERKEY; + if (empty($options['consumerSecret']) && defined('ELFINDER_DROPBOX_CONSUMERSECRET')) $options['consumerSecret'] = ELFINDER_DROPBOX_CONSUMERSECRET; + + if ($options['user'] === 'init') { + + if (! $this->dropbox_phpFound || empty($options['consumerKey']) || empty($options['consumerSecret']) || !class_exists('PDO', false)) { + return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}'); + } + + if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) { + $this->oauth = new Dropbox_OAuth_Curl($options['consumerKey'], $options['consumerSecret']); + } else { + if (class_exists('OAuth', false)) { + $this->oauth = new Dropbox_OAuth_PHP($options['consumerKey'], $options['consumerSecret']); + } else { + if (! class_exists('HTTP_OAuth_Consumer')) { + // We're going to try to load in manually + include 'HTTP/OAuth/Consumer.php'; + } + if (class_exists('HTTP_OAuth_Consumer', false)) { + $this->oauth = new Dropbox_OAuth_PEAR($options['consumerKey'], $options['consumerSecret']); + } + } + } + + if (! $this->oauth) { + return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}'); + } + + if ($options['pass'] === 'init') { + $html = ''; + if ($sessionToken = $this->session->get('DropboxTokens')) { + // token check + try { + list(, $accessToken, $accessTokenSecret) = $sessionToken; + $this->oauth->setToken($accessToken, $accessTokenSecret); + $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']); + $this->dropbox->getAccountInfo(); + $script = ''; + $html = $script; + } catch (Dropbox_Exception $e) { + $this->session->remove('DropboxTokens'); + } + } + if (! $html) { + // get customdata + $cdata = ''; + $innerKeys = array('cmd', 'host', 'options', 'pass', 'protocol', 'user'); + $this->ARGS = $_SERVER['REQUEST_METHOD'] === 'POST'? $_POST : $_GET; + foreach($this->ARGS as $k => $v) { + if (! in_array($k, $innerKeys)) { + $cdata .= '&' . $k . '=' . rawurlencode($v); + } + } + if (strpos($options['url'], 'http') !== 0 ) { + $options['url'] = elFinder::getConnectorUrl(); + } + $callback = $options['url'] + . '?cmd=netmount&protocol=dropbox&host=dropbox.com&user=init&pass=return&node='.$options['id'].$cdata; + + try { + $tokens = $this->oauth->getRequestToken(); + $url= $this->oauth->getAuthorizeUrl(rawurlencode($callback)); + } catch (Dropbox_Exception $e) { + return array('exit' => true, 'body' => '{msg:errAccess}'); + } + + $this->session->set('DropboxAuthTokens', $tokens); + $html = ''; + $html .= ''; + } + return array('exit' => true, 'body' => $html); + } else { + $this->oauth->setToken($this->session->get('DropboxAuthTokens')); + $this->session->remove('DropboxAuthTokens'); + $tokens = $this->oauth->getAccessToken(); + $this->session->set('DropboxTokens', array($_GET['uid'], $tokens['token'], $tokens['token_secret'])); + + $out = array( + 'node' => $_GET['node'], + 'json' => '{"protocol": "dropbox", "mode": "done"}', + 'bind' => 'netmount' + ); + + return array('exit' => 'callback', 'out' => $out); + } + } + if ($sessionToken = $this->session->get('DropboxTokens')) { + list($options['dropboxUid'], $options['accessToken'], $options['accessTokenSecret']) = $sessionToken; + } + unset($options['user'], $options['pass']); + return $options; + } + + /** + * process of on netunmount + * Drop table `dropbox` & rm thumbs + * + * @param $netVolumes + * @param $key + * @return bool + * @internal param array $options + */ + public function netunmount($netVolumes, $key) { + $count = 0; + $dropboxUid = ''; + if (isset($netVolumes[$key])) { + $dropboxUid = $netVolumes[$key]['dropboxUid']; + } + foreach($netVolumes as $volume) { + if ($volume['host'] === 'dropbox' && $volume['dropboxUid'] === $dropboxUid) { + $count++; + } + } + if ($count === 1) { + $this->DB->exec('drop table '.$this->DB_TableName); + foreach(glob(rtrim($this->options['tmbPath'], '\\/').DIRECTORY_SEPARATOR.$this->tmbPrefix.'*.png') as $tmb) { + unlink($tmb); + } + } + return true; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare FTP connection + * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn + * + * @return bool + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function init() { + if (!class_exists('PDO', false)) { + return $this->setError('PHP PDO class is require.'); + } + + if (!$this->options['consumerKey'] + || !$this->options['consumerSecret'] + || !$this->options['accessToken'] + || !$this->options['accessTokenSecret']) { + return $this->setError('Required options undefined.'); + } + + if (empty($this->options['metaCachePath']) && defined('ELFINDER_DROPBOX_META_CACHE_PATH')) { + $this->options['metaCachePath'] = ELFINDER_DROPBOX_META_CACHE_PATH; + } + + // make net mount key + $this->netMountKey = md5(join('-', array('dropbox', $this->options['path']))); + + if (! $this->oauth) { + if (defined('ELFINDER_DROPBOX_USE_CURL_PUT')) { + $this->oauth = new Dropbox_OAuth_Curl($this->options['consumerKey'], $this->options['consumerSecret']); + } else { + if (class_exists('OAuth', false)) { + $this->oauth = new Dropbox_OAuth_PHP($this->options['consumerKey'], $this->options['consumerSecret']); + } else { + if (! class_exists('HTTP_OAuth_Consumer')) { + // We're going to try to load in manually + include 'HTTP/OAuth/Consumer.php'; + } + if (class_exists('HTTP_OAuth_Consumer', false)) { + $this->oauth = new Dropbox_OAuth_PEAR($this->options['consumerKey'], $this->options['consumerSecret']); + } + } + } + } + + if (! $this->oauth) { + return $this->setError('OAuth extension not loaded.'); + } + + // normalize root path + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + if (empty($this->options['alias'])) { + $this->options['alias'] = ($this->options['path'] === '/')? 'Dropbox.com' : 'Dropbox'.$this->options['path']; + } + + $this->rootName = $this->options['alias']; + + try { + $this->oauth->setToken($this->options['accessToken'], $this->options['accessTokenSecret']); + $this->dropbox = new Dropbox_API($this->oauth, $this->options['root']); + } catch (Dropbox_Exception $e) { + $this->session->remove('DropboxTokens'); + return $this->setError('Dropbox error: '.$e->getMessage()); + } + + // user + if (empty($this->options['dropboxUid'])) { + try { + $res = $this->dropbox->getAccountInfo(); + $this->options['dropboxUid'] = $res['uid']; + } catch (Dropbox_Exception $e) { + $this->session->remove('DropboxTokens'); + return $this->setError('Dropbox error: '.$e->getMessage()); + } + } + + $this->dropboxUid = $this->options['dropboxUid']; + $this->tmbPrefix = 'dropbox'.base_convert($this->dropboxUid, 10, 32); + + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } + } + if (!$this->tmp && is_writable($this->options['tmbPath'])) { + $this->tmp = $this->options['tmbPath']; + } + if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { + $this->tmp = $tmp; + } + + if (!empty($this->options['metaCachePath'])) { + if ((is_dir($this->options['metaCachePath']) || mkdir($this->options['metaCachePath'])) && is_writable($this->options['metaCachePath'])) { + $this->metaCache = $this->options['metaCachePath']; + } + } + if (!$this->metaCache && $this->tmp) { + $this->metaCache = $this->tmp; + } + + if (!$this->metaCache) { + return $this->setError('Cache dirctory (metaCachePath or tmp) is require.'); + } + + // setup PDO + if (! $this->options['PDO_DSN']) { + $this->options['PDO_DSN'] = 'sqlite:'.$this->metaCache.DIRECTORY_SEPARATOR.'.elFinder_dropbox_db_'.md5($this->dropboxUid.$this->options['consumerSecret']); + } + // DataBase table name + $this->DB_TableName = $this->options['PDO_DBName']; + // DataBase check or make table + try { + $this->DB = new PDO($this->options['PDO_DSN'], $this->options['PDO_User'], $this->options['PDO_Pass'], $this->options['PDO_Options']); + if (! $this->checkDB()) { + return $this->setError('Can not make DB table'); + } + } catch (PDOException $e) { + return $this->setError('PDO connection failed: '.$e->getMessage()); + } + + $res = $this->deltaCheck($this->isMyReload()); + if ($res !== true) { + if (is_string($res)) { + return $this->setError($res); + } else { + return $this->setError('Could not check API "delta"'); + } + } + + if (is_null($this->options['syncChkAsTs'])) { + $this->options['syncChkAsTs'] = true; + } + if ($this->options['syncChkAsTs']) { + // 'tsPlSleep' minmum 5 sec + $this->options['tsPlSleep'] = max(5, $this->options['tsPlSleep']); + } else { + // 'lsPlSleep' minmum 10 sec + $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']); + } + + return true; + } + + + /** + * Configure after successful mount. + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function configure() { + parent::configure(); + + $this->disabled[] = 'archive'; + $this->disabled[] = 'extract'; + } + + /** + * Check DB for delta cache + * + * @return bool + */ + private function checkDB() { + $res = $this->query('SELECT * FROM sqlite_master WHERE type=\'table\' AND name=\''.$this->DB_TableName.'\''); + if ($res && isset($_REQUEST['init'])) { + // check is index(nameidx) UNIQUE? + $chk = $this->query('SELECT sql FROM sqlite_master WHERE type=\'index\' and name=\'nameidx\''); + if (!$chk || strpos(strtoupper($chk[0]), 'UNIQUE') === false) { + // remake + $this->DB->exec('DROP TABLE '.$this->DB_TableName); + $res = false; + } + } + if (! $res) { + try { + $this->DB->exec('CREATE TABLE '.$this->DB_TableName.'(path text, fname text, dat blob, isdir integer);'); + $this->DB->exec('CREATE UNIQUE INDEX nameidx ON '.$this->DB_TableName.'(path, fname)'); + $this->DB->exec('CREATE INDEX isdiridx ON '.$this->DB_TableName.'(isdir)'); + } catch (PDOException $e) { + return $this->setError($e->getMessage()); + } + } + return true; + } + + /** + * DB query and fetchAll + * + * @param string $sql + * @return boolean|array + */ + private function query($sql) { + if ($sth = $this->DB->query($sql)) { + $res = $sth->fetchAll(PDO::FETCH_COLUMN); + } else { + $res = false; + } + return $res; + } + + /** + * Get dat(dropbox metadata) from DB + * + * @param string $path + * @return array dropbox metadata + */ + private function getDBdat($path) { + if ($res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower($this->_basename($path))).' limit 1')) { + return unserialize($res[0]); + } else { + return array(); + } + } + + /** + * Update DB dat(dropbox metadata) + * + * @param string $path + * @param array $dat + * @return bool|array + */ + private function updateDBdat($path, $dat) { + return $this->query('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($dat)) + . ', isdir=' . ($dat['is_dir']? 1 : 0) + . ' where path='.$this->DB->quote(strtolower($this->_dirname($path))).' and fname='.$this->DB->quote(strtolower($this->_basename($path)))); + } + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function umount() { + + } + + /** + * Get delta data and DB update + * + * @param boolean $refresh force refresh + * @return true|string error message + */ + protected function deltaCheck($refresh = true) { + $chk = false; + if (! $refresh && $chk = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) { + $chk = unserialize($chk[0]); + } + if ($chk && ($chk['mtime'] + $this->options['metaCacheTime']) > $_SERVER['REQUEST_TIME']) { + return true; + } + + try { + $more = true; + $this->DB->beginTransaction(); + + if ($res = $this->query('select dat from '.$this->DB_TableName.' where path=\'\' and fname=\'\' limit 1')) { + $res = unserialize($res[0]); + $cursor = $res['cursor']; + } else { + $cursor = ''; + } + $delete = false; + $reset = false; + $ptimes = array(); + $now = time(); + do { + ini_set('max_execution_time', 120); + $_info = $this->dropbox->delta($cursor); + if (! empty($_info['reset'])) { + $this->DB->exec('TRUNCATE table '.$this->DB_TableName); + $this->DB->exec('insert into '.$this->DB_TableName.' values(\'\', \'\', \''.serialize(array('cursor' => '', 'mtime' => 0)).'\', 0);'); + $this->DB->exec('insert into '.$this->DB_TableName.' values(\'/\', \'\', \''.serialize(array( + 'path' => '/', + 'is_dir' => 1, + 'mime_type' => '', + 'bytes' => 0 + )).'\', 0);'); + $reset = true; + } + $cursor = $_info['cursor']; + + foreach($_info['entries'] as $entry) { + $key = strtolower($entry[0]); + $pkey = strtolower($this->_dirname($key)); + + $path = $this->DB->quote($pkey); + $fname = $this->DB->quote(strtolower($this->_basename($key))); + $where = 'where path='.$path.' and fname='.$fname; + + if (empty($entry[1])) { + $ptimes[$pkey] = isset($ptimes[$pkey])? max(array($now, $ptimes[$pkey])) : $now; + $this->DB->exec('delete from '.$this->DB_TableName.' '.$where); + ! $delete && $delete = true; + continue; + } + + $_itemTime = strtotime(isset($entry[1]['client_mtime'])? $entry[1]['client_mtime'] : $entry[1]['modified']); + $ptimes[$pkey] = isset($ptimes[$pkey])? max(array($_itemTime, $ptimes[$pkey])) : $_itemTime; + $sql = 'select path from '.$this->DB_TableName.' '.$where.' limit 1'; + if (! $reset && $this->query($sql)) { + $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($entry[1])).', isdir='.($entry[1]['is_dir']? 1 : 0).' ' .$where); + } else { + $this->DB->exec('insert into '.$this->DB_TableName.' values ('.$path.', '.$fname.', '.$this->DB->quote(serialize($entry[1])).', '.(int)$entry[1]['is_dir'].')'); + } + } + } while (! empty($_info['has_more'])); + + // update time stamp of parent holder + foreach ($ptimes as $_p => $_t) { + if ($praw = $this->getDBdat($_p)) { + $_update = false; + if (isset($praw['client_mtime']) && $_t > strtotime($praw['client_mtime'])) { + $praw['client_mtime'] = date('r', $_t); + $_update = true; + } + if (isset($praw['modified']) && $_t > strtotime($praw['modified'])) { + $praw['modified'] = date('r', $_t); + $_update = true; + } + if ($_update) { + $pwhere = 'where path='.$this->DB->quote(strtolower($this->_dirname($_p))).' and fname='.$this->DB->quote(strtolower($this->_basename($_p))); + $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize($praw)).' '.$pwhere); + } + } + } + + $this->DB->exec('update '.$this->DB_TableName.' set dat='.$this->DB->quote(serialize(array('cursor'=>$cursor, 'mtime'=>$_SERVER['REQUEST_TIME']))).' where path=\'\' and fname=\'\''); + if (! $this->DB->commit()) { + $e = $this->DB->errorInfo(); + return $e[2]; + } + if ($delete) { + $this->DB->exec('vacuum'); + } + } catch(Dropbox_Exception $e) { + return $e->getMessage(); + } + return true; + } + + /** + * Parse line from dropbox metadata output and return file stat (array) + * + * @param string $raw line from ftp_rawlist() output + * @return array + * @author Dmitry Levashov + **/ + protected function parseRaw($raw) { + $stat = array(); + + $stat['rev'] = isset($raw['rev'])? $raw['rev'] : 'root'; + $stat['name'] = $this->_basename($raw['path']); + $stat['mime'] = $raw['is_dir']? 'directory' : $raw['mime_type']; + $stat['size'] = $stat['mime'] == 'directory' ? 0 : $raw['bytes']; + $stat['ts'] = isset($raw['client_mtime'])? strtotime($raw['client_mtime']) : + (isset($raw['modified'])? strtotime($raw['modified']) : $_SERVER['REQUEST_TIME']); + $stat['dirs'] = 0; + if ($raw['is_dir']) { + $stat['dirs'] = (int)(bool)$this->query('select path from '.$this->DB_TableName.' where isdir=1 and path='.$this->DB->quote(strtolower($raw['path']))); + } + + if (!empty($raw['url'])) { + $stat['url'] = $raw['url']; + } else if (! $this->disabledGetUrl) { + $stat['url'] = '1'; + } + if (isset($raw['width'])) $stat['width'] = $raw['width']; + if (isset($raw['height'])) $stat['height'] = $raw['height']; + + return $stat; + } + + /** + * Cache dir contents + * + * @param string $path dir path + * @return string + * @author Dmitry Levashov + **/ + protected function cacheDir($path) { + $this->dirsCache[$path] = array(); + $hasDir = false; + + $res = $this->query('select dat from '.$this->DB_TableName.' where path='.$this->DB->quote(strtolower($path))); + + if ($res) { + foreach($res as $raw) { + $raw = unserialize($raw); + if ($stat = $this->parseRaw($raw)) { + $stat = $this->updateCache($raw['path'], $stat); + if (empty($stat['hidden']) && $path !== $raw['path']) { + if (! $hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $raw['path']; + } + } + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + + return $this->dirsCache[$path]; + } + + /** + * Recursive files search + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * @return array + * @author Naoki Sawada + **/ + protected function doSearch($path, $q, $mimes) { + $result = array(); + $sth = $this->DB->prepare('select dat from '.$this->DB_TableName.' WHERE path LIKE ? AND fname LIKE ?'); + $sth->execute(array((($path === '/')? '' : strtolower($path)).'%', '%'.strtolower($q).'%')); + $res = $sth->fetchAll(PDO::FETCH_COLUMN); + $timeout = $this->options['searchTimeout']? $this->searchStart + $this->options['searchTimeout'] : 0; + + if ($res) { + foreach($res as $raw) { + if ($timeout && $timeout < time()) { + $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); + break; + } + + $raw = unserialize($raw); + if ($stat = $this->parseRaw($raw)) { + if (!isset($this->cache[$raw['path']])) { + $stat = $this->updateCache($raw['path'], $stat); + } + if (!empty($stat['hidden']) || ($mimes && $stat['mime'] === 'directory') || !$this->mimeAccepted($stat['mime'], $mimes)) { + continue; + } + $stat = $this->stat($raw['path']); + $stat['path'] = $this->path($stat['hash']); + $result[] = $stat; + } + } + } + return $result; + } + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * @return string|false + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + **/ + protected function copy($src, $dst, $name) { + + $this->clearcache(); + + return $this->_copy($src, $dst, $name) + ? $this->_joinPath($dst, $name) + : $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + + /** + * Remove file/ recursive remove dir + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * @param bool $recursive + * @return bool + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function remove($path, $force = false, $recursive = false) { + $stat = $this->stat($path); + $stat['realpath'] = $path; + $this->rmTmb($stat); + $this->clearcache(); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path)); + } + + if ($stat['mime'] == 'directory') { + if (!$recursive && !$this->_rmdir($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } else { + if (!$recursive && !$this->_unlink($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } + + $this->removed[] = $stat; + return true; + } + + /** + * Create thumnbnail and return it's URL on success + * + * @param string $path file path + * @param $stat + * @return false|string + * @internal param string $mime file mime type + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function createTmb($path, $stat) { + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath.DIRECTORY_SEPARATOR.$name; + + // copy image into tmbPath so some drivers does not store files on local fs + if (! $data = $this->getThumbnail($path, $this->options['getTmbSize'])) { + return false; + } + if (! file_put_contents($tmb, $data)) { + return false; + } + + $result = false; + + $tmbSize = $this->tmbSize; + + if (($s = getimagesize($tmb)) == false) { + return false; + } + + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' ); + + } else { + + if ($this->options['tmbCrop']) { + + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize) ) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if (($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize)/2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize)/2) : 0; + $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png'); + } + + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); + } + + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png' ); + } + + if (!$result) { + unlink($tmb); + return false; + } + + return $name; + } + + /** + * Return thumbnail file name for required file + * + * @param array $stat file stat + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function tmbname($stat) { + return $this->tmbPrefix.$stat['rev'].'.png'; + } + + /** + * Get thumbnail from dropbox.com + * @param string $path + * @param string $size + * @return string | boolean + */ + protected function getThumbnail($path, $size = 'small') { + try { + return $this->dropbox->getThumbnail($path, $size); + } catch (Dropbox_Exception $e) { + return false; + } + } + + /** + * Return content URL + * + * @param string $hash file hash + * @param array $options options + * @return array + * @author Naoki Sawada + **/ + public function getContentUrl($hash, $options = array()) { + if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) { + $path = $this->decode($hash); + $cache = $this->getDBdat($path); + $url = ''; + if (isset($cache['share']) && strpos($cache['share'], $this->dropbox_dlhost) !== false) { + $res = $this->getHttpResponseHeader($cache['share']); + if (preg_match("/^HTTP\/[01\.]+ ([0-9]{3})/", $res, $match)) { + if ($match[1] < 400) { + $url = $cache['share']; + } + } + } + if (! $url) { + try { + $res = $this->dropbox->share($path, null, false); + $url = $res['url']; + if (strpos($url, 'www.dropbox.com') === false) { + $res = $this->getHttpResponseHeader($url); + if (preg_match('/^location:\s*(http[^\s]+)/im', $res, $match)) { + $url = $match[1]; + } + } + list($url) = explode('?', $url); + $url = str_replace('www.dropbox.com', $this->dropbox_dlhost, $url); + if (! isset($cache['share']) || $cache['share'] !== $url) { + $cache['share'] = $url; + $this->updateDBdat($path, $cache); + } + } catch (Dropbox_Exception $e) { + return false; + } + } + return $url; + } + return $file['url']; + } + + /** + * Get HTTP request response header string + * + * @param string $url target URL + * @return string + * @author Naoki Sawada + */ + private function getHttpResponseHeader($url) { + if (function_exists('curl_exec')) { + + $c = curl_init(); + curl_setopt( $c, CURLOPT_RETURNTRANSFER, true ); + curl_setopt( $c, CURLOPT_CUSTOMREQUEST, 'HEAD' ); + curl_setopt( $c, CURLOPT_HEADER, 1 ); + curl_setopt( $c, CURLOPT_NOBODY, true ); + curl_setopt( $c, CURLOPT_URL, $url ); + $res = curl_exec( $c ); + + } else { + + require_once 'HTTP/Request2.php'; + try { + $request2 = new HTTP_Request2(); + $request2->setConfig(array( + 'ssl_verify_peer' => false, + 'ssl_verify_host' => false + )); + $request2->setUrl($url); + $request2->setMethod(HTTP_Request2::METHOD_HEAD); + $result = $request2->send(); + $res = array(); + $res[] = 'HTTP/'.$result->getVersion().' '.$result->getStatus().' '.$result->getReasonPhrase(); + foreach($result->getHeader() as $key => $val) { + $res[] = $key . ': ' . $val; + } + $res = join("\r\n", $res); + } catch( HTTP_Request2_Exception $e ){ + $res = ''; + } catch (Exception $e){ + $res = ''; + } + + } + return $res; + } + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) { + return $this->_normpath(substr($path, 0, strrpos($path, '/'))); + } + + /** + * Return file name + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) { + return substr($path, strrpos($path, '/') + 1); + } + + /** + * Join dir name and file name and retur full path + * + * @param string $dir + * @param string $name + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) { + return $this->_normpath($dir.'/'.$name); + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python + * + * @param string $path path + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) { + $path = '/' . ltrim($path, '/'); + return $path; + } + + /** + * Return file path related to root dir + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) { + return $path; + } + + /** + * Convert path related to root dir into real path + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) { + return $path; + } + + /** + * Return fake path started from root dir + * + * @param string $path file path + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) { + return $this->rootName . $this->_normpath(substr($path, strlen($this->root))); + } + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) { + return $path == $parent || strpos($path, $parent.'/') === 0; + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) { + //if (!empty($this->ARGS['reload']) && isset($this->ARGS['target']) && strpos($this->ARGS['target'], $this->id) === 0) { + if ($this->isMyReload()) { + $this->deltaCheck(); + } + if ($raw = $this->getDBdat($path)) { + return $this->parseRaw($raw); + } + return false; + } + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _subdirs($path) { + return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false; + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dimensions($path, $mime) { + if (strpos($mime, 'image') !== 0) return ''; + $cache = $this->getDBdat($path); + if (isset($cache['width']) && isset($cache['height'])) { + return $cache['width'].'x'.$cache['height']; + } + $ret = ''; + if ($work = $this->getWorkFile($path)) { + if ($size = getimagesize($work)) { + $cache['width'] = $size[0]; + $cache['height'] = $size[1]; + $this->updateDBdat($path, $cache); + $ret = $size[0].'x'.$size[1]; + } + } + is_file($work) && unlink($work); + return $ret; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * @return array + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function _scandir($path) { + return isset($this->dirsCache[$path]) + ? $this->dirsCache[$path] + : $this->cacheDir($path); + } + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param string $mode + * @return false|resource + * @internal param bool $write open file for writing + * @author Dmitry (dio) Levashov + */ + protected function _fopen($path, $mode='rb') { + + if (($mode == 'rb' || $mode == 'r')) { + try { + $res = $this->dropbox->media($path); + $url = parse_url($res['url']); + $fp = stream_socket_client('ssl://'.$url['host'].':443'); + fputs($fp, "GET {$url['path']} HTTP/1.0\r\n"); + fputs($fp, "Host: {$url['host']}\r\n"); + fputs($fp, "\r\n"); + while(trim(fgets($fp)) !== ''){}; + return $fp; + } catch (Dropbox_Exception $e) { + return false; + } + } + + if ($this->tmp) { + $contents = $this->_getContents($path); + + if ($contents === false) { + return false; + } + + if ($local = $this->getTempFile($path)) { + if (file_put_contents($local, $contents, LOCK_EX) !== false) { + return fopen($local, $mode); + } + } + } + + return false; + } + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function _fclose($fp, $path='') { + fclose($fp); + if ($path) { + unlink($this->getTempFile($path)); + } + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) { + $path = $this->_normpath($path.'/'.$name); + try { + $this->dropbox->createFolder($path); + } catch (Dropbox_Exception $e) { + $this->deltaCheck(); + if ($this->dir($this->encode($path))) { + return $path; + } + return $this->setError('Dropbox error: '.$e->getMessage()); + } + $this->deltaCheck(); + return $path; + } + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) { + return $this->_filePutContents($path.'/'.$name, ''); + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * @param string $name + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function _symlink($target, $path, $name) { + return false; + } + + /** + * Copy file into another file + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) { + $path = $this->_normpath($targetDir.'/'.$name); + try { + $this->dropbox->copy($source, $path); + } catch (Dropbox_Exception $e) { + return $this->setError('Dropbox error: '.$e->getMessage()); + } + $this->deltaCheck(); + return true; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + protected function _move($source, $targetDir, $name) { + $target = $this->_normpath($targetDir.'/'.$name); + try { + $this->dropbox->move($source, $target); + } catch (Dropbox_Exception $e) { + return $this->setError('Dropbox error: '.$e->getMessage()); + } + $this->deltaCheck(); + return $target; + } + + /** + * Remove file + * + * @param string $path file path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) { + try { + $this->dropbox->delete($path); + } catch (Dropbox_Exception $e) { + return $this->setError('Dropbox error: '.$e->getMessage()); + } + $this->deltaCheck(); + return true; + } + + /** + * Remove dir + * + * @param string $path dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) { + return $this->_unlink($path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * @return bool|string + * @internal param string $dir target dir path + * @author Dmitry (dio) Levashov + */ + protected function _save($fp, $path, $name, $stat) { + if ($name) $path .= '/'.$name; + $path = $this->_normpath($path); + try { + $this->dropbox->putFile($path, $fp); + } catch (Dropbox_Exception $e) { + return $this->setError('Dropbox error: '.$e->getMessage()); + } + $this->deltaCheck(); + if (is_array($stat)) { + $raw = $this->getDBdat($path); + if (isset($stat['width'])) $raw['width'] = $stat['width']; + if (isset($stat['height'])) $raw['height'] = $stat['height']; + $this->updateDBdat($path, $raw); + } + return $path; + } + + /** + * Get file contents + * + * @param string $path file path + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) { + $contents = ''; + try { + $contents = $this->dropbox->getFile($path); + } catch (Dropbox_Exception $e) { + return $this->setError('Dropbox error: '.$e->getMessage()); + } + return $contents; + } + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) { + $res = false; + + if ($local = $this->getTempFile($path)) { + if (file_put_contents($local, $content, LOCK_EX) !== false + && ($fp = fopen($local, 'rb'))) { + clearstatcache(); + $res = $this->_save($fp, $path, '', array()); + fclose($fp); + } + file_exists($local) && unlink($local); + } + + return $res; + } + + /** + * Detect available archivers + * + * @return array + **/ + protected function _checkArchivers() { + // die('Not yet implemented. (_checkArchivers)'); + return array(); + } + + /** + * chmod implementation + * + * @param string $path + * @param string $mode + * @return bool + */ + protected function _chmod($path, $mode) { + return false; + } + + /** + * Unpack archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * @return true + * @return void + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function _unpack($path, $arc) { + die('Not yet implemented. (_unpack)'); + } + + /** + * Recursive symlinks search + * + * @param string $path file/dir path + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _findSymlinks($path) { + die('Not yet implemented. (_findSymlinks)'); + } + + /** + * Extract files from archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * @return true + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _extract($path, $arc) { + die('Not yet implemented. (_extract)'); + + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) { + die('Not yet implemented. (_archive)'); + } + +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeDropbox2.class.php b/lib/redactor/elfinder/php/elFinderVolumeDropbox2.class.php new file mode 100644 index 0000000..f00d79c --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeDropbox2.class.php @@ -0,0 +1,1516 @@ + '', + 'app_secret' => '', + 'access_token' => '', + 'aliasFormat' => '%s@Dropbox', + 'path' => '/', + 'separator' => '/', + 'acceptedName' => '#^[^\\\/]+$#', + 'rootCssClass' => 'elfinder-navbar-root-dropbox', + 'publishPermission' => [ + 'requested_visibility' => 'public', + //'link_password' => '', + //'expires' => '', + ], + 'getThumbSize' => 'medium', // Available sizes: 'thumb', 'small', 'medium', 'large', 'huge' + ]; + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /*********************************************************************/ + /* ORIGINAL FUNCTIONS */ + /*********************************************************************/ + + /** + * Get Parent ID, Item ID, Parent Path as an array from path. + * + * @param string $path + * + * @return array + */ + protected function _db_splitPath($path) + { + $path = trim($path, '/'); + if ($path === '') { + $dirname = '/'; + $basename = ''; + } else { + $pos = strrpos($path, '/'); + if ($pos === false) { + $dirname = '/'; + $basename = $path; + } else { + $dirname = '/' . substr($path, 0, $pos); + $basename = substr($path, $pos + 1); + } + } + + return [$dirname, $basename]; + } + + /** + * Get dat(Dropbox metadata) from Dropbox. + * + * @param string $path + * + * @return boolean|object Dropbox metadata + */ + private function _db_getFile($path) + { + if ($path === '/') { + return true; + } + + $res = false; + try { + $file = $this->service->getMetadata($path, $this->FETCH_OPTIONS); + if ($file instanceof FolderMetadata || $file instanceof FileMetadata) { + $res = $file; + } + + return $res; + } catch (DropboxClientException $e) { + return false; + } + } + + /** + * Parse line from Dropbox metadata output and return file stat (array). + * + * @param object $raw line from ftp_rawlist() output + * + * @return array + * @author Naoki Sawada + **/ + protected function _db_parseRaw($raw) + { + $stat = []; + $isFolder = false; + if ($raw === true) { + // root folder + $isFolder = true; + $stat['name'] = ''; + $stat['iid'] = '0'; + } + + $data = []; + if (is_object($raw)) { + $isFolder = $raw instanceof FolderMetadata; + $data = $raw->getData(); + } elseif (is_array($raw)) { + $isFolder = $raw['.tag'] === 'folder'; + $data = $raw; + } + + if (isset($data['path_lower'])) { + $stat['path'] = $data['path_lower']; + } + + if (isset($data['name'])) { + $stat['name'] = $data['name']; + } + + if (isset($data['id'])) { + $stat['iid'] = substr($data['id'], 3); + } + + if ($isFolder) { + $stat['mime'] = 'directory'; + $stat['size'] = 0; + $stat['ts'] = 0; + $stat['dirs'] = -1; + } else { + $stat['size'] = isset($data['size']) ? (int)$data['size'] : 0; + if (isset($data['server_modified'])) { + $stat['ts'] = strtotime($data['server_modified']); + } elseif (isset($data['client_modified'])) { + $stat['ts'] = strtotime($data['client_modified']); + } else { + $stat['ts'] = 0; + } + $stat['url'] = '1'; + } + + return $stat; + } + + /** + * Get thumbnail from Dropbox. + * + * @param string $path + * @param string $size + * + * @return string | boolean + */ + protected function _db_getThumbnail($path) + { + try { + return $this->service->getThumbnail($path, $this->options['getThumbSize'])->getContents(); + } catch (DropboxClientException $e) { + return false; + } + } + + /** + * Join dir name and file name(display name) and retur full path. + * + * @param string $dir + * @param string $displayName + * + * @return string + */ + protected function _db_joinName($dir, $displayName) + { + return rtrim($dir, '/') . '/' . $displayName; + } + + /** + * Get OAuth2 access token form OAuth1 tokens. + * + * @param string $app_key + * @param string $app_secret + * @param string $oauth1_token + * @param string $oauth1_secret + * + * @return string|false + */ + public static function getTokenFromOauth1($app_key, $app_secret, $oauth1_token, $oauth1_secret) + { + $data = [ + 'oauth1_token' => $oauth1_token, + 'oauth1_token_secret' => $oauth1_secret, + ]; + $auth = base64_encode($app_key . ':' . $app_secret); + + $ch = curl_init('https://api.dropboxapi.com/2/auth/token/from_oauth1'); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'Authorization: Basic ' . $auth, + ]); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + $result = curl_exec($ch); + curl_close($ch); + + $res = $result ? json_decode($result, true) : []; + + return isset($res['oauth2_token']) ? $res['oauth2_token'] : false; + } + + /*********************************************************************/ + /* EXTENDED FUNCTIONS */ + /*********************************************************************/ + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount(). + * + * @return array + * @author Naoki Sawada + **/ + public function netmountPrepare($options) + { + if (empty($options['app_key']) && defined('ELFINDER_DROPBOX_APPKEY')) { + $options['app_key'] = ELFINDER_DROPBOX_APPKEY; + } + if (empty($options['app_secret']) && defined('ELFINDER_DROPBOX_APPSECRET')) { + $options['app_secret'] = ELFINDER_DROPBOX_APPSECRET; + } + + if (!isset($options['pass'])) { + $options['pass'] = ''; + } + + try { + $app = new DropboxApp($options['app_key'], $options['app_secret']); + $dropbox = new Dropbox($app); + $authHelper = $dropbox->getAuthHelper(); + + if ($options['pass'] === 'reauth') { + $options['pass'] = ''; + $this->session->set('Dropbox2AuthParams', [])->set('Dropbox2Tokens', []); + } elseif ($options['pass'] === 'dropbox2') { + $options['pass'] = ''; + } + + $options = array_merge($this->session->get('Dropbox2AuthParams', []), $options); + + if (!isset($options['tokens'])) { + $options['tokens'] = $this->session->get('Dropbox2Tokens', []); + $this->session->remove('Dropbox2Tokens'); + } + $aToken = $options['tokens']; + if (!is_array($aToken) || !isset($aToken['access_token'])) { + $aToken = []; + } + + $service = null; + if ($aToken) { + try { + $dropbox->setAccessToken($aToken['access_token']); + $this->session->set('Dropbox2AuthParams', $options); + } catch (DropboxClientException $e) { + $aToken = []; + $options['tokens'] = []; + if ($options['user'] !== 'init') { + $this->session->set('Dropbox2AuthParams', $options); + + return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE]; + } + } + } + + if ((isset($options['user']) && $options['user'] === 'init') || (isset($_GET['host']) && $_GET['host'] == '1')) { + if (empty($options['url'])) { + $options['url'] = elFinder::getConnectorUrl(); + } + + if (!empty($options['id'])) { + $callback = $options['url'] + . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=dropbox2&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']); + } + + $itpCare = isset($options['code']); + $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : ''); + $state = $itpCare? $options['state'] : (isset($_GET['state'])? $_GET['state'] : ''); + if (!$aToken && empty($code)) { + $url = $authHelper->getAuthUrl($callback); + + $html = ''; + $html .= ''; + if (empty($options['pass']) && $options['host'] !== '1') { + $options['pass'] = 'return'; + $this->session->set('Dropbox2AuthParams', $options); + + return ['exit' => true, 'body' => $html]; + } else { + $out = [ + 'node' => $options['id'], + 'json' => '{"protocol": "dropbox2", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}', + 'bind' => 'netmount', + ]; + + return ['exit' => 'callback', 'out' => $out]; + } + } else { + if ($code && $state) { + if (!empty($options['id'])) { + // see https://github.com/kunalvarma05/dropbox-php-sdk/issues/115 + $authHelper->getPersistentDataStore()->set('state', htmlspecialchars($state)); + $tokenObj = $authHelper->getAccessToken($code, $state, $callback); + $options['tokens'] = [ + 'access_token' => $tokenObj->getToken(), + 'uid' => $tokenObj->getUid(), + ]; + unset($options['code'], $options['state']); + $this->session->set('Dropbox2Tokens', $options['tokens'])->set('Dropbox2AuthParams', $options); + $out = [ + 'node' => $options['id'], + 'json' => '{"protocol": "dropbox2", "mode": "done", "reset": 1}', + 'bind' => 'netmount', + ]; + } else { + $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host']; + $out = [ + 'node' => $nodeid, + 'json' => json_encode(array( + 'protocol' => 'dropbox2', + 'host' => $nodeid, + 'mode' => 'redirect', + 'options' => array( + 'id' => $nodeid, + 'code' => $code, + 'state' => $state + ) + )), + 'bind' => 'netmount' + ]; + } + if (!$itpCare) { + return array('exit' => 'callback', 'out' => $out); + } else { + return array('exit' => true, 'body' => $out['json']); + } + } + $path = $options['path']; + $folders = []; + $listFolderContents = $dropbox->listFolder($path); + $items = $listFolderContents->getItems(); + foreach ($items as $item) { + $data = $item->getData(); + if ($data['.tag'] === 'folder') { + $folders[$data['path_lower']] = $data['name']; + } + } + natcasesort($folders); + + if ($options['pass'] === 'folders') { + return ['exit' => true, 'folders' => $folders]; + } + + $folders = ['/' => '/'] + $folders; + $folders = json_encode($folders); + $json = '{"protocol": "dropbox2", "mode": "done", "folders": ' . $folders . '}'; + $options['pass'] = 'return'; + $html = 'Dropbox.com'; + $html .= ''; + $this->session->set('Dropbox2AuthParams', $options); + + return ['exit' => true, 'body' => $html]; + } + } + } catch (DropboxClientException $e) { + $this->session->remove('Dropbox2AuthParams')->remove('Dropbox2Tokens'); + if (empty($options['pass'])) { + return ['exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage()]; + } else { + return ['exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]]; + } + } + + if (!$aToken) { + return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE]; + } + + if ($options['path'] === 'root') { + $options['path'] = '/'; + } + + try { + if ($options['path'] !== '/') { + $file = $dropbox->getMetadata($options['path']); + $name = $file->getName(); + } else { + $name = 'root'; + } + $options['alias'] = sprintf($this->options['aliasFormat'], $name); + } catch (DropboxClientException $e) { + return ['exit' => true, 'error' => $e->getMessage()]; + } + + foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) { + unset($options[$key]); + } + + return $options; + } + + /** + * process of on netunmount + * Drop `Dropbox` & rm thumbs. + * + * @param array $options + * + * @return bool + */ + public function netunmount($netVolumes, $key) + { + if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->driverId . '_' . $this->options['tokens']['uid'] . '*.png')) { + foreach ($tmbs as $file) { + unlink($file); + } + } + + return true; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare Dropbox connection + * Connect to remote server and check if credentials are correct, if so, store the connection id in $this->service. + * + * @return bool + * @author Naoki Sawada + **/ + protected function init() + { + if (empty($this->options['app_key'])) { + if (defined('ELFINDER_DROPBOX_APPKEY') && ELFINDER_DROPBOX_APPKEY) { + $this->options['app_key'] = ELFINDER_DROPBOX_APPKEY; + } else { + return $this->setError('Required option "app_key" is undefined.'); + } + } + if (empty($this->options['app_secret'])) { + if (defined('ELFINDER_DROPBOX_APPSECRET') && ELFINDER_DROPBOX_APPSECRET) { + $this->options['app_secret'] = ELFINDER_DROPBOX_APPSECRET; + } else { + return $this->setError('Required option "app_secret" is undefined.'); + } + } + if (isset($this->options['tokens']) && is_array($this->options['tokens']) && !empty($this->options['tokens']['access_token'])) { + $this->options['access_token'] = $this->options['tokens']['access_token']; + } + if (!$this->options['access_token']) { + return $this->setError('Required option "access_token" or "refresh_token" is undefined.'); + } + + try { + // make net mount key for network mount + $aToken = $this->options['access_token']; + $this->netMountKey = md5($aToken . '-' . $this->options['path']); + + $errors = []; + if ($this->needOnline && !$this->service) { + $app = new DropboxApp($this->options['app_key'], $this->options['app_secret'], $aToken); + $this->service = new Dropbox($app); + // to check access_token + $this->service->getCurrentAccount(); + } + } catch (DropboxClientException $e) { + $errors[] = 'Dropbox error: ' . $e->getMessage(); + } catch (Exception $e) { + $errors[] = $e->getMessage(); + } + + if ($this->needOnline && !$this->service) { + $errors[] = 'Dropbox Service could not be loaded.'; + } + + if ($errors) { + return $this->setError($errors); + } + + // normalize root path + $this->options['path'] = strtolower($this->options['path']); + if ($this->options['path'] == 'root') { + $this->options['path'] = '/'; + } + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + if (empty($this->options['alias'])) { + $this->options['alias'] = sprintf($this->options['aliasFormat'], ($this->options['path'] === '/') ? 'Root' : $this->_basename($this->options['path'])); + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } + + $this->rootName = $this->options['alias']; + + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } + } + + if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { + $this->tmp = $tmp; + } + + // This driver dose not support `syncChkAsTs` + $this->options['syncChkAsTs'] = false; + + // 'lsPlSleep' minmum 10 sec + $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']); + + // enable command archive + $this->options['useRemoteArchive'] = true; + + return true; + } + + /** + * Configure after successfull mount. + * + * @author Naoki Sawada + * @throws elFinderAbortException + */ + protected function configure() + { + parent::configure(); + + // fallback of $this->tmp + if (!$this->tmp && $this->tmbPathWritable) { + $this->tmp = $this->tmbPath; + } + + if ($this->isMyReload()) { + //$this->_db_getDirectoryData(false); + } + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection. + **/ + public function umount() + { + } + + /** + * Cache dir contents. + * + * @param string $path dir path + * + * @return + * @author Naoki Sawada + */ + protected function cacheDir($path) + { + $this->dirsCache[$path] = []; + $hasDir = false; + + $res = $this->service->listFolder($path, $this->FETCH_OPTIONS); + + if ($res) { + $items = $res->getItems()->all(); + foreach ($items as $raw) { + if ($stat = $this->_db_parseRaw($raw)) { + $mountPath = $this->_joinPath($path, $stat['name']); + $stat = $this->updateCache($mountPath, $stat); + if (empty($stat['hidden']) && $path !== $mountPath) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $mountPath; + } + } + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + + return $this->dirsCache[$path]; + } + + /** + * Recursive files search. + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * + * @return array + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function doSearch($path, $q, $mimes) + { + if (!empty($this->doSearchCurrentQuery['matchMethod']) || $mimes) { + // has custom match method or mimes, use elFinderVolumeDriver::doSearch() + return parent::doSearch($path, $q, $mimes); + } + + $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; + + $searchRes = $this->service->search($path, $q, ['start' => 0, 'max_results' => 1000]); + $items = $searchRes->getItems(); + $more = $searchRes->hasMoreItems(); + while ($more) { + if ($timeout && $timeout < time()) { + $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->_path($path)); + break; + } + $searchRes = $this->service->search($path, $q, ['start' => $searchRes->getCursor(), 'max_results' => 1000]); + $more = $searchRes->hasMoreItems(); + $items = $items->merge($searchRes->getItems()); + } + + $result = []; + foreach ($items as $raw) { + if ($stat = $this->_db_parseRaw($raw->getMetadata())) { + $stat = $this->updateCache($stat['path'], $stat); + if (empty($stat['hidden'])) { + $result[] = $stat; + } + } + } + + return $result; + } + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * + * @return string|false + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function copy($src, $dst, $name) + { + $srcStat = $this->stat($src); + $target = $this->_joinPath($dst, $name); + $tgtStat = $this->stat($target); + if ($tgtStat) { + if ($srcStat['mime'] === 'directory') { + return parent::copy($src, $dst, $name); + } else { + $this->_unlink($target); + } + } + $this->clearcache(); + if ($res = $this->_copy($src, $dst, $name)) { + $this->added[] = $this->stat($target); + $res = $target; + } + + return $res; + } + + /** + * Remove file/ recursive remove dir. + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * @param bool $recursive + * + * @return bool + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function remove($path, $force = false, $recursive = false) + { + $stat = $this->stat($path); + $stat['realpath'] = $path; + $this->rmTmb($stat); + $this->clearcache(); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path)); + } + + if ($stat['mime'] == 'directory') { + if (!$recursive && !$this->_rmdir($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } else { + if (!$recursive && !$this->_unlink($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } + + $this->removed[] = $stat; + + return true; + } + + /** + * Create thumnbnail and return it's URL on success. + * + * @param string $path file path + * @param $stat + * + * @return string|false + * @throws ImagickException + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function createTmb($path, $stat) + { + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name; + + // copy image into tmbPath so some drivers does not store files on local fs + if (!$data = $this->_db_getThumbnail($path)) { + return false; + } + if (!file_put_contents($tmb, $data)) { + return false; + } + + $tmbSize = $this->tmbSize; + + if (($s = getimagesize($tmb)) == false) { + return false; + } + + $result = true; + + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } else { + if ($this->options['tmbCrop']) { + + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if ($result && ($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0; + $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png'); + } + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); + } + + if ($result) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + + } + } + + if (!$result) { + unlink($tmb); + + return false; + } + + return $name; + } + + /** + * Return thumbnail file name for required file. + * + * @param array $stat file stat + * + * @return string + * @author Naoki Sawada + **/ + protected function tmbname($stat) + { + $name = $this->driverId . '_'; + if (isset($this->options['tokens']) && is_array($this->options['tokens'])) { + $name .= $this->options['tokens']['uid']; + } + + return $name . md5($stat['iid']) . $stat['ts'] . '.png'; + } + + /** + * Return content URL (for netmout volume driver) + * If file.url == 1 requests from JavaScript client with XHR. + * + * @param string $hash file hash + * @param array $options options array + * + * @return bool|string + * @author Naoki Sawada + */ + public function getContentUrl($hash, $options = []) + { + if (!empty($options['onetime']) && $this->options['onetimeUrl']) { + return parent::getContentUrl($hash, $options); + } + if (!empty($options['temporary'])) { + // try make temporary file + $url = parent::getContentUrl($hash, $options); + if ($url) { + return $url; + } + } + $file = $this->file($hash); + if (($file = $this->file($hash)) !== false && (!$file['url'] || $file['url'] == 1)) { + $path = $this->decode($hash); + $url = ''; + try { + $res = $this->service->postToAPI('/sharing/list_shared_links', ['path' => $path, 'direct_only' => true])->getDecodedBody(); + if ($res && !empty($res['links'])) { + foreach ($res['links'] as $link) { + if (isset($link['link_permissions']) + && isset($link['link_permissions']['requested_visibility']) + && $link['link_permissions']['requested_visibility']['.tag'] === $this->options['publishPermission']['requested_visibility']) { + $url = $link['url']; + break; + } + } + } + if (!$url) { + $res = $this->service->postToAPI('/sharing/create_shared_link_with_settings', ['path' => $path, 'settings' => $this->options['publishPermission']])->getDecodedBody(); + if (isset($res['url'])) { + $url = $res['url']; + } + } + if ($url) { + $url = str_replace('www.dropbox.com', 'dl.dropboxusercontent.com', $url); + $url = str_replace('?dl=0', '', $url); + + return $url; + } + } catch (DropboxClientException $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + } + + return false; + } + + /** + * Return debug info for client. + * + * @return array + **/ + public function debug() + { + $res = parent::debug(); + if (!empty($this->options['netkey']) && isset($this->options['tokens']) && !empty($this->options['tokens']['uid'])) { + $res['Dropbox uid'] = $this->options['tokens']['uid']; + $res['access_token'] = $this->options['tokens']['access_token']; + } + + return $res; + } + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path. + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function _dirname($path) + { + list($dirname) = $this->_db_splitPath($path); + + return $dirname; + } + + /** + * Return file name. + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function _basename($path) + { + list(, $basename) = $this->_db_splitPath($path); + + return $basename; + } + + /** + * Join dir name and file name and retur full path. + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + return rtrim($dir, '/') . '/' . strtolower($name); + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python. + * + * @param string $path path + * + * @return string + * @author Naoki Sawada + **/ + protected function _normpath($path) + { + return '/' . ltrim($path, '/'); + } + + /** + * Return file path related to root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + if ($path === $this->root) { + return ''; + } else { + return ltrim(substr($path, strlen($this->root)), '/'); + } + } + + /** + * Convert path related to root dir into real path. + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function _abspath($path) + { + if ($path === '/') { + return $this->root; + } else { + return $this->_joinPath($this->root, $path); + } + } + + /** + * Return fake path started from root dir. + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function _path($path) + { + $path = $this->_normpath(substr($path, strlen($this->root))); + + return $path; + } + + /** + * Return true if $path is children of $parent. + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Naoki Sawada + **/ + protected function _inpath($path, $parent) + { + return $path == $parent || strpos($path, $parent . '/') === 0; + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally. + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + if ($raw = $this->_db_getFile($path)) { + return $this->_db_parseRaw($raw); + } + + return false; + } + + /** + * Return true if path is dir and has at least one childs directory. + * + * @param string $path dir path + * + * @return bool + * @author Naoki Sawada + **/ + protected function _subdirs($path) + { + $hasdir = false; + + try { + $res = $this->service->listFolder($path); + if ($res) { + $items = $res->getItems(); + foreach ($items as $raw) { + if ($raw instanceof FolderMetadata) { + $hasdir = true; + break; + } + } + } + } catch (DropboxClientException $e) { + $this->setError('Dropbox error: ' . $e->getMessage()); + } + + return $hasdir; + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @throws ImagickException + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function _dimensions($path, $mime) + { + if (strpos($mime, 'image') !== 0) { + return ''; + } + $ret = ''; + + if ($data = $this->_getContents($path)) { + $tmp = $this->getTempFile(); + file_put_contents($tmp, $data); + $size = getimagesize($tmp); + if ($size) { + $ret = array('dim' => $size[0] . 'x' . $size[1]); + $srcfp = fopen($tmp, 'rb'); + $target = isset(elFinder::$currentArgs['target'])? elFinder::$currentArgs['target'] : ''; + if ($subImgLink = $this->getSubstituteImgLink($target, $size, $srcfp)) { + $ret['url'] = $subImgLink; + } + } + } + + return $ret; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @author Naoki Sawada + **/ + protected function _scandir($path) + { + return isset($this->dirsCache[$path]) + ? $this->dirsCache[$path] + : $this->cacheDir($path); + } + + /** + * Open file and return file pointer. + * + * @param string $path file path + * @param bool $write open file for writing + * + * @return resource|false + * @author Naoki Sawada + **/ + protected function _fopen($path, $mode = 'rb') + { + if ($mode === 'rb' || $mode === 'r') { + if ($link = $this->service->getTemporaryLink($path)) { + $access_token = $this->service->getAccessToken(); + if ($access_token) { + $data = array( + 'target' => $link->getLink(), + 'headers' => array('Authorization: Bearer ' . $access_token), + ); + + // to support range request + if (func_num_args() > 2) { + $opts = func_get_arg(2); + } else { + $opts = array(); + } + if (!empty($opts['httpheaders'])) { + $data['headers'] = array_merge($opts['httpheaders'], $data['headers']); + } + + return elFinder::getStreamByUrl($data); + } + } + } + + return false; + } + + /** + * Close opened file. + * + * @param resource $fp file pointer + * + * @return bool + * @author Naoki Sawada + **/ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed. + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Naoki Sawada + **/ + protected function _mkdir($path, $name) + { + try { + return $this->service->createFolder($this->_db_joinName($path, $name))->getPathLower(); + } catch (DropboxClientException $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + } + + /** + * Create file and return it's path or false on failed. + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Naoki Sawada + **/ + protected function _mkfile($path, $name) + { + return $this->_save($this->tmpfile(), $path, $name, []); + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * + * @return bool + * @author Naoki Sawada + **/ + protected function _symlink($target, $path, $name) + { + return false; + } + + /** + * Copy file into another file. + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Naoki Sawada + **/ + protected function _copy($source, $targetDir, $name) + { + try { + $this->service->copy($source, $this->_db_joinName($targetDir, $name))->getPathLower(); + } catch (DropboxClientException $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param string $target target dir path + * @param string $name file name + * + * @return string|bool + * @author Naoki Sawada + **/ + protected function _move($source, $targetDir, $name) + { + try { + return $this->service->move($source, $this->_db_joinName($targetDir, $name))->getPathLower(); + } catch (DropboxClientException $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + } + + /** + * Remove file. + * + * @param string $path file path + * + * @return bool + * @author Naoki Sawada + **/ + protected function _unlink($path) + { + try { + $this->service->delete($path); + + return true; + } catch (DropboxClientException $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Remove dir. + * + * @param string $path dir path + * + * @return bool + * @author Naoki Sawada + **/ + protected function _rmdir($path) + { + return $this->_unlink($path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Naoki Sawada + **/ + protected function _save($fp, $path, $name, $stat) + { + try { + $info = stream_get_meta_data($fp); + if (empty($info['uri']) || preg_match('#^[a-z0-9.-]+://#', $info['uri'])) { + if ($filepath = $this->getTempFile()) { + $_fp = fopen($filepath, 'wb'); + stream_copy_to_stream($fp, $_fp); + fclose($_fp); + } + } else { + $filepath = $info['uri']; + } + $dropboxFile = new DropboxFile($filepath); + if ($name === '') { + $fullpath = $path; + } else { + $fullpath = $this->_db_joinName($path, $name); + } + + return $this->service->upload($dropboxFile, $fullpath, ['mode' => 'overwrite'])->getPathLower(); + } catch (DropboxClientException $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + } + + /** + * Get file contents. + * + * @param string $path file path + * + * @return string|false + * @author Naoki Sawada + **/ + protected function _getContents($path) + { + $contents = ''; + + try { + $file = $this->service->download($path); + $contents = $file->getContents(); + } catch (Exception $e) { + return $this->setError('Dropbox error: ' . $e->getMessage()); + } + + return $contents; + } + + /** + * Write a string to a file. + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Naoki Sawada + **/ + protected function _filePutContents($path, $content) + { + $res = false; + + if ($local = $this->getTempFile($path)) { + if (file_put_contents($local, $content, LOCK_EX) !== false + && ($fp = fopen($local, 'rb'))) { + clearstatcache(); + $name = ''; + $stat = $this->stat($path); + if ($stat) { + // keep real name + $path = $this->_dirname($path); + $name = $stat['name']; + } + $res = $this->_save($fp, $path, $name, []); + fclose($fp); + } + file_exists($local) && unlink($local); + } + + return $res; + } + + /** + * Detect available archivers. + **/ + protected function _checkArchivers() + { + // die('Not yet implemented. (_checkArchivers)'); + return []; + } + + /** + * chmod implementation. + * + * @return bool + **/ + protected function _chmod($path, $mode) + { + return false; + } + + /** + * Unpack archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return true + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function _unpack($path, $arc) + { + die('Not yet implemented. (_unpack)'); + //return false; + } + + /** + * Recursive symlinks search. + * + * @param string $path file/dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _findSymlinks($path) + { + die('Not yet implemented. (_findSymlinks)'); + } + + /** + * Extract files from archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return true + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _extract($path, $arc) + { + die('Not yet implemented. (_extract)'); + } + + /** + * Create archive and return its path. + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) + { + die('Not yet implemented. (_archive)'); + } +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeFTP.class.php b/lib/redactor/elfinder/php/elFinderVolumeFTP.class.php new file mode 100644 index 0000000..23d5d04 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeFTP.class.php @@ -0,0 +1,1810 @@ + 'localhost', + 'user' => '', + 'pass' => '', + 'port' => 21, + 'mode' => 'passive', + 'ssl' => false, + 'path' => '/', + 'timeout' => 20, + 'owner' => true, + 'tmbPath' => '', + 'tmpPath' => '', + 'separator' => '/', + 'checkSubfolders' => -1, + 'dirMode' => 0755, + 'fileMode' => 0644, + 'rootCssClass' => 'elfinder-navbar-root-ftp', + 'ftpListOption' => '-al', + ); + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount() + * + * @param $options + * + * @return array volume root options + * @author Naoki Sawada + */ + public function netmountPrepare($options) + { + if (!empty($_REQUEST['encoding']) && iconv('UTF-8', $_REQUEST['encoding'], '') !== false) { + $options['encoding'] = $_REQUEST['encoding']; + if (!empty($_REQUEST['locale']) && setlocale(LC_ALL, $_REQUEST['locale'])) { + setlocale(LC_ALL, elFinder::$locale); + $options['locale'] = $_REQUEST['locale']; + } + } + if (!empty($_REQUEST['FTPS'])) { + $options['ssl'] = true; + } + $options['statOwner'] = true; + $options['allowChmodReadOnly'] = true; + $options['acceptedName'] = '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#'; + return $options; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare FTP connection + * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn + * + * @return bool + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function init() + { + if (!$this->options['host'] + || !$this->options['port']) { + return $this->setError('Required options undefined.'); + } + + if (!$this->options['user']) { + $this->options['user'] = 'anonymous'; + $this->options['pass'] = ''; + } + if (!$this->options['path']) { + $this->options['path'] = '/'; + } + + // make ney mount key + $this->netMountKey = md5(join('-', array('ftp', $this->options['host'], $this->options['port'], $this->options['path'], $this->options['user']))); + + if (!function_exists('ftp_connect')) { + return $this->setError('FTP extension not loaded.'); + } + + // remove protocol from host + $scheme = parse_url($this->options['host'], PHP_URL_SCHEME); + + if ($scheme) { + $this->options['host'] = substr($this->options['host'], strlen($scheme) + 3); + } + + // normalize root path + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + if (empty($this->options['alias'])) { + $this->options['alias'] = $this->options['user'] . '@' . $this->options['host']; + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } + + $this->rootName = $this->options['alias']; + $this->options['separator'] = '/'; + + if (is_null($this->options['syncChkAsTs'])) { + $this->options['syncChkAsTs'] = true; + } + + if (isset($this->options['ftpListOption'])) { + $this->ftpListOption = $this->options['ftpListOption']; + } + + return $this->needOnline? $this->connect() : true; + + } + + + /** + * Configure after successfull mount. + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function configure() + { + parent::configure(); + + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], 0755, true)) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } + } + if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { + $this->tmp = $tmp; + } + + // fallback of $this->tmp + if (!$this->tmp && $this->tmbPathWritable) { + $this->tmp = $this->tmbPath; + } + + if (!$this->tmp) { + $this->disabled[] = 'mkfile'; + $this->disabled[] = 'paste'; + $this->disabled[] = 'duplicate'; + $this->disabled[] = 'upload'; + $this->disabled[] = 'edit'; + $this->disabled[] = 'archive'; + $this->disabled[] = 'extract'; + } + + // echo $this->tmp; + + } + + /** + * Connect to ftp server + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function connect() + { + $withSSL = empty($this->options['ssl']) ? '' : ' with SSL'; + if ($withSSL) { + if (!function_exists('ftp_ssl_connect') || !($this->connect = ftp_ssl_connect($this->options['host'], $this->options['port'], $this->options['timeout']))) { + return $this->setError('Unable to connect to FTP server ' . $this->options['host'] . $withSSL); + } + $this->isFTPS = true; + } else { + if (!($this->connect = ftp_connect($this->options['host'], $this->options['port'], $this->options['timeout']))) { + return $this->setError('Unable to connect to FTP server ' . $this->options['host']); + } + } + if (!ftp_login($this->connect, $this->options['user'], $this->options['pass'])) { + $this->umount(); + return $this->setError('Unable to login into ' . $this->options['host'] . $withSSL); + } + + // try switch utf8 mode + if ($this->encoding) { + ftp_raw($this->connect, 'OPTS UTF8 OFF'); + } else { + ftp_raw($this->connect, 'OPTS UTF8 ON'); + } + + $help = ftp_raw($this->connect, 'HELP'); + $this->isPureFtpd = stripos(implode(' ', $help), 'Pure-FTPd') !== false; + + if (!$this->isPureFtpd) { + // switch off extended passive mode - may be usefull for some servers + // this command, for pure-ftpd, doesn't work and takes a timeout in some pure-ftpd versions + ftp_raw($this->connect, 'epsv4 off'); + } + // enter passive mode if required + $pasv = ($this->options['mode'] == 'passive'); + if (!ftp_pasv($this->connect, $pasv)) { + if ($pasv) { + $this->options['mode'] = 'active'; + } + } + + // enter root folder + if (!ftp_chdir($this->connect, $this->root) + || $this->root != ftp_pwd($this->connect)) { + $this->umount(); + return $this->setError('Unable to open root folder.'); + } + + // check for MLST support + $features = ftp_raw($this->connect, 'FEAT'); + if (!is_array($features)) { + $this->umount(); + return $this->setError('Server does not support command FEAT.'); + } + + foreach ($features as $feat) { + if (strpos(trim($feat), 'MLST') === 0) { + $this->MLSTsupprt = true; + break; + } + } + + return true; + } + + /** + * Call ftp_rawlist with option prefix + * + * @param string $path + * + * @return array + */ + protected function ftpRawList($path) + { + if ($this->isPureFtpd) { + $path = str_replace(' ', '\ ', $path); + } + if ($this->ftpListOption) { + $path = $this->ftpListOption . ' ' . $path; + } + $res = ftp_rawlist($this->connect, $path); + if ($res === false) { + $res = array(); + } + return $res; + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + $this->connect && ftp_close($this->connect); + } + + + /** + * Parse line from ftp_rawlist() output and return file stat (array) + * + * @param string $raw line from ftp_rawlist() output + * @param $base + * @param bool $nameOnly + * + * @return array + * @author Dmitry Levashov + */ + protected function parseRaw($raw, $base, $nameOnly = false) + { + static $now; + static $lastyear; + + if (!$now) { + $now = time(); + $lastyear = date('Y') - 1; + } + + $info = preg_split("/\s+/", $raw, 8); + if (isset($info[7])) { + list($info[7], $info[8]) = explode(' ', $info[7], 2); + } + $stat = array(); + + if (!isset($this->ftpOsUnix)) { + $this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1)); + } + if (!$this->ftpOsUnix) { + $info = $this->normalizeRawWindows($raw); + } + + if (count($info) < 9 || $info[8] == '.' || $info[8] == '..') { + return false; + } + + $name = $info[8]; + + if (preg_match('|(.+)\-\>(.+)|', $name, $m)) { + $name = trim($m[1]); + // check recursive processing + if ($this->cacheDirTarget && $this->_joinPath($base, $name) !== $this->cacheDirTarget) { + return array(); + } + if (!$nameOnly) { + $target = trim($m[2]); + if (substr($target, 0, 1) !== $this->separator) { + $target = $this->getFullPath($target, $base); + } + $target = $this->_normpath($target); + $stat['name'] = $name; + $stat['target'] = $target; + return $stat; + } + } + + if ($nameOnly) { + return array('name' => $name); + } + + if (is_numeric($info[5]) && !$info[6] && !$info[7]) { + // by normalizeRawWindows() + $stat['ts'] = $info[5]; + } else { + $stat['ts'] = strtotime($info[5] . ' ' . $info[6] . ' ' . $info[7]); + if ($stat['ts'] && $stat['ts'] > $now && strpos($info[7], ':') !== false) { + $stat['ts'] = strtotime($info[5] . ' ' . $info[6] . ' ' . $lastyear . ' ' . $info[7]); + } + if (empty($stat['ts'])) { + $stat['ts'] = strtotime($info[6] . ' ' . $info[5] . ' ' . $info[7]); + if ($stat['ts'] && $stat['ts'] > $now && strpos($info[7], ':') !== false) { + $stat['ts'] = strtotime($info[6] . ' ' . $info[5] . ' ' . $lastyear . ' ' . $info[7]); + } + } + } + + if ($this->options['statOwner']) { + $stat['owner'] = $info[2]; + $stat['group'] = $info[3]; + $stat['perm'] = substr($info[0], 1); + // + // if not exists owner in LS ftp ==> isowner = true + // if is defined as option : 'owner' => true isowner = true + // + // if exist owner in LS ftp and 'owner' => False isowner = result of owner(file) == user(logged with ftp) + // + $stat['isowner'] = isset($stat['owner']) ? ($this->options['owner'] ? true : ($stat['owner'] == $this->options['user'])) : true; + } + + $owner_computed = isset($stat['isowner']) ? $stat['isowner'] : $this->options['owner']; + $perm = $this->parsePermissions($info[0], $owner_computed); + $stat['name'] = $name; + $stat['mime'] = substr(strtolower($info[0]), 0, 1) == 'd' ? 'directory' : $this->mimetype($stat['name'], true); + $stat['size'] = $stat['mime'] == 'directory' ? 0 : $info[4]; + $stat['read'] = $perm['read']; + $stat['write'] = $perm['write']; + + return $stat; + } + + /** + * Normalize MS-DOS style FTP LIST Raw line + * + * @param string $raw line from FTP LIST (MS-DOS style) + * + * @return array + * @author Naoki Sawada + **/ + protected function normalizeRawWindows($raw) + { + $info = array_pad(array(), 9, ''); + $item = preg_replace('#\s+#', ' ', trim($raw), 3); + list($date, $time, $size, $name) = explode(' ', $item, 4); + $format = strlen($date) === 8 ? 'm-d-yH:iA' : 'Y-m-dH:i'; + $dateObj = DateTime::createFromFormat($format, $date . $time); + $info[5] = strtotime($dateObj->format('Y-m-d H:i')); + $info[8] = $name; + if ($size === '') { + $info[4] = 0; + $info[0] = 'drwxr-xr-x'; + } else { + $info[4] = (int)$size; + $info[0] = '-rw-r--r--'; + } + return $info; + } + + /** + * Parse permissions string. Return array(read => true/false, write => true/false) + * + * @param string $perm permissions string 'rwx' + 'rwx' + 'rwx' + * ^ ^ ^ + * | | +-> others + * | +---------> group + * +-----------------> owner + * The isowner parameter is computed by the caller. + * If the owner parameter in the options is true, the user is the actual owner of all objects even if che user used in the ftp Login + * is different from the file owner id. + * If the owner parameter is false to understand if the user is the file owner we compare the ftp user with the file owner id. + * @param Boolean $isowner . Tell if the current user is the owner of the object. + * + * @return array + * @author Dmitry (dio) Levashov + * @author Ugo Vierucci + */ + protected function parsePermissions($perm, $isowner = true) + { + $res = array(); + $parts = array(); + for ($i = 0, $l = strlen($perm); $i < $l; $i++) { + $parts[] = substr($perm, $i, 1); + } + + $read = ($isowner && $parts[1] == 'r') || $parts[4] == 'r' || $parts[7] == 'r'; + + return array( + 'read' => $parts[0] == 'd' ? $read && (($isowner && $parts[3] == 'x') || $parts[6] == 'x' || $parts[9] == 'x') : $read, + 'write' => ($isowner && $parts[2] == 'w') || $parts[5] == 'w' || $parts[8] == 'w' + ); + } + + /** + * Cache dir contents + * + * @param string $path dir path + * + * @return void + * @author Dmitry Levashov + **/ + protected function cacheDir($path) + { + $this->dirsCache[$path] = array(); + $hasDir = false; + + $list = array(); + $encPath = $this->convEncIn($path); + foreach ($this->ftpRawList($encPath) as $raw) { + if (($stat = $this->parseRaw($raw, $encPath))) { + $list[] = $stat; + } + } + $list = $this->convEncOut($list); + $prefix = ($path === $this->separator) ? $this->separator : $path . $this->separator; + $targets = array(); + foreach ($list as $stat) { + $p = $prefix . $stat['name']; + if (isset($stat['target'])) { + // stat later + $targets[$stat['name']] = $stat['target']; + } else { + $stat = $this->updateCache($p, $stat); + if (empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $p; + } + } + } + // stat link targets + foreach ($targets as $name => $target) { + $stat = array(); + $stat['name'] = $name; + $p = $prefix . $name; + $cacheDirTarget = $this->cacheDirTarget; + $this->cacheDirTarget = $this->convEncIn($target, true); + if ($tstat = $this->stat($target)) { + $stat['size'] = $tstat['size']; + $stat['alias'] = $target; + $stat['thash'] = $tstat['hash']; + $stat['mime'] = $tstat['mime']; + $stat['read'] = $tstat['read']; + $stat['write'] = $tstat['write']; + + if (isset($tstat['ts'])) { + $stat['ts'] = $tstat['ts']; + } + if (isset($tstat['owner'])) { + $stat['owner'] = $tstat['owner']; + } + if (isset($tstat['group'])) { + $stat['group'] = $tstat['group']; + } + if (isset($tstat['perm'])) { + $stat['perm'] = $tstat['perm']; + } + if (isset($tstat['isowner'])) { + $stat['isowner'] = $tstat['isowner']; + } + } else { + + $stat['mime'] = 'symlink-broken'; + $stat['read'] = false; + $stat['write'] = false; + $stat['size'] = 0; + + } + $this->cacheDirTarget = $cacheDirTarget; + $stat = $this->updateCache($p, $stat); + if (empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $p; + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + } + + /** + * Return ftp transfer mode for file + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function ftpMode($path) + { + return strpos($this->mimetype($path), 'text/') === 0 ? FTP_ASCII : FTP_BINARY; + } + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function _dirname($path) + { + $parts = explode($this->separator, trim($path, $this->separator)); + array_pop($parts); + return $this->separator . join($this->separator, $parts); + } + + /** + * Return file name + * + * @param string $path file path + * + * @return string + * @author Naoki Sawada + **/ + protected function _basename($path) + { + $parts = explode($this->separator, trim($path, $this->separator)); + return array_pop($parts); + } + + /** + * Join dir name and file name and retur full path + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + return rtrim($dir, $this->separator) . $this->separator . $name; + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python + * + * @param string $path path + * + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) + { + if (empty($path)) { + $path = '.'; + } + // path must be start with / + $path = preg_replace('|^\.\/?|', $this->separator, $path); + $path = preg_replace('/^([^\/])/', "/$1", $path); + + if ($path[0] === $this->separator) { + $initial_slashes = true; + } else { + $initial_slashes = false; + } + + if (($initial_slashes) + && (strpos($path, '//') === 0) + && (strpos($path, '///') === false)) { + $initial_slashes = 2; + } + + $initial_slashes = (int)$initial_slashes; + + $comps = explode($this->separator, $path); + $new_comps = array(); + foreach ($comps as $comp) { + if (in_array($comp, array('', '.'))) { + continue; + } + + if (($comp != '..') + || (!$initial_slashes && !$new_comps) + || ($new_comps && (end($new_comps) == '..'))) { + array_push($new_comps, $comp); + } elseif ($new_comps) { + array_pop($new_comps); + } + } + $comps = $new_comps; + $path = implode($this->separator, $comps); + if ($initial_slashes) { + $path = str_repeat($this->separator, $initial_slashes) . $path; + } + + return $path ? $path : '.'; + } + + /** + * Return file path related to root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + if ($path === $this->root) { + return ''; + } else { + if (strpos($path, $this->root) === 0) { + return ltrim(substr($path, strlen($this->root)), $this->separator); + } else { + // for link + return $path; + } + } + } + + /** + * Convert path related to root dir into real path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) + { + if ($path === $this->separator) { + return $this->root; + } else { + if ($path[0] === $this->separator) { + // for link + return $path; + } else { + return $this->_joinPath($this->root, $path); + } + } + } + + /** + * Return fake path started from root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) + { + return $this->rootName . ($path == $this->root ? '' : $this->separator . $this->_relpath($path)); + } + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) + { + return $path == $parent || strpos($path, rtrim($parent, $this->separator) . $this->separator) === 0; + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + $outPath = $this->convEncOut($path); + if (isset($this->cache[$outPath])) { + return $this->convEncIn($this->cache[$outPath]); + } else { + $this->convEncIn(); + } + if (!$this->MLSTsupprt) { + if ($path === $this->root) { + $res = array( + 'name' => $this->root, + 'mime' => 'directory', + 'dirs' => -1 + ); + if ($this->needOnline && (($this->ARGS['cmd'] === 'open' && $this->ARGS['target'] === $this->encode($this->root)) || $this->isMyReload())) { + $check = array( + 'ts' => true, + 'dirs' => true, + ); + $ts = 0; + foreach ($this->ftpRawList($path) as $str) { + $info = preg_split('/\s+/', $str, 9); + if ($info[8] === '.') { + $info[8] = 'root'; + if ($stat = $this->parseRaw(join(' ', $info), $path)) { + unset($stat['name']); + $res = array_merge($res, $stat); + if ($res['ts']) { + $ts = 0; + unset($check['ts']); + } + } + } + if ($check && ($stat = $this->parseRaw($str, $path))) { + if (isset($stat['ts']) && !empty($stat['ts'])) { + $ts = max($ts, $stat['ts']); + } + if (isset($stat['dirs']) && $stat['mime'] === 'directory') { + $res['dirs'] = 1; + unset($stat['dirs']); + } + if (!$check) { + break; + } + } + } + if ($ts) { + $res['ts'] = $ts; + } + $this->cache[$outPath] = $res; + } + return $res; + } + + $pPath = $this->_dirname($path); + if ($this->_inPath($pPath, $this->root)) { + $outPPpath = $this->convEncOut($pPath); + if (!isset($this->dirsCache[$outPPpath])) { + $parentSubdirs = null; + if (isset($this->sessionCache['subdirs']) && isset($this->sessionCache['subdirs'][$outPPpath])) { + $parentSubdirs = $this->sessionCache['subdirs'][$outPPpath]; + } + $this->cacheDir($outPPpath); + if ($parentSubdirs) { + $this->sessionCache['subdirs'][$outPPpath] = $parentSubdirs; + } + } + } + + $stat = $this->convEncIn(isset($this->cache[$outPath]) ? $this->cache[$outPath] : array()); + if (!$this->mounted) { + // dispose incomplete cache made by calling `stat` by 'startPath' option + $this->cache = array(); + } + return $stat; + } + $raw = ftp_raw($this->connect, 'MLST ' . $path); + if (is_array($raw) && count($raw) > 1 && substr(trim($raw[0]), 0, 1) == 2) { + $parts = explode(';', trim($raw[1])); + array_pop($parts); + $parts = array_map('strtolower', $parts); + $stat = array(); + $mode = ''; + foreach ($parts as $part) { + + list($key, $val) = explode('=', $part, 2); + + switch ($key) { + case 'type': + if (strpos($val, 'dir') !== false) { + $stat['mime'] = 'directory'; + } else if (strpos($val, 'link') !== false) { + $stat['mime'] = 'symlink'; + break(2); + } else { + $stat['mime'] = $this->mimetype($path); + } + break; + + case 'size': + $stat['size'] = $val; + break; + + case 'modify': + $ts = mktime(intval(substr($val, 8, 2)), intval(substr($val, 10, 2)), intval(substr($val, 12, 2)), intval(substr($val, 4, 2)), intval(substr($val, 6, 2)), substr($val, 0, 4)); + $stat['ts'] = $ts; + break; + + case 'unix.mode': + $mode = strval($val); + break; + + case 'unix.uid': + $stat['owner'] = $val; + break; + + case 'unix.gid': + $stat['group'] = $val; + break; + + case 'perm': + $val = strtolower($val); + $stat['read'] = (int)preg_match('/e|l|r/', $val); + $stat['write'] = (int)preg_match('/w|m|c/', $val); + if (!preg_match('/f|d/', $val)) { + $stat['locked'] = 1; + } + break; + } + } + + if (empty($stat['mime'])) { + return array(); + } + + // do not use MLST to get stat of symlink + if ($stat['mime'] === 'symlink') { + $this->MLSTsupprt = false; + $res = $this->_stat($path); + $this->MLSTsupprt = true; + return $res; + } + + if ($stat['mime'] === 'directory') { + $stat['size'] = 0; + } + + if ($mode) { + $stat['perm'] = ''; + if ($mode[0] === '0') { + $mode = substr($mode, 1); + } + + $perm = array(); + for ($i = 0; $i <= 2; $i++) { + $perm[$i] = array(false, false, false); + $n = isset($mode[$i]) ? $mode[$i] : 0; + + if ($n - 4 >= 0) { + $perm[$i][0] = true; + $n = $n - 4; + $stat['perm'] .= 'r'; + } else { + $stat['perm'] .= '-'; + } + + if ($n - 2 >= 0) { + $perm[$i][1] = true; + $n = $n - 2; + $stat['perm'] .= 'w'; + } else { + $stat['perm'] .= '-'; + } + + if ($n - 1 == 0) { + $perm[$i][2] = true; + $stat['perm'] .= 'x'; + } else { + $stat['perm'] .= '-'; + } + } + + $stat['perm'] = trim($stat['perm']); + // + // if not exists owner in LS ftp ==> isowner = true + // if is defined as option : 'owner' => true isowner = true + // + // if exist owner in LS ftp and 'owner' => False isowner = result of owner(file) == user(logged with ftp) + + $owner_computed = isset($stat['owner']) ? ($this->options['owner'] ? true : ($stat['owner'] == $this->options['user'])) : true; + + $read = ($owner_computed && $perm[0][0]) || $perm[1][0] || $perm[2][0]; + + $stat['read'] = $stat['mime'] == 'directory' ? $read && (($owner_computed && $perm[0][2]) || $perm[1][2] || $perm[2][2]) : $read; + $stat['write'] = ($owner_computed && $perm[0][1]) || $perm[1][1] || $perm[2][1]; + + if ($this->options['statOwner']) { + $stat['isowner'] = $owner_computed; + } else { + unset($stat['owner'], $stat['group'], $stat['perm']); + } + } + + return $stat; + + } + + return array(); + } + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _subdirs($path) + { + + foreach ($this->ftpRawList($path) as $str) { + $info = preg_split('/\s+/', $str, 9); + if (!isset($this->ftpOsUnix)) { + $this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1)); + } + if (!$this->ftpOsUnix) { + $info = $this->normalizeRawWindows($str); + } + $name = isset($info[8]) ? trim($info[8]) : ''; + if ($name && $name !== '.' && $name !== '..' && substr(strtolower($info[0]), 0, 1) === 'd') { + return true; + } + } + return false; + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string|false + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _dimensions($path, $mime) + { + $ret = false; + if ($imgsize = $this->getImageSize($path, $mime)) { + $ret = array('dim' => $imgsize['dimensions']); + if (!empty($imgsize['url'])) { + $ret['url'] = $imgsize['url']; + } + } + return $ret; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function _scandir($path) + { + $files = array(); + + foreach ($this->ftpRawList($path) as $str) { + if (($stat = $this->parseRaw($str, $path, true))) { + $files[] = $this->_joinPath($path, $stat['name']); + } + } + + return $files; + } + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param string $mode + * + * @return false|resource + * @throws elFinderAbortException + * @internal param bool $write open file for writing + * @author Dmitry (dio) Levashov + */ + protected function _fopen($path, $mode = 'rb') + { + // try ftp stream wrapper + if ($this->options['mode'] === 'passive' && ini_get('allow_url_fopen')) { + $url = ($this->isFTPS ? 'ftps' : 'ftp') . '://' . $this->options['user'] . ':' . $this->options['pass'] . '@' . $this->options['host'] . ':' . $this->options['port'] . $path; + if (strtolower($mode[0]) === 'w') { + $context = stream_context_create(array('ftp' => array('overwrite' => true))); + $fp = fopen($url, $mode, false, $context); + } else { + $fp = fopen($url, $mode); + } + if ($fp) { + return $fp; + } + } + + if ($this->tmp) { + $local = $this->getTempFile($path); + $fp = fopen($local, 'wb'); + $ret = ftp_nb_fget($this->connect, $fp, $path, FTP_BINARY); + while ($ret === FTP_MOREDATA) { + elFinder::extendTimeLimit(); + $ret = ftp_nb_continue($this->connect); + } + if ($ret === FTP_FINISHED) { + fclose($fp); + $fp = fopen($local, $mode); + return $fp; + } + fclose($fp); + is_file($local) && unlink($local); + } + + return false; + } + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path + * + * @return void + * @author Dmitry (dio) Levashov + */ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + if ($path) { + unlink($this->getTempFile($path)); + } + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + $path = $this->_joinPath($path, $name); + if (ftp_mkdir($this->connect, $path) === false) { + return false; + } + + $this->options['dirMode'] && ftp_chmod($this->connect, $this->options['dirMode'], $path); + return $path; + } + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) + { + if ($this->tmp) { + $path = $this->_joinPath($path, $name); + $local = $this->getTempFile(); + $res = touch($local) && ftp_put($this->connect, $path, $local, FTP_ASCII); + unlink($local); + return $res ? $path : false; + } + return false; + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * @param string $name + * + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function _symlink($target, $path, $name) + { + return false; + } + + /** + * Copy file into another file + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) + { + $res = false; + + if ($this->tmp) { + $local = $this->getTempFile(); + $target = $this->_joinPath($targetDir, $name); + + if (ftp_get($this->connect, $local, $source, FTP_BINARY) + && ftp_put($this->connect, $target, $local, $this->ftpMode($target))) { + $res = $target; + } + unlink($local); + } + + return $res; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + protected function _move($source, $targetDir, $name) + { + $target = $this->_joinPath($targetDir, $name); + return ftp_rename($this->connect, $source, $target) ? $target : false; + } + + /** + * Remove file + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + return ftp_delete($this->connect, $path); + } + + /** + * Remove dir + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + return ftp_rmdir($this->connect, $path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + protected function _save($fp, $dir, $name, $stat) + { + $path = $this->_joinPath($dir, $name); + return ftp_fput($this->connect, $path, $fp, $this->ftpMode($path)) + ? $path + : false; + } + + /** + * Get file contents + * + * @param string $path file path + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _getContents($path) + { + $contents = ''; + if (($fp = $this->_fopen($path))) { + while (!feof($fp)) { + $contents .= fread($fp, 8192); + } + $this->_fclose($fp, $path); + return $contents; + } + return false; + } + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + $res = false; + + if ($this->tmp) { + $local = $this->getTempFile(); + + if (file_put_contents($local, $content, LOCK_EX) !== false + && ($fp = fopen($local, 'rb'))) { + $file = $this->stat($this->convEncOut($path, false)); + if (!empty($file['thash'])) { + $path = $this->decode($file['thash']); + } + clearstatcache(); + $res = ftp_fput($this->connect, $path, $fp, $this->ftpMode($path)); + fclose($fp); + } + file_exists($local) && unlink($local); + } + + return $res; + } + + /** + * Detect available archivers + * + * @return void + * @throws elFinderAbortException + */ + protected function _checkArchivers() + { + $this->archivers = $this->getArchivers(); + return; + } + + /** + * chmod availability + * + * @param string $path + * @param string $mode + * + * @return bool + */ + protected function _chmod($path, $mode) + { + $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode)); + return ftp_chmod($this->connect, $modeOct, $path); + } + + /** + * Extract files from archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return true + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _extract($path, $arc) + { + $dir = $this->tempDir(); + if (!$dir) { + return false; + } + + $basename = $this->_basename($path); + $localPath = $dir . DIRECTORY_SEPARATOR . $basename; + + if (!ftp_get($this->connect, $localPath, $path, FTP_BINARY)) { + //cleanup + $this->rmdirRecursive($dir); + return false; + } + + $this->unpackArchive($localPath, $arc); + + $this->archiveSize = 0; + + // find symlinks and check extracted items + $checkRes = $this->checkExtractItems($dir); + if ($checkRes['symlinks']) { + $this->rmdirRecursive($dir); + return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS))); + } + $this->archiveSize = $checkRes['totalSize']; + if ($checkRes['rmNames']) { + foreach ($checkRes['rmNames'] as $name) { + $this->addError(elFinder::ERROR_SAVE, $name); + } + } + + $filesToProcess = self::listFilesInDirectory($dir, true); + + // no files - extract error ? + if (empty($filesToProcess)) { + $this->rmdirRecursive($dir); + return false; + } + + // check max files size + if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) { + $this->rmdirRecursive($dir); + return $this->setError(elFinder::ERROR_ARC_MAXSIZE); + } + + $extractTo = $this->extractToNewdir; // 'auto', ture or false + + // archive contains one item - extract in archive dir + $name = ''; + $src = $dir . DIRECTORY_SEPARATOR . $filesToProcess[0]; + if (($extractTo === 'auto' || !$extractTo) && count($filesToProcess) === 1 && is_file($src)) { + $name = $filesToProcess[0]; + } else if ($extractTo === 'auto' || $extractTo) { + // for several files - create new directory + // create unique name for directory + $src = $dir; + $splits = elFinder::splitFileExtention(basename($path)); + $name = $splits[0]; + $test = $this->_joinPath(dirname($path), $name); + if ($this->stat($test)) { + $name = $this->uniqueName(dirname($path), $name, '-', false); + } + } + + if ($name !== '' && is_file($src)) { + $result = $this->_joinPath(dirname($path), $name); + + if (!ftp_put($this->connect, $result, $src, FTP_BINARY)) { + $this->rmdirRecursive($dir); + return false; + } + } else { + $dstDir = $this->_dirname($path); + $result = array(); + if (is_dir($src) && $name) { + $target = $this->_joinPath($dstDir, $name); + $_stat = $this->_stat($target); + if ($_stat) { + if (!$this->options['copyJoin']) { + if ($_stat['mime'] === 'directory') { + $this->delTree($target); + } else { + $this->_unlink($target); + } + $_stat = false; + } else { + $dstDir = $target; + } + } + if (!$_stat && (!$dstDir = $this->_mkdir($dstDir, $name))) { + $this->rmdirRecursive($dir); + return false; + } + $result[] = $dstDir; + } + foreach ($filesToProcess as $name) { + $name = rtrim($name, DIRECTORY_SEPARATOR); + $src = $dir . DIRECTORY_SEPARATOR . $name; + if (is_dir($src)) { + $p = dirname($name); + if ($p === '.') { + $p = ''; + } + $name = basename($name); + $target = $this->_joinPath($this->_joinPath($dstDir, $p), $name); + $_stat = $this->_stat($target); + if ($_stat) { + if (!$this->options['copyJoin']) { + if ($_stat['mime'] === 'directory') { + $this->delTree($target); + } else { + $this->_unlink($target); + } + $_stat = false; + } + } + if (!$_stat && (!$target = $this->_mkdir($this->_joinPath($dstDir, $p), $name))) { + $this->rmdirRecursive($dir); + return false; + } + } else { + $target = $this->_joinPath($dstDir, $name); + if (!ftp_put($this->connect, $target, $src, FTP_BINARY)) { + $this->rmdirRecursive($dir); + return false; + } + } + $result[] = $target; + } + if (!$result) { + $this->rmdirRecursive($dir); + return false; + } + } + + is_dir($dir) && $this->rmdirRecursive($dir); + + $this->clearcache(); + return $result ? $result : false; + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _archive($dir, $files, $name, $arc) + { + // get current directory + $cwd = getcwd(); + + $tmpDir = $this->tempDir(); + if (!$tmpDir) { + return false; + } + + //download data + if (!$this->ftp_download_files($dir, $files, $tmpDir)) { + //cleanup + $this->rmdirRecursive($tmpDir); + return false; + } + + $remoteArchiveFile = false; + if ($path = $this->makeArchive($tmpDir, $files, $name, $arc)) { + $remoteArchiveFile = $this->_joinPath($dir, $name); + if (!ftp_put($this->connect, $remoteArchiveFile, $path, FTP_BINARY)) { + $remoteArchiveFile = false; + } + } + + //cleanup + if (!$this->rmdirRecursive($tmpDir)) { + return false; + } + + return $remoteArchiveFile; + } + + /** + * Create writable temporary directory and return path to it. + * + * @return string path to the new temporary directory or false in case of error. + */ + private function tempDir() + { + $tempPath = tempnam($this->tmp, 'elFinder'); + if (!$tempPath) { + $this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp); + return false; + } + $success = unlink($tempPath); + if (!$success) { + $this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp); + return false; + } + $success = mkdir($tempPath, 0700, true); + if (!$success) { + $this->setError(elFinder::ERROR_CREATING_TEMP_DIR, $this->tmp); + return false; + } + return $tempPath; + } + + /** + * Gets an array of absolute remote FTP paths of files and + * folders in $remote_directory omitting symbolic links. + * + * @param $remote_directory string remote FTP path to scan for file and folders recursively + * @param $targets array Array of target item. `null` is to get all of items + * + * @return array of elements each of which is an array of two elements: + *
                        + *
                      • $item['path'] - absolute remote FTP path
                      • + *
                      • $item['type'] - either 'f' for file or 'd' for directory
                      • + *
                      + */ + protected function ftp_scan_dir($remote_directory, $targets = null) + { + $buff = $this->ftpRawList($remote_directory); + $items = array(); + if ($targets && is_array($targets)) { + $targets = array_flip($targets); + } else { + $targets = false; + } + foreach ($buff as $str) { + $info = preg_split("/\s+/", $str, 9); + if (!isset($this->ftpOsUnix)) { + $this->ftpOsUnix = !preg_match('/\d/', substr($info[0], 0, 1)); + } + if (!$this->ftpOsUnix) { + $info = $this->normalizeRawWindows($str); + } + $type = substr($info[0], 0, 1); + $name = trim($info[8]); + if ($name !== '.' && $name !== '..' && (!$targets || isset($targets[$name]))) { + switch ($type) { + case 'l' : //omit symbolic links + case 'd' : + $remote_file_path = $this->_joinPath($remote_directory, $name); + $item = array(); + $item['path'] = $remote_file_path; + $item['type'] = 'd'; // normal file + $items[] = $item; + $items = array_merge($items, $this->ftp_scan_dir($remote_file_path)); + break; + default: + $remote_file_path = $this->_joinPath($remote_directory, $name); + $item = array(); + $item['path'] = $remote_file_path; + $item['type'] = 'f'; // normal file + $items[] = $item; + } + } + } + return $items; + } + + /** + * Downloads specified files from remote directory + * if there is a directory among files it is downloaded recursively (omitting symbolic links). + * + * @param $remote_directory string remote FTP path to a source directory to download from. + * @param array $files list of files to download from remote directory. + * @param $dest_local_directory string destination folder to store downloaded files. + * + * @return bool true on success and false on failure. + */ + private function ftp_download_files($remote_directory, array $files, $dest_local_directory) + { + $contents = $this->ftp_scan_dir($remote_directory, $files); + if (!isset($contents)) { + $this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory); + return false; + } + $remoteDirLen = strlen($remote_directory); + foreach ($contents as $item) { + $relative_path = substr($item['path'], $remoteDirLen); + $local_path = $dest_local_directory . DIRECTORY_SEPARATOR . $relative_path; + switch ($item['type']) { + case 'd': + $success = mkdir($local_path); + break; + case 'f': + $success = ftp_get($this->connect, $local_path, $item['path'], FTP_BINARY); + break; + default: + $success = true; + } + if (!$success) { + $this->setError(elFinder::ERROR_FTP_DOWNLOAD_FILE, $remote_directory); + return false; + } + } + return true; + } + + /** + * Delete local directory recursively. + * + * @param $dirPath string to directory to be erased. + * + * @return bool true on success and false on failure. + * @throws Exception + */ + private function deleteDir($dirPath) + { + if (!is_dir($dirPath)) { + $success = unlink($dirPath); + } else { + $success = true; + foreach (array_reverse(elFinderVolumeFTP::listFilesInDirectory($dirPath, false)) as $path) { + $path = $dirPath . DIRECTORY_SEPARATOR . $path; + if (is_link($path)) { + unlink($path); + } else if (is_dir($path)) { + $success = rmdir($path); + } else { + $success = unlink($path); + } + if (!$success) { + break; + } + } + if ($success) { + $success = rmdir($dirPath); + } + } + if (!$success) { + $this->setError(elFinder::ERROR_RM, $dirPath); + return false; + } + return $success; + } + + /** + * Returns array of strings containing all files and folders in the specified local directory. + * + * @param $dir + * @param $omitSymlinks + * @param string $prefix + * + * @return array array of files and folders names relative to the $path + * or an empty array if the directory $path is empty, + *
                      + * false if $path is not a directory or does not exist. + * @throws Exception + * @internal param string $path path to directory to scan. + */ + private static function listFilesInDirectory($dir, $omitSymlinks, $prefix = '') + { + if (!is_dir($dir)) { + return false; + } + $excludes = array(".", ".."); + $result = array(); + $files = self::localScandir($dir); + if (!$files) { + return array(); + } + foreach ($files as $file) { + if (!in_array($file, $excludes)) { + $path = $dir . DIRECTORY_SEPARATOR . $file; + if (is_link($path)) { + if ($omitSymlinks) { + continue; + } else { + $result[] = $prefix . $file; + } + } else if (is_dir($path)) { + $result[] = $prefix . $file . DIRECTORY_SEPARATOR; + $subs = elFinderVolumeFTP::listFilesInDirectory($path, $omitSymlinks, $prefix . $file . DIRECTORY_SEPARATOR); + if ($subs) { + $result = array_merge($result, $subs); + } + + } else { + $result[] = $prefix . $file; + } + } + } + return $result; + } + +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeGoogleDrive.class.php b/lib/redactor/elfinder/php/elFinderVolumeGoogleDrive.class.php new file mode 100644 index 0000000..d04a4fd --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeGoogleDrive.class.php @@ -0,0 +1,2163 @@ + name of each items. + * + * @var array + */ + protected $names = []; + + /** + * MIME tyoe of directory. + * + * @var string + */ + const DIRMIME = 'application/vnd.google-apps.folder'; + + /** + * Fetch fields for list. + * + * @var string + */ + const FETCHFIELDS_LIST = 'files(id,name,mimeType,modifiedTime,parents,permissions,size,imageMediaMetadata(height,width),thumbnailLink,webContentLink,webViewLink),nextPageToken'; + + /** + * Fetch fields for get. + * + * @var string + */ + const FETCHFIELDS_GET = 'id,name,mimeType,modifiedTime,parents,permissions,size,imageMediaMetadata(height,width),thumbnailLink,webContentLink,webViewLink'; + + /** + * Directory for tmp files + * If not set driver will try to use tmbDir as tmpDir. + * + * @var string + **/ + protected $tmp = ''; + + /** + * Net mount key. + * + * @var string + **/ + public $netMountKey = ''; + + /** + * Current token expires + * + * @var integer + **/ + private $expires; + + /** + * Constructor + * Extend options with required fields. + * + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + public function __construct() + { + $opts = [ + 'client_id' => '', + 'client_secret' => '', + 'access_token' => [], + 'refresh_token' => '', + 'serviceAccountConfigFile' => '', + 'root' => 'My Drive', + 'gdAlias' => '%s@GDrive', + 'googleApiClient' => '', + 'path' => '/', + 'tmbPath' => '', + 'separator' => '/', + 'useGoogleTmb' => true, + 'acceptedName' => '#.#', + 'rootCssClass' => 'elfinder-navbar-root-googledrive', + 'publishPermission' => [ + 'type' => 'anyone', + 'role' => 'reader', + 'withLink' => true, + ], + 'appsExportMap' => [ + 'application/vnd.google-apps.document' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.google-apps.spreadsheet' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.google-apps.drawing' => 'application/pdf', + 'application/vnd.google-apps.presentation' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'application/vnd.google-apps.script' => 'application/vnd.google-apps.script+json', + 'default' => 'application/pdf', + ], + ]; + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /*********************************************************************/ + /* ORIGINAL FUNCTIONS */ + /*********************************************************************/ + + /** + * Get Parent ID, Item ID, Parent Path as an array from path. + * + * @param string $path + * + * @return array + */ + protected function _gd_splitPath($path) + { + $path = trim($path, '/'); + $pid = ''; + if ($path === '') { + $id = 'root'; + $parent = ''; + } else { + $path = str_replace('\\/', chr(0), $path); + $paths = explode('/', $path); + $id = array_pop($paths); + $id = str_replace(chr(0), '/', $id); + if ($paths) { + $parent = '/' . implode('/', $paths); + $pid = array_pop($paths); + } else { + $rootid = ($this->root === '/') ? 'root' : trim($this->root, '/'); + if ($id === $rootid) { + $parent = ''; + } else { + $parent = $this->root; + $pid = $rootid; + } + } + } + + return array($pid, $id, $parent); + } + + /** + * Drive query and fetchAll. + * + * @param string $sql + * + * @return bool|array + */ + private function _gd_query($opts) + { + $result = []; + $pageToken = null; + $parameters = [ + 'fields' => self::FETCHFIELDS_LIST, + 'pageSize' => 1000, + 'spaces' => 'drive', + ]; + + if (is_array($opts)) { + $parameters = array_merge($parameters, $opts); + } + do { + try { + if ($pageToken) { + $parameters['pageToken'] = $pageToken; + } + $files = $this->service->files->listFiles($parameters); + + $result = array_merge($result, $files->getFiles()); + $pageToken = $files->getNextPageToken(); + } catch (Exception $e) { + $pageToken = null; + } + } while ($pageToken); + + return $result; + } + + /** + * Get dat(googledrive metadata) from GoogleDrive. + * + * @param string $path + * + * @return array googledrive metadata + */ + private function _gd_getFile($path, $fields = '') + { + list(, $itemId) = $this->_gd_splitPath($path); + if (!$fields) { + $fields = self::FETCHFIELDS_GET; + } + try { + $file = $this->service->files->get($itemId, ['fields' => $fields]); + if ($file instanceof Google_Service_Drive_DriveFile) { + return $file; + } else { + return []; + } + } catch (Exception $e) { + return []; + } + } + + /** + * Parse line from googledrive metadata output and return file stat (array). + * + * @param array $raw line from ftp_rawlist() output + * + * @return array + * @author Dmitry Levashov + **/ + protected function _gd_parseRaw($raw) + { + $stat = []; + + $stat['iid'] = isset($raw['id']) ? $raw['id'] : 'root'; + $stat['name'] = isset($raw['name']) ? $raw['name'] : ''; + if (isset($raw['modifiedTime'])) { + $stat['ts'] = strtotime($raw['modifiedTime']); + } + + if ($raw['mimeType'] === self::DIRMIME) { + $stat['mime'] = 'directory'; + $stat['size'] = 0; + } else { + $stat['mime'] = $raw['mimeType'] == 'image/bmp' ? 'image/x-ms-bmp' : $raw['mimeType']; + $stat['size'] = (int)$raw['size']; + if ($size = $raw->getImageMediaMetadata()) { + $stat['width'] = $size['width']; + $stat['height'] = $size['height']; + } + + $published = $this->_gd_isPublished($raw); + + if ($this->options['useGoogleTmb']) { + if (isset($raw['thumbnailLink'])) { + if ($published) { + $stat['tmb'] = 'drive.google.com/thumbnail?authuser=0&sz=s' . $this->options['tmbSize'] . '&id=' . $raw['id']; + } else { + $stat['tmb'] = substr($raw['thumbnailLink'], 8); // remove "https://" + } + } else { + $stat['tmb'] = ''; + } + } + + if ($published) { + $stat['url'] = $this->_gd_getLink($raw); + } elseif (!$this->disabledGetUrl) { + $stat['url'] = '1'; + } + } + + return $stat; + } + + /** + * Get dat(googledrive metadata) from GoogleDrive. + * + * @param string $path + * + * @return array googledrive metadata + */ + private function _gd_getNameByPath($path) + { + list(, $itemId) = $this->_gd_splitPath($path); + if (!$this->names) { + $this->_gd_getDirectoryData(); + } + + return isset($this->names[$itemId]) ? $this->names[$itemId] : ''; + } + + /** + * Make cache of $parents, $names and $directories. + * + * @param bool $usecache + */ + protected function _gd_getDirectoryData($usecache = true) + { + if ($usecache) { + $cache = $this->session->get($this->id . $this->netMountKey, []); + if ($cache) { + $this->parents = $cache['parents']; + $this->names = $cache['names']; + $this->directories = $cache['directories']; + + return; + } + } + + $root = ''; + if ($this->root === '/') { + // get root id + if ($res = $this->_gd_getFile('/', 'id')) { + $root = $res->getId(); + } + } + + $data = []; + $opts = [ + 'fields' => 'files(id, name, parents)', + 'q' => sprintf('trashed=false and mimeType="%s"', self::DIRMIME), + ]; + $res = $this->_gd_query($opts); + foreach ($res as $raw) { + if ($parents = $raw->getParents()) { + $id = $raw->getId(); + $this->parents[$id] = $parents; + $this->names[$id] = $raw->getName(); + foreach ($parents as $p) { + if (isset($data[$p])) { + $data[$p][] = $id; + } else { + $data[$p] = [$id]; + } + } + } + } + if ($root && isset($data[$root])) { + $data['root'] = $data[$root]; + } + $this->directories = $data; + $this->session->set($this->id . $this->netMountKey, [ + 'parents' => $this->parents, + 'names' => $this->names, + 'directories' => $this->directories, + ]); + } + + /** + * Get descendants directories. + * + * @param string $itemId + * + * @return array + */ + protected function _gd_getDirectories($itemId) + { + $ret = []; + if ($this->directories === null) { + $this->_gd_getDirectoryData(); + } + $data = $this->directories; + if (isset($data[$itemId])) { + $ret = $data[$itemId]; + foreach ($data[$itemId] as $cid) { + $ret = array_merge($ret, $this->_gd_getDirectories($cid)); + } + } + + return $ret; + } + + /** + * Get ID based path from item ID. + * + * @param string $id + * + * @return array + */ + protected function _gd_getMountPaths($id) + { + $root = false; + if ($this->directories === null) { + $this->_gd_getDirectoryData(); + } + list($pid) = explode('/', $id, 2); + $path = $id; + if ('/' . $pid === $this->root) { + $root = true; + } elseif (!isset($this->parents[$pid])) { + $root = true; + $path = ltrim(substr($path, strlen($pid)), '/'); + } + $res = []; + if ($root) { + if ($this->root === '/' || strpos('/' . $path, $this->root) === 0) { + $res = [(strpos($path, '/') === false) ? '/' : ('/' . $path)]; + } + } else { + foreach ($this->parents[$pid] as $p) { + $_p = $p . '/' . $path; + $res = array_merge($res, $this->_gd_getMountPaths($_p)); + } + } + + return $res; + } + + /** + * Return is published. + * + * @param object $file + * + * @return bool + */ + protected function _gd_isPublished($file) + { + $res = false; + $pType = $this->options['publishPermission']['type']; + $pRole = $this->options['publishPermission']['role']; + if ($permissions = $file->getPermissions()) { + foreach ($permissions as $permission) { + if ($permission->type === $pType && $permission->role === $pRole) { + $res = true; + break; + } + } + } + + return $res; + } + + /** + * return item URL link. + * + * @param object $file + * + * @return string + */ + protected function _gd_getLink($file) + { + if (strpos($file->mimeType, 'application/vnd.google-apps.') !== 0) { + if ($url = $file->getWebContentLink()) { + return str_replace('export=download', 'export=media', $url); + } + } + if ($url = $file->getWebViewLink()) { + return $url; + } + + return ''; + } + + /** + * Get download url. + * + * @param Google_Service_Drive_DriveFile $file + * + * @return string|false + */ + protected function _gd_getDownloadUrl($file) + { + if (strpos($file->mimeType, 'application/vnd.google-apps.') !== 0) { + return 'https://www.googleapis.com/drive/v3/files/' . $file->getId() . '?alt=media'; + } else { + $mimeMap = $this->options['appsExportMap']; + if (isset($mimeMap[$file->getMimeType()])) { + $mime = $mimeMap[$file->getMimeType()]; + } else { + $mime = $mimeMap['default']; + } + $mime = rawurlencode($mime); + + return 'https://www.googleapis.com/drive/v3/files/' . $file->getId() . '/export?mimeType=' . $mime; + } + + return false; + } + + /** + * Get thumbnail from GoogleDrive.com. + * + * @param string $path + * + * @return string | boolean + */ + protected function _gd_getThumbnail($path) + { + list(, $itemId) = $this->_gd_splitPath($path); + + try { + $contents = $this->service->files->get($itemId, [ + 'alt' => 'media', + ]); + $contents = $contents->getBody()->detach(); + rewind($contents); + + return $contents; + } catch (Exception $e) { + return false; + } + } + + /** + * Publish permissions specified path item. + * + * @param string $path + * + * @return bool + */ + protected function _gd_publish($path) + { + if ($file = $this->_gd_getFile($path)) { + if ($this->_gd_isPublished($file)) { + return true; + } + try { + if ($this->service->permissions->create($file->getId(), new \Google_Service_Drive_Permission($this->options['publishPermission']))) { + return true; + } + } catch (Exception $e) { + return false; + } + } + + return false; + } + + /** + * unPublish permissions specified path. + * + * @param string $path + * + * @return bool + */ + protected function _gd_unPublish($path) + { + if ($file = $this->_gd_getFile($path)) { + if (!$this->_gd_isPublished($file)) { + return true; + } + $permissions = $file->getPermissions(); + $pType = $this->options['publishPermission']['type']; + $pRole = $this->options['publishPermission']['role']; + try { + foreach ($permissions as $permission) { + if ($permission->type === $pType && $permission->role === $pRole) { + $this->service->permissions->delete($file->getId(), $permission->getId()); + + return true; + break; + } + } + } catch (Exception $e) { + return false; + } + } + + return false; + } + + /** + * Read file chunk. + * + * @param resource $handle + * @param int $chunkSize + * + * @return string + */ + protected function _gd_readFileChunk($handle, $chunkSize) + { + $byteCount = 0; + $giantChunk = ''; + while (!feof($handle)) { + // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file + $chunk = fread($handle, 8192); + $byteCount += strlen($chunk); + $giantChunk .= $chunk; + if ($byteCount >= $chunkSize) { + return $giantChunk; + } + } + + return $giantChunk; + } + + /*********************************************************************/ + /* EXTENDED FUNCTIONS */ + /*********************************************************************/ + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount(). + * + * @return array + * @author Naoki Sawada + * @author Raja Sharma updating for GoogleDrive + **/ + public function netmountPrepare($options) + { + if (empty($options['client_id']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTID')) { + $options['client_id'] = ELFINDER_GOOGLEDRIVE_CLIENTID; + } + if (empty($options['client_secret']) && defined('ELFINDER_GOOGLEDRIVE_CLIENTSECRET')) { + $options['client_secret'] = ELFINDER_GOOGLEDRIVE_CLIENTSECRET; + } + if (empty($options['googleApiClient']) && defined('ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT')) { + $options['googleApiClient'] = ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT; + include_once $options['googleApiClient']; + } + + if (!isset($options['pass'])) { + $options['pass'] = ''; + } + + try { + $client = new \Google_Client(); + $client->setClientId($options['client_id']); + $client->setClientSecret($options['client_secret']); + + if ($options['pass'] === 'reauth') { + $options['pass'] = ''; + $this->session->set('GoogleDriveAuthParams', [])->set('GoogleDriveTokens', []); + } elseif ($options['pass'] === 'googledrive') { + $options['pass'] = ''; + } + + $options = array_merge($this->session->get('GoogleDriveAuthParams', []), $options); + + if (!isset($options['access_token'])) { + $options['access_token'] = $this->session->get('GoogleDriveTokens', []); + $this->session->remove('GoogleDriveTokens'); + } + $aToken = $options['access_token']; + + $rootObj = $service = null; + if ($aToken) { + try { + $client->setAccessToken($aToken); + if ($client->isAccessTokenExpired()) { + $aToken = array_merge($aToken, $client->fetchAccessTokenWithRefreshToken()); + $client->setAccessToken($aToken); + } + $service = new \Google_Service_Drive($client); + $rootObj = $service->files->get('root'); + + $options['access_token'] = $aToken; + $this->session->set('GoogleDriveAuthParams', $options); + } catch (Exception $e) { + $aToken = []; + $options['access_token'] = []; + if ($options['user'] !== 'init') { + $this->session->set('GoogleDriveAuthParams', $options); + + return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE]; + } + } + } + + $itpCare = isset($options['code']); + $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : ''); + if ($code || (isset($options['user']) && $options['user'] === 'init')) { + if (empty($options['url'])) { + $options['url'] = elFinder::getConnectorUrl(); + } + + if (isset($options['id'])) { + $callback = $options['url'] + . (strpos($options['url'], '?') !== false? '&' : '?') . 'cmd=netmount&protocol=googledrive&host=' . ($options['id'] === 'elfinder'? '1' : $options['id']); + $client->setRedirectUri($callback); + } + + if (!$aToken && empty($code)) { + $client->setScopes([Google_Service_Drive::DRIVE]); + if (!empty($options['offline'])) { + $client->setApprovalPrompt('force'); + $client->setAccessType('offline'); + } + $url = $client->createAuthUrl(); + + $html = ''; + $html .= ''; + if (empty($options['pass']) && $options['host'] !== '1') { + $options['pass'] = 'return'; + $this->session->set('GoogleDriveAuthParams', $options); + + return ['exit' => true, 'body' => $html]; + } else { + $out = [ + 'node' => $options['id'], + 'json' => '{"protocol": "googledrive", "mode": "makebtn", "body" : "' . str_replace($html, '"', '\\"') . '", "error" : "' . elFinder::ERROR_ACCESS_DENIED . '"}', + 'bind' => 'netmount', + ]; + + return ['exit' => 'callback', 'out' => $out]; + } + } else { + if ($code) { + if (!empty($options['id'])) { + $aToken = $client->fetchAccessTokenWithAuthCode($code); + $options['access_token'] = $aToken; + unset($options['code']); + $this->session->set('GoogleDriveTokens', $aToken)->set('GoogleDriveAuthParams', $options); + $out = [ + 'node' => $options['id'], + 'json' => '{"protocol": "googledrive", "mode": "done", "reset": 1}', + 'bind' => 'netmount', + ]; + } else { + $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host']; + $out = array( + 'node' => $nodeid, + 'json' => json_encode(array( + 'protocol' => 'googledrive', + 'host' => $nodeid, + 'mode' => 'redirect', + 'options' => array( + 'id' => $nodeid, + 'code'=> $code + ) + )), + 'bind' => 'netmount' + ); + } + if (!$itpCare) { + return array('exit' => 'callback', 'out' => $out); + } else { + return array('exit' => true, 'body' => $out['json']); + } + } + $path = $options['path']; + if ($path === '/') { + $path = 'root'; + } + $folders = []; + foreach ($service->files->listFiles([ + 'pageSize' => 1000, + 'q' => sprintf('trashed = false and "%s" in parents and mimeType = "application/vnd.google-apps.folder"', $path), + ]) as $f) { + $folders[$f->getId()] = $f->getName(); + } + natcasesort($folders); + + if ($options['pass'] === 'folders') { + return ['exit' => true, 'folders' => $folders]; + } + + $folders = ['root' => $rootObj->getName()] + $folders; + $folders = json_encode($folders); + $expires = empty($aToken['refresh_token']) ? $aToken['created'] + $aToken['expires_in'] - 30 : 0; + $mnt2res = empty($aToken['refresh_token']) ? '' : ', "mnt2res": 1'; + $json = '{"protocol": "googledrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res . '}'; + $options['pass'] = 'return'; + $html = 'Google.com'; + $html .= ''; + $this->session->set('GoogleDriveAuthParams', $options); + + return ['exit' => true, 'body' => $html]; + } + } + } catch (Exception $e) { + $this->session->remove('GoogleDriveAuthParams')->remove('GoogleDriveTokens'); + if (empty($options['pass'])) { + return ['exit' => true, 'body' => '{msg:' . elFinder::ERROR_ACCESS_DENIED . '}' . ' ' . $e->getMessage()]; + } else { + return ['exit' => true, 'error' => [elFinder::ERROR_ACCESS_DENIED, $e->getMessage()]]; + } + } + + if (!$aToken) { + return ['exit' => true, 'error' => elFinder::ERROR_REAUTH_REQUIRE]; + } + + if ($options['path'] === '/') { + $options['path'] = 'root'; + } + + try { + $file = $service->files->get($options['path']); + $options['alias'] = sprintf($this->options['gdAlias'], $file->getName()); + } catch (Google_Service_Exception $e) { + $err = json_decode($e->getMessage(), true); + if (isset($err['error']) && $err['error']['code'] == 404) { + return ['exit' => true, 'error' => [elFinder::ERROR_TRGDIR_NOT_FOUND, $options['path']]]; + } else { + return ['exit' => true, 'error' => $e->getMessage()]; + } + } catch (Exception $e) { + return ['exit' => true, 'error' => $e->getMessage()]; + } + + foreach (['host', 'user', 'pass', 'id', 'offline'] as $key) { + unset($options[$key]); + } + + return $options; + } + + /** + * process of on netunmount + * Drop `googledrive` & rm thumbs. + * + * @param $netVolumes + * @param $key + * + * @return bool + */ + public function netunmount($netVolumes, $key) + { + if (!$this->options['useGoogleTmb']) { + if ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->netMountKey . '*.png')) { + foreach ($tmbs as $file) { + unlink($file); + } + } + } + $this->session->remove($this->id . $this->netMountKey); + + return true; + } + + /** + * Return fileinfo based on filename + * For item ID based path file system + * Please override if needed on each drivers. + * + * @param string $path file cache + * + * @return array + */ + protected function isNameExists($path) + { + list($parentId, $name) = $this->_gd_splitPath($path); + $opts = [ + 'q' => sprintf('trashed=false and "%s" in parents and name="%s"', $parentId, $name), + 'fields' => self::FETCHFIELDS_LIST, + ]; + $srcFile = $this->_gd_query($opts); + + return empty($srcFile) ? false : $this->_gd_parseRaw($srcFile[0]); + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare FTP connection + * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn. + * + * @return bool + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function init() + { + $serviceAccountConfig = ''; + if (empty($this->options['serviceAccountConfigFile'])) { + if (empty($options['client_id'])) { + if (defined('ELFINDER_GOOGLEDRIVE_CLIENTID') && ELFINDER_GOOGLEDRIVE_CLIENTID) { + $this->options['client_id'] = ELFINDER_GOOGLEDRIVE_CLIENTID; + } else { + return $this->setError('Required option "client_id" is undefined.'); + } + } + if (empty($options['client_secret'])) { + if (defined('ELFINDER_GOOGLEDRIVE_CLIENTSECRET') && ELFINDER_GOOGLEDRIVE_CLIENTSECRET) { + $this->options['client_secret'] = ELFINDER_GOOGLEDRIVE_CLIENTSECRET; + } else { + return $this->setError('Required option "client_secret" is undefined.'); + } + } + if (!$this->options['access_token'] && !$this->options['refresh_token']) { + return $this->setError('Required option "access_token" or "refresh_token" is undefined.'); + } + } else { + if (!is_readable($this->options['serviceAccountConfigFile'])) { + return $this->setError('Option "serviceAccountConfigFile" file is not readable.'); + } + $serviceAccountConfig = $this->options['serviceAccountConfigFile']; + } + + try { + if (!$serviceAccountConfig) { + $aTokenFile = ''; + if ($this->options['refresh_token']) { + // permanent mount + $aToken = $this->options['refresh_token']; + $this->options['access_token'] = ''; + $tmp = elFinder::getStaticVar('commonTempPath'); + if (!$tmp) { + $tmp = $this->getTempPath(); + } + if ($tmp) { + $aTokenFile = $tmp . DIRECTORY_SEPARATOR . md5($this->options['client_id'] . $this->options['refresh_token']) . '.gtoken'; + if (is_file($aTokenFile)) { + $this->options['access_token'] = json_decode(file_get_contents($aTokenFile), true); + } + } + } else { + // make net mount key for network mount + if (is_array($this->options['access_token'])) { + $aToken = !empty($this->options['access_token']['refresh_token']) + ? $this->options['access_token']['refresh_token'] + : $this->options['access_token']['access_token']; + } else { + return $this->setError('Required option "access_token" is not Array or empty.'); + } + } + } + + $errors = []; + if ($this->needOnline && !$this->service) { + if (($this->options['googleApiClient'] || defined('ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT')) && !class_exists('Google_Client')) { + include_once $this->options['googleApiClient'] ? $this->options['googleApiClient'] : ELFINDER_GOOGLEDRIVE_GOOGLEAPICLIENT; + } + if (!class_exists('Google_Client')) { + return $this->setError('Class Google_Client not found.'); + } + + $this->client = new \Google_Client(); + + $client = $this->client; + + if (!$serviceAccountConfig) { + if ($this->options['access_token']) { + $client->setAccessToken($this->options['access_token']); + $access_token = $this->options['access_token']; + } + if ($client->isAccessTokenExpired()) { + $client->setClientId($this->options['client_id']); + $client->setClientSecret($this->options['client_secret']); + $access_token = $client->fetchAccessTokenWithRefreshToken($this->options['refresh_token'] ?: null); + $client->setAccessToken($access_token); + if ($aTokenFile) { + file_put_contents($aTokenFile, json_encode($access_token)); + } else { + $access_token['refresh_token'] = $this->options['access_token']['refresh_token']; + } + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'access_token', $access_token); + } + $this->options['access_token'] = $access_token; + } + $this->expires = empty($access_token['refresh_token']) ? $access_token['created'] + $access_token['expires_in'] - 30 : 0; + } else { + $client->setAuthConfigFile($serviceAccountConfig); + $client->setScopes([Google_Service_Drive::DRIVE]); + $aToken = $client->getClientId(); + } + $this->service = new \Google_Service_Drive($client); + } + + if ($this->needOnline) { + $this->netMountKey = md5($aToken . '-' . $this->options['path']); + } + } catch (InvalidArgumentException $e) { + $errors[] = $e->getMessage(); + } catch (Google_Service_Exception $e) { + $errors[] = $e->getMessage(); + } + + if ($this->needOnline && !$this->service) { + $this->session->remove($this->id . $this->netMountKey); + if ($aTokenFile) { + if (is_file($aTokenFile)) { + unlink($aTokenFile); + } + } + $errors[] = 'Google Drive Service could not be loaded.'; + + return $this->setError($errors); + } + + // normalize root path + if ($this->options['path'] == 'root') { + $this->options['path'] = '/'; + } + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + if (empty($this->options['alias'])) { + if ($this->needOnline) { + $this->options['root'] = ($this->options['root'] === '')? $this->_gd_getNameByPath('root') : $this->options['root']; + $this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] : sprintf($this->options['gdAlias'], $this->_gd_getNameByPath($this->options['path'])); + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } else { + $this->options['root'] = ($this->options['root'] === '')? 'GoogleDrive' : $this->options['root']; + $this->options['alias'] = $this->options['root']; + } + } + + $this->rootName = isset($this->options['alias'])? $this->options['alias'] : 'GoogleDrive'; + + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } + } + + if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { + $this->tmp = $tmp; + } + + // This driver dose not support `syncChkAsTs` + $this->options['syncChkAsTs'] = false; + + // 'lsPlSleep' minmum 10 sec + $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']); + + if ($this->options['useGoogleTmb']) { + $this->options['tmbURL'] = 'https://'; + $this->options['tmbPath'] = ''; + } + + // enable command archive + $this->options['useRemoteArchive'] = true; + + return true; + } + + /** + * Configure after successfull mount. + * + * @author Dmitry (dio) Levashov + **/ + protected function configure() + { + parent::configure(); + + // fallback of $this->tmp + if (!$this->tmp && $this->tmbPathWritable) { + $this->tmp = $this->tmbPath; + } + + if ($this->needOnline && $this->isMyReload()) { + $this->_gd_getDirectoryData(false); + } + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection. + * + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + } + + /** + * Cache dir contents. + * + * @param string $path dir path + * + * @return array + * @author Dmitry Levashov + */ + protected function cacheDir($path) + { + $this->dirsCache[$path] = []; + $hasDir = false; + + list(, $pid) = $this->_gd_splitPath($path); + + $opts = [ + 'fields' => self::FETCHFIELDS_LIST, + 'q' => sprintf('trashed=false and "%s" in parents', $pid), + ]; + + $res = $this->_gd_query($opts); + + $mountPath = $this->_normpath($path . '/'); + + if ($res) { + foreach ($res as $raw) { + if ($stat = $this->_gd_parseRaw($raw)) { + $stat = $this->updateCache($mountPath . $raw->id, $stat); + if (empty($stat['hidden']) && $path !== $mountPath . $raw->id) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $mountPath . $raw->id; + } + } + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + + return $this->dirsCache[$path]; + } + + /** + * Recursive files search. + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * + * @return array + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function doSearch($path, $q, $mimes) + { + if (!empty($this->doSearchCurrentQuery['matchMethod'])) { + // has custom match method use elFinderVolumeDriver::doSearch() + return parent::doSearch($path, $q, $mimes); + } + + list(, $itemId) = $this->_gd_splitPath($path); + + $path = $this->_normpath($path . '/'); + $result = []; + $query = ''; + + if ($itemId !== 'root') { + $dirs = array_merge([$itemId], $this->_gd_getDirectories($itemId)); + $query = '(\'' . implode('\' in parents or \'', $dirs) . '\' in parents)'; + } + + $tmp = []; + if (!$mimes) { + foreach (explode(' ', $q) as $_v) { + $tmp[] = 'fullText contains \'' . str_replace('\'', '\\\'', $_v) . '\''; + } + $query .= ($query ? ' and ' : '') . implode(' and ', $tmp); + } else { + foreach ($mimes as $_v) { + $tmp[] = 'mimeType contains \'' . str_replace('\'', '\\\'', $_v) . '\''; + } + $query .= ($query ? ' and ' : '') . '(' . implode(' or ', $tmp) . ')'; + } + + $opts = [ + 'q' => sprintf('trashed=false and (%s)', $query), + ]; + + $res = $this->_gd_query($opts); + + $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; + foreach ($res as $raw) { + if ($timeout && $timeout < time()) { + $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->_path($path)); + break; + } + if ($stat = $this->_gd_parseRaw($raw)) { + if ($parents = $raw->getParents()) { + foreach ($parents as $parent) { + $paths = $this->_gd_getMountPaths($parent); + foreach ($paths as $path) { + $path = ($path === '') ? '/' : (rtrim($path, '/') . '/'); + if (!isset($this->cache[$path . $raw->id])) { + $stat = $this->updateCache($path . $raw->id, $stat); + } else { + $stat = $this->cache[$path . $raw->id]; + } + if (empty($stat['hidden'])) { + $stat['path'] = $this->_path($path) . $stat['name']; + $result[] = $stat; + } + } + } + } + } + } + + return $result; + } + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * + * @return string|false + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + **/ + protected function copy($src, $dst, $name) + { + $this->clearcache(); + $res = $this->_gd_getFile($src); + if ($res['mimeType'] == self::DIRMIME) { + $newDir = $this->_mkdir($dst, $name); + if ($newDir) { + list(, $itemId) = $this->_gd_splitPath($newDir); + list(, $srcId) = $this->_gd_splitPath($src); + $path = $this->_joinPath($dst, $itemId); + $opts = [ + 'q' => sprintf('trashed=false and "%s" in parents', $srcId), + ]; + + $res = $this->_gd_query($opts); + foreach ($res as $raw) { + $raw['mimeType'] == self::DIRMIME ? $this->copy($src . '/' . $raw['id'], $path, $raw['name']) : $this->_copy($src . '/' . $raw['id'], $path, $raw['name']); + } + + $ret = $this->_joinPath($dst, $itemId); + $this->added[] = $this->stat($ret); + } else { + $ret = $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + } else { + if ($itemId = $this->_copy($src, $dst, $name)) { + $ret = $this->_joinPath($dst, $itemId); + $this->added[] = $this->stat($ret); + } else { + $ret = $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + } + return $ret; + } + + /** + * Remove file/ recursive remove dir. + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * @param bool $recursive + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function remove($path, $force = false, $recursive = false) + { + $stat = $this->stat($path); + $stat['realpath'] = $path; + $this->rmTmb($stat); + $this->clearcache(); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path)); + } + + if ($stat['mime'] == 'directory') { + if (!$recursive && !$this->_rmdir($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } else { + if (!$recursive && !$this->_unlink($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } + + $this->removed[] = $stat; + + return true; + } + + /** + * Create thumnbnail and return it's URL on success. + * + * @param string $path file path + * @param $stat + * + * @return string|false + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function createTmb($path, $stat) + { + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name; + + // copy image into tmbPath so some drivers does not store files on local fs + if (!$data = $this->_gd_getThumbnail($path)) { + return false; + } + if (!file_put_contents($tmb, $data)) { + return false; + } + + $result = false; + + $tmbSize = $this->tmbSize; + + if (($s = getimagesize($tmb)) == false) { + return false; + } + + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } else { + if ($this->options['tmbCrop']) { + + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if (($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0; + $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png'); + } + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); + } + + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } + + if (!$result) { + unlink($tmb); + + return false; + } + + return $name; + } + + /** + * Return thumbnail file name for required file. + * + * @param array $stat file stat + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function tmbname($stat) + { + return $this->netMountKey . $stat['iid'] . $stat['ts'] . '.png'; + } + + /** + * Return content URL (for netmout volume driver) + * If file.url == 1 requests from JavaScript client with XHR. + * + * @param string $hash file hash + * @param array $options options array + * + * @return bool|string + * @author Naoki Sawada + */ + public function getContentUrl($hash, $options = []) + { + if (!empty($options['onetime']) && $this->options['onetimeUrl']) { + return parent::getContentUrl($hash, $options); + } + if (!empty($options['temporary'])) { + // try make temporary file + $url = parent::getContentUrl($hash, $options); + if ($url) { + return $url; + } + } + if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) { + $path = $this->decode($hash); + + if ($this->_gd_publish($path)) { + if ($raw = $this->_gd_getFile($path)) { + return $this->_gd_getLink($raw); + } + } + } + + return false; + } + + /** + * Return debug info for client. + * + * @return array + **/ + public function debug() + { + $res = parent::debug(); + if (!empty($this->options['netkey']) && empty($this->options['refresh_token']) && $this->options['access_token'] && isset($this->options['access_token']['refresh_token'])) { + $res['refresh_token'] = $this->options['access_token']['refresh_token']; + } + + return $res; + } + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) + { + list(, , $parent) = $this->_gd_splitPath($path); + + return $this->_normpath($parent); + } + + /** + * Return file name. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) + { + list(, $basename) = $this->_gd_splitPath($path); + + return $basename; + } + + /** + * Join dir name and file name and retur full path. + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + return $this->_normpath($dir . '/' . str_replace('/', '\\/', $name)); + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python. + * + * @param string $path path + * + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) + { + if (DIRECTORY_SEPARATOR !== '/') { + $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); + } + $path = '/' . ltrim($path, '/'); + + return $path; + } + + /** + * Return file path related to root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + return $path; + } + + /** + * Convert path related to root dir into real path. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) + { + return $path; + } + + /** + * Return fake path started from root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) + { + if (!$this->names) { + $this->_gd_getDirectoryData(); + } + $path = $this->_normpath(substr($path, strlen($this->root))); + $names = []; + $paths = explode('/', $path); + foreach ($paths as $_p) { + $names[] = isset($this->names[$_p]) ? $this->names[$_p] : $_p; + } + + return $this->rootName . implode('/', $names); + } + + /** + * Return true if $path is children of $parent. + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) + { + return $path == $parent || strpos($path, $parent . '/') === 0; + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally. + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + if ($raw = $this->_gd_getFile($path)) { + $stat = $this->_gd_parseRaw($raw); + if ($path === $this->root) { + $stat['expires'] = $this->expires; + } + return $stat; + } + + return false; + } + + /** + * Return true if path is dir and has at least one childs directory. + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _subdirs($path) + { + if ($this->directories === null) { + $this->_gd_getDirectoryData(); + } + list(, $itemId) = $this->_gd_splitPath($path); + + return isset($this->directories[$itemId]); + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _dimensions($path, $mime) + { + if (strpos($mime, 'image') !== 0) { + return ''; + } + $ret = ''; + + if ($file = $this->_gd_getFile($path)) { + if (isset($file['imageMediaMetadata'])) { + $ret = array('dim' => $file['imageMediaMetadata']['width'] . 'x' . $file['imageMediaMetadata']['height']); + if (func_num_args() > 2) { + $args = func_get_arg(2); + } else { + $args = array(); + } + if (!empty($args['substitute'])) { + $tmbSize = intval($args['substitute']); + $srcSize = explode('x', $ret['dim']); + if ($srcSize[0] && $srcSize[1]) { + if (min(($tmbSize / $srcSize[0]), ($tmbSize / $srcSize[1])) < 1) { + if ($this->_gd_isPublished($file)) { + $tmbSize = strval($tmbSize); + $ret['url'] = 'https://drive.google.com/thumbnail?authuser=0&sz=s' . $tmbSize . '&id=' . $file['id']; + } elseif ($subImgLink = $this->getSubstituteImgLink(elFinder::$currentArgs['target'], $srcSize)) { + $ret['url'] = $subImgLink; + } + } + } + } + } + } + + return $ret; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function _scandir($path) + { + return isset($this->dirsCache[$path]) + ? $this->dirsCache[$path] + : $this->cacheDir($path); + } + + /** + * Open file and return file pointer. + * + * @param string $path file path + * @param bool $write open file for writing + * + * @return resource|false + * @author Dmitry (dio) Levashov + **/ + protected function _fopen($path, $mode = 'rb') + { + if ($mode === 'rb' || $mode === 'r') { + if ($file = $this->_gd_getFile($path)) { + if ($dlurl = $this->_gd_getDownloadUrl($file)) { + $token = $this->client->getAccessToken(); + if (!$token && $this->client->isUsingApplicationDefaultCredentials()) { + $this->client->fetchAccessTokenWithAssertion(); + $token = $this->client->getAccessToken(); + } + $access_token = ''; + if (is_array($token)) { + $access_token = $token['access_token']; + } else { + if ($token = json_decode($this->client->getAccessToken())) { + $access_token = $token->access_token; + } + } + if ($access_token) { + $data = array( + 'target' => $dlurl, + 'headers' => array('Authorization: Bearer ' . $access_token), + ); + + // to support range request + if (func_num_args() > 2) { + $opts = func_get_arg(2); + } else { + $opts = array(); + } + if (!empty($opts['httpheaders'])) { + $data['headers'] = array_merge($opts['httpheaders'], $data['headers']); + } + + return elFinder::getStreamByUrl($data); + } + } + } + } + + return false; + } + + /** + * Close opened file. + * + * @param resource $fp file pointer + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + if ($path) { + unlink($this->getTempFile($path)); + } + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed. + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + $path = $this->_joinPath($path, $name); + list($parentId, , $parent) = $this->_gd_splitPath($path); + + try { + $file = new \Google_Service_Drive_DriveFile(); + + $file->setName($name); + $file->setMimeType(self::DIRMIME); + $file->setParents([$parentId]); + + //create the Folder in the Parent + $obj = $this->service->files->create($file); + + if ($obj instanceof Google_Service_Drive_DriveFile) { + $path = $this->_joinPath($parent, $obj['id']); + $this->_gd_getDirectoryData(false); + + return $path; + } else { + return false; + } + } catch (Exception $e) { + return $this->setError('GoogleDrive error: ' . $e->getMessage()); + } + } + + /** + * Create file and return it's path or false on failed. + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) + { + return $this->_save($this->tmpfile(), $path, $name, []); + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _symlink($target, $path, $name) + { + return false; + } + + /** + * Copy file into another file. + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) + { + $source = $this->_normpath($source); + $targetDir = $this->_normpath($targetDir); + + try { + $file = new \Google_Service_Drive_DriveFile(); + $file->setName($name); + + //Set the Parent id + list(, $parentId) = $this->_gd_splitPath($targetDir); + $file->setParents([$parentId]); + + list(, $srcId) = $this->_gd_splitPath($source); + $file = $this->service->files->copy($srcId, $file, ['fields' => self::FETCHFIELDS_GET]); + $itemId = $file->id; + + return $itemId; + } catch (Exception $e) { + return $this->setError('GoogleDrive error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param string $target target dir path + * @param string $name file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _move($source, $targetDir, $name) + { + list($removeParents, $itemId) = $this->_gd_splitPath($source); + $target = $this->_normpath($targetDir . '/' . $itemId); + try { + //moving and renaming a file or directory + $files = new \Google_Service_Drive_DriveFile(); + $files->setName($name); + + //Set new Parent and remove old parent + list(, $addParents) = $this->_gd_splitPath($targetDir); + $opts = ['addParents' => $addParents, 'removeParents' => $removeParents]; + + $file = $this->service->files->update($itemId, $files, $opts); + + if ($file->getMimeType() === self::DIRMIME) { + $this->_gd_getDirectoryData(false); + } + } catch (Exception $e) { + return $this->setError('GoogleDrive error: ' . $e->getMessage()); + } + + return $target; + } + + /** + * Remove file. + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + try { + $files = new \Google_Service_Drive_DriveFile(); + $files->setTrashed(true); + + list($pid, $itemId) = $this->_gd_splitPath($path); + $opts = ['removeParents' => $pid]; + $this->service->files->update($itemId, $files, $opts); + } catch (Exception $e) { + return $this->setError('GoogleDrive error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Remove dir. + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + $res = $this->_unlink($path); + $res && $this->_gd_getDirectoryData(false); + + return $res; + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param $path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + */ + protected function _save($fp, $path, $name, $stat) + { + if ($name !== '') { + $path .= '/' . str_replace('/', '\\/', $name); + } + list($parentId, $itemId, $parent) = $this->_gd_splitPath($path); + if ($name === '') { + $stat['iid'] = $itemId; + } + + if (!$stat || empty($stat['iid'])) { + $opts = [ + 'q' => sprintf('trashed=false and "%s" in parents and name="%s"', $parentId, $name), + 'fields' => self::FETCHFIELDS_LIST, + ]; + $srcFile = $this->_gd_query($opts); + $srcFile = empty($srcFile) ? null : $srcFile[0]; + } else { + $srcFile = $this->_gd_getFile($path); + } + + try { + $mode = 'update'; + $mime = isset($stat['mime']) ? $stat['mime'] : ''; + + $file = new Google_Service_Drive_DriveFile(); + if ($srcFile) { + $mime = $srcFile->getMimeType(); + } else { + $mode = 'insert'; + $file->setName($name); + $file->setParents([ + $parentId, + ]); + } + + if (!$mime) { + $mime = self::mimetypeInternalDetect($name); + } + if ($mime === 'unknown') { + $mime = 'application/octet-stream'; + } + $file->setMimeType($mime); + + $size = 0; + if (isset($stat['size'])) { + $size = $stat['size']; + } else { + $fstat = fstat($fp); + if (!empty($fstat['size'])) { + $size = $fstat['size']; + } + } + + // set chunk size (max: 100MB) + $chunkSizeBytes = 100 * 1024 * 1024; + if ($size > 0) { + $memory = elFinder::getIniBytes('memory_limit'); + if ($memory > 0) { + $chunkSizeBytes = max(262144, min([$chunkSizeBytes, (intval($memory / 4 / 256) * 256)])); + } + } + + if ($size > $chunkSizeBytes) { + $client = $this->client; + // Call the API with the media upload, defer so it doesn't immediately return. + $client->setDefer(true); + if ($mode === 'insert') { + $request = $this->service->files->create($file, [ + 'fields' => self::FETCHFIELDS_GET, + ]); + } else { + $request = $this->service->files->update($srcFile->getId(), $file, [ + 'fields' => self::FETCHFIELDS_GET, + ]); + } + + // Create a media file upload to represent our upload process. + $media = new Google_Http_MediaFileUpload($client, $request, $mime, null, true, $chunkSizeBytes); + $media->setFileSize($size); + // Upload the various chunks. $status will be false until the process is + // complete. + $status = false; + while (!$status && !feof($fp)) { + elFinder::checkAborted(); + // read until you get $chunkSizeBytes from TESTFILE + // fread will never return more than 8192 bytes if the stream is read buffered and it does not represent a plain file + // An example of a read buffered file is when reading from a URL + $chunk = $this->_gd_readFileChunk($fp, $chunkSizeBytes); + $status = $media->nextChunk($chunk); + } + // The final value of $status will be the data from the API for the object + // that has been uploaded. + if ($status !== false) { + $obj = $status; + } + + $client->setDefer(false); + } else { + $params = [ + 'data' => stream_get_contents($fp), + 'uploadType' => 'media', + 'fields' => self::FETCHFIELDS_GET, + ]; + if ($mode === 'insert') { + $obj = $this->service->files->create($file, $params); + } else { + $obj = $this->service->files->update($srcFile->getId(), $file, $params); + } + } + if ($obj instanceof Google_Service_Drive_DriveFile) { + return $this->_joinPath($parent, $obj->getId()); + } else { + return false; + } + } catch (Exception $e) { + return $this->setError('GoogleDrive error: ' . $e->getMessage()); + } + } + + /** + * Get file contents. + * + * @param string $path file path + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) + { + $contents = ''; + + try { + list(, $itemId) = $this->_gd_splitPath($path); + + $contents = $this->service->files->get($itemId, [ + 'alt' => 'media', + ]); + $contents = (string)$contents->getBody(); + } catch (Exception $e) { + return $this->setError('GoogleDrive error: ' . $e->getMessage()); + } + + return $contents; + } + + /** + * Write a string to a file. + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + $res = false; + + if ($local = $this->getTempFile($path)) { + if (file_put_contents($local, $content, LOCK_EX) !== false + && ($fp = fopen($local, 'rb'))) { + clearstatcache(); + $res = $this->_save($fp, $path, '', []); + fclose($fp); + } + file_exists($local) && unlink($local); + } + + return $res; + } + + /** + * Detect available archivers. + **/ + protected function _checkArchivers() + { + // die('Not yet implemented. (_checkArchivers)'); + return []; + } + + /** + * chmod implementation. + * + * @return bool + **/ + protected function _chmod($path, $mode) + { + return false; + } + + /** + * Unpack archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return void + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + protected function _unpack($path, $arc) + { + die('Not yet implemented. (_unpack)'); + //return false; + } + + /** + * Extract files from archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return void + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _extract($path, $arc) + { + die('Not yet implemented. (_extract)'); + } + + /** + * Create archive and return its path. + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) + { + die('Not yet implemented. (_archive)'); + } +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeGroup.class.php b/lib/redactor/elfinder/php/elFinderVolumeGroup.class.php new file mode 100644 index 0000000..38e7e54 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeGroup.class.php @@ -0,0 +1,315 @@ +options['type'] = 'group'; + $this->options['path'] = '/'; + $this->options['dirUrlOwn'] = true; + $this->options['syncMinMs'] = 0; + $this->options['tmbPath'] = ''; + $this->options['disabled'] = array( + 'archive', + 'copy', + 'cut', + 'duplicate', + 'edit', + 'empty', + 'extract', + 'getfile', + 'mkdir', + 'mkfile', + 'paste', + 'resize', + 'rm', + 'upload' + ); + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /*********************** paths/urls *************************/ + + /** + * @inheritdoc + **/ + protected function _dirname($path) + { + return '/'; + } + + /** + * {@inheritDoc} + **/ + protected function _basename($path) + { + return ''; + } + + /** + * {@inheritDoc} + **/ + protected function _joinPath($dir, $name) + { + return '/' . $name; + } + + /** + * {@inheritDoc} + **/ + protected function _normpath($path) + { + return '/'; + } + + /** + * {@inheritDoc} + **/ + protected function _relpath($path) + { + return '/'; + } + + /** + * {@inheritDoc} + **/ + protected function _abspath($path) + { + return '/'; + } + + /** + * {@inheritDoc} + **/ + protected function _path($path) + { + return '/'; + } + + /** + * {@inheritDoc} + **/ + protected function _inpath($path, $parent) + { + return false; + } + + + + /***************** file stat ********************/ + + /** + * {@inheritDoc} + **/ + protected function _stat($path) + { + if ($path === '/') { + return array( + 'size' => 0, + 'ts' => 0, + 'mime' => 'directory', + 'read' => true, + 'write' => false, + 'locked' => true, + 'hidden' => false, + 'dirs' => 0 + ); + } + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _subdirs($path) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _dimensions($path, $mime) + { + return false; + } + /******************** file/dir content *********************/ + + /** + * {@inheritDoc} + **/ + protected function readlink($path) + { + return null; + } + + /** + * {@inheritDoc} + **/ + protected function _scandir($path) + { + return array(); + } + + /** + * {@inheritDoc} + **/ + protected function _fopen($path, $mode = 'rb') + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _fclose($fp, $path = '') + { + return true; + } + + /******************** file/dir manipulations *************************/ + + /** + * {@inheritDoc} + **/ + protected function _mkdir($path, $name) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _mkfile($path, $name) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _symlink($source, $targetDir, $name) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _copy($source, $targetDir, $name) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _move($source, $targetDir, $name) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _unlink($path) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _rmdir($path) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _save($fp, $dir, $name, $stat) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _getContents($path) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _filePutContents($path, $content) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _checkArchivers() + { + return; + } + + /** + * {@inheritDoc} + **/ + protected function _chmod($path, $mode) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _findSymlinks($path) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _extract($path, $arc) + { + return false; + } + + /** + * {@inheritDoc} + **/ + protected function _archive($dir, $files, $name, $arc) + { + return false; + } +} + diff --git a/lib/redactor/elfinder/php/elFinderVolumeLocalFileSystem.class.php b/lib/redactor/elfinder/php/elFinderVolumeLocalFileSystem.class.php new file mode 100644 index 0000000..0c29745 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeLocalFileSystem.class.php @@ -0,0 +1,1483 @@ +callback = $callback; + parent::__construct($iterator); + } + + public function accept() + { + return call_user_func($this->callback, parent::current(), parent::key(), parent::getInnerIterator()); + } + + public function getChildren() + { + return new self($this->getInnerIterator()->getChildren(), $this->callback); + } + } +} + +/** + * elFinder driver for local filesystem. + * + * @author Dmitry (dio) Levashov + * @author Troex Nevelin + **/ +class elFinderVolumeLocalFileSystem extends elFinderVolumeDriver +{ + + /** + * Driver id + * Must be started from letter and contains [a-z0-9] + * Used as part of volume id + * + * @var string + **/ + protected $driverId = 'l'; + + /** + * Required to count total archive files size + * + * @var int + **/ + protected $archiveSize = 0; + + /** + * Is checking stat owner + * + * @var boolean + */ + protected $statOwner = false; + + /** + * Path to quarantine directory + * + * @var string + */ + private $quarantine; + + /** + * Constructor + * Extend options with required fields + * + * @author Dmitry (dio) Levashov + */ + public function __construct() + { + $this->options['alias'] = ''; // alias to replace root dir name + $this->options['dirMode'] = 0755; // new dirs mode + $this->options['fileMode'] = 0644; // new files mode + $this->options['rootCssClass'] = 'elfinder-navbar-root-local'; + $this->options['followSymLinks'] = true; + $this->options['detectDirIcon'] = ''; // file name that is detected as a folder icon e.g. '.diricon.png' + $this->options['keepTimestamp'] = array('copy', 'move'); // keep timestamp at inner filesystem allowed 'copy', 'move' and 'upload' + $this->options['substituteImg'] = true; // support substitute image with dim command + $this->options['statCorrector'] = null; // callable to correct stat data `function(&$stat, $path, $statOwner, $volumeDriveInstance){}` + if (DIRECTORY_SEPARATOR === '/') { + // Linux + $this->options['acceptedName'] = '/^[^\.\/\x00][^\/\x00]*$/'; + } else { + // Windows + $this->options['acceptedName'] = '/^[^\.\/\x00\\\:*?"<>|][^\/\x00\\\:*?"<>|]*$/'; + } + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare driver before mount volume. + * Return true if volume is ready. + * + * @return bool + **/ + protected function init() + { + // Normalize directory separator for windows + if (DIRECTORY_SEPARATOR !== '/') { + foreach (array('path', 'tmbPath', 'tmpPath', 'quarantine') as $key) { + if (!empty($this->options[$key])) { + $this->options[$key] = str_replace('/', DIRECTORY_SEPARATOR, $this->options[$key]); + } + } + // PHP >= 7.1 Supports UTF-8 path on Windows + if (version_compare(PHP_VERSION, '7.1', '>=')) { + $this->options['encoding'] = ''; + $this->options['locale'] = ''; + } + } + if (!$cwd = getcwd()) { + return $this->setError('elFinder LocalVolumeDriver requires a result of getcwd().'); + } + // detect systemRoot + if (!isset($this->options['systemRoot'])) { + if ($cwd[0] === DIRECTORY_SEPARATOR || $this->root[0] === DIRECTORY_SEPARATOR) { + $this->systemRoot = DIRECTORY_SEPARATOR; + } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $this->root, $m)) { + $this->systemRoot = $m[1]; + } else if (preg_match('/^([a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . ')/', $cwd, $m)) { + $this->systemRoot = $m[1]; + } + } + $this->root = $this->getFullPath($this->root, $cwd); + if (!empty($this->options['startPath'])) { + $this->options['startPath'] = $this->getFullPath($this->options['startPath'], $this->root); + } + + if (is_null($this->options['syncChkAsTs'])) { + $this->options['syncChkAsTs'] = true; + } + if (is_null($this->options['syncCheckFunc'])) { + $this->options['syncCheckFunc'] = array($this, 'localFileSystemInotify'); + } + // check 'statCorrector' + if (empty($this->options['statCorrector']) || !is_callable($this->options['statCorrector'])) { + $this->options['statCorrector'] = null; + } + + return true; + } + + /** + * Configure after successfull mount. + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function configure() + { + $hiddens = array(); + $root = $this->stat($this->root); + + // check thumbnails path + if (!empty($this->options['tmbPath'])) { + if (strpos($this->options['tmbPath'], DIRECTORY_SEPARATOR) === false) { + $hiddens['tmb'] = $this->options['tmbPath']; + $this->options['tmbPath'] = $this->_abspath($this->options['tmbPath']); + } else { + $this->options['tmbPath'] = $this->_normpath($this->options['tmbPath']); + } + } + // check temp path + if (!empty($this->options['tmpPath'])) { + if (strpos($this->options['tmpPath'], DIRECTORY_SEPARATOR) === false) { + $hiddens['temp'] = $this->options['tmpPath']; + $this->options['tmpPath'] = $this->_abspath($this->options['tmpPath']); + } else { + $this->options['tmpPath'] = $this->_normpath($this->options['tmpPath']); + } + } + // check quarantine path + $_quarantine = ''; + if (!empty($this->options['quarantine'])) { + if (strpos($this->options['quarantine'], DIRECTORY_SEPARATOR) === false) { + //$hiddens['quarantine'] = $this->options['quarantine']; + //$this->options['quarantine'] = $this->_abspath($this->options['quarantine']); + $_quarantine = $this->_abspath($this->options['quarantine']); + $this->options['quarantine'] = ''; + } else { + $this->options['quarantine'] = $this->_normpath($this->options['quarantine']); + } + } else { + $_quarantine = $this->_abspath('.quarantine'); + } + is_dir($_quarantine) && self::localRmdirRecursive($_quarantine); + + parent::configure(); + + // check tmbPath + if (!$this->tmbPath && isset($hiddens['tmb'])) { + unset($hiddens['tmb']); + } + + // if no thumbnails url - try detect it + if ($root['read'] && !$this->tmbURL && $this->URL) { + if (strpos($this->tmbPath, $this->root) === 0) { + $this->tmbURL = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($this->tmbPath, strlen($this->root) + 1)); + if (preg_match("|[^/?&=]$|", $this->tmbURL)) { + $this->tmbURL .= '/'; + } + } + } + + // set $this->tmp by options['tmpPath'] + $this->tmp = ''; + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'], $this->options['dirMode'], true)) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } else { + if (isset($hiddens['temp'])) { + unset($hiddens['temp']); + } + } + } + if (!$this->tmp && ($tmp = elFinder::getStaticVar('commonTempPath'))) { + $this->tmp = $tmp; + } + + // check quarantine dir + $this->quarantine = ''; + if (!empty($this->options['quarantine'])) { + if ((is_dir($this->options['quarantine']) || mkdir($this->options['quarantine'], $this->options['dirMode'], true)) && is_writable($this->options['quarantine'])) { + $this->quarantine = $this->options['quarantine']; + } else { + if (isset($hiddens['quarantine'])) { + unset($hiddens['quarantine']); + } + } + } else if ($_path = elFinder::getCommonTempPath()) { + $this->quarantine = $_path; + } + + if (!$this->quarantine) { + if (!$this->tmp) { + $this->archivers['extract'] = array(); + $this->disabled[] = 'extract'; + } else { + $this->quarantine = $this->tmp; + } + } + + if ($hiddens) { + foreach ($hiddens as $hidden) { + $this->attributes[] = array( + 'pattern' => '~^' . preg_quote(DIRECTORY_SEPARATOR . $hidden, '~') . '$~', + 'read' => false, + 'write' => false, + 'locked' => true, + 'hidden' => true + ); + } + } + + if (!empty($this->options['keepTimestamp'])) { + $this->options['keepTimestamp'] = array_flip($this->options['keepTimestamp']); + } + + $this->statOwner = (!empty($this->options['statOwner'])); + + // enable WinRemoveTailDots plugin on Windows server + if (DIRECTORY_SEPARATOR !== '/') { + if (!isset($this->options['plugin'])) { + $this->options['plugin'] = array(); + } + $this->options['plugin']['WinRemoveTailDots'] = array('enable' => true); + } + } + + /** + * Long pooling sync checker + * This function require server command `inotifywait` + * If `inotifywait` need full path, Please add `define('ELFINER_INOTIFYWAIT_PATH', '/PATH_TO/inotifywait');` into connector.php + * + * @param string $path + * @param int $standby + * @param number $compare + * + * @return number|bool + * @throws elFinderAbortException + */ + public function localFileSystemInotify($path, $standby, $compare) + { + if (isset($this->sessionCache['localFileSystemInotify_disable'])) { + return false; + } + $path = realpath($path); + $mtime = filemtime($path); + if (!$mtime) { + return false; + } + if ($mtime != $compare) { + return $mtime; + } + $inotifywait = defined('ELFINER_INOTIFYWAIT_PATH') ? ELFINER_INOTIFYWAIT_PATH : 'inotifywait'; + $standby = max(1, intval($standby)); + $cmd = $inotifywait . ' ' . escapeshellarg($path) . ' -t ' . $standby . ' -e moved_to,moved_from,move,close_write,delete,delete_self'; + $this->procExec($cmd, $o, $r); + if ($r === 0) { + // changed + clearstatcache(); + if (file_exists($path)) { + $mtime = filemtime($path); // error on busy? + return $mtime ? $mtime : time(); + } else { + // target was removed + return 0; + } + } else if ($r === 2) { + // not changed (timeout) + return $compare; + } + // error + // cache to $_SESSION + $this->sessionCache['localFileSystemInotify_disable'] = true; + $this->session->set($this->id, $this->sessionCache); + return false; + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) + { + return dirname($path); + } + + /** + * Return file name + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) + { + return basename($path); + } + + /** + * Join dir name and file name and retur full path + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + $dir = rtrim($dir, DIRECTORY_SEPARATOR); + $path = realpath($dir . DIRECTORY_SEPARATOR . $name); + // realpath() returns FALSE if the file does not exist + if ($path === false || strpos($path, $this->root) !== 0) { + if (DIRECTORY_SEPARATOR !== '/') { + $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir); + $name = str_replace('/', DIRECTORY_SEPARATOR, $name); + } + // Directory traversal measures + if (strpos($dir, '..' . DIRECTORY_SEPARATOR) !== false || substr($dir, -2) == '..') { + $dir = $this->root; + } + if (strpos($name, '..' . DIRECTORY_SEPARATOR) !== false) { + $name = basename($name); + } + $path = $dir . DIRECTORY_SEPARATOR . $name; + } + return $path; + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python + * + * @param string $path path + * + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) + { + if (empty($path)) { + return '.'; + } + + $changeSep = (DIRECTORY_SEPARATOR !== '/'); + if ($changeSep) { + $drive = ''; + if (preg_match('/^([a-zA-Z]:)(.*)/', $path, $m)) { + $drive = $m[1]; + $path = $m[2] ? $m[2] : '/'; + } + $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); + } + + if (strpos($path, '/') === 0) { + $initial_slashes = true; + } else { + $initial_slashes = false; + } + + if (($initial_slashes) + && (strpos($path, '//') === 0) + && (strpos($path, '///') === false)) { + $initial_slashes = 2; + } + + $initial_slashes = (int)$initial_slashes; + + $comps = explode('/', $path); + $new_comps = array(); + foreach ($comps as $comp) { + if (in_array($comp, array('', '.'))) { + continue; + } + + if (($comp != '..') + || (!$initial_slashes && !$new_comps) + || ($new_comps && (end($new_comps) == '..'))) { + array_push($new_comps, $comp); + } elseif ($new_comps) { + array_pop($new_comps); + } + } + $comps = $new_comps; + $path = implode('/', $comps); + if ($initial_slashes) { + $path = str_repeat('/', $initial_slashes) . $path; + } + + if ($changeSep) { + $path = $drive . str_replace('/', DIRECTORY_SEPARATOR, $path); + } + + return $path ? $path : '.'; + } + + /** + * Return file path related to root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + if ($path === $this->root) { + return ''; + } else { + if (strpos($path, $this->root) === 0) { + return ltrim(substr($path, strlen($this->root)), DIRECTORY_SEPARATOR); + } else { + // for link + return $path; + } + } + } + + /** + * Convert path related to root dir into real path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) + { + if ($path === DIRECTORY_SEPARATOR) { + return $this->root; + } else { + $path = $this->_normpath($path); + if (strpos($path, $this->systemRoot) === 0) { + return $path; + } else if (DIRECTORY_SEPARATOR !== '/' && preg_match('/^[a-zA-Z]:' . preg_quote(DIRECTORY_SEPARATOR, '/') . '/', $path)) { + return $path; + } else { + return $this->_joinPath($this->root, $path); + } + } + } + + /** + * Return fake path started from root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) + { + return $this->rootName . ($path == $this->root ? '' : $this->separator . $this->_relpath($path)); + } + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) + { + $cwd = getcwd(); + $real_path = $this->getFullPath($path, $cwd); + $real_parent = $this->getFullPath($parent, $cwd); + if ($real_path && $real_parent) { + return $real_path === $real_parent || strpos($real_path, rtrim($real_parent, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR) === 0; + } + return false; + } + + + + /***************** file stat ********************/ + + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + $stat = array(); + + if (!file_exists($path) && !is_link($path)) { + return $stat; + } + + //Verifies the given path is the root or is inside the root. Prevents directory traveral. + if (!$this->_inpath($path, $this->root)) { + return $stat; + } + + $stat['isowner'] = false; + $linkreadable = false; + if ($path != $this->root && is_link($path)) { + if (!$this->options['followSymLinks']) { + return array(); + } + if (!($target = $this->readlink($path)) + || $target == $path) { + if (is_null($target)) { + $stat = array(); + return $stat; + } else { + $stat['mime'] = 'symlink-broken'; + $target = readlink($path); + $lstat = lstat($path); + $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']); + $linkreadable = !empty($ostat['isowner']); + } + } + $stat['alias'] = $this->_path($target); + $stat['target'] = $target; + } + + $readable = is_readable($path); + + if ($readable) { + $size = sprintf('%u', filesize($path)); + $stat['ts'] = filemtime($path); + if ($this->statOwner) { + $fstat = stat($path); + $uid = $fstat['uid']; + $gid = $fstat['gid']; + $stat['perm'] = substr((string)decoct($fstat['mode']), -4); + $stat = array_merge($stat, $this->getOwnerStat($uid, $gid)); + } + } + + if (($dir = is_dir($path)) && $this->options['detectDirIcon']) { + $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon']; + if ($this->URL && file_exists($favicon)) { + $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1)); + } + } + + if (!isset($stat['mime'])) { + $stat['mime'] = $dir ? 'directory' : $this->mimetype($path); + } + //logical rights first + $stat['read'] = ($linkreadable || $readable) ? null : false; + $stat['write'] = is_writable($path) ? null : false; + + if (is_null($stat['read'])) { + if ($dir) { + $stat['size'] = 0; + } else if (isset($size)) { + $stat['size'] = $size; + } + } + + if ($this->options['statCorrector']) { + call_user_func_array($this->options['statCorrector'], array(&$stat, $path, $this->statOwner, $this)); + } + + return $stat; + } + + /** + * Get stat `owner`, `group` and `isowner` by `uid` and `gid` + * Sub-fuction of _stat() and _scandir() + * + * @param integer $uid + * @param integer $gid + * + * @return array stat + */ + protected function getOwnerStat($uid, $gid) + { + static $names = null; + static $phpuid = null; + + if (is_null($names)) { + $names = array('uid' => array(), 'gid' => array()); + } + if (is_null($phpuid)) { + if (is_callable('posix_getuid')) { + $phpuid = posix_getuid(); + } else { + $phpuid = 0; + } + } + + $stat = array(); + + if ($uid) { + $stat['isowner'] = ($phpuid == $uid); + if (isset($names['uid'][$uid])) { + $stat['owner'] = $names['uid'][$uid]; + } else if (is_callable('posix_getpwuid')) { + $pwuid = posix_getpwuid($uid); + $stat['owner'] = $names['uid'][$uid] = $pwuid['name']; + } else { + $stat['owner'] = $names['uid'][$uid] = $uid; + } + } + if ($gid) { + if (isset($names['gid'][$gid])) { + $stat['group'] = $names['gid'][$gid]; + } else if (is_callable('posix_getgrgid')) { + $grgid = posix_getgrgid($gid); + $stat['group'] = $names['gid'][$gid] = $grgid['name']; + } else { + $stat['group'] = $names['gid'][$gid] = $gid; + } + } + + return $stat; + } + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _subdirs($path) + { + + $dirs = false; + if (is_dir($path) && is_readable($path)) { + if (class_exists('FilesystemIterator', false)) { + $dirItr = new ParentIterator( + new RecursiveDirectoryIterator($path, + FilesystemIterator::SKIP_DOTS | + FilesystemIterator::CURRENT_AS_SELF | + (defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') ? + RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0) + ) + ); + $dirItr->rewind(); + if ($dirItr->hasChildren()) { + $dirs = true; + $name = $dirItr->getSubPathName(); + while ($dirItr->valid()) { + if (!$this->attr($path . DIRECTORY_SEPARATOR . $name, 'read', null, true)) { + $dirs = false; + $dirItr->next(); + $name = $dirItr->getSubPathName(); + continue; + } + $dirs = true; + break; + } + } + } else { + $path = strtr($path, array('[' => '\\[', ']' => '\\]', '*' => '\\*', '?' => '\\?')); + return (bool)glob(rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '*', GLOB_ONLYDIR); + } + } + return $dirs; + } + + /** + * Return object width and height + * Usualy used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dimensions($path, $mime) + { + clearstatcache(); + return strpos($mime, 'image') === 0 && is_readable($path) && filesize($path) && ($s = getimagesize($path)) !== false + ? $s[0] . 'x' . $s[1] + : false; + } + /******************** file/dir content *********************/ + + /** + * Return symlink target file + * + * @param string $path link path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function readlink($path) + { + if (!($target = readlink($path))) { + return null; + } + + if (strpos($target, $this->systemRoot) !== 0) { + $target = $this->_joinPath(dirname($path), $target); + } + + if (!file_exists($target)) { + return false; + } + + return $target; + } + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _scandir($path) + { + elFinder::checkAborted(); + $files = array(); + $cache = array(); + $dirWritable = is_writable($path); + $dirItr = array(); + $followSymLinks = $this->options['followSymLinks']; + try { + $dirItr = new DirectoryIterator($path); + } catch (UnexpectedValueException $e) { + } + + foreach ($dirItr as $file) { + try { + if ($file->isDot()) { + continue; + } + + $files[] = $fpath = $file->getPathname(); + + $br = false; + $stat = array(); + + $stat['isowner'] = false; + $linkreadable = false; + if ($file->isLink()) { + if (!$followSymLinks) { + continue; + } + if (!($target = $this->readlink($fpath)) + || $target == $fpath) { + if (is_null($target)) { + $stat = array(); + $br = true; + } else { + $_path = $fpath; + $stat['mime'] = 'symlink-broken'; + $target = readlink($_path); + $lstat = lstat($_path); + $ostat = $this->getOwnerStat($lstat['uid'], $lstat['gid']); + $linkreadable = !empty($ostat['isowner']); + $dir = false; + $stat['alias'] = $this->_path($target); + $stat['target'] = $target; + } + } else { + $dir = is_dir($target); + $stat['alias'] = $this->_path($target); + $stat['target'] = $target; + $stat['mime'] = $dir ? 'directory' : $this->mimetype($stat['alias']); + } + } else { + if (($dir = $file->isDir()) && $this->options['detectDirIcon']) { + $path = $file->getPathname(); + $favicon = $path . DIRECTORY_SEPARATOR . $this->options['detectDirIcon']; + if ($this->URL && file_exists($favicon)) { + $stat['icon'] = $this->URL . str_replace(DIRECTORY_SEPARATOR, '/', substr($favicon, strlen($this->root) + 1)); + } + } + $stat['mime'] = $dir ? 'directory' : $this->mimetype($fpath); + } + $size = sprintf('%u', $file->getSize()); + $stat['ts'] = $file->getMTime(); + if (!$br) { + if ($this->statOwner && !$linkreadable) { + $uid = $file->getOwner(); + $gid = $file->getGroup(); + $stat['perm'] = substr((string)decoct($file->getPerms()), -4); + $stat = array_merge($stat, $this->getOwnerStat($uid, $gid)); + } + + //logical rights first + $stat['read'] = ($linkreadable || $file->isReadable()) ? null : false; + $stat['write'] = $file->isWritable() ? null : false; + $stat['locked'] = $dirWritable ? null : true; + + if (is_null($stat['read'])) { + $stat['size'] = $dir ? 0 : $size; + } + + if ($this->options['statCorrector']) { + call_user_func_array($this->options['statCorrector'], array(&$stat, $fpath, $this->statOwner, $this)); + } + } + + $cache[] = array($fpath, $stat); + } catch (RuntimeException $e) { + continue; + } + } + + if ($cache) { + $cache = $this->convEncOut($cache, false); + foreach ($cache as $d) { + $this->updateCache($d[0], $d[1]); + } + } + + return $files; + } + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param string $mode + * + * @return false|resource + * @internal param bool $write open file for writing + * @author Dmitry (dio) Levashov + */ + protected function _fopen($path, $mode = 'rb') + { + return fopen($path, $mode); + } + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path + * + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function _fclose($fp, $path = '') + { + return (is_resource($fp) && fclose($fp)); + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + $path = $this->_joinPath($path, $name); + + if (mkdir($path)) { + chmod($path, $this->options['dirMode']); + return $path; + } + + return false; + } + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) + { + $path = $this->_joinPath($path, $name); + + if (($fp = fopen($path, 'w'))) { + fclose($fp); + chmod($path, $this->options['fileMode']); + return $path; + } + return false; + } + + /** + * Create symlink + * + * @param string $source file to link to + * @param string $targetDir folder to create link in + * @param string $name symlink name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _symlink($source, $targetDir, $name) + { + return $this->localFileSystemSymlink($source, $this->_joinPath($targetDir, $name)); + } + + /** + * Copy file into another file + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) + { + $mtime = filemtime($source); + $target = $this->_joinPath($targetDir, $name); + if ($ret = copy($source, $target)) { + isset($this->options['keepTimestamp']['copy']) && $mtime && touch($target, $mtime); + } + return $ret; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + protected function _move($source, $targetDir, $name) + { + $mtime = filemtime($source); + $target = $this->_joinPath($targetDir, $name); + if ($ret = rename($source, $target) ? $target : false) { + isset($this->options['keepTimestamp']['move']) && $mtime && touch($target, $mtime); + } + return $ret; + } + + /** + * Remove file + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + return is_file($path) && unlink($path); + } + + /** + * Remove dir + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + return rmdir($path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + protected function _save($fp, $dir, $name, $stat) + { + $path = $this->_joinPath($dir, $name); + + $meta = stream_get_meta_data($fp); + $uri = isset($meta['uri']) ? $meta['uri'] : ''; + if ($uri && !preg_match('#^[a-zA-Z0-9]+://#', $uri) && !is_link($uri)) { + fclose($fp); + $mtime = filemtime($uri); + $isCmdPaste = ($this->ARGS['cmd'] === 'paste'); + $isCmdCopy = ($isCmdPaste && empty($this->ARGS['cut'])); + if (($isCmdCopy || !rename($uri, $path)) && !copy($uri, $path)) { + return false; + } + // keep timestamp on upload + if ($mtime && $this->ARGS['cmd'] === 'upload') { + touch($path, isset($this->options['keepTimestamp']['upload']) ? $mtime : time()); + } + } else { + if (file_put_contents($path, $fp, LOCK_EX) === false) { + return false; + } + } + + chmod($path, $this->options['fileMode']); + return $path; + } + + /** + * Get file contents + * + * @param string $path file path + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) + { + return file_get_contents($path); + } + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + return (file_put_contents($path, $content, LOCK_EX) !== false); + } + + /** + * Detect available archivers + * + * @return void + * @throws elFinderAbortException + */ + protected function _checkArchivers() + { + $this->archivers = $this->getArchivers(); + return; + } + + /** + * chmod availability + * + * @param string $path + * @param string $mode + * + * @return bool + */ + protected function _chmod($path, $mode) + { + $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode)); + return chmod($path, $modeOct); + } + + /** + * Recursive symlinks search + * + * @param string $path file/dir path + * + * @return bool + * @throws Exception + * @author Dmitry (dio) Levashov + */ + protected function _findSymlinks($path) + { + return self::localFindSymlinks($path); + } + + /** + * Extract files from archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return array|string|boolean + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _extract($path, $arc) + { + + if ($this->quarantine) { + + $dir = $this->quarantine . DIRECTORY_SEPARATOR . md5(basename($path) . mt_rand()); + $archive = (isset($arc['toSpec']) || $arc['cmd'] === 'phpfunction') ? '' : $dir . DIRECTORY_SEPARATOR . basename($path); + + if (!mkdir($dir)) { + return false; + } + + // insurance unexpected shutdown + register_shutdown_function(array($this, 'rmdirRecursive'), realpath($dir)); + + chmod($dir, 0777); + + // copy in quarantine + if (!is_readable($path) || ($archive && !copy($path, $archive))) { + return false; + } + + // extract in quarantine + try { + $this->unpackArchive($path, $arc, $archive ? true : $dir); + } catch(Exception $e) { + return $this->setError($e->getMessage()); + } + + // get files list + try { + $ls = self::localScandir($dir); + } catch (Exception $e) { + return false; + } + + // no files - extract error ? + if (empty($ls)) { + return false; + } + + $this->archiveSize = 0; + + // find symlinks and check extracted items + $checkRes = $this->checkExtractItems($dir); + if ($checkRes['symlinks']) { + self::localRmdirRecursive($dir); + return $this->setError(array_merge($this->error, array(elFinder::ERROR_ARC_SYMLINKS))); + } + $this->archiveSize = $checkRes['totalSize']; + if ($checkRes['rmNames']) { + foreach ($checkRes['rmNames'] as $name) { + $this->addError(elFinder::ERROR_SAVE, $name); + } + } + + // check max files size + if ($this->options['maxArcFilesSize'] > 0 && $this->options['maxArcFilesSize'] < $this->archiveSize) { + $this->delTree($dir); + return $this->setError(elFinder::ERROR_ARC_MAXSIZE); + } + + $extractTo = $this->extractToNewdir; // 'auto', ture or false + + // archive contains one item - extract in archive dir + $name = ''; + $src = $dir . DIRECTORY_SEPARATOR . $ls[0]; + if (($extractTo === 'auto' || !$extractTo) && count($ls) === 1 && is_file($src)) { + $name = $ls[0]; + } else if ($extractTo === 'auto' || $extractTo) { + // for several files - create new directory + // create unique name for directory + $src = $dir; + $splits = elFinder::splitFileExtention(basename($path)); + $name = $splits[0]; + $test = dirname($path) . DIRECTORY_SEPARATOR . $name; + if (file_exists($test) || is_link($test)) { + $name = $this->uniqueName(dirname($path), $name, '-', false); + } + } + + if ($name !== '') { + $result = dirname($path) . DIRECTORY_SEPARATOR . $name; + + if (!rename($src, $result)) { + $this->delTree($dir); + return false; + } + } else { + $dstDir = dirname($path); + $result = array(); + foreach ($ls as $name) { + $target = $dstDir . DIRECTORY_SEPARATOR . $name; + if (self::localMoveRecursive($dir . DIRECTORY_SEPARATOR . $name, $target, true, $this->options['copyJoin'])) { + $result[] = $target; + } + } + if (!$result) { + $this->delTree($dir); + return false; + } + } + + is_dir($dir) && $this->delTree($dir); + + return (is_array($result) || file_exists($result)) ? $result : false; + } + //TODO: Add return statement here + return false; + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _archive($dir, $files, $name, $arc) + { + return $this->makeArchive($dir, $files, $name, $arc); + } + + /******************** Over write functions *************************/ + + /** + * File path of local server side work file path + * + * @param string $path + * + * @return string + * @author Naoki Sawada + */ + protected function getWorkFile($path) + { + return $path; + } + + /** + * Delete dirctory trees + * + * @param string $localpath path need convert encoding to server encoding + * + * @return boolean + * @throws elFinderAbortException + * @author Naoki Sawada + */ + protected function delTree($localpath) + { + return $this->rmdirRecursive($localpath); + } + + /** + * Return fileinfo based on filename + * For item ID based path file system + * Please override if needed on each drivers + * + * @param string $path file cache + * + * @return array|boolean false + */ + protected function isNameExists($path) + { + $exists = file_exists($this->convEncIn($path)); + // restore locale + $this->convEncOut(); + return $exists ? $this->stat($path) : false; + } + + /******************** Over write (Optimized) functions *************************/ + + /** + * Recursive files search + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function doSearch($path, $q, $mimes) + { + if (!empty($this->doSearchCurrentQuery['matchMethod']) || $this->encoding || !class_exists('FilesystemIterator', false)) { + // has custom match method or non UTF-8, use elFinderVolumeDriver::doSearch() + return parent::doSearch($path, $q, $mimes); + } + + $result = array(); + + $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; + if ($timeout && $timeout < time()) { + $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); + return $result; + } + elFinder::extendTimeLimit($this->options['searchTimeout'] + 30); + + $match = array(); + try { + $iterator = new RecursiveIteratorIterator( + new RecursiveCallbackFilterIterator( + new RecursiveDirectoryIterator($path, + FilesystemIterator::KEY_AS_PATHNAME | + FilesystemIterator::SKIP_DOTS | + ((defined('RecursiveDirectoryIterator::FOLLOW_SYMLINKS') && $this->options['followSymLinks']) ? + RecursiveDirectoryIterator::FOLLOW_SYMLINKS : 0) + ), + array($this, 'localFileSystemSearchIteratorFilter') + ), + RecursiveIteratorIterator::SELF_FIRST, + RecursiveIteratorIterator::CATCH_GET_CHILD + ); + foreach ($iterator as $key => $node) { + if ($timeout && ($this->error || $timeout < time())) { + !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($node->getPath))); + break; + } + if ($node->isDir()) { + if ($this->stripos($node->getFilename(), $q) !== false) { + $match[] = $key; + } + } else { + $match[] = $key; + } + } + } catch (Exception $e) { + } + + if ($match) { + foreach ($match as $p) { + if ($timeout && ($this->error || $timeout < time())) { + !$this->error && $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode(dirname($p)))); + break; + } + + $stat = $this->stat($p); + + if (!$stat) { // invalid links + continue; + } + + if (!empty($stat['hidden']) || !$this->mimeAccepted($stat['mime'], $mimes)) { + continue; + } + + if ((!$mimes || $stat['mime'] !== 'directory')) { + $stat['path'] = $this->path($stat['hash']); + if ($this->URL && !isset($stat['url'])) { + $_path = str_replace(DIRECTORY_SEPARATOR, '/', substr($p, strlen($this->root) + 1)); + $stat['url'] = $this->URL . str_replace('%2F', '/', rawurlencode($_path)); + } + + $result[] = $stat; + } + } + } + + return $result; + } + + /******************** Original local functions ************************ + * + * @param $file + * @param $key + * @param $iterator + * + * @return bool + */ + + public function localFileSystemSearchIteratorFilter($file, $key, $iterator) + { + /* @var FilesystemIterator $file */ + /* @var RecursiveDirectoryIterator $iterator */ + $name = $file->getFilename(); + if ($this->doSearchCurrentQuery['excludes']) { + foreach ($this->doSearchCurrentQuery['excludes'] as $exclude) { + if ($this->stripos($name, $exclude) !== false) { + return false; + } + } + } + if ($iterator->hasChildren()) { + if ($this->options['searchExDirReg'] && preg_match($this->options['searchExDirReg'], $key)) { + return false; + } + return (bool)$this->attr($key, 'read', null, true); + } + return ($this->stripos($name, $this->doSearchCurrentQuery['q']) === false) ? false : true; + } + + /** + * Creates a symbolic link + * + * @param string $target The target + * @param string $link The link + * + * @return boolean ( result of symlink() ) + */ + protected function localFileSystemSymlink($target, $link) + { + $res = false; + if (function_exists('symlink') and is_callable('symlink')) { + $errlev = error_reporting(); + error_reporting($errlev ^ E_WARNING); + if ($res = symlink(realpath($target), $link)) { + $res = is_readable($link); + } + error_reporting($errlev); + } + return $res; + } +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeMySQL.class.php b/lib/redactor/elfinder/php/elFinderVolumeMySQL.class.php new file mode 100644 index 0000000..d0e420e --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeMySQL.class.php @@ -0,0 +1,1042 @@ + 'localhost', + 'user' => '', + 'pass' => '', + 'db' => '', + 'port' => null, + 'socket' => null, + 'files_table' => 'elfinder_file', + 'tmbPath' => '', + 'tmpPath' => '', + 'rootCssClass' => 'elfinder-navbar-root-sql', + 'noSessionCache' => array('hasdirs'), + 'isLocalhost' => false + ); + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare driver before mount volume. + * Connect to db, check required tables and fetch root path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function init() + { + + if (!($this->options['host'] || $this->options['socket']) + || !$this->options['user'] + || !$this->options['pass'] + || !$this->options['db'] + || !$this->options['path'] + || !$this->options['files_table']) { + return $this->setError('Required options "host", "socket", "user", "pass", "db", "path" or "files_table" are undefined.'); + } + + $err = null; + if ($this->db = @new mysqli($this->options['host'], $this->options['user'], $this->options['pass'], $this->options['db'], $this->options['port'], $this->options['socket'])) { + if ($this->db && $this->db->connect_error) { + $err = $this->db->connect_error; + } + } else { + $err = mysqli_connect_error(); + } + if ($err) { + return $this->setError(array('Unable to connect to MySQL server.', $err)); + } + + if (!$this->needOnline && empty($this->ARGS['init'])) { + $this->db->close(); + $this->db = null; + return true; + } + + $this->db->set_charset('utf8'); + + if ($res = $this->db->query('SHOW TABLES')) { + while ($row = $res->fetch_array()) { + if ($row[0] == $this->options['files_table']) { + $this->tbf = $this->options['files_table']; + break; + } + } + } + + if (!$this->tbf) { + return $this->setError('The specified database table cannot be found.'); + } + + $this->updateCache($this->options['path'], $this->_stat($this->options['path'])); + + // enable command archive + $this->options['useRemoteArchive'] = true; + + // check isLocalhost + $this->isLocalhost = $this->options['isLocalhost'] || $this->options['host'] === 'localhost' || $this->options['host'] === '127.0.0.1' || $this->options['host'] === '::1'; + + return true; + } + + + /** + * Set tmp path + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function configure() + { + parent::configure(); + + if (($tmp = $this->options['tmpPath'])) { + if (!file_exists($tmp)) { + if (mkdir($tmp)) { + chmod($tmp, $this->options['tmbPathMode']); + } + } + + $this->tmpPath = is_dir($tmp) && is_writable($tmp) ? $tmp : false; + } + if (!$this->tmpPath && ($tmp = elFinder::getStaticVar('commonTempPath'))) { + $this->tmpPath = $tmp; + } + + // fallback of $this->tmp + if (!$this->tmpPath && $this->tmbPathWritable) { + $this->tmpPath = $this->tmbPath; + } + + $this->mimeDetect = 'internal'; + } + + /** + * Close connection + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + $this->db && $this->db->close(); + } + + /** + * Return debug info for client + * + * @return array + * @author Dmitry (dio) Levashov + **/ + public function debug() + { + $debug = parent::debug(); + $debug['sqlCount'] = $this->sqlCnt; + if ($this->dbError) { + $debug['dbError'] = $this->dbError; + } + return $debug; + } + + /** + * Perform sql query and return result. + * Increase sqlCnt and save error if occured + * + * @param string $sql query + * + * @return bool|mysqli_result + * @author Dmitry (dio) Levashov + */ + protected function query($sql) + { + $this->sqlCnt++; + $res = $this->db->query($sql); + if (!$res) { + $this->dbError = $this->db->error; + } + return $res; + } + + /** + * Perform sql prepared statement and return result. + * Increase sqlCnt and save error if occurred. + * + * @param mysqli_stmt $stmt + * @return bool + */ + protected function execute($stmt) + { + $this->sqlCnt++; + $res = $stmt->execute(); + if (!$res) { + $this->dbError = $this->db->error; + } + return $res; + } + + /** + * Create empty object with required mimetype + * + * @param string $path parent dir path + * @param string $name object name + * @param string $mime mime type + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function make($path, $name, $mime) + { + $sql = 'INSERT INTO %s (`parent_id`, `name`, `size`, `mtime`, `mime`, `content`, `read`, `write`, `locked`, `hidden`, `width`, `height`) VALUES (\'%s\', \'%s\', 0, %d, \'%s\', \'\', \'%d\', \'%d\', \'%d\', \'%d\', 0, 0)'; + $sql = sprintf($sql, $this->tbf, $path, $this->db->real_escape_string($name), time(), $mime, $this->defaults['read'], $this->defaults['write'], $this->defaults['locked'], $this->defaults['hidden']); + // echo $sql; + return $this->query($sql) && $this->db->affected_rows > 0; + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Cache dir contents + * + * @param string $path dir path + * + * @return string + * @author Dmitry Levashov + **/ + protected function cacheDir($path) + { + $this->dirsCache[$path] = array(); + + $sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, IF(ch.id, 1, 0) AS dirs + FROM ' . $this->tbf . ' AS f + LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\' + WHERE f.parent_id=\'' . $path . '\' + GROUP BY f.id, ch.id'; + + $res = $this->query($sql); + if ($res) { + while ($row = $res->fetch_assoc()) { + $id = $row['id']; + if ($row['parent_id'] && $id != $this->root) { + $row['phash'] = $this->encode($row['parent_id']); + } + + if ($row['mime'] == 'directory') { + unset($row['width']); + unset($row['height']); + $row['size'] = 0; + } else { + unset($row['dirs']); + } + + unset($row['id']); + unset($row['parent_id']); + + + if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) { + $this->dirsCache[$path][] = $id; + } + } + } + + return $this->dirsCache[$path]; + } + + /** + * Return array of parents paths (ids) + * + * @param int $path file path (id) + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function getParents($path) + { + $parents = array(); + + while ($path) { + if ($file = $this->stat($path)) { + array_unshift($parents, $path); + $path = isset($file['phash']) ? $this->decode($file['phash']) : false; + } + } + + if (count($parents)) { + array_pop($parents); + } + return $parents; + } + + /** + * Return correct file path for LOAD_FILE method + * + * @param string $path file path (id) + * + * @return string + * @author Troex Nevelin + **/ + protected function loadFilePath($path) + { + $realPath = realpath($path); + if (DIRECTORY_SEPARATOR == '\\') { // windows + $realPath = str_replace('\\', '\\\\', $realPath); + } + return $this->db->real_escape_string($realPath); + } + + /** + * Recursive files search + * + * @param string $path dir path + * @param string $q search string + * @param array $mimes + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function doSearch($path, $q, $mimes) + { + if (!empty($this->doSearchCurrentQuery['matchMethod'])) { + // has custom match method use elFinderVolumeDriver::doSearch() + return parent::doSearch($path, $q, $mimes); + } + + $dirs = array(); + $timeout = $this->options['searchTimeout'] ? $this->searchStart + $this->options['searchTimeout'] : 0; + + if ($path != $this->root || $this->rootHasParent) { + $dirs = $inpath = array(intval($path)); + while ($inpath) { + $in = '(' . join(',', $inpath) . ')'; + $inpath = array(); + $sql = 'SELECT f.id FROM %s AS f WHERE f.parent_id IN ' . $in . ' AND `mime` = \'directory\''; + $sql = sprintf($sql, $this->tbf); + if ($res = $this->query($sql)) { + $_dir = array(); + while ($dat = $res->fetch_assoc()) { + $inpath[] = $dat['id']; + } + $dirs = array_merge($dirs, $inpath); + } + } + } + + $result = array(); + + if ($mimes) { + $whrs = array(); + foreach ($mimes as $mime) { + if (strpos($mime, '/') === false) { + $whrs[] = sprintf('f.mime LIKE \'%s/%%\'', $this->db->real_escape_string($mime)); + } else { + $whrs[] = sprintf('f.mime = \'%s\'', $this->db->real_escape_string($mime)); + } + } + $whr = join(' OR ', $whrs); + } else { + $whr = sprintf('f.name LIKE \'%%%s%%\'', $this->db->real_escape_string($q)); + } + if ($dirs) { + $whr = '(' . $whr . ') AND (`parent_id` IN (' . join(',', $dirs) . '))'; + } + + $sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, 0 AS dirs + FROM %s AS f + WHERE %s'; + + $sql = sprintf($sql, $this->tbf, $whr); + + if (($res = $this->query($sql))) { + while ($row = $res->fetch_assoc()) { + if ($timeout && $timeout < time()) { + $this->setError(elFinder::ERROR_SEARCH_TIMEOUT, $this->path($this->encode($path))); + break; + } + + if (!$this->mimeAccepted($row['mime'], $mimes)) { + continue; + } + $id = $row['id']; + if ($id == $this->root) { + continue; + } + if ($row['parent_id'] && $id != $this->root) { + $row['phash'] = $this->encode($row['parent_id']); + } + $row['path'] = $this->_path($id); + + if ($row['mime'] == 'directory') { + unset($row['width']); + unset($row['height']); + } else { + unset($row['dirs']); + } + + unset($row['id']); + unset($row['parent_id']); + + if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) { + $result[] = $stat; + } + } + } + return $result; + } + + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) + { + return ($stat = $this->stat($path)) ? (!empty($stat['phash']) ? $this->decode($stat['phash']) : $this->root) : false; + } + + /** + * Return file name + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) + { + return (($stat = $this->stat($path)) && isset($stat['name'])) ? $stat['name'] : false; + } + + /** + * Join dir name and file name and return full path + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + $sql = 'SELECT id FROM ' . $this->tbf . ' WHERE parent_id=\'' . $dir . '\' AND name=\'' . $this->db->real_escape_string($name) . '\''; + + if (($res = $this->query($sql)) && ($r = $res->fetch_assoc())) { + $this->updateCache($r['id'], $this->_stat($r['id'])); + return $r['id']; + } + return -1; + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python + * + * @param string $path path + * + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) + { + return $path; + } + + /** + * Return file path related to root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + return $path; + } + + /** + * Convert path related to root dir into real path + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) + { + return $path; + } + + /** + * Return fake path started from root dir + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) + { + if (($file = $this->stat($path)) == false) { + return ''; + } + + $parentsIds = $this->getParents($path); + $path = ''; + foreach ($parentsIds as $id) { + $dir = $this->stat($id); + $path .= $dir['name'] . $this->separator; + } + return $path . $file['name']; + } + + /** + * Return true if $path is children of $parent + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) + { + return $path == $parent + ? true + : in_array($parent, $this->getParents($path)); + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + $sql = 'SELECT f.id, f.parent_id, f.name, f.size, f.mtime AS ts, f.mime, f.read, f.write, f.locked, f.hidden, f.width, f.height, IF(ch.id, 1, 0) AS dirs + FROM ' . $this->tbf . ' AS f + LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime=\'directory\' + WHERE f.id=\'' . $path . '\' + GROUP BY f.id, ch.id'; + + $res = $this->query($sql); + + if ($res) { + $stat = $res->fetch_assoc(); + if ($stat['id'] == $this->root) { + $this->rootHasParent = true; + $stat['parent_id'] = ''; + } + if ($stat['parent_id']) { + $stat['phash'] = $this->encode($stat['parent_id']); + } + if ($stat['mime'] == 'directory') { + unset($stat['width']); + unset($stat['height']); + $stat['size'] = 0; + } else { + if (!$stat['mime']) { + unset($stat['mime']); + } + unset($stat['dirs']); + } + unset($stat['id']); + unset($stat['parent_id']); + return $stat; + + } + return array(); + } + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _subdirs($path) + { + return ($stat = $this->stat($path)) && isset($stat['dirs']) ? $stat['dirs'] : false; + } + + /** + * Return object width and height + * Usualy used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dimensions($path, $mime) + { + return ($stat = $this->stat($path)) && isset($stat['width']) && isset($stat['height']) ? $stat['width'] . 'x' . $stat['height'] : ''; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @author Dmitry (dio) Levashov + **/ + protected function _scandir($path) + { + return isset($this->dirsCache[$path]) + ? $this->dirsCache[$path] + : $this->cacheDir($path); + } + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param string $mode open file mode (ignored in this driver) + * + * @return resource|false + * @author Dmitry (dio) Levashov + **/ + protected function _fopen($path, $mode = 'rb') + { + $fp = $this->tmpPath + ? fopen($this->getTempFile($path), 'w+') + : $this->tmpfile(); + + + if ($fp) { + if (($res = $this->query('SELECT content FROM ' . $this->tbf . ' WHERE id=\'' . $path . '\'')) + && ($r = $res->fetch_assoc())) { + fwrite($fp, $r['content']); + rewind($fp); + return $fp; + } else { + $this->_fclose($fp, $path); + } + } + + return false; + } + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path + * + * @return void + * @author Dmitry (dio) Levashov + */ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + if ($path) { + $file = $this->getTempFile($path); + is_file($file) && unlink($file); + } + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + return $this->make($path, $name, 'directory') ? $this->_joinPath($path, $name) : false; + } + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) + { + return $this->make($path, $name, '') ? $this->_joinPath($path, $name) : false; + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * @param string $name + * + * @return bool + * @author Dmitry (dio) Levashov + */ + protected function _symlink($target, $path, $name) + { + return false; + } + + /** + * Copy file into another file + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) + { + $this->clearcache(); + $id = $this->_joinPath($targetDir, $name); + + $sql = $id > 0 + ? sprintf('REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height, `read`, `write`, `locked`, `hidden`) (SELECT %d, %d, name, content, size, mtime, mime, width, height, `read`, `write`, `locked`, `hidden` FROM %s WHERE id=%d)', $this->tbf, $id, $this->_dirname($id), $this->tbf, $source) + : sprintf('INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height, `read`, `write`, `locked`, `hidden`) SELECT %d, \'%s\', content, size, %d, mime, width, height, `read`, `write`, `locked`, `hidden` FROM %s WHERE id=%d', $this->tbf, $targetDir, $this->db->real_escape_string($name), time(), $this->tbf, $source); + + return $this->query($sql); + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + protected function _move($source, $targetDir, $name) + { + $sql = 'UPDATE %s SET parent_id=%d, name=\'%s\' WHERE id=%d LIMIT 1'; + $sql = sprintf($sql, $this->tbf, $targetDir, $this->db->real_escape_string($name), $source); + return $this->query($sql) && $this->db->affected_rows > 0 ? $source : false; + } + + /** + * Remove file + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime!=\'directory\' LIMIT 1', $this->tbf, $path)) && $this->db->affected_rows; + } + + /** + * Remove dir + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + return $this->query(sprintf('DELETE FROM %s WHERE id=%d AND mime=\'directory\' LIMIT 1', $this->tbf, $path)) && $this->db->affected_rows; + } + + /** + * undocumented function + * + * @param $path + * @param $fp + * + * @author Dmitry Levashov + */ + protected function _setContent($path, $fp) + { + elFinder::rewind($fp); + $fstat = fstat($fp); + $size = $fstat['size']; + + + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + protected function _save($fp, $dir, $name, $stat) + { + $this->clearcache(); + + $mime = !empty($stat['mime']) ? $stat['mime'] : $this->mimetype($name, true); + $w = !empty($stat['width']) ? $stat['width'] : 0; + $h = !empty($stat['height']) ? $stat['height'] : 0; + $ts = !empty($stat['ts']) ? $stat['ts'] : time(); + + $id = $this->_joinPath($dir, $name); + if (!isset($stat['size'])) { + $stat = fstat($fp); + $size = $stat['size']; + } else { + $size = $stat['size']; + } + + if ($this->isLocalhost && ($tmpfile = tempnam($this->tmpPath, $this->id))) { + if (($trgfp = fopen($tmpfile, 'wb')) == false) { + unlink($tmpfile); + } else { + elFinder::rewind($fp); + stream_copy_to_stream($fp, $trgfp); + fclose($trgfp); + chmod($tmpfile, 0644); + + $sql = $id > 0 + ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', ?, ?, LOAD_FILE(?), ?, ?, ?, ?, ?)' + : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (?, ?, LOAD_FILE(?), ?, ?, ?, ?, ?)'; + $stmt = $this->db->prepare(sprintf($sql, $this->tbf)); + $path = $this->loadFilePath($tmpfile); + $stmt->bind_param("issiisii", $dir, $name, $path, $size, $ts, $mime, $w, $h); + + $res = $this->execute($stmt); + unlink($tmpfile); + + if ($res) { + return $id > 0 ? $id : $this->db->insert_id; + } + } + } + + + $content = ''; + elFinder::rewind($fp); + while (!feof($fp)) { + $content .= fread($fp, 8192); + } + + $sql = $id > 0 + ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', ?, ?, ?, ?, ?, ?, ?, ?)' + : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'; + $stmt = $this->db->prepare(sprintf($sql, $this->tbf)); + $stmt->bind_param("issiisii", $dir, $name, $content, $size, $ts, $mime, $w, $h); + + unset($content); + + if ($this->execute($stmt)) { + return $id > 0 ? $id : $this->db->insert_id; + } + + return false; + } + + /** + * Get file contents + * + * @param string $path file path + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) + { + return ($res = $this->query(sprintf('SELECT content FROM %s WHERE id=%d', $this->tbf, $path))) && ($r = $res->fetch_assoc()) ? $r['content'] : false; + } + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + return $this->query(sprintf('UPDATE %s SET content=\'%s\', size=%d, mtime=%d WHERE id=%d LIMIT 1', $this->tbf, $this->db->real_escape_string($content), strlen($content), time(), $path)); + } + + /** + * Detect available archivers + * + * @return void + **/ + protected function _checkArchivers() + { + return; + } + + /** + * chmod implementation + * + * @param string $path + * @param string $mode + * + * @return bool + */ + protected function _chmod($path, $mode) + { + return false; + } + + /** + * Unpack archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return void + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + **/ + protected function _unpack($path, $arc) + { + return; + } + + /** + * Extract files from archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return true + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _extract($path, $arc) + { + return false; + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) + { + return false; + } + +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeOneDrive.class.php b/lib/redactor/elfinder/php/elFinderVolumeOneDrive.class.php new file mode 100644 index 0000000..6edbbf0 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeOneDrive.class.php @@ -0,0 +1,2132 @@ + '', + 'client_secret' => '', + 'accessToken' => '', + 'root' => 'OneDrive.com', + 'OneDriveApiClient' => '', + 'path' => '/', + 'separator' => '/', + 'tmbPath' => '', + 'tmbURL' => '', + 'tmpPath' => '', + 'acceptedName' => '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#', + 'rootCssClass' => 'elfinder-navbar-root-onedrive', + 'useApiThumbnail' => true, + ); + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /*********************************************************************/ + /* ORIGINAL FUNCTIONS */ + /*********************************************************************/ + + /** + * Obtains a new access token from OAuth. This token is valid for one hour. + * + * @param $client_id + * @param $client_secret + * @param string $code The code returned by OneDrive after + * successful log in + * + * @return object|string + * @throws Exception Thrown if the redirect URI of this Client instance's + * state is not set + */ + protected function _od_obtainAccessToken($client_id, $client_secret, $code, $nodeid) + { + if (null === $client_id) { + return 'The client ID must be set to call obtainAccessToken()'; + } + + if (null === $client_secret) { + return 'The client Secret must be set to call obtainAccessToken()'; + } + + $redirect = elFinder::getConnectorUrl(); + if (strpos($redirect, '/netmount/onedrive/') === false) { + $redirect .= '/netmount/onedrive/' . ($nodeid === 'elfinder'? '1' : $nodeid); + } + + $url = self::TOKEN_URL; + + $curl = curl_init(); + + $fields = http_build_query( + array( + 'client_id' => $client_id, + 'redirect_uri' => $redirect, + 'client_secret' => $client_secret, + 'code' => $code, + 'grant_type' => 'authorization_code', + ) + ); + + curl_setopt_array($curl, array( + // General options. + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $fields, + + CURLOPT_HTTPHEADER => array( + 'Content-Length: ' . strlen($fields), + ), + + CURLOPT_URL => $url, + )); + + $result = elFinder::curlExec($curl); + + $decoded = json_decode($result); + + if (null === $decoded) { + throw new \Exception('json_decode() failed'); + } + + if (!empty($decoded->error)) { + $error = $decoded->error; + if (!empty($decoded->error_description)) { + $error .= ': ' . $decoded->error_description; + } + throw new \Exception($error); + } + + $res = (object)array( + 'expires' => time() + $decoded->expires_in - 30, + 'initialToken' => '', + 'data' => $decoded + ); + if (!empty($decoded->refresh_token)) { + $res->initialToken = md5($client_id . $decoded->refresh_token); + } + return $res; + } + + /** + * Get token and auto refresh. + * + * @return true + * @throws Exception + */ + protected function _od_refreshToken() + { + if (!property_exists($this->token, 'expires') || $this->token->expires < time()) { + if (!$this->options['client_id']) { + $this->options['client_id'] = ELFINDER_ONEDRIVE_CLIENTID; + } + + if (!$this->options['client_secret']) { + $this->options['client_secret'] = ELFINDER_ONEDRIVE_CLIENTSECRET; + } + + if (empty($this->token->data->refresh_token)) { + throw new \Exception(elFinder::ERROR_REAUTH_REQUIRE); + } else { + $refresh_token = $this->token->data->refresh_token; + $initialToken = $this->_od_getInitialToken(); + } + + $url = self::TOKEN_URL; + + $curl = curl_init(); + + curl_setopt_array($curl, array( + // General options. + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POST => true, // i am sending post data + CURLOPT_POSTFIELDS => 'client_id=' . urlencode($this->options['client_id']) + . '&client_secret=' . urlencode($this->options['client_secret']) + . '&grant_type=refresh_token' + . '&refresh_token=' . urlencode($this->token->data->refresh_token), + + CURLOPT_URL => $url, + )); + + $result = elFinder::curlExec($curl); + + $decoded = json_decode($result); + + if (!$decoded) { + throw new \Exception('json_decode() failed'); + } + + if (empty($decoded->access_token)) { + if ($this->aTokenFile) { + if (is_file($this->aTokenFile)) { + unlink($this->aTokenFile); + } + } + $err = property_exists($decoded, 'error')? ' ' . $decoded->error : ''; + $err .= property_exists($decoded, 'error_description')? ' ' . $decoded->error_description : ''; + throw new \Exception($err? $err : elFinder::ERROR_REAUTH_REQUIRE); + } + + $token = (object)array( + 'expires' => time() + $decoded->expires_in - 30, + 'initialToken' => $initialToken, + 'data' => $decoded, + ); + + $this->token = $token; + $json = json_encode($token); + + if (!empty($decoded->refresh_token)) { + if (empty($this->options['netkey']) && $this->aTokenFile) { + file_put_contents($this->aTokenFile, json_encode($token)); + $this->options['accessToken'] = $json; + } else if (!empty($this->options['netkey'])) { + // OAuth2 refresh token can be used only once, + // so update it if it is the same as the token file + $aTokenFile = $this->_od_getATokenFile(); + if ($aTokenFile && is_file($aTokenFile)) { + if ($_token = json_decode(file_get_contents($aTokenFile))) { + if ($_token->data->refresh_token === $refresh_token) { + file_put_contents($aTokenFile, $json); + } + } + } + $this->options['accessToken'] = $json; + // update session value + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'accessToken', $this->options['accessToken']); + $this->session->set('OneDriveTokens', $token); + } else { + throw new \Exception(elFinder::ERROR_CREATING_TEMP_DIR); + } + } + } + + return true; + } + + /** + * Get Parent ID, Item ID, Parent Path as an array from path. + * + * @param string $path + * + * @return array + */ + protected function _od_splitPath($path) + { + $path = trim($path, '/'); + $pid = ''; + if ($path === '') { + $id = 'root'; + $parent = ''; + } else { + $paths = explode('/', trim($path, '/')); + $id = array_pop($paths); + if ($paths) { + $parent = '/' . implode('/', $paths); + $pid = array_pop($paths); + } else { + $pid = 'root'; + $parent = '/'; + } + } + + return array($pid, $id, $parent); + } + + /** + * Creates a base cURL object which is compatible with the OneDrive API. + * + * @return resource A compatible cURL object + */ + protected function _od_prepareCurl($url = null) + { + $curl = curl_init($url); + + $defaultOptions = array( + // General options. + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/json', + 'Authorization: Bearer ' . $this->token->data->access_token, + ), + ); + + curl_setopt_array($curl, $defaultOptions); + + return $curl; + } + + /** + * Creates a base cURL object which is compatible with the OneDrive API. + * + * @param string $path The path of the API call (eg. me/skydrive) + * @param bool $contents + * + * @return resource A compatible cURL object + * @throws elFinderAbortException + */ + protected function _od_createCurl($path, $contents = false) + { + elFinder::checkAborted(); + $curl = $this->_od_prepareCurl($path); + + if ($contents) { + $res = elFinder::curlExec($curl); + } else { + $result = json_decode(elFinder::curlExec($curl)); + if (isset($result->value)) { + $res = $result->value; + unset($result->value); + $result = (array)$result; + if (!empty($result['@odata.nextLink'])) { + $nextRes = $this->_od_createCurl($result['@odata.nextLink'], false); + if (is_array($nextRes)) { + $res = array_merge($res, $nextRes); + } + } + } else { + $res = $result; + } + } + + return $res; + } + + /** + * Drive query and fetchAll. + * + * @param $itemId + * @param bool $fetch_self + * @param bool $recursive + * @param array $options + * + * @return object|array + * @throws elFinderAbortException + */ + protected function _od_query($itemId, $fetch_self = false, $recursive = false, $options = array()) + { + $result = array(); + + if (null === $itemId) { + $itemId = 'root'; + } + + if ($fetch_self == true) { + $path = $itemId; + } else { + $path = $itemId . '/children'; + } + + if (isset($options['query'])) { + $path .= '?' . http_build_query($options['query']); + } + + $url = self::API_URL . $path; + + $res = $this->_od_createCurl($url); + if (!$fetch_self && $recursive && is_array($res)) { + foreach ($res as $file) { + $result[] = $file; + if (!empty($file->folder)) { + $result = array_merge($result, $this->_od_query($file->id, false, true, $options)); + } + } + } else { + $result = $res; + } + + return isset($result->error) ? array() : $result; + } + + /** + * Parse line from onedrive metadata output and return file stat (array). + * + * @param object $raw line from ftp_rawlist() output + * + * @return array + * @author Dmitry Levashov + **/ + protected function _od_parseRaw($raw) + { + $stat = array(); + + $folder = isset($raw->folder) ? $raw->folder : null; + + $stat['rev'] = isset($raw->id) ? $raw->id : 'root'; + $stat['name'] = $raw->name; + if (isset($raw->lastModifiedDateTime)) { + $stat['ts'] = strtotime($raw->lastModifiedDateTime); + } + + if ($folder) { + $stat['mime'] = 'directory'; + $stat['size'] = 0; + if (empty($folder->childCount)) { + $stat['dirs'] = 0; + } else { + $stat['dirs'] = -1; + } + } else { + if (isset($raw->file->mimeType)) { + $stat['mime'] = $raw->file->mimeType; + } + $stat['size'] = (int)$raw->size; + if (!$this->disabledGetUrl) { + $stat['url'] = '1'; + } + if (isset($raw->image) && $img = $raw->image) { + isset($img->width) ? $stat['width'] = $img->width : $stat['width'] = 0; + isset($img->height) ? $stat['height'] = $img->height : $stat['height'] = 0; + } + if (!empty($raw->thumbnails)) { + if ($raw->thumbnails[0]->small->url) { + $stat['tmb'] = substr($raw->thumbnails[0]->small->url, 8); // remove "https://" + } + } elseif (!empty($raw->file->processingMetadata)) { + $stat['tmb'] = '1'; + } + } + + return $stat; + } + + /** + * Get raw data(onedrive metadata) from OneDrive. + * + * @param string $path + * + * @return array|object onedrive metadata + */ + protected function _od_getFileRaw($path) + { + list(, $itemId) = $this->_od_splitPath($path); + try { + $res = $this->_od_query($itemId, true, false, $this->queryOptions); + + return $res; + } catch (Exception $e) { + return array(); + } + } + + /** + * Get thumbnail from OneDrive.com. + * + * @param string $path + * + * @return string | boolean + */ + protected function _od_getThumbnail($path) + { + list(, $itemId) = $this->_od_splitPath($path); + + try { + $url = self::API_URL . $itemId . '/thumbnails/0/medium/content'; + + return $this->_od_createCurl($url, $contents = true); + } catch (Exception $e) { + return false; + } + } + + /** + * Upload large files with an upload session. + * + * @param resource $fp source file pointer + * @param number $size total size + * @param string $name item name + * @param string $itemId item identifier + * @param string $parent parent + * @param string $parentId parent identifier + * + * @return string The item path + */ + protected function _od_uploadSession($fp, $size, $name, $itemId, $parent, $parentId) + { + try { + $send = $this->_od_getChunkData($fp); + if ($send === false) { + throw new Exception('Data can not be acquired from the source.'); + } + + // create upload session + if ($itemId) { + $url = self::API_URL . $itemId . '/createUploadSession'; + } else { + $url = self::API_URL . $parentId . ':/' . rawurlencode($name) . ':/createUploadSession'; + } + $curl = $this->_od_prepareCurl($url); + curl_setopt_array($curl, array( + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => '{}', + )); + $sess = json_decode(elFinder::curlExec($curl)); + + if ($sess) { + if (isset($sess->error)) { + throw new Exception($sess->error->message); + } + $next = strlen($send); + $range = '0-' . ($next - 1) . '/' . $size; + } else { + throw new Exception('API response can not be obtained.'); + } + + $id = null; + $retry = 0; + while ($sess) { + elFinder::extendTimeLimit(); + $putFp = tmpfile(); + fwrite($putFp, $send); + rewind($putFp); + $_size = strlen($send); + $url = $sess->uploadUrl; + $curl = curl_init(); + $options = array( + CURLOPT_URL => $url, + CURLOPT_PUT => true, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_INFILE => $putFp, + CURLOPT_INFILESIZE => $_size, + CURLOPT_HTTPHEADER => array( + 'Content-Length: ' . $_size, + 'Content-Range: bytes ' . $range, + ), + ); + curl_setopt_array($curl, $options); + $sess = json_decode(elFinder::curlExec($curl)); + if ($sess) { + if (isset($sess->error)) { + throw new Exception($sess->error->message); + } + if (isset($sess->id)) { + $id = $sess->id; + break; + } + if (isset($sess->nextExpectedRanges)) { + list($_next) = explode('-', $sess->nextExpectedRanges[0]); + if ($next == $_next) { + $send = $this->_od_getChunkData($fp); + if ($send === false) { + throw new Exception('Data can not be acquired from the source.'); + } + $next += strlen($send); + $range = $_next . '-' . ($next - 1) . '/' . $size; + $retry = 0; + } else { + if (++$retry > 3) { + throw new Exception('Retry limit exceeded with uploadSession API call.'); + } + } + $sess->uploadUrl = $url; + } + } else { + throw new Exception('API response can not be obtained.'); + } + } + + if ($id) { + return $this->_joinPath($parent, $id); + } else { + throw new Exception('An error occurred in the uploadSession API call.'); + } + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + } + + /** + * Get chunk data by file pointer to upload session. + * + * @param resource $fp source file pointer + * + * @return bool|string chunked data + */ + protected function _od_getChunkData($fp) + { + static $chunkSize = null; + if ($chunkSize === null) { + $mem = elFinder::getIniBytes('memory_limit'); + if ($mem < 1) { + $mem = 10485760; // 10 MiB + } else { + $mem -= memory_get_usage() - 1061548; + $mem = min($mem, 10485760); + } + if ($mem > 327680) { + $chunkSize = floor($mem / 327680) * 327680; + } else { + $chunkSize = $mem; + } + } + if ($chunkSize < 8192) { + return false; + } + + $contents = ''; + while (!feof($fp) && strlen($contents) < $chunkSize) { + $contents .= fread($fp, 8192); + } + + return $contents; + } + + /** + * Get AccessToken file path + * + * @return string ( description_of_the_return_value ) + */ + protected function _od_getATokenFile() + { + $tmp = $aTokenFile = ''; + if (!empty($this->token->data->refresh_token)) { + if (!$this->tmp) { + $tmp = elFinder::getStaticVar('commonTempPath'); + if (!$tmp) { + $tmp = $this->getTempPath(); + } + $this->tmp = $tmp; + } + if ($tmp) { + $aTokenFile = $tmp . DIRECTORY_SEPARATOR . $this->_od_getInitialToken() . '.otoken'; + } + } + return $aTokenFile; + } + + /** + * Get Initial Token (MD5 hash) + * + * @return string + */ + protected function _od_getInitialToken() + { + return (empty($this->token->initialToken)? md5($this->options['client_id'] . (!empty($this->token->data->refresh_token)? $this->token->data->refresh_token : $this->token->data->access_token)) : $this->token->initialToken); + } + + /*********************************************************************/ + /* OVERRIDE FUNCTIONS */ + /*********************************************************************/ + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount(). + * + * @return array + * @author Naoki Sawada + * @author Raja Sharma updating for OneDrive + **/ + public function netmountPrepare($options) + { + if (empty($options['client_id']) && defined('ELFINDER_ONEDRIVE_CLIENTID')) { + $options['client_id'] = ELFINDER_ONEDRIVE_CLIENTID; + } + if (empty($options['client_secret']) && defined('ELFINDER_ONEDRIVE_CLIENTSECRET')) { + $options['client_secret'] = ELFINDER_ONEDRIVE_CLIENTSECRET; + } + + if (isset($options['pass']) && $options['pass'] === 'reauth') { + $options['user'] = 'init'; + $options['pass'] = ''; + $this->session->remove('OneDriveTokens'); + } + + if (isset($options['id'])) { + $this->session->set('nodeId', $options['id']); + } elseif ($_id = $this->session->get('nodeId')) { + $options['id'] = $_id; + $this->session->set('nodeId', $_id); + } + + if (!empty($options['tmpPath'])) { + if ((is_dir($options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($options['tmpPath'])) { + $this->tmp = $options['tmpPath']; + } + } + + try { + if (empty($options['client_id']) || empty($options['client_secret'])) { + return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}'); + } + + $itpCare = isset($options['code']); + $code = $itpCare? $options['code'] : (isset($_GET['code'])? $_GET['code'] : ''); + if ($code) { + try { + if (!empty($options['id'])) { + // Obtain the token using the code received by the OneDrive API + $this->session->set('OneDriveTokens', + $this->_od_obtainAccessToken($options['client_id'], $options['client_secret'], $code, $options['id'])); + + $out = array( + 'node' => $options['id'], + 'json' => '{"protocol": "onedrive", "mode": "done", "reset": 1}', + 'bind' => 'netmount', + ); + } else { + $nodeid = ($_GET['host'] === '1')? 'elfinder' : $_GET['host']; + $out = array( + 'node' => $nodeid, + 'json' => json_encode(array( + 'protocol' => 'onedrive', + 'host' => $nodeid, + 'mode' => 'redirect', + 'options' => array( + 'id' => $nodeid, + 'code'=> $code + ) + )), + 'bind' => 'netmount' + ); + } + if (!$itpCare) { + return array('exit' => 'callback', 'out' => $out); + } else { + return array('exit' => true, 'body' => $out['json']); + } + } catch (Exception $e) { + $out = array( + 'node' => $options['id'], + 'json' => json_encode(array('error' => elFinder::ERROR_ACCESS_DENIED . ' ' . $e->getMessage())), + ); + + return array('exit' => 'callback', 'out' => $out); + } + } elseif (!empty($_GET['error'])) { + $out = array( + 'node' => $options['id'], + 'json' => json_encode(array('error' => elFinder::ERROR_ACCESS_DENIED)), + ); + + return array('exit' => 'callback', 'out' => $out); + } + + if ($options['user'] === 'init') { + $this->token = $this->session->get('OneDriveTokens'); + + if ($this->token) { + try { + $this->_od_refreshToken(); + } catch (Exception $e) { + $this->setError($e->getMessage()); + $this->token = null; + $this->session->remove('OneDriveTokens'); + } + } + + if (empty($this->token)) { + $result = false; + } else { + $path = $options['path']; + if ($path === '/') { + $path = 'root'; + } + $result = $this->_od_query($path, false, false, array( + 'query' => array( + 'select' => 'id,name', + 'filter' => 'folder ne null', + ), + )); + } + + if ($result === false) { + try { + $this->session->set('OneDriveTokens', (object)array('token' => null)); + + $offline = ''; + // Gets a log in URL with sufficient privileges from the OneDrive API + if (!empty($options['offline'])) { + $offline = ' offline_access'; + } + + $redirect_uri = elFinder::getConnectorUrl() . '/netmount/onedrive/' . ($options['id'] === 'elfinder'? '1' : $options['id']); + $url = self::AUTH_URL + . '?client_id=' . urlencode($options['client_id']) + . '&scope=' . urlencode('files.readwrite.all' . $offline) + . '&response_type=code' + . '&redirect_uri=' . urlencode($redirect_uri); + + } catch (Exception $e) { + return array('exit' => true, 'body' => '{msg:errAccess}'); + } + + $html = ''; + $html .= ''; + + return array('exit' => true, 'body' => $html); + } else { + $folders = []; + + if ($result) { + foreach ($result as $res) { + $folders[$res->id] = $res->name; + } + natcasesort($folders); + } + + if ($options['pass'] === 'folders') { + return ['exit' => true, 'folders' => $folders]; + } + + $folders = ['root' => 'My OneDrive'] + $folders; + $folders = json_encode($folders); + + $expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0; + $mnt2res = empty($this->token->data->refresh_token) ? '' : ', "mnt2res": 1'; + $json = '{"protocol": "onedrive", "mode": "done", "folders": ' . $folders . ', "expires": ' . $expires . $mnt2res .'}'; + $html = 'OneDrive.com'; + $html .= ''; + + return array('exit' => true, 'body' => $html); + } + } + } catch (Exception $e) { + return array('exit' => true, 'body' => '{msg:errNetMountNoDriver}'); + } + + if ($_aToken = $this->session->get('OneDriveTokens')) { + $options['accessToken'] = json_encode($_aToken); + if ($this->options['path'] === 'root' || !$this->options['path']) { + $this->options['path'] = '/'; + } + } else { + $this->session->remove('OneDriveTokens'); + $this->setError(elFinder::ERROR_NETMOUNT, $options['host'], implode(' ', $this->error())); + + return array('exit' => true, 'error' => $this->error()); + } + + $this->session->remove('nodeId'); + unset($options['user'], $options['pass'], $options['id']); + + return $options; + } + + /** + * process of on netunmount + * Drop `onedrive` & rm thumbs. + * + * @param array $options + * + * @return bool + */ + public function netunmount($netVolumes, $key) + { + if (!$this->options['useApiThumbnail'] && ($tmbs = glob(rtrim($this->options['tmbPath'], '\\/') . DIRECTORY_SEPARATOR . $this->tmbPrefix . '*.png'))) { + foreach ($tmbs as $file) { + unlink($file); + } + } + + return true; + } + + /** + * Return debug info for client. + * + * @return array + **/ + public function debug() + { + $res = parent::debug(); + if (!empty($this->options['netkey']) && !empty($this->options['accessToken'])) { + $res['accessToken'] = $this->options['accessToken']; + } + + return $res; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare FTP connection + * Connect to remote server and check if credentials are correct, if so, store the connection id in $ftp_conn. + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + */ + protected function init() + { + if (!$this->options['accessToken']) { + return $this->setError('Required option `accessToken` is undefined.'); + } + + if (!empty($this->options['tmpPath'])) { + if ((is_dir($this->options['tmpPath']) || mkdir($this->options['tmpPath'])) && is_writable($this->options['tmpPath'])) { + $this->tmp = $this->options['tmpPath']; + } + } + + $error = false; + try { + $this->token = json_decode($this->options['accessToken']); + if (!is_object($this->token)) { + throw new Exception('Required option `accessToken` is invalid JSON.'); + } + + // make net mount key + if (empty($this->options['netkey'])) { + $this->netMountKey = $this->_od_getInitialToken(); + } else { + $this->netMountKey = $this->options['netkey']; + } + + if ($this->aTokenFile = $this->_od_getATokenFile()) { + if (empty($this->options['netkey'])) { + if ($this->aTokenFile) { + if (is_file($this->aTokenFile)) { + $this->token = json_decode(file_get_contents($this->aTokenFile)); + if (!is_object($this->token)) { + unlink($this->aTokenFile); + throw new Exception('Required option `accessToken` is invalid JSON.'); + } + } else { + file_put_contents($this->aTokenFile, $this->token); + } + } + } else if (is_file($this->aTokenFile)) { + // If the refresh token is the same as the permanent volume + $this->token = json_decode(file_get_contents($this->aTokenFile)); + } + } + + if ($this->needOnline) { + $this->_od_refreshToken(); + + $this->expires = empty($this->token->data->refresh_token) ? (int)$this->token->expires : 0; + } + } catch (Exception $e) { + $this->token = null; + $error = true; + $this->setError($e->getMessage()); + } + + if ($this->netMountKey) { + $this->tmbPrefix = 'onedrive' . base_convert($this->netMountKey, 16, 32); + } + + if ($error) { + if (empty($this->options['netkey']) && $this->tmbPrefix) { + // for delete thumbnail + $this->netunmount(null, null); + } + return false; + } + + // normalize root path + if ($this->options['path'] == 'root') { + $this->options['path'] = '/'; + } + + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + $this->options['root'] = ($this->options['root'] == '')? 'OneDrive.com' : $this->options['root']; + + if (empty($this->options['alias'])) { + if ($this->needOnline) { + $this->options['alias'] = ($this->options['path'] === '/') ? $this->options['root'] : + $this->_od_query(basename($this->options['path']), $fetch_self = true)->name . '@OneDrive'; + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } else { + $this->options['alias'] = $this->options['root']; + } + } + + $this->rootName = $this->options['alias']; + + // This driver dose not support `syncChkAsTs` + $this->options['syncChkAsTs'] = false; + + // 'lsPlSleep' minmum 10 sec + $this->options['lsPlSleep'] = max(10, $this->options['lsPlSleep']); + + $this->queryOptions = array( + 'query' => array( + 'select' => 'id,name,lastModifiedDateTime,file,folder,size,image', + ), + ); + + if ($this->options['useApiThumbnail']) { + $this->options['tmbURL'] = 'https://'; + $this->options['tmbPath'] = ''; + $this->queryOptions['query']['expand'] = 'thumbnails(select=small)'; + } + + // enable command archive + $this->options['useRemoteArchive'] = true; + + return true; + } + + /** + * Configure after successfull mount. + * + * @author Dmitry (dio) Levashov + **/ + protected function configure() + { + parent::configure(); + + // fallback of $this->tmp + if (!$this->tmp && $this->tmbPathWritable) { + $this->tmp = $this->tmbPath; + } + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection. + * + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + } + + protected function isNameExists($path) + { + list($pid, $name) = $this->_od_splitPath($path); + + $raw = $this->_od_query($pid . '/children/' . rawurlencode($name), true); + return $raw ? $this->_od_parseRaw($raw) : false; + } + + /** + * Cache dir contents. + * + * @param string $path dir path + * + * @return array + * @throws elFinderAbortException + * @author Dmitry Levashov + */ + protected function cacheDir($path) + { + $this->dirsCache[$path] = array(); + $hasDir = false; + + list(, $itemId) = $this->_od_splitPath($path); + + $res = $this->_od_query($itemId, false, false, $this->queryOptions); + + if ($res) { + foreach ($res as $raw) { + if ($stat = $this->_od_parseRaw($raw)) { + $itemPath = $this->_joinPath($path, $raw->id); + $stat = $this->updateCache($itemPath, $stat); + if (empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $itemPath; + } + } + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + + return $this->dirsCache[$path]; + } + + /** + * Copy file/recursive copy dir only in current volume. + * Return new file path or false. + * + * @param string $src source path + * @param string $dst destination dir path + * @param string $name new file name (optionaly) + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function copy($src, $dst, $name) + { + $itemId = ''; + if ($this->options['copyJoin']) { + $test = $this->joinPathCE($dst, $name); + if ($testStat = $this->isNameExists($test)) { + $this->remove($test); + } + } + + if ($path = $this->_copy($src, $dst, $name)) { + $this->added[] = $this->stat($path); + } else { + $this->setError(elFinder::ERROR_COPY, $this->_path($src)); + } + + return $path; + } + + /** + * Remove file/ recursive remove dir. + * + * @param string $path file path + * @param bool $force try to remove even if file locked + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function remove($path, $force = false) + { + $stat = $this->stat($path); + $stat['realpath'] = $path; + $this->rmTmb($stat); + $this->clearcache(); + + if (empty($stat)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path), elFinder::ERROR_FILE_NOT_FOUND); + } + + if (!$force && !empty($stat['locked'])) { + return $this->setError(elFinder::ERROR_LOCKED, $this->_path($path)); + } + + if ($stat['mime'] == 'directory') { + if (!$this->_rmdir($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } else { + if (!$this->_unlink($path)) { + return $this->setError(elFinder::ERROR_RM, $this->_path($path)); + } + } + + $this->removed[] = $stat; + + return true; + } + + /** + * Create thumnbnail and return it's URL on success. + * + * @param string $path file path + * @param $stat + * + * @return string|false + * @throws ImagickException + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Naoki Sawada + */ + protected function createTmb($path, $stat) + { + if ($this->options['useApiThumbnail']) { + if (func_num_args() > 2) { + list(, , $count) = func_get_args(); + } else { + $count = 0; + } + if ($count < 10) { + if (isset($stat['tmb']) && $stat['tmb'] != '1') { + return $stat['tmb']; + } else { + sleep(2); + elFinder::extendTimeLimit(); + $this->clearcache(); + $stat = $this->stat($path); + + return $this->createTmb($path, $stat, ++$count); + } + } + + return false; + } + if (!$stat || !$this->canCreateTmb($path, $stat)) { + return false; + } + + $name = $this->tmbname($stat); + $tmb = $this->tmbPath . DIRECTORY_SEPARATOR . $name; + + // copy image into tmbPath so some drivers does not store files on local fs + if (!$data = $this->_od_getThumbnail($path)) { + return false; + } + if (!file_put_contents($tmb, $data)) { + return false; + } + + $result = false; + + $tmbSize = $this->tmbSize; + + if (($s = getimagesize($tmb)) == false) { + return false; + } + + /* If image smaller or equal thumbnail size - just fitting to thumbnail square */ + if ($s[0] <= $tmbSize && $s[1] <= $tmbSize) { + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } else { + if ($this->options['tmbCrop']) { + + /* Resize and crop if image bigger than thumbnail */ + if (!(($s[0] > $tmbSize && $s[1] <= $tmbSize) || ($s[0] <= $tmbSize && $s[1] > $tmbSize)) || ($s[0] > $tmbSize && $s[1] > $tmbSize)) { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, false, 'png'); + } + + if (($s = getimagesize($tmb)) != false) { + $x = $s[0] > $tmbSize ? intval(($s[0] - $tmbSize) / 2) : 0; + $y = $s[1] > $tmbSize ? intval(($s[1] - $tmbSize) / 2) : 0; + $result = $this->imgCrop($tmb, $tmbSize, $tmbSize, $x, $y, 'png'); + } + } else { + $result = $this->imgResize($tmb, $tmbSize, $tmbSize, true, true, 'png'); + } + + $result = $this->imgSquareFit($tmb, $tmbSize, $tmbSize, 'center', 'middle', $this->options['tmbBgColor'], 'png'); + } + + if (!$result) { + unlink($tmb); + + return false; + } + + return $name; + } + + /** + * Return thumbnail file name for required file. + * + * @param array $stat file stat + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function tmbname($stat) + { + return $this->tmbPrefix . $stat['rev'] . $stat['ts'] . '.png'; + } + + /** + * Return content URL. + * + * @param string $hash file hash + * @param array $options options + * + * @return string + * @author Naoki Sawada + **/ + public function getContentUrl($hash, $options = array()) + { + if (!empty($options['onetime']) && $this->options['onetimeUrl']) { + return parent::getContentUrl($hash, $options); + } + if (!empty($options['temporary'])) { + // try make temporary file + $url = parent::getContentUrl($hash, $options); + if ($url) { + return $url; + } + } + $res = ''; + if (($file = $this->file($hash)) == false || !$file['url'] || $file['url'] == 1) { + $path = $this->decode($hash); + + list(, $itemId) = $this->_od_splitPath($path); + try { + $url = self::API_URL . $itemId . '/createLink'; + $data = (object)array( + 'type' => 'embed', + 'scope' => 'anonymous', + ); + $curl = $this->_od_prepareCurl($url); + curl_setopt_array($curl, array( + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($data), + )); + + $result = elFinder::curlExec($curl); + if ($result) { + $result = json_decode($result); + if (isset($result->link)) { + // list(, $res) = explode('?', $result->link->webUrl); + // $res = 'https://onedrive.live.com/download.aspx?' . $res; + $res = $result->link->webUrl; + } + } + } catch (Exception $e) { + $res = ''; + } + } + + return $res; + } + + /*********************** paths/urls *************************/ + + /** + * Return parent directory path. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _dirname($path) + { + list(, , $dirname) = $this->_od_splitPath($path); + + return $dirname; + } + + /** + * Return file name. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _basename($path) + { + list(, $basename) = $this->_od_splitPath($path); + + return $basename; + } + + /** + * Join dir name and file name and retur full path. + * + * @param string $dir + * @param string $name + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _joinPath($dir, $name) + { + if ($dir === 'root') { + $dir = ''; + } + + return $this->_normpath($dir . '/' . $name); + } + + /** + * Return normalized path, this works the same as os.path.normpath() in Python. + * + * @param string $path path + * + * @return string + * @author Troex Nevelin + **/ + protected function _normpath($path) + { + if (DIRECTORY_SEPARATOR !== '/') { + $path = str_replace(DIRECTORY_SEPARATOR, '/', $path); + } + $path = '/' . ltrim($path, '/'); + + return $path; + } + + /** + * Return file path related to root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _relpath($path) + { + return $path; + } + + /** + * Convert path related to root dir into real path. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _abspath($path) + { + return $path; + } + + /** + * Return fake path started from root dir. + * + * @param string $path file path + * + * @return string + * @author Dmitry (dio) Levashov + **/ + protected function _path($path) + { + return $this->rootName . $this->_normpath(substr($path, strlen($this->root))); + } + + /** + * Return true if $path is children of $parent. + * + * @param string $path path to check + * @param string $parent parent path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _inpath($path, $parent) + { + return $path == $parent || strpos($path, $parent . '/') === 0; + } + + /***************** file stat ********************/ + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally. + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + if ($raw = $this->_od_getFileRaw($path)) { + $stat = $this->_od_parseRaw($raw); + if ($path === $this->root) { + $stat['expires'] = $this->expires; + } + return $stat; + } + + return false; + } + + /** + * Return true if path is dir and has at least one childs directory. + * + * @param string $path dir path + * + * @return bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _subdirs($path) + { + list(, $itemId) = $this->_od_splitPath($path); + + return (bool)$this->_od_query($itemId, false, false, array( + 'query' => array( + 'top' => 1, + 'select' => 'id', + 'filter' => 'folder ne null', + ), + )); + } + + /** + * Return object width and height + * Ususaly used for images, but can be realize for video etc... + * + * @param string $path file path + * @param string $mime file mime type + * + * @return string + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _dimensions($path, $mime) + { + if (strpos($mime, 'image') !== 0) { + return ''; + } + + //$cache = $this->_od_getFileRaw($path); + if (func_num_args() > 2) { + $args = func_get_arg(2); + } else { + $args = array(); + } + if (!empty($args['substitute'])) { + $tmbSize = intval($args['substitute']); + } else { + $tmbSize = null; + } + list(, $itemId) = $this->_od_splitPath($path); + $options = array( + 'query' => array( + 'select' => 'id,image', + ), + ); + if ($tmbSize) { + $tmb = 'c' . $tmbSize . 'x' . $tmbSize; + $options['query']['expand'] = 'thumbnails(select=' . $tmb . ')'; + } + $raw = $this->_od_query($itemId, true, false, $options); + + if ($raw && property_exists($raw, 'image') && $img = $raw->image) { + if (isset($img->width) && isset($img->height)) { + $ret = array('dim' => $img->width . 'x' . $img->height); + if ($tmbSize) { + $srcSize = explode('x', $ret['dim']); + if (min(($tmbSize / $srcSize[0]), ($tmbSize / $srcSize[1])) < 1) { + if (!empty($raw->thumbnails)) { + $tmbArr = (array)$raw->thumbnails[0]; + if (!empty($tmbArr[$tmb]->url)) { + $ret['url'] = $tmbArr[$tmb]->url; + } + } + } + } + + return $ret; + } + } + + $ret = ''; + if ($work = $this->getWorkFile($path)) { + if ($size = @getimagesize($work)) { + $cache['width'] = $size[0]; + $cache['height'] = $size[1]; + $ret = $size[0] . 'x' . $size[1]; + } + } + is_file($work) && @unlink($work); + + return $ret; + } + + /******************** file/dir content *********************/ + + /** + * Return files list in directory. + * + * @param string $path dir path + * + * @return array + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + */ + protected function _scandir($path) + { + return isset($this->dirsCache[$path]) + ? $this->dirsCache[$path] + : $this->cacheDir($path); + } + + /** + * Open file and return file pointer. + * + * @param string $path file path + * @param bool $write open file for writing + * + * @return resource|false + * @author Dmitry (dio) Levashov + **/ + protected function _fopen($path, $mode = 'rb') + { + if ($mode === 'rb' || $mode === 'r') { + list(, $itemId) = $this->_od_splitPath($path); + $data = array( + 'target' => self::API_URL . $itemId . '/content', + 'headers' => array('Authorization: Bearer ' . $this->token->data->access_token), + ); + + // to support range request + if (func_num_args() > 2) { + $opts = func_get_arg(2); + } else { + $opts = array(); + } + if (!empty($opts['httpheaders'])) { + $data['headers'] = array_merge($opts['httpheaders'], $data['headers']); + } + + return elFinder::getStreamByUrl($data); + } + + return false; + } + + /** + * Close opened file. + * + * @param resource $fp file pointer + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + if ($path) { + unlink($this->getTempFile($path)); + } + } + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed. + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + $namePath = $this->_joinPath($path, $name); + list($parentId) = $this->_od_splitPath($namePath); + + try { + $properties = array( + 'name' => (string)$name, + 'folder' => (object)array(), + ); + + $data = (object)$properties; + + $url = self::API_URL . $parentId . '/children'; + + $curl = $this->_od_prepareCurl($url); + + curl_setopt_array($curl, array( + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($data), + )); + + //create the Folder in the Parent + $result = elFinder::curlExec($curl); + $folder = json_decode($result); + + return $this->_joinPath($path, $folder->id); + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + } + + /** + * Create file and return it's path or false on failed. + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkfile($path, $name) + { + return $this->_save($this->tmpfile(), $path, $name, array()); + } + + /** + * Create symlink. FTP driver does not support symlinks. + * + * @param string $target link target + * @param string $path symlink path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _symlink($target, $path, $name) + { + return false; + } + + /** + * Copy file into another file. + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _copy($source, $targetDir, $name) + { + $path = $this->_joinPath($targetDir, $name); + + try { + //Set the Parent id + list(, $parentId) = $this->_od_splitPath($targetDir); + list(, $itemId) = $this->_od_splitPath($source); + + $url = self::API_URL . $itemId . '/copy'; + + $properties = array( + 'name' => (string)$name, + ); + if ($parentId === 'root') { + $properties['parentReference'] = (object)array('path' => '/drive/root:'); + } else { + $properties['parentReference'] = (object)array('id' => (string)$parentId); + } + $data = (object)$properties; + $curl = $this->_od_prepareCurl($url); + curl_setopt_array($curl, array( + CURLOPT_POST => true, + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/json', + 'Authorization: Bearer ' . $this->token->data->access_token, + 'Prefer: respond-async', + ), + CURLOPT_POSTFIELDS => json_encode($data), + )); + $result = elFinder::curlExec($curl); + + $res = new stdClass(); + if (preg_match('/Location: (.+)/', $result, $m)) { + $monUrl = trim($m[1]); + while ($res) { + usleep(200000); + $curl = curl_init($monUrl); + curl_setopt_array($curl, array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/json', + ), + )); + $res = json_decode(elFinder::curlExec($curl)); + if (isset($res->status)) { + if ($res->status === 'completed' || $res->status === 'failed') { + break; + } + } elseif (isset($res->error)) { + return $this->setError('OneDrive error: ' . $res->error->message); + } + } + } + + if ($res && isset($res->resourceId)) { + if (isset($res->folder) && isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$targetDir] = true; + } + + return $this->_joinPath($targetDir, $res->resourceId); + } + + return false; + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return string|bool + * @author Dmitry (dio) Levashov + */ + protected function _move($source, $targetDir, $name) + { + try { + list(, $targetParentId) = $this->_od_splitPath($targetDir); + list($sourceParentId, $itemId, $srcParent) = $this->_od_splitPath($source); + + $properties = array( + 'name' => (string)$name, + ); + if ($targetParentId !== $sourceParentId) { + $properties['parentReference'] = (object)array('id' => (string)$targetParentId); + } + + $url = self::API_URL . $itemId; + $data = (object)$properties; + + $curl = $this->_od_prepareCurl($url); + + curl_setopt_array($curl, array( + CURLOPT_CUSTOMREQUEST => 'PATCH', + CURLOPT_POSTFIELDS => json_encode($data), + )); + + $result = json_decode(elFinder::curlExec($curl)); + if ($result && isset($result->id)) { + return $targetDir . '/' . $result->id; + } else { + return false; + } + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + + return false; + } + + /** + * Remove file. + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + $stat = $this->stat($path); + try { + list(, $itemId) = $this->_od_splitPath($path); + + $url = self::API_URL . $itemId; + + $curl = $this->_od_prepareCurl($url); + curl_setopt_array($curl, array( + CURLOPT_CUSTOMREQUEST => 'DELETE', + )); + + //unlink or delete File or Folder in the Parent + $result = elFinder::curlExec($curl); + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + + return true; + } + + /** + * Remove dir. + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + return $this->_unlink($path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param $path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + */ + protected function _save($fp, $path, $name, $stat) + { + $itemId = ''; + $size = null; + if ($name === '') { + list($parentId, $itemId, $parent) = $this->_od_splitPath($path); + } else { + if ($stat) { + if (isset($stat['name'])) { + $name = $stat['name']; + } + if (isset($stat['rev']) && strpos($stat['hash'], $this->id) === 0) { + $itemId = $stat['rev']; + } + } + list(, $parentId) = $this->_od_splitPath($path); + $parent = $path; + } + + if ($stat && isset($stat['size'])) { + $size = $stat['size']; + } else { + $stats = fstat($fp); + if (isset($stats[7])) { + $size = $stats[7]; + } + } + + if ($size > 4194304) { + return $this->_od_uploadSession($fp, $size, $name, $itemId, $parent, $parentId); + } + + try { + // for unseekable file pointer + if (!elFinder::isSeekableStream($fp)) { + if ($tfp = tmpfile()) { + if (stream_copy_to_stream($fp, $tfp, $size? $size : -1) !== false) { + rewind($tfp); + $fp = $tfp; + } + } + } + + //Create or Update a file + if ($itemId === '') { + $url = self::API_URL . $parentId . ':/' . rawurlencode($name) . ':/content'; + } else { + $url = self::API_URL . $itemId . '/content'; + } + $curl = $this->_od_prepareCurl(); + + $options = array( + CURLOPT_URL => $url, + CURLOPT_PUT => true, + CURLOPT_INFILE => $fp, + ); + // Size + if ($size !== null) { + $options[CURLOPT_INFILESIZE] = $size; + } + + curl_setopt_array($curl, $options); + + //create or update File in the Target + $file = json_decode(elFinder::curlExec($curl)); + + return $this->_joinPath($parent, $file->id); + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + } + + /** + * Get file contents. + * + * @param string $path file path + * + * @return string|false + * @author Dmitry (dio) Levashov + **/ + protected function _getContents($path) + { + $contents = ''; + + try { + list(, $itemId) = $this->_od_splitPath($path); + $url = self::API_URL . $itemId . '/content'; + $contents = $this->_od_createCurl($url, $contents = true); + } catch (Exception $e) { + return $this->setError('OneDrive error: ' . $e->getMessage()); + } + + return $contents; + } + + /** + * Write a string to a file. + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + $res = false; + + if ($local = $this->getTempFile($path)) { + if (file_put_contents($local, $content, LOCK_EX) !== false + && ($fp = fopen($local, 'rb'))) { + clearstatcache(); + $res = $this->_save($fp, $path, '', array()); + fclose($fp); + } + file_exists($local) && unlink($local); + } + + return $res; + } + + /** + * Detect available archivers. + **/ + protected function _checkArchivers() + { + // die('Not yet implemented. (_checkArchivers)'); + return array(); + } + + /** + * chmod implementation. + * + * @return bool + **/ + protected function _chmod($path, $mode) + { + return false; + } + + /** + * Unpack archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return void + * @author Dmitry (dio) Levashov + * @author Alexey Sukhotin + */ + protected function _unpack($path, $arc) + { + die('Not yet implemented. (_unpack)'); + //return false; + } + + /** + * Extract files from archive. + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return void + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _extract($path, $arc) + { + die('Not yet implemented. (_extract)'); + } + + /** + * Create archive and return its path. + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + **/ + protected function _archive($dir, $files, $name, $arc) + { + die('Not yet implemented. (_archive)'); + } +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeSFTPphpseclib.class.php b/lib/redactor/elfinder/php/elFinderVolumeSFTPphpseclib.class.php new file mode 100644 index 0000000..2225773 --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeSFTPphpseclib.class.php @@ -0,0 +1,853 @@ + 'localhost', + 'user' => '', + 'pass' => '', + 'port' => 22, + 'path' => '/', + 'timeout' => 20, + 'owner' => true, + 'tmbPath' => '', + 'tmpPath' => '', + 'separator' => '/', + 'phpseclibDir' => '../phpseclib/', + 'connectCallback' => null, //provide your own already instantiated phpseclib $Sftp object returned by this callback + //'connectCallback'=> function($options) { + // //load and instantiate phpseclib $sftp + // return $sftp; + // }, + 'checkSubfolders' => -1, + 'dirMode' => 0755, + 'fileMode' => 0644, + 'rootCssClass' => 'elfinder-navbar-root-ftp', + ); + $this->options = array_merge($this->options, $opts); + $this->options['mimeDetect'] = 'internal'; + } + + /** + * Prepare + * Call from elFinder::netmout() before volume->mount() + * + * @param $options + * + * @return array volume root options + * @author Naoki Sawada + */ + public function netmountPrepare($options) + { + $options['statOwner'] = true; + $options['allowChmodReadOnly'] = true; + $options['acceptedName'] = '#^[^/\\?*:|"<>]*[^./\\?*:|"<>]$#'; + return $options; + } + + /*********************************************************************/ + /* INIT AND CONFIGURE */ + /*********************************************************************/ + + /** + * Prepare SFTP connection + * Connect to remote server and check if credentials are correct, if so, store the connection + * + * @return bool + * @author Dmitry (dio) Levashov + * @author Cem (DiscoFever) + **/ + protected function init() + { + if (!$this->options['connectCallback']) { + if (!$this->options['host'] + || !$this->options['port']) { + return $this->setError('Required options undefined.'); + } + + if (!$this->options['path']) { + $this->options['path'] = '/'; + } + + // make net mount key + $this->netMountKey = md5(join('-', array('sftpphpseclib', $this->options['host'], $this->options['port'], $this->options['path'], $this->options['user']))); + + set_include_path(get_include_path() . PATH_SEPARATOR . getcwd().'/'.$this->options['phpseclibDir']); + include_once('Net/SFTP.php'); + + if (!class_exists('Net_SFTP')) { + return $this->setError('SFTP extension not loaded. Install phpseclib version 1: http://phpseclib.sourceforge.net/ Set option "phpseclibDir" accordingly.'); + } + + // remove protocol from host + $scheme = parse_url($this->options['host'], PHP_URL_SCHEME); + + if ($scheme) { + $this->options['host'] = substr($this->options['host'], strlen($scheme) + 3); + } + } else { + // make net mount key + $this->netMountKey = md5(join('-', array('sftpphpseclib', $this->options['path']))); + } + + // normalize root path + $this->root = $this->options['path'] = $this->_normpath($this->options['path']); + + if (empty($this->options['alias'])) { + $this->options['alias'] = $this->options['user'] . '@' . $this->options['host']; + if (!empty($this->options['netkey'])) { + elFinder::$instance->updateNetVolumeOption($this->options['netkey'], 'alias', $this->options['alias']); + } + } + + $this->rootName = $this->options['alias']; + $this->options['separator'] = '/'; + + if (is_null($this->options['syncChkAsTs'])) { + $this->options['syncChkAsTs'] = true; + } + + return $this->needOnline? $this->connect() : true; + + } + + + /** + * Configure after successfull mount. + * + * @return void + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function configure() + { + parent::configure(); + + if (!$this->tmp) { + $this->disabled[] = 'mkfile'; + $this->disabled[] = 'paste'; + $this->disabled[] = 'upload'; + $this->disabled[] = 'edit'; + //$this->disabled[] = 'archive'; + //$this->disabled[] = 'extract'; + } + + $this->disabled[] = 'archive'; + $this->disabled[] = 'extract'; + } + + /** + * Connect to sftp server + * + * @return bool + * @author sitecode + **/ + protected function connect() + { + //use ca + if ($this->options['connectCallback']) { + $this->connect = $this->options['connectCallback']($this->options); + if (!$this->connect || !$this->connect->isConnected()) { + return $this->setError('Unable to connect successfully'); + } + + return true; + } + + try{ + $host = $this->options['host'] . ($this->options['port'] != 22 ? ':' . $this->options['port'] : ''); + $this->connect = new Net_SFTP($host); + //TODO check fingerprint before login, fail if no match to last time + if (!$this->connect->login($this->options['user'], $this->options['pass'])) { + return $this->setError('Unable to connect to SFTP server ' . $host); + } + } catch (Exception $e) { + return $this->setError('Error while connecting to SFTP server ' . $host . ': ' . $e->getMessage()); + } + + if (!$this->connect->chdir($this->root) + /*|| $this->root != $this->connect->pwd()*/) { + //$this->umount(); + return $this->setError('Unable to open root folder.'); + } + + return true; + } + + /** + * Call rawlist + * + * @param string $path + * + * @return array + */ + protected function ftpRawList($path) + { + return $this->connect->rawlist($path ?: '.') ?: []; + } + + /*********************************************************************/ + /* FS API */ + /*********************************************************************/ + + /** + * Close opened connection + * + * @return void + * @author Dmitry (dio) Levashov + **/ + public function umount() + { + $this->connect && $this->connect->disconnect(); + } + + + /** + * Parse line from rawlist() output and return file stat (array) + * + * @param array $info from rawlist() output + * @param $base + * @param bool $nameOnly + * + * @return array + * @author Dmitry Levashov + */ + protected function parseRaw($info, $base, $nameOnly = false) + { + $stat = array(); + + if ($info['filename'] == '.' || $info['filename'] == '..') { + return false; + } + + $name = $info['filename']; + //for compatability with phpseclib version 2/3 + if (empty($info['permissions'])) { + $info['permissions'] = $info['mode']; + } + + if ($info['type'] === 3) { + // check recursive processing + if ($this->cacheDirTarget && $this->_joinPath($base, $name) !== $this->cacheDirTarget) { + return array(); + } + if (!$nameOnly) { + $target = $this->connect->readlink($name); + if (substr($target, 0, 1) !== $this->separator) { + $target = $this->getFullPath($target, $base); + } + $target = $this->_normpath($target); + $stat['name'] = $name; + $stat['target'] = $target; + return $stat; + } + } + + if ($nameOnly) { + return array('name' => $name); + } + + $stat['ts'] = $info['mtime']; + + if ($this->options['statOwner']) { + $stat['owner'] = $info['uid']; + $stat['group'] = $info['gid']; + $stat['perm'] = $info['permissions']; + $stat['isowner'] = isset($stat['owner']) ? ($this->options['owner'] ? true : ($stat['owner'] == $this->options['user'])) : true; + } + + $owner_computed = isset($stat['isowner']) ? $stat['isowner'] : $this->options['owner']; + $perm = $this->parsePermissions($info['permissions'], $owner_computed); + $stat['name'] = $name; + if ($info['type'] === NET_SFTP_TYPE_DIRECTORY) { + $stat['mime'] = 'directory'; + $stat['size'] = 0; + + } elseif ($info['type'] === NET_SFTP_TYPE_SYMLINK) { + $stat['mime'] = 'symlink'; + $stat['size'] = 0; + + } else { + $stat['mime'] = $this->mimetype($stat['name'], true); + $stat['size'] = $info['size']; + } + + $stat['read'] = $perm['read']; + $stat['write'] = $perm['write']; + + return $stat; + } + + /** + * Parse permissions string. Return array(read => true/false, write => true/false) + * + * @param int $perm + * The isowner parameter is computed by the caller. + * If the owner parameter in the options is true, the user is the actual owner of all objects even if the user used in the ftp Login + * is different from the file owner id. + * If the owner parameter is false to understand if the user is the file owner we compare the ftp user with the file owner id. + * @param Boolean $isowner . Tell if the current user is the owner of the object. + * + * @return array + * @author Dmitry (dio) Levashov + * @author sitecode + */ + protected function parsePermissions($permissions, $isowner = true) + { + $permissions = decoct($permissions); + $perm = $isowner ? decbin((int)$permissions[-3]) : decbin((int)$permissions[-1]); + + return array( + 'read' => $perm[-3], + 'write' => $perm[-2] + ); + } + + /** + * Cache dir contents + * + * @param string $path dir path + * + * @return void + * @author Dmitry Levashov, sitecode + **/ + protected function cacheDir($path) + { + $this->dirsCache[$path] = array(); + $hasDir = false; + + $list = array(); + $encPath = $this->convEncIn($path); + foreach ($this->ftpRawList($encPath) as $info) { + if (($stat = $this->parseRaw($info, $encPath))) { + $list[] = $stat; + } + } + $list = $this->convEncOut($list); + $prefix = ($path === $this->separator) ? $this->separator : $path . $this->separator; + $targets = array(); + foreach ($list as $stat) { + $p = $prefix . $stat['name']; + if (isset($stat['target'])) { + // stat later + $targets[$stat['name']] = $stat['target']; + } else { + $stat = $this->updateCache($p, $stat); + if (empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } elseif (!$hasDir && $stat['mime'] === 'symlink') { + $hasDir = true; + } + $this->dirsCache[$path][] = $p; + } + } + } + // stat link targets + foreach ($targets as $name => $target) { + $stat = array(); + $stat['name'] = $name; + $p = $prefix . $name; + $cacheDirTarget = $this->cacheDirTarget; + $this->cacheDirTarget = $this->convEncIn($target, true); + if ($tstat = $this->stat($target)) { + $stat['size'] = $tstat['size']; + $stat['alias'] = $target; + $stat['thash'] = $tstat['hash']; + $stat['mime'] = $tstat['mime']; + $stat['read'] = $tstat['read']; + $stat['write'] = $tstat['write']; + + if (isset($tstat['ts'])) { + $stat['ts'] = $tstat['ts']; + } + if (isset($tstat['owner'])) { + $stat['owner'] = $tstat['owner']; + } + if (isset($tstat['group'])) { + $stat['group'] = $tstat['group']; + } + if (isset($tstat['perm'])) { + $stat['perm'] = $tstat['perm']; + } + if (isset($tstat['isowner'])) { + $stat['isowner'] = $tstat['isowner']; + } + } else { + + $stat['mime'] = 'symlink-broken'; + $stat['read'] = false; + $stat['write'] = false; + $stat['size'] = 0; + + } + $this->cacheDirTarget = $cacheDirTarget; + $stat = $this->updateCache($p, $stat); + if (empty($stat['hidden'])) { + if (!$hasDir && $stat['mime'] === 'directory') { + $hasDir = true; + } + $this->dirsCache[$path][] = $p; + } + } + + if (isset($this->sessionCache['subdirs'])) { + $this->sessionCache['subdirs'][$path] = $hasDir; + } + } + + + /***************** file stat ********************/ + + /** + * Return stat for given path. + * Stat contains following fields: + * - (int) size file size in b. required + * - (int) ts file modification time in unix time. required + * - (string) mime mimetype. required for folders, others - optionally + * - (bool) read read permissions. required + * - (bool) write write permissions. required + * - (bool) locked is object locked. optionally + * - (bool) hidden is object hidden. optionally + * - (string) alias for symlinks - link target path relative to root path. optionally + * - (string) target for symlinks - link target path. optionally + * If file does not exists - returns empty array or false. + * + * @param string $path file path + * + * @return array|false + * @author Dmitry (dio) Levashov + **/ + protected function _stat($path) + { + $outPath = $this->convEncOut($path); + if (isset($this->cache[$outPath])) { + return $this->convEncIn($this->cache[$outPath]); + } else { + $this->convEncIn(); + } + if ($path === $this->root) { + $res = array( + 'name' => $this->root, + 'mime' => 'directory', + 'dirs' => -1 + ); + if ($this->needOnline && (($this->ARGS['cmd'] === 'open' && $this->ARGS['target'] === $this->encode($this->root)) || $this->isMyReload())) { + $check = array( + 'ts' => true, + 'dirs' => true, + ); + $ts = 0; + foreach ($this->ftpRawList($path) as $info) { + if ($info['filename'] === '.') { + $info['filename'] = 'root'; + if ($stat = $this->parseRaw($info, $path)) { + unset($stat['name']); + $res = array_merge($res, $stat); + if ($res['ts']) { + $ts = 0; + unset($check['ts']); + } + } + } + if ($check && ($stat = $this->parseRaw($info, $path))) { + if (isset($stat['ts']) && !empty($stat['ts'])) { + $ts = max($ts, $stat['ts']); + } + if (isset($stat['dirs']) && $stat['mime'] === 'directory') { + $res['dirs'] = 1; + unset($stat['dirs']); + } + if (!$check) { + break; + } + } + } + if ($ts) { + $res['ts'] = $ts; + } + $this->cache[$outPath] = $res; + } + return $res; + } + + $pPath = $this->_dirname($path); + if ($this->_inPath($pPath, $this->root)) { + $outPPpath = $this->convEncOut($pPath); + if (!isset($this->dirsCache[$outPPpath])) { + $parentSubdirs = null; + if (isset($this->sessionCache['subdirs']) && isset($this->sessionCache['subdirs'][$outPPpath])) { + $parentSubdirs = $this->sessionCache['subdirs'][$outPPpath]; + } + $this->cacheDir($outPPpath); + if ($parentSubdirs) { + $this->sessionCache['subdirs'][$outPPpath] = $parentSubdirs; + } + } + } + + $stat = $this->convEncIn(isset($this->cache[$outPath]) ? $this->cache[$outPath] : array()); + if (!$this->mounted) { + // dispose incomplete cache made by calling `stat` by 'startPath' option + $this->cache = array(); + } + + return $stat; + } + + /** + * Return true if path is dir and has at least one childs directory + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov, sitecode + **/ + protected function _subdirs($path) + { + foreach ($this->ftpRawList($path) as $info) { + $name = $info['filename']; + if ($name && $name !== '.' && $name !== '..' && $info['type'] == NET_SFTP_TYPE_DIRECTORY) { + return true; + } + if ($name && $name !== '.' && $name !== '..' && $info['type'] == NET_SFTP_TYPE_SYMLINK) { + //return true; + } + } + + return false; + } + + + /******************** file/dir content *********************/ + + /** + * Open file and return file pointer + * + * @param string $path file path + * @param string $mode + * + * @return false|resource + * @throws elFinderAbortException + * @internal param bool $write open file for writing + * @author Dmitry (dio) Levashov + */ + protected function _fopen($path, $mode = 'rb') + { + if ($this->tmp) { + $local = $this->getTempFile($path); + $this->connect->get($path, $local); + return @fopen($local, $mode); + } + + return false; + } + + /** + * Close opened file + * + * @param resource $fp file pointer + * @param string $path + * + * @return void + * @author Dmitry (dio) Levashov + */ + protected function _fclose($fp, $path = '') + { + is_resource($fp) && fclose($fp); + if ($path) { + unlink($this->getTempFile($path)); + } + } + + + /******************** file/dir manipulations *************************/ + + /** + * Create dir and return created dir path or false on failed + * + * @param string $path parent dir path + * @param string $name new directory name + * + * @return string|bool + * @author Dmitry (dio) Levashov + **/ + protected function _mkdir($path, $name) + { + $path = $this->_joinPath($path, $this->_basename($name)); + if ($this->connect->mkdir($path) === false) { + return false; + } + + $this->options['dirMode'] && $this->connect->chmod($this->options['dirMode'], $path); + return $path; + } + + /** + * Create file and return it's path or false on failed + * + * @param string $path parent dir path + * @param string $name new file name + * + * @return string|bool + * @author sitecode + **/ + protected function _mkfile($path, $name) + { + $path = $this->_joinPath($path, $this->_basename($name)); + return $this->connect->put($path, '') ? $path : false; +/* + if ($this->tmp) { + $path = $this->_joinPath($path, $name); + $local = $this->getTempFile(); + $res = touch($local) && $this->connect->put($path, $local, self::NET_SFTP_LOCAL_FILE); + unlink($local); + return $res ? $path : false; + } + + return false; + */ + } + + /** + * Copy file into another file + * + * @param string $source source file path + * @param string $targetDir target directory path + * @param string $name new file name + * + * @return bool + * @author Dmitry (dio) Levashov, sitecode + **/ + protected function _copy($source, $targetDir, $name) + { + $res = false; + + $target = $this->_joinPath($targetDir, $this->_basename($name)); + if ($this->tmp) { + $local = $this->getTempFile(); + + if ($this->connect->get($source, $local) + && $this->connect->put($target, $local, self::NET_SFTP_LOCAL_FILE)) { + $res = true; + } + unlink($local); + } else { + //not memory efficient + $res = $this->_filePutContents($target, $this->_getContents($source)); + } + + return $res; + } + + /** + * Move file into another parent dir. + * Return new file path or false. + * + * @param string $source source file path + * @param $targetDir + * @param string $name file name + * + * @return bool|string + * @internal param string $target target dir path + * @author Dmitry (dio) Levashov + */ + protected function _move($source, $targetDir, $name) + { + $target = $this->_joinPath($targetDir, $this->_basename($name)); + return $this->connect->rename($source, $target) ? $target : false; + } + + /** + * Remove file + * + * @param string $path file path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _unlink($path) + { + return $this->connect->delete($path, false); + } + + /** + * Remove dir + * + * @param string $path dir path + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _rmdir($path) + { + return $this->connect->delete($path); + } + + /** + * Create new file and write into it from file pointer. + * Return new file path or false on error. + * + * @param resource $fp file pointer + * @param string $dir target dir path + * @param string $name file name + * @param array $stat file stat (required by some virtual fs) + * + * @return bool|string + * @author Dmitry (dio) Levashov + **/ + protected function _save($fp, $dir, $name, $stat) + { + //TODO optionally encrypt $fp before uploading if mime is not already encrypted type + $path = $this->_joinPath($dir, $this->_basename($name)); + return $this->connect->put($path, $fp) + ? $path + : false; + } + + /** + * Get file contents + * + * @param string $path file path + * + * @return string|false + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov + */ + protected function _getContents($path) + { + return $this->connect->get($path); + } + + /** + * Write a string to a file + * + * @param string $path file path + * @param string $content new file content + * + * @return bool + * @author Dmitry (dio) Levashov + **/ + protected function _filePutContents($path, $content) + { + return $this->connect->put($path, $content); + } + + /** + * chmod availability + * + * @param string $path + * @param string $mode + * + * @return bool + */ + protected function _chmod($path, $mode) + { + $modeOct = is_string($mode) ? octdec($mode) : octdec(sprintf("%04o", $mode)); + return $this->connect->chmod($modeOct, $path); + } + + /** + * Extract files from archive + * + * @param string $path archive path + * @param array $arc archiver command and arguments (same as in $this->archivers) + * + * @return true + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _extract($path, $arc) + { + return false; //TODO + } + + /** + * Create archive and return its path + * + * @param string $dir target dir + * @param array $files files names list + * @param string $name archive name + * @param array $arc archiver options + * + * @return string|bool + * @throws elFinderAbortException + * @author Dmitry (dio) Levashov, + * @author Alexey Sukhotin + */ + protected function _archive($dir, $files, $name, $arc) + { + return false; //TODO + } + + /** + * Gets an array of absolute remote SFTP paths of files and + * folders in $remote_directory omitting symbolic links. + * + * @param $remote_directory string remote SFTP path to scan for file and folders recursively + * @param $targets array Array of target item. `null` is to get all of items + * + * @return array of elements each of which is an array of two elements: + *
                        + *
                      • $item['path'] - absolute remote SFTP path
                      • + *
                      • $item['type'] - either 'f' for file or 'd' for directory
                      • + *
                      + */ + protected function ftp_scan_dir($remote_directory, $targets = null) + { + $buff = $this->ftpRawList($remote_directory); + $items = array(); + if ($targets && is_array($targets)) { + $targets = array_flip($targets); + } else { + $targets = false; + } + foreach ($buff as $info) { + $name = $info['filename']; + if ($name !== '.' && $name !== '..' && (!$targets || isset($targets[$name]))) { + switch ($info['type']) { + case NET_SFTP_TYPE_SYMLINK : //omit symbolic links + case NET_SFTP_TYPE_DIRECTORY : + $remote_file_path = $this->_joinPath($remote_directory, $name); + $item = array(); + $item['path'] = $remote_file_path; + $item['type'] = 'd'; // normal file + $items[] = $item; + $items = array_merge($items, $this->ftp_scan_dir($remote_file_path)); + break; + default: + $remote_file_path = $this->_joinPath($remote_directory, $name); + $item = array(); + $item['path'] = $remote_file_path; + $item['type'] = 'f'; // normal file + $items[] = $item; + } + } + } + return $items; + } + +} // END class diff --git a/lib/redactor/elfinder/php/elFinderVolumeTrash.class.php b/lib/redactor/elfinder/php/elFinderVolumeTrash.class.php new file mode 100644 index 0000000..5140e7d --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeTrash.class.php @@ -0,0 +1,51 @@ +options['lockEverything'] = false; // Lock all items in the trash to disable delete, move, rename. + + // common options as the volume driver + $this->options['alias'] = 'Trash'; + $this->options['quarantine'] = ''; + $this->options['rootCssClass'] = 'elfinder-navbar-root-trash'; + $this->options['copyOverwrite'] = false; + $this->options['uiCmdMap'] = array('paste' => 'hidden', 'mkdir' => 'hidden', 'copy' => 'restore'); + $this->options['disabled'] = array('archive', 'duplicate', 'edit', 'extract', 'mkfile', 'places', 'put', 'rename', 'resize', 'upload'); + } + + public function mount(array $opts) + { + if ($this->options['lockEverything']) { + if (!is_array($opts['attributes'])) { + $opts['attributes'] = array(); + } + $attr = array( + 'pattern' => '/./', + 'locked' => true, + ); + array_unshift($opts['attributes'], $attr); + } + // force set `copyJoin` to true + $opts['copyJoin'] = true; + + return parent::mount($opts); + } +} diff --git a/lib/redactor/elfinder/php/elFinderVolumeTrashMySQL.class.php b/lib/redactor/elfinder/php/elFinderVolumeTrashMySQL.class.php new file mode 100644 index 0000000..6d6307e --- /dev/null +++ b/lib/redactor/elfinder/php/elFinderVolumeTrashMySQL.class.php @@ -0,0 +1,51 @@ +options['lockEverything'] = false; // Lock all items in the trash to disable delete, move, rename. + + // common options as the volume driver + $this->options['alias'] = 'Trash'; + $this->options['quarantine'] = ''; + $this->options['rootCssClass'] = 'elfinder-navbar-root-trash'; + $this->options['copyOverwrite'] = false; + $this->options['uiCmdMap'] = array('paste' => 'hidden', 'mkdir' => 'hidden', 'copy' => 'restore'); + $this->options['disabled'] = array('archive', 'duplicate', 'edit', 'extract', 'mkfile', 'places', 'put', 'rename', 'resize', 'upload'); + } + + public function mount(array $opts) + { + if ($this->options['lockEverything']) { + if (!is_array($opts['attributes'])) { + $opts['attributes'] = array(); + } + $attr = array( + 'pattern' => '/./', + 'locked' => true, + ); + array_unshift($opts['attributes'], $attr); + } + // force set `copyJoin` to true + $opts['copyJoin'] = true; + + return parent::mount($opts); + } +} diff --git a/lib/redactor/elfinder/php/libs/GdBmp.php b/lib/redactor/elfinder/php/libs/GdBmp.php new file mode 100644 index 0000000..0b51f38 --- /dev/null +++ b/lib/redactor/elfinder/php/libs/GdBmp.php @@ -0,0 +1,473 @@ += 26) { + $bfh = unpack("vtype/Vsize", $filename_or_stream_or_binary); + if ($bfh["type"] == 0x4d42 && ($bfh["size"] == 0 || $bfh["size"] == strlen($filename_or_stream_or_binary))) { + return self::loadFromString($filename_or_stream_or_binary); + } + } + return self::loadFromFile($filename_or_stream_or_binary); + } + + public static function loadFromFile($filename) + { + $fp = fopen($filename, "rb"); + if ($fp === false) { + return false; + } + + $bmp = self::loadFromStream($fp); + + fclose($fp); + return $bmp; + } + + public static function loadFromString($str) + { + //data scheme より古いバージョンから対応しているようなので php://memory を使う + $fp = fopen("php://memory", "r+b"); + if ($fp === false) { + return false; + } + + if (fwrite($fp, $str) != strlen($str)) { + fclose($fp); + return false; + } + + if (fseek($fp, 0) === -1) { + fclose($fp); + return false; + } + + $bmp = self::loadFromStream($fp); + + fclose($fp); + return $bmp; + } + + public static function loadFromStream($stream) + { + $buf = fread($stream, 14); //2+4+2+2+4 + if ($buf === false) { + return false; + } + + //シグネチャチェック + if ($buf[0] != 'B' || $buf[1] != 'M') { + return false; + } + + $bitmap_file_header = unpack( + //BITMAPFILEHEADER構造体 + "vtype/" . + "Vsize/" . + "vreserved1/" . + "vreserved2/" . + "Voffbits", $buf + ); + + return self::loadFromStreamAndFileHeader($stream, $bitmap_file_header); + } + + public static function loadFromStreamAndFileHeader($stream, array $bitmap_file_header) + { + if ($bitmap_file_header["type"] != 0x4d42) { + return false; + } + + //情報ヘッダサイズを元に形式を区別して読み込み + $buf = fread($stream, 4); + if ($buf === false) { + return false; + } + list(, $header_size) = unpack("V", $buf); + + + if ($header_size == 12) { + $buf = fread($stream, $header_size - 4); + if ($buf === false) { + return false; + } + + extract(unpack( + //BITMAPCOREHEADER構造体 - OS/2 Bitmap + "vwidth/" . + "vheight/" . + "vplanes/" . + "vbit_count", $buf + )); + //飛んでこない分は 0 で初期化しておく + $clr_used = $clr_important = $alpha_mask = $compression = 0; + + //マスク類は初期化されないのでここで割り当てておく + $red_mask = 0x00ff0000; + $green_mask = 0x0000ff00; + $blue_mask = 0x000000ff; + } else if (124 < $header_size || $header_size < 40) { + //未知の形式 + return false; + } else { + //この時点で36バイト読めることまではわかっている + $buf = fread($stream, 36); //既に読んだ部分は除外しつつBITMAPINFOHEADERのサイズだけ読む + if ($buf === false) { + return false; + } + + //BITMAPINFOHEADER構造体 - Windows Bitmap + extract(unpack( + "Vwidth/" . + "Vheight/" . + "vplanes/" . + "vbit_count/" . + "Vcompression/" . + "Vsize_image/" . + "Vx_pels_per_meter/" . + "Vy_pels_per_meter/" . + "Vclr_used/" . + "Vclr_important", $buf + )); + /** + * @var integer $width + * @var integer $height + * @var integer $planes + * @var integer $bit_count + * @var integer $compression + * @var integer $size_image + * @var integer $x_pels_per_meter + * @var integer $y_pels_per_meter + * @var integer $clr_used + * @var integer $clr_important + */ + //負の整数を受け取る可能性があるものは自前で変換する + if ($width & 0x80000000) { + $width = -(~$width & 0xffffffff) - 1; + } + if ($height & 0x80000000) { + $height = -(~$height & 0xffffffff) - 1; + } + if ($x_pels_per_meter & 0x80000000) { + $x_pels_per_meter = -(~$x_pels_per_meter & 0xffffffff) - 1; + } + if ($y_pels_per_meter & 0x80000000) { + $y_pels_per_meter = -(~$y_pels_per_meter & 0xffffffff) - 1; + } + + //ファイルによっては BITMAPINFOHEADER のサイズがおかしい(書き込み間違い?)ケースがある + //自分でファイルサイズを元に逆算することで回避できることもあるので再計算できそうなら正当性を調べる + //シークできないストリームの場合全体のファイルサイズは取得できないので、$bitmap_file_headerにサイズ申告がなければやらない + if ($bitmap_file_header["size"] != 0) { + $colorsize = $bit_count == 1 || $bit_count == 4 || $bit_count == 8 ? ($clr_used ? $clr_used : pow(2, $bit_count)) << 2 : 0; + $bodysize = $size_image ? $size_image : ((($width * $bit_count + 31) >> 3) & ~3) * abs($height); + $calcsize = $bitmap_file_header["size"] - $bodysize - $colorsize - 14; + + //本来であれば一致するはずなのに合わない時は、値がおかしくなさそうなら(BITMAPV5HEADERの範囲内なら)計算して求めた値を採用する + if ($header_size < $calcsize && 40 <= $header_size && $header_size <= 124) { + $header_size = $calcsize; + } + } + + //BITMAPV4HEADER や BITMAPV5HEADER の場合まだ読むべきデータが残っている可能性がある + if ($header_size - 40 > 0) { + $buf = fread($stream, $header_size - 40); + if ($buf === false) { + return false; + } + + extract(unpack( + //BITMAPV4HEADER構造体(Windows95以降) + //BITMAPV5HEADER構造体(Windows98/2000以降) + "Vred_mask/" . + "Vgreen_mask/" . + "Vblue_mask/" . + "Valpha_mask", $buf . str_repeat("\x00", 120) + )); + } else { + $alpha_mask = $red_mask = $green_mask = $blue_mask = 0; + } + + //パレットがないがカラーマスクもない時 + if ( + ($bit_count == 16 || $bit_count == 24 || $bit_count == 32) && + $compression == 0 && + $red_mask == 0 && $green_mask == 0 && $blue_mask == 0 + ) { + //もしカラーマスクを所持していない場合は + //規定のカラーマスクを適用する + switch ($bit_count) { + case 16: + $red_mask = 0x7c00; + $green_mask = 0x03e0; + $blue_mask = 0x001f; + break; + case 24: + case 32: + $red_mask = 0x00ff0000; + $green_mask = 0x0000ff00; + $blue_mask = 0x000000ff; + break; + } + } + } + + if ( + ($width == 0) || + ($height == 0) || + ($planes != 1) || + (($alpha_mask & $red_mask) != 0) || + (($alpha_mask & $green_mask) != 0) || + (($alpha_mask & $blue_mask) != 0) || + (($red_mask & $green_mask) != 0) || + (($red_mask & $blue_mask) != 0) || + (($green_mask & $blue_mask) != 0) + ) { + //不正な画像 + return false; + } + + //BI_JPEG と BI_PNG の場合は jpeg/png がそのまま入ってるだけなのでそのまま取り出してデコードする + if ($compression == 4 || $compression == 5) { + $buf = stream_get_contents($stream, $size_image); + if ($buf === false) { + return false; + } + return imagecreatefromstring($buf); + } + + //画像本体の読み出し + //1行のバイト数 + $line_bytes = (($width * $bit_count + 31) >> 3) & ~3; + //全体の行数 + $lines = abs($height); + //y軸進行量(ボトムアップかトップダウンか) + $y = $height > 0 ? $lines - 1 : 0; + $line_step = $height > 0 ? -1 : 1; + + //256色以下の画像か? + if ($bit_count == 1 || $bit_count == 4 || $bit_count == 8) { + $img = imagecreate($width, $lines); + + //画像データの前にパレットデータがあるのでパレットを作成する + $palette_size = $header_size == 12 ? 3 : 4; //OS/2形式の場合は x に相当する箇所のデータは最初から確保されていない + $colors = $clr_used ? $clr_used : pow(2, $bit_count); //色数 + $palette = array(); + for ($i = 0; $i < $colors; ++$i) { + $buf = fread($stream, $palette_size); + if ($buf === false) { + imagedestroy($img); + return false; + } + extract(unpack("Cb/Cg/Cr/Cx", $buf . "\x00")); + /** + * @var integer $b + * @var integer $g + * @var integer $r + * @var integer $x + */ + $palette[] = imagecolorallocate($img, $r, $g, $b); + } + + $shift_base = 8 - $bit_count; + $mask = ((1 << $bit_count) - 1) << $shift_base; + + //圧縮されている場合とされていない場合でデコード処理が大きく変わる + if ($compression == 1 || $compression == 2) { + $x = 0; + $qrt_mod2 = $bit_count >> 2 & 1; + for (; ;) { + //もし描写先が範囲外になっている場合デコード処理がおかしくなっているので抜ける + //変なデータが渡されたとしても最悪なケースで255回程度の無駄なので目を瞑る + if ($x < -1 || $x > $width || $y < -1 || $y > $height) { + imagedestroy($img); + return false; + } + $buf = fread($stream, 1); + if ($buf === false) { + imagedestroy($img); + return false; + } + switch ($buf) { + case "\x00": + $buf = fread($stream, 1); + if ($buf === false) { + imagedestroy($img); + return false; + } + switch ($buf) { + case "\x00": //EOL + $y += $line_step; + $x = 0; + break; + case "\x01": //EOB + $y = 0; + $x = 0; + break 3; + case "\x02": //MOV + $buf = fread($stream, 2); + if ($buf === false) { + imagedestroy($img); + return false; + } + list(, $xx, $yy) = unpack("C2", $buf); + $x += $xx; + $y += $yy * $line_step; + break; + default: //ABS + list(, $pixels) = unpack("C", $buf); + $bytes = ($pixels >> $qrt_mod2) + ($pixels & $qrt_mod2); + $buf = fread($stream, ($bytes + 1) & ~1); + if ($buf === false) { + imagedestroy($img); + return false; + } + for ($i = 0, $pos = 0; $i < $pixels; ++$i, ++$x, $pos += $bit_count) { + list(, $c) = unpack("C", $buf[$pos >> 3]); + $b = $pos & 0x07; + imagesetpixel($img, $x, $y, $palette[($c & ($mask >> $b)) >> ($shift_base - $b)]); + } + break; + } + break; + default: + $buf2 = fread($stream, 1); + if ($buf2 === false) { + imagedestroy($img); + return false; + } + list(, $size, $c) = unpack("C2", $buf . $buf2); + for ($i = 0, $pos = 0; $i < $size; ++$i, ++$x, $pos += $bit_count) { + $b = $pos & 0x07; + imagesetpixel($img, $x, $y, $palette[($c & ($mask >> $b)) >> ($shift_base - $b)]); + } + break; + } + } + } else { + for ($line = 0; $line < $lines; ++$line, $y += $line_step) { + $buf = fread($stream, $line_bytes); + if ($buf === false) { + imagedestroy($img); + return false; + } + + $pos = 0; + for ($x = 0; $x < $width; ++$x, $pos += $bit_count) { + list(, $c) = unpack("C", $buf[$pos >> 3]); + $b = $pos & 0x7; + imagesetpixel($img, $x, $y, $palette[($c & ($mask >> $b)) >> ($shift_base - $b)]); + } + } + } + } else { + $img = imagecreatetruecolor($width, $lines); + imagealphablending($img, false); + if ($alpha_mask) { + //αデータがあるので透過情報も保存できるように + imagesavealpha($img, true); + } + + //x軸進行量 + $pixel_step = $bit_count >> 3; + $alpha_max = $alpha_mask ? 0x7f : 0x00; + $alpha_mask_r = $alpha_mask ? 1 / $alpha_mask : 1; + $red_mask_r = $red_mask ? 1 / $red_mask : 1; + $green_mask_r = $green_mask ? 1 / $green_mask : 1; + $blue_mask_r = $blue_mask ? 1 / $blue_mask : 1; + + for ($line = 0; $line < $lines; ++$line, $y += $line_step) { + $buf = fread($stream, $line_bytes); + if ($buf === false) { + imagedestroy($img); + return false; + } + + $pos = 0; + for ($x = 0; $x < $width; ++$x, $pos += $pixel_step) { + list(, $c) = unpack("V", substr($buf, $pos, $pixel_step) . "\x00\x00"); + $a_masked = $c & $alpha_mask; + $r_masked = $c & $red_mask; + $g_masked = $c & $green_mask; + $b_masked = $c & $blue_mask; + $a = $alpha_max - ((($a_masked << 7) - $a_masked) * $alpha_mask_r); + $r = (($r_masked << 8) - $r_masked) * $red_mask_r; + $g = (($g_masked << 8) - $g_masked) * $green_mask_r; + $b = (($b_masked << 8) - $b_masked) * $blue_mask_r; + imagesetpixel($img, $x, $y, ($a << 24) | ($r << 16) | ($g << 8) | $b); + } + } + imagealphablending($img, true); //デフォルト値に戻しておく + } + return $img; + } +} diff --git a/lib/redactor/elfinder/php/mime.types b/lib/redactor/elfinder/php/mime.types new file mode 100644 index 0000000..b8463f1 --- /dev/null +++ b/lib/redactor/elfinder/php/mime.types @@ -0,0 +1,782 @@ +# This file maps Internet media types to unique file extension(s). +# Although created for httpd, this file is used by many software systems +# and has been placed in the public domain for unlimited redisribution. +# +# The table below contains both registered and (common) unregistered types. +# A type that has no unique extension can be ignored -- they are listed +# here to guide configurations toward known types and to make it easier to +# identify "new" types. File extensions are also commonly used to indicate +# content languages and encodings, so choose them carefully. +# +# Internet media types should be registered as described in RFC 4288. +# The registry is at . +# +# MIME type (lowercased) Extensions +application/andrew-inset ez +application/applixware aw +application/atom+xml atom +application/atomcat+xml atomcat +application/atomsvc+xml atomsvc +application/ccxml+xml ccxml +application/cdmi-capability cdmia +application/cdmi-container cdmic +application/cdmi-domain cdmid +application/cdmi-object cdmio +application/cdmi-queue cdmiq +application/cu-seeme cu +application/davmount+xml davmount +application/docbook+xml dbk +application/dssc+der dssc +application/dssc+xml xdssc +application/ecmascript ecma +application/emma+xml emma +application/epub+zip epub +application/exi exi +application/font-tdpfr pfr +application/gml+xml gml +application/gpx+xml gpx +application/gxf gxf +application/hyperstudio stk +application/inkml+xml ink inkml +application/ipfix ipfix +application/java-archive jar +application/java-serialized-object ser +application/java-vm class +application/javascript js +application/json json +application/jsonml+json jsonml +application/lost+xml lostxml +application/mac-binhex40 hqx +application/mac-compactpro cpt +application/mads+xml mads +application/marc mrc +application/marcxml+xml mrcx +application/mathematica ma nb mb +application/mathml+xml mathml +application/mbox mbox +application/mediaservercontrol+xml mscml +application/metalink+xml metalink +application/metalink4+xml meta4 +application/mets+xml mets +application/mods+xml mods +application/mp21 m21 mp21 +application/mp4 mp4s +application/msword doc dot +application/mxf mxf +application/octet-stream bin dms lrf mar so dist distz pkg bpk dump elc deploy +application/oda oda +application/oebps-package+xml opf +application/ogg ogx +application/omdoc+xml omdoc +application/onenote onetoc onetoc2 onetmp onepkg +application/oxps oxps +application/patch-ops-error+xml xer +application/pdf pdf +application/pgp-encrypted pgp +application/pgp-signature asc sig +application/pics-rules prf +application/pkcs10 p10 +application/pkcs7-mime p7m p7c +application/pkcs7-signature p7s +application/pkcs8 p8 +application/pkix-attr-cert ac +application/pkix-cert cer +application/pkix-crl crl +application/pkix-pkipath pkipath +application/pkixcmp pki +application/pls+xml pls +application/postscript ai eps ps +application/prs.cww cww +application/pskc+xml pskcxml +application/rdf+xml rdf +application/reginfo+xml rif +application/relax-ng-compact-syntax rnc +application/resource-lists+xml rl +application/resource-lists-diff+xml rld +application/rls-services+xml rs +application/rpki-ghostbusters gbr +application/rpki-manifest mft +application/rpki-roa roa +application/rsd+xml rsd +application/rss+xml rss +application/rtf rtf +application/sbml+xml sbml +application/scvp-cv-request scq +application/scvp-cv-response scs +application/scvp-vp-request spq +application/scvp-vp-response spp +application/sdp sdp +application/set-payment-initiation setpay +application/set-registration-initiation setreg +application/shf+xml shf +application/smil+xml smi smil +application/sparql-query rq +application/sparql-results+xml srx +application/srgs gram +application/srgs+xml grxml +application/sru+xml sru +application/ssdl+xml ssdl +application/ssml+xml ssml +application/tei+xml tei teicorpus +application/thraud+xml tfi +application/timestamped-data tsd +application/vnd.3gpp.pic-bw-large plb +application/vnd.3gpp.pic-bw-small psb +application/vnd.3gpp.pic-bw-var pvb +application/vnd.3gpp2.tcap tcap +application/vnd.3m.post-it-notes pwn +application/vnd.accpac.simply.aso aso +application/vnd.accpac.simply.imp imp +application/vnd.acucobol acu +application/vnd.acucorp atc acutc +application/vnd.adobe.air-application-installer-package+zip air +application/vnd.adobe.formscentral.fcdt fcdt +application/vnd.adobe.fxp fxp fxpl +application/vnd.adobe.xdp+xml xdp +application/vnd.adobe.xfdf xfdf +application/vnd.ahead.space ahead +application/vnd.airzip.filesecure.azf azf +application/vnd.airzip.filesecure.azs azs +application/vnd.amazon.ebook azw +application/vnd.americandynamics.acc acc +application/vnd.amiga.ami ami +application/vnd.android.package-archive apk +application/vnd.anser-web-certificate-issue-initiation cii +application/vnd.anser-web-funds-transfer-initiation fti +application/vnd.antix.game-component atx +application/vnd.apple.installer+xml mpkg +application/vnd.apple.mpegurl m3u8 +application/vnd.aristanetworks.swi swi +application/vnd.astraea-software.iota iota +application/vnd.audiograph aep +application/vnd.blueice.multipass mpm +application/vnd.bmi bmi +application/vnd.businessobjects rep +application/vnd.chemdraw+xml cdxml +application/vnd.chipnuts.karaoke-mmd mmd +application/vnd.cinderella cdy +application/vnd.claymore cla +application/vnd.cloanto.rp9 rp9 +application/vnd.clonk.c4group c4g c4d c4f c4p c4u +application/vnd.cluetrust.cartomobile-config c11amc +application/vnd.cluetrust.cartomobile-config-pkg c11amz +application/vnd.commonspace csp +application/vnd.contact.cmsg cdbcmsg +application/vnd.cosmocaller cmc +application/vnd.crick.clicker clkx +application/vnd.crick.clicker.keyboard clkk +application/vnd.crick.clicker.palette clkp +application/vnd.crick.clicker.template clkt +application/vnd.crick.clicker.wordbank clkw +application/vnd.criticaltools.wbs+xml wbs +application/vnd.ctc-posml pml +application/vnd.cups-ppd ppd +application/vnd.curl.car car +application/vnd.curl.pcurl pcurl +application/vnd.dart dart +application/vnd.data-vision.rdz rdz +application/vnd.dece.data uvf uvvf uvd uvvd +application/vnd.dece.ttml+xml uvt uvvt +application/vnd.dece.unspecified uvx uvvx +application/vnd.dece.zip uvz uvvz +application/vnd.denovo.fcselayout-link fe_launch +application/vnd.dna dna +application/vnd.dolby.mlp mlp +application/vnd.dpgraph dpg +application/vnd.dreamfactory dfac +application/vnd.ds-keypoint kpxx +application/vnd.dvb.ait ait +application/vnd.dvb.service svc +application/vnd.dynageo geo +application/vnd.ecowin.chart mag +application/vnd.enliven nml +application/vnd.epson.esf esf +application/vnd.epson.msf msf +application/vnd.epson.quickanime qam +application/vnd.epson.salt slt +application/vnd.epson.ssf ssf +application/vnd.eszigno3+xml es3 et3 +application/vnd.ezpix-album ez2 +application/vnd.ezpix-package ez3 +application/vnd.fdf fdf +application/vnd.fdsn.mseed mseed +application/vnd.fdsn.seed seed dataless +application/vnd.flographit gph +application/vnd.fluxtime.clip ftc +application/vnd.framemaker fm frame maker book +application/vnd.frogans.fnc fnc +application/vnd.frogans.ltf ltf +application/vnd.fsc.weblaunch fsc +application/vnd.fujitsu.oasys oas +application/vnd.fujitsu.oasys2 oa2 +application/vnd.fujitsu.oasys3 oa3 +application/vnd.fujitsu.oasysgp fg5 +application/vnd.fujitsu.oasysprs bh2 +application/vnd.fujixerox.ddd ddd +application/vnd.fujixerox.docuworks xdw +application/vnd.fujixerox.docuworks.binder xbd +application/vnd.fuzzysheet fzs +application/vnd.genomatix.tuxedo txd +application/vnd.geogebra.file ggb +application/vnd.geogebra.tool ggt +application/vnd.geometry-explorer gex gre +application/vnd.geonext gxt +application/vnd.geoplan g2w +application/vnd.geospace g3w +application/vnd.gmx gmx +application/vnd.google-earth.kml+xml kml +application/vnd.google-earth.kmz kmz +application/vnd.grafeq gqf gqs +application/vnd.groove-account gac +application/vnd.groove-help ghf +application/vnd.groove-identity-message gim +application/vnd.groove-injector grv +application/vnd.groove-tool-message gtm +application/vnd.groove-tool-template tpl +application/vnd.groove-vcard vcg +application/vnd.hal+xml hal +application/vnd.handheld-entertainment+xml zmm +application/vnd.hbci hbci +application/vnd.hhe.lesson-player les +application/vnd.hp-hpgl hpgl +application/vnd.hp-hpid hpid +application/vnd.hp-hps hps +application/vnd.hp-jlyt jlt +application/vnd.hp-pcl pcl +application/vnd.hp-pclxl pclxl +application/vnd.hydrostatix.sof-data sfd-hdstx +application/vnd.ibm.minipay mpy +application/vnd.ibm.modcap afp listafp list3820 +application/vnd.ibm.rights-management irm +application/vnd.ibm.secure-container sc +application/vnd.iccprofile icc icm +application/vnd.igloader igl +application/vnd.immervision-ivp ivp +application/vnd.immervision-ivu ivu +application/vnd.insors.igm igm +application/vnd.intercon.formnet xpw xpx +application/vnd.intergeo i2g +application/vnd.intu.qbo qbo +application/vnd.intu.qfx qfx +application/vnd.ipunplugged.rcprofile rcprofile +application/vnd.irepository.package+xml irp +application/vnd.is-xpr xpr +application/vnd.isac.fcs fcs +application/vnd.jam jam +application/vnd.jcp.javame.midlet-rms rms +application/vnd.jisp jisp +application/vnd.joost.joda-archive joda +application/vnd.kahootz ktz ktr +application/vnd.kde.karbon karbon +application/vnd.kde.kchart chrt +application/vnd.kde.kformula kfo +application/vnd.kde.kivio flw +application/vnd.kde.kontour kon +application/vnd.kde.kpresenter kpr kpt +application/vnd.kde.kspread ksp +application/vnd.kde.kword kwd kwt +application/vnd.kenameaapp htke +application/vnd.kidspiration kia +application/vnd.kinar kne knp +application/vnd.koan skp skd skt skm +application/vnd.kodak-descriptor sse +application/vnd.las.las+xml lasxml +application/vnd.llamagraphics.life-balance.desktop lbd +application/vnd.llamagraphics.life-balance.exchange+xml lbe +application/vnd.lotus-1-2-3 123 +application/vnd.lotus-approach apr +application/vnd.lotus-freelance pre +application/vnd.lotus-notes nsf +application/vnd.lotus-organizer org +application/vnd.lotus-screencam scm +application/vnd.lotus-wordpro lwp +application/vnd.macports.portpkg portpkg +application/vnd.mcd mcd +application/vnd.medcalcdata mc1 +application/vnd.mediastation.cdkey cdkey +application/vnd.mfer mwf +application/vnd.mfmp mfm +application/vnd.micrografx.flo flo +application/vnd.micrografx.igx igx +application/vnd.mif mif +application/vnd.mobius.daf daf +application/vnd.mobius.dis dis +application/vnd.mobius.mbk mbk +application/vnd.mobius.mqy mqy +application/vnd.mobius.msl msl +application/vnd.mobius.plc plc +application/vnd.mobius.txf txf +application/vnd.mophun.application mpn +application/vnd.mophun.certificate mpc +application/vnd.mozilla.xul+xml xul +application/vnd.ms-artgalry cil +application/vnd.ms-cab-compressed cab +application/vnd.ms-excel xls xlm xla xlc xlt xlw +application/vnd.ms-excel.addin.macroenabled.12 xlam +application/vnd.ms-excel.sheet.binary.macroenabled.12 xlsb +application/vnd.ms-excel.sheet.macroenabled.12 xlsm +application/vnd.ms-excel.template.macroenabled.12 xltm +application/vnd.ms-fontobject eot +application/vnd.ms-htmlhelp chm +application/vnd.ms-ims ims +application/vnd.ms-lrm lrm +application/vnd.ms-officetheme thmx +application/vnd.ms-outlook msg +application/vnd.ms-pki.seccat cat +application/vnd.ms-pki.stl stl +application/vnd.ms-powerpoint ppt pps pot +application/vnd.ms-powerpoint.addin.macroenabled.12 ppam +application/vnd.ms-powerpoint.presentation.macroenabled.12 pptm +application/vnd.ms-powerpoint.slide.macroenabled.12 sldm +application/vnd.ms-powerpoint.slideshow.macroenabled.12 ppsm +application/vnd.ms-powerpoint.template.macroenabled.12 potm +application/vnd.ms-project mpp mpt +application/vnd.ms-word.document.macroenabled.12 docm +application/vnd.ms-word.template.macroenabled.12 dotm +application/vnd.ms-works wps wks wcm wdb +application/vnd.ms-wpl wpl +application/vnd.ms-xpsdocument xps +application/vnd.mseq mseq +application/vnd.musician mus +application/vnd.muvee.style msty +application/vnd.mynfc taglet +application/vnd.neurolanguage.nlu nlu +application/vnd.nitf ntf nitf +application/vnd.noblenet-directory nnd +application/vnd.noblenet-sealer nns +application/vnd.noblenet-web nnw +application/vnd.nokia.n-gage.data ngdat +application/vnd.nokia.n-gage.symbian.install n-gage +application/vnd.nokia.radio-preset rpst +application/vnd.nokia.radio-presets rpss +application/vnd.novadigm.edm edm +application/vnd.novadigm.edx edx +application/vnd.novadigm.ext ext +application/vnd.oasis.opendocument.chart odc +application/vnd.oasis.opendocument.chart-template otc +application/vnd.oasis.opendocument.database odb +application/vnd.oasis.opendocument.formula odf +application/vnd.oasis.opendocument.formula-template odft +application/vnd.oasis.opendocument.graphics odg +application/vnd.oasis.opendocument.graphics-template otg +application/vnd.oasis.opendocument.image odi +application/vnd.oasis.opendocument.image-template oti +application/vnd.oasis.opendocument.presentation odp +application/vnd.oasis.opendocument.presentation-template otp +application/vnd.oasis.opendocument.spreadsheet ods +application/vnd.oasis.opendocument.spreadsheet-template ots +application/vnd.oasis.opendocument.text odt +application/vnd.oasis.opendocument.text-master odm +application/vnd.oasis.opendocument.text-template ott +application/vnd.oasis.opendocument.text-web oth +application/vnd.olpc-sugar xo +application/vnd.oma.dd2+xml dd2 +application/vnd.openofficeorg.extension oxt +application/vnd.openxmlformats-officedocument.presentationml.presentation pptx +application/vnd.openxmlformats-officedocument.presentationml.slide sldx +application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx +application/vnd.openxmlformats-officedocument.presentationml.template potx +application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx +application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx +application/vnd.openxmlformats-officedocument.wordprocessingml.document docx +application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx +application/vnd.osgeo.mapguide.package mgp +application/vnd.osgi.dp dp +application/vnd.osgi.subsystem esa +application/vnd.palm pdb pqa oprc +application/vnd.pawaafile paw +application/vnd.pg.format str +application/vnd.pg.osasli ei6 +application/vnd.picsel efif +application/vnd.pmi.widget wg +application/vnd.pocketlearn plf +application/vnd.powerbuilder6 pbd +application/vnd.previewsystems.box box +application/vnd.proteus.magazine mgz +application/vnd.publishare-delta-tree qps +application/vnd.pvi.ptid1 ptid +application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb +application/vnd.realvnc.bed bed +application/vnd.recordare.musicxml mxl +application/vnd.recordare.musicxml+xml musicxml +application/vnd.rig.cryptonote cryptonote +application/vnd.rim.cod cod +application/vnd.rn-realmedia rm +application/vnd.rn-realmedia-vbr rmvb +application/vnd.route66.link66+xml link66 +application/vnd.sailingtracker.track st +application/vnd.seemail see +application/vnd.sema sema +application/vnd.semd semd +application/vnd.semf semf +application/vnd.shana.informed.formdata ifm +application/vnd.shana.informed.formtemplate itp +application/vnd.shana.informed.interchange iif +application/vnd.shana.informed.package ipk +application/vnd.simtech-mindmapper twd twds +application/vnd.smaf mmf +application/vnd.smart.teacher teacher +application/vnd.solent.sdkm+xml sdkm sdkd +application/vnd.spotfire.dxp dxp +application/vnd.spotfire.sfs sfs +application/vnd.stardivision.calc sdc +application/vnd.stardivision.draw sda +application/vnd.stardivision.impress sdd +application/vnd.stardivision.math smf +application/vnd.stardivision.writer sdw vor +application/vnd.stardivision.writer-global sgl +application/vnd.stepmania.package smzip +application/vnd.stepmania.stepchart sm +application/vnd.sun.xml.calc sxc +application/vnd.sun.xml.calc.template stc +application/vnd.sun.xml.draw sxd +application/vnd.sun.xml.draw.template std +application/vnd.sun.xml.impress sxi +application/vnd.sun.xml.impress.template sti +application/vnd.sun.xml.math sxm +application/vnd.sun.xml.writer sxw +application/vnd.sun.xml.writer.global sxg +application/vnd.sun.xml.writer.template stw +application/vnd.sus-calendar sus susp +application/vnd.svd svd +application/vnd.symbian.install sis sisx +application/vnd.syncml+xml xsm +application/vnd.syncml.dm+wbxml bdm +application/vnd.syncml.dm+xml xdm +application/vnd.tao.intent-module-archive tao +application/vnd.tcpdump.pcap pcap cap dmp +application/vnd.tmobile-livetv tmo +application/vnd.trid.tpt tpt +application/vnd.triscape.mxs mxs +application/vnd.trueapp tra +application/vnd.ufdl ufd ufdl +application/vnd.uiq.theme utz +application/vnd.umajin umj +application/vnd.unity unityweb +application/vnd.uoml+xml uoml +application/vnd.vcx vcx +application/vnd.visio vsd vst vss vsw +application/vnd.visionary vis +application/vnd.vsf vsf +application/vnd.wap.wbxml wbxml +application/vnd.wap.wmlc wmlc +application/vnd.wap.wmlscriptc wmlsc +application/vnd.webturbo wtb +application/vnd.wolfram.player nbp +application/vnd.wordperfect wpd +application/vnd.wqd wqd +application/vnd.wt.stf stf +application/vnd.xara xar +application/vnd.xfdl xfdl +application/vnd.yamaha.hv-dic hvd +application/vnd.yamaha.hv-script hvs +application/vnd.yamaha.hv-voice hvp +application/vnd.yamaha.openscoreformat osf +application/vnd.yamaha.openscoreformat.osfpvg+xml osfpvg +application/vnd.yamaha.smaf-audio saf +application/vnd.yamaha.smaf-phrase spf +application/vnd.yellowriver-custom-menu cmp +application/vnd.zul zir zirz +application/vnd.zzazz.deck+xml zaz +application/voicexml+xml vxml +application/widget wgt +application/winhlp hlp +application/wsdl+xml wsdl +application/wspolicy+xml wspolicy +application/x-7z-compressed 7z +application/x-abiword abw +application/x-ace-compressed ace +application/x-apple-diskimage dmg +application/x-authorware-bin aab x32 u32 vox +application/x-authorware-map aam +application/x-authorware-seg aas +application/x-bcpio bcpio +application/x-bittorrent torrent +application/x-blorb blb blorb +application/x-bzip bz +application/x-bzip2 bz2 boz +application/x-cbr cbr cba cbt cbz cb7 +application/x-cdlink vcd +application/x-cfs-compressed cfs +application/x-chat chat +application/x-chess-pgn pgn +application/x-conference nsc +application/x-cpio cpio +application/x-csh csh +application/x-debian-package deb udeb +application/x-dgc-compressed dgc +application/x-director dir dcr dxr cst cct cxt w3d fgd swa +application/x-doom wad +application/x-dtbncx+xml ncx +application/x-dtbook+xml dtb +application/x-dtbresource+xml res +application/x-dvi dvi +application/x-envoy evy +application/x-eva eva +application/x-font-bdf bdf +application/x-font-ghostscript gsf +application/x-font-linux-psf psf +application/x-font-pcf pcf +application/x-font-snf snf +application/x-font-type1 pfa pfb pfm afm +application/x-freearc arc +application/x-futuresplash spl +application/x-gca-compressed gca +application/x-glulx ulx +application/x-gnumeric gnumeric +application/x-gramps-xml gramps +application/x-gtar gtar +application/x-hdf hdf +application/x-install-instructions install +application/x-iso9660-image iso +application/x-java-jnlp-file jnlp +application/x-latex latex +application/x-lzh-compressed lzh lha +application/x-mie mie +application/x-mobipocket-ebook prc mobi +application/x-ms-application application +application/x-ms-shortcut lnk +application/x-ms-wmd wmd +application/x-ms-wmz wmz +application/x-ms-xbap xbap +application/x-msaccess mdb +application/x-msbinder obd +application/x-mscardfile crd +application/x-msclip clp +application/x-msdownload exe dll com bat msi +application/x-msmediaview mvb m13 m14 +application/x-msmetafile wmf wmz emf emz +application/x-msmoney mny +application/x-mspublisher pub +application/x-msschedule scd +application/x-msterminal trm +application/x-mswrite wri +application/x-netcdf nc cdf +application/x-nzb nzb +application/x-pkcs12 p12 pfx +application/x-pkcs7-certificates p7b spc +application/x-pkcs7-certreqresp p7r +application/x-rar-compressed rar +application/x-research-info-systems ris +application/x-sh sh +application/x-shar shar +application/x-shockwave-flash swf +application/x-silverlight-app xap +application/x-sql sql +application/x-stuffit sit +application/x-stuffitx sitx +application/x-subrip srt +application/x-sv4cpio sv4cpio +application/x-sv4crc sv4crc +application/x-t3vm-image t3 +application/x-tads gam +application/x-tar tar +application/x-tcl tcl +application/x-tex tex +application/x-tex-tfm tfm +application/x-texinfo texinfo texi +application/x-tgif obj +application/x-ustar ustar +application/x-wais-source src +application/x-x509-ca-cert der crt +application/x-xfig fig +application/x-xliff+xml xlf +application/x-xpinstall xpi +application/x-xz xz +application/x-zmachine z1 z2 z3 z4 z5 z6 z7 z8 +application/xaml+xml xaml +application/xcap-diff+xml xdf +application/xenc+xml xenc +application/xhtml+xml xhtml xht +application/xml xml xsl +application/xml-dtd dtd +application/xop+xml xop +application/xproc+xml xpl +application/xslt+xml xslt +application/xspf+xml xspf +application/xv+xml mxml xhvml xvml xvm +application/yang yang +application/yin+xml yin +application/zip zip +audio/adpcm adp +audio/basic au snd +audio/midi mid midi kar rmi +audio/mp4 m4a mp4a +audio/mpeg mpga mp2 mp2a mp3 m2a m3a +audio/ogg oga ogg spx +audio/s3m s3m +audio/silk sil +audio/vnd.dece.audio uva uvva +audio/vnd.digital-winds eol +audio/vnd.dra dra +audio/vnd.dts dts +audio/vnd.dts.hd dtshd +audio/vnd.lucent.voice lvp +audio/vnd.ms-playready.media.pya pya +audio/vnd.nuera.ecelp4800 ecelp4800 +audio/vnd.nuera.ecelp7470 ecelp7470 +audio/vnd.nuera.ecelp9600 ecelp9600 +audio/vnd.rip rip +audio/webm weba +audio/x-aac aac +audio/x-aiff aif aiff aifc +audio/x-caf caf +audio/x-flac flac +audio/x-matroska mka +audio/x-mpegurl m3u +audio/x-ms-wax wax +audio/x-ms-wma wma +audio/x-pn-realaudio ram ra +audio/x-pn-realaudio-plugin rmp +audio/x-wav wav +audio/xm xm +chemical/x-cdx cdx +chemical/x-cif cif +chemical/x-cmdf cmdf +chemical/x-cml cml +chemical/x-csml csml +chemical/x-xyz xyz +font/collection ttc +font/otf otf +font/ttf ttf +font/woff woff +font/woff2 woff2 +image/bmp bmp +image/cgm cgm +image/g3fax g3 +image/gif gif +image/ief ief +image/jpeg jpeg jpg jpe +image/ktx ktx +image/png png +image/prs.btif btif +image/sgi sgi +image/svg+xml svg svgz +image/tiff tiff tif +image/vnd.adobe.photoshop psd +image/vnd.dece.graphic uvi uvvi uvg uvvg +image/vnd.djvu djvu djv +image/vnd.dvb.subtitle sub +image/vnd.dwg dwg +image/vnd.dxf dxf +image/vnd.fastbidsheet fbs +image/vnd.fpx fpx +image/vnd.fst fst +image/vnd.fujixerox.edmics-mmr mmr +image/vnd.fujixerox.edmics-rlc rlc +image/vnd.ms-modi mdi +image/vnd.ms-photo wdp +image/vnd.net-fpx npx +image/vnd.wap.wbmp wbmp +image/vnd.xiff xif +image/webp webp +image/x-3ds 3ds +image/x-cmu-raster ras +image/x-cmx cmx +image/x-freehand fh fhc fh4 fh5 fh7 +image/x-icon ico +image/x-mrsid-image sid +image/x-pcx pcx +image/x-pict pic pct +image/x-portable-anymap pnm +image/x-portable-bitmap pbm +image/x-portable-graymap pgm +image/x-portable-pixmap ppm +image/x-rgb rgb +image/x-tga tga +image/x-xbitmap xbm +image/x-xpixmap xpm +image/x-xwindowdump xwd +message/rfc822 eml mime +model/iges igs iges +model/mesh msh mesh silo +model/vnd.collada+xml dae +model/vnd.dwf dwf +model/vnd.gdl gdl +model/vnd.gtw gtw +model/vnd.mts mts +model/vnd.vtu vtu +model/vrml wrl vrml +model/x3d+binary x3db x3dbz +model/x3d+vrml x3dv x3dvz +model/x3d+xml x3d x3dz +text/cache-manifest appcache +text/calendar ics ifb +text/css css +text/csv csv +text/html html htm +text/n3 n3 +text/plain txt text conf def list log in +text/prs.lines.tag dsc +text/richtext rtx +text/sgml sgml sgm +text/tab-separated-values tsv +text/troff t tr roff man me ms +text/turtle ttl +text/uri-list uri uris urls +text/vcard vcard +text/vnd.curl curl +text/vnd.curl.dcurl dcurl +text/vnd.curl.mcurl mcurl +text/vnd.curl.scurl scurl +text/vnd.dvb.subtitle sub +text/vnd.fly fly +text/vnd.fmi.flexstor flx +text/vnd.graphviz gv +text/vnd.in3d.3dml 3dml +text/vnd.in3d.spot spot +text/vnd.sun.j2me.app-descriptor jad +text/vnd.wap.wml wml +text/vnd.wap.wmlscript wmls +text/x-asm s asm +text/x-c c cc cxx cpp h hh dic +text/x-fortran f for f77 f90 +text/x-java-source java +text/x-nfo nfo +text/x-opml opml +text/x-pascal p pas +text/x-setext etx +text/x-sfv sfv +text/x-uuencode uu +text/x-vcalendar vcs +text/x-vcard vcf +video/3gpp 3gp +video/3gpp2 3g2 +video/h261 h261 +video/h263 h263 +video/h264 h264 +video/jpeg jpgv +video/jpm jpm jpgm +video/mj2 mj2 mjp2 +video/mp4 mp4 mp4v mpg4 +video/mpeg mpeg mpg mpe m1v m2v +video/ogg ogv +video/quicktime qt mov +video/vnd.dece.hd uvh uvvh +video/vnd.dece.mobile uvm uvvm +video/vnd.dece.pd uvp uvvp +video/vnd.dece.sd uvs uvvs +video/vnd.dece.video uvv uvvv +video/vnd.dvb.file dvb +video/vnd.fvt fvt +video/vnd.mpegurl mxu m4u +video/vnd.ms-playready.media.pyv pyv +video/vnd.uvvu.mp4 uvu uvvu +video/vnd.vivo viv +video/webm webm +video/x-f4v f4v +video/x-fli fli +video/x-flv flv +video/x-m4v m4v +video/x-matroska mkv mk3d mks +video/x-mng mng +video/x-ms-asf asf asx +video/x-ms-vob vob +video/x-ms-wm wm +video/x-ms-wmv wmv +video/x-ms-wmx wmx +video/x-ms-wvx wvx +video/x-msvideo avi +video/x-sgi-movie movie +video/x-smv smv +x-conference/x-cooltalk ice diff --git a/lib/redactor/elfinder/php/plugins/AutoResize/plugin.php b/lib/redactor/elfinder/php/plugins/AutoResize/plugin.php new file mode 100644 index 0000000..4c63543 --- /dev/null +++ b/lib/redactor/elfinder/php/plugins/AutoResize/plugin.php @@ -0,0 +1,151 @@ + array( + * 'upload.presave' => array( + * 'Plugin.AutoResize.onUpLoadPreSave' + * ) + * ), + * // global configure (optional) + * 'plugin' => array( + * 'AutoResize' => array( + * 'enable' => true, // For control by volume driver + * 'maxWidth' => 1024, // Path to Water mark image + * 'maxHeight' => 1024, // Margin right pixel + * 'quality' => 95, // JPEG image save quality + * 'preserveExif' => false, // Preserve EXIF data (Imagick only) + * 'forceEffect' => false, // For change quality or make progressive JPEG of small images + * 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field ) + * 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * ) + * ), + * // each volume configure (optional) + * 'roots' => array( + * array( + * 'driver' => 'LocalFileSystem', + * 'path' => '/path/to/files/', + * 'URL' => 'http://localhost/to/files/' + * 'plugin' => array( + * 'AutoResize' => array( + * 'enable' => true, // For control by volume driver + * 'maxWidth' => 1024, // Path to Water mark image + * 'maxHeight' => 1024, // Margin right pixel + * 'quality' => 95, // JPEG image save quality + * 'preserveExif' => false, // Preserve EXIF data (Imagick only) + * 'forceEffect' => false, // For change quality or make progressive JPEG of small images + * 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field ) + * 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * ) + * ) + * ) + * ) + * ); + * + * @package elfinder + * @author Naoki Sawada + * @license New BSD + */ +class elFinderPluginAutoResize extends elFinderPlugin +{ + + public function __construct($opts) + { + $defaults = array( + 'enable' => true, // For control by volume driver + 'maxWidth' => 1024, // Path to Water mark image + 'maxHeight' => 1024, // Margin right pixel + 'quality' => 95, // JPEG image save quality + 'preserveExif' => false, // Preserve EXIF data (Imagick only) + 'forceEffect' => false, // For change quality or make progressive JPEG of small images + 'targetType' => IMG_GIF | IMG_JPG | IMG_PNG | IMG_WBMP, // Target image formats ( bit-field ) + 'offDropWith' => null, // To disable it if it is dropped with pressing the meta key + // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + // In case of using any key, specify it as an array + 'disableWithContentSaveId' => true // Disable on URL upload with post data "contentSaveId" + ); + + $this->opts = array_merge($defaults, $opts); + + } + + public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume) + { + if (!$src) { + return false; + } + + $opts = $this->getCurrentOpts($volume); + + if (!$this->iaEnabled($opts, $elfinder)) { + return false; + } + + $imageType = null; + $srcImgInfo = null; + if (extension_loaded('fileinfo') && function_exists('mime_content_type')) { + $mime = mime_content_type($src); + if (substr($mime, 0, 5) !== 'image') { + return false; + } + } + if (extension_loaded('exif') && function_exists('exif_imagetype')) { + $imageType = exif_imagetype($src); + if ($imageType === false) { + return false; + } + } else { + $srcImgInfo = getimagesize($src); + if ($srcImgInfo === false) { + return false; + } + $imageType = $srcImgInfo[2]; + } + + // check target image type + $imgTypes = array( + IMAGETYPE_GIF => IMG_GIF, + IMAGETYPE_JPEG => IMG_JPEG, + IMAGETYPE_PNG => IMG_PNG, + IMAGETYPE_BMP => IMG_WBMP, + IMAGETYPE_WBMP => IMG_WBMP + ); + if (!isset($imgTypes[$imageType]) || !($opts['targetType'] & $imgTypes[$imageType])) { + return false; + } + + if (!$srcImgInfo) { + $srcImgInfo = getimagesize($src); + } + + if ($opts['forceEffect'] || $srcImgInfo[0] > $opts['maxWidth'] || $srcImgInfo[1] > $opts['maxHeight']) { + return $this->resize($volume, $src, $srcImgInfo, $opts['maxWidth'], $opts['maxHeight'], $opts['quality'], $opts['preserveExif']); + } + + return false; + } + + private function resize($volume, $src, $srcImgInfo, $maxWidth, $maxHeight, $jpgQuality, $preserveExif) + { + $zoom = min(($maxWidth / $srcImgInfo[0]), ($maxHeight / $srcImgInfo[1])); + $width = round($srcImgInfo[0] * $zoom); + $height = round($srcImgInfo[1] * $zoom); + $unenlarge = true; + $checkAnimated = true; + + return $volume->imageUtil('resize', $src, compact('width', 'height', 'jpgQuality', 'preserveExif', 'unenlarge', 'checkAnimated')); + } +} diff --git a/lib/redactor/elfinder/php/plugins/AutoRotate/plugin.php b/lib/redactor/elfinder/php/plugins/AutoRotate/plugin.php new file mode 100644 index 0000000..c69ac95 --- /dev/null +++ b/lib/redactor/elfinder/php/plugins/AutoRotate/plugin.php @@ -0,0 +1,148 @@ + array( + * 'upload.presave' => array( + * 'Plugin.AutoRotate.onUpLoadPreSave' + * ) + * ), + * // global configure (optional) + * 'plugin' => array( + * 'AutoRotate' => array( + * 'enable' => true, // For control by volume driver + * 'quality' => 95, // JPEG image save quality + * 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * ) + * ), + * // each volume configure (optional) + * 'roots' => array( + * array( + * 'driver' => 'LocalFileSystem', + * 'path' => '/path/to/files/', + * 'URL' => 'http://localhost/to/files/' + * 'plugin' => array( + * 'AutoRotate' => array( + * 'enable' => true, // For control by volume driver + * 'quality' => 95, // JPEG image save quality + * 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * ) + * ) + * ) + * ) + * ); + * + * @package elfinder + * @author Naoki Sawada + * @license New BSD + */ +class elFinderPluginAutoRotate extends elFinderPlugin +{ + + public function __construct($opts) + { + $defaults = array( + 'enable' => true, // For control by volume driver + 'quality' => 95, // JPEG image save quality + 'offDropWith' => null, // To disable it if it is dropped with pressing the meta key + // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + // In case of using any key, specify it as an array + 'disableWithContentSaveId' => true // Disable on URL upload with post data "contentSaveId" + ); + + $this->opts = array_merge($defaults, $opts); + + } + + public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume) + { + if (!$src) { + return false; + } + + $opts = $this->getCurrentOpts($volume); + + if (!$this->iaEnabled($opts, $elfinder)) { + return false; + } + + $imageType = null; + $srcImgInfo = null; + if (extension_loaded('fileinfo') && function_exists('mime_content_type')) { + $mime = mime_content_type($src); + if (substr($mime, 0, 5) !== 'image') { + return false; + } + } + if (extension_loaded('exif') && function_exists('exif_imagetype')) { + $imageType = exif_imagetype($src); + if ($imageType === false) { + return false; + } + } else { + $srcImgInfo = getimagesize($src); + if ($srcImgInfo === false) { + return false; + } + $imageType = $srcImgInfo[2]; + } + + // check target image type + if ($imageType !== IMAGETYPE_JPEG) { + return false; + } + + if (!$srcImgInfo) { + $srcImgInfo = getimagesize($src); + } + + return $this->rotate($volume, $src, $srcImgInfo, $opts['quality']); + } + + private function rotate($volume, $src, $srcImgInfo, $quality) + { + if (!function_exists('exif_read_data')) { + return false; + } + $degree = 0; + $errlev =error_reporting(); + error_reporting($errlev ^ E_WARNING); + $exif = exif_read_data($src); + error_reporting($errlev); + if ($exif && !empty($exif['Orientation'])) { + switch ($exif['Orientation']) { + case 8: + $degree = 270; + break; + case 3: + $degree = 180; + break; + case 6: + $degree = 90; + break; + } + } + if (!$degree) { + return false; + } + $opts = array( + 'degree' => $degree, + 'jpgQuality' => $quality, + 'checkAnimated' => true + ); + return $volume->imageUtil('rotate', $src, $opts); + } +} diff --git a/lib/redactor/elfinder/php/plugins/Normalizer/plugin.php b/lib/redactor/elfinder/php/plugins/Normalizer/plugin.php new file mode 100644 index 0000000..a83a910 --- /dev/null +++ b/lib/redactor/elfinder/php/plugins/Normalizer/plugin.php @@ -0,0 +1,204 @@ += 5.3.0, PECL intl >= 1.0.0) + * or PEAR package "I18N_UnicodeNormalizer" + * ex. binding, configure on connector options + * $opts = array( + * 'bind' => array( + * 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array( + * 'Plugin.Normalizer.cmdPreprocess' + * ), + * 'upload.presave paste.copyfrom' => array( + * 'Plugin.Normalizer.onUpLoadPreSave' + * ) + * ), + * // global configure (optional) + * 'plugin' => array( + * 'Normalizer' => array( + * 'enable' => true, + * 'nfc' => true, + * 'nfkc' => true, + * 'umlauts' => false, + * 'lowercase' => false, + * 'convmap' => array() + * ) + * ), + * // each volume configure (optional) + * 'roots' => array( + * array( + * 'driver' => 'LocalFileSystem', + * 'path' => '/path/to/files/', + * 'URL' => 'http://localhost/to/files/' + * 'plugin' => array( + * 'Normalizer' => array( + * 'enable' => true, + * 'nfc' => true, + * 'nfkc' => true, + * 'umlauts' => false, + * 'lowercase' => false, + * 'convmap' => array() + * ) + * ) + * ) + * ) + * ); + * + * @package elfinder + * @author Naoki Sawada + * @license New BSD + */ +class elFinderPluginNormalizer extends elFinderPlugin +{ + private $replaced = array(); + private $keyMap = array( + 'ls' => 'intersect', + 'upload' => 'renames', + 'mkdir' => array('name', 'dirs') + ); + + public function __construct($opts) + { + $defaults = array( + 'enable' => true, // For control by volume driver + 'nfc' => true, // Canonical Decomposition followed by Canonical Composition + 'nfkc' => true, // Compatibility Decomposition followed by Canonical + 'umlauts' => false, // Convert umlauts with their closest 7 bit ascii equivalent + 'lowercase' => false, // Make chars lowercase + 'convmap' => array()// Convert map ('FROM' => 'TO') array + ); + + $this->opts = array_merge($defaults, $opts); + } + + public function cmdPreprocess($cmd, &$args, $elfinder, $volume) + { + $opts = $this->getCurrentOpts($volume); + if (!$opts['enable']) { + return false; + } + $this->replaced[$cmd] = array(); + $key = (isset($this->keyMap[$cmd])) ? $this->keyMap[$cmd] : 'name'; + + if (is_array($key)) { + $keys = $key; + } else { + $keys = array($key); + } + foreach ($keys as $key) { + if (isset($args[$key])) { + if (is_array($args[$key])) { + foreach ($args[$key] as $i => $name) { + if ($cmd === 'mkdir' && $key === 'dirs') { + // $name need '/' as prefix see #2607 + $name = '/' . ltrim($name, '/'); + $_names = explode('/', $name); + $_res = array(); + foreach ($_names as $_name) { + $_res[] = $this->normalize($_name, $opts); + } + $this->replaced[$cmd][$name] = $args[$key][$i] = join('/', $_res); + } else { + $this->replaced[$cmd][$name] = $args[$key][$i] = $this->normalize($name, $opts); + } + } + } else if ($args[$key] !== '') { + $name = $args[$key]; + $this->replaced[$cmd][$name] = $args[$key] = $this->normalize($name, $opts); + } + } + } + if ($cmd === 'ls' || $cmd === 'mkdir') { + if (!empty($this->replaced[$cmd])) { + // un-regist for legacy settings + $elfinder->unbind($cmd, array($this, 'cmdPostprocess')); + $elfinder->bind($cmd, array($this, 'cmdPostprocess')); + } + } + return true; + } + + public function cmdPostprocess($cmd, &$result, $args, $elfinder, $volume) + { + if ($cmd === 'ls') { + if (!empty($result['list']) && !empty($this->replaced['ls'])) { + foreach ($result['list'] as $hash => $name) { + if ($keys = array_keys($this->replaced['ls'], $name)) { + if (count($keys) === 1) { + $result['list'][$hash] = $keys[0]; + } else { + $result['list'][$hash] = $keys; + } + } + } + } + } else if ($cmd === 'mkdir') { + if (!empty($result['hashes']) && !empty($this->replaced['mkdir'])) { + foreach ($result['hashes'] as $name => $hash) { + if ($keys = array_keys($this->replaced['mkdir'], $name)) { + $result['hashes'][$keys[0]] = $hash; + } + } + } + } + } + + // NOTE: $thash is directory hash so it unneed to process at here + public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume) + { + $opts = $this->getCurrentOpts($volume); + if (!$opts['enable']) { + return false; + } + + $name = $this->normalize($name, $opts); + return true; + } + + protected function normalize($str, $opts) + { + if ($opts['nfc'] || $opts['nfkc']) { + if (class_exists('Normalizer', false)) { + if ($opts['nfc'] && !Normalizer::isNormalized($str, Normalizer::FORM_C)) + $str = Normalizer::normalize($str, Normalizer::FORM_C); + if ($opts['nfkc'] && !Normalizer::isNormalized($str, Normalizer::FORM_KC)) + $str = Normalizer::normalize($str, Normalizer::FORM_KC); + } else { + if (!class_exists('I18N_UnicodeNormalizer', false)) { + if (is_readable('I18N/UnicodeNormalizer.php')) { + include_once 'I18N/UnicodeNormalizer.php'; + } else { + trigger_error('Plugin Normalizer\'s options "nfc" or "nfkc" require PHP class "Normalizer" or PEAR package "I18N_UnicodeNormalizer"', E_USER_WARNING); + } + } + if (class_exists('I18N_UnicodeNormalizer', false)) { + $normalizer = new I18N_UnicodeNormalizer(); + if ($opts['nfc']) + $str = $normalizer->normalize($str, 'NFC'); + if ($opts['nfkc']) + $str = $normalizer->normalize($str, 'NFKC'); + } + } + } + if ($opts['umlauts']) { + if (strpos($str = htmlentities($str, ENT_QUOTES, 'UTF-8'), '&') !== false) { + $str = html_entity_decode(preg_replace('~&([a-z]{1,2})(?:acute|caron|cedil|circ|grave|lig|orn|ring|slash|tilde|uml);~i', '$1', $str), ENT_QUOTES, 'utf-8'); + } + } + if ($opts['convmap'] && is_array($opts['convmap'])) { + $str = strtr($str, $opts['convmap']); + } + if ($opts['lowercase']) { + if (function_exists('mb_strtolower')) { + $str = mb_strtolower($str, 'UTF-8'); + } else { + $str = strtolower($str); + } + } + return $str; + } +} diff --git a/lib/redactor/elfinder/php/plugins/Sanitizer/plugin.php b/lib/redactor/elfinder/php/plugins/Sanitizer/plugin.php new file mode 100644 index 0000000..04aeded --- /dev/null +++ b/lib/redactor/elfinder/php/plugins/Sanitizer/plugin.php @@ -0,0 +1,157 @@ + array( + * 'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array( + * 'Plugin.Sanitizer.cmdPreprocess' + * ), + * 'upload.presave paste.copyfrom' => array( + * 'Plugin.Sanitizer.onUpLoadPreSave' + * ) + * ), + * // global configure (optional) + * 'plugin' => array( + * 'Sanitizer' => array( + * 'enable' => true, + * 'targets' => array('\\','/',':','*','?','"','<','>','|'), // target chars + * 'replace' => '_', // replace to this + * 'callBack' => null // Or @callable sanitize function + * ) + * ), + * // each volume configure (optional) + * 'roots' => array( + * array( + * 'driver' => 'LocalFileSystem', + * 'path' => '/path/to/files/', + * 'URL' => 'http://localhost/to/files/' + * 'plugin' => array( + * 'Sanitizer' => array( + * 'enable' => true, + * 'targets' => array('\\','/',':','*','?','"','<','>','|'), // target chars + * 'replace' => '_', // replace to this + * 'callBack' => null // Or @callable sanitize function + * ) + * ) + * ) + * ) + * ); + * + * @package elfinder + * @author Naoki Sawada + * @license New BSD + */ +class elFinderPluginSanitizer extends elFinderPlugin +{ + private $replaced = array(); + private $keyMap = array( + 'ls' => 'intersect', + 'upload' => 'renames', + 'mkdir' => array('name', 'dirs') + ); + + public function __construct($opts) + { + $defaults = array( + 'enable' => true, // For control by volume driver + 'targets' => array('\\', '/', ':', '*', '?', '"', '<', '>', '|'), // target chars + 'replace' => '_', // replace to this + 'callBack' => null // Or callable sanitize function + ); + $this->opts = array_merge($defaults, $opts); + } + + public function cmdPreprocess($cmd, &$args, $elfinder, $volume) + { + $opts = $this->getCurrentOpts($volume); + if (!$opts['enable']) { + return false; + } + $this->replaced[$cmd] = array(); + $key = (isset($this->keyMap[$cmd])) ? $this->keyMap[$cmd] : 'name'; + + if (is_array($key)) { + $keys = $key; + } else { + $keys = array($key); + } + foreach ($keys as $key) { + if (isset($args[$key])) { + if (is_array($args[$key])) { + foreach ($args[$key] as $i => $name) { + if ($cmd === 'mkdir' && $key === 'dirs') { + // $name need '/' as prefix see #2607 + $name = '/' . ltrim($name, '/'); + $_names = explode('/', $name); + $_res = array(); + foreach ($_names as $_name) { + $_res[] = $this->sanitizeFileName($_name, $opts); + } + $this->replaced[$cmd][$name] = $args[$key][$i] = join('/', $_res); + } else { + $this->replaced[$cmd][$name] = $args[$key][$i] = $this->sanitizeFileName($name, $opts); + } + } + } else if ($args[$key] !== '') { + $name = $args[$key]; + $this->replaced[$cmd][$name] = $args[$key] = $this->sanitizeFileName($name, $opts); + } + } + } + if ($cmd === 'ls' || $cmd === 'mkdir') { + if (!empty($this->replaced[$cmd])) { + // un-regist for legacy settings + $elfinder->unbind($cmd, array($this, 'cmdPostprocess')); + $elfinder->bind($cmd, array($this, 'cmdPostprocess')); + } + } + return true; + } + + public function cmdPostprocess($cmd, &$result, $args, $elfinder, $volume) + { + if ($cmd === 'ls') { + if (!empty($result['list']) && !empty($this->replaced['ls'])) { + foreach ($result['list'] as $hash => $name) { + if ($keys = array_keys($this->replaced['ls'], $name)) { + if (count($keys) === 1) { + $result['list'][$hash] = $keys[0]; + } else { + $result['list'][$hash] = $keys; + } + } + } + } + } else if ($cmd === 'mkdir') { + if (!empty($result['hashes']) && !empty($this->replaced['mkdir'])) { + foreach ($result['hashes'] as $name => $hash) { + if ($keys = array_keys($this->replaced['mkdir'], $name)) { + $result['hashes'][$keys[0]] = $hash; + } + } + } + } + } + + // NOTE: $thash is directory hash so it unneed to process at here + public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume) + { + $opts = $this->getCurrentOpts($volume); + if (!$opts['enable']) { + return false; + } + $name = $this->sanitizeFileName($name, $opts); + return true; + } + + protected function sanitizeFileName($filename, $opts) + { + if (!empty($opts['callBack']) && is_callable($opts['callBack'])) { + return call_user_func_array($opts['callBack'], array($filename, $opts)); + } + return str_replace($opts['targets'], $opts['replace'], $filename); + } +} diff --git a/lib/redactor/elfinder/php/plugins/Watermark/logo.png b/lib/redactor/elfinder/php/plugins/Watermark/logo.png new file mode 100644 index 0000000..35a1487 Binary files /dev/null and b/lib/redactor/elfinder/php/plugins/Watermark/logo.png differ diff --git a/lib/redactor/elfinder/php/plugins/Watermark/plugin.php b/lib/redactor/elfinder/php/plugins/Watermark/plugin.php new file mode 100644 index 0000000..3d7f907 --- /dev/null +++ b/lib/redactor/elfinder/php/plugins/Watermark/plugin.php @@ -0,0 +1,432 @@ + array( + * 'upload.presave' => array( + * 'Plugin.Watermark.onUpLoadPreSave' + * ) + * ), + * // global configure (optional) + * 'plugin' => array( + * 'Watermark' => array( + * 'enable' => true, // For control by volume driver + * 'source' => 'logo.png', // Path to Water mark image + * 'ratio' => 0.2, // Ratio to original image (ratio > 0 and ratio <= 1) + * 'position' => 'RB', // Position L(eft)/C(enter)/R(ight) and T(op)/M(edium)/B(ottom) + * 'marginX' => 5, // Margin horizontal pixel + * 'marginY' => 5, // Margin vertical pixel + * 'quality' => 95, // JPEG image save quality + * 'transparency' => 70, // Water mark image transparency ( other than PNG ) + * 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field ) + * 'targetMinPixel' => 200, // Target image minimum pixel size + * 'interlace' => IMG_GIF|IMG_JPG, // Set interlacebit image formats ( bit-field ) + * 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * ) + * ), + * // each volume configure (optional) + * 'roots' => array( + * array( + * 'driver' => 'LocalFileSystem', + * 'path' => '/path/to/files/', + * 'URL' => 'http://localhost/to/files/' + * 'plugin' => array( + * 'Watermark' => array( + * 'enable' => true, // For control by volume driver + * 'source' => 'logo.png', // Path to Water mark image + * 'ratio' => 0.2, // Ratio to original image (ratio > 0 and ratio <= 1) + * 'position' => 'RB', // Position L(eft)/C(enter)/R(ight) and T(op)/M(edium)/B(ottom) + * 'marginX' => 5, // Margin horizontal pixel + * 'marginY' => 5, // Margin vertical pixel + * 'quality' => 95, // JPEG image save quality + * 'transparency' => 70, // Water mark image transparency ( other than PNG ) + * 'targetType' => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field ) + * 'targetMinPixel' => 200, // Target image minimum pixel size + * 'interlace' => IMG_GIF|IMG_JPG, // Set interlacebit image formats ( bit-field ) + * 'offDropWith' => null, // Enabled by default. To disable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * 'onDropWith' => null // Disabled by default. To enable it if it is dropped with pressing the meta key + * // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + * // In case of using any key, specify it as an array + * ) + * ) + * ) + * ) + * ); + * + * @package elfinder + * @author Naoki Sawada + * @license New BSD + */ +class elFinderPluginWatermark extends elFinderPlugin +{ + + private $watermarkImgInfo = null; + + public function __construct($opts) + { + $defaults = array( + 'enable' => true, // For control by volume driver + 'source' => 'logo.png', // Path to Water mark image + 'ratio' => 0.2, // Ratio to original image (ratio > 0 and ratio <= 1) + 'position' => 'RB', // Position L(eft)/C(enter)/R(ight) and T(op)/M(edium)/B(ottom) + 'marginX' => 5, // Margin horizontal pixel + 'marginY' => 5, // Margin vertical pixel + 'quality' => 95, // JPEG image save quality + 'transparency' => 70, // Water mark image transparency ( other than PNG ) + 'targetType' => IMG_GIF | IMG_JPG | IMG_PNG | IMG_WBMP, // Target image formats ( bit-field ) + 'targetMinPixel' => 200, // Target image minimum pixel size + 'interlace' => IMG_GIF | IMG_JPG, // Set interlacebit image formats ( bit-field ) + 'offDropWith' => null, // To disable it if it is dropped with pressing the meta key + // Alt: 8, Ctrl: 4, Meta: 2, Shift: 1 - sum of each value + // In case of using any key, specify it as an array + 'marginRight' => 0, // Deprecated - marginX should be used + 'marginBottom' => 0, // Deprecated - marginY should be used + 'disableWithContentSaveId' => true // Disable on URL upload with post data "contentSaveId" + ); + + $this->opts = array_merge($defaults, $opts); + + } + + public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume) + { + if (!$src) { + return false; + } + + $opts = $this->getCurrentOpts($volume); + + if (!$this->iaEnabled($opts, $elfinder)) { + return false; + } + + $imageType = null; + $srcImgInfo = null; + if (extension_loaded('fileinfo') && function_exists('mime_content_type')) { + $mime = mime_content_type($src); + if (substr($mime, 0, 5) !== 'image') { + return false; + } + } + if (extension_loaded('exif') && function_exists('exif_imagetype')) { + $imageType = exif_imagetype($src); + if ($imageType === false) { + return false; + } + } else { + $srcImgInfo = getimagesize($src); + if ($srcImgInfo === false) { + return false; + } + $imageType = $srcImgInfo[2]; + } + + // check target image type + $imgTypes = array( + IMAGETYPE_GIF => IMG_GIF, + IMAGETYPE_JPEG => IMG_JPEG, + IMAGETYPE_PNG => IMG_PNG, + IMAGETYPE_BMP => IMG_WBMP, + IMAGETYPE_WBMP => IMG_WBMP + ); + if (!isset($imgTypes[$imageType]) || !($opts['targetType'] & $imgTypes[$imageType])) { + return false; + } + + // check Animation Gif + if ($imageType === IMAGETYPE_GIF && elFinder::isAnimationGif($src)) { + return false; + } + // check Animation Png + if ($imageType === IMAGETYPE_PNG && elFinder::isAnimationPng($src)) { + return false; + } + // check water mark image + if (!file_exists($opts['source'])) { + $opts['source'] = dirname(__FILE__) . "/" . $opts['source']; + } + if (is_readable($opts['source'])) { + $watermarkImgInfo = getimagesize($opts['source']); + if (!$watermarkImgInfo) { + return false; + } + } else { + return false; + } + + if (!$srcImgInfo) { + $srcImgInfo = getimagesize($src); + } + + $watermark = $opts['source']; + $quality = $opts['quality']; + $transparency = $opts['transparency']; + + // check target image size + if ($opts['targetMinPixel'] > 0 && $opts['targetMinPixel'] > min($srcImgInfo[0], $srcImgInfo[1])) { + return false; + } + + $watermark_width = $watermarkImgInfo[0]; + $watermark_height = $watermarkImgInfo[1]; + + // Specified as a ratio to the image size + if ($opts['ratio'] && $opts['ratio'] > 0 && $opts['ratio'] <= 1) { + $maxW = $srcImgInfo[0] * $opts['ratio'] - ($opts['marginX'] * 2); + $maxH = $srcImgInfo[1] * $opts['ratio'] - ($opts['marginY'] * 2); + $dx = $dy = 0; + if (($maxW >= $watermarkImgInfo[0] && $maxH >= $watermarkImgInfo[0]) || ($maxW <= $watermarkImgInfo[0] && $maxH <= $watermarkImgInfo[0])) { + $dx = abs($srcImgInfo[0] - $watermarkImgInfo[0]); + $dy = abs($srcImgInfo[1] - $watermarkImgInfo[1]); + } else if ($maxW < $watermarkImgInfo[0]) { + $dx = -1; + } else { + $dy = -1; + } + if ($dx < $dy) { + $ww = $maxW; + $wh = $watermarkImgInfo[1] * ($ww / $watermarkImgInfo[0]); + } else { + $wh = $maxH; + $ww = $watermarkImgInfo[0] * ($wh / $watermarkImgInfo[1]); + } + $watermarkImgInfo[0] = $ww; + $watermarkImgInfo[1] = $wh; + } else { + $opts['ratio'] = null; + } + + $opts['position'] = strtoupper($opts['position']); + + // Set vertical position + if (strpos($opts['position'], 'T') !== false) { + // Top + $dest_x = $opts['marginX']; + } else if (strpos($opts['position'], 'M') !== false) { + // Middle + $dest_x = ($srcImgInfo[0] - $watermarkImgInfo[0]) / 2; + } else { + // Bottom + $dest_x = $srcImgInfo[0] - $watermarkImgInfo[0] - max($opts['marginBottom'], $opts['marginX']); + } + + // Set horizontal position + if (strpos($opts['position'], 'L') !== false) { + // Left + $dest_y = $opts['marginY']; + } else if (strpos($opts['position'], 'C') !== false) { + // Middle + $dest_y = ($srcImgInfo[1] - $watermarkImgInfo[1]) / 2; + } else { + // Right + $dest_y = $srcImgInfo[1] - $watermarkImgInfo[1] - max($opts['marginRight'], $opts['marginY']); + } + + + // check interlace + $opts['interlace'] = ($opts['interlace'] & $imgTypes[$imageType]); + + // Repeated use of Imagick::compositeImage() may cause PHP to hang, so disable it + //if (class_exists('Imagick', false)) { + // return $this->watermarkPrint_imagick($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts); + //} else { + elFinder::expandMemoryForGD(array($watermarkImgInfo, $srcImgInfo)); + return $this->watermarkPrint_gd($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $srcImgInfo, $opts); + //} + } + + private function watermarkPrint_imagick($src, $watermarkSrc, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $opts) + { + + try { + + // Open the original image + $img = new Imagick($src); + + // Open the watermark + $watermark = new Imagick($watermarkSrc); + + // zoom + if ($opts['ratio']) { + $watermark->scaleImage($watermarkImgInfo[0], $watermarkImgInfo[1]); + } + + // Set transparency + if (strtoupper($watermark->getImageFormat()) !== 'PNG') { + $watermark->setImageOpacity($transparency / 100); + } + + // Overlay the watermark on the original image + $img->compositeImage($watermark, imagick::COMPOSITE_OVER, $dest_x, $dest_y); + + // Set quality + if (strtoupper($img->getImageFormat()) === 'JPEG') { + $img->setImageCompression(imagick::COMPRESSION_JPEG); + $img->setCompressionQuality($quality); + } + + // set interlace + $opts['interlace'] && $img->setInterlaceScheme(Imagick::INTERLACE_PLANE); + + $result = $img->writeImage($src); + + $img->clear(); + $img->destroy(); + $watermark->clear(); + $watermark->destroy(); + + return $result ? true : false; + } catch (Exception $e) { + $ermsg = $e->getMessage(); + $ermsg && trigger_error($ermsg); + return false; + } + } + + private function watermarkPrint_gd($src, $watermark, $dest_x, $dest_y, $quality, $transparency, $watermarkImgInfo, $srcImgInfo, $opts) + { + + $watermark_width = $watermarkImgInfo[0]; + $watermark_height = $watermarkImgInfo[1]; + + $ermsg = ''; + switch ($watermarkImgInfo['mime']) { + case 'image/gif': + if (imagetypes() & IMG_GIF) { + $oWatermarkImg = imagecreatefromgif($watermark); + } else { + $ermsg = 'GIF images are not supported as watermark image'; + } + break; + case 'image/jpeg': + if (imagetypes() & IMG_JPG) { + $oWatermarkImg = imagecreatefromjpeg($watermark); + } else { + $ermsg = 'JPEG images are not supported as watermark image'; + } + break; + case 'image/png': + if (imagetypes() & IMG_PNG) { + $oWatermarkImg = imagecreatefrompng($watermark); + } else { + $ermsg = 'PNG images are not supported as watermark image'; + } + break; + case 'image/wbmp': + if (imagetypes() & IMG_WBMP) { + $oWatermarkImg = imagecreatefromwbmp($watermark); + } else { + $ermsg = 'WBMP images are not supported as watermark image'; + } + break; + default: + $oWatermarkImg = false; + $ermsg = $watermarkImgInfo['mime'] . ' images are not supported as watermark image'; + break; + } + + + if (!$ermsg) { + // zoom + if ($opts['ratio']) { + $tmpImg = imagecreatetruecolor($watermarkImgInfo[0], $watermarkImgInfo[1]); + imagealphablending($tmpImg, false); + imagesavealpha($tmpImg, true); + imagecopyresampled($tmpImg, $oWatermarkImg, 0, 0, 0, 0, $watermarkImgInfo[0], $watermarkImgInfo[1], imagesx($oWatermarkImg), imagesy($oWatermarkImg)); + imageDestroy($oWatermarkImg); + $oWatermarkImg = $tmpImg; + $tmpImg = null; + } + + switch ($srcImgInfo['mime']) { + case 'image/gif': + if (imagetypes() & IMG_GIF) { + $oSrcImg = imagecreatefromgif($src); + } else { + $ermsg = 'GIF images are not supported as source image'; + } + break; + case 'image/jpeg': + if (imagetypes() & IMG_JPG) { + $oSrcImg = imagecreatefromjpeg($src); + } else { + $ermsg = 'JPEG images are not supported as source image'; + } + break; + case 'image/png': + if (imagetypes() & IMG_PNG) { + $oSrcImg = imagecreatefrompng($src); + } else { + $ermsg = 'PNG images are not supported as source image'; + } + break; + case 'image/wbmp': + if (imagetypes() & IMG_WBMP) { + $oSrcImg = imagecreatefromwbmp($src); + } else { + $ermsg = 'WBMP images are not supported as source image'; + } + break; + default: + $oSrcImg = false; + $ermsg = $srcImgInfo['mime'] . ' images are not supported as source image'; + break; + } + } + + if ($ermsg || false === $oSrcImg || false === $oWatermarkImg) { + $ermsg && trigger_error($ermsg); + return false; + } + + if ($srcImgInfo['mime'] === 'image/png') { + if (function_exists('imagecolorallocatealpha')) { + $bg = imagecolorallocatealpha($oSrcImg, 255, 255, 255, 127); + imagefill($oSrcImg, 0, 0, $bg); + } + } + + if ($watermarkImgInfo['mime'] === 'image/png') { + imagecopy($oSrcImg, $oWatermarkImg, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height); + } else { + imagecopymerge($oSrcImg, $oWatermarkImg, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height, $transparency); + } + + // set interlace + $opts['interlace'] && imageinterlace($oSrcImg, true); + + switch ($srcImgInfo['mime']) { + case 'image/gif': + imagegif($oSrcImg, $src); + break; + case 'image/jpeg': + imagejpeg($oSrcImg, $src, $quality); + break; + case 'image/png': + if (function_exists('imagesavealpha') && function_exists('imagealphablending')) { + imagealphablending($oSrcImg, false); + imagesavealpha($oSrcImg, true); + } + imagepng($oSrcImg, $src); + break; + case 'image/wbmp': + imagewbmp($oSrcImg, $src); + break; + } + + imageDestroy($oSrcImg); + imageDestroy($oWatermarkImg); + + return true; + } +} diff --git a/lib/redactor/elfinder/php/plugins/WinRemoveTailDots/plugin.php b/lib/redactor/elfinder/php/plugins/WinRemoveTailDots/plugin.php new file mode 100644 index 0000000..3fe5339 --- /dev/null +++ b/lib/redactor/elfinder/php/plugins/WinRemoveTailDots/plugin.php @@ -0,0 +1,114 @@ + 'intersect', + 'upload' => 'renames', + 'mkdir' => array('name', 'dirs') + ); + + public function __construct($opts) + { + $defaults = array( + 'enable' => false, // For control by volume driver + ); + + $this->opts = array_merge($defaults, $opts); + } + + public function cmdPreprocess($cmd, &$args, $elfinder, $volume) + { + $opts = $this->getCurrentOpts($volume); + if (!$opts['enable']) { + return false; + } + $this->replaced[$cmd] = array(); + $key = (isset($this->keyMap[$cmd])) ? $this->keyMap[$cmd] : 'name'; + + if (is_array($key)) { + $keys = $key; + } else { + $keys = array($key); + } + foreach ($keys as $key) { + if (isset($args[$key])) { + if (is_array($args[$key])) { + foreach ($args[$key] as $i => $name) { + if ($cmd === 'mkdir' && $key === 'dirs') { + // $name need '/' as prefix see #2607 + $name = '/' . ltrim($name, '/'); + $_names = explode('/', $name); + $_res = array(); + foreach ($_names as $_name) { + $_res[] = $this->normalize($_name, $opts); + } + $this->replaced[$cmd][$name] = $args[$key][$i] = join('/', $_res); + } else { + $this->replaced[$cmd][$name] = $args[$key][$i] = $this->normalize($name, $opts); + } + } + } else if ($args[$key] !== '') { + $name = $args[$key]; + $this->replaced[$cmd][$name] = $args[$key] = $this->normalize($name, $opts); + } + } + } + if ($cmd === 'ls' || $cmd === 'mkdir') { + if (!empty($this->replaced[$cmd])) { + // un-regist for legacy settings + $elfinder->unbind($cmd, array($this, 'cmdPostprocess')); + $elfinder->bind($cmd, array($this, 'cmdPostprocess')); + } + } + return true; + } + + public function cmdPostprocess($cmd, &$result, $args, $elfinder, $volume) + { + if ($cmd === 'ls') { + if (!empty($result['list']) && !empty($this->replaced['ls'])) { + foreach ($result['list'] as $hash => $name) { + if ($keys = array_keys($this->replaced['ls'], $name)) { + if (count($keys) === 1) { + $result['list'][$hash] = $keys[0]; + } else { + $result['list'][$hash] = $keys; + } + } + } + } + } else if ($cmd === 'mkdir') { + if (!empty($result['hashes']) && !empty($this->replaced['mkdir'])) { + foreach ($result['hashes'] as $name => $hash) { + if ($keys = array_keys($this->replaced['mkdir'], $name)) { + $result['hashes'][$keys[0]] = $hash; + } + } + } + } + } + + // NOTE: $thash is directory hash so it unneed to process at here + public function onUpLoadPreSave(&$thash, &$name, $src, $elfinder, $volume) + { + $opts = $this->getCurrentOpts($volume); + if (!$opts['enable']) { + return false; + } + + $name = $this->normalize($name, $opts); + return true; + } + + protected function normalize($str, $opts) + { + $str = rtrim($str, '.'); + return $str; + } +} // END class elFinderPluginWinRemoveTailDots diff --git a/lib/redactor/elfinder/php/resources/image.png b/lib/redactor/elfinder/php/resources/image.png new file mode 100644 index 0000000..fc6f33e Binary files /dev/null and b/lib/redactor/elfinder/php/resources/image.png differ diff --git a/lib/redactor/elfinder/php/resources/video.png b/lib/redactor/elfinder/php/resources/video.png new file mode 100644 index 0000000..1523cc1 Binary files /dev/null and b/lib/redactor/elfinder/php/resources/video.png differ diff --git a/lib/redactor/elfinder/sounds/rm.wav b/lib/redactor/elfinder/sounds/rm.wav new file mode 100644 index 0000000..0e1a21a Binary files /dev/null and b/lib/redactor/elfinder/sounds/rm.wav differ diff --git a/lib/scripts/clipboard.min.js b/lib/scripts/clipboard.min.js new file mode 100644 index 0000000..580433f --- /dev/null +++ b/lib/scripts/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v1.5.12 + * https://zenorocha.github.io/clipboard.js + * + * Licensed MIT © Zeno Rocha + */ +!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,o){function i(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(r)return r(a,!0);var l=new Error("Cannot find module '"+a+"'");throw l.code="MODULE_NOT_FOUND",l}var u=n[a]={exports:{}};e[a][0].call(u.exports,function(t){var n=e[a][1][t];return i(n?n:t)},u,u.exports,t,e,n,o)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;ao;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],i=[];if(o&&e)for(var r=0,a=o.length;a>r;r++)o[r].fn!==e&&o[r].fn._!==e&&i.push(o[r]);return i.length?n[t]=i:delete n[t],this}},e.exports=o},{}],8:[function(e,n,o){!function(i,r){if("function"==typeof t&&t.amd)t(["module","select"],r);else if("undefined"!=typeof o)r(n,e("select"));else{var a={exports:{}};r(a,i.select),i.clipboardAction=a.exports}}(this,function(t,e){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=n(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},a=function(){function t(t,e){for(var n=0;na?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
                      ",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
                      a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
                      ","
                      "],area:[1,"",""],param:[1,"",""],thead:[1,"","
                      "],tr:[2,"","
                      "],col:[2,"","
                      "],td:[3,"","
                      "],_default:k.htmlSerialize?[0,"",""]:[1,"X
                      ","
                      "]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("':""),a._keyEvent=!1,K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='
                      ',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}return l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
                      ",l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e,e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));return b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth())),this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");return b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10),{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);return typeof a!="string"||a!="isDisabled"&&a!="getDate"&&a!="widget"?a=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b)):this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)}):$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.24",window["DP_jQuery_"+dpuuid]=$}(jQuery),function(a,b){var c="ui-dialog ui-widget ui-widget-content ui-corner-all ",d={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},e={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};a.widget("ui.dialog",{options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",collision:"fit",using:function(b){var c=a(this).css(b).offset().top;c<0&&a(this).css("top",b.top-c)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.options.title=this.options.title||this.originalTitle;var b=this,d=b.options,e=d.title||" ",f=a.ui.dialog.getTitleId(b.element),g=(b.uiDialog=a("
                      ")).appendTo(document.body).hide().addClass(c+d.dialogClass).css({zIndex:d.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(c){d.closeOnEscape&&!c.isDefaultPrevented()&&c.keyCode&&c.keyCode===a.ui.keyCode.ESCAPE&&(b.close(c),c.preventDefault())}).attr({role:"dialog","aria-labelledby":f}).mousedown(function(a){b.moveToTop(!1,a)}),h=b.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g),i=(b.uiDialogTitlebar=a("
                      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),j=a('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){j.addClass("ui-state-hover")},function(){j.removeClass("ui-state-hover")}).focus(function(){j.addClass("ui-state-focus")}).blur(function(){j.removeClass("ui-state-focus")}).click(function(a){return b.close(a),!1}).appendTo(i),k=(b.uiDialogTitlebarCloseText=a("")).addClass("ui-icon ui-icon-closethick").text(d.closeText).appendTo(j),l=a("").addClass("ui-dialog-title").attr("id",f).html(e).prependTo(i);a.isFunction(d.beforeclose)&&!a.isFunction(d.beforeClose)&&(d.beforeClose=d.beforeclose),i.find("*").add(i).disableSelection(),d.draggable&&a.fn.draggable&&b._makeDraggable(),d.resizable&&a.fn.resizable&&b._makeResizable(),b._createButtons(d.buttons),b._isOpen=!1,a.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;return a.overlay&&a.overlay.destroy(),a.uiDialog.hide(),a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),a.uiDialog.remove(),a.originalTitle&&a.element.attr("title",a.originalTitle),a},widget:function(){return this.uiDialog},close:function(b){var c=this,d,e;if(!1===c._trigger("beforeClose",b))return;return c.overlay&&c.overlay.destroy(),c.uiDialog.unbind("keypress.ui-dialog"),c._isOpen=!1,c.options.hide?c.uiDialog.hide(c.options.hide,function(){c._trigger("close",b)}):(c.uiDialog.hide(),c._trigger("close",b)),a.ui.dialog.overlay.resize(),c.options.modal&&(d=0,a(".ui-dialog").each(function(){this!==c.uiDialog[0]&&(e=a(this).css("z-index"),isNaN(e)||(d=Math.max(d,e)))}),a.ui.dialog.maxZ=d),c},isOpen:function(){return this._isOpen},moveToTop:function(b,c){var d=this,e=d.options,f;return e.modal&&!b||!e.stack&&!e.modal?d._trigger("focus",c):(e.zIndex>a.ui.dialog.maxZ&&(a.ui.dialog.maxZ=e.zIndex),d.overlay&&(a.ui.dialog.maxZ+=1,d.overlay.$el.css("z-index",a.ui.dialog.overlay.maxZ=a.ui.dialog.maxZ)),f={scrollTop:d.element.scrollTop(),scrollLeft:d.element.scrollLeft()},a.ui.dialog.maxZ+=1,d.uiDialog.css("z-index",a.ui.dialog.maxZ),d.element.attr(f),d._trigger("focus",c),d)},open:function(){if(this._isOpen)return;var b=this,c=b.options,d=b.uiDialog;return b.overlay=c.modal?new a.ui.dialog.overlay(b):null,b._size(),b._position(c.position),d.show(c.show),b.moveToTop(!0),c.modal&&d.bind("keydown.ui-dialog",function(b){if(b.keyCode!==a.ui.keyCode.TAB)return;var c=a(":tabbable",this),d=c.filter(":first"),e=c.filter(":last");if(b.target===e[0]&&!b.shiftKey)return d.focus(1),!1;if(b.target===d[0]&&b.shiftKey)return e.focus(1),!1}),a(b.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus(),b._isOpen=!0,b._trigger("open"),b},_createButtons:function(b){var c=this,d=!1,e=a("
                      ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),f=a("
                      ").addClass("ui-dialog-buttonset").appendTo(e);c.uiDialog.find(".ui-dialog-buttonpane").remove(),typeof b=="object"&&b!==null&&a.each(b,function(){return!(d=!0)}),d&&(a.each(b,function(b,d){d=a.isFunction(d)?{click:d,text:b}:d;var e=a('').click(function(){d.click.apply(c.element[0],arguments)}).appendTo(f);a.each(d,function(a,b){if(a==="click")return;a in e?e[a](b):e.attr(a,b)}),a.fn.button&&e.button()}),e.appendTo(c.uiDialog))},_makeDraggable:function(){function f(a){return{position:a.position,offset:a.offset}}var b=this,c=b.options,d=a(document),e;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(d,g){e=c.height==="auto"?"auto":a(this).height(),a(this).height(a(this).height()).addClass("ui-dialog-dragging"),b._trigger("dragStart",d,f(g))},drag:function(a,c){b._trigger("drag",a,f(c))},stop:function(g,h){c.position=[h.position.left-d.scrollLeft(),h.position.top-d.scrollTop()],a(this).removeClass("ui-dialog-dragging").height(e),b._trigger("dragStop",g,f(h)),a.ui.dialog.overlay.resize()}})},_makeResizable:function(c){function h(a){return{originalPosition:a.originalPosition,originalSize:a.originalSize,position:a.position,size:a.size}}c=c===b?this.options.resizable:c;var d=this,e=d.options,f=d.uiDialog.css("position"),g=typeof c=="string"?c:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:g,start:function(b,c){a(this).addClass("ui-dialog-resizing"),d._trigger("resizeStart",b,h(c))},resize:function(a,b){d._trigger("resize",a,h(b))},stop:function(b,c){a(this).removeClass("ui-dialog-resizing"),e.height=a(this).height(),e.width=a(this).width(),d._trigger("resizeStop",b,h(c)),a.ui.dialog.overlay.resize()}}).css("position",f).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(b){var c=[],d=[0,0],e;if(b){if(typeof b=="string"||typeof b=="object"&&"0"in b)c=b.split?b.split(" "):[b[0],b[1]],c.length===1&&(c[1]=c[0]),a.each(["left","top"],function(a,b){+c[a]===c[a]&&(d[a]=c[a],c[a]=b)}),b={my:c.join(" "),at:c.join(" "),offset:d.join(" ")};b=a.extend({},a.ui.dialog.prototype.options.position,b)}else b=a.ui.dialog.prototype.options.position;e=this.uiDialog.is(":visible"),e||this.uiDialog.show(),this.uiDialog.css({top:0,left:0}).position(a.extend({of:window},b)),e||this.uiDialog.hide()},_setOptions:function(b){var c=this,f={},g=!1;a.each(b,function(a,b){c._setOption(a,b),a in d&&(g=!0),a in e&&(f[a]=b)}),g&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",f)},_setOption:function(b,d){var e=this,f=e.uiDialog;switch(b){case"beforeclose":b="beforeClose";break;case"buttons":e._createButtons(d);break;case"closeText":e.uiDialogTitlebarCloseText.text(""+d);break;case"dialogClass":f.removeClass(e.options.dialogClass).addClass(c+d);break;case"disabled":d?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case"draggable":var g=f.is(":data(draggable)");g&&!d&&f.draggable("destroy"),!g&&d&&e._makeDraggable();break;case"position":e._position(d);break;case"resizable":var h=f.is(":data(resizable)");h&&!d&&f.resizable("destroy"),h&&typeof d=="string"&&f.resizable("option","handles",d),!h&&d!==!1&&e._makeResizable(d);break;case"title":a(".ui-dialog-title",e.uiDialogTitlebar).html(""+(d||" "))}a.Widget.prototype._setOption.apply(e,arguments)},_size:function(){var b=this.options,c,d,e=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),b.minWidth>b.width&&(b.width=b.minWidth),c=this.uiDialog.css({height:"auto",width:b.width}).height(),d=Math.max(0,b.minHeight-c);if(b.height==="auto")if(a.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();var f=this.element.css("height","auto").height();e||this.uiDialog.hide(),this.element.height(Math.max(f,d))}else this.element.height(Math.max(b.height-c,0));this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),a.extend(a.ui.dialog,{version:"1.8.24",uuid:0,maxZ:0,getTitleId:function(a){var b=a.attr("id");return b||(this.uuid+=1,b=this.uuid),"ui-dialog-title-"+b},overlay:function(b){this.$el=a.ui.dialog.overlay.create(b)}}),a.extend(a.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:a.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(b){this.instances.length===0&&(setTimeout(function(){a.ui.dialog.overlay.instances.length&&a(document).bind(a.ui.dialog.overlay.events,function(b){if(a(b.target).zIndex()").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});return a.fn.bgiframe&&c.bgiframe(),this.instances.push(c),c},destroy:function(b){var c=a.inArray(b,this.instances);c!=-1&&this.oldInstances.push(this.instances.splice(c,1)[0]),this.instances.length===0&&a([document,window]).unbind(".dialog-overlay"),b.remove();var d=0;a.each(this.instances,function(){d=Math.max(d,this.css("z-index"))}),this.maxZ=d},height:function(){var b,c;return a.browser.msie&&a.browser.version<7?(b=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),c=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),b0?b.left-e:Math.max(b.left-c.collisionPosition.left,b.left)},top:function(b,c){var d=a(window),e=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop();b.top=e>0?b.top-e:Math.max(b.top-c.collisionPosition.top,b.top)}},flip:{left:function(b,c){if(c.at[0]===e)return;var d=a(window),f=c.collisionPosition.left+c.collisionWidth-d.width()-d.scrollLeft(),g=c.my[0]==="left"?-c.elemWidth:c.my[0]==="right"?c.elemWidth:0,h=c.at[0]==="left"?c.targetWidth:-c.targetWidth,i=-2*c.offset[0];b.left+=c.collisionPosition.left<0?g+h+i:f>0?g+h+i:0},top:function(b,c){if(c.at[1]===e)return;var d=a(window),f=c.collisionPosition.top+c.collisionHeight-d.height()-d.scrollTop(),g=c.my[1]==="top"?-c.elemHeight:c.my[1]==="bottom"?c.elemHeight:0,h=c.at[1]==="top"?c.targetHeight:-c.targetHeight,i=-2*c.offset[1];b.top+=c.collisionPosition.top<0?g+h+i:f>0?g+h+i:0}}},a.offset.setOffset||(a.offset.setOffset=function(b,c){/static/.test(a.curCSS(b,"position"))&&(b.style.position="relative");var d=a(b),e=d.offset(),f=parseInt(a.curCSS(b,"top",!0),10)||0,g=parseInt(a.curCSS(b,"left",!0),10)||0,h={top:c.top-e.top+f,left:c.left-e.left+g};"using"in c?c.using.call(b,h):d.css(h)},a.fn.offset=function(b){var c=this[0];return!c||!c.ownerDocument?null:b?a.isFunction(b)?this.each(function(c){a(this).offset(b.call(this,c,a(this).offset()))}):this.each(function(){a.offset.setOffset(this,b)}):h.call(this)}),a.curCSS||(a.curCSS=a.css),function(){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d,e,g,h,i;d=document.createElement(b?"div":"body"),g={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},b&&a.extend(g,{position:"absolute",left:"-1000px",top:"-1000px"});for(var j in g)d.style[j]=g[j];d.appendChild(c),e=b||document.documentElement,e.insertBefore(d,e.firstChild),c.style.cssText="position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;",h=a(c).offset(function(a,b){return b}).offset(),d.innerHTML="",e.removeChild(d),i=h.top+h.left+(b?2e3:0),f.fractions=i>21&&i<22}()}(jQuery),function(a,b){a.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()}),this.valueDiv=a("
                      ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove(),a.Widget.prototype.destroy.apply(this,arguments)},value:function(a){return a===b?this._value():(this._setOption("value",a),this)},_setOption:function(b,c){b==="value"&&(this.options.value=c,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),a.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;return typeof a!="number"&&(a=0),Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var a=this.value(),b=this._percentage();this.oldValue!==a&&(this.oldValue=a,this._trigger("change")),this.valueDiv.toggle(a>this.min).toggleClass("ui-corner-right",a===this.options.max).width(b.toFixed(0)+"%"),this.element.attr("aria-valuenow",a)}}),a.extend(a.ui.progressbar,{version:"1.8.24"})}(jQuery),function(a,b){var c=5;a.widget("ui.slider",a.ui.mouse,{widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var b=this,d=this.options,e=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),f="",g=d.values&&d.values.length||1,h=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(d.disabled?" ui-slider-disabled ui-disabled":"")),this.range=a([]),d.range&&(d.range===!0&&(d.values||(d.values=[this._valueMin(),this._valueMin()]),d.values.length&&d.values.length!==2&&(d.values=[d.values[0],d.values[0]])),this.range=a("
                      ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(d.range==="min"||d.range==="max"?" ui-slider-range-"+d.range:"")));for(var i=e.length;ic&&(f=c,g=a(this),i=b)}),c.range===!0&&this.values(1)===c.min&&(i+=1,g=a(this.handles[i])),j=this._start(b,i),j===!1?!1:(this._mouseSliding=!0,h._handleIndex=i,g.addClass("ui-state-active").focus(),k=g.offset(),l=!a(b.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=l?{left:0,top:0}:{left:b.pageX-k.left-g.width()/2,top:b.pageY-k.top-g.height()/2-(parseInt(g.css("borderTopWidth"),10)||0)-(parseInt(g.css("borderBottomWidth"),10)||0)+(parseInt(g.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(b,i,e),this._animateOff=!0,!0))},_mouseStart:function(a){return!0},_mouseDrag:function(a){var b={x:a.pageX,y:a.pageY},c=this._normValueFromMouse(b);return this._slide(a,this._handleIndex,c),!1},_mouseStop:function(a){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(a,this._handleIndex),this._change(a,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b,c,d,e,f;return this.orientation==="horizontal"?(b=this.elementSize.width,c=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(b=this.elementSize.height,c=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),d=c/b,d>1&&(d=1),d<0&&(d=0),this.orientation==="vertical"&&(d=1-d),e=this._valueMax()-this._valueMin(),f=this._valueMin()+d*e,this._trimAlignValue(f)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};return this.options.values&&this.options.values.length&&(c.value=this.values(b),c.values=this.values()),this._trigger("start",a,c)},_slide:function(a,b,c){var d,e,f;this.options.values&&this.options.values.length?(d=this.values(b?0:1),this.options.values.length===2&&this.options.range===!0&&(b===0&&c>d||b===1&&c1){this.options.values[b]=this._trimAlignValue(c),this._refreshValue(),this._change(null,b);return}if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(b):this.value();d=this.options.values,e=arguments[0];for(f=0;f=this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=(a-this._valueMin())%b,d=a-c;return Math.abs(c)*2>=b&&(d+=c>0?b:-b),parseFloat(d.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var b=this.options.range,c=this.options,d=this,e=this._animateOff?!1:c.animate,f,g={},h,i,j,k;this.options.values&&this.options.values.length?this.handles.each(function(b,i){f=(d.values(b)-d._valueMin())/(d._valueMax()-d._valueMin())*100,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",a(this).stop(1,1)[e?"animate":"css"](g,c.animate),d.options.range===!0&&(d.orientation==="horizontal"?(b===0&&d.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({width:f-h+"%"},{queue:!1,duration:c.animate})):(b===0&&d.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},c.animate),b===1&&d.range[e?"animate":"css"]({height:f-h+"%"},{queue:!1,duration:c.animate}))),h=f}):(i=this.value(),j=this._valueMin(),k=this._valueMax(),f=k!==j?(i-j)/(k-j)*100:0,g[d.orientation==="horizontal"?"left":"bottom"]=f+"%",this.handle.stop(1,1)[e?"animate":"css"](g,c.animate),b==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},c.animate),b==="max"&&this.orientation==="horizontal"&&this.range[e?"animate":"css"]({width:100-f+"%"},{queue:!1,duration:c.animate}),b==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},c.animate),b==="max"&&this.orientation==="vertical"&&this.range[e?"animate":"css"]({height:100-f+"%"},{queue:!1,duration:c.animate}))}}),a.extend(a.ui.slider,{version:"1.8.24"})}(jQuery),function(a,b){function e(){return++c}function f(){return++d}var c=0,d=0;a.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:!1,cookie:null,collapsible:!1,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"
                      ",remove:null,select:null,show:null,spinner:"Loading…",tabTemplate:"
                    • #{label}
                    • "},_create:function(){this._tabify(!0)},_setOption:function(a,b){if(a=="selected"){if(this.options.collapsible&&b==this.options.selected)return;this.select(b)}else this.options[a]=b,this._tabify()},_tabId:function(a){return a.title&&a.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+e()},_sanitizeSelector:function(a){return a.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+f());return a.cookie.apply(null,[b].concat(a.makeArray(arguments)))},_ui:function(a,b){return{tab:a,panel:b,index:this.anchors.index(a)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=a(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(c){function m(b,c){b.css("display",""),!a.support.opacity&&c.opacity&&b[0].style.removeAttribute("filter")}var d=this,e=this.options,f=/^#.+/;this.list=this.element.find("ol,ul").eq(0),this.lis=a(" > li:has(a[href])",this.list),this.anchors=this.lis.map(function(){return a("a",this)[0]}),this.panels=a([]),this.anchors.each(function(b,c){var g=a(c).attr("href"),h=g.split("#")[0],i;h&&(h===location.toString().split("#")[0]||(i=a("base")[0])&&h===i.href)&&(g=c.hash,c.href=g);if(f.test(g))d.panels=d.panels.add(d.element.find(d._sanitizeSelector(g)));else if(g&&g!=="#"){a.data(c,"href.tabs",g),a.data(c,"load.tabs",g.replace(/#.*$/,""));var j=d._tabId(c);c.href="#"+j;var k=d.element.find("#"+j);k.length||(k=a(e.panelTemplate).attr("id",j).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(d.panels[b-1]||d.list),k.data("destroy.tabs",!0)),d.panels=d.panels.add(k)}else e.disabled.push(b)}),c?(this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all"),this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.lis.addClass("ui-state-default ui-corner-top"),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom"),e.selected===b?(location.hash&&this.anchors.each(function(a,b){if(b.hash==location.hash)return e.selected=a,!1}),typeof e.selected!="number"&&e.cookie&&(e.selected=parseInt(d._cookie(),10)),typeof e.selected!="number"&&this.lis.filter(".ui-tabs-selected").length&&(e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))),e.selected=e.selected||(this.lis.length?0:-1)):e.selected===null&&(e.selected=-1),e.selected=e.selected>=0&&this.anchors[e.selected]||e.selected<0?e.selected:0,e.disabled=a.unique(e.disabled.concat(a.map(this.lis.filter(".ui-state-disabled"),function(a,b){return d.lis.index(a)}))).sort(),a.inArray(e.selected,e.disabled)!=-1&&e.disabled.splice(a.inArray(e.selected,e.disabled),1),this.panels.addClass("ui-tabs-hide"),this.lis.removeClass("ui-tabs-selected ui-state-active"),e.selected>=0&&this.anchors.length&&(d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash)).removeClass("ui-tabs-hide"),this.lis.eq(e.selected).addClass("ui-tabs-selected ui-state-active"),d.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[e.selected],d.element.find(d._sanitizeSelector(d.anchors[e.selected].hash))[0]))}),this.load(e.selected)),a(window).bind("unload",function(){d.lis.add(d.anchors).unbind(".tabs"),d.lis=d.anchors=d.panels=null})):e.selected=this.lis.index(this.lis.filter(".ui-tabs-selected")),this.element[e.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible"),e.cookie&&this._cookie(e.selected,e.cookie);for(var g=0,h;h=this.lis[g];g++)a(h)[a.inArray(g,e.disabled)!=-1&&!a(h).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");e.cache===!1&&this.anchors.removeData("cache.tabs"),this.lis.add(this.anchors).unbind(".tabs");if(e.event!=="mouseover"){var i=function(a,b){b.is(":not(.ui-state-disabled)")&&b.addClass("ui-state-"+a)},j=function(a,b){b.removeClass("ui-state-"+a)};this.lis.bind("mouseover.tabs",function(){i("hover",a(this))}),this.lis.bind("mouseout.tabs",function(){j("hover",a(this))}),this.anchors.bind("focus.tabs",function(){i("focus",a(this).closest("li"))}),this.anchors.bind("blur.tabs",function(){j("focus",a(this).closest("li"))})}var k,l;e.fx&&(a.isArray(e.fx)?(k=e.fx[0],l=e.fx[1]):k=l=e.fx);var n=l?function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.hide().removeClass("ui-tabs-hide").animate(l,l.duration||"normal",function(){m(c,l),d._trigger("show",null,d._ui(b,c[0]))})}:function(b,c){a(b).closest("li").addClass("ui-tabs-selected ui-state-active"),c.removeClass("ui-tabs-hide"),d._trigger("show",null,d._ui(b,c[0]))},o=k?function(a,b){b.animate(k,k.duration||"normal",function(){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),m(b,k),d.element.dequeue("tabs")})}:function(a,b,c){d.lis.removeClass("ui-tabs-selected ui-state-active"),b.addClass("ui-tabs-hide"),d.element.dequeue("tabs")};this.anchors.bind(e.event+".tabs",function(){var b=this,c=a(b).closest("li"),f=d.panels.filter(":not(.ui-tabs-hide)"),g=d.element.find(d._sanitizeSelector(b.hash));if(c.hasClass("ui-tabs-selected")&&!e.collapsible||c.hasClass("ui-state-disabled")||c.hasClass("ui-state-processing")||d.panels.filter(":animated").length||d._trigger("select",null,d._ui(this,g[0]))===!1)return this.blur(),!1;e.selected=d.anchors.index(this),d.abort();if(e.collapsible){if(c.hasClass("ui-tabs-selected"))return e.selected=-1,e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){o(b,f)}).dequeue("tabs"),this.blur(),!1;if(!f.length)return e.cookie&&d._cookie(e.selected,e.cookie),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this)),this.blur(),!1}e.cookie&&d._cookie(e.selected,e.cookie);if(g.length)f.length&&d.element.queue("tabs",function(){o(b,f)}),d.element.queue("tabs",function(){n(b,g)}),d.load(d.anchors.index(this));else throw"jQuery UI Tabs: Mismatching fragment identifier.";a.browser.msie&&this.blur()}),this.anchors.bind("click.tabs",function(){return!1})},_getIndex:function(a){return typeof a=="string"&&(a=this.anchors.index(this.anchors.filter("[href$='"+a+"']"))),a},destroy:function(){var b=this.options;return this.abort(),this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs"),this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all"),this.anchors.each(function(){var b=a.data(this,"href.tabs");b&&(this.href=b);var c=a(this).unbind(".tabs");a.each(["href","load","cache"],function(a,b){c.removeData(b+".tabs")})}),this.lis.unbind(".tabs").add(this.panels).each(function(){a.data(this,"destroy.tabs")?a(this).remove():a(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}),b.cookie&&this._cookie(null,b.cookie),this},add:function(c,d,e){e===b&&(e=this.anchors.length);var f=this,g=this.options,h=a(g.tabTemplate.replace(/#\{href\}/g,c).replace(/#\{label\}/g,d)),i=c.indexOf("#")?this._tabId(a("a",h)[0]):c.replace("#","");h.addClass("ui-state-default ui-corner-top").data("destroy.tabs",!0);var j=f.element.find("#"+i);return j.length||(j=a(g.panelTemplate).attr("id",i).data("destroy.tabs",!0)),j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide"),e>=this.lis.length?(h.appendTo(this.list),j.appendTo(this.list[0].parentNode)):(h.insertBefore(this.lis[e]),j.insertBefore(this.panels[e])),g.disabled=a.map(g.disabled,function(a,b){return a>=e?++a:a}),this._tabify(),this.anchors.length==1&&(g.selected=0,h.addClass("ui-tabs-selected ui-state-active"),j.removeClass("ui-tabs-hide"),this.element.queue("tabs",function(){f._trigger("show",null,f._ui(f.anchors[0],f.panels[0]))}),this.load(0)),this._trigger("add",null,this._ui(this.anchors[e],this.panels[e])),this},remove:function(b){b=this._getIndex(b);var c=this.options,d=this.lis.eq(b).remove(),e=this.panels.eq(b).remove();return d.hasClass("ui-tabs-selected")&&this.anchors.length>1&&this.select(b+(b+1=b?--a:a}),this._tabify(),this._trigger("remove",null,this._ui(d.find("a")[0],e[0])),this},enable:function(b){b=this._getIndex(b);var c=this.options;if(a.inArray(b,c.disabled)==-1)return;return this.lis.eq(b).removeClass("ui-state-disabled"),c.disabled=a.grep(c.disabled,function(a,c){return a!=b}),this._trigger("enable",null,this._ui(this.anchors[b],this.panels[b])),this},disable:function(a){a=this._getIndex(a);var b=this,c=this.options;return a!=c.selected&&(this.lis.eq(a).addClass("ui-state-disabled"),c.disabled.push(a),c.disabled.sort(),this._trigger("disable",null,this._ui(this.anchors[a],this.panels[a]))),this},select:function(a){a=this._getIndex(a);if(a==-1)if(this.options.collapsible&&this.options.selected!=-1)a=this.options.selected;else return this;return this.anchors.eq(a).trigger(this.options.event+".tabs"),this},load:function(b){b=this._getIndex(b);var c=this,d=this.options,e=this.anchors.eq(b)[0],f=a.data(e,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&a.data(e,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(b).addClass("ui-state-processing");if(d.spinner){var g=a("span",e);g.data("label.tabs",g.html()).html(d.spinner)}return this.xhr=a.ajax(a.extend({},d.ajaxOptions,{url:f,success:function(f,g){c.element.find(c._sanitizeSelector(e.hash)).html(f),c._cleanup(),d.cache&&a.data(e,"cache.tabs",!0),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.success(f,g)}catch(h){}},error:function(a,f,g){c._cleanup(),c._trigger("load",null,c._ui(c.anchors[b],c.panels[b]));try{d.ajaxOptions.error(a,f,b,e)}catch(g){}}})),c.element.dequeue("tabs"),this},abort:function(){return this.element.queue([]),this.panels.stop(!1,!0),this.element.queue("tabs",this.element.queue("tabs").splice(-2,2)),this.xhr&&(this.xhr.abort(),delete this.xhr),this._cleanup(),this},url:function(a,b){return this.anchors.eq(a).removeData("cache.tabs").data("load.tabs",b),this},length:function(){return this.anchors.length}}),a.extend(a.ui.tabs,{version:"1.8.24"}),a.extend(a.ui.tabs.prototype,{rotation:null,rotate:function(a,b){var c=this,d=this.options,e=c._rotate||(c._rotate=function(b){clearTimeout(c.rotation),c.rotation=setTimeout(function(){var a=d.selected;c.select(++a' + + '' + + '' + + ''); + + if ($.alerts.dialogClass) $("#popup_container").addClass($.alerts.dialogClass); + + // IE6 Fix + var pos = ($.browser.msie && parseInt($.browser.version) <= 6) ? 'absolute' : 'fixed'; + + $("#popup_container").css({ + position: pos, + zIndex: 99999, + padding: 5, + margin: 0 + }); + + $("#popup_title").text(title); + $("#popup_content").addClass(type); + $("#popup_message").text(msg); + $("#popup_message").html($("#popup_message").text().replace(/\n/g, '
                      ')); + + $("#popup_container").css({ + minWidth: $("#popup_container").outerWidth(), + maxWidth: $("#popup_container").outerWidth() + }); + + $.alerts._reposition(); + $.alerts._maintainPosition(true); + + switch (type) { + case 'alert': + $("#popup_message").after(''); + $("#popup_ok").click(function() { + $.alerts._hide(); + callback(true); + }); + $("#popup_ok").focus().keypress(function(e) { + if (e.keyCode == 13 || e.keyCode == 27) $("#popup_ok").trigger('click'); + }); + break; + case 'confirm': + $("#popup_message").after(''); + $("#popup_ok").click(function() { + $.alerts._hide(); + if (callback) callback(true); + }); + $("#popup_cancel").click(function() { + $.alerts._hide(); + if (callback) callback(false); + }); + $("#popup_ok").focus(); + $("#popup_ok, #popup_cancel").keypress(function(e) { + if (e.keyCode == 13) $("#popup_ok").trigger('click'); + if (e.keyCode == 27) $("#popup_cancel").trigger('click'); + }); + break; + case 'prompt': + $("#popup_message").append('
                      ').after(''); + /*$("#popup_prompt").width( $("#popup_message").width(-10) );*/ + $("#popup_ok").click(function() { + var val = $("#popup_prompt").val(); + $.alerts._hide(); + if (callback) callback(val); + }); + $("#popup_cancel").click(function() { + $.alerts._hide(); + if (callback) callback(null); + }); + $("#popup_prompt, #popup_ok, #popup_cancel").keypress(function(e) { + if (e.keyCode == 13) $("#popup_ok").trigger('click'); + if (e.keyCode == 27) $("#popup_cancel").trigger('click'); + }); + if (value) $("#popup_prompt").val(value); + $("#popup_prompt").focus().select(); + break; + } + + // Make draggable + if ($.alerts.draggable) { + try { + $("#popup_container").draggable({ + handle: $("#popup_title") + }); + $("#popup_title").css({ + cursor: 'move' + }); + } catch (e) { /* requires jQuery UI draggables */ } + } + }, + + _hide: function() { + $("#popup_container").remove(); + $.alerts._overlay('hide'); + $.alerts._maintainPosition(false); + }, + + _overlay: function(status) { + switch (status) { + case 'show': + $.alerts._overlay('hide'); + $("BODY").append(''); + $("#popup_alert_overlay").css({ + position: 'absolute', + zIndex: 99998, + top: '0px', + left: '0px', + width: '100%', + cursor: 'wait', + height: $(document).height(), + background: $.alerts.overlayColor, + opacity: $.alerts.overlayOpacity + }); + break; + case 'hide': + $("#popup_alert_overlay").remove(); + break; + } + }, + + _reposition: function() { + var top = (($(window).height() / 2) - ($("#popup_container").outerHeight() / 2)) + $.alerts.verticalOffset; + var left = (($(window).width() / 2) - ($("#popup_container").outerWidth() / 2)) + $.alerts.horizontalOffset; + if (top < 0) top = 0; + if (left < 0) left = 0; + + // IE6 fix + if ($.browser.msie && parseInt($.browser.version) <= 6) top = top + $(window).scrollTop(); + + $("#popup_container").css({ + top: top + 'px', + left: left + 'px' + }); + $("#popup_overlay").height($(document).height()); + }, + + _maintainPosition: function(status) { + if ($.alerts.repositionOnResize) { + switch (status) { + case true: + $(window).bind('resize', $.alerts._reposition); + break; + case false: + $(window).unbind('resize', $.alerts._reposition); + break; + } + } + } + + } + + // Shortuct functions + jAlert = function(message, title, callback) { + $.alerts.alert(message, title, callback); + } + + jConfirm = function(message, title, callback) { + $.alerts.confirm(message, title, callback); + }; + + jPrompt = function(message, value, title, callback) { + $.alerts.prompt(message, value, title, callback); + }; + +})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.autocomplete.js b/lib/scripts/jquery.autocomplete.js new file mode 100644 index 0000000..497a80a --- /dev/null +++ b/lib/scripts/jquery.autocomplete.js @@ -0,0 +1,848 @@ +/* + * jQuery Autocomplete plugin 1.2.3 + * + * Copyright (c) 2009 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * With small modifications by Alfonso Gómez-Arzola. + * See changelog for details. + * + */ + +;(function($) { + +$.fn.extend({ + autocomplete: function(urlOrData, options) { + var isUrl = typeof urlOrData == "string"; + options = $.extend({}, $.Autocompleter.defaults, { + url: isUrl ? urlOrData : null, + data: isUrl ? null : urlOrData, + delay: isUrl ? $.Autocompleter.defaults.delay : 10, + max: options && !options.scroll ? 10 : 150, + noRecord: "No Records." + }, options); + + // if highlight is set to false, replace it with a do-nothing function + options.highlight = options.highlight || function(value) { return value; }; + + // if the formatMatch option is not specified, then use formatItem for backwards compatibility + options.formatMatch = options.formatMatch || options.formatItem; + + return this.each(function() { + new $.Autocompleter(this, options); + }); + }, + result: function(handler) { + return this.bind("result", handler); + }, + search: function(handler) { + return this.trigger("search", [handler]); + }, + flushCache: function() { + return this.trigger("flushCache"); + }, + setOptions: function(options){ + return this.trigger("setOptions", [options]); + }, + unautocomplete: function() { + return this.trigger("unautocomplete"); + } +}); + +$.Autocompleter = function(input, options) { + + var KEY = { + UP: 38, + DOWN: 40, + DEL: 46, + TAB: 9, + RETURN: 13, + ESC: 27, + COMMA: 188, + PAGEUP: 33, + PAGEDOWN: 34, + BACKSPACE: 8 + }; + + var globalFailure = null; + if(options.failure != null && typeof options.failure == "function") { + globalFailure = options.failure; + } + + // Create $ object for input element + var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass); + + var timeout; + var previousValue = ""; + var cache = $.Autocompleter.Cache(options); + var hasFocus = 0; + var lastKeyPressCode; + var config = { + mouseDownOnSelect: false + }; + var select = $.Autocompleter.Select(options, input, selectCurrent, config); + + var blockSubmit; + + // prevent form submit in opera when selecting with return key + navigator.userAgent.indexOf("Opera") != -1 && $(input.form).bind("submit.autocomplete", function() { + if (blockSubmit) { + blockSubmit = false; + return false; + } + }); + + // older versions of opera don't trigger keydown multiple times while pressed, others don't work with keypress at all + $input.bind((navigator.userAgent.indexOf("Opera") != -1 && !'KeyboardEvent' in window ? "keypress" : "keydown") + ".autocomplete", function(event) { + // a keypress means the input has focus + // avoids issue where input had focus before the autocomplete was applied + hasFocus = 1; + // track last key pressed + lastKeyPressCode = event.keyCode; + switch(event.keyCode) { + + case KEY.UP: + if ( select.visible() ) { + event.preventDefault(); + select.prev(); + } else { + onChange(0, true); + } + break; + + case KEY.DOWN: + if ( select.visible() ) { + event.preventDefault(); + select.next(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEUP: + if ( select.visible() ) { + event.preventDefault(); + select.pageUp(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEDOWN: + if ( select.visible() ) { + event.preventDefault(); + select.pageDown(); + } else { + onChange(0, true); + } + break; + + // matches also semicolon + case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA: + case KEY.TAB: + case KEY.RETURN: + if( selectCurrent() ) { + // stop default to prevent a form submit, Opera needs special handling + event.preventDefault(); + blockSubmit = true; + return false; + } + break; + + case KEY.ESC: + select.hide(); + break; + + default: + clearTimeout(timeout); + timeout = setTimeout(onChange, options.delay); + break; + } + }).focus(function(){ + // track whether the field has focus, we shouldn't process any + // results if the field no longer has focus + hasFocus++; + }).blur(function() { + hasFocus = 0; + if (!config.mouseDownOnSelect) { + hideResults(); + } + }).click(function() { + // show select when clicking in a focused field + // but if clickFire is true, don't require field + // to be focused to begin with; just show select + if( options.clickFire ) { + if ( !select.visible() ) { + onChange(0, true); + } + } else { + if ( hasFocus++ > 1 && !select.visible() ) { + onChange(0, true); + } + } + }).bind("search", function() { + // TODO why not just specifying both arguments? + var fn = (arguments.length > 1) ? arguments[1] : null; + function findValueCallback(q, data) { + var result; + if( data && data.length ) { + for (var i=0; i < data.length; i++) { + if( data[i].result.toLowerCase() == q.toLowerCase() ) { + result = data[i]; + break; + } + } + } + if( typeof fn == "function" ) fn(result); + else $input.trigger("result", result && [result.data, result.value]); + } + $.each(trimWords($input.val()), function(i, value) { + request(value, findValueCallback, findValueCallback); + }); + }).bind("flushCache", function() { + cache.flush(); + }).bind("setOptions", function() { + $.extend(true, options, arguments[1]); + // if we've updated the data, repopulate + if ( "data" in arguments[1] ) + cache.populate(); + }).bind("unautocomplete", function() { + select.unbind(); + $input.unbind(); + $(input.form).unbind(".autocomplete"); + }); + + + function selectCurrent() { + var selected = select.selected(); + if( !selected ) + return false; + + var v = selected.result; + previousValue = v; + + if ( options.multiple ) { + var words = trimWords($input.val()); + if ( words.length > 1 ) { + var seperator = options.multipleSeparator.length; + var cursorAt = $(input).selection().start; + var wordAt, progress = 0; + $.each(words, function(i, word) { + progress += word.length; + if (cursorAt <= progress) { + wordAt = i; + return false; + } + progress += seperator; + }); + words[wordAt] = v; + // TODO this should set the cursor to the right position, but it gets overriden somewhere + //$.Autocompleter.Selection(input, progress + seperator, progress + seperator); + v = words.join( options.multipleSeparator ); + } + v += options.multipleSeparator; + } + + $input.val(v); + hideResultsNow(); + $input.trigger("result", [selected.data, selected.value]); + return true; + } + + function onChange(crap, skipPrevCheck) { + if( lastKeyPressCode == KEY.DEL ) { + select.hide(); + return; + } + + var currentValue = $input.val(); + + if ( !skipPrevCheck && currentValue == previousValue ) + return; + + previousValue = currentValue; + + currentValue = lastWord(currentValue); + if ( currentValue.length >= options.minChars) { + $input.addClass(options.loadingClass); + if (!options.matchCase) + currentValue = currentValue.toLowerCase(); + request(currentValue, receiveData, hideResultsNow); + } else { + stopLoading(); + select.hide(); + } + }; + + function trimWords(value) { + if (!value) + return [""]; + if (!options.multiple) + return [$.trim(value)]; + return $.map(value.split(options.multipleSeparator), function(word) { + return $.trim(value).length ? $.trim(word) : null; + }); + } + + function lastWord(value) { + if ( !options.multiple ) + return value; + var words = trimWords(value); + if (words.length == 1) + return words[0]; + var cursorAt = $(input).selection().start; + if (cursorAt == value.length) { + words = trimWords(value) + } else { + words = trimWords(value.replace(value.substring(cursorAt), "")); + } + return words[words.length - 1]; + } + + // fills in the input box w/the first match (assumed to be the best match) + // q: the term entered + // sValue: the first matching result + function autoFill(q, sValue){ + // autofill in the complete box w/the first match as long as the user hasn't entered in more data + // if the last user key pressed was backspace, don't autofill + if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) { + // fill in the value (keep the case the user has typed) + $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); + // select the portion of the value not typed by the user (so the next character will erase) + $(input).selection(previousValue.length, previousValue.length + sValue.length); + } + }; + + function hideResults() { + clearTimeout(timeout); + timeout = setTimeout(hideResultsNow, 200); + }; + + function hideResultsNow() { + var wasVisible = select.visible(); + select.hide(); + clearTimeout(timeout); + stopLoading(); + if (options.mustMatch) { + // call search and run callback + $input.search( + function (result){ + // if no value found, clear the input box + if( !result ) { + if (options.multiple) { + var words = trimWords($input.val()).slice(0, -1); + $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") ); + } + else { + $input.val( "" ); + $input.trigger("result", null); + } + } + } + ); + } + }; + + function receiveData(q, data) { + if ( data && data.length && hasFocus ) { + stopLoading(); + select.display(data, q); + autoFill(q, data[0].value); + select.show(); + } else { + hideResultsNow(); + } + }; + + function request(term, success, failure) { + if (!options.matchCase) + term = term.toLowerCase(); + var data = cache.load(term); + // recieve the cached data + if (data) { + if(data.length) { + success(term, data); + } + else{ + var parsed = options.parse && options.parse(options.noRecord) || parse(options.noRecord); + success(term,parsed); + } + // if an AJAX url has been supplied, try loading the data now + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + + var extraParams = { + timestamp: +new Date() + }; + $.each(options.extraParams, function(key, param) { + extraParams[key] = typeof param == "function" ? param() : param; + }); + + $.ajax({ + // try to leverage ajaxQueue plugin to abort previous requests + mode: "abort", + // limit abortion to this input + port: "autocomplete" + input.name, + dataType: options.dataType, + url: options.url, + data: $.extend({ + q: lastWord(term), + limit: options.max + }, extraParams), + success: function(data) { + var parsed = options.parse && options.parse(data) || parse(data); + cache.add(term, parsed); + success(term, parsed); + } + }); + } else { + // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match + select.emptyList(); + if(globalFailure != null) { + globalFailure(); + } + else { + failure(term); + } + } + }; + + function parse(data) { + var parsed = []; + var rows = data.split("\n"); + for (var i=0; i < rows.length; i++) { + var row = $.trim(rows[i]); + if (row) { + row = row.split("|"); + parsed[parsed.length] = { + data: row, + value: row[0], + result: options.formatResult && options.formatResult(row, row[0]) || row[0] + }; + } + } + return parsed; + }; + + function stopLoading() { + $input.removeClass(options.loadingClass); + }; + +}; + +$.Autocompleter.defaults = { + inputClass: "ac_input", + resultsClass: "ac_results", + loadingClass: "ac_loading", + minChars: 1, + delay: 400, + matchCase: false, + matchSubset: true, + matchContains: false, + cacheLength: 100, + max: 1000, + mustMatch: false, + extraParams: {}, + selectFirst: true, + formatItem: function(row) { return row[0]; }, + formatMatch: null, + autoFill: false, + width: 0, + multiple: false, + multipleSeparator: " ", + inputFocus: true, + clickFire: false, + highlight: function(value, term) { + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); + }, + scroll: true, + scrollHeight: 180, + scrollJumpPosition: true +}; + +$.Autocompleter.Cache = function(options) { + + var data = {}; + var length = 0; + + function matchSubset(s, sub) { + if (!options.matchCase) + s = s.toLowerCase(); + var i = s.indexOf(sub); + if (options.matchContains == "word"){ + i = s.toLowerCase().search("\\b" + sub.toLowerCase()); + } + if (i == -1) return false; + return i == 0 || options.matchContains; + }; + + function add(q, value) { + if (length > options.cacheLength){ + flush(); + } + if (!data[q]){ + length++; + } + data[q] = value; + } + + function populate(){ + if( !options.data ) return false; + // track the matches + var stMatchSets = {}, + nullData = 0; + + // no url was specified, we need to adjust the cache length to make sure it fits the local data store + if( !options.url ) options.cacheLength = 1; + + // track all options for minChars = 0 + stMatchSets[""] = []; + + // loop through the array and create a lookup structure + for ( var i = 0, ol = options.data.length; i < ol; i++ ) { + var rawValue = options.data[i]; + // if rawValue is a string, make an array otherwise just reference the array + rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue; + + var value = options.formatMatch(rawValue, i+1, options.data.length); + if ( typeof(value) === 'undefined' || value === false ) + continue; + + var firstChar = value.charAt(0).toLowerCase(); + // if no lookup array for this character exists, look it up now + if( !stMatchSets[firstChar] ) + stMatchSets[firstChar] = []; + + // if the match is a string + var row = { + value: value, + data: rawValue, + result: options.formatResult && options.formatResult(rawValue) || value + }; + + // push the current match into the set list + stMatchSets[firstChar].push(row); + + // keep track of minChars zero items + if ( nullData++ < options.max ) { + stMatchSets[""].push(row); + } + }; + + // add the data items to the cache + $.each(stMatchSets, function(i, value) { + // increase the cache size + options.cacheLength++; + // add to the cache + add(i, value); + }); + } + + // populate any existing data + setTimeout(populate, 25); + + function flush(){ + data = {}; + length = 0; + } + + return { + flush: flush, + add: add, + populate: populate, + load: function(q) { + if (!options.cacheLength || !length) + return null; + /* + * if dealing w/local data and matchContains than we must make sure + * to loop through all the data collections looking for matches + */ + if( !options.url && options.matchContains ){ + // track all matches + var csub = []; + // loop through all the data grids for matches + for( var k in data ){ + // don't search through the stMatchSets[""] (minChars: 0) cache + // this prevents duplicates + if( k.length > 0 ){ + var c = data[k]; + $.each(c, function(i, x) { + // if we've got a match, add it to the array + if (matchSubset(x.value, q)) { + csub.push(x); + } + }); + } + } + return csub; + } else + // if the exact item exists, use it + if (data[q]){ + return data[q]; + } else + if (options.matchSubset) { + for (var i = q.length - 1; i >= options.minChars; i--) { + var c = data[q.substr(0, i)]; + if (c) { + var csub = []; + $.each(c, function(i, x) { + if (matchSubset(x.value, q)) { + csub[csub.length] = x; + } + }); + return csub; + } + } + } + return null; + } + }; +}; + +$.Autocompleter.Select = function (options, input, select, config) { + var CLASSES = { + ACTIVE: "ac_over" + }; + + var listItems, + active = -1, + data, + term = "", + needsInit = true, + element, + list; + + // Create results + function init() { + if (!needsInit) + return; + element = $("
                      ") + .hide() + .addClass(options.resultsClass) + .css("position", "absolute") + .appendTo(document.body) + .hover(function(event) { + // Browsers except FF do not fire mouseup event on scrollbars, resulting in mouseDownOnSelect remaining true, and results list not always hiding. + if($(this).is(":visible")) { + input.focus(); + } + config.mouseDownOnSelect = false; + }); + + list = $("
                        ").appendTo(element).mouseover( function(event) { + if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') { + active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event)); + $(target(event)).addClass(CLASSES.ACTIVE); + } + }).click(function(event) { + $(target(event)).addClass(CLASSES.ACTIVE); + select(); + if( options.inputFocus ) + input.focus(); + return false; + }).mousedown(function() { + config.mouseDownOnSelect = true; + }).mouseup(function() { + config.mouseDownOnSelect = false; + }); + + if( options.width > 0 ) + element.css("width", options.width); + + needsInit = false; + } + + function target(event) { + var element = event.target; + while(element && element.tagName != "LI") + element = element.parentNode; + // more fun with IE, sometimes event.target is empty, just ignore it then + if(!element) + return []; + return element; + } + + function moveSelect(step) { + listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE); + movePosition(step); + var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE); + if(options.scroll) { + var offset = 0; + listItems.slice(0, active).each(function() { + offset += this.offsetHeight; + }); + if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) { + list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight()); + } else if(offset < list.scrollTop()) { + list.scrollTop(offset); + } + } + }; + + function movePosition(step) { + if (options.scrollJumpPosition || (!options.scrollJumpPosition && !((step < 0 && active == 0) || (step > 0 && active == listItems.size() - 1)) )) { + active += step; + if (active < 0) { + active = listItems.size() - 1; + } else if (active >= listItems.size()) { + active = 0; + } + } + } + + + function limitNumberOfItems(available) { + return options.max && options.max < available + ? options.max + : available; + } + + function fillList() { + list.empty(); + var max = limitNumberOfItems(data.length); + for (var i=0; i < max; i++) { + if (!data[i]) + continue; + var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term); + if ( formatted === false ) + continue; + var li = $("
                      • ").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0]; + $.data(li, "ac_data", data[i]); + } + listItems = list.find("li"); + if ( options.selectFirst ) { + listItems.slice(0, 1).addClass(CLASSES.ACTIVE); + active = 0; + } + // apply bgiframe if available + if ( $.fn.bgiframe ) + list.bgiframe(); + } + + return { + display: function(d, q) { + init(); + data = d; + term = q; + fillList(); + }, + next: function() { + moveSelect(1); + }, + prev: function() { + moveSelect(-1); + }, + pageUp: function() { + if (active != 0 && active - 8 < 0) { + moveSelect( -active ); + } else { + moveSelect(-8); + } + }, + pageDown: function() { + if (active != listItems.size() - 1 && active + 8 > listItems.size()) { + moveSelect( listItems.size() - 1 - active ); + } else { + moveSelect(8); + } + }, + hide: function() { + element && element.hide(); + listItems && listItems.removeClass(CLASSES.ACTIVE); + active = -1; + }, + visible : function() { + return element && element.is(":visible"); + }, + current: function() { + return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]); + }, + show: function() { + var offset = $(input).offset(); + element.css({ + width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(), + top: offset.top + input.offsetHeight, + left: offset.left + }).show(); + if(options.scroll) { + list.scrollTop(0); + list.css({ + maxHeight: options.scrollHeight, + overflow: 'auto' + }); + + if(navigator.userAgent.indexOf("MSIE") != -1 && typeof document.body.style.maxHeight === "undefined") { + var listHeight = 0; + listItems.each(function() { + listHeight += this.offsetHeight; + }); + var scrollbarsVisible = listHeight > options.scrollHeight; + list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight ); + if (!scrollbarsVisible) { + // IE doesn't recalculate width when scrollbar disappears + listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) ); + } + } + + } + }, + selected: function() { + var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE); + return selected && selected.length && $.data(selected[0], "ac_data"); + }, + emptyList: function (){ + list && list.empty(); + }, + unbind: function() { + element && element.remove(); + } + }; +}; + +$.fn.selection = function(start, end) { + if (start !== undefined) { + return this.each(function() { + if( this.createTextRange ){ + var selRange = this.createTextRange(); + if (end === undefined || start == end) { + selRange.move("character", start); + selRange.select(); + } else { + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } + } else if( this.setSelectionRange ){ + this.setSelectionRange(start, end); + } else if( this.selectionStart ){ + this.selectionStart = start; + this.selectionEnd = end; + } + }); + } + var field = this[0]; + if ( field.createTextRange ) { + var range = document.selection.createRange(), + orig = field.value, + teststring = "<->", + textLength = range.text.length; + range.text = teststring; + var caretAt = field.value.indexOf(teststring); + field.value = orig; + this.selection(caretAt, caretAt + textLength); + return { + start: caretAt, + end: caretAt + textLength + } + } else if( field.selectionStart !== undefined ){ + return { + start: field.selectionStart, + end: field.selectionEnd + } + } +}; + +})(jQuery); diff --git a/lib/scripts/jquery.collapsible.min.js b/lib/scripts/jquery.collapsible.min.js new file mode 100644 index 0000000..d15cda5 --- /dev/null +++ b/lib/scripts/jquery.collapsible.min.js @@ -0,0 +1,496 @@ +/** + * Collapsible, jQuery Plugin + * + * Collapsible management. Optional cookie support using the jQuery Cookie plugin: + * https://github.com/carhartl/jquery-cookie + * + * Copyright (c) 2010 John Snyder (snyderplace.com) + * @license http://www.snyderplace.com/collapsible/license.txt New BSD + * @version 1.2.1 + */ +(function($) { + $.fn.collapsible = function(cmd, arg) { + + //firewalling + if (!this || this.length < 1) { + return this; + } + + //address command requests + if (typeof cmd == 'string') { + return $.fn.collapsible.dispatcher[cmd](this, arg); + } + + //return the command dispatcher + return $.fn.collapsible.dispatcher['_create'](this, cmd); + }; + + //create the command dispatcher + $.fn.collapsible.dispatcher = { + + //initialized with options + _create: function(obj, arg) { + createCollapsible(obj, arg); + }, + + //toggle the element's display + toggle: function(obj) { + toggle(obj, loadOpts(obj)); + return obj; + }, + + //show the element + open: function(obj) { + open(obj, loadOpts(obj)); + return obj; + }, + + //hide the element + close: function(obj) { + close(obj, loadOpts(obj)); + return obj; + }, + + //check if the element is closed + collapsed: function(obj) { + return collapsed(obj, loadOpts(obj)); + }, + + //open all closed containers + openAll: function(obj) { + return openAll(obj, loadOpts(obj)); + }, + + //close all opened containers + closeAll: function(obj) { + return closeAll(obj, loadOpts(obj)); + }, + + callBack: function() { + console.log('132'); + return true; + } + }; + + //create the initial collapsible + function createCollapsible(obj, options) { + + //build main options before element iteration + var opts = $.extend({}, $.fn.collapsible.defaults, options); + + //store any opened default values to set cookie later + var opened = []; + + //iterate each matched object, bind, and open/close + obj.each(function() { + + var $this = $(this); + saveOpts($this, opts); + + //bind it to the event + if (opts.bind == 'mouseenter') { + $this.on('mouseenter', function(event) { + event.preventDefault(); + toggle($this, opts); + }); + } + + //bind it to the event + if (opts.bind == 'mouseover') { + $this.on('mouseover', function(event) { + event.preventDefault(); + toggle($this, opts); + }); + } + + //bind it to the event + if (opts.bind == 'click') { + $this.on('click', function(event) { + event.preventDefault(); + toggle($this, opts); + }); + + } + + //bind it to the event + if (opts.bind == 'dblclick') { + $this.on('dblclick', function(event) { + event.preventDefault(); + toggle($this, opts); + }); + + } + + //initialize the collapsibles + //get the id for this element + var id = $this.attr('id'); + + //if not using cookies, open defaults + if (!useCookies(opts)) { + + //is this collapsible in the default open array? + var dOpenIndex = inDefaultOpen(id, opts); + + //close it if not defaulted to open + if (dOpenIndex === false) { + + $this.addClass(opts.cssClose); + opts.loadClose($this, opts); + + } else { //its a default open, open it + + $this.addClass(opts.cssOpen); + opts.loadOpen($this, opts); + opened.push(id); + } + + } else { //can use cookies, use them now + + //has a cookie been set, this overrides default open + if (issetCookie(opts)) { + + var cookieIndex = inCookie(id, opts); + + if (cookieIndex === false) { + + $this.addClass(opts.cssClose); + opts.loadClose($this, opts); + + } else { + + $this.addClass(opts.cssOpen); + opts.loadOpen($this, opts); + opened.push(id); + } + + } else { //a cookie hasn't been set open defaults, add them to opened array + + dOpenIndex = inDefaultOpen(id, opts); + + if (dOpenIndex === false) { + + $this.addClass(opts.cssClose); + opts.loadClose($this, opts); + + } else { + + $this.addClass(opts.cssOpen); + opts.loadOpen($this, opts); + opened.push(id); + } + } + } + }); + + //now that the loop is done, set the cookie + if (opened.length > 0 && useCookies(opts)) { + + setCookie(opened.toString(), opts); + + } else { //there are none open, set cookie + + setCookie('', opts); + } + + return obj; + } + + //load opts from object + function loadOpts($this) { + return $this.data('collapsible-opts'); + } + + //save opts into object + function saveOpts($this, opts) { + return $this.data('collapsible-opts', opts); + } + + //returns true if object is opened + function collapsed($this, opts) { + return $this.hasClass(opts.cssClose); + } + + //hides a collapsible + function close($this, opts) { + + //give the proper class to the linked element + $this.addClass(opts.cssClose).removeClass(opts.cssOpen); + + //close the element + opts.animateClose($this, opts); + + //do cookies if plugin available + if (useCookies(opts)) { + // split the cookieOpen string by "," + var id = $this.attr('id'); + unsetCookieId(id, opts); + } + } + + //opens a collapsible + function open($this, opts) { + + //give the proper class to the linked element + $this.removeClass(opts.cssClose).addClass(opts.cssOpen); + + //open the element + opts.animateOpen($this, opts); + + //do cookies if plugin available + if (useCookies(opts)) { + + // split the cookieOpen string by "," + var id = $this.attr('id'); + appendCookie(id, opts); + } + } + + //toggle a collapsible on an event + function toggle($this, opts) { + + if (collapsed($this, opts)) { + //open a closed element + open($this, opts); + setTimeout(function() { + AveAdmin.sticky_panel_refresh(); + }, 20); + } else { + //close an open element + close($this, opts); + setTimeout(function() { + AveAdmin.sticky_panel_refresh(); + }, 20); + } + + return false; + } + + //open all closed containers + function openAll($this, opts) { + + // loop through all container elements + $.each($this, function(elem, value) { + + if (collapsed($(value), opts)) { + + //open a closed element + open($(value), opts); + } + }); + } + + //close all open containers + function closeAll($this, opts) { + + $.each($this, function(elem, value) { + + if (!collapsed($(value), opts)) { + + //close an opened element + close($(value), opts); + } + }); + } + + //close all open containers + function callBack($this, opts) { + alert(); + } + + //use cookies? + function useCookies(opts) { + + //return false if cookie plugin not present or if a cookie name is not provided + if (!$.cookie || opts.cookieName == '') { + return false; + } + + //we can use cookies + return true; + } + + //append a collapsible to the cookie + function appendCookie(value, opts) { + + //check if cookie plugin available and cookiename is set + if (!useCookies(opts)) { + return false; + } + + //does a cookie already exist + if (!issetCookie(opts)) { + + //no lets set one + setCookie(value, opts); + return true; + } + + //cookie already exists, is this collapsible already set? + if (inCookie(value, opts)) { //yes, quit here + return true; + } + + //get the cookie + var cookie = decodeURIComponent($.cookie(opts.cookieName)); + + //turn it into an array + var cookieArray = cookie.split(','); + + //add it to list + cookieArray.push(value); + + //save it + setCookie(cookieArray.toString(), opts); + + return true; + } + + //unset a collapsible from the cookie + function unsetCookieId(value, opts) { + //check if cookie plugin available and cookiename is set + if (!useCookies(opts)) { + return false; + } + + //if its not there we don't need to remove from it + if (!issetCookie(opts)) { //quit here, don't have a cookie + return true; + } + + //we have a cookie, is this collapsible in it + var cookieIndex = inCookie(value, opts); + if (cookieIndex === false) { //not in the cookie quit here + return true; + } + + //still here get the cookie + var cookie = decodeURIComponent($.cookie(opts.cookieName)); + + //turn it into an array + var cookieArray = cookie.split(','); + + //lets pop it out of the array + cookieArray.splice(cookieIndex, 1); + + //overwrite + setCookie(cookieArray.toString(), opts); + + return true + } + + //set a cookie + function setCookie(value, opts) { + //can use the cookie plugin + if (!useCookies(opts)) { //no, quit here + return false; + } + + //cookie plugin is available, lets set the cookie + $.cookie(opts.cookieName, value, opts.cookieOptions); + + return true; + } + + //check if a collapsible is in the cookie + function inCookie(value, opts) { + //can use the cookie plugin + if (!useCookies(opts)) { + return false; + } + + //if its not there we don't need to remove from it + if (!issetCookie(opts)) { //quit here, don't have a cookie + return false; + } + + //get the cookie value + var cookie = decodeURIComponent($.cookie(opts.cookieName)); + + //turn it into an array + var cookieArray = cookie.split(','); + + //get the index of the collapsible if in the cookie array + var cookieIndex = $.inArray(value, cookieArray); + + //is this value in the cookie array + if (cookieIndex == -1) { //no, quit here + return false; + } + + return cookieIndex; + } + + //check if a cookie is set + function issetCookie(opts) { + //can we use the cookie plugin + if (!useCookies(opts)) { //no, quit here + return false; + } + + //is the cookie set + if ($.cookie(opts.cookieName) === null) { //no, quit here + return false; + } + + return true; + } + + //check if a collapsible is in the list of collapsibles to be opened by default + function inDefaultOpen(id, opts) { + //get the array of open collapsibles + var defaultOpen = getDefaultOpen(opts); + + //is it in the default open array + var index = $.inArray(id, defaultOpen); + if (index == -1) { //nope, quit here + return false; + } + + return index; + } + + //get the default open collapsibles and return array + function getDefaultOpen(opts) { + //initialize an empty array + var defaultOpen = []; + + //if there is a list, lets split it into an array + if (opts.defaultOpen != '') { + defaultOpen = opts.defaultOpen.split(','); + } + + return defaultOpen; + } + + // settings + $.fn.collapsible.defaults = { + cssClose: 'collapse-close', //class you want to assign to a closed collapsible header + cssOpen: 'collapse-open', //class you want to assign an opened collapsible header + cookieName: 'collapsible', //name of the cookie you want to set for this collapsible + cookieOptions: { //cookie options, see cookie plugin for details + path: '/', + expires: 7, + domain: '', + secure: '' + }, + defaultOpen: '', //comma separated list of header ids that you want opened by default + speed: 'slow', //speed of the slide effect + bind: 'click', //event to bind to, supports click, dblclick, mouseover and mouseenter + animateOpen: function(elem, opts) { //replace the standard slideUp with custom function + elem.next().stop(true, true).slideDown(opts.speed); + }, + animateClose: function(elem, opts) { //replace the standard slideDown with custom function + elem.next().stop(true, true).slideUp(opts.speed); + }, + loadOpen: function(elem, opts) { //replace the default open state with custom function + elem.next().show(); + }, + loadClose: function(elem, opts) { //replace the default close state with custom function + elem.next().hide(); + }, + callBack: function(opts) { + console.log('132'); + } + }; + +})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.cookie.js b/lib/scripts/jquery.cookie.js new file mode 100644 index 0000000..cb09af9 --- /dev/null +++ b/lib/scripts/jquery.cookie.js @@ -0,0 +1,10 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options=$.extend({},options);options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i= (iPages - iPageCountHalf)) + { + iStartButton = iPages - iPageCount + 1; + iEndButton = iPages; + } + else + { + iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1; + iEndButton = iStartButton + iPageCount - 1; + } + } + } + + /* Build the dynamic list */ + for ( i=iStartButton ; i<=iEndButton ; i++ ) + { + if ( iCurrentPage != i ) + { + sList += ''+i+''; + } + else + { + sList += ''+i+''; + } + } + + /* Loop over each instance of the pager */ + var an = oSettings.aanFeatures.p; + var anButtons, anStatic, nPaginateList; + var fnClick = function(e) { + /* Use the information in the element to jump to the required page */ + var iTarget = (this.innerHTML * 1) - 1; + oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength; + fnCallbackDraw( oSettings ); + e.preventDefault(); + }; + var fnFalse = function () { return false; }; + + for ( i=0, iLen=an.length ; i y) ? 1 : 0)); + }, + + "string-desc": function ( a, b ) + { + if ( typeof a != 'string' ) { a = ''; } + if ( typeof b != 'string' ) { b = ''; } + var x = a.toLowerCase(); + var y = b.toLowerCase(); + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * html sorting (ignore html tags) + */ + "html-asc": function ( a, b ) + { + var x = a.replace( /<.*?>/g, "" ).toLowerCase(); + var y = b.replace( /<.*?>/g, "" ).toLowerCase(); + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + }, + + "html-desc": function ( a, b ) + { + var x = a.replace( /<.*?>/g, "" ).toLowerCase(); + var y = b.replace( /<.*?>/g, "" ).toLowerCase(); + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * date sorting + */ + "date-asc": function ( a, b ) + { + var x = Date.parse( a ); + var y = Date.parse( b ); + + if ( isNaN(x) || x==="" ) + { + x = Date.parse( "01/01/1970 00:00:00" ); + } + if ( isNaN(y) || y==="" ) + { + y = Date.parse( "01/01/1970 00:00:00" ); + } + + return x - y; + }, + + "date-desc": function ( a, b ) + { + var x = Date.parse( a ); + var y = Date.parse( b ); + + if ( isNaN(x) || x==="" ) + { + x = Date.parse( "01/01/1970 00:00:00" ); + } + if ( isNaN(y) || y==="" ) + { + y = Date.parse( "01/01/1970 00:00:00" ); + } + + return y - x; + }, + + + /* + * numerical sorting + */ + "numeric-asc": function ( a, b ) + { + var x = (a=="-" || a==="") ? 0 : a*1; + var y = (b=="-" || b==="") ? 0 : b*1; + return x - y; + }, + + "numeric-desc": function ( a, b ) + { + var x = (a=="-" || a==="") ? 0 : a*1; + var y = (b=="-" || b==="") ? 0 : b*1; + return y - x; + } + }; + + + /* + * Variable: aTypes + * Purpose: Container for the various type of type detection that dataTables supports + * Scope: jQuery.fn.dataTableExt + * Notes: The functions in this array are expected to parse a string to see if it is a data + * type that it recognises. If so then the function should return the name of the type (a + * corresponding sort function should be defined!), if the type is not recognised then the + * function should return null such that the parser and move on to check the next type. + * Note that ordering is important in this array - the functions are processed linearly, + * starting at index 0. + * Note that the input for these functions is always a string! It cannot be any other data + * type + */ + _oExt.aTypes = [ + /* + * Function: - + * Purpose: Check to see if a string is numeric + * Returns: string:'numeric' or null + * Inputs: mixed:sText - string to check + */ + function ( sData ) + { + /* Allow zero length strings as a number */ + if ( typeof sData == 'number' ) + { + return 'numeric'; + } + else if ( typeof sData != 'string' ) + { + return null; + } + + var sValidFirstChars = "0123456789-"; + var sValidChars = "0123456789."; + var Char; + var bDecimal = false; + + /* Check for a valid first char (no period and allow negatives) */ + Char = sData.charAt(0); + if (sValidFirstChars.indexOf(Char) == -1) + { + return null; + } + + /* Check all the other characters are valid */ + for ( var i=1 ; i') != -1 ) + { + return 'html'; + } + return null; + } + ]; + + /* + * Function: fnVersionCheck + * Purpose: Check a version string against this version of DataTables. Useful for plug-ins + * Returns: bool:true -this version of DataTables is greater or equal to the required version + * false -this version of DataTales is not suitable + * Inputs: string:sVersion - the version to check against. May be in the following formats: + * "a", "a.b" or "a.b.c" + * Notes: This function will only check the first three parts of a version string. It is + * assumed that beta and dev versions will meet the requirements. This might change in future + */ + _oExt.fnVersionCheck = function( sVersion ) + { + /* This is cheap, but very effective */ + var fnZPad = function (Zpad, count) + { + while(Zpad.length < count) { + Zpad += '0'; + } + return Zpad; + }; + var aThis = _oExt.sVersion.split('.'); + var aThat = sVersion.split('.'); + var sThis = '', sThat = ''; + + for ( var i=0, iLen=aThat.length ; i= parseInt(sThat, 10); + }; + + /* + * Variable: _oExternConfig + * Purpose: Store information for DataTables to access globally about other instances + * Scope: jQuery.fn.dataTableExt + */ + _oExt._oExternConfig = { + /* int:iNextUnique - next unique number for an instance */ + "iNextUnique": 0 + }; + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Section - DataTables prototype + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /* + * Function: dataTable + * Purpose: DataTables information + * Returns: - + * Inputs: object:oInit - initialisation options for the table + */ + $.fn.dataTable = function( oInit ) + { + /* + * Function: classSettings + * Purpose: Settings container function for all 'class' properties which are required + * by dataTables + * Returns: - + * Inputs: - + */ + function classSettings () + { + this.fnRecordsTotal = function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsTotal, 10); + } else { + return this.aiDisplayMaster.length; + } + }; + + this.fnRecordsDisplay = function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsDisplay, 10); + } else { + return this.aiDisplay.length; + } + }; + + this.fnDisplayEnd = function () + { + if ( this.oFeatures.bServerSide ) { + if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) { + return this._iDisplayStart+this.aiDisplay.length; + } else { + return Math.min( this._iDisplayStart+this._iDisplayLength, + this._iRecordsDisplay ); + } + } else { + return this._iDisplayEnd; + } + }; + + /* + * Variable: oInstance + * Purpose: The DataTables object for this table + * Scope: jQuery.dataTable.classSettings + */ + this.oInstance = null; + + /* + * Variable: sInstance + * Purpose: Unique idendifier for each instance of the DataTables object + * Scope: jQuery.dataTable.classSettings + */ + this.sInstance = null; + + /* + * Variable: oFeatures + * Purpose: Indicate the enablement of key dataTable features + * Scope: jQuery.dataTable.classSettings + */ + this.oFeatures = { + "bPaginate": true, + "bLengthChange": true, + "bFilter": true, + "bSort": true, + "bInfo": true, + "bAutoWidth": true, + "bProcessing": false, + "bSortClasses": true, + "bStateSave": false, + "bServerSide": false, + "bDeferRender": false + }; + + /* + * Variable: oScroll + * Purpose: Container for scrolling options + * Scope: jQuery.dataTable.classSettings + */ + this.oScroll = { + "sX": "", + "sXInner": "", + "sY": "", + "bCollapse": false, + "bInfinite": false, + "iLoadGap": 100, + "iBarWidth": 0, + "bAutoCss": true + }; + + /* + * Variable: aanFeatures + * Purpose: Array referencing the nodes which are used for the features + * Scope: jQuery.dataTable.classSettings + * Notes: The parameters of this object match what is allowed by sDom - i.e. + * 'l' - Length changing + * 'f' - Filtering input + * 't' - The table! + * 'i' - Information + * 'p' - Pagination + * 'r' - pRocessing + */ + this.aanFeatures = []; + + /* + * Variable: oLanguage + * Purpose: Store the language strings used by dataTables + * Scope: jQuery.dataTable.classSettings + * Notes: The words in the format _VAR_ are variables which are dynamically replaced + * by javascript + */ + this.oLanguage = { + "sProcessing": "В процессе...", + "sLengthMenu": "Количество на странице: _MENU_", + "sZeroRecords": "Соответствующих записей не найдено", + "sEmptyTable": "Нет данных в таблице", + "sLoadingRecords": "Загрузка...", + "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", + "sInfoEmpty": "Showing 0 to 0 of 0 entries", + "sInfoFiltered": "(_MAX_ всего)", + "sInfoPostFix": "", + "sInfoThousands": ",", + "sSearch": "Поиск:", + "sUrl": "", + "oPaginate": { + "sFirst": "Первая", + "sPrevious": "Предыдущая", + "sNext": "Следущая", + "sLast": "Последняя" + }, + "fnInfoCallback": null + }; + + /* + * Variable: aoData + * Purpose: Store data information + * Scope: jQuery.dataTable.classSettings + * Notes: This is an array of objects with the following parameters: + * int: _iId - internal id for tracking + * array: _aData - internal data - used for sorting / filtering etc + * node: nTr - display node + * array node: _anHidden - hidden TD nodes + * string: _sRowStripe + */ + this.aoData = []; + + /* + * Variable: aiDisplay + * Purpose: Array of indexes which are in the current display (after filtering etc) + * Scope: jQuery.dataTable.classSettings + */ + this.aiDisplay = []; + + /* + * Variable: aiDisplayMaster + * Purpose: Array of indexes for display - no filtering + * Scope: jQuery.dataTable.classSettings + */ + this.aiDisplayMaster = []; + + /* + * Variable: aoColumns + * Purpose: Store information about each column that is in use + * Scope: jQuery.dataTable.classSettings + */ + this.aoColumns = []; + + /* + * Variable: aoHeader + * Purpose: Store information about the table's header + * Scope: jQuery.dataTable.classSettings + */ + this.aoHeader = []; + + /* + * Variable: aoFooter + * Purpose: Store information about the table's footer + * Scope: jQuery.dataTable.classSettings + */ + this.aoFooter = []; + + /* + * Variable: iNextId + * Purpose: Store the next unique id to be used for a new row + * Scope: jQuery.dataTable.classSettings + */ + this.iNextId = 0; + + /* + * Variable: asDataSearch + * Purpose: Search data array for regular expression searching + * Scope: jQuery.dataTable.classSettings + */ + this.asDataSearch = []; + + /* + * Variable: oPreviousSearch + * Purpose: Store the previous search incase we want to force a re-search + * or compare the old search to a new one + * Scope: jQuery.dataTable.classSettings + */ + this.oPreviousSearch = { + "sSearch": "", + "bRegex": false, + "bSmart": true + }; + + /* + * Variable: aoPreSearchCols + * Purpose: Store the previous search for each column + * Scope: jQuery.dataTable.classSettings + */ + this.aoPreSearchCols = []; + + /* + * Variable: aaSorting + * Purpose: Sorting information + * Scope: jQuery.dataTable.classSettings + * Notes: Index 0 - column number + * Index 1 - current sorting direction + * Index 2 - index of asSorting for this column + */ + this.aaSorting = [ [0, 'asc', 0] ]; + + /* + * Variable: aaSortingFixed + * Purpose: Sorting information that is always applied + * Scope: jQuery.dataTable.classSettings + */ + this.aaSortingFixed = null; + + /* + * Variable: asStripeClasses + * Purpose: Classes to use for the striping of a table + * Scope: jQuery.dataTable.classSettings + */ + this.asStripeClasses = []; + + /* + * Variable: asDestroyStripes + * Purpose: If restoring a table - we should restore its striping classes as well + * Scope: jQuery.dataTable.classSettings + */ + this.asDestroyStripes = []; + + /* + * Variable: sDestroyWidth + * Purpose: If restoring a table - we should restore its width + * Scope: jQuery.dataTable.classSettings + */ + this.sDestroyWidth = 0; + + /* + * Variable: fnRowCallback + * Purpose: Call this function every time a row is inserted (draw) + * Scope: jQuery.dataTable.classSettings + */ + this.fnRowCallback = null; + + /* + * Variable: fnHeaderCallback + * Purpose: Callback function for the header on each draw + * Scope: jQuery.dataTable.classSettings + */ + this.fnHeaderCallback = null; + + /* + * Variable: fnFooterCallback + * Purpose: Callback function for the footer on each draw + * Scope: jQuery.dataTable.classSettings + */ + this.fnFooterCallback = null; + + /* + * Variable: aoDrawCallback + * Purpose: Array of callback functions for draw callback functions + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call + * string:sName - name callback (feature). useful for arranging array + */ + this.aoDrawCallback = []; + + /* + * Variable: fnPreDrawCallback + * Purpose: Callback function for just before the table is redrawn. A return of false + * will be used to cancel the draw. + * Scope: jQuery.dataTable.classSettings + */ + this.fnPreDrawCallback = null; + + /* + * Variable: fnInitComplete + * Purpose: Callback function for when the table has been initialised + * Scope: jQuery.dataTable.classSettings + */ + this.fnInitComplete = null; + + /* + * Variable: sTableId + * Purpose: Cache the table ID for quick access + * Scope: jQuery.dataTable.classSettings + */ + this.sTableId = ""; + + /* + * Variable: nTable + * Purpose: Cache the table node for quick access + * Scope: jQuery.dataTable.classSettings + */ + this.nTable = null; + + /* + * Variable: nTHead + * Purpose: Permanent ref to the thead element + * Scope: jQuery.dataTable.classSettings + */ + this.nTHead = null; + + /* + * Variable: nTFoot + * Purpose: Permanent ref to the tfoot element - if it exists + * Scope: jQuery.dataTable.classSettings + */ + this.nTFoot = null; + + /* + * Variable: nTBody + * Purpose: Permanent ref to the tbody element + * Scope: jQuery.dataTable.classSettings + */ + this.nTBody = null; + + /* + * Variable: nTableWrapper + * Purpose: Cache the wrapper node (contains all DataTables controlled elements) + * Scope: jQuery.dataTable.classSettings + */ + this.nTableWrapper = null; + + /* + * Variable: bDeferLoading + * Purpose: Indicate if when using server-side processing the loading of data + * should be deferred until the second draw + * Scope: jQuery.dataTable.classSettings + */ + this.bDeferLoading = false; + + /* + * Variable: bInitialised + * Purpose: Indicate if all required information has been read in + * Scope: jQuery.dataTable.classSettings + */ + this.bInitialised = false; + + /* + * Variable: aoOpenRows + * Purpose: Information about open rows + * Scope: jQuery.dataTable.classSettings + * Notes: Has the parameters 'nTr' and 'nParent' + */ + this.aoOpenRows = []; + + /* + * Variable: sDom + * Purpose: Dictate the positioning that the created elements will take + * Scope: jQuery.dataTable.classSettings + * Notes: + * The following options are allowed: + * 'l' - Length changing + * 'f' - Filtering input + * 't' - The table! + * 'i' - Information + * 'p' - Pagination + * 'r' - pRocessing + * The following constants are allowed: + * 'H' - jQueryUI theme "header" classes + * 'F' - jQueryUI theme "footer" classes + * The following syntax is expected: + * '<' and '>' - div elements + * '<"class" and '>' - div with a class + * Examples: + * '<"wrapper"flipt>', 'ip>' + */ + this.sDom = 'lfrtip'; + + /* + * Variable: sPaginationType + * Purpose: Note which type of sorting should be used + * Scope: jQuery.dataTable.classSettings + */ + this.sPaginationType = "two_button"; + + /* + * Variable: iCookieDuration + * Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours + * Scope: jQuery.dataTable.classSettings + */ + this.iCookieDuration = 60 * 60 * 2; + + /* + * Variable: sCookiePrefix + * Purpose: The cookie name prefix + * Scope: jQuery.dataTable.classSettings + */ + this.sCookiePrefix = "SpryMedia_DataTables_"; + + /* + * Variable: fnCookieCallback + * Purpose: Callback function for cookie creation + * Scope: jQuery.dataTable.classSettings + */ + this.fnCookieCallback = null; + + /* + * Variable: aoStateSave + * Purpose: Array of callback functions for state saving + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call. Takes two parameters, oSettings and the JSON string to + * save that has been thus far created. Returns a JSON string to be inserted into a + * json object (i.e. '"param": [ 0, 1, 2]') + * string:sName - name of callback + */ + this.aoStateSave = []; + + /* + * Variable: aoStateLoad + * Purpose: Array of callback functions for state loading + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call. Takes two parameters, oSettings and the object stored. + * May return false to cancel state loading. + * string:sName - name of callback + */ + this.aoStateLoad = []; + + /* + * Variable: oLoadedState + * Purpose: State that was loaded from the cookie. Useful for back reference + * Scope: jQuery.dataTable.classSettings + */ + this.oLoadedState = null; + + /* + * Variable: sAjaxSource + * Purpose: Source url for AJAX data for the table + * Scope: jQuery.dataTable.classSettings + */ + this.sAjaxSource = null; + + /* + * Variable: sAjaxDataProp + * Purpose: Property from a given object from which to read the table data from. This can + * be an empty string (when not server-side processing), in which case it is + * assumed an an array is given directly. + * Scope: jQuery.dataTable.classSettings + */ + this.sAjaxDataProp = 'aaData'; + + /* + * Variable: bAjaxDataGet + * Purpose: Note if draw should be blocked while getting data + * Scope: jQuery.dataTable.classSettings + */ + this.bAjaxDataGet = true; + + /* + * Variable: jqXHR + * Purpose: The last jQuery XHR object that was used for server-side data gathering. + * This can be used for working with the XHR information in one of the callbacks + * Scope: jQuery.dataTable.classSettings + */ + this.jqXHR = null; + + /* + * Variable: fnServerData + * Purpose: Function to get the server-side data - can be overruled by the developer + * Scope: jQuery.dataTable.classSettings + */ + this.fnServerData = function ( url, data, callback, settings ) { + settings.jqXHR = $.ajax( { + "url": url, + "data": data, + "success": function (json) { + $(settings.oInstance).trigger('xhr', settings); + callback( json ); + }, + "dataType": "json", + "cache": false, + "error": function (xhr, error, thrown) { + if ( error == "parsererror" ) { + alert( "DataTables warning: JSON data from server could not be parsed. "+ + "This is caused by a JSON formatting error." ); + } + } + } ); + }; + + /* + * Variable: aoServerParams + * Purpose: Functions which are called prior to sending an Ajax request so extra parameters + * can easily be sent to the server + * Scope: jQuery.dataTable.classSettings + * Notes: Each array element is an object with the following parameters: + * function:fn - function to call + * string:sName - name callback - useful for knowing where it came from (plugin etc) + */ + this.aoServerParams = []; + + /* + * Variable: fnFormatNumber + * Purpose: Format numbers for display + * Scope: jQuery.dataTable.classSettings + */ + this.fnFormatNumber = function ( iIn ) + { + if ( iIn < 1000 ) + { + /* A small optimisation for what is likely to be the vast majority of use cases */ + return iIn; + } + else + { + var s=(iIn+""), a=s.split(""), out="", iLen=s.length; + + for ( var i=0 ; i
                      '+s+'
                      ':'
                      '+s+"
                      ":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding}); +y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height== +i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents()); +f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode== +37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto"); +s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('').appendTo(j); +f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c); +j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type== +"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"), +10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)}; +b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("data-rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[data-rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k= +0,C=a.length;ko.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+ +1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h= +true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1; +b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5- +d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('
                      '),t=b('
                      '),u=b('
                      '),f=b('
                      '));D=b('
                      ').append('
                      ').appendTo(f); +D.append(j=b('
                      '),E=b(''),n=b('
                      '),z=b(''),A=b(''));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()}); +b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('').prependTo(D)}}}; +b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing", +easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.form.min.js b/lib/scripts/jquery.form.min.js new file mode 100644 index 0000000..ee9b9ef --- /dev/null +++ b/lib/scripts/jquery.form.min.js @@ -0,0 +1,7 @@ +/* +* jQuery Form Plugin; v20140218 +* http://jquery.malsup.com/form/ +* Copyright (c) 2014 M. Alsup; Dual licensed: MIT/GPL +* https://github.com/malsup/form#copyright-and-license +*/ +;!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):a("undefined"!=typeof jQuery?jQuery:window.Zepto)}(function(a){"use strict";function b(b){var c=b.data;b.isDefaultPrevented()||(b.preventDefault(),a(b.target).ajaxSubmit(c))}function c(b){var c=b.target,d=a(c);if(!d.is("[type=submit],[type=image]")){var e=d.closest("[type=submit]");if(0===e.length)return;c=e[0]}var f=this;if(f.clk=c,"image"==c.type)if(void 0!==b.offsetX)f.clk_x=b.offsetX,f.clk_y=b.offsetY;else if("function"==typeof a.fn.offset){var g=d.offset();f.clk_x=b.pageX-g.left,f.clk_y=b.pageY-g.top}else f.clk_x=b.pageX-c.offsetLeft,f.clk_y=b.pageY-c.offsetTop;setTimeout(function(){f.clk=f.clk_x=f.clk_y=null},100)}function d(){if(a.fn.ajaxSubmit.debug){var b="[jquery.form] "+Array.prototype.join.call(arguments,"");window.console&&window.console.log?window.console.log(b):window.opera&&window.opera.postError&&window.opera.postError(b)}}var e={};e.fileapi=void 0!==a("").get(0).files,e.formdata=void 0!==window.FormData;var f=!!a.fn.prop;a.fn.attr2=function(){if(!f)return this.attr.apply(this,arguments);var a=this.prop.apply(this,arguments);return a&&a.jquery||"string"==typeof a?a:this.attr.apply(this,arguments)},a.fn.ajaxSubmit=function(b){function c(c){var d,e,f=a.param(c,b.traditional).split("&"),g=f.length,h=[];for(d=0;g>d;d++)f[d]=f[d].replace(/\+/g," "),e=f[d].split("="),h.push([decodeURIComponent(e[0]),decodeURIComponent(e[1])]);return h}function g(d){for(var e=new FormData,f=0;f').val(m.extraData[n].value).appendTo(x)[0]):k.push(a('').val(m.extraData[n]).appendTo(x)[0]));m.iframeTarget||q.appendTo("body"),r.attachEvent?r.attachEvent("onload",h):r.addEventListener("load",h,!1),setTimeout(b,15);try{x.submit()}catch(p){var s=document.createElement("form").submit;s.apply(x)}}finally{x.setAttribute("action",f),x.setAttribute("enctype",j),c?x.setAttribute("target",c):l.removeAttr("target"),a(k).remove()}}function h(b){if(!s.aborted&&!F){if(E=e(r),E||(d("cannot access response document"),b=A),b===z&&s)return s.abort("timeout"),y.reject(s,"timeout"),void 0;if(b==A&&s)return s.abort("server abort"),y.reject(s,"error","server abort"),void 0;if(E&&E.location.href!=m.iframeSrc||v){r.detachEvent?r.detachEvent("onload",h):r.removeEventListener("load",h,!1);var c,f="success";try{if(v)throw"timeout";var g="xml"==m.dataType||E.XMLDocument||a.isXMLDoc(E);if(d("isXml="+g),!g&&window.opera&&(null===E.body||!E.body.innerHTML)&&--G)return d("requeing onLoad callback, DOM not available"),setTimeout(h,250),void 0;var i=E.body?E.body:E.documentElement;s.responseText=i?i.innerHTML:null,s.responseXML=E.XMLDocument?E.XMLDocument:E,g&&(m.dataType="xml"),s.getResponseHeader=function(a){var b={"content-type":m.dataType};return b[a.toLowerCase()]},i&&(s.status=Number(i.getAttribute("status"))||s.status,s.statusText=i.getAttribute("statusText")||s.statusText);var j=(m.dataType||"").toLowerCase(),k=/(json|script|text)/.test(j);if(k||m.textarea){var l=E.getElementsByTagName("textarea")[0];if(l)s.responseText=l.value,s.status=Number(l.getAttribute("status"))||s.status,s.statusText=l.getAttribute("statusText")||s.statusText;else if(k){var o=E.getElementsByTagName("pre")[0],p=E.getElementsByTagName("body")[0];o?s.responseText=o.textContent?o.textContent:o.innerText:p&&(s.responseText=p.textContent?p.textContent:p.innerText)}}else"xml"==j&&!s.responseXML&&s.responseText&&(s.responseXML=H(s.responseText));try{D=J(s,j,m)}catch(t){f="parsererror",s.error=c=t||f}}catch(t){d("error caught: ",t),f="error",s.error=c=t||f}s.aborted&&(d("upload aborted"),f=null),s.status&&(f=s.status>=200&&s.status<300||304===s.status?"success":"error"),"success"===f?(m.success&&m.success.call(m.context,D,"success",s),y.resolve(s.responseText,"success",s),n&&a.event.trigger("ajaxSuccess",[s,m])):f&&(void 0===c&&(c=s.statusText),m.error&&m.error.call(m.context,s,f,c),y.reject(s,"error",c),n&&a.event.trigger("ajaxError",[s,m,c])),n&&a.event.trigger("ajaxComplete",[s,m]),n&&!--a.active&&a.event.trigger("ajaxStop"),m.complete&&m.complete.call(m.context,s,f),F=!0,m.timeout&&clearTimeout(w),setTimeout(function(){m.iframeTarget?q.attr("src",m.iframeSrc):q.remove(),s.responseXML=null},100)}}}var j,k,m,n,o,q,r,s,t,u,v,w,x=l[0],y=a.Deferred();if(y.abort=function(a){s.abort(a)},c)for(k=0;k'),q.css({position:"absolute",top:"-1000px",left:"-1000px"})),r=q[0],s={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(b){var c="timeout"===b?"timeout":"aborted";d("aborting upload... "+c),this.aborted=1;try{r.contentWindow.document.execCommand&&r.contentWindow.document.execCommand("Stop")}catch(e){}q.attr("src",m.iframeSrc),s.error=c,m.error&&m.error.call(m.context,s,c,b),n&&a.event.trigger("ajaxError",[s,m,c]),m.complete&&m.complete.call(m.context,s,c)}},n=m.global,n&&0===a.active++&&a.event.trigger("ajaxStart"),n&&a.event.trigger("ajaxSend",[s,m]),m.beforeSend&&m.beforeSend.call(m.context,s,m)===!1)return m.global&&a.active--,y.reject(),y;if(s.aborted)return y.reject(),y;t=x.clk,t&&(u=t.name,u&&!t.disabled&&(m.extraData=m.extraData||{},m.extraData[u]=t.value,"image"==t.type&&(m.extraData[u+".x"]=x.clk_x,m.extraData[u+".y"]=x.clk_y)));var z=1,A=2,B=a("meta[name=csrf-token]").attr("content"),C=a("meta[name=csrf-param]").attr("content");C&&B&&(m.extraData=m.extraData||{},m.extraData[C]=B),m.forceSync?g():setTimeout(g,10);var D,E,F,G=50,H=a.parseXML||function(a,b){return window.ActiveXObject?(b=new ActiveXObject("Microsoft.XMLDOM"),b.async="false",b.loadXML(a)):b=(new DOMParser).parseFromString(a,"text/xml"),b&&b.documentElement&&"parsererror"!=b.documentElement.nodeName?b:null},I=a.parseJSON||function(a){return window.eval("("+a+")")},J=function(b,c,d){var e=b.getResponseHeader("content-type")||"",f="xml"===c||!c&&e.indexOf("xml")>=0,g=f?b.responseXML:b.responseText;return f&&"parsererror"===g.documentElement.nodeName&&a.error&&a.error("parsererror"),d&&d.dataFilter&&(g=d.dataFilter(g,c)),"string"==typeof g&&("json"===c||!c&&e.indexOf("json")>=0?g=I(g):("script"===c||!c&&e.indexOf("javascript")>=0)&&a.globalEval(g)),g};return y}if(!this.length)return d("ajaxSubmit: skipping submit process - no element selected"),this;var i,j,k,l=this;"function"==typeof b?b={success:b}:void 0===b&&(b={}),i=b.type||this.attr2("method"),j=b.url||this.attr2("action"),k="string"==typeof j?a.trim(j):"",k=k||window.location.href||"",k&&(k=(k.match(/^([^#]+)/)||[])[1]),b=a.extend(!0,{url:k,success:a.ajaxSettings.success,type:i||a.ajaxSettings.type,iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},b);var m={};if(this.trigger("form-pre-serialize",[this,b,m]),m.veto)return d("ajaxSubmit: submit vetoed via form-pre-serialize trigger"),this;if(b.beforeSerialize&&b.beforeSerialize(this,b)===!1)return d("ajaxSubmit: submit aborted via beforeSerialize callback"),this;var n=b.traditional;void 0===n&&(n=a.ajaxSettings.traditional);var o,p=[],q=this.formToArray(b.semantic,p);if(b.data&&(b.extraData=b.data,o=a.param(b.data,n)),b.beforeSubmit&&b.beforeSubmit(q,this,b)===!1)return d("ajaxSubmit: submit aborted via beforeSubmit callback"),this;if(this.trigger("form-submit-validate",[q,this,b,m]),m.veto)return d("ajaxSubmit: submit vetoed via form-submit-validate trigger"),this;var r=a.param(q,n);o&&(r=r?r+"&"+o:o),"GET"==b.type.toUpperCase()?(b.url+=(b.url.indexOf("?")>=0?"&":"?")+r,b.data=null):b.data=r;var s=[];if(b.resetForm&&s.push(function(){l.resetForm()}),b.clearForm&&s.push(function(){l.clearForm(b.includeHidden)}),!b.dataType&&b.target){var t=b.success||function(){};s.push(function(c){var d=b.replaceTarget?"replaceWith":"html";a(b.target)[d](c).each(t,arguments)})}else b.success&&s.push(b.success);if(b.success=function(a,c,d){for(var e=b.context||this,f=0,g=s.length;g>f;f++)s[f].apply(e,[a,c,d||l,l])},b.error){var u=b.error;b.error=function(a,c,d){var e=b.context||this;u.apply(e,[a,c,d,l])}}if(b.complete){var v=b.complete;b.complete=function(a,c){var d=b.context||this;v.apply(d,[a,c,l])}}var w=a("input[type=file]:enabled",this).filter(function(){return""!==a(this).val()}),x=w.length>0,y="multipart/form-data",z=l.attr("enctype")==y||l.attr("encoding")==y,A=e.fileapi&&e.formdata;d("fileAPI :"+A);var B,C=(x||z)&&!A;b.iframe!==!1&&(b.iframe||C)?b.closeKeepAlive?a.get(b.closeKeepAlive,function(){B=h(q)}):B=h(q):B=(x||z)&&A?g(q):a.ajax(b),l.removeData("jqxhr").data("jqxhr",B);for(var D=0;Dj;j++)if(n=i[j],l=n.name,l&&!n.disabled)if(b&&g.clk&&"image"==n.type)g.clk==n&&(d.push({name:l,value:a(n).val(),type:n.type}),d.push({name:l+".x",value:g.clk_x},{name:l+".y",value:g.clk_y}));else if(m=a.fieldValue(n,!0),m&&m.constructor==Array)for(c&&c.push(n),k=0,p=m.length;p>k;k++)d.push({name:l,value:m[k]});else if(e.fileapi&&"file"==n.type){c&&c.push(n);var q=n.files;if(q.length)for(k=0;kf;f++)c.push({name:d,value:e[f]});else null!==e&&"undefined"!=typeof e&&c.push({name:this.name,value:e})}}),a.param(c)},a.fn.fieldValue=function(b){for(var c=[],d=0,e=this.length;e>d;d++){var f=this[d],g=a.fieldValue(f,b);null===g||"undefined"==typeof g||g.constructor==Array&&!g.length||(g.constructor==Array?a.merge(c,g):c.push(g))}return c},a.fieldValue=function(b,c){var d=b.name,e=b.type,f=b.tagName.toLowerCase();if(void 0===c&&(c=!0),c&&(!d||b.disabled||"reset"==e||"button"==e||("checkbox"==e||"radio"==e)&&!b.checked||("submit"==e||"image"==e)&&b.form&&b.form.clk!=b||"select"==f&&-1==b.selectedIndex))return null;if("select"==f){var g=b.selectedIndex;if(0>g)return null;for(var h=[],i=b.options,j="select-one"==e,k=j?g+1:i.length,l=j?g:0;k>l;l++){var m=i[l];if(m.selected){var n=m.value;if(n||(n=m.attributes&&m.attributes.value&&!m.attributes.value.specified?m.text:m.value),j)return n;h.push(n)}}return h}return a(b).val()},a.fn.clearForm=function(b){return this.each(function(){a("input,select,textarea",this).clearFields(b)})},a.fn.clearFields=a.fn.clearInputs=function(b){var c=/^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i;return this.each(function(){var d=this.type,e=this.tagName.toLowerCase();c.test(d)||"textarea"==e?this.value="":"checkbox"==d||"radio"==d?this.checked=!1:"select"==e?this.selectedIndex=-1:"file"==d?/MSIE/.test(navigator.userAgent)?a(this).replaceWith(a(this).clone(!0)):a(this).val(""):b&&(b===!0&&/hidden/.test(d)||"string"==typeof b&&a(this).is(b))&&(this.value="")})},a.fn.resetForm=function(){return this.each(function(){("function"==typeof this.reset||"object"==typeof this.reset&&!this.reset.nodeType)&&this.reset()})},a.fn.enable=function(a){return void 0===a&&(a=!0),this.each(function(){this.disabled=!a})},a.fn.selected=function(b){return void 0===b&&(b=!0),this.each(function(){var c=this.type;if("checkbox"==c||"radio"==c)this.checked=b;else if("option"==this.tagName.toLowerCase()){var d=a(this).parent("select");b&&d[0]&&"select-one"==d[0].type&&d.find("option").selected(!1),this.selected=b}})},a.fn.ajaxSubmit.debug=!1}); \ No newline at end of file diff --git a/lib/scripts/jquery.formstyler.min.js b/lib/scripts/jquery.formstyler.min.js new file mode 100644 index 0000000..52fc7f7 --- /dev/null +++ b/lib/scripts/jquery.formstyler.min.js @@ -0,0 +1,2 @@ +/* jQuery Form Styler v2.0.2 | (c) Dimox | https://github.com/Dimox/jQueryFormStyler */ +!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof exports?module.exports=e($||require("jquery")):e(jQuery)}(function(e){"use strict";function t(t,s){this.element=t,this.options=e.extend({},l,s);var i=this.options.locale;void 0!==this.options.locales[i]&&e.extend(this.options,this.options.locales[i]),this.init()}function s(t){if(!e(t.target).parents().hasClass("jq-selectbox")&&"OPTION"!=t.target.nodeName&&e("div.jq-selectbox.opened").length){var s=e("div.jq-selectbox.opened"),l=e("div.jq-selectbox__search input",s),o=e("div.jq-selectbox__dropdown",s);s.find("select").data("_"+i).options.onSelectClosed.call(s),l.length&&l.val("").keyup(),o.hide().find("li.sel").addClass("selected"),s.removeClass("focused opened dropup dropdown")}}var i="styler",l={idSuffix:"-styler",filePlaceholder:"Файл не выбран",fileBrowse:"Обзор...",fileNumber:"Выбрано файлов: %s",selectPlaceholder:"Выберите...",selectSearch:!1,selectSearchLimit:10,selectSearchNotFound:"Совпадений не найдено",selectSearchPlaceholder:"Поиск...",selectVisibleOptions:0,selectSmartPositioning:!0,locale:"ru",locales:{en:{filePlaceholder:"No file selected",fileBrowse:"Browse...",fileNumber:"Selected files: %s",selectPlaceholder:"Select...",selectSearchNotFound:"No matches found",selectSearchPlaceholder:"Search..."}},onSelectOpened:function(){},onSelectClosed:function(){},onFormStyled:function(){}};t.prototype={init:function(){function t(){void 0!==i.attr("id")&&""!==i.attr("id")&&(this.id=i.attr("id")+l.idSuffix),this.title=i.attr("title"),this.classes=i.attr("class"),this.data=i.data()}var i=e(this.element),l=this.options,o=!(!navigator.userAgent.match(/(iPad|iPhone|iPod)/i)||navigator.userAgent.match(/(Windows\sPhone)/i)),a=!(!navigator.userAgent.match(/Android/i)||navigator.userAgent.match(/(Windows\sPhone)/i));if(i.is(":checkbox")){var d=function(){var s=new t,l=e('
                      ').attr({id:s.id,title:s.title}).addClass(s.classes).data(s.data);i.after(l).prependTo(l),i.is(":checked")&&l.addClass("checked"),i.is(":disabled")&&l.addClass("disabled"),l.click(function(e){e.preventDefault(),i.triggerHandler("click"),l.is(".disabled")||(i.is(":checked")?(i.prop("checked",!1),l.removeClass("checked")):(i.prop("checked",!0),l.addClass("checked")),i.focus().change())}),i.closest("label").add('label[for="'+i.attr("id")+'"]').on("click.styler",function(t){e(t.target).is("a")||e(t.target).closest(l).length||(l.triggerHandler("click"),t.preventDefault())}),i.on("change.styler",function(){i.is(":checked")?l.addClass("checked"):l.removeClass("checked")}).on("keydown.styler",function(e){32==e.which&&l.click()}).on("focus.styler",function(){l.is(".disabled")||l.addClass("focused")}).on("blur.styler",function(){l.removeClass("focused")})};d(),i.on("refresh",function(){i.closest("label").add('label[for="'+i.attr("id")+'"]').off(".styler"),i.off(".styler").parent().before(i).remove(),d()})}else if(i.is(":radio")){var r=function(){var s=new t,l=e('
                      ').attr({id:s.id,title:s.title}).addClass(s.classes).data(s.data);i.after(l).prependTo(l),i.is(":checked")&&l.addClass("checked"),i.is(":disabled")&&l.addClass("disabled"),e.fn.commonParents=function(){var t=this;return t.first().parents().filter(function(){return e(this).find(t).length===t.length})},e.fn.commonParent=function(){return e(this).commonParents().first()},l.click(function(t){if(t.preventDefault(),i.triggerHandler("click"),!l.is(".disabled")){var s=e('input[name="'+i.attr("name")+'"]');s.commonParent().find(s).prop("checked",!1).parent().removeClass("checked"),i.prop("checked",!0).parent().addClass("checked"),i.focus().change()}}),i.closest("label").add('label[for="'+i.attr("id")+'"]').on("click.styler",function(t){e(t.target).is("a")||e(t.target).closest(l).length||(l.triggerHandler("click"),t.preventDefault())}),i.on("change.styler",function(){i.parent().addClass("checked")}).on("focus.styler",function(){l.is(".disabled")||l.addClass("focused")}).on("blur.styler",function(){l.removeClass("focused")})};r(),i.on("refresh",function(){i.closest("label").add('label[for="'+i.attr("id")+'"]').off(".styler"),i.off(".styler").parent().before(i).remove(),r()})}else if(i.is(":file")){var c=function(){var s=new t,o=i.data("placeholder");void 0===o&&(o=l.filePlaceholder);var a=i.data("browse");void 0!==a&&""!==a||(a=l.fileBrowse);var d=e('
                      '+o+'
                      '+a+"
                      ").attr({id:s.id,title:s.title}).addClass(s.classes).data(s.data);i.after(d).appendTo(d),i.is(":disabled")&&d.addClass("disabled");var r=i.val(),c=e("div.jq-file__name",d);r&&c.text(r.replace(/.+[\\\/]/,"")),i.on("change.styler",function(){var e=i.val();if(i.is("[multiple]")){e="";var t=i[0].files.length;if(t>0){var s=i.data("number");void 0===s&&(s=l.fileNumber),s=s.replace("%s",t),e=s}}c.text(e.replace(/.+[\\\/]/,"")),""===e?(c.text(o),d.removeClass("changed")):d.addClass("changed")}).on("focus.styler",function(){d.addClass("focused")}).on("blur.styler",function(){d.removeClass("focused")}).on("click.styler",function(){d.removeClass("focused")})};c(),i.on("refresh",function(){i.off(".styler").parent().before(i).remove(),c()})}else if(i.is('input[type="number"]')){var n=function(){var s=new t,l=e('
                      ').attr({id:s.id,title:s.title}).addClass(s.classes).data(s.data);i.after(l).prependTo(l).wrap('
                      '),i.is(":disabled")&&l.addClass("disabled");var o,a,d,r=null,c=null;void 0!==i.attr("min")&&(o=i.attr("min")),void 0!==i.attr("max")&&(a=i.attr("max")),d=void 0!==i.attr("step")&&e.isNumeric(i.attr("step"))?Number(i.attr("step")):Number(1);var n=function(t){var s,l=i.val();e.isNumeric(l)||(l=0,i.val("0")),t.is(".minus")?s=Number(l)-d:t.is(".plus")&&(s=Number(l)+d);var r=(d.toString().split(".")[1]||[]).length;if(r>0){for(var c="1";c.length<=r;)c+="0";s=Math.round(s*c)/c}e.isNumeric(o)&&e.isNumeric(a)?s>=o&&s<=a&&i.val(s):e.isNumeric(o)&&!e.isNumeric(a)?s>=o&&i.val(s):!e.isNumeric(o)&&e.isNumeric(a)?s<=a&&i.val(s):i.val(s)};l.is(".disabled")||(l.on("mousedown","div.jq-number__spin",function(){var t=e(this);n(t),r=setTimeout(function(){c=setInterval(function(){n(t)},40)},350)}).on("mouseup mouseout","div.jq-number__spin",function(){clearTimeout(r),clearInterval(c)}).on("mouseup","div.jq-number__spin",function(){i.change().trigger("input")}),i.on("focus.styler",function(){l.addClass("focused")}).on("blur.styler",function(){l.removeClass("focused")}))};n(),i.on("refresh",function(){i.off(".styler").closest(".jq-number").before(i).remove(),n()})}else if(i.is("select")){var f=function(){function d(e){var t=e.prop("scrollHeight")-e.outerHeight(),s=null,i=null;e.off("mousewheel DOMMouseScroll").on("mousewheel DOMMouseScroll",function(l){s=l.originalEvent.detail<0||l.originalEvent.wheelDelta>0?1:-1,((i=e.scrollTop())>=t&&s<0||i<=0&&s>0)&&(l.stopPropagation(),l.preventDefault())})}function r(){for(var e=0;e"+t.html()+"",t.parent().is("optgroup")&&(void 0!==t.parent().attr("class")&&(h=" "+t.parent().attr("class")),s=""+t.html()+"",t.is(":first-child")&&(s='
                    • '+t.parent().attr("label")+"
                    • "+s)),n+=s}}var c=e("option",i),n="";if(i.is("[multiple]")){if(a||o)return;!function(){var s=new t,l=e('
                      ').attr({id:s.id,title:s.title}).addClass(s.classes).data(s.data);i.after(l),r(),l.append("
                        "+n+"
                      ");var o=e("ul",l),a=e("li",l),f=i.attr("size"),h=o.outerHeight(),u=a.outerHeight();void 0!==f&&f>0?o.css({height:u*f}):o.css({height:4*u}),h>l.height()&&(o.css("overflowY","scroll"),d(o),a.filter(".selected").length&&o.scrollTop(o.scrollTop()+a.filter(".selected").position().top)),i.prependTo(l),i.is(":disabled")?(l.addClass("disabled"),c.each(function(){e(this).is(":selected")&&a.eq(e(this).index()).addClass("selected")})):(a.filter(":not(.disabled):not(.optgroup)").click(function(t){i.focus();var s=e(this);if(t.ctrlKey||t.metaKey||s.addClass("selected"),t.shiftKey||s.addClass("first"),t.ctrlKey||t.metaKey||t.shiftKey||s.siblings().removeClass("selected first"),(t.ctrlKey||t.metaKey)&&(s.is(".selected")?s.removeClass("selected first"):s.addClass("selected first"),s.siblings().removeClass("first")),t.shiftKey){var l=!1,o=!1;s.siblings().removeClass("selected").siblings(".first").addClass("selected"),s.prevAll().each(function(){e(this).is(".first")&&(l=!0)}),s.nextAll().each(function(){e(this).is(".first")&&(o=!0)}),l&&s.prevAll().each(function(){if(e(this).is(".selected"))return!1;e(this).not(".disabled, .optgroup").addClass("selected")}),o&&s.nextAll().each(function(){if(e(this).is(".selected"))return!1;e(this).not(".disabled, .optgroup").addClass("selected")}),1==a.filter(".selected").length&&s.addClass("first")}c.prop("selected",!1),a.filter(".selected").each(function(){var t=e(this),s=t.index();t.is(".option")&&(s-=t.prevAll(".optgroup").length),c.eq(s).prop("selected",!0)}),i.change()}),c.each(function(t){e(this).data("optionIndex",t)}),i.on("change.styler",function(){a.removeClass("selected");var t=[];c.filter(":selected").each(function(){t.push(e(this).data("optionIndex"))}),a.not(".optgroup").filter(function(s){return e.inArray(s,t)>-1}).addClass("selected")}).on("focus.styler",function(){l.addClass("focused")}).on("blur.styler",function(){l.removeClass("focused")}),h>l.height()&&i.on("keydown.styler",function(e){38!=e.which&&37!=e.which&&33!=e.which||o.scrollTop(o.scrollTop()+a.filter(".selected").position().top-u),40!=e.which&&39!=e.which&&34!=e.which||o.scrollTop(o.scrollTop()+a.filter(".selected:last").position().top-o.innerHeight()+2*u)}))}()}else!function(){var a=new t,f="",h=i.data("placeholder"),u=i.data("search"),p=i.data("search-limit"),v=i.data("search-not-found"),m=i.data("search-placeholder"),g=i.data("smart-positioning");void 0===h&&(h=l.selectPlaceholder),void 0!==u&&""!==u||(u=l.selectSearch),void 0!==p&&""!==p||(p=l.selectSearchLimit),void 0!==v&&""!==v||(v=l.selectSearchNotFound),void 0===m&&(m=l.selectSearchPlaceholder),void 0!==g&&""!==g||(g=l.selectSmartPositioning);var b=e('
                      ').attr({id:a.id,title:a.title}).addClass(a.classes).data(a.data);i.after(b).prependTo(b);var C=b.css("z-index");C=C>0?C:1;var x=e("div.jq-selectbox__select",b),y=e("div.jq-selectbox__select-text",b),w=c.filter(":selected");r(),u&&(f='
                      '+v+"
                      ");var q=e('
                      '+f+"
                        "+n+"
                      ");b.append(q);var _=e("ul",q),j=e("li",q),k=e("input",q),S=e("div.jq-selectbox__not-found",q).hide();j.lengthT&&(T=t.innerWidth(),N=t.width())}),j.css({display:""}),y.is(".placeholder")&&y.width()>T)y.width(y.width());else{var P=b.clone().appendTo("body").width("auto"),H=P.outerWidth();P.remove(),H==b.outerWidth()&&y.width(N)}T>b.width()&&q.width(T),""===c.first().text()&&""!==i.data("placeholder")&&j.first().hide();var A=b.outerHeight(!0),D=k.parent().outerHeight(!0)||0,I=_.css("max-height"),K=j.filter(".selected");if(K.length<1&&j.first().addClass("selected sel"),void 0===j.data("li-height")){var O=j.outerHeight();!1!==h&&(O=j.eq(1).outerHeight()),j.data("li-height",O)}var M=q.css("top");if("auto"==q.css("left")&&q.css({left:0}),"auto"==q.css("top")&&(q.css({top:A}),M=A),q.hide(),K.length&&(c.first().text()!=w.text()&&b.addClass("changed"),b.data("jqfs-class",K.data("jqfs-class")),b.addClass(K.data("jqfs-class"))),i.is(":disabled"))return b.addClass("disabled"),!1;x.click(function(){if(e("div.jq-selectbox").filter(".opened").length&&l.onSelectClosed.call(e("div.jq-selectbox").filter(".opened")),i.focus(),!o){var t=e(window),s=j.data("li-height"),a=b.offset().top,r=t.height()-A-(a-t.scrollTop()),n=i.data("visible-options");void 0!==n&&""!==n||(n=l.selectVisibleOptions);var f=5*s,h=s*n;n>0&&n<6&&(f=h),0===n&&(h="auto");var u=function(){q.height("auto").css({bottom:"auto",top:M});var e=function(){_.css("max-height",Math.floor((r-20-D)/s)*s)};e(),_.css("max-height",h),"none"!=I&&_.css("max-height",I),rf+D+20?(u(),b.removeClass("dropup").addClass("dropdown")):(function(){q.height("auto").css({top:"auto",bottom:M});var e=function(){_.css("max-height",Math.floor((a-t.scrollTop()-20-D)/s)*s)};e(),_.css("max-height",h),"none"!=I&&_.css("max-height",I),a-t.scrollTop()-20f+D+20&&(u(),b.removeClass("dropup").addClass("dropdown")):(q.height("auto").css({bottom:"auto",top:M}),_.css("max-height",h),"none"!=I&&_.css("max-height",I)),b.offset().left+q.outerWidth()>t.width()&&q.css({left:"auto",right:0}),e("div.jqselect").css({zIndex:C-1}).removeClass("opened"),b.css({zIndex:C}),q.is(":hidden")?(e("div.jq-selectbox__dropdown:visible").hide(),q.show(),b.addClass("opened focused"),l.onSelectOpened.call(b)):(q.hide(),b.removeClass("opened dropup dropdown"),e("div.jq-selectbox").filter(".opened").length&&l.onSelectClosed.call(b)),k.length&&(k.val("").keyup(),S.hide(),k.keyup(function(){var t=e(this).val();j.each(function(){e(this).html().match(new RegExp(".*?"+t+".*?","i"))?e(this).show():e(this).hide()}),""===c.first().text()&&""!==i.data("placeholder")&&j.first().hide(),j.filter(":visible").length<1?S.show():S.hide()})),j.filter(".selected").length&&(""===i.val()?_.scrollTop(0):(_.innerHeight()/s%2!=0&&(s/=2),_.scrollTop(_.scrollTop()+j.filter(".selected").position().top-_.innerHeight()/2+s))),d(_)}}),j.hover(function(){e(this).siblings().removeClass("selected")});var W=j.filter(".selected").text();j.filter(":not(.disabled):not(.optgroup)").click(function(){i.focus();var t=e(this),s=t.text();if(!t.is(".selected")){var o=t.index();o-=t.prevAll(".optgroup").length,t.addClass("selected sel").siblings().removeClass("selected sel"),c.prop("selected",!1).eq(o).prop("selected",!0),W=s,y.text(s),b.data("jqfs-class")&&b.removeClass(b.data("jqfs-class")),b.data("jqfs-class",t.data("jqfs-class")),b.addClass(t.data("jqfs-class")),i.change()}q.hide(),b.removeClass("opened dropup dropdown"),l.onSelectClosed.call(b)}),q.mouseout(function(){e("li.sel",q).addClass("selected")}),i.on("change.styler",function(){y.text(c.filter(":selected").text()).removeClass("placeholder"),j.removeClass("selected sel").not(".optgroup").eq(i[0].selectedIndex).addClass("selected sel"),c.first().text()!=j.filter(".selected").text()?b.addClass("changed"):b.removeClass("changed")}).on("focus.styler",function(){b.addClass("focused"),e("div.jqselect").not(".focused").removeClass("opened dropup dropdown").find("div.jq-selectbox__dropdown").hide()}).on("blur.styler",function(){b.removeClass("focused")}).on("keydown.styler keyup.styler",function(e){var t=j.data("li-height");""===i.val()?y.text(h).addClass("placeholder"):y.text(c.filter(":selected").text()),j.removeClass("selected sel").not(".optgroup").eq(i[0].selectedIndex).addClass("selected sel"),38!=e.which&&37!=e.which&&33!=e.which&&36!=e.which||(""===i.val()?_.scrollTop(0):_.scrollTop(_.scrollTop()+j.filter(".selected").position().top)),40!=e.which&&39!=e.which&&34!=e.which&&35!=e.which||_.scrollTop(_.scrollTop()+j.filter(".selected").position().top-_.innerHeight()+t),13==e.which&&(e.preventDefault(),q.hide(),b.removeClass("opened dropup dropdown"),l.onSelectClosed.call(b))}).on("keydown.styler",function(e){32==e.which&&(e.preventDefault(),x.click())}),s.registered||(e(document).on("click",s),s.registered=!0)}()};f(),i.on("refresh",function(){i.off(".styler").parent().before(i).remove(),f()})}else i.is(":reset")&&i.on("click",function(){setTimeout(function(){i.closest("form").find("input, select").trigger("refresh")},1)})},destroy:function(){var t=e(this.element);t.is(":checkbox")||t.is(":radio")?(t.removeData("_"+i).off(".styler refresh").removeAttr("style").parent().before(t).remove(),t.closest("label").add('label[for="'+t.attr("id")+'"]').off(".styler")):t.is('input[type="number"]')?t.removeData("_"+i).off(".styler refresh").closest(".jq-number").before(t).remove():(t.is(":file")||t.is("select"))&&t.removeData("_"+i).off(".styler refresh").removeAttr("style").parent().before(t).remove()}},e.fn[i]=function(s){var l=arguments;if(void 0===s||"object"==typeof s)return this.each(function(){e.data(this,"_"+i)||e.data(this,"_"+i,new t(this,s))}).promise().done(function(){var t=e(this[0]).data("_"+i);t&&t.options.onFormStyled.call()}),this;if("string"==typeof s&&"_"!==s[0]&&"init"!==s){var o;return this.each(function(){var a=e.data(this,"_"+i);a instanceof t&&"function"==typeof a[s]&&(o=a[s].apply(a,Array.prototype.slice.call(l,1)))}),void 0!==o?o:this}},s.registered=!1}); \ No newline at end of file diff --git a/lib/scripts/jquery.jgrowl.js b/lib/scripts/jquery.jgrowl.js new file mode 100644 index 0000000..b7cbdff --- /dev/null +++ b/lib/scripts/jquery.jgrowl.js @@ -0,0 +1 @@ +(function(e){var t=function(){return!1===e.support.boxModel&&e.support.objectAll&&e.support.leadingWhitespace}();e.jGrowl=function(t,i){0==e("#jGrowl").size()&&e('
                      ').addClass(i&&i.position?i.position:e.jGrowl.defaults.position).appendTo("body"),e("#jGrowl").jGrowl(t,i)},e.fn.jGrowl=function(t,i){if(e.isFunction(this.each)){var o=arguments;return this.each(function(){void 0==e(this).data("jGrowl.instance")&&(e(this).data("jGrowl.instance",e.extend(new e.fn.jGrowl,{notifications:[],element:null,interval:null})),e(this).data("jGrowl.instance").startup(this)),e.isFunction(e(this).data("jGrowl.instance")[t])?e(this).data("jGrowl.instance")[t].apply(e(this).data("jGrowl.instance"),e.makeArray(o).slice(1)):e(this).data("jGrowl.instance").create(t,i)})}},e.extend(e.fn.jGrowl.prototype,{defaults:{pool:0,header:"",group:"",sticky:!1,position:"top-right",glue:"after",theme:"default",themeState:"highlight",corners:"10px",check:250,life:3e3,closeDuration:"normal",openDuration:"normal",easing:"swing",closer:!0,closeTemplate:"×",closerTemplate:"
                      [ close all ]
                      ",log:function(){},beforeOpen:function(){},afterOpen:function(){},open:function(){},beforeClose:function(){},close:function(){},animateOpen:{opacity:"show"},animateClose:{opacity:"hide"}},notifications:[],element:null,interval:null,create:function(t,i){var i=e.extend({},this.defaults,i);i.speed!==void 0&&(i.openDuration=i.speed,i.closeDuration=i.speed),this.notifications.push({message:t,options:i}),i.log.apply(this.element,[this.element,t,i])},render:function(t){var i=this,o=t.message,n=t.options;n.themeState=""==n.themeState?"":"ui-state-"+n.themeState;var t=e("
                      ").addClass("jGrowl-notification "+n.themeState+" ui-corner-all"+(void 0!=n.group&&""!=n.group?" "+n.group:"")).append(e("
                      ").addClass("jGrowl-close").html(n.closeTemplate)).append(e("
                      ").addClass("jGrowl-header").html(n.header)).append(e("
                      ").addClass("jGrowl-message").html(o)).data("jGrowl",n).addClass(n.theme).children("div.jGrowl-close").bind("click.jGrowl",function(){e(this).parent().trigger("jGrowl.beforeClose")}).parent();e(t).bind("mouseover.jGrowl",function(){e("div.jGrowl-notification",i.element).data("jGrowl.pause",!0)}).bind("mouseout.jGrowl",function(){e("div.jGrowl-notification",i.element).data("jGrowl.pause",!1)}).bind("jGrowl.beforeOpen",function(){n.beforeOpen.apply(t,[t,o,n,i.element])!==!1&&e(this).trigger("jGrowl.open")}).bind("jGrowl.open",function(){n.open.apply(t,[t,o,n,i.element])!==!1&&("after"==n.glue?e("div.jGrowl-notification:last",i.element).after(t):e("div.jGrowl-notification:first",i.element).before(t),e(this).animate(n.animateOpen,n.openDuration,n.easing,function(){e.support.opacity===!1&&this.style.removeAttribute("filter"),null!==e(this).data("jGrowl")&&(e(this).data("jGrowl").created=new Date),e(this).trigger("jGrowl.afterOpen")}))}).bind("jGrowl.afterOpen",function(){n.afterOpen.apply(t,[t,o,n,i.element])}).bind("jGrowl.beforeClose",function(){n.beforeClose.apply(t,[t,o,n,i.element])!==!1&&e(this).trigger("jGrowl.close")}).bind("jGrowl.close",function(){e(this).data("jGrowl.pause",!0),e(this).animate(n.animateClose,n.closeDuration,n.easing,function(){e.isFunction(n.close)?n.close.apply(t,[t,o,n,i.element])!==!1&&e(this).remove():e(this).remove()})}).trigger("jGrowl.beforeOpen"),""!=n.corners&&void 0!=e.fn.corner&&e(t).corner(n.corners),e("div.jGrowl-notification:parent",i.element).size()>1&&0==e("div.jGrowl-closer",i.element).size()&&this.defaults.closer!==!1&&e(this.defaults.closerTemplate).addClass("jGrowl-closer "+this.defaults.themeState+" ui-corner-all").addClass(this.defaults.theme).appendTo(i.element).animate(this.defaults.animateOpen,this.defaults.speed,this.defaults.easing).bind("click.jGrowl",function(){e(this).siblings().trigger("jGrowl.beforeClose"),e.isFunction(i.defaults.closer)&&i.defaults.closer.apply(e(this).parent()[0],[e(this).parent()[0]])})},update:function(){e(this.element).find("div.jGrowl-notification:parent").each(function(){void 0!=e(this).data("jGrowl")&&void 0!==e(this).data("jGrowl").created&&e(this).data("jGrowl").created.getTime()+parseInt(e(this).data("jGrowl").life)<(new Date).getTime()&&e(this).data("jGrowl").sticky!==!0&&(void 0==e(this).data("jGrowl.pause")||e(this).data("jGrowl.pause")!==!0)&&e(this).trigger("jGrowl.beforeClose")}),this.notifications.length>0&&(0==this.defaults.pool||e(this.element).find("div.jGrowl-notification:parent").size()e(this.element).find("div.jGrowl-notification:parent").size()&&e(this.element).find("div.jGrowl-closer").animate(this.defaults.animateClose,this.defaults.speed,this.defaults.easing,function(){e(this).remove()})},startup:function(i){this.element=e(i).addClass("jGrowl").append('
                      '),this.interval=setInterval(function(){e(i).data("jGrowl.instance").update()},parseInt(this.defaults.check)),t&&e(this.element).addClass("ie6")},shutdown:function(){e(this.element).removeClass("jGrowl").find("div.jGrowl-notification").trigger("jGrowl.close").parent().empty(),clearInterval(this.interval)},close:function(){e(this.element).find("div.jGrowl-notification").each(function(){e(this).trigger("jGrowl.beforeClose")})}}),e.jGrowl.defaults=e.fn.jGrowl.prototype.defaults})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.lazyload.mini.js b/lib/scripts/jquery.lazyload.mini.js new file mode 100644 index 0000000..9d61e0c --- /dev/null +++ b/lib/scripts/jquery.lazyload.mini.js @@ -0,0 +1,12 @@ + +(function($){$.fn.lazyload=function(options){var settings={threshold:0,failurelimit:0,event:"scroll",effect:"show",container:window};if(options){$.extend(settings,options);} +var elements=this;if("scroll"==settings.event){$(settings.container).bind("scroll",function(event){var counter=0;elements.each(function(){if($.abovethetop(this,settings)||$.leftofbegin(this,settings)){}else if(!$.belowthefold(this,settings)&&!$.rightoffold(this,settings)){$(this).trigger("appear");}else{if(counter++>settings.failurelimit){return false;}}});var temp=$.grep(elements,function(element){return!element.loaded;});elements=$(temp);});} +this.each(function(){var self=this;if(undefined==$(self).attr("original")){$(self).attr("original",$(self).attr("src"));} +if("scroll"!=settings.event||undefined==$(self).attr("src")||settings.placeholder==$(self).attr("src")||($.abovethetop(self,settings)||$.leftofbegin(self,settings)||$.belowthefold(self,settings)||$.rightoffold(self,settings))){if(settings.placeholder){$(self).attr("src",settings.placeholder);}else{$(self).removeAttr("src");} +self.loaded=false;}else{self.loaded=true;} +$(self).one("appear",function(){if(!this.loaded){$("").bind("load",function(){$(self).hide().attr("src",$(self).attr("original")) +[settings.effect](settings.effectspeed);self.loaded=true;}).attr("src",$(self).attr("original"));};});if("scroll"!=settings.event){$(self).bind(settings.event,function(event){if(!self.loaded){$(self).trigger("appear");}});}});$(settings.container).trigger(settings.event);return this;};$.belowthefold=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).height()+$(window).scrollTop();}else{var fold=$(settings.container).offset().top+$(settings.container).height();} +return fold<=$(element).offset().top-settings.threshold;};$.rightoffold=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).width()+$(window).scrollLeft();}else{var fold=$(settings.container).offset().left+$(settings.container).width();} +return fold<=$(element).offset().left-settings.threshold;};$.abovethetop=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).scrollTop();}else{var fold=$(settings.container).offset().top;} +return fold>=$(element).offset().top+settings.threshold+$(element).height();};$.leftofbegin=function(element,settings){if(settings.container===undefined||settings.container===window){var fold=$(window).scrollLeft();}else{var fold=$(settings.container).offset().left;} +return fold>=$(element).offset().left+settings.threshold+$(element).width();};$.extend($.expr[':'],{"below-the-fold":"$.belowthefold(a, {threshold : 0, container: window})","above-the-fold":"!$.belowthefold(a, {threshold : 0, container: window})","right-of-fold":"$.rightoffold(a, {threshold : 0, container: window})","left-of-fold":"!$.rightoffold(a, {threshold : 0, container: window})"});})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.mousewheel.js b/lib/scripts/jquery.mousewheel.js new file mode 100644 index 0000000..3390202 --- /dev/null +++ b/lib/scripts/jquery.mousewheel.js @@ -0,0 +1,12 @@ +/*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net) + * Licensed under the MIT License (LICENSE.txt). + * + * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers. + * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix. + * Thanks to: Seamus Leahy for adding deltaX and deltaY + * + * Version: 3.0.6 + * + * Requires: 1.2.2+ + */ +(function(a){function d(b){var c=b||window.event,d=[].slice.call(arguments,1),e=0,f=!0,g=0,h=0;return b=a.event.fix(c),b.type="mousewheel",c.wheelDelta&&(e=c.wheelDelta/120),c.detail&&(e=-c.detail/3),h=e,c.axis!==undefined&&c.axis===c.HORIZONTAL_AXIS&&(h=0,g=-1*e),c.wheelDeltaY!==undefined&&(h=c.wheelDeltaY/120),c.wheelDeltaX!==undefined&&(g=-1*c.wheelDeltaX/120),d.unshift(b,e,g,h),(a.event.dispatch||a.event.handle).apply(this,d)}var b=["DOMMouseScroll","mousewheel"];if(a.event.fixHooks)for(var c=b.length;c;)a.event.fixHooks[b[--c]]=a.event.mouseHooks;a.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=b.length;a;)this.addEventListener(b[--a],d,!1);else this.onmousewheel=d},teardown:function(){if(this.removeEventListener)for(var a=b.length;a;)this.removeEventListener(b[--a],d,!1);else this.onmousewheel=null}},a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery) diff --git a/lib/scripts/jquery.nestable.js b/lib/scripts/jquery.nestable.js new file mode 100644 index 0000000..4b51857 --- /dev/null +++ b/lib/scripts/jquery.nestable.js @@ -0,0 +1,484 @@ +/*! + * Nestable jQuery Plugin - Copyright (c) 2012 David Bushell - http://dbushell.com/ + * Dual-licensed under the BSD or MIT licenses + */ +;(function($, window, document, undefined) +{ + var hasTouch = 'ontouchstart' in document; + + /** + * Detect CSS pointer-events property + * events are normally disabled on the dragging element to avoid conflicts + * https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js + */ + var hasPointerEvents = (function() + { + var el = document.createElement('div'), + docEl = document.documentElement; + if (!('pointerEvents' in el.style)) { + return false; + } + el.style.pointerEvents = 'auto'; + el.style.pointerEvents = 'x'; + docEl.appendChild(el); + var supports = window.getComputedStyle && window.getComputedStyle(el, '').pointerEvents === 'auto'; + docEl.removeChild(el); + return !!supports; + })(); + + var defaults = { + listNodeName : 'ol', + itemNodeName : 'li', + rootClass : 'dd', + listClass : 'dd-list', + itemClass : 'dd-item', + dragClass : 'dd-dragel', + handleClass : 'dd-handle', + collapsedClass : 'dd-collapsed', + placeClass : 'dd-placeholder', + noDragClass : 'dd-nodrag', + emptyClass : 'dd-empty', + expandBtnHTML : '', + collapseBtnHTML : '', + group : 0, + maxDepth : 5, + threshold : 20 + }; + + function Plugin(element, options) + { + this.w = $(document); + this.el = $(element); + this.options = $.extend({}, defaults, options); + this.init(); + } + + Plugin.prototype = { + + init: function() + { + var list = this; + + list.reset(); + + list.el.data('nestable-group', this.options.group); + + list.placeEl = $('
                      '); + + $.each(this.el.find(list.options.itemNodeName), function(k, el) { + list.setParent($(el)); + }); + + list.el.on('click', 'button', function(e) { + if (list.dragEl) { + return; + } + var target = $(e.currentTarget), + action = target.data('action'), + item = target.parent(list.options.itemNodeName); + if (action === 'collapse') { + list.collapseItem(item); + } + if (action === 'expand') { + list.expandItem(item); + } + }); + + var onStartEvent = function(e) + { + var handle = $(e.target); + if (!handle.hasClass(list.options.handleClass)) { + if (handle.closest('.' + list.options.noDragClass).length) { + return; + } + handle = handle.closest('.' + list.options.handleClass); + } + + if (!handle.length || list.dragEl) { + return; + } + + list.isTouch = /^touch/.test(e.type); + if (list.isTouch && e.touches.length !== 1) { + return; + } + + e.preventDefault(); + list.dragStart(e.touches ? e.touches[0] : e); + }; + + var onMoveEvent = function(e) + { + if (list.dragEl) { + e.preventDefault(); + list.dragMove(e.touches ? e.touches[0] : e); + } + }; + + var onEndEvent = function(e) + { + if (list.dragEl) { + e.preventDefault(); + list.dragStop(e.touches ? e.touches[0] : e); + } + }; + + if (hasTouch) { + list.el[0].addEventListener('touchstart', onStartEvent, false); + window.addEventListener('touchmove', onMoveEvent, false); + window.addEventListener('touchend', onEndEvent, false); + window.addEventListener('touchcancel', onEndEvent, false); + } + + list.el.on('mousedown', onStartEvent); + list.w.on('mousemove', onMoveEvent); + list.w.on('mouseup', onEndEvent); + + }, + + serialize: function() + { + var data, + depth = 0, + list = this; + step = function(level, depth) + { + var array = [ ], + items = level.children(list.options.itemNodeName); + items.each(function() + { + var li = $(this), + item = $.extend({}, li.data()), + sub = li.children(list.options.listNodeName); + if (sub.length) { + item.children = step(sub, depth + 1); + } + array.push(item); + }); + return array; + }; + data = step(list.el.find(list.options.listNodeName).first(), depth); + return data; + }, + + serialise: function() + { + return this.serialize(); + }, + + reset: function() + { + this.mouse = { + offsetX : 0, + offsetY : 0, + startX : 0, + startY : 0, + lastX : 0, + lastY : 0, + nowX : 0, + nowY : 0, + distX : 0, + distY : 0, + dirAx : 0, + dirX : 0, + dirY : 0, + lastDirX : 0, + lastDirY : 0, + distAxX : 0, + distAxY : 0 + }; + this.isTouch = false; + this.moving = false; + this.dragEl = null; + this.dragRootEl = null; + this.dragDepth = 0; + this.hasNewRoot = false; + this.pointEl = null; + }, + + expandItem: function(li) + { + li.removeClass(this.options.collapsedClass); + li.children('[data-action="expand"]').hide(); + li.children('[data-action="collapse"]').show(); + li.children(this.options.listNodeName).show(); + }, + + collapseItem: function(li) + { + var lists = li.children(this.options.listNodeName); + if (lists.length) { + li.addClass(this.options.collapsedClass); + li.children('[data-action="collapse"]').hide(); + li.children('[data-action="expand"]').show(); + li.children(this.options.listNodeName).hide(); + } + }, + + expandAll: function() + { + var list = this; + list.el.find(list.options.itemNodeName).each(function() { + list.expandItem($(this)); + }); + }, + + collapseAll: function() + { + var list = this; + list.el.find(list.options.itemNodeName).each(function() { + list.collapseItem($(this)); + }); + }, + + setParent: function(li) + { + if (li.children(this.options.listNodeName).length) { + li.prepend($(this.options.expandBtnHTML)); + li.prepend($(this.options.collapseBtnHTML)); + } + li.children('[data-action="expand"]').hide(); + }, + + unsetParent: function(li) + { + li.removeClass(this.options.collapsedClass); + li.children('[data-action]').remove(); + li.children(this.options.listNodeName).remove(); + }, + + dragStart: function(e) + { + var mouse = this.mouse, + target = $(e.target), + dragItem = target.closest(this.options.itemNodeName); + + this.placeEl.css('height', dragItem.height()); + + mouse.offsetX = e.offsetX !== undefined ? e.offsetX : e.pageX - target.offset().left; + mouse.offsetY = e.offsetY !== undefined ? e.offsetY : e.pageY - target.offset().top; + mouse.startX = mouse.lastX = e.pageX; + mouse.startY = mouse.lastY = e.pageY; + + this.dragRootEl = this.el; + + this.dragEl = $(document.createElement(this.options.listNodeName)).addClass(this.options.listClass + ' ' + this.options.dragClass); + this.dragEl.css('width', dragItem.width()); + + dragItem.after(this.placeEl); + dragItem[0].parentNode.removeChild(dragItem[0]); + dragItem.appendTo(this.dragEl); + + $(document.body).append(this.dragEl); + this.dragEl.css({ + 'left' : e.pageX - mouse.offsetX, + 'top' : e.pageY - mouse.offsetY + }); + // total depth of dragging item + var i, depth, + items = this.dragEl.find(this.options.itemNodeName); + for (i = 0; i < items.length; i++) { + depth = $(items[i]).parents(this.options.listNodeName).length; + if (depth > this.dragDepth) { + this.dragDepth = depth; + } + } + }, + + dragStop: function(e) + { + var el = this.dragEl.children(this.options.itemNodeName).first(); + el[0].parentNode.removeChild(el[0]); + this.placeEl.replaceWith(el); + + this.dragEl.remove(); + this.el.trigger('change'); + if (this.hasNewRoot) { + this.dragRootEl.trigger('change'); + } + this.reset(); + }, + + dragMove: function(e) + { + var list, parent, prev, next, depth, + opt = this.options, + mouse = this.mouse; + + this.dragEl.css({ + 'left' : e.pageX - mouse.offsetX, + 'top' : e.pageY - mouse.offsetY + }); + + // mouse position last events + mouse.lastX = mouse.nowX; + mouse.lastY = mouse.nowY; + // mouse position this events + mouse.nowX = e.pageX; + mouse.nowY = e.pageY; + // distance mouse moved between events + mouse.distX = mouse.nowX - mouse.lastX; + mouse.distY = mouse.nowY - mouse.lastY; + // direction mouse was moving + mouse.lastDirX = mouse.dirX; + mouse.lastDirY = mouse.dirY; + // direction mouse is now moving (on both axis) + mouse.dirX = mouse.distX === 0 ? 0 : mouse.distX > 0 ? 1 : -1; + mouse.dirY = mouse.distY === 0 ? 0 : mouse.distY > 0 ? 1 : -1; + // axis mouse is now moving on + var newAx = Math.abs(mouse.distX) > Math.abs(mouse.distY) ? 1 : 0; + + // do nothing on first move + if (!mouse.moving) { + mouse.dirAx = newAx; + mouse.moving = true; + return; + } + + // calc distance moved on this axis (and direction) + if (mouse.dirAx !== newAx) { + mouse.distAxX = 0; + mouse.distAxY = 0; + } else { + mouse.distAxX += Math.abs(mouse.distX); + if (mouse.dirX !== 0 && mouse.dirX !== mouse.lastDirX) { + mouse.distAxX = 0; + } + mouse.distAxY += Math.abs(mouse.distY); + if (mouse.dirY !== 0 && mouse.dirY !== mouse.lastDirY) { + mouse.distAxY = 0; + } + } + mouse.dirAx = newAx; + + /** + * move horizontal + */ + if (mouse.dirAx && mouse.distAxX >= opt.threshold) { + // reset move distance on x-axis for new phase + mouse.distAxX = 0; + prev = this.placeEl.prev(opt.itemNodeName); + // increase horizontal level if previous sibling exists and is not collapsed + if (mouse.distX > 0 && prev.length && !prev.hasClass(opt.collapsedClass)) { + // cannot increase level when item above is collapsed + list = prev.find(opt.listNodeName).last(); + // check if depth limit has reached + depth = this.placeEl.parents(opt.listNodeName).length; + if (depth + this.dragDepth <= opt.maxDepth) { + // create new sub-level if one doesn't exist + if (!list.length) { + list = $('<' + opt.listNodeName + '/>').addClass(opt.listClass); + list.append(this.placeEl); + prev.append(list); + this.setParent(prev); + } else { + // else append to next level up + list = prev.children(opt.listNodeName).last(); + list.append(this.placeEl); + } + } + } + // decrease horizontal level + if (mouse.distX < 0) { + // we can't decrease a level if an item preceeds the current one + next = this.placeEl.next(opt.itemNodeName); + if (!next.length) { + parent = this.placeEl.parent(); + this.placeEl.closest(opt.itemNodeName).after(this.placeEl); + if (!parent.children().length) { + this.unsetParent(parent.parent()); + } + } + } + } + + var isEmpty = false; + + // find list item under cursor + if (!hasPointerEvents) { + this.dragEl[0].style.visibility = 'hidden'; + } + this.pointEl = $(document.elementFromPoint(e.pageX - document.body.scrollLeft, e.pageY - (window.pageYOffset || document.documentElement.scrollTop))); + if (!hasPointerEvents) { + this.dragEl[0].style.visibility = 'visible'; + } + if (this.pointEl.hasClass(opt.handleClass)) { + this.pointEl = this.pointEl.parent(opt.itemNodeName); + } + if (this.pointEl.hasClass(opt.emptyClass)) { + isEmpty = true; + } + else if (!this.pointEl.length || !this.pointEl.hasClass(opt.itemClass)) { + return; + } + + // find parent list of item under cursor + var pointElRoot = this.pointEl.closest('.' + opt.rootClass), + isNewRoot = this.dragRootEl.data('nestable-id') !== pointElRoot.data('nestable-id'); + + /** + * move vertical + */ + if (!mouse.dirAx || isNewRoot || isEmpty) { + // check if groups match if dragging over new root + if (isNewRoot && opt.group !== pointElRoot.data('nestable-group')) { + return; + } + // check depth limit + depth = this.dragDepth - 1 + this.pointEl.parents(opt.listNodeName).length; + if (depth > opt.maxDepth) { + return; + } + var before = e.pageY < (this.pointEl.offset().top + this.pointEl.height() / 2); + parent = this.placeEl.parent(); + // if empty create new list to replace empty placeholder + if (isEmpty) { + list = $(document.createElement(opt.listNodeName)).addClass(opt.listClass); + list.append(this.placeEl); + this.pointEl.replaceWith(list); + } + else if (before) { + this.pointEl.before(this.placeEl); + } + else { + this.pointEl.after(this.placeEl); + } + if (!parent.children().length) { + this.unsetParent(parent.parent()); + } + if (!this.dragRootEl.find(opt.itemNodeName).length) { + this.dragRootEl.append('
                      '); + } + // parent root list has changed + if (isNewRoot) { + this.dragRootEl = pointElRoot; + this.hasNewRoot = this.el[0] !== this.dragRootEl[0]; + } + } + } + + }; + + $.fn.nestable = function(params) + { + var lists = this, + retval = this; + + lists.each(function() + { + var plugin = $(this).data("nestable"); + + if (!plugin) { + $(this).data("nestable", new Plugin(this, params)); + $(this).data("nestable-id", new Date().getTime()); + } else { + if (typeof params === 'string' && typeof plugin[params] === 'function') { + retval = plugin[params](); + } + } + }); + + return retval || lists; + }; + +})(window.jQuery || window.Zepto, window, document); \ No newline at end of file diff --git a/lib/scripts/jquery.nicefileinput.min.js b/lib/scripts/jquery.nicefileinput.min.js new file mode 100644 index 0000000..5a19796 --- /dev/null +++ b/lib/scripts/jquery.nicefileinput.min.js @@ -0,0 +1 @@ +!function(a){a.fn.nicefileinput=function(b){var c={label:"Browse...",fullPath:!1};return b&&a.extend(c,b),this.each(function(){var b=this;if(void 0===a(b).attr("data-styled")){var d=Math.round(1e4*Math.random()),e=new Date,f=e.getTime()+d.toString(),g=a('').css({display:"block","float":"left",margin:0,padding:"0 5px"}).addClass("NFI-filename NFI"+f),h=a("
                      ").css({overflow:"hidden",position:"relative",display:"block","float":"left","white-space":"nowrap","text-align":"center"}).addClass("NFI-button NFI"+f).html(c.label);a(b).after(g),a(b).wrap(h),a(".NFI"+f).wrapAll('
                      '),a(".NFI-wrapper").css({overflow:"auto",display:"inline-block"}),a("#NFI-wrapper-"+f).addClass(a(b).attr("class")),a(b).css({opacity:0,position:"absolute",border:"none",margin:0,padding:0,top:0,right:0,cursor:"pointer",height:"60px"}).addClass("NFI-current"),a(b).on("change",function(){var d=a(b).val();if(c.fullPath)g.val(d);else{var e=d.split(/[/\\]/);g.val(e[e.length-1])}}),a(b).attr("data-styled",!0)}})}}(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.placeholder.min.js b/lib/scripts/jquery.placeholder.min.js new file mode 100644 index 0000000..f04903a --- /dev/null +++ b/lib/scripts/jquery.placeholder.min.js @@ -0,0 +1,11 @@ +/* +* Placeholder plugin for jQuery +* --- +* Copyright 2010, Daniel Stocks (http://webcloud.se) +* Released under the MIT, BSD, and GPL Licenses. +*/ + +(function(b){function d(a){this.input=a;a.attr("type")=="password"&&this.handlePassword();b(a[0].form).submit(function(){if(a.hasClass("placeholder")&&a[0].value==a.attr("placeholder"))a[0].value=""})}d.prototype={show:function(a){if(this.input[0].value===""||a&&this.valueIsPlaceholder()){if(this.isPassword)try{this.input[0].setAttribute("type","text")}catch(b){this.input.before(this.fakePassword.show()).hide()}this.input.addClass("placeholder");this.input[0].value=this.input.attr("placeholder")}}, +hide:function(){if(this.valueIsPlaceholder()&&this.input.hasClass("placeholder")&&(this.input.removeClass("placeholder"),this.input[0].value="",this.isPassword)){try{this.input[0].setAttribute("type","password")}catch(a){}this.input.show();this.input[0].focus()}},valueIsPlaceholder:function(){return this.input[0].value==this.input.attr("placeholder")},handlePassword:function(){var a=this.input;a.attr("realType","password");this.isPassword=!0;if(b.browser.msie&&a[0].outerHTML){var c=b(a[0].outerHTML.replace(/type=(['"])?password\1/gi, +"type=$1text$1"));this.fakePassword=c.val(a.attr("placeholder")).addClass("placeholder").focus(function(){a.trigger("focus");b(this).hide()});b(a[0].form).submit(function(){c.remove();a.show()})}}};var e=!!("placeholder"in document.createElement("input"));b.fn.placeholder=function(){return e?this:this.each(function(){var a=b(this),c=new d(a);c.show(!0);a.focus(function(){c.hide()});a.blur(function(){c.show(!1)});b.browser.msie&&(b(window).load(function(){a.val()&&a.removeClass("placeholder");c.show(!0)}), +a.focus(function(){if(this.value==""){var a=this.createTextRange();a.collapse(!0);a.moveStart("character",0);a.select()}}))})}})(jQuery); diff --git a/lib/scripts/jquery.sticky.js b/lib/scripts/jquery.sticky.js new file mode 100644 index 0000000..d545982 --- /dev/null +++ b/lib/scripts/jquery.sticky.js @@ -0,0 +1,112 @@ +// Sticky Plugin +// ============= +// Author: Anthony Garand +// Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk) +// Improvements by Leonardo C. Daronco (daronco) +// Created: 2/14/2011 +// Date: 2/12/2012 +// Website: http://labs.anthonygarand.com/sticky +// Description: Makes an element on the page stick on the screen as you scroll +// It will only set the 'top' and 'position' of your element, you +// might need to adjust the width in some cases. + +(function($) { + var defaults = { + topSpacing: 0, + bottomSpacing: 0, + className: 'is-sticky', + wrapperClassName: 'sticky-wrapper' + }, + $window = $(window), + $document = $(document), + sticked = [], + windowHeight = $window.height(), + scroller = function() { + var scrollTop = $window.scrollTop(), + documentHeight = $document.height(), + dwh = documentHeight - windowHeight, + extra = (scrollTop > dwh) ? dwh - scrollTop : 0; + for (var i = 0; i < sticked.length; i++) { + var s = sticked[i], + elementTop = s.stickyWrapper.offset().top, + etse = elementTop - s.topSpacing - extra; + if (scrollTop <= etse) { + if (s.currentTop !== null) { + s.stickyElement + .css('position', '') + .css('top', '') + .removeClass(s.className); + s.stickyElement.parent().removeClass(s.className); + s.currentTop = null; + } + } + else { + var newTop = documentHeight - s.stickyElement.outerHeight() + - s.topSpacing - s.bottomSpacing - scrollTop - extra; + if (newTop < 0) { + newTop = newTop + s.topSpacing; + } else { + newTop = s.topSpacing; + } + if (s.currentTop != newTop) { + s.stickyElement + .css('position', 'fixed') + .css('top', newTop) + .addClass(s.className); + s.stickyElement.parent().addClass(s.className); + s.currentTop = newTop; + } + } + } + }, + resizer = function() { + windowHeight = $window.height(); + }, + methods = { + init: function(options) { + var o = $.extend(defaults, options); + return this.each(function() { + var stickyElement = $(this); + + stickyId = stickyElement.attr('id'); + wrapper = $('
                      ') + .attr('id', stickyId + '-sticky-wrapper') + .addClass(o.wrapperClassName); + stickyElement.wrapAll(wrapper); + var stickyWrapper = stickyElement.parent(); + stickyWrapper.css('height', stickyElement.outerHeight()); + sticked.push({ + topSpacing: o.topSpacing, + bottomSpacing: o.bottomSpacing, + stickyElement: stickyElement, + currentTop: null, + stickyWrapper: stickyWrapper, + className: o.className + }); + }); + }, + update: scroller + }; + + // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): + if (window.addEventListener) { + window.addEventListener('scroll', scroller, false); + window.addEventListener('resize', resizer, false); + } else if (window.attachEvent) { + window.attachEvent('onscroll', scroller); + window.attachEvent('onresize', resizer); + } + + $.fn.sticky = function(method) { + if (methods[method]) { + return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); + } else if (typeof method === 'object' || !method ) { + return methods.init.apply( this, arguments ); + } else { + $.error('Method ' + method + ' does not exist on jQuery.sticky'); + } + }; + $(function() { + setTimeout(scroller, 0); + }); +})(jQuery); diff --git a/lib/scripts/jquery.tipsy.js b/lib/scripts/jquery.tipsy.js new file mode 100644 index 0000000..7286206 --- /dev/null +++ b/lib/scripts/jquery.tipsy.js @@ -0,0 +1,198 @@ +// tipsy, facebook style tooltips for jquery +// version 1.0.0a +// (c) 2008-2010 jason frame [jason@onehackoranother.com] +// releated under the MIT license + +(function($) { + + function fixTitle($ele) { + if ($ele.attr('title') || typeof($ele.attr('original-title')) != 'string') { + $ele.attr('original-title', $ele.attr('title') || '').removeAttr('title'); + } + } + + function Tipsy(element, options) { + this.$element = $(element); + this.options = options; + this.enabled = true; + fixTitle(this.$element); + } + + Tipsy.prototype = { + show: function() { + var title = this.getTitle(); + if (title && this.enabled) { + var $tip = this.tip(); + + $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title); + $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity + $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body); + + var pos = $.extend({}, this.$element.offset(), { + width: this.$element[0].offsetWidth, + height: this.$element[0].offsetHeight + }); + + var actualWidth = $tip[0].offsetWidth, actualHeight = $tip[0].offsetHeight; + var gravity = (typeof this.options.gravity == 'function') + ? this.options.gravity.call(this.$element[0]) + : this.options.gravity; + + var tp; + switch (gravity.charAt(0)) { + case 'n': + tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}; + break; + case 's': + tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}; + break; + case 'e': + tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}; + break; + case 'w': + tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}; + break; + } + + if (gravity.length == 2) { + if (gravity.charAt(1) == 'w') { + tp.left = pos.left + pos.width / 2 - 15; + } else { + tp.left = pos.left + pos.width / 2 - actualWidth + 15; + } + } + + $tip.css(tp).addClass('tipsy-' + gravity); + + if (this.options.fade) { + $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity}); + } else { + $tip.css({visibility: 'visible', opacity: this.options.opacity}); + } + } + }, + + hide: function() { + if (this.options.fade) { + this.tip().stop().fadeOut(function() { $(this).remove(); }); + } else { + this.tip().remove(); + } + }, + + getTitle: function() { + var title, $e = this.$element, o = this.options; + fixTitle($e); + var title, o = this.options; + if (typeof o.title == 'string') { + title = $e.attr(o.title == 'title' ? 'original-title' : o.title); + } else if (typeof o.title == 'function') { + title = o.title.call($e[0]); + } + title = ('' + title).replace(/(^\s*|\s*$)/, ""); + return title || o.fallback; + }, + + tip: function() { + if (!this.$tip) { + this.$tip = $('
                      ').html('
                      '); + } + return this.$tip; + }, + + validate: function() { + if (!this.$element[0].parentNode) { + this.hide(); + this.$element = null; + this.options = null; + } + }, + + enable: function() { this.enabled = true; }, + disable: function() { this.enabled = false; }, + toggleEnabled: function() { this.enabled = !this.enabled; } + }; + + $.fn.tipsy = function(options) { + + if (options === true) { + return this.data('tipsy'); + } else if (typeof options == 'string') { + return this.data('tipsy')[options](); + } + + options = $.extend({}, $.fn.tipsy.defaults, options); + + function get(ele) { + var tipsy = $.data(ele, 'tipsy'); + if (!tipsy) { + tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options)); + $.data(ele, 'tipsy', tipsy); + } + return tipsy; + } + + function enter() { + var tipsy = get(this); + tipsy.hoverState = 'in'; + if (options.delayIn == 0) { + tipsy.show(); + } else { + setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn); + } + }; + + function leave() { + var tipsy = get(this); + tipsy.hoverState = 'out'; + if (options.delayOut == 0) { + tipsy.hide(); + } else { + setTimeout(function() { if (tipsy.hoverState == 'out') tipsy.hide(); }, options.delayOut); + } + }; + + if (!options.live) this.each(function() { get(this); }); + + if (options.trigger != 'manual') { + var binder = options.live ? 'live' : 'bind', + eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus', + eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'; + this[binder](eventIn, enter)[binder](eventOut, leave); + } + + return this; + + }; + + $.fn.tipsy.defaults = { + delayIn: 0, + delayOut: 0, + fade: false, + fallback: '', + gravity: 'n', + html: true, + live: false, + offset: 0, + opacity: 0.9, + title: 'title', + trigger: 'hover' + }; + + // Overwrite this method to provide options on a per-element basis. + // For example, you could store the gravity in a 'tipsy-gravity' attribute: + // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' }); + // (remember - do not modify 'options' in place!) + $.fn.tipsy.elementOptions = function(ele, options) { + return $.metadata ? $.extend({}, options, $(ele).metadata()) : options; + }; + + $.fn.tipsy.autoNS = function() { + return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n'; + }; + + $.fn.tipsy.autoWE = function() { + return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w'; + }; + +})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.tmpl.min.js b/lib/scripts/jquery.tmpl.min.js new file mode 100644 index 0000000..a615f5b --- /dev/null +++ b/lib/scripts/jquery.tmpl.min.js @@ -0,0 +1,10 @@ +/* + * 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(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i").join(">").split('"').join(""").split("'").join("'")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},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:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.totop.js b/lib/scripts/jquery.totop.js new file mode 100644 index 0000000..83f845a --- /dev/null +++ b/lib/scripts/jquery.totop.js @@ -0,0 +1,5 @@ +/* UItoTop jQuery Plugin 1.2 | Matt Varone | http://www.mattvarone.com/web-design/uitotop-jquery-plugin */ +(function($){$.fn.UItoTop=function(options){var defaults={text:'To Top',min:200,inDelay:600,outDelay:400,containerID:'toTop',containerHoverID:'toTopHover',scrollSpeed:1200,easingType:'linear'},settings=$.extend(defaults,options),containerIDhash='#'+settings.containerID,containerHoverIDHash='#'+settings.containerHoverID;$('body').append(''+settings.text+'');$(containerIDhash).hide().on('click.UItoTop',function(){$('html, body').animate({scrollTop:0},settings.scrollSpeed,settings.easingType);$('#'+settings.containerHoverID,this).stop().animate({'opacity':0},settings.inDelay,settings.easingType);return false;}).prepend('').hover(function(){$(containerHoverIDHash,this).stop().animate({'opacity':1},600,'linear');},function(){$(containerHoverIDHash,this).stop().animate({'opacity':0},700,'linear');});$(window).scroll(function(){var sd=$(window).scrollTop();if(typeof document.body.style.maxHeight==="undefined"){$(containerIDhash).css({'position':'absolute','top':sd+$(window).height()-50});} +if(sd>settings.min) +$(containerIDhash).fadeIn(settings.inDelay);else +$(containerIDhash).fadeOut(settings.Outdelay);});};})(jQuery); \ No newline at end of file diff --git a/lib/scripts/jquery.transform.js b/lib/scripts/jquery.transform.js new file mode 100644 index 0000000..27ef12b --- /dev/null +++ b/lib/scripts/jquery.transform.js @@ -0,0 +1,140 @@ +(function($){ + var defaultOptions = {preloadImg:true}; + + /*************************** + Labels + ***************************/ + var jqTransformGetLabel = function(objfield){ + var selfForm = $(objfield.get(0).form); + var oLabel = objfield.next(); + if(!oLabel.is('label')) { + oLabel = objfield.prev(); + if(oLabel.is('label')){ + var inputname = objfield.attr('id'); + if(inputname){ + oLabel = selfForm.find('label[for="'+inputname+'"]'); + } + } + } + if(oLabel.is('label')){return oLabel.css('cursor','pointer');} + return false; + }; + + /* Check for an external click */ + var jqTransformCheckExternalClick = function(event) { + if ($(event.target).parents('.jqTransformSelectWrapper').length === 0) { jqTransformHideSelect($(event.target)); } + }; + + /* Apply document listener */ + var jqTransformAddDocumentListener = function (){ + $(document).on('mousedown', jqTransformCheckExternalClick); + }; + + /* Add a new handler for the reset action */ + var jqTransformReset = function(f){ + $('a.jqTransformCheckbox, a.jqTransformRadio', f).removeClass('jqTransformChecked'); + $('input:checkbox, input:radio', f).each(function(){if(this.checked){$('a', $(this).parent()).addClass('jqTransformChecked');}}); + }; + + /*************************** + Check Boxes + ***************************/ + $.fn.jqTransCheckBox = function(){ + return this.each(function(){ + if($(this).hasClass('jqTransformHidden')) {return;} + + var $input = $(this); + + //set the click on the label + var oLabel = jqTransformGetLabel($input); + oLabel && oLabel.click(function(){aLink.trigger('click');}); + + if($input.attr('title') && $input.attr('class')){ + var aLink = $(''); + }else{ + var aLink = $(''); + } + + //wrap and add the link + + if($input.hasClass('float')){ + $input.addClass('jqTransformHidden').wrap('').parent().prepend(aLink); + }else{ + $input.addClass('jqTransformHidden').wrap('').parent().prepend(aLink); + }; + + if($input.attr('disabled')){aLink.addClass('jqTransformCheckedDisable')}; + if($input.attr('disabled') && $input.attr('checked')){aLink.addClass('jqTransformCheckedDisableCheck')}; + + //on change, change the class of the link + $input.change(function(){ + this.checked && aLink.addClass('jqTransformChecked') || aLink.removeClass('jqTransformChecked'); + return true; + }); + + // Click Handler, trigger the click and change event on the input + aLink.on('click', function(){ + //do nothing if the original input is disabled + if($input.attr('disabled')){return false;} + //trigger the envents on the input object + $input.trigger('click').trigger("change"); + return false; + }); + + // set the default state + this.checked && aLink.addClass('jqTransformChecked'); + }); + }; + + /*************************** + Radio Buttons + ***************************/ + $.fn.jqTransRadio = function(){ + return this.each(function(){ + if($(this).hasClass('jqTransformHidden')) {return;} + + var $input = $(this); + var inputSelf = this; + + oLabel = jqTransformGetLabel($input); + oLabel && oLabel.click(function(){aLink.trigger('click');}); + + var aLink = $(''); + $input.addClass('jqTransformHidden').wrap('').parent().prepend(aLink); + + $input.change(function(){ + inputSelf.checked && aLink.addClass('jqTransformChecked') || aLink.removeClass('jqTransformChecked'); + return true; + }); + + // Click Handler + aLink.on('click', function(){ + if($input.attr('disabled')){return false;} + $input.trigger('click').trigger('change'); + + // uncheck all others of same name input radio elements + $('input[name="'+$input.attr('name')+'"]',inputSelf.form).not($input).each(function(){ + $(this).attr('type')=='radio' && $(this).trigger('change'); + }); + + return false; + }); + // set the default state + inputSelf.checked && aLink.addClass('jqTransformChecked'); + }); + }; + + $.fn.jqTransform = function(options){ + var opt = $.extend({},defaultOptions,options); + + /* each form */ + return this.each(function(){ + + $('input:checkbox', this).jqTransCheckBox(); + $('input:radio', this).jqTransRadio(); + + }); /* End Form each */ + + };/* End the Plugin */ + +})(jQuery); \ No newline at end of file diff --git a/lib/scripts/mousetrap.js b/lib/scripts/mousetrap.js new file mode 100644 index 0000000..114a222 --- /dev/null +++ b/lib/scripts/mousetrap.js @@ -0,0 +1,9 @@ +/* mousetrap v1.4.6 craig.is/killing/mice */ +(function(J,r,f){function s(a,b,d){a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a){a=a||{};var b=!1,d;for(d in n)a[d]?b=!0:n[d]=0;b||(u=!1)}function C(a,b,d,c,e,v){var g,k,f=[],h=d.type;if(!l[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(g=0;gg||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[d]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:c,modifiers:f,action:e}}function F(a,b,d,c,e){q[a+":"+d]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,d){a=a instanceof Array?a:[a];for(var c=0;c
                      ' + }; + + /** + * Updates configuration. + * + * NProgress.configure({ + * minimum: 0.1 + * }); + */ + NProgress.configure = function(options) { + var key, value; + for (key in options) { + value = options[key]; + if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value; + } + + return this; + }; + + /** + * Last number. + */ + + NProgress.status = null; + + /** + * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`. + * + * NProgress.set(0.4); + * NProgress.set(1.0); + */ + + NProgress.set = function(n) { + var started = NProgress.isStarted(); + + n = clamp(n, Settings.minimum, 1); + NProgress.status = (n === 1 ? null : n); + + var progress = NProgress.render(!started), + bar = progress.querySelector(Settings.barSelector), + speed = Settings.speed, + ease = Settings.easing; + + progress.offsetWidth; /* Repaint */ + + queue(function(next) { + // Set positionUsing if it hasn't already been set + if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS(); + + // Add transition + css(bar, barPositionCSS(n, speed, ease)); + + if (n === 1) { + // Fade out + css(progress, { + transition: 'none', + opacity: 1 + }); + progress.offsetWidth; /* Repaint */ + + setTimeout(function() { + css(progress, { + transition: 'all ' + speed + 'ms linear', + opacity: 0 + }); + setTimeout(function() { + NProgress.remove(); + next(); + }, speed); + }, speed); + } else { + setTimeout(next, speed); + } + }); + + return this; + }; + + NProgress.isStarted = function() { + return typeof NProgress.status === 'number'; + }; + + /** + * Shows the progress bar. + * This is the same as setting the status to 0%, except that it doesn't go backwards. + * + * NProgress.start(); + * + */ + NProgress.start = function() { + if (!NProgress.status) NProgress.set(0); + + var work = function() { + setTimeout(function() { + if (!NProgress.status) return; + NProgress.trickle(); + work(); + }, Settings.trickleSpeed); + }; + + if (Settings.trickle) work(); + + return this; + }; + + /** + * Hides the progress bar. + * This is the *sort of* the same as setting the status to 100%, with the + * difference being `done()` makes some placebo effect of some realistic motion. + * + * NProgress.done(); + * + * If `true` is passed, it will show the progress bar even if its hidden. + * + * NProgress.done(true); + */ + + NProgress.done = function(force) { + if (!force && !NProgress.status) return this; + + return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); + }; + + /** + * Increments by a random amount. + */ + + NProgress.inc = function(amount) { + var n = NProgress.status; + + if (!n) { + return NProgress.start(); + } else { + if (typeof amount !== 'number') { + amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95); + } + + n = clamp(n + amount, 0, 0.994); + return NProgress.set(n); + } + }; + + NProgress.trickle = function() { + return NProgress.inc(Math.random() * Settings.trickleRate); + }; + + /** + * Waits for all supplied jQuery promises and + * increases the progress as the promises resolve. + * + * @param $promise jQUery Promise + */ + (function() { + var initial = 0, current = 0; + + NProgress.promise = function($promise) { + if (!$promise || $promise.state() == "resolved") { + return this; + } + + if (current == 0) { + NProgress.start(); + } + + initial++; + current++; + + $promise.always(function() { + current--; + if (current == 0) { + initial = 0; + NProgress.done(); + } else { + NProgress.set((initial - current) / initial); + } + }); + + return this; + }; + + })(); + + /** + * (Internal) renders the progress bar markup based on the `template` + * setting. + */ + + NProgress.render = function(fromStart) { + if (NProgress.isRendered()) return document.getElementById('nprogress'); + + addClass(document.documentElement, 'nprogress-busy'); + + var progress = document.createElement('div'); + progress.id = 'nprogress'; + progress.innerHTML = Settings.template; + + var bar = progress.querySelector(Settings.barSelector), + perc = fromStart ? '-100' : toBarPerc(NProgress.status || 0), + spinner; + + css(bar, { + transition: 'all 0 linear', + transform: 'translate3d(' + perc + '%,0,0)' + }); + + if (!Settings.showSpinner) { + spinner = progress.querySelector(Settings.spinnerSelector); + spinner && removeElement(spinner); + } + + document.body.appendChild(progress); + return progress; + }; + + /** + * Removes the element. Opposite of render(). + */ + + NProgress.remove = function() { + removeClass(document.documentElement, 'nprogress-busy'); + var progress = document.getElementById('nprogress'); + progress && removeElement(progress); + }; + + /** + * Checks if the progress bar is rendered. + */ + + NProgress.isRendered = function() { + return !!document.getElementById('nprogress'); + }; + + /** + * Determine which positioning CSS rule to use. + */ + + NProgress.getPositioningCSS = function() { + // Sniff on document.body.style + var bodyStyle = document.body.style; + + // Sniff prefixes + var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' : + ('MozTransform' in bodyStyle) ? 'Moz' : + ('msTransform' in bodyStyle) ? 'ms' : + ('OTransform' in bodyStyle) ? 'O' : ''; + + if (vendorPrefix + 'Perspective' in bodyStyle) { + // Modern browsers with 3D support, e.g. Webkit, IE10 + return 'translate3d'; + } else if (vendorPrefix + 'Transform' in bodyStyle) { + // Browsers without 3D support, e.g. IE9 + return 'translate'; + } else { + // Browsers without translate() support, e.g. IE7-8 + return 'margin'; + } + }; + + /** + * Helpers + */ + + function clamp(n, min, max) { + if (n < min) return min; + if (n > max) return max; + return n; + } + + /** + * (Internal) converts a percentage (`0..1`) to a bar translateX + * percentage (`-100%..0%`). + */ + + function toBarPerc(n) { + return (-1 + n) * 100; + } + + + /** + * (Internal) returns the correct CSS for changing the bar's + * position given an n percentage, and speed and ease from Settings + */ + + function barPositionCSS(n, speed, ease) { + var barCSS; + + if (Settings.positionUsing === 'translate3d') { + barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' }; + } else if (Settings.positionUsing === 'translate') { + barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' }; + } else { + barCSS = { 'margin-left': toBarPerc(n)+'%' }; + } + + barCSS.transition = 'all '+speed+'ms '+ease; + + return barCSS; + } + + /** + * (Internal) Queues a function to be executed. + */ + + var queue = (function() { + var pending = []; + + function next() { + var fn = pending.shift(); + if (fn) { + fn(next); + } + } + + return function(fn) { + pending.push(fn); + if (pending.length == 1) next(); + }; + })(); + + /** + * (Internal) Applies css properties to an element, similar to the jQuery + * css method. + * + * While this helper does assist with vendor prefixed property names, it + * does not perform any manipulation of values prior to setting styles. + */ + + var css = (function() { + var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ], + cssProps = {}; + + function camelCase(string) { + return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) { + return letter.toUpperCase(); + }); + } + + function getVendorProp(name) { + var style = document.body.style; + if (name in style) return name; + + var i = cssPrefixes.length, + capName = name.charAt(0).toUpperCase() + name.slice(1), + vendorName; + while (i--) { + vendorName = cssPrefixes[i] + capName; + if (vendorName in style) return vendorName; + } + + return name; + } + + function getStyleProp(name) { + name = camelCase(name); + return cssProps[name] || (cssProps[name] = getVendorProp(name)); + } + + function applyCss(element, prop, value) { + prop = getStyleProp(prop); + element.style[prop] = value; + } + + return function(element, properties) { + var args = arguments, + prop, + value; + + if (args.length == 2) { + for (prop in properties) { + value = properties[prop]; + if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value); + } + } else { + applyCss(element, args[1], args[2]); + } + } + })(); + + /** + * (Internal) Determines if an element or space separated list of class names contains a class name. + */ + + function hasClass(element, name) { + var list = typeof element == 'string' ? element : classList(element); + return list.indexOf(' ' + name + ' ') >= 0; + } + + /** + * (Internal) Adds a class to an element. + */ + + function addClass(element, name) { + var oldList = classList(element), + newList = oldList + name; + + if (hasClass(oldList, name)) return; + + // Trim the opening space. + element.className = newList.substring(1); + } + + /** + * (Internal) Removes a class from an element. + */ + + function removeClass(element, name) { + var oldList = classList(element), + newList; + + if (!hasClass(element, name)) return; + + // Replace the class name. + newList = oldList.replace(' ' + name + ' ', ' '); + + // Trim the opening and closing spaces. + element.className = newList.substring(1, newList.length - 1); + } + + /** + * (Internal) Gets a space separated list of the class names on the element. + * The list is wrapped with a single space on each end to facilitate finding + * matches within the list. + */ + + function classList(element) { + return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' '); + } + + /** + * (Internal) Removes an element from the DOM. + */ + + function removeElement(element) { + element && element.parentNode && element.parentNode.removeChild(element); + } + + return NProgress; +}); + diff --git a/lib/scripts/uploader/Moxie.swf b/lib/scripts/uploader/Moxie.swf new file mode 100644 index 0000000..6493572 Binary files /dev/null and b/lib/scripts/uploader/Moxie.swf differ diff --git a/lib/scripts/uploader/Moxie.xap b/lib/scripts/uploader/Moxie.xap new file mode 100644 index 0000000..3a9f389 Binary files /dev/null and b/lib/scripts/uploader/Moxie.xap differ diff --git a/lib/scripts/uploader/browserplus.js b/lib/scripts/uploader/browserplus.js new file mode 100644 index 0000000..aecd19b --- /dev/null +++ b/lib/scripts/uploader/browserplus.js @@ -0,0 +1,8 @@ +/* + * browserplus.js + * + * Provides a gateway between user JavaScript and the BrowserPlus platform + * + * Copyright 2007-2009 Yahoo! Inc. All rights reserved. + */ +BrowserPlus=(typeof BrowserPlus!="undefined"&&BrowserPlus)?BrowserPlus:(function(){var P=false;var F="__browserPlusPluginID";var E="uninitialized";var G=[];var D="application/x-yahoo-browserplus_2";var J,K,L,H,A;return{initWhenAvailable:function(R,S){setTimeout(function(){try{navigator.plugins.refresh(false)}catch(T){}BrowserPlus.init(R,function(U){if(U.success){S(U)}else{BrowserPlus.initWhenAvailable(R,S)}})},1000)},clientSystemInfo:function(){return I()},listActiveServices:function(R){if(R==null||R.constructor!=Function){throw new Error("BrowserPlus.services() invoked without required callback parameter.")}return N().EnumerateServices(R)},getPlatformInfo:function(){if(N()===null){throw new Error("BrowserPlus.getPlatformInfo() invoked, but init() has not completed successfully.")}return N().Info()},isServiceLoaded:function(S,R){return((S!=undefined&&BrowserPlus.hasOwnProperty(S))&&(R==undefined||BrowserPlus[S].hasOwnProperty(R)))},describeService:function(S,R){if(R==null||R.constructor!=Function){throw new Error("BrowserPlus.services() invoked without required callback parameter")}if(N()===null){throw new Error("BrowserPlus.describeService() invoked, but init() has not completed successfully.")}return N().DescribeService(S,R)},isServiceActivated:function(S,R){return N().DescribeService(S,(function(){var T=R;return function(U){T(U.success)}})())},isInitialized:function(){return(E==="succeeded")},require:function(S,T){if(T==null||T.constructor!=Function){throw new Error("BrowserPlus.require() invoked without required callback parameter")}var R=function(V){if(V.success){var W=[];for(var U=0;U';document.documentElement.appendChild(S);P=true;return true}function C(){if(N()!=null){return true}try{var R=document.createElement("object");R.id=F;R.type=D;R.style.display="none";document.body.appendChild(R);document.getElementById(F).Ping();P=true;return true}catch(T){try{document.body.removeChild(R)}catch(S){}}return false}function N(){if(P){return document.getElementById(F)}return null}function B(){return(I().browser=="Explorer")}function M(T){T=T.value;var V=T.name;var R=T.versionString;if(!BrowserPlus[V]){BrowserPlus[V]={};BrowserPlus[V].corelet=V;BrowserPlus[V].version=R}if(!BrowserPlus[V][R]){BrowserPlus[V][R]={};BrowserPlus[V][R].corelet=V;BrowserPlus[V][R].version=R}if(V=="core"){BrowserPlus[V].version=R}if(T.functions){for(var S=0;S +
                      +

                      Your browser doesn't have Flash, Silverlight or HTML5 support.

                      +
                      + + + +@example + // Retrieving a reference to plupload.Uploader object + var uploader = $('#uploader').pluploadQueue(); + + uploader.bind('FilesAdded', function() { + + // Autostart + setTimeout(uploader.start, 1); // "detach" from the main thread + }); + +@class pluploadQueue +@constructor +@param {Object} settings For detailed information about each option check documentation. + @param {String} settings.url URL of the server-side upload handler. + @param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled. + @param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message. + @param {Array} [settings.filters=[]] Set of file type filters, each one defined by hash of title and extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR` + @param {String} [settings.flash_swf_url] URL of the Flash swf. + @param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs. + @param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`. + @param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event. + @param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message. + @param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload. + @param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog. + @param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`. + @param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess. + @param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}` + @param {Number} [settings.resize.width] If image is bigger, it will be resized. + @param {Number} [settings.resize.height] If image is bigger, it will be resized. + @param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100). + @param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally. + @param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails. + @param {String} [settings.silverlight_xap_url] URL of the Silverlight xap. + @param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files. + + @param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop. + @param {Boolean} [settings.rename=false] Enable ability to rename files in the queue. + @param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure. +*/ +(function($, o) { + var uploaders = {}; + + function _(str) { + return plupload.translate(str) || str; + } + + function renderUI(id, target) { + // Remove all existing non plupload items + target.contents().each(function(i, node) { + node = $(node); + + if (!node.is('.plupload')) { + node.remove(); + } + }); + + target.prepend( + '
                      ' + + '
                      ' + + '
                      ' + + '
                      ' + + '
                      ' + + '
                      ' + + '
                      ' + + + '
                      ' + + '
                      ' + + '
                      ' + _('Filename') + '
                      ' + + '
                       
                      ' + + '
                      ' + _('Status') + '
                      ' + + '
                      ' + _('Size') + '
                      ' + + '
                       
                      ' + + '
                      ' + + + '
                        ' + + + '' + + '
                        ' + + '
                        ' + + '
                        ' + + '' + + '
                        ' + ); + } + + $.fn.pluploadQueue = function(settings) { + if (settings) { + this.each(function() { + var uploader, target, id, contents_bak; + + target = $(this); + id = target.attr('id'); + + if (!id) { + id = plupload.guid(); + target.attr('id', id); + } + + contents_bak = target.html(); + renderUI(id, target); + + settings = $.extend({ + dragdrop: true, + browse_button: id + '_browse', + container: id + }, settings); + + // Enable drag/drop (see PostInit handler as well) + if (settings.dragdrop) { + settings.drop_element = id + '_filelist'; + } + + uploader = new plupload.Uploader(settings); + + uploaders[id] = uploader; + + function handleStatus(file) { + var actionClass; + + if (file.status == plupload.DONE) { + actionClass = 'plupload_done'; + } + + if (file.status == plupload.FAILED) { + actionClass = 'plupload_failed'; + } + + if (file.status == plupload.QUEUED) { + actionClass = 'plupload_delete'; + } + + if (file.status == plupload.UPLOADING) { + actionClass = 'plupload_uploading'; + } + + var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block'); + if (file.hint) { + icon.attr('title', file.hint); + } + } + + function updateTotalProgress() { + $('span.plupload_total_status', target).html(uploader.total.percent + '%'); + $('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%'); + $('span.plupload_upload_status', target).html( + o.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length) + ); + } + + function updateList() { + var fileList = $('ul.plupload_filelist', target).html(''), + inputCount = 0, + inputHTML; + + $.each(uploader.files, function(i, file) { + inputHTML = ''; + + if (file.status == plupload.DONE) { + if (file.target_name) { + inputHTML += ''; + } + + inputHTML += ''; + inputHTML += ''; + + inputCount++; + + $('#' + id + '_count').val(inputCount); + } + + fileList.append( + '
                      • ' + + '
                        ' + file.name + '
                        ' + + '
                        ' + + '
                        ' + file.percent + '%
                        ' + + '
                        ' + plupload.formatSize(file.size) + '
                        ' + + '
                         
                        ' + + inputHTML + + '
                      • ' + ); + + handleStatus(file); + + $('#' + file.id + '.plupload_delete a').click(function(e) { + $('#' + file.id).remove(); + uploader.removeFile(file); + + e.preventDefault(); + }); + }); + + $('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size)); + + if (uploader.total.queued === 0) { + $('span.plupload_add_text', target).html(_('Add Files')); + } else { + $('span.plupload_add_text', target).html(o.sprintf(_('%d files queued'), uploader.total.queued)); + } + + $('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed)); + + // Scroll to end of file list + fileList[0].scrollTop = fileList[0].scrollHeight; + + updateTotalProgress(); + + // Re-add drag message if there is no files + if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) { + $('#' + id + '_filelist').append('
                      • ' + _("Drag files here.") + '
                      • '); + } + } + + function destroy() { + delete uploaders[id]; + uploader.destroy(); + target.html(contents_bak); + uploader = target = contents_bak = null; + } + + uploader.bind("UploadFile", function(up, file) { + $('#' + file.id).addClass('plupload_current_file'); + }); + + uploader.bind('Init', function(up, res) { + // Enable rename support + if (!settings.unique_names && settings.rename) { + target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) { + var targetSpan = $(e.target), + file, parts, name, ext = ""; + + // Get file name and split out name and extension + file = up.getFile(targetSpan.parents('li')[0].id); + name = file.name; + parts = /^(.+)(\.[^.]+)$/.exec(name); + if (parts) { + name = parts[1]; + ext = parts[2]; + } + + // Display input element + targetSpan.hide().after(''); + targetSpan.next().val(name).focus().blur(function() { + targetSpan.show().next().remove(); + }).keydown(function(e) { + var targetInput = $(this); + + if (e.keyCode == 13) { + e.preventDefault(); + + // Rename file and glue extension back on + file.name = targetInput.val() + ext; + targetSpan.html(file.name); + targetInput.blur(); + } + }); + }); + } + + $('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime); + + $('a.plupload_start', target).click(function(e) { + if (!$(this).hasClass('plupload_disabled')) { + uploader.start(); + } + + e.preventDefault(); + }); + + $('a.plupload_stop', target).click(function(e) { + e.preventDefault(); + uploader.stop(); + }); + + $('a.plupload_start', target).addClass('plupload_disabled'); + }); + + uploader.bind("Error", function(up, err) { + var file = err.file, + message; + + if (file) { + message = err.message; + + if (err.details) { + message += " (" + err.details + ")"; + } + + if (err.code == plupload.FILE_SIZE_ERROR) { + alert(_("Error: File too large:") + " " + file.name); + } + + if (err.code == plupload.FILE_EXTENSION_ERROR) { + alert(_("Error: Invalid file extension:") + " " + file.name); + } + + file.hint = message; + $('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message); + } + + if (err.code === plupload.INIT_ERROR) { + setTimeout(function() { + destroy(); + }, 1); + } + }); + + uploader.bind("PostInit", function(up) { + // features are populated only after input components are fully instantiated + if (up.settings.dragdrop && up.features.dragdrop) { + $('#' + id + '_filelist').append('
                      • ' + _("Drag files here.") + '
                      • '); + } + }); + + uploader.init(); + + uploader.bind('StateChanged', function() { + if (uploader.state === plupload.STARTED) { + $('li.plupload_delete a,div.plupload_buttons', target).hide(); + $('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block'); + $('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files'); + + if (settings.multiple_queues) { + $('span.plupload_total_status,span.plupload_total_file_size', target).show(); + } + } else { + updateList(); + $('a.plupload_stop,div.plupload_progress', target).hide(); + $('a.plupload_delete', target).css('display', 'block'); + + if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) { + $(".plupload_buttons,.plupload_upload_status", target).css("display", "inline"); + $(".plupload_start", target).addClass("plupload_disabled"); + $('span.plupload_total_status,span.plupload_total_file_size', target).hide(); + } + } + }); + + uploader.bind('FilesAdded', updateList); + + uploader.bind('FilesRemoved', function() { + // since the whole file list is redrawn for every change in the queue + // we need to scroll back to the file removal point to avoid annoying + // scrolling to the bottom bug (see #926) + var scrollTop = $('#' + id + '_filelist').scrollTop(); + updateList(); + $('#' + id + '_filelist').scrollTop(scrollTop); + }); + + uploader.bind('FileUploaded', function(up, file) { + handleStatus(file); + }); + + uploader.bind("UploadProgress", function(up, file) { + // Set file specific progress + $('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%'); + + handleStatus(file); + updateTotalProgress(); + }); + + // Call setup function + if (settings.setup) { + settings.setup(uploader); + } + }); + + return this; + } else { + // Get uploader instance for specified element + return uploaders[$(this[0]).attr('id')]; + } + }; +})(jQuery, mOxie); \ No newline at end of file diff --git a/lib/scripts/uploader/moxie.js b/lib/scripts/uploader/moxie.js new file mode 100644 index 0000000..afd0aec --- /dev/null +++ b/lib/scripts/uploader/moxie.js @@ -0,0 +1,10684 @@ +/** + * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill + * v1.2.0 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2014-01-16 + */ +/** + * Compiled inline version. (Library mode) + */ + +/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ +/*globals $code */ + +(function(exports, undefined) { + "use strict"; + + var modules = {}; + + function require(ids, callback) { + var module, defs = []; + + for (var i = 0; i < ids.length; ++i) { + module = modules[ids[i]] || resolve(ids[i]); + if (!module) { + throw 'module definition dependecy not found: ' + ids[i]; + } + + defs.push(module); + } + + callback.apply(null, defs); + } + + function define(id, dependencies, definition) { + if (typeof id !== 'string') { + throw 'invalid module definition, module id must be defined and be a string'; + } + + if (dependencies === undefined) { + throw 'invalid module definition, dependencies must be specified'; + } + + if (definition === undefined) { + throw 'invalid module definition, definition function must be specified'; + } + + require(dependencies, function() { + modules[id] = definition.apply(null, arguments); + }); + } + + function defined(id) { + return !!modules[id]; + } + + function resolve(id) { + var target = exports; + var fragments = id.split(/[.\/]/); + + for (var fi = 0; fi < fragments.length; ++fi) { + if (!target[fragments[fi]]) { + return; + } + + target = target[fragments[fi]]; + } + + return target; + } + + function expose(ids) { + for (var i = 0; i < ids.length; i++) { + var target = exports; + var id = ids[i]; + var fragments = id.split(/[.\/]/); + + for (var fi = 0; fi < fragments.length - 1; ++fi) { + if (target[fragments[fi]] === undefined) { + target[fragments[fi]] = {}; + } + + target = target[fragments[fi]]; + } + + target[fragments[fragments.length - 1]] = modules[id]; + } + } + +// Included from: src/javascript/core/utils/Basic.js + +/** + * Basic.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Basic', [], function() { + /** + Gets the true type of the built-in object (better version of typeof). + @author Angus Croll (http://javascriptweblog.wordpress.com/) + + @method typeOf + @for Utils + @static + @param {Object} o Object to check. + @return {String} Object [[Class]] + */ + var typeOf = function(o) { + var undef; + + if (o === undef) { + return 'undefined'; + } else if (o === null) { + return 'null'; + } else if (o.nodeType) { + return 'node'; + } + + // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8 + return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); + }; + + /** + Extends the specified object with another object. + + @method extend + @static + @param {Object} target Object to extend. + @param {Object} [obj]* Multiple objects to extend with. + @return {Object} Same as target, the extended object. + */ + var extend = function(target) { + var undef; + + each(arguments, function(arg, i) { + if (i > 0) { + each(arg, function(value, key) { + if (value !== undef) { + if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) { + extend(target[key], value); + } else { + target[key] = value; + } + } + }); + } + }); + return target; + }; + + /** + Executes the callback function for each item in array/object. If you return false in the + callback it will break the loop. + + @method each + @static + @param {Object} obj Object to iterate. + @param {function} callback Callback function to execute for each item. + */ + var each = function(obj, callback) { + var length, key, i, undef; + + if (obj) { + try { + length = obj.length; + } catch(ex) { + length = undef; + } + + if (length === undef) { + // Loop object items + for (key in obj) { + if (obj.hasOwnProperty(key)) { + if (callback(obj[key], key) === false) { + return; + } + } + } + } else { + // Loop array items + for (i = 0; i < length; i++) { + if (callback(obj[i], i) === false) { + return; + } + } + } + } + }; + + /** + Checks if object is empty. + + @method isEmptyObj + @static + @param {Object} o Object to check. + @return {Boolean} + */ + var isEmptyObj = function(obj) { + var prop; + + if (!obj || typeOf(obj) !== 'object') { + return true; + } + + for (prop in obj) { + return false; + } + + return true; + }; + + /** + Recieve an array of functions (usually async) to call in sequence, each function + receives a callback as first argument that it should call, when it completes. Finally, + after everything is complete, main callback is called. Passing truthy value to the + callback as a first argument will interrupt the sequence and invoke main callback + immediately. + + @method inSeries + @static + @param {Array} queue Array of functions to call in sequence + @param {Function} cb Main callback that is called in the end, or in case of erro + */ + var inSeries = function(queue, cb) { + var i = 0, length = queue.length; + + if (typeOf(cb) !== 'function') { + cb = function() {}; + } + + if (!queue || !queue.length) { + cb(); + } + + function callNext(i) { + if (typeOf(queue[i]) === 'function') { + queue[i](function(error) { + /*jshint expr:true */ + ++i < length && !error ? callNext(i) : cb(error); + }); + } + } + callNext(i); + }; + + + /** + Recieve an array of functions (usually async) to call in parallel, each function + receives a callback as first argument that it should call, when it completes. After + everything is complete, main callback is called. Passing truthy value to the + callback as a first argument will interrupt the process and invoke main callback + immediately. + + @method inParallel + @static + @param {Array} queue Array of functions to call in sequence + @param {Function} cb Main callback that is called in the end, or in case of erro + */ + var inParallel = function(queue, cb) { + var count = 0, num = queue.length, cbArgs = new Array(num); + + each(queue, function(fn, i) { + fn(function(error) { + if (error) { + return cb(error); + } + + var args = [].slice.call(arguments); + args.shift(); // strip error - undefined or not + + cbArgs[i] = args; + count++; + + if (count === num) { + cbArgs.unshift(null); + cb.apply(this, cbArgs); + } + }); + }); + }; + + + /** + Find an element in array and return it's index if present, otherwise return -1. + + @method inArray + @static + @param {Mixed} needle Element to find + @param {Array} array + @return {Int} Index of the element, or -1 if not found + */ + var inArray = function(needle, array) { + if (array) { + if (Array.prototype.indexOf) { + return Array.prototype.indexOf.call(array, needle); + } + + for (var i = 0, length = array.length; i < length; i++) { + if (array[i] === needle) { + return i; + } + } + } + return -1; + }; + + + /** + Returns elements of first array if they are not present in second. And false - otherwise. + + @private + @method arrayDiff + @param {Array} needles + @param {Array} array + @return {Array|Boolean} + */ + var arrayDiff = function(needles, array) { + var diff = []; + + if (typeOf(needles) !== 'array') { + needles = [needles]; + } + + if (typeOf(array) !== 'array') { + array = [array]; + } + + for (var i in needles) { + if (inArray(needles[i], array) === -1) { + diff.push(needles[i]); + } + } + return diff.length ? diff : false; + }; + + + /** + Find intersection of two arrays. + + @private + @method arrayIntersect + @param {Array} array1 + @param {Array} array2 + @return {Array} Intersection of two arrays or null if there is none + */ + var arrayIntersect = function(array1, array2) { + var result = []; + each(array1, function(item) { + if (inArray(item, array2) !== -1) { + result.push(item); + } + }); + return result.length ? result : null; + }; + + + /** + Forces anything into an array. + + @method toArray + @static + @param {Object} obj Object with length field. + @return {Array} Array object containing all items. + */ + var toArray = function(obj) { + var i, arr = []; + + for (i = 0; i < obj.length; i++) { + arr[i] = obj[i]; + } + + return arr; + }; + + + /** + Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers. + The only way a user would be able to get the same ID is if the two persons at the same exact milisecond manages + to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique. + It's more probable for the earth to be hit with an ansteriod. Y + + @method guid + @static + @param {String} prefix to prepend (by default 'o' will be prepended). + @method guid + @return {String} Virtually unique id. + */ + var guid = (function() { + var counter = 0; + + return function(prefix) { + var guid = new Date().getTime().toString(32), i; + + for (i = 0; i < 5; i++) { + guid += Math.floor(Math.random() * 65535).toString(32); + } + + return (prefix || 'o_') + guid + (counter++).toString(32); + }; + }()); + + + /** + Trims white spaces around the string + + @method trim + @static + @param {String} str + @return {String} + */ + var trim = function(str) { + if (!str) { + return str; + } + return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, ''); + }; + + + /** + Parses the specified size string into a byte value. For example 10kb becomes 10240. + + @method parseSizeStr + @static + @param {String/Number} size String to parse or number to just pass through. + @return {Number} Size in bytes. + */ + var parseSizeStr = function(size) { + if (typeof(size) !== 'string') { + return size; + } + + var muls = { + t: 1099511627776, + g: 1073741824, + m: 1048576, + k: 1024 + }, + mul; + + size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, '')); + mul = size[2]; + size = +size[1]; + + if (muls.hasOwnProperty(mul)) { + size *= muls[mul]; + } + return size; + }; + + + return { + guid: guid, + typeOf: typeOf, + extend: extend, + each: each, + isEmptyObj: isEmptyObj, + inSeries: inSeries, + inParallel: inParallel, + inArray: inArray, + arrayDiff: arrayDiff, + arrayIntersect: arrayIntersect, + toArray: toArray, + trim: trim, + parseSizeStr: parseSizeStr + }; +}); + +// Included from: src/javascript/core/I18n.js + +/** + * I18n.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/core/I18n", [ + "moxie/core/utils/Basic" +], function(Basic) { + var i18n = {}; + + return { + /** + * Extends the language pack object with new items. + * + * @param {Object} pack Language pack items to add. + * @return {Object} Extended language pack object. + */ + addI18n: function(pack) { + return Basic.extend(i18n, pack); + }, + + /** + * Translates the specified string by checking for the english string in the language pack lookup. + * + * @param {String} str String to look for. + * @return {String} Translated string or the input string if it wasn't found. + */ + translate: function(str) { + return i18n[str] || str; + }, + + /** + * Shortcut for translate function + * + * @param {String} str String to look for. + * @return {String} Translated string or the input string if it wasn't found. + */ + _: function(str) { + return this.translate(str); + }, + + /** + * Pseudo sprintf implementation - simple way to replace tokens with specified values. + * + * @param {String} str String with tokens + * @return {String} String with replaced tokens + */ + sprintf: function(str) { + var args = [].slice.call(arguments, 1); + + return str.replace(/%[a-z]/g, function() { + var value = args.shift(); + return Basic.typeOf(value) !== 'undefined' ? value : ''; + }); + } + }; +}); + +// Included from: src/javascript/core/utils/Mime.js + +/** + * Mime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/core/utils/Mime", [ + "moxie/core/utils/Basic", + "moxie/core/I18n" +], function(Basic, I18n) { + + var mimeData = "" + + "application/msword,doc dot," + + "application/pdf,pdf," + + "application/pgp-signature,pgp," + + "application/postscript,ps ai eps," + + "application/rtf,rtf," + + "application/vnd.ms-excel,xls xlb," + + "application/vnd.ms-powerpoint,ppt pps pot," + + "application/zip,zip," + + "application/x-shockwave-flash,swf swfl," + + "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," + + "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," + + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," + + "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," + + "application/vnd.openxmlformats-officedocument.presentationml.template,potx," + + "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," + + "application/x-javascript,js," + + "application/json,json," + + "audio/mpeg,mp3 mpga mpega mp2," + + "audio/x-wav,wav," + + "audio/x-m4a,m4a," + + "audio/ogg,oga ogg," + + "audio/aiff,aiff aif," + + "audio/flac,flac," + + "audio/aac,aac," + + "audio/ac3,ac3," + + "audio/x-ms-wma,wma," + + "image/bmp,bmp," + + "image/gif,gif," + + "image/jpeg,jpg jpeg jpe," + + "image/photoshop,psd," + + "image/png,png," + + "image/svg+xml,svg svgz," + + "image/tiff,tiff tif," + + "text/plain,asc txt text diff log," + + "text/html,htm html xhtml," + + "text/css,css," + + "text/csv,csv," + + "text/rtf,rtf," + + "video/mpeg,mpeg mpg mpe m2v," + + "video/quicktime,qt mov," + + "video/mp4,mp4," + + "video/x-m4v,m4v," + + "video/x-flv,flv," + + "video/x-ms-wmv,wmv," + + "video/avi,avi," + + "video/webm,webm," + + "video/3gpp,3gpp 3gp," + + "video/3gpp2,3g2," + + "video/vnd.rn-realvideo,rv," + + "video/ogg,ogv," + + "video/x-matroska,mkv," + + "application/vnd.oasis.opendocument.formula-template,otf," + + "application/octet-stream,exe"; + + + var Mime = { + + mimes: {}, + + extensions: {}, + + // Parses the default mime types string into a mimes and extensions lookup maps + addMimeType: function (mimeData) { + var items = mimeData.split(/,/), i, ii, ext; + + for (i = 0; i < items.length; i += 2) { + ext = items[i + 1].split(/ /); + + // extension to mime lookup + for (ii = 0; ii < ext.length; ii++) { + this.mimes[ext[ii]] = items[i]; + } + // mime to extension lookup + this.extensions[items[i]] = ext; + } + }, + + + extList2mimes: function (filters, addMissingExtensions) { + var self = this, ext, i, ii, type, mimes = []; + + // convert extensions to mime types list + for (i = 0; i < filters.length; i++) { + ext = filters[i].extensions.split(/\s*,\s*/); + + for (ii = 0; ii < ext.length; ii++) { + + // if there's an asterisk in the list, then accept attribute is not required + if (ext[ii] === '*') { + return []; + } + + type = self.mimes[ext[ii]]; + if (!type) { + if (addMissingExtensions && /^\w+$/.test(ext[ii])) { + mimes.push('.' + ext[ii]); + } else { + return []; // accept all + } + } else if (Basic.inArray(type, mimes) === -1) { + mimes.push(type); + } + } + } + return mimes; + }, + + + mimes2exts: function(mimes) { + var self = this, exts = []; + + Basic.each(mimes, function(mime) { + if (mime === '*') { + exts = []; + return false; + } + + // check if this thing looks like mime type + var m = mime.match(/^(\w+)\/(\*|\w+)$/); + if (m) { + if (m[2] === '*') { + // wildcard mime type detected + Basic.each(self.extensions, function(arr, mime) { + if ((new RegExp('^' + m[1] + '/')).test(mime)) { + [].push.apply(exts, self.extensions[mime]); + } + }); + } else if (self.extensions[mime]) { + [].push.apply(exts, self.extensions[mime]); + } + } + }); + return exts; + }, + + + mimes2extList: function(mimes) { + var accept = [], exts = []; + + if (Basic.typeOf(mimes) === 'string') { + mimes = Basic.trim(mimes).split(/\s*,\s*/); + } + + exts = this.mimes2exts(mimes); + + accept.push({ + title: I18n.translate('Files'), + extensions: exts.length ? exts.join(',') : '*' + }); + + // save original mimes string + accept.mimes = mimes; + + return accept; + }, + + + getFileExtension: function(fileName) { + var matches = fileName && fileName.match(/\.([^.]+)$/); + if (matches) { + return matches[1].toLowerCase(); + } + return ''; + }, + + getFileMime: function(fileName) { + return this.mimes[this.getFileExtension(fileName)] || ''; + } + }; + + Mime.addMimeType(mimeData); + + return Mime; +}); + +// Included from: src/javascript/core/utils/Env.js + +/** + * Env.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/core/utils/Env", [ + "moxie/core/utils/Basic" +], function(Basic) { + + // UAParser.js v0.6.2 + // Lightweight JavaScript-based User-Agent string parser + // https://github.com/faisalman/ua-parser-js + // + // Copyright © 2012-2013 Faisalman + // Dual licensed under GPLv2 & MIT + + var UAParser = (function (undefined) { + + ////////////// + // Constants + ///////////// + + + var EMPTY = '', + UNKNOWN = '?', + FUNC_TYPE = 'function', + UNDEF_TYPE = 'undefined', + OBJ_TYPE = 'object', + MAJOR = 'major', + MODEL = 'model', + NAME = 'name', + TYPE = 'type', + VENDOR = 'vendor', + VERSION = 'version', + ARCHITECTURE= 'architecture', + CONSOLE = 'console', + MOBILE = 'mobile', + TABLET = 'tablet'; + + + /////////// + // Helper + ////////// + + + var util = { + has : function (str1, str2) { + return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; + }, + lowerize : function (str) { + return str.toLowerCase(); + } + }; + + + /////////////// + // Map helper + ////////////// + + + var mapper = { + + rgx : function () { + + // loop through all regexes maps + for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { + + var regex = args[i], // even sequence (0,2,4,..) + props = args[i + 1]; // odd sequence (1,3,5,..) + + // construct object barebones + if (typeof(result) === UNDEF_TYPE) { + result = {}; + for (p in props) { + q = props[p]; + if (typeof(q) === OBJ_TYPE) { + result[q[0]] = undefined; + } else { + result[q] = undefined; + } + } + } + + // try matching uastring with regexes + for (j = k = 0; j < regex.length; j++) { + matches = regex[j].exec(this.getUA()); + if (!!matches) { + for (p = 0; p < props.length; p++) { + match = matches[++k]; + q = props[p]; + // check if given property is actually array + if (typeof(q) === OBJ_TYPE && q.length > 0) { + if (q.length == 2) { + if (typeof(q[1]) == FUNC_TYPE) { + // assign modified match + result[q[0]] = q[1].call(this, match); + } else { + // assign given value, ignore regex match + result[q[0]] = q[1]; + } + } else if (q.length == 3) { + // check whether function or regex + if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { + // call function (usually string mapper) + result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; + } else { + // sanitize match using given regex + result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; + } + } else if (q.length == 4) { + result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; + } + } else { + result[q] = match ? match : undefined; + } + } + break; + } + } + + if(!!matches) break; // break the loop immediately if match found + } + return result; + }, + + str : function (str, map) { + + for (var i in map) { + // check if array + if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { + for (var j = 0; j < map[i].length; j++) { + if (util.has(map[i][j], str)) { + return (i === UNKNOWN) ? undefined : i; + } + } + } else if (util.has(map[i], str)) { + return (i === UNKNOWN) ? undefined : i; + } + } + return str; + } + }; + + + /////////////// + // String map + ////////////// + + + var maps = { + + browser : { + oldsafari : { + major : { + '1' : ['/8', '/1', '/3'], + '2' : '/4', + '?' : '/' + }, + version : { + '1.0' : '/8', + '1.2' : '/1', + '1.3' : '/3', + '2.0' : '/412', + '2.0.2' : '/416', + '2.0.3' : '/417', + '2.0.4' : '/419', + '?' : '/' + } + } + }, + + device : { + sprint : { + model : { + 'Evo Shift 4G' : '7373KT' + }, + vendor : { + 'HTC' : 'APA', + 'Sprint' : 'Sprint' + } + } + }, + + os : { + windows : { + version : { + 'ME' : '4.90', + 'NT 3.11' : 'NT3.51', + 'NT 4.0' : 'NT4.0', + '2000' : 'NT 5.0', + 'XP' : ['NT 5.1', 'NT 5.2'], + 'Vista' : 'NT 6.0', + '7' : 'NT 6.1', + '8' : 'NT 6.2', + '8.1' : 'NT 6.3', + 'RT' : 'ARM' + } + } + } + }; + + + ////////////// + // Regex map + ///////////// + + + var regexes = { + + browser : [[ + + // Presto based + /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini + /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i, // Opera Mobi/Tablet + /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera > 9.80 + /(opera)[\/\s]+((\d+)?[\w\.]+)/i // Opera < 9.80 + + ], [NAME, VERSION, MAJOR], [ + + /\s(opr)\/((\d+)?[\w\.]+)/i // Opera Webkit + ], [[NAME, 'Opera'], VERSION, MAJOR], [ + + // Mixed + /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle + /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i, + // Lunascape/Maxthon/Netfront/Jasmine/Blazer + + // Trident based + /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i, + // Avant/IEMobile/SlimBrowser/Baidu + /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer + + // Webkit/KHTML based + /(rekonq)((?:\/)[\w\.]+)*/i, // Rekonq + /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron)\/((\d+)?[\w\.-]+)/i + // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron + ], [NAME, VERSION, MAJOR], [ + + /(trident).+rv[:\s]((\d+)?[\w\.]+).+like\sgecko/i // IE11 + ], [[NAME, 'IE'], VERSION, MAJOR], [ + + /(yabrowser)\/((\d+)?[\w\.]+)/i // Yandex + ], [[NAME, 'Yandex'], VERSION, MAJOR], [ + + /(comodo_dragon)\/((\d+)?[\w\.]+)/i // Comodo Dragon + ], [[NAME, /_/g, ' '], VERSION, MAJOR], [ + + /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i + // Chrome/OmniWeb/Arora/Tizen/Nokia + ], [NAME, VERSION, MAJOR], [ + + /(dolfin)\/((\d+)?[\w\.]+)/i // Dolphin + ], [[NAME, 'Dolphin'], VERSION, MAJOR], [ + + /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i // Chrome for Android/iOS + ], [[NAME, 'Chrome'], VERSION, MAJOR], [ + + /((?:android.+))version\/((\d+)?[\w\.]+)\smobile\ssafari/i // Android Browser + ], [[NAME, 'Android Browser'], VERSION, MAJOR], [ + + /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari + ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [ + + /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile + ], [VERSION, MAJOR, NAME], [ + + /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i // Safari < 3.0 + ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [ + + /(konqueror)\/((\d+)?[\w\.]+)/i, // Konqueror + /(webkit|khtml)\/((\d+)?[\w\.]+)/i + ], [NAME, VERSION, MAJOR], [ + + // Gecko based + /(navigator|netscape)\/((\d+)?[\w\.-]+)/i // Netscape + ], [[NAME, 'Netscape'], VERSION, MAJOR], [ + /(swiftfox)/i, // Swiftfox + /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i, + // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror + /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i, + // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix + /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla + + // Other + /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|qqbrowser)[\/\s]?((\d+)?[\w\.]+)/i, + // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/QQBrowser + /(links)\s\(((\d+)?[\w\.]+)/i, // Links + /(gobrowser)\/?((\d+)?[\w\.]+)*/i, // GoBrowser + /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, // ICE Browser + /(mosaic)[\/\s]((\d+)?[\w\.]+)/i // Mosaic + ], [NAME, VERSION, MAJOR] + ], + + engine : [[ + + /(presto)\/([\w\.]+)/i, // Presto + /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m + /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links + /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab + ], [NAME, VERSION], [ + + /rv\:([\w\.]+).*(gecko)/i // Gecko + ], [VERSION, NAME] + ], + + os : [[ + + // Windows based + /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT + /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i + ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ + /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i + ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ + + // Mobile/Embedded OS + /\((bb)(10);/i // BlackBerry 10 + ], [[NAME, 'BlackBerry'], VERSION], [ + /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry + /(tizen)\/([\w\.]+)/i, // Tizen + /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i + // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo + ], [NAME, VERSION], [ + /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian + ], [[NAME, 'Symbian'], VERSION],[ + /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS + ], [[NAME, 'Firefox OS'], VERSION], [ + + // Console + /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation + + // GNU/Linux based + /(mint)[\/\s\(]?(\w+)*/i, // Mint + /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, + // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware + // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk + /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux + /(gnu)\s?([\w\.]+)*/i // GNU + ], [NAME, VERSION], [ + + /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS + ], [[NAME, 'Chromium OS'], VERSION],[ + + // Solaris + /(sunos)\s?([\w\.]+\d)*/i // Solaris + ], [[NAME, 'Solaris'], VERSION], [ + + // BSD based + /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly + ], [NAME, VERSION],[ + + /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS + ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ + + /(mac\sos\sx)\s?([\w\s\.]+\w)*/i // Mac OS + ], [NAME, [VERSION, /_/g, '.']], [ + + // Other + /(haiku)\s(\w+)/i, // Haiku + /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX + /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i, + // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS + /(unix)\s?([\w\.]+)*/i // UNIX + ], [NAME, VERSION] + ] + }; + + + ///////////////// + // Constructor + //////////////// + + + var UAParser = function (uastring) { + + var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); + + this.getBrowser = function () { + return mapper.rgx.apply(this, regexes.browser); + }; + this.getEngine = function () { + return mapper.rgx.apply(this, regexes.engine); + }; + this.getOS = function () { + return mapper.rgx.apply(this, regexes.os); + }; + this.getResult = function() { + return { + ua : this.getUA(), + browser : this.getBrowser(), + engine : this.getEngine(), + os : this.getOS() + }; + }; + this.getUA = function () { + return ua; + }; + this.setUA = function (uastring) { + ua = uastring; + return this; + }; + this.setUA(ua); + }; + + return new UAParser().getResult(); + })(); + + + function version_compare(v1, v2, operator) { + // From: http://phpjs.org/functions + // + original by: Philippe Jausions (http://pear.php.net/user/jausions) + // + original by: Aidan Lister (http://aidanlister.com/) + // + reimplemented by: Kankrelune (http://www.webfaktory.info/) + // + improved by: Brett Zamir (http://brett-zamir.me) + // + improved by: Scott Baker + // + improved by: Theriault + // * example 1: version_compare('8.2.5rc', '8.2.5a'); + // * returns 1: 1 + // * example 2: version_compare('8.2.50', '8.2.52', '<'); + // * returns 2: true + // * example 3: version_compare('5.3.0-dev', '5.3.0'); + // * returns 3: -1 + // * example 4: version_compare('4.1.0.52','4.01.0.51'); + // * returns 4: 1 + + // Important: compare must be initialized at 0. + var i = 0, + x = 0, + compare = 0, + // vm maps textual PHP versions to negatives so they're less than 0. + // PHP currently defines these as CASE-SENSITIVE. It is important to + // leave these as negatives so that they can come before numerical versions + // and as if no letters were there to begin with. + // (1alpha is < 1 and < 1.1 but > 1dev1) + // If a non-numerical value can't be mapped to this table, it receives + // -7 as its value. + vm = { + 'dev': -6, + 'alpha': -5, + 'a': -5, + 'beta': -4, + 'b': -4, + 'RC': -3, + 'rc': -3, + '#': -2, + 'p': 1, + 'pl': 1 + }, + // This function will be called to prepare each version argument. + // It replaces every _, -, and + with a dot. + // It surrounds any nonsequence of numbers/dots with dots. + // It replaces sequences of dots with a single dot. + // version_compare('4..0', '4.0') == 0 + // Important: A string of 0 length needs to be converted into a value + // even less than an unexisting value in vm (-7), hence [-8]. + // It's also important to not strip spaces because of this. + // version_compare('', ' ') == 1 + prepVersion = function (v) { + v = ('' + v).replace(/[_\-+]/g, '.'); + v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); + return (!v.length ? [-8] : v.split('.')); + }, + // This converts a version component to a number. + // Empty component becomes 0. + // Non-numerical component becomes a negative number. + // Numerical component becomes itself as an integer. + numVersion = function (v) { + return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); + }; + + v1 = prepVersion(v1); + v2 = prepVersion(v2); + x = Math.max(v1.length, v2.length); + for (i = 0; i < x; i++) { + if (v1[i] == v2[i]) { + continue; + } + v1[i] = numVersion(v1[i]); + v2[i] = numVersion(v2[i]); + if (v1[i] < v2[i]) { + compare = -1; + break; + } else if (v1[i] > v2[i]) { + compare = 1; + break; + } + } + if (!operator) { + return compare; + } + + // Important: operator is CASE-SENSITIVE. + // "No operator" seems to be treated as "<." + // Any other values seem to make the function return null. + switch (operator) { + case '>': + case 'gt': + return (compare > 0); + case '>=': + case 'ge': + return (compare >= 0); + case '<=': + case 'le': + return (compare <= 0); + case '==': + case '=': + case 'eq': + return (compare === 0); + case '<>': + case '!=': + case 'ne': + return (compare !== 0); + case '': + case '<': + case 'lt': + return (compare < 0); + default: + return null; + } + } + + + var can = (function() { + var caps = { + define_property: (function() { + /* // currently too much extra code required, not exactly worth it + try { // as of IE8, getters/setters are supported only on DOM elements + var obj = {}; + if (Object.defineProperty) { + Object.defineProperty(obj, 'prop', { + enumerable: true, + configurable: true + }); + return true; + } + } catch(ex) {} + + if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { + return true; + }*/ + return false; + }()), + + create_canvas: (function() { + // On the S60 and BB Storm, getContext exists, but always returns undefined + // so we actually have to call getContext() to verify + // github.com/Modernizr/Modernizr/issues/issue/97/ + var el = document.createElement('canvas'); + return !!(el.getContext && el.getContext('2d')); + }()), + + return_response_type: function(responseType) { + try { + if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) { + return true; + } else if (window.XMLHttpRequest) { + var xhr = new XMLHttpRequest(); + xhr.open('get', '/'); // otherwise Gecko throws an exception + if ('responseType' in xhr) { + xhr.responseType = responseType; + // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?) + if (xhr.responseType !== responseType) { + return false; + } + return true; + } + } + } catch (ex) {} + return false; + }, + + // ideas for this heavily come from Modernizr (http://modernizr.com/) + use_data_uri: (function() { + var du = new Image(); + + du.onload = function() { + caps.use_data_uri = (du.width === 1 && du.height === 1); + }; + + setTimeout(function() { + du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; + }, 1); + return false; + }()), + + use_data_uri_over32kb: function() { // IE8 + return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9); + }, + + use_data_uri_of: function(bytes) { + return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); + }, + + use_fileinput: function() { + var el = document.createElement('input'); + el.setAttribute('type', 'file'); + return !el.disabled; + } + }; + + return function(cap) { + var args = [].slice.call(arguments); + args.shift(); // shift of cap + return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap]; + }; + }()); + + + var Env = { + can: can, + + browser: UAParser.browser.name, + version: parseFloat(UAParser.browser.major), + os: UAParser.os.name, // everybody intuitively types it in a lowercase for some reason + osVersion: UAParser.os.version, + + verComp: version_compare, + + swf_url: "../flash/Moxie.swf", + xap_url: "../silverlight/Moxie.xap", + global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent" + }; + + // for backward compatibility + // @deprecated Use `Env.os` instead + Env.OS = Env.os; + + return Env; +}); + +// Included from: src/javascript/core/utils/Dom.js + +/** + * Dom.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) { + + /** + Get DOM Element by it's id. + + @method get + @for Utils + @param {String} id Identifier of the DOM Element + @return {DOMElement} + */ + var get = function(id) { + if (typeof id !== 'string') { + return id; + } + return document.getElementById(id); + }; + + /** + Checks if specified DOM element has specified class. + + @method hasClass + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Class name + */ + var hasClass = function(obj, name) { + if (!obj.className) { + return false; + } + + var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); + return regExp.test(obj.className); + }; + + /** + Adds specified className to specified DOM element. + + @method addClass + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Class name + */ + var addClass = function(obj, name) { + if (!hasClass(obj, name)) { + obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name; + } + }; + + /** + Removes specified className from specified DOM element. + + @method removeClass + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Class name + */ + var removeClass = function(obj, name) { + if (obj.className) { + var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); + obj.className = obj.className.replace(regExp, function($0, $1, $2) { + return $1 === ' ' && $2 === ' ' ? ' ' : ''; + }); + } + }; + + /** + Returns a given computed style of a DOM element. + + @method getStyle + @static + @param {Object} obj DOM element like object. + @param {String} name Style you want to get from the DOM element + */ + var getStyle = function(obj, name) { + if (obj.currentStyle) { + return obj.currentStyle[name]; + } else if (window.getComputedStyle) { + return window.getComputedStyle(obj, null)[name]; + } + }; + + + /** + Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. + + @method getPos + @static + @param {Element} node HTML element or element id to get x, y position from. + @param {Element} root Optional root element to stop calculations at. + @return {object} Absolute position of the specified element object with x, y fields. + */ + var getPos = function(node, root) { + var x = 0, y = 0, parent, doc = document, nodeRect, rootRect; + + node = node; + root = root || doc.body; + + // Returns the x, y cordinate for an element on IE 6 and IE 7 + function getIEPos(node) { + var bodyElm, rect, x = 0, y = 0; + + if (node) { + rect = node.getBoundingClientRect(); + bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body; + x = rect.left + bodyElm.scrollLeft; + y = rect.top + bodyElm.scrollTop; + } + + return { + x : x, + y : y + }; + } + + // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode + if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) { + nodeRect = getIEPos(node); + rootRect = getIEPos(root); + + return { + x : nodeRect.x - rootRect.x, + y : nodeRect.y - rootRect.y + }; + } + + parent = node; + while (parent && parent != root && parent.nodeType) { + x += parent.offsetLeft || 0; + y += parent.offsetTop || 0; + parent = parent.offsetParent; + } + + parent = node.parentNode; + while (parent && parent != root && parent.nodeType) { + x -= parent.scrollLeft || 0; + y -= parent.scrollTop || 0; + parent = parent.parentNode; + } + + return { + x : x, + y : y + }; + }; + + /** + Returns the size of the specified node in pixels. + + @method getSize + @static + @param {Node} node Node to get the size of. + @return {Object} Object with a w and h property. + */ + var getSize = function(node) { + return { + w : node.offsetWidth || node.clientWidth, + h : node.offsetHeight || node.clientHeight + }; + }; + + return { + get: get, + hasClass: hasClass, + addClass: addClass, + removeClass: removeClass, + getStyle: getStyle, + getPos: getPos, + getSize: getSize + }; +}); + +// Included from: src/javascript/core/Exceptions.js + +/** + * Exceptions.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/Exceptions', [ + 'moxie/core/utils/Basic' +], function(Basic) { + function _findKey(obj, value) { + var key; + for (key in obj) { + if (obj[key] === value) { + return key; + } + } + return null; + } + + return { + RuntimeError: (function() { + var namecodes = { + NOT_INIT_ERR: 1, + NOT_SUPPORTED_ERR: 9, + JS_ERR: 4 + }; + + function RuntimeError(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": RuntimeError " + this.code; + } + + Basic.extend(RuntimeError, namecodes); + RuntimeError.prototype = Error.prototype; + return RuntimeError; + }()), + + OperationNotAllowedException: (function() { + + function OperationNotAllowedException(code) { + this.code = code; + this.name = 'OperationNotAllowedException'; + } + + Basic.extend(OperationNotAllowedException, { + NOT_ALLOWED_ERR: 1 + }); + + OperationNotAllowedException.prototype = Error.prototype; + + return OperationNotAllowedException; + }()), + + ImageError: (function() { + var namecodes = { + WRONG_FORMAT: 1, + MAX_RESOLUTION_ERR: 2 + }; + + function ImageError(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": ImageError " + this.code; + } + + Basic.extend(ImageError, namecodes); + ImageError.prototype = Error.prototype; + + return ImageError; + }()), + + FileException: (function() { + var namecodes = { + NOT_FOUND_ERR: 1, + SECURITY_ERR: 2, + ABORT_ERR: 3, + NOT_READABLE_ERR: 4, + ENCODING_ERR: 5, + NO_MODIFICATION_ALLOWED_ERR: 6, + INVALID_STATE_ERR: 7, + SYNTAX_ERR: 8 + }; + + function FileException(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": FileException " + this.code; + } + + Basic.extend(FileException, namecodes); + FileException.prototype = Error.prototype; + return FileException; + }()), + + DOMException: (function() { + var namecodes = { + INDEX_SIZE_ERR: 1, + DOMSTRING_SIZE_ERR: 2, + HIERARCHY_REQUEST_ERR: 3, + WRONG_DOCUMENT_ERR: 4, + INVALID_CHARACTER_ERR: 5, + NO_DATA_ALLOWED_ERR: 6, + NO_MODIFICATION_ALLOWED_ERR: 7, + NOT_FOUND_ERR: 8, + NOT_SUPPORTED_ERR: 9, + INUSE_ATTRIBUTE_ERR: 10, + INVALID_STATE_ERR: 11, + SYNTAX_ERR: 12, + INVALID_MODIFICATION_ERR: 13, + NAMESPACE_ERR: 14, + INVALID_ACCESS_ERR: 15, + VALIDATION_ERR: 16, + TYPE_MISMATCH_ERR: 17, + SECURITY_ERR: 18, + NETWORK_ERR: 19, + ABORT_ERR: 20, + URL_MISMATCH_ERR: 21, + QUOTA_EXCEEDED_ERR: 22, + TIMEOUT_ERR: 23, + INVALID_NODE_TYPE_ERR: 24, + DATA_CLONE_ERR: 25 + }; + + function DOMException(code) { + this.code = code; + this.name = _findKey(namecodes, code); + this.message = this.name + ": DOMException " + this.code; + } + + Basic.extend(DOMException, namecodes); + DOMException.prototype = Error.prototype; + return DOMException; + }()), + + EventException: (function() { + function EventException(code) { + this.code = code; + this.name = 'EventException'; + } + + Basic.extend(EventException, { + UNSPECIFIED_EVENT_TYPE_ERR: 0 + }); + + EventException.prototype = Error.prototype; + + return EventException; + }()) + }; +}); + +// Included from: src/javascript/core/EventTarget.js + +/** + * EventTarget.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/EventTarget', [ + 'moxie/core/Exceptions', + 'moxie/core/utils/Basic' +], function(x, Basic) { + /** + Parent object for all event dispatching components and objects + + @class EventTarget + @constructor EventTarget + */ + function EventTarget() { + // hash of event listeners by object uid + var eventpool = {}; + + Basic.extend(this, { + + /** + Unique id of the event dispatcher, usually overriden by children + + @property uid + @type String + */ + uid: null, + + /** + Can be called from within a child in order to acquire uniqie id in automated manner + + @method init + */ + init: function() { + if (!this.uid) { + this.uid = Basic.guid('uid_'); + } + }, + + /** + Register a handler to a specific event dispatched by the object + + @method addEventListener + @param {String} type Type or basically a name of the event to subscribe to + @param {Function} fn Callback function that will be called when event happens + @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first + @param {Object} [scope=this] A scope to invoke event handler in + */ + addEventListener: function(type, fn, priority, scope) { + var self = this, list; + + type = Basic.trim(type); + + if (/\s/.test(type)) { + // multiple event types were passed for one handler + Basic.each(type.split(/\s+/), function(type) { + self.addEventListener(type, fn, priority, scope); + }); + return; + } + + type = type.toLowerCase(); + priority = parseInt(priority, 10) || 0; + + list = eventpool[this.uid] && eventpool[this.uid][type] || []; + list.push({fn : fn, priority : priority, scope : scope || this}); + + if (!eventpool[this.uid]) { + eventpool[this.uid] = {}; + } + eventpool[this.uid][type] = list; + }, + + /** + Check if any handlers were registered to the specified event + + @method hasEventListener + @param {String} type Type or basically a name of the event to check + @return {Mixed} Returns a handler if it was found and false, if - not + */ + hasEventListener: function(type) { + return type ? !!(eventpool[this.uid] && eventpool[this.uid][type]) : !!eventpool[this.uid]; + }, + + /** + Unregister the handler from the event, or if former was not specified - unregister all handlers + + @method removeEventListener + @param {String} type Type or basically a name of the event + @param {Function} [fn] Handler to unregister + */ + removeEventListener: function(type, fn) { + type = type.toLowerCase(); + + var list = eventpool[this.uid] && eventpool[this.uid][type], i; + + if (list) { + if (fn) { + for (i = list.length - 1; i >= 0; i--) { + if (list[i].fn === fn) { + list.splice(i, 1); + break; + } + } + } else { + list = []; + } + + // delete event list if it has become empty + if (!list.length) { + delete eventpool[this.uid][type]; + + // and object specific entry in a hash if it has no more listeners attached + if (Basic.isEmptyObj(eventpool[this.uid])) { + delete eventpool[this.uid]; + } + } + } + }, + + /** + Remove all event handlers from the object + + @method removeAllEventListeners + */ + removeAllEventListeners: function() { + if (eventpool[this.uid]) { + delete eventpool[this.uid]; + } + }, + + /** + Dispatch the event + + @method dispatchEvent + @param {String/Object} Type of event or event object to dispatch + @param {Mixed} [...] Variable number of arguments to be passed to a handlers + @return {Boolean} true by default and false if any handler returned false + */ + dispatchEvent: function(type) { + var uid, list, args, tmpEvt, evt = {}, result = true, undef; + + if (Basic.typeOf(type) !== 'string') { + // we can't use original object directly (because of Silverlight) + tmpEvt = type; + + if (Basic.typeOf(tmpEvt.type) === 'string') { + type = tmpEvt.type; + + if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event + evt.total = tmpEvt.total; + evt.loaded = tmpEvt.loaded; + } + evt.async = tmpEvt.async || false; + } else { + throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR); + } + } + + // check if event is meant to be dispatched on an object having specific uid + if (type.indexOf('::') !== -1) { + (function(arr) { + uid = arr[0]; + type = arr[1]; + }(type.split('::'))); + } else { + uid = this.uid; + } + + type = type.toLowerCase(); + + list = eventpool[uid] && eventpool[uid][type]; + + if (list) { + // sort event list by prority + list.sort(function(a, b) { return b.priority - a.priority; }); + + args = [].slice.call(arguments); + + // first argument will be pseudo-event object + args.shift(); + evt.type = type; + args.unshift(evt); + + // Dispatch event to all listeners + var queue = []; + Basic.each(list, function(handler) { + // explicitly set the target, otherwise events fired from shims do not get it + args[0].target = handler.scope; + // if event is marked as async, detach the handler + if (evt.async) { + queue.push(function(cb) { + setTimeout(function() { + cb(handler.fn.apply(handler.scope, args) === false); + }, 1); + }); + } else { + queue.push(function(cb) { + cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation + }); + } + }); + if (queue.length) { + Basic.inSeries(queue, function(err) { + result = !err; + }); + } + } + return result; + }, + + /** + Alias for addEventListener + + @method bind + @protected + */ + bind: function() { + this.addEventListener.apply(this, arguments); + }, + + /** + Alias for removeEventListener + + @method unbind + @protected + */ + unbind: function() { + this.removeEventListener.apply(this, arguments); + }, + + /** + Alias for removeAllEventListeners + + @method unbindAll + @protected + */ + unbindAll: function() { + this.removeAllEventListeners.apply(this, arguments); + }, + + /** + Alias for dispatchEvent + + @method trigger + @protected + */ + trigger: function() { + return this.dispatchEvent.apply(this, arguments); + }, + + + /** + Converts properties of on[event] type to corresponding event handlers, + is used to avoid extra hassle around the process of calling them back + + @method convertEventPropsToHandlers + @private + */ + convertEventPropsToHandlers: function(handlers) { + var h; + + if (Basic.typeOf(handlers) !== 'array') { + handlers = [handlers]; + } + + for (var i = 0; i < handlers.length; i++) { + h = 'on' + handlers[i]; + + if (Basic.typeOf(this[h]) === 'function') { + this.addEventListener(handlers[i], this[h]); + } else if (Basic.typeOf(this[h]) === 'undefined') { + this[h] = null; // object must have defined event properties, even if it doesn't make use of them + } + } + } + + }); + } + + EventTarget.instance = new EventTarget(); + + return EventTarget; +}); + +// Included from: src/javascript/core/utils/Encode.js + +/** + * Encode.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Encode', [], function() { + + /** + Encode string with UTF-8 + + @method utf8_encode + @for Utils + @static + @param {String} str String to encode + @return {String} UTF-8 encoded string + */ + var utf8_encode = function(str) { + return unescape(encodeURIComponent(str)); + }; + + /** + Decode UTF-8 encoded string + + @method utf8_decode + @static + @param {String} str String to decode + @return {String} Decoded string + */ + var utf8_decode = function(str_data) { + return decodeURIComponent(escape(str_data)); + }; + + /** + Decode Base64 encoded string (uses browser's default method if available), + from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js + + @method atob + @static + @param {String} data String to decode + @return {String} Decoded string + */ + var atob = function(data, utf8) { + if (typeof(window.atob) === 'function') { + return utf8 ? utf8_decode(window.atob(data)) : window.atob(data); + } + + // http://kevin.vanzonneveld.net + // + original by: Tyler Akins (http://rumkin.com) + // + improved by: Thunder.m + // + input by: Aman Gupta + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + bugfixed by: Pellentesque Malesuada + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Brett Zamir (http://brett-zamir.me) + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); + // * returns 1: 'Kevin van Zonneveld' + // mozilla has this native + // - but breaks in 2.0.0.12! + //if (typeof this.window.atob == 'function') { + // return atob(data); + //} + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + dec = "", + tmp_arr = []; + + if (!data) { + return data; + } + + data += ''; + + do { // unpack four hexets into three octets using index points in b64 + h1 = b64.indexOf(data.charAt(i++)); + h2 = b64.indexOf(data.charAt(i++)); + h3 = b64.indexOf(data.charAt(i++)); + h4 = b64.indexOf(data.charAt(i++)); + + bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; + + o1 = bits >> 16 & 0xff; + o2 = bits >> 8 & 0xff; + o3 = bits & 0xff; + + if (h3 == 64) { + tmp_arr[ac++] = String.fromCharCode(o1); + } else if (h4 == 64) { + tmp_arr[ac++] = String.fromCharCode(o1, o2); + } else { + tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); + } + } while (i < data.length); + + dec = tmp_arr.join(''); + + return utf8 ? utf8_decode(dec) : dec; + }; + + /** + Base64 encode string (uses browser's default method if available), + from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js + + @method btoa + @static + @param {String} data String to encode + @return {String} Base64 encoded string + */ + var btoa = function(data, utf8) { + if (utf8) { + utf8_encode(data); + } + + if (typeof(window.btoa) === 'function') { + return window.btoa(data); + } + + // http://kevin.vanzonneveld.net + // + original by: Tyler Akins (http://rumkin.com) + // + improved by: Bayron Guevara + // + improved by: Thunder.m + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Pellentesque Malesuada + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Rafał Kukawski (http://kukawski.pl) + // * example 1: base64_encode('Kevin van Zonneveld'); + // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' + // mozilla has this native + // - but breaks in 2.0.0.12! + var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, + ac = 0, + enc = "", + tmp_arr = []; + + if (!data) { + return data; + } + + do { // pack three octets into four hexets + o1 = data.charCodeAt(i++); + o2 = data.charCodeAt(i++); + o3 = data.charCodeAt(i++); + + bits = o1 << 16 | o2 << 8 | o3; + + h1 = bits >> 18 & 0x3f; + h2 = bits >> 12 & 0x3f; + h3 = bits >> 6 & 0x3f; + h4 = bits & 0x3f; + + // use hexets to index into b64, and append result to encoded string + tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); + } while (i < data.length); + + enc = tmp_arr.join(''); + + var r = data.length % 3; + + return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); + }; + + + return { + utf8_encode: utf8_encode, + utf8_decode: utf8_decode, + atob: atob, + btoa: btoa + }; +}); + +// Included from: src/javascript/runtime/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/runtime/Runtime', [ + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/EventTarget" +], function(Basic, Dom, EventTarget) { + var runtimeConstructors = {}, runtimes = {}; + + /** + Common set of methods and properties for every runtime instance + + @class Runtime + + @param {Object} options + @param {String} type Sanitized name of the runtime + @param {Object} [caps] Set of capabilities that differentiate specified runtime + @param {Object} [modeCaps] Set of capabilities that do require specific operational mode + @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested + */ + function Runtime(options, type, caps, modeCaps, preferredMode) { + /** + Dispatched when runtime is initialized and ready. + Results in RuntimeInit on a connected component. + + @event Init + */ + + /** + Dispatched when runtime fails to initialize. + Results in RuntimeError on a connected component. + + @event Error + */ + + var self = this + , _shim + , _uid = Basic.guid(type + '_') + , defaultMode = preferredMode || 'browser' + ; + + options = options || {}; + + // register runtime in private hash + runtimes[_uid] = this; + + /** + Default set of capabilities, which can be redifined later by specific runtime + + @private + @property caps + @type Object + */ + caps = Basic.extend({ + // Runtime can: + // provide access to raw binary data of the file + access_binary: false, + // provide access to raw binary data of the image (image extension is optional) + access_image_binary: false, + // display binary data as thumbs for example + display_media: false, + // make cross-domain requests + do_cors: false, + // accept files dragged and dropped from the desktop + drag_and_drop: false, + // filter files in selection dialog by their extensions + filter_by_extension: true, + // resize image (and manipulate it raw data of any file in general) + resize_image: false, + // periodically report how many bytes of total in the file were uploaded (loaded) + report_upload_progress: false, + // provide access to the headers of http response + return_response_headers: false, + // support response of specific type, which should be passed as an argument + // e.g. runtime.can('return_response_type', 'blob') + return_response_type: false, + // return http status code of the response + return_status_code: true, + // send custom http header with the request + send_custom_headers: false, + // pick up the files from a dialog + select_file: false, + // select whole folder in file browse dialog + select_folder: false, + // select multiple files at once in file browse dialog + select_multiple: true, + // send raw binary data, that is generated after image resizing or manipulation of other kind + send_binary_string: false, + // send cookies with http request and therefore retain session + send_browser_cookies: true, + // send data formatted as multipart/form-data + send_multipart: true, + // slice the file or blob to smaller parts + slice_blob: false, + // upload file without preloading it to memory, stream it out directly from disk + stream_upload: false, + // programmatically trigger file browse dialog + summon_file_dialog: false, + // upload file of specific size, size should be passed as argument + // e.g. runtime.can('upload_filesize', '500mb') + upload_filesize: true, + // initiate http request with specific http method, method should be passed as argument + // e.g. runtime.can('use_http_method', 'put') + use_http_method: true + }, caps); + + + // default to the mode that is compatible with preferred caps + if (options.preferred_caps) { + defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode); + } + + // small extension factory here (is meant to be extended with actual extensions constructors) + _shim = (function() { + var objpool = {}; + return { + exec: function(uid, comp, fn, args) { + if (_shim[comp]) { + if (!objpool[uid]) { + objpool[uid] = { + context: this, + instance: new _shim[comp]() + }; + } + if (objpool[uid].instance[fn]) { + return objpool[uid].instance[fn].apply(this, args); + } + } + }, + + removeInstance: function(uid) { + delete objpool[uid]; + }, + + removeAllInstances: function() { + var self = this; + Basic.each(objpool, function(obj, uid) { + if (Basic.typeOf(obj.instance.destroy) === 'function') { + obj.instance.destroy.call(obj.context); + } + self.removeInstance(uid); + }); + } + }; + }()); + + + // public methods + Basic.extend(this, { + /** + Specifies whether runtime instance was initialized or not + + @property initialized + @type {Boolean} + @default false + */ + initialized: false, // shims require this flag to stop initialization retries + + /** + Unique ID of the runtime + + @property uid + @type {String} + */ + uid: _uid, + + /** + Runtime type (e.g. flash, html5, etc) + + @property type + @type {String} + */ + type: type, + + /** + Runtime (not native one) may operate in browser or client mode. + + @property mode + @private + @type {String|Boolean} current mode or false, if none possible + */ + mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode), + + /** + id of the DOM container for the runtime (if available) + + @property shimid + @type {String} + */ + shimid: _uid + '_container', + + /** + Number of connected clients. If equal to zero, runtime can be destroyed + + @property clients + @type {Number} + */ + clients: 0, + + /** + Runtime initialization options + + @property options + @type {Object} + */ + options: options, + + /** + Checks if the runtime has specific capability + + @method can + @param {String} cap Name of capability to check + @param {Mixed} [value] If passed, capability should somehow correlate to the value + @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set) + @return {Boolean} true if runtime has such capability and false, if - not + */ + can: function(cap, value) { + var refCaps = arguments[2] || caps; + + // if cap var is a comma-separated list of caps, convert it to object (key/value) + if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') { + cap = Runtime.parseCaps(cap); + } + + if (Basic.typeOf(cap) === 'object') { + for (var key in cap) { + if (!this.can(key, cap[key], refCaps)) { + return false; + } + } + return true; + } + + // check the individual cap + if (Basic.typeOf(refCaps[cap]) === 'function') { + return refCaps[cap].call(this, value); + } else { + return (value === refCaps[cap]); + } + }, + + /** + Returns container for the runtime as DOM element + + @method getShimContainer + @return {DOMElement} + */ + getShimContainer: function() { + var container, shimContainer = Dom.get(this.shimid); + + // if no container for shim, create one + if (!shimContainer) { + container = this.options.container ? Dom.get(this.options.container) : document.body; + + // create shim container and insert it at an absolute position into the outer container + shimContainer = document.createElement('div'); + shimContainer.id = this.shimid; + shimContainer.className = 'moxie-shim moxie-shim-' + this.type; + + Basic.extend(shimContainer.style, { + position: 'absolute', + top: '0px', + left: '0px', + width: '1px', + height: '1px', + overflow: 'hidden' + }); + + container.appendChild(shimContainer); + container = null; + } + + return shimContainer; + }, + + /** + Returns runtime as DOM element (if appropriate) + + @method getShim + @return {DOMElement} + */ + getShim: function() { + return _shim; + }, + + /** + Invokes a method within the runtime itself (might differ across the runtimes) + + @method shimExec + @param {Mixed} [] + @protected + @return {Mixed} Depends on the action and component + */ + shimExec: function(component, action) { + var args = [].slice.call(arguments, 2); + return self.getShim().exec.call(this, this.uid, component, action, args); + }, + + /** + Operaional interface that is used by components to invoke specific actions on the runtime + (is invoked in the scope of component) + + @method exec + @param {Mixed} []* + @protected + @return {Mixed} Depends on the action and component + */ + exec: function(component, action) { // this is called in the context of component, not runtime + var args = [].slice.call(arguments, 2); + + if (self[component] && self[component][action]) { + return self[component][action].apply(this, args); + } + return self.shimExec.apply(this, arguments); + }, + + /** + Destroys the runtime (removes all events and deletes DOM structures) + + @method destroy + */ + destroy: function() { + if (!self) { + return; // obviously already destroyed + } + + var shimContainer = Dom.get(this.shimid); + if (shimContainer) { + shimContainer.parentNode.removeChild(shimContainer); + } + + if (_shim) { + _shim.removeAllInstances(); + } + + this.unbindAll(); + delete runtimes[this.uid]; + this.uid = null; // mark this runtime as destroyed + _uid = self = _shim = shimContainer = null; + } + }); + + // once we got the mode, test against all caps + if (this.mode && options.required_caps && !this.can(options.required_caps)) { + this.mode = false; + } + } + + + /** + Default order to try different runtime types + + @property order + @type String + @static + */ + Runtime.order = 'html5,flash,silverlight,html4'; + + + /** + Retrieves runtime from private hash by it's uid + + @method getRuntime + @private + @static + @param {String} uid Unique identifier of the runtime + @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not + */ + Runtime.getRuntime = function(uid) { + return runtimes[uid] ? runtimes[uid] : false; + }; + + + /** + Register constructor for the Runtime of new (or perhaps modified) type + + @method addConstructor + @static + @param {String} type Runtime type (e.g. flash, html5, etc) + @param {Function} construct Constructor for the Runtime type + */ + Runtime.addConstructor = function(type, constructor) { + constructor.prototype = EventTarget.instance; + runtimeConstructors[type] = constructor; + }; + + + /** + Get the constructor for the specified type. + + method getConstructor + @static + @param {String} type Runtime type (e.g. flash, html5, etc) + @return {Function} Constructor for the Runtime type + */ + Runtime.getConstructor = function(type) { + return runtimeConstructors[type] || null; + }; + + + /** + Get info about the runtime (uid, type, capabilities) + + @method getInfo + @static + @param {String} uid Unique identifier of the runtime + @return {Mixed} Info object or null if runtime doesn't exist + */ + Runtime.getInfo = function(uid) { + var runtime = Runtime.getRuntime(uid); + + if (runtime) { + return { + uid: runtime.uid, + type: runtime.type, + mode: runtime.mode, + can: function() { + return runtime.can.apply(runtime, arguments); + } + }; + } + return null; + }; + + + /** + Convert caps represented by a comma-separated string to the object representation. + + @method parseCaps + @static + @param {String} capStr Comma-separated list of capabilities + @return {Object} + */ + Runtime.parseCaps = function(capStr) { + var capObj = {}; + + if (Basic.typeOf(capStr) !== 'string') { + return capStr || {}; + } + + Basic.each(capStr.split(','), function(key) { + capObj[key] = true; // we assume it to be - true + }); + + return capObj; + }; + + /** + Test the specified runtime for specific capabilities. + + @method can + @static + @param {String} type Runtime type (e.g. flash, html5, etc) + @param {String|Object} caps Set of capabilities to check + @return {Boolean} Result of the test + */ + Runtime.can = function(type, caps) { + var runtime + , constructor = Runtime.getConstructor(type) + , mode + ; + if (constructor) { + runtime = new constructor({ + required_caps: caps + }); + mode = runtime.mode; + runtime.destroy(); + return !!mode; + } + return false; + }; + + + /** + Figure out a runtime that supports specified capabilities. + + @method thatCan + @static + @param {String|Object} caps Set of capabilities to check + @param {String} [runtimeOrder] Comma-separated list of runtimes to check against + @return {String} Usable runtime identifier or null + */ + Runtime.thatCan = function(caps, runtimeOrder) { + var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/); + for (var i in types) { + if (Runtime.can(types[i], caps)) { + return types[i]; + } + } + return null; + }; + + + /** + Figure out an operational mode for the specified set of capabilities. + + @method getMode + @static + @param {Object} modeCaps Set of capabilities that depend on particular runtime mode + @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for + @param {String|Boolean} [defaultMode='browser'] Default mode to use + @return {String|Boolean} Compatible operational mode + */ + Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) { + var mode = null; + + if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified + defaultMode = 'browser'; + } + + if (requiredCaps && !Basic.isEmptyObj(modeCaps)) { + // loop over required caps and check if they do require the same mode + Basic.each(requiredCaps, function(value, cap) { + if (modeCaps.hasOwnProperty(cap)) { + var capMode = modeCaps[cap](value); + + // make sure we always have an array + if (typeof(capMode) === 'string') { + capMode = [capMode]; + } + + if (!mode) { + mode = capMode; + } else if (!(mode = Basic.arrayIntersect(mode, capMode))) { + // if cap requires conflicting mode - runtime cannot fulfill required caps + return (mode = false); + } + } + }); + + if (mode) { + return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0]; + } else if (mode === false) { + return false; + } + } + return defaultMode; + }; + + + /** + Capability check that always returns true + + @private + @static + @return {True} + */ + Runtime.capTrue = function() { + return true; + }; + + /** + Capability check that always returns false + + @private + @static + @return {False} + */ + Runtime.capFalse = function() { + return false; + }; + + /** + Evaluate the expression to boolean value and create a function that always returns it. + + @private + @static + @param {Mixed} expr Expression to evaluate + @return {Function} Function returning the result of evaluation + */ + Runtime.capTest = function(expr) { + return function() { + return !!expr; + }; + }; + + return Runtime; +}); + +// Included from: src/javascript/runtime/RuntimeClient.js + +/** + * RuntimeClient.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/runtime/RuntimeClient', [ + 'moxie/core/Exceptions', + 'moxie/core/utils/Basic', + 'moxie/runtime/Runtime' +], function(x, Basic, Runtime) { + /** + Set of methods and properties, required by a component to acquire ability to connect to a runtime + + @class RuntimeClient + */ + return function RuntimeClient() { + var runtime; + + Basic.extend(this, { + /** + Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one. + Increments number of clients connected to the specified runtime. + + @method connectRuntime + @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites + */ + connectRuntime: function(options) { + var comp = this, ruid; + + function initialize(items) { + var type, constructor; + + // if we ran out of runtimes + if (!items.length) { + comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); + runtime = null; + return; + } + + type = items.shift(); + constructor = Runtime.getConstructor(type); + if (!constructor) { + initialize(items); + return; + } + + // try initializing the runtime + runtime = new constructor(options); + + runtime.bind('Init', function() { + // mark runtime as initialized + runtime.initialized = true; + + // jailbreak ... + setTimeout(function() { + runtime.clients++; + // this will be triggered on component + comp.trigger('RuntimeInit', runtime); + }, 1); + }); + + runtime.bind('Error', function() { + runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here + initialize(items); + }); + + /*runtime.bind('Exception', function() { });*/ + + // check if runtime managed to pick-up operational mode + if (!runtime.mode) { + runtime.trigger('Error'); + return; + } + + runtime.init(); + } + + // check if a particular runtime was requested + if (Basic.typeOf(options) === 'string') { + ruid = options; + } else if (Basic.typeOf(options.ruid) === 'string') { + ruid = options.ruid; + } + + if (ruid) { + runtime = Runtime.getRuntime(ruid); + if (runtime) { + runtime.clients++; + return runtime; + } else { + // there should be a runtime and there's none - weird case + throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR); + } + } + + // initialize a fresh one, that fits runtime list and required features best + initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/)); + }, + + /** + Returns the runtime to which the client is currently connected. + + @method getRuntime + @return {Runtime} Runtime or null if client is not connected + */ + getRuntime: function() { + if (runtime && runtime.uid) { + return runtime; + } + runtime = null; // make sure we do not leave zombies rambling around + return null; + }, + + /** + Disconnects from the runtime. Decrements number of clients connected to the specified runtime. + + @method disconnectRuntime + */ + disconnectRuntime: function() { + if (runtime && --runtime.clients <= 0) { + runtime.destroy(); + runtime = null; + } + } + + }); + }; + + +}); + +// Included from: src/javascript/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/Blob', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Encode', + 'moxie/runtime/RuntimeClient' +], function(Basic, Encode, RuntimeClient) { + + var blobpool = {}; + + /** + @class Blob + @constructor + @param {String} ruid Unique id of the runtime, to which this blob belongs to + @param {Object} blob Object "Native" blob object, as it is represented in the runtime + */ + function Blob(ruid, blob) { + + function _sliceDetached(start, end, type) { + var blob, data = blobpool[this.uid]; + + if (Basic.typeOf(data) !== 'string' || !data.length) { + return null; // or throw exception + } + + blob = new Blob(null, { + type: type, + size: end - start + }); + blob.detach(data.substr(start, blob.size)); + + return blob; + } + + RuntimeClient.call(this); + + if (ruid) { + this.connectRuntime(ruid); + } + + if (!blob) { + blob = {}; + } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string + blob = { data: blob }; + } + + Basic.extend(this, { + + /** + Unique id of the component + + @property uid + @type {String} + */ + uid: blob.uid || Basic.guid('uid_'), + + /** + Unique id of the connected runtime, if falsy, then runtime will have to be initialized + before this Blob can be used, modified or sent + + @property ruid + @type {String} + */ + ruid: ruid, + + /** + Size of blob + + @property size + @type {Number} + @default 0 + */ + size: blob.size || 0, + + /** + Mime type of blob + + @property type + @type {String} + @default '' + */ + type: blob.type || '', + + /** + @method slice + @param {Number} [start=0] + */ + slice: function(start, end, type) { + if (this.isDetached()) { + return _sliceDetached.apply(this, arguments); + } + return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type); + }, + + /** + Returns "native" blob object (as it is represented in connected runtime) or null if not found + + @method getSource + @return {Blob} Returns "native" blob object or null if not found + */ + getSource: function() { + if (!blobpool[this.uid]) { + return null; + } + return blobpool[this.uid]; + }, + + /** + Detaches blob from any runtime that it depends on and initialize with standalone value + + @method detach + @protected + @param {DOMString} [data=''] Standalone value + */ + detach: function(data) { + if (this.ruid) { + this.getRuntime().exec.call(this, 'Blob', 'destroy', blobpool[this.uid]); + this.disconnectRuntime(); + this.ruid = null; + } + + data = data || ''; + + // if dataUrl, convert to binary string + var matches = data.match(/^data:([^;]*);base64,/); + if (matches) { + this.type = matches[1]; + data = Encode.atob(data.substring(data.indexOf('base64,') + 7)); + } + + this.size = data.length; + + blobpool[this.uid] = data; + }, + + /** + Checks if blob is standalone (detached of any runtime) + + @method isDetached + @protected + @return {Boolean} + */ + isDetached: function() { + return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string'; + }, + + /** + Destroy Blob and free any resources it was using + + @method destroy + */ + destroy: function() { + this.detach(); + delete blobpool[this.uid]; + } + }); + + + if (blob.data) { + this.detach(blob.data); // auto-detach if payload has been passed + } else { + blobpool[this.uid] = blob; + } + } + + return Blob; +}); + +// Included from: src/javascript/file/File.js + +/** + * File.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/File', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Mime', + 'moxie/file/Blob' +], function(Basic, Mime, Blob) { + /** + @class File + @extends Blob + @constructor + @param {String} ruid Unique id of the runtime, to which this blob belongs to + @param {Object} file Object "Native" file object, as it is represented in the runtime + */ + function File(ruid, file) { + var name, type; + + if (!file) { // avoid extra errors in case we overlooked something + file = {}; + } + + // figure out the type + if (file.type && file.type !== '') { + type = file.type; + } else { + type = Mime.getFileMime(file.name); + } + + // sanitize file name or generate new one + if (file.name) { + name = file.name.replace(/\\/g, '/'); + name = name.substr(name.lastIndexOf('/') + 1); + } else { + var prefix = type.split('/')[0]; + name = Basic.guid((prefix !== '' ? prefix : 'file') + '_'); + + if (Mime.extensions[type]) { + name += '.' + Mime.extensions[type][0]; // append proper extension if possible + } + } + + Blob.apply(this, arguments); + + Basic.extend(this, { + /** + File mime type + + @property type + @type {String} + @default '' + */ + type: type || '', + + /** + File name + + @property name + @type {String} + @default UID + */ + name: name || Basic.guid('file_'), + + /** + Date of last modification + + @property lastModifiedDate + @type {String} + @default now + */ + lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) + }); + } + + File.prototype = Blob.prototype; + + return File; +}); + +// Included from: src/javascript/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileInput', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Mime', + 'moxie/core/utils/Dom', + 'moxie/core/Exceptions', + 'moxie/core/EventTarget', + 'moxie/core/I18n', + 'moxie/file/File', + 'moxie/runtime/Runtime', + 'moxie/runtime/RuntimeClient' +], function(Basic, Mime, Dom, x, EventTarget, I18n, File, Runtime, RuntimeClient) { + /** + Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click, + converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory + with _FileReader_ or uploaded to a server through _XMLHttpRequest_. + + @class FileInput + @constructor + @extends EventTarget + @uses RuntimeClient + @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_. + @param {String|DOMElement} options.browse_button DOM Element to turn into file picker. + @param {Array} [options.accept] Array of mime types to accept. By default accepts all. + @param {String} [options.file='file'] Name of the file field (not the filename). + @param {Boolean} [options.multiple=false] Enable selection of multiple files. + @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time). + @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode + for _browse\_button_. + @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support. + + @example +
                        + Browse... +
                        + + + */ + var dispatches = [ + /** + Dispatched when runtime is connected and file-picker is ready to be used. + + @event ready + @param {Object} event + */ + 'ready', + + /** + Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. + Check [corresponding documentation entry](#method_refresh) for more info. + + @event refresh + @param {Object} event + */ + + /** + Dispatched when selection of files in the dialog is complete. + + @event change + @param {Object} event + */ + 'change', + + 'cancel', // TODO: might be useful + + /** + Dispatched when mouse cursor enters file-picker area. Can be used to style element + accordingly. + + @event mouseenter + @param {Object} event + */ + 'mouseenter', + + /** + Dispatched when mouse cursor leaves file-picker area. Can be used to style element + accordingly. + + @event mouseleave + @param {Object} event + */ + 'mouseleave', + + /** + Dispatched when functional mouse button is pressed on top of file-picker area. + + @event mousedown + @param {Object} event + */ + 'mousedown', + + /** + Dispatched when functional mouse button is released on top of file-picker area. + + @event mouseup + @param {Object} event + */ + 'mouseup' + ]; + + function FileInput(options) { + var self = this, + container, browseButton, defaults; + + // if flat argument passed it should be browse_button id + if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) { + options = { browse_button : options }; + } + + // this will help us to find proper default container + browseButton = Dom.get(options.browse_button); + if (!browseButton) { + // browse button is required + throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); + } + + // figure out the options + defaults = { + accept: [{ + title: I18n.translate('All Files'), + extensions: '*' + }], + name: 'file', + multiple: false, + required_caps: false, + container: browseButton.parentNode || document.body + }; + + options = Basic.extend({}, defaults, options); + + // convert to object representation + if (typeof(options.required_caps) === 'string') { + options.required_caps = Runtime.parseCaps(options.required_caps); + } + + // normalize accept option (could be list of mime types or array of title/extensions pairs) + if (typeof(options.accept) === 'string') { + options.accept = Mime.mimes2extList(options.accept); + } + + container = Dom.get(options.container); + // make sure we have container + if (!container) { + container = document.body; + } + + // make container relative, if it's not + if (Dom.getStyle(container, 'position') === 'static') { + container.style.position = 'relative'; + } + + container = browseButton = null; // IE + + RuntimeClient.call(self); + + Basic.extend(self, { + /** + Unique id of the component + + @property uid + @protected + @readOnly + @type {String} + @default UID + */ + uid: Basic.guid('uid_'), + + /** + Unique id of the connected runtime, if any. + + @property ruid + @protected + @type {String} + */ + ruid: null, + + /** + Unique id of the runtime container. Useful to get hold of it for various manipulations. + + @property shimid + @protected + @type {String} + */ + shimid: null, + + /** + Array of selected mOxie.File objects + + @property files + @type {Array} + @default null + */ + files: null, + + /** + Initializes the file-picker, connects it to runtime and dispatches event ready when done. + + @method init + */ + init: function() { + self.convertEventPropsToHandlers(dispatches); + + self.bind('RuntimeInit', function(e, runtime) { + self.ruid = runtime.uid; + self.shimid = runtime.shimid; + + self.bind("Ready", function() { + self.trigger("Refresh"); + }, 999); + + self.bind("Change", function() { + var files = runtime.exec.call(self, 'FileInput', 'getFiles'); + + self.files = []; + + Basic.each(files, function(file) { + // ignore empty files (IE10 for example hangs if you try to send them via XHR) + if (file.size === 0) { + return true; + } + self.files.push(new File(self.ruid, file)); + }); + }, 999); + + // re-position and resize shim container + self.bind('Refresh', function() { + var pos, size, browseButton, shimContainer; + + browseButton = Dom.get(options.browse_button); + shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist + + if (browseButton) { + pos = Dom.getPos(browseButton, Dom.get(options.container)); + size = Dom.getSize(browseButton); + + if (shimContainer) { + Basic.extend(shimContainer.style, { + top : pos.y + 'px', + left : pos.x + 'px', + width : size.w + 'px', + height : size.h + 'px' + }); + } + } + shimContainer = browseButton = null; + }); + + runtime.exec.call(self, 'FileInput', 'init', options); + }); + + // runtime needs: options.required_features, options.runtime_order and options.container + self.connectRuntime(Basic.extend({}, options, { + required_caps: { + select_file: true + } + })); + }, + + /** + Disables file-picker element, so that it doesn't react to mouse clicks. + + @method disable + @param {Boolean} [state=true] Disable component if - true, enable if - false + */ + disable: function(state) { + var runtime = this.getRuntime(); + if (runtime) { + runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state); + } + }, + + + /** + Reposition and resize dialog trigger to match the position and size of browse_button element. + + @method refresh + */ + refresh: function() { + self.trigger("Refresh"); + }, + + + /** + Destroy component. + + @method destroy + */ + destroy: function() { + var runtime = this.getRuntime(); + if (runtime) { + runtime.exec.call(this, 'FileInput', 'destroy'); + this.disconnectRuntime(); + } + + if (Basic.typeOf(this.files) === 'array') { + // no sense in leaving associated files behind + Basic.each(this.files, function(file) { + file.destroy(); + }); + } + this.files = null; + } + }); + } + + FileInput.prototype = EventTarget.instance; + + return FileInput; +}); + +// Included from: src/javascript/file/FileDrop.js + +/** + * FileDrop.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileDrop', [ + 'moxie/core/I18n', + 'moxie/core/utils/Dom', + 'moxie/core/Exceptions', + 'moxie/core/utils/Basic', + 'moxie/file/File', + 'moxie/runtime/RuntimeClient', + 'moxie/core/EventTarget', + 'moxie/core/utils/Mime' +], function(I18n, Dom, x, Basic, File, RuntimeClient, EventTarget, Mime) { + /** + Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used + in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through + _XMLHttpRequest_. + + @example +
                        + Drop files here +
                        +
                        +
                        + + + + @class FileDrop + @constructor + @extends EventTarget + @uses RuntimeClient + @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone + @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone + @param {Array} [options.accept] Array of mime types to accept. By default accepts all + @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support + */ + var dispatches = [ + /** + Dispatched when runtime is connected and drop zone is ready to accept files. + + @event ready + @param {Object} event + */ + 'ready', + + /** + Dispatched when dragging cursor enters the drop zone. + + @event dragenter + @param {Object} event + */ + 'dragenter', + + /** + Dispatched when dragging cursor leaves the drop zone. + + @event dragleave + @param {Object} event + */ + 'dragleave', + + /** + Dispatched when file is dropped onto the drop zone. + + @event drop + @param {Object} event + */ + 'drop', + + /** + Dispatched if error occurs. + + @event error + @param {Object} event + */ + 'error' + ]; + + function FileDrop(options) { + var self = this, defaults; + + // if flat argument passed it should be drop_zone id + if (typeof(options) === 'string') { + options = { drop_zone : options }; + } + + // figure out the options + defaults = { + accept: [{ + title: I18n.translate('All Files'), + extensions: '*' + }], + required_caps: { + drag_and_drop: true + } + }; + + options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults; + + // this will help us to find proper default container + options.container = Dom.get(options.drop_zone) || document.body; + + // make container relative, if it is not + if (Dom.getStyle(options.container, 'position') === 'static') { + options.container.style.position = 'relative'; + } + + // normalize accept option (could be list of mime types or array of title/extensions pairs) + if (typeof(options.accept) === 'string') { + options.accept = Mime.mimes2extList(options.accept); + } + + RuntimeClient.call(self); + + Basic.extend(self, { + uid: Basic.guid('uid_'), + + ruid: null, + + files: null, + + init: function() { + + self.convertEventPropsToHandlers(dispatches); + + self.bind('RuntimeInit', function(e, runtime) { + self.ruid = runtime.uid; + + self.bind("Drop", function() { + var files = runtime.exec.call(self, 'FileDrop', 'getFiles'); + + self.files = []; + + Basic.each(files, function(file) { + self.files.push(new File(self.ruid, file)); + }); + }, 999); + + runtime.exec.call(self, 'FileDrop', 'init', options); + + self.dispatchEvent('ready'); + }); + + // runtime needs: options.required_features, options.runtime_order and options.container + self.connectRuntime(options); // throws RuntimeError + }, + + destroy: function() { + var runtime = this.getRuntime(); + if (runtime) { + runtime.exec.call(this, 'FileDrop', 'destroy'); + this.disconnectRuntime(); + } + this.files = null; + } + }); + } + + FileDrop.prototype = EventTarget.instance; + + return FileDrop; +}); + +// Included from: src/javascript/runtime/RuntimeTarget.js + +/** + * RuntimeTarget.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/runtime/RuntimeTarget', [ + 'moxie/core/utils/Basic', + 'moxie/runtime/RuntimeClient', + "moxie/core/EventTarget" +], function(Basic, RuntimeClient, EventTarget) { + /** + Instance of this class can be used as a target for the events dispatched by shims, + when allowing them onto components is for either reason inappropriate + + @class RuntimeTarget + @constructor + @protected + @extends EventTarget + */ + function RuntimeTarget() { + this.uid = Basic.guid('uid_'); + + RuntimeClient.call(this); + + this.destroy = function() { + this.disconnectRuntime(); + this.unbindAll(); + }; + } + + RuntimeTarget.prototype = EventTarget.instance; + + return RuntimeTarget; +}); + +// Included from: src/javascript/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileReader', [ + 'moxie/core/utils/Basic', + 'moxie/core/utils/Encode', + 'moxie/core/Exceptions', + 'moxie/core/EventTarget', + 'moxie/file/Blob', + 'moxie/file/File', + 'moxie/runtime/RuntimeTarget' +], function(Basic, Encode, x, EventTarget, Blob, File, RuntimeTarget) { + /** + Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader) + interface. Where possible uses native FileReader, where - not falls back to shims. + + @class FileReader + @constructor FileReader + @extends EventTarget + @uses RuntimeClient + */ + var dispatches = [ + + /** + Dispatched when the read starts. + + @event loadstart + @param {Object} event + */ + 'loadstart', + + /** + Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total). + + @event progress + @param {Object} event + */ + 'progress', + + /** + Dispatched when the read has successfully completed. + + @event load + @param {Object} event + */ + 'load', + + /** + Dispatched when the read has been aborted. For instance, by invoking the abort() method. + + @event abort + @param {Object} event + */ + 'abort', + + /** + Dispatched when the read has failed. + + @event error + @param {Object} event + */ + 'error', + + /** + Dispatched when the request has completed (either in success or failure). + + @event loadend + @param {Object} event + */ + 'loadend' + ]; + + function FileReader() { + var self = this, _fr; + + Basic.extend(this, { + /** + UID of the component instance. + + @property uid + @type {String} + */ + uid: Basic.guid('uid_'), + + /** + Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING + and FileReader.DONE. + + @property readyState + @type {Number} + @default FileReader.EMPTY + */ + readyState: FileReader.EMPTY, + + /** + Result of the successful read operation. + + @property result + @type {String} + */ + result: null, + + /** + Stores the error of failed asynchronous read operation. + + @property error + @type {DOMError} + */ + error: null, + + /** + Initiates reading of File/Blob object contents to binary string. + + @method readAsBinaryString + @param {Blob|File} blob Object to preload + */ + readAsBinaryString: function(blob) { + _read.call(this, 'readAsBinaryString', blob); + }, + + /** + Initiates reading of File/Blob object contents to dataURL string. + + @method readAsDataURL + @param {Blob|File} blob Object to preload + */ + readAsDataURL: function(blob) { + _read.call(this, 'readAsDataURL', blob); + }, + + /** + Initiates reading of File/Blob object contents to string. + + @method readAsText + @param {Blob|File} blob Object to preload + */ + readAsText: function(blob) { + _read.call(this, 'readAsText', blob); + }, + + /** + Aborts preloading process. + + @method abort + */ + abort: function() { + this.result = null; + + if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) { + return; + } else if (this.readyState === FileReader.LOADING) { + this.readyState = FileReader.DONE; + } + + if (_fr) { + _fr.getRuntime().exec.call(this, 'FileReader', 'abort'); + } + + this.trigger('abort'); + this.trigger('loadend'); + }, + + /** + Destroy component and release resources. + + @method destroy + */ + destroy: function() { + this.abort(); + + if (_fr) { + _fr.getRuntime().exec.call(this, 'FileReader', 'destroy'); + _fr.disconnectRuntime(); + } + + self = _fr = null; + } + }); + + + function _read(op, blob) { + _fr = new RuntimeTarget(); + + function error(err) { + self.readyState = FileReader.DONE; + self.error = err; + self.trigger('error'); + loadEnd(); + } + + function loadEnd() { + _fr.destroy(); + _fr = null; + self.trigger('loadend'); + } + + function exec(runtime) { + _fr.bind('Error', function(e, err) { + error(err); + }); + + _fr.bind('Progress', function(e) { + self.result = runtime.exec.call(_fr, 'FileReader', 'getResult'); + self.trigger(e); + }); + + _fr.bind('Load', function(e) { + self.readyState = FileReader.DONE; + self.result = runtime.exec.call(_fr, 'FileReader', 'getResult'); + self.trigger(e); + loadEnd(); + }); + + runtime.exec.call(_fr, 'FileReader', 'read', op, blob); + } + + this.convertEventPropsToHandlers(dispatches); + + if (this.readyState === FileReader.LOADING) { + return error(new x.DOMException(x.DOMException.INVALID_STATE_ERR)); + } + + this.readyState = FileReader.LOADING; + this.trigger('loadstart'); + + // if source is o.Blob/o.File + if (blob instanceof Blob) { + if (blob.isDetached()) { + var src = blob.getSource(); + switch (op) { + case 'readAsText': + case 'readAsBinaryString': + this.result = src; + break; + case 'readAsDataURL': + this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src); + break; + } + this.readyState = FileReader.DONE; + this.trigger('load'); + loadEnd(); + } else { + exec(_fr.connectRuntime(blob.ruid)); + } + } else { + error(new x.DOMException(x.DOMException.NOT_FOUND_ERR)); + } + } + } + + /** + Initial FileReader state + + @property EMPTY + @type {Number} + @final + @static + @default 0 + */ + FileReader.EMPTY = 0; + + /** + FileReader switches to this state when it is preloading the source + + @property LOADING + @type {Number} + @final + @static + @default 1 + */ + FileReader.LOADING = 1; + + /** + Preloading is complete, this is a final state + + @property DONE + @type {Number} + @final + @static + @default 2 + */ + FileReader.DONE = 2; + + FileReader.prototype = EventTarget.instance; + + return FileReader; +}); + +// Included from: src/javascript/core/utils/Url.js + +/** + * Url.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Url', [], function() { + /** + Parse url into separate components and fill in absent parts with parts from current url, + based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js + + @method parseUrl + @for Utils + @static + @param {String} url Url to parse (defaults to empty string if undefined) + @return {Object} Hash containing extracted uri components + */ + var parseUrl = function(url, currentUrl) { + var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'] + , i = key.length + , ports = { + http: 80, + https: 443 + } + , uri = {} + , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/ + , m = regex.exec(url || '') + ; + + while (i--) { + if (m[i]) { + uri[key[i]] = m[i]; + } + } + + // when url is relative, we set the origin and the path ourselves + if (!uri.scheme) { + // come up with defaults + if (!currentUrl || typeof(currentUrl) === 'string') { + currentUrl = parseUrl(currentUrl || document.location.href); + } + + uri.scheme = currentUrl.scheme; + uri.host = currentUrl.host; + uri.port = currentUrl.port; + + var path = ''; + // for urls without trailing slash we need to figure out the path + if (/^[^\/]/.test(uri.path)) { + path = currentUrl.path; + // if path ends with a filename, strip it + if (!/(\/|\/[^\.]+)$/.test(path)) { + path = path.replace(/\/[^\/]+$/, '/'); + } else { + path += '/'; + } + } + uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir + } + + if (!uri.port) { + uri.port = ports[uri.scheme] || 80; + } + + uri.port = parseInt(uri.port, 10); + + if (!uri.path) { + uri.path = "/"; + } + + delete uri.source; + + return uri; + }; + + /** + Resolve url - among other things will turn relative url to absolute + + @method resolveUrl + @static + @param {String} url Either absolute or relative + @return {String} Resolved, absolute url + */ + var resolveUrl = function(url) { + var ports = { // we ignore default ports + http: 80, + https: 443 + } + , urlp = parseUrl(url) + ; + + return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : ''); + }; + + /** + Check if specified url has the same origin as the current document + + @method hasSameOrigin + @param {String|Object} url + @return {Boolean} + */ + var hasSameOrigin = function(url) { + function origin(url) { + return [url.scheme, url.host, url.port].join('/'); + } + + if (typeof url === 'string') { + url = parseUrl(url); + } + + return origin(parseUrl()) === origin(url); + }; + + return { + parseUrl: parseUrl, + resolveUrl: resolveUrl, + hasSameOrigin: hasSameOrigin + }; +}); + +// Included from: src/javascript/file/FileReaderSync.js + +/** + * FileReaderSync.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/file/FileReaderSync', [ + 'moxie/core/utils/Basic', + 'moxie/runtime/RuntimeClient', + 'moxie/core/utils/Encode' +], function(Basic, RuntimeClient, Encode) { + /** + Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here + it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be, + but probably < 1mb). Not meant to be used directly by user. + + @class FileReaderSync + @private + @constructor + */ + return function() { + RuntimeClient.call(this); + + Basic.extend(this, { + uid: Basic.guid('uid_'), + + readAsBinaryString: function(blob) { + return _read.call(this, 'readAsBinaryString', blob); + }, + + readAsDataURL: function(blob) { + return _read.call(this, 'readAsDataURL', blob); + }, + + /*readAsArrayBuffer: function(blob) { + return _read.call(this, 'readAsArrayBuffer', blob); + },*/ + + readAsText: function(blob) { + return _read.call(this, 'readAsText', blob); + } + }); + + function _read(op, blob) { + if (blob.isDetached()) { + var src = blob.getSource(); + switch (op) { + case 'readAsBinaryString': + return src; + case 'readAsDataURL': + return 'data:' + blob.type + ';base64,' + Encode.btoa(src); + case 'readAsText': + var txt = ''; + for (var i = 0, length = src.length; i < length; i++) { + txt += String.fromCharCode(src[i]); + } + return txt; + } + } else { + var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob); + this.disconnectRuntime(); + return result; + } + } + }; +}); + +// Included from: src/javascript/xhr/FormData.js + +/** + * FormData.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/xhr/FormData", [ + "moxie/core/Exceptions", + "moxie/core/utils/Basic", + "moxie/file/Blob" +], function(x, Basic, Blob) { + /** + FormData + + @class FormData + @constructor + */ + function FormData() { + var _blob, _fields = []; + + Basic.extend(this, { + /** + Append another key-value pair to the FormData object + + @method append + @param {String} name Name for the new field + @param {String|Blob|Array|Object} value Value for the field + */ + append: function(name, value) { + var self = this, valueType = Basic.typeOf(value); + + // according to specs value might be either Blob or String + if (value instanceof Blob) { + _blob = { + name: name, + value: value // unfortunately we can only send single Blob in one FormData + }; + } else if ('array' === valueType) { + name += '[]'; + + Basic.each(value, function(value) { + self.append(name, value); + }); + } else if ('object' === valueType) { + Basic.each(value, function(value, key) { + self.append(name + '[' + key + ']', value); + }); + } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) { + self.append(name, "false"); + } else { + _fields.push({ + name: name, + value: value.toString() + }); + } + }, + + /** + Checks if FormData contains Blob. + + @method hasBlob + @return {Boolean} + */ + hasBlob: function() { + return !!this.getBlob(); + }, + + /** + Retrieves blob. + + @method getBlob + @return {Object} Either Blob if found or null + */ + getBlob: function() { + return _blob && _blob.value || null; + }, + + /** + Retrieves blob field name. + + @method getBlobName + @return {String} Either Blob field name or null + */ + getBlobName: function() { + return _blob && _blob.name || null; + }, + + /** + Loop over the fields in FormData and invoke the callback for each of them. + + @method each + @param {Function} cb Callback to call for each field + */ + each: function(cb) { + Basic.each(_fields, function(field) { + cb(field.value, field.name); + }); + + if (_blob) { + cb(_blob.value, _blob.name); + } + }, + + destroy: function() { + _blob = null; + _fields = []; + } + }); + } + + return FormData; +}); + +// Included from: src/javascript/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/xhr/XMLHttpRequest", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/core/EventTarget", + "moxie/core/utils/Encode", + "moxie/core/utils/Url", + "moxie/runtime/Runtime", + "moxie/runtime/RuntimeTarget", + "moxie/file/Blob", + "moxie/file/FileReaderSync", + "moxie/xhr/FormData", + "moxie/core/utils/Env", + "moxie/core/utils/Mime" +], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) { + + var httpCode = { + 100: 'Continue', + 101: 'Switching Protocols', + 102: 'Processing', + + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 207: 'Multi-Status', + 226: 'IM Used', + + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 306: 'Reserved', + 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', + 422: 'Unprocessable Entity', + 423: 'Locked', + 424: 'Failed Dependency', + 426: 'Upgrade Required', + + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported', + 506: 'Variant Also Negotiates', + 507: 'Insufficient Storage', + 510: 'Not Extended' + }; + + function XMLHttpRequestUpload() { + this.uid = Basic.guid('uid_'); + } + + XMLHttpRequestUpload.prototype = EventTarget.instance; + + /** + Implementation of XMLHttpRequest + + @class XMLHttpRequest + @constructor + @uses RuntimeClient + @extends EventTarget + */ + var dispatches = ['loadstart', 'progress', 'abort', 'error', 'load', 'timeout', 'loadend']; // & readystatechange (for historical reasons) + + var NATIVE = 1, RUNTIME = 2; + + function XMLHttpRequest() { + var self = this, + // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible + props = { + /** + The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout. + + @property timeout + @type Number + @default 0 + */ + timeout: 0, + + /** + Current state, can take following values: + UNSENT (numeric value 0) + The object has been constructed. + + OPENED (numeric value 1) + The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method. + + HEADERS_RECEIVED (numeric value 2) + All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available. + + LOADING (numeric value 3) + The response entity body is being received. + + DONE (numeric value 4) + + @property readyState + @type Number + @default 0 (UNSENT) + */ + readyState: XMLHttpRequest.UNSENT, + + /** + True when user credentials are to be included in a cross-origin request. False when they are to be excluded + in a cross-origin request and when cookies are to be ignored in its response. Initially false. + + @property withCredentials + @type Boolean + @default false + */ + withCredentials: false, + + /** + Returns the HTTP status code. + + @property status + @type Number + @default 0 + */ + status: 0, + + /** + Returns the HTTP status text. + + @property statusText + @type String + */ + statusText: "", + + /** + Returns the response type. Can be set to change the response type. Values are: + the empty string (default), "arraybuffer", "blob", "document", "json", and "text". + + @property responseType + @type String + */ + responseType: "", + + /** + Returns the document response entity body. + + Throws an "InvalidStateError" exception if responseType is not the empty string or "document". + + @property responseXML + @type Document + */ + responseXML: null, + + /** + Returns the text response entity body. + + Throws an "InvalidStateError" exception if responseType is not the empty string or "text". + + @property responseText + @type String + */ + responseText: null, + + /** + Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body). + Can become: ArrayBuffer, Blob, Document, JSON, Text + + @property response + @type Mixed + */ + response: null + }, + + _async = true, + _url, + _method, + _headers = {}, + _user, + _password, + _encoding = null, + _mimeType = null, + + // flags + _sync_flag = false, + _send_flag = false, + _upload_events_flag = false, + _upload_complete_flag = false, + _error_flag = false, + _same_origin_flag = false, + + // times + _start_time, + _timeoutset_time, + + _finalMime = null, + _finalCharset = null, + + _options = {}, + _xhr, + _responseHeaders = '', + _responseHeadersBag + ; + + + Basic.extend(this, props, { + /** + Unique id of the component + + @property uid + @type String + */ + uid: Basic.guid('uid_'), + + /** + Target for Upload events + + @property upload + @type XMLHttpRequestUpload + */ + upload: new XMLHttpRequestUpload(), + + + /** + Sets the request method, request URL, synchronous flag, request username, and request password. + + Throws a "SyntaxError" exception if one of the following is true: + + method is not a valid HTTP method. + url cannot be resolved. + url contains the "user:password" format in the userinfo production. + Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK. + + Throws an "InvalidAccessError" exception if one of the following is true: + + Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin. + There is an associated XMLHttpRequest document and either the timeout attribute is not zero, + the withCredentials attribute is true, or the responseType attribute is not the empty string. + + + @method open + @param {String} method HTTP method to use on request + @param {String} url URL to request + @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default. + @param {String} [user] Username to use in HTTP authentication process on server-side + @param {String} [password] Password to use in HTTP authentication process on server-side + */ + open: function(method, url, async, user, password) { + var urlp; + + // first two arguments are required + if (!method || !url) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method + if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 3 + if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) { + _method = method.toUpperCase(); + } + + + // 4 - allowing these methods poses a security risk + if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) { + throw new x.DOMException(x.DOMException.SECURITY_ERR); + } + + // 5 + url = Encode.utf8_encode(url); + + // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError". + urlp = Url.parseUrl(url); + + _same_origin_flag = Url.hasSameOrigin(urlp); + + // 7 - manually build up absolute url + _url = Url.resolveUrl(url); + + // 9-10, 12-13 + if ((user || password) && !_same_origin_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + _user = user || urlp.user; + _password = password || urlp.pass; + + // 11 + _async = async || true; + + if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // 14 - terminate abort() + + // 15 - terminate send() + + // 18 + _sync_flag = !_async; + _send_flag = false; + _headers = {}; + _reset.call(this); + + // 19 + _p('readyState', XMLHttpRequest.OPENED); + + // 20 + this.convertEventPropsToHandlers(['readystatechange']); // unify event handlers + this.dispatchEvent('readystatechange'); + }, + + /** + Appends an header to the list of author request headers, or if header is already + in the list of author request headers, combines its value with value. + + Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. + Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value + is not a valid HTTP header field value. + + @method setRequestHeader + @param {String} header + @param {String|Number} value + */ + setRequestHeader: function(header, value) { + var uaHeaders = [ // these headers are controlled by the user agent + "accept-charset", + "accept-encoding", + "access-control-request-headers", + "access-control-request-method", + "connection", + "content-length", + "cookie", + "cookie2", + "content-transfer-encoding", + "date", + "expect", + "host", + "keep-alive", + "origin", + "referer", + "te", + "trailer", + "transfer-encoding", + "upgrade", + "user-agent", + "via" + ]; + + // 1-2 + if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 3 + if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 4 + /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values + if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + }*/ + + header = Basic.trim(header).toLowerCase(); + + // setting of proxy-* and sec-* headers is prohibited by spec + if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) { + return false; + } + + // camelize + // browsers lowercase header names (at least for custom ones) + // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); }); + + if (!_headers[header]) { + _headers[header] = value; + } else { + // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph) + _headers[header] += ', ' + value; + } + return true; + }, + + /** + Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2. + + @method getAllResponseHeaders + @return {String} reponse headers or empty string + */ + getAllResponseHeaders: function() { + return _responseHeaders || ''; + }, + + /** + Returns the header field value from the response of which the field name matches header, + unless the field name is Set-Cookie or Set-Cookie2. + + @method getResponseHeader + @param {String} header + @return {String} value(s) for the specified header or null + */ + getResponseHeader: function(header) { + header = header.toLowerCase(); + + if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) { + return null; + } + + if (_responseHeaders && _responseHeaders !== '') { + // if we didn't parse response headers until now, do it and keep for later + if (!_responseHeadersBag) { + _responseHeadersBag = {}; + Basic.each(_responseHeaders.split(/\r\n/), function(line) { + var pair = line.split(/:\s+/); + if (pair.length === 2) { // last line might be empty, omit + pair[0] = Basic.trim(pair[0]); // just in case + _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form + header: pair[0], + value: Basic.trim(pair[1]) + }; + } + }); + } + if (_responseHeadersBag.hasOwnProperty(header)) { + return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value; + } + } + return null; + }, + + /** + Sets the Content-Type header for the response to mime. + Throws an "InvalidStateError" exception if the state is LOADING or DONE. + Throws a "SyntaxError" exception if mime is not a valid media type. + + @method overrideMimeType + @param String mime Mime type to set + */ + overrideMimeType: function(mime) { + var matches, charset; + + // 1 + if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2 + mime = Basic.trim(mime.toLowerCase()); + + if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) { + mime = matches[1]; + if (matches[2]) { + charset = matches[2]; + } + } + + if (!Mime.mimes[mime]) { + throw new x.DOMException(x.DOMException.SYNTAX_ERR); + } + + // 3-4 + _finalMime = mime; + _finalCharset = charset; + }, + + /** + Initiates the request. The optional argument provides the request entity body. + The argument is ignored if request method is GET or HEAD. + + Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. + + @method send + @param {Blob|Document|String|FormData} [data] Request entity body + @param {Object} [options] Set of requirements and pre-requisities for runtime initialization + */ + send: function(data, options) { + if (Basic.typeOf(options) === 'string') { + _options = { ruid: options }; + } else if (!options) { + _options = {}; + } else { + _options = options; + } + + this.convertEventPropsToHandlers(dispatches); + this.upload.convertEventPropsToHandlers(dispatches); + + // 1-2 + if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 3 + // sending Blob + if (data instanceof Blob) { + _options.ruid = data.ruid; + _mimeType = data.type || 'application/octet-stream'; + } + + // FormData + else if (data instanceof FormData) { + if (data.hasBlob()) { + var blob = data.getBlob(); + _options.ruid = blob.ruid; + _mimeType = blob.type || 'application/octet-stream'; + } + } + + // DOMString + else if (typeof data === 'string') { + _encoding = 'UTF-8'; + _mimeType = 'text/plain;charset=UTF-8'; + + // data should be converted to Unicode and encoded as UTF-8 + data = Encode.utf8_encode(data); + } + + // if withCredentials not set, but requested, set it automatically + if (!this.withCredentials) { + this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag; + } + + // 4 - storage mutex + // 5 + _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP + // 6 + _error_flag = false; + // 7 + _upload_complete_flag = !data; + // 8 - Asynchronous steps + if (!_sync_flag) { + // 8.1 + _send_flag = true; + // 8.2 + // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr + // 8.3 + //if (!_upload_complete_flag) { + // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr + //} + } + // 8.5 - Return the send() method call, but continue running the steps in this algorithm. + _doXHR.call(this, data); + }, + + /** + Cancels any network activity. + + @method abort + */ + abort: function() { + _error_flag = true; + _sync_flag = false; + + if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) { + _p('readyState', XMLHttpRequest.DONE); + _send_flag = false; + + if (_xhr) { + _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag); + } else { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + _upload_complete_flag = true; + } else { + _p('readyState', XMLHttpRequest.UNSENT); + } + }, + + destroy: function() { + if (_xhr) { + if (Basic.typeOf(_xhr.destroy) === 'function') { + _xhr.destroy(); + } + _xhr = null; + } + + this.unbindAll(); + + if (this.upload) { + this.upload.unbindAll(); + this.upload = null; + } + } + }); + + /* this is nice, but maybe too lengthy + + // if supported by JS version, set getters/setters for specific properties + o.defineProperty(this, 'readyState', { + configurable: false, + + get: function() { + return _p('readyState'); + } + }); + + o.defineProperty(this, 'timeout', { + configurable: false, + + get: function() { + return _p('timeout'); + }, + + set: function(value) { + + if (_sync_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // timeout still should be measured relative to the start time of request + _timeoutset_time = (new Date).getTime(); + + _p('timeout', value); + } + }); + + // the withCredentials attribute has no effect when fetching same-origin resources + o.defineProperty(this, 'withCredentials', { + configurable: false, + + get: function() { + return _p('withCredentials'); + }, + + set: function(value) { + // 1-2 + if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 3-4 + if (_anonymous_flag || _sync_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // 5 + _p('withCredentials', value); + } + }); + + o.defineProperty(this, 'status', { + configurable: false, + + get: function() { + return _p('status'); + } + }); + + o.defineProperty(this, 'statusText', { + configurable: false, + + get: function() { + return _p('statusText'); + } + }); + + o.defineProperty(this, 'responseType', { + configurable: false, + + get: function() { + return _p('responseType'); + }, + + set: function(value) { + // 1 + if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2 + if (_sync_flag) { + throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); + } + + // 3 + _p('responseType', value.toLowerCase()); + } + }); + + o.defineProperty(this, 'responseText', { + configurable: false, + + get: function() { + // 1 + if (!~o.inArray(_p('responseType'), ['', 'text'])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2-3 + if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + return _p('responseText'); + } + }); + + o.defineProperty(this, 'responseXML', { + configurable: false, + + get: function() { + // 1 + if (!~o.inArray(_p('responseType'), ['', 'document'])) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // 2-3 + if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + return _p('responseXML'); + } + }); + + o.defineProperty(this, 'response', { + configurable: false, + + get: function() { + if (!!~o.inArray(_p('responseType'), ['', 'text'])) { + if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { + return ''; + } + } + + if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { + return null; + } + + return _p('response'); + } + }); + + */ + + function _p(prop, value) { + if (!props.hasOwnProperty(prop)) { + return; + } + if (arguments.length === 1) { // get + return Env.can('define_property') ? props[prop] : self[prop]; + } else { // set + if (Env.can('define_property')) { + props[prop] = value; + } else { + self[prop] = value; + } + } + } + + /* + function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) { + // TODO: http://tools.ietf.org/html/rfc3490#section-4.1 + return str.toLowerCase(); + } + */ + + + function _doXHR(data) { + var self = this; + + _start_time = new Date().getTime(); + + _xhr = new RuntimeTarget(); + + function loadEnd() { + _xhr.destroy(); + _xhr = null; + self.dispatchEvent('loadend'); + self = null; + } + + function exec(runtime) { + _xhr.bind('LoadStart', function(e) { + _p('readyState', XMLHttpRequest.LOADING); + self.dispatchEvent('readystatechange'); + + self.dispatchEvent(e); + + if (_upload_events_flag) { + self.upload.dispatchEvent(e); + } + }); + + _xhr.bind('Progress', function(e) { + if (_p('readyState') !== XMLHttpRequest.LOADING) { + _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example) + self.dispatchEvent('readystatechange'); + } + self.dispatchEvent(e); + }); + + _xhr.bind('UploadProgress', function(e) { + if (_upload_events_flag) { + self.upload.dispatchEvent({ + type: 'progress', + lengthComputable: false, + total: e.total, + loaded: e.loaded + }); + } + }); + + _xhr.bind('Load', function(e) { + _p('readyState', XMLHttpRequest.DONE); + _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0)); + _p('statusText', httpCode[_p('status')] || ""); + + _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType'))); + + if (!!~Basic.inArray(_p('responseType'), ['text', ''])) { + _p('responseText', _p('response')); + } else if (_p('responseType') === 'document') { + _p('responseXML', _p('response')); + } + + _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders'); + + self.dispatchEvent('readystatechange'); + + if (_p('status') > 0) { // status 0 usually means that server is unreachable + if (_upload_events_flag) { + self.upload.dispatchEvent(e); + } + self.dispatchEvent(e); + } else { + _error_flag = true; + self.dispatchEvent('error'); + } + loadEnd(); + }); + + _xhr.bind('Abort', function(e) { + self.dispatchEvent(e); + loadEnd(); + }); + + _xhr.bind('Error', function(e) { + _error_flag = true; + _p('readyState', XMLHttpRequest.DONE); + self.dispatchEvent('readystatechange'); + _upload_complete_flag = true; + self.dispatchEvent(e); + loadEnd(); + }); + + runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', { + url: _url, + method: _method, + async: _async, + user: _user, + password: _password, + headers: _headers, + mimeType: _mimeType, + encoding: _encoding, + responseType: self.responseType, + withCredentials: self.withCredentials, + options: _options + }, data); + } + + // clarify our requirements + if (typeof(_options.required_caps) === 'string') { + _options.required_caps = Runtime.parseCaps(_options.required_caps); + } + + _options.required_caps = Basic.extend({}, _options.required_caps, { + return_response_type: self.responseType + }); + + if (data instanceof FormData) { + _options.required_caps.send_multipart = true; + } + + if (!_same_origin_flag) { + _options.required_caps.do_cors = true; + } + + + if (_options.ruid) { // we do not need to wait if we can connect directly + exec(_xhr.connectRuntime(_options)); + } else { + _xhr.bind('RuntimeInit', function(e, runtime) { + exec(runtime); + }); + _xhr.bind('RuntimeError', function(e, err) { + self.dispatchEvent('RuntimeError', err); + }); + _xhr.connectRuntime(_options); + } + } + + + function _reset() { + _p('responseText', ""); + _p('responseXML', null); + _p('response', null); + _p('status', 0); + _p('statusText', ""); + _start_time = _timeoutset_time = null; + } + } + + XMLHttpRequest.UNSENT = 0; + XMLHttpRequest.OPENED = 1; + XMLHttpRequest.HEADERS_RECEIVED = 2; + XMLHttpRequest.LOADING = 3; + XMLHttpRequest.DONE = 4; + + XMLHttpRequest.prototype = EventTarget.instance; + + return XMLHttpRequest; +}); + +// Included from: src/javascript/runtime/Transporter.js + +/** + * Transporter.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/runtime/Transporter", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Encode", + "moxie/runtime/RuntimeClient", + "moxie/core/EventTarget" +], function(Basic, Encode, RuntimeClient, EventTarget) { + function Transporter() { + var mod, _runtime, _data, _size, _pos, _chunk_size; + + RuntimeClient.call(this); + + Basic.extend(this, { + uid: Basic.guid('uid_'), + + state: Transporter.IDLE, + + result: null, + + transport: function(data, type, options) { + var self = this; + + options = Basic.extend({ + chunk_size: 204798 + }, options); + + // should divide by three, base64 requires this + if ((mod = options.chunk_size % 3)) { + options.chunk_size += 3 - mod; + } + + _chunk_size = options.chunk_size; + + _reset.call(this); + _data = data; + _size = data.length; + + if (Basic.typeOf(options) === 'string' || options.ruid) { + _run.call(self, type, this.connectRuntime(options)); + } else { + // we require this to run only once + var cb = function(e, runtime) { + self.unbind("RuntimeInit", cb); + _run.call(self, type, runtime); + }; + this.bind("RuntimeInit", cb); + this.connectRuntime(options); + } + }, + + abort: function() { + var self = this; + + self.state = Transporter.IDLE; + if (_runtime) { + _runtime.exec.call(self, 'Transporter', 'clear'); + self.trigger("TransportingAborted"); + } + + _reset.call(self); + }, + + + destroy: function() { + this.unbindAll(); + _runtime = null; + this.disconnectRuntime(); + _reset.call(this); + } + }); + + function _reset() { + _size = _pos = 0; + _data = this.result = null; + } + + function _run(type, runtime) { + var self = this; + + _runtime = runtime; + + //self.unbind("RuntimeInit"); + + self.bind("TransportingProgress", function(e) { + _pos = e.loaded; + + if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) { + _transport.call(self); + } + }, 999); + + self.bind("TransportingComplete", function() { + _pos = _size; + self.state = Transporter.DONE; + _data = null; // clean a bit + self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || ''); + }, 999); + + self.state = Transporter.BUSY; + self.trigger("TransportingStarted"); + _transport.call(self); + } + + function _transport() { + var self = this, + chunk, + bytesLeft = _size - _pos; + + if (_chunk_size > bytesLeft) { + _chunk_size = bytesLeft; + } + + chunk = Encode.btoa(_data.substr(_pos, _chunk_size)); + _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size); + } + } + + Transporter.IDLE = 0; + Transporter.BUSY = 1; + Transporter.DONE = 2; + + Transporter.prototype = EventTarget.instance; + + return Transporter; +}); + +// Included from: src/javascript/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define("moxie/image/Image", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/Exceptions", + "moxie/file/FileReaderSync", + "moxie/xhr/XMLHttpRequest", + "moxie/runtime/Runtime", + "moxie/runtime/RuntimeClient", + "moxie/runtime/Transporter", + "moxie/core/utils/Env", + "moxie/core/EventTarget", + "moxie/file/Blob", + "moxie/file/File", + "moxie/core/utils/Encode" +], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) { + /** + Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data. + + @class Image + @constructor + @extends EventTarget + */ + var dispatches = [ + 'progress', + + /** + Dispatched when loading is complete. + + @event load + @param {Object} event + */ + 'load', + + 'error', + + /** + Dispatched when resize operation is complete. + + @event resize + @param {Object} event + */ + 'resize', + + /** + Dispatched when visual representation of the image is successfully embedded + into the corresponsing container. + + @event embedded + @param {Object} event + */ + 'embedded' + ]; + + function Image() { + RuntimeClient.call(this); + + Basic.extend(this, { + /** + Unique id of the component + + @property uid + @type {String} + */ + uid: Basic.guid('uid_'), + + /** + Unique id of the connected runtime, if any. + + @property ruid + @type {String} + */ + ruid: null, + + /** + Name of the file, that was used to create an image, if available. If not equals to empty string. + + @property name + @type {String} + @default "" + */ + name: "", + + /** + Size of the image in bytes. Actual value is set only after image is preloaded. + + @property size + @type {Number} + @default 0 + */ + size: 0, + + /** + Width of the image. Actual value is set only after image is preloaded. + + @property width + @type {Number} + @default 0 + */ + width: 0, + + /** + Height of the image. Actual value is set only after image is preloaded. + + @property height + @type {Number} + @default 0 + */ + height: 0, + + /** + Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded. + + @property type + @type {String} + @default "" + */ + type: "", + + /** + Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded. + + @property meta + @type {Object} + @default {} + */ + meta: {}, + + /** + Alias for load method, that takes another mOxie.Image object as a source (see load). + + @method clone + @param {Image} src Source for the image + @param {Boolean} [exact=false] Whether to activate in-depth clone mode + */ + clone: function() { + this.load.apply(this, arguments); + }, + + /** + Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File, + native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL, + Image will be downloaded from remote destination and loaded in memory. + + @example + var img = new mOxie.Image(); + img.onload = function() { + var blob = img.getAsBlob(); + + var formData = new mOxie.FormData(); + formData.append('file', blob); + + var xhr = new mOxie.XMLHttpRequest(); + xhr.onload = function() { + // upload complete + }; + xhr.open('post', 'upload.php'); + xhr.send(formData); + }; + img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg) + + + @method load + @param {Image|Blob|File|String} src Source for the image + @param {Boolean|Object} [mixed] + */ + load: function() { + // this is here because to bind properly we need an uid first, which is created above + this.bind('Load Resize', function() { + _updateInfo.call(this); + }, 999); + + this.convertEventPropsToHandlers(dispatches); + + _load.apply(this, arguments); + }, + + /** + Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions. + + @method downsize + @param {Number} width Resulting width + @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) + @param {Boolean} [crop=false] Whether to crop the image to exact dimensions + @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) + */ + downsize: function(width, height, crop, preserveHeaders) { + try { + if (!this.size) { // only preloaded image objects can be used as source + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + // no way to reliably intercept the crash due to high resolution, so we simply avoid it + if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { + throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); + } + + if (!width && !height || Basic.typeOf(crop) === 'undefined') { + crop = false; + } + + width = width || this.width; + height = height || this.height; + + preserveHeaders = (Basic.typeOf(preserveHeaders) === 'undefined' ? true : !!preserveHeaders); + + this.getRuntime().exec.call(this, 'Image', 'downsize', width, height, crop, preserveHeaders); + } catch(ex) { + // for now simply trigger error event + this.trigger('error', ex); + } + }, + + /** + Alias for downsize(width, height, true). (see downsize) + + @method crop + @param {Number} width Resulting width + @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) + @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) + */ + crop: function(width, height, preserveHeaders) { + this.downsize(width, height, true, preserveHeaders); + }, + + getAsCanvas: function() { + if (!Env.can('create_canvas')) { + throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); + } + + var runtime = this.connectRuntime(this.ruid); + return runtime.exec.call(this, 'Image', 'getAsCanvas'); + }, + + /** + Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws + DOMException.INVALID_STATE_ERR). + + @method getAsBlob + @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png + @param {Number} [quality=90] Applicable only together with mime type image/jpeg + @return {Blob} Image as Blob + */ + getAsBlob: function(type, quality) { + if (!this.size) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + if (!type) { + type = 'image/jpeg'; + } + + if (type === 'image/jpeg' && !quality) { + quality = 90; + } + + return this.getRuntime().exec.call(this, 'Image', 'getAsBlob', type, quality); + }, + + /** + Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws + DOMException.INVALID_STATE_ERR). + + @method getAsDataURL + @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png + @param {Number} [quality=90] Applicable only together with mime type image/jpeg + @return {String} Image as dataURL string + */ + getAsDataURL: function(type, quality) { + if (!this.size) { + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + return this.getRuntime().exec.call(this, 'Image', 'getAsDataURL', type, quality); + }, + + /** + Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws + DOMException.INVALID_STATE_ERR). + + @method getAsBinaryString + @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png + @param {Number} [quality=90] Applicable only together with mime type image/jpeg + @return {String} Image as binary string + */ + getAsBinaryString: function(type, quality) { + var dataUrl = this.getAsDataURL(type, quality); + return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)); + }, + + /** + Embeds the image, or better to say, it's visual representation into the specified node. Depending on the runtime + in use, might be a canvas, or image (actual ) element or shim object (Flash or SilverLight - very rare, used for + legacy browsers that do not have canvas or proper dataURI support). + + @method embed + @param {DOMElement} el DOM element to insert the image object into + @param {Object} options Set of key/value pairs controlling the mime type, dimensions and cropping factor of resulting + representation + */ + embed: function(el) { + var self = this + , imgCopy + , type, quality, crop + , options = arguments[1] || {} + , width = this.width + , height = this.height + , runtime // this has to be outside of all the closures to contain proper runtime + ; + + function onResize() { + // if possible, embed a canvas element directly + if (Env.can('create_canvas')) { + var canvas = imgCopy.getAsCanvas(); + if (canvas) { + el.appendChild(canvas); + canvas = null; + imgCopy.destroy(); + self.trigger('embedded'); + return; + } + } + + var dataUrl = imgCopy.getAsDataURL(type, quality); + if (!dataUrl) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + + if (Env.can('use_data_uri_of', dataUrl.length)) { + el.innerHTML = ''; + imgCopy.destroy(); + self.trigger('embedded'); + } else { + var tr = new Transporter(); + + tr.bind("TransportingComplete", function() { + runtime = self.connectRuntime(this.result.ruid); + + self.bind("Embedded", function() { + // position and size properly + Basic.extend(runtime.getShimContainer().style, { + //position: 'relative', + top: '0px', + left: '0px', + width: imgCopy.width + 'px', + height: imgCopy.height + 'px' + }); + + // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's + // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and + // sometimes 8 and they do not have this problem, we can comment this for now + /*tr.bind("RuntimeInit", function(e, runtime) { + tr.destroy(); + runtime.destroy(); + onResize.call(self); // re-feed our image data + });*/ + + runtime = null; + }, 999); + + runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height); + imgCopy.destroy(); + }); + + tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, Basic.extend({}, options, { + required_caps: { + display_media: true + }, + runtime_order: 'flash,silverlight', + container: el + })); + } + } + + try { + if (!(el = Dom.get(el))) { + throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR); + } + + if (!this.size) { // only preloaded image objects can be used as source + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + + if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { + throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); + } + + type = options.type || this.type || 'image/jpeg'; + quality = options.quality || 90; + crop = Basic.typeOf(options.crop) !== 'undefined' ? options.crop : false; + + // figure out dimensions for the thumb + if (options.width) { + width = options.width; + height = options.height || width; + } else { + // if container element has > 0 dimensions, take them + var dimensions = Dom.getSize(el); + if (dimensions.w && dimensions.h) { // both should be > 0 + width = dimensions.w; + height = dimensions.h; + } + } + + imgCopy = new Image(); + + imgCopy.bind("Resize", function() { + onResize.call(self); + }); + + imgCopy.bind("Load", function() { + imgCopy.downsize(width, height, crop, false); + }); + + imgCopy.clone(this, false); + + return imgCopy; + } catch(ex) { + // for now simply trigger error event + this.trigger('error', ex); + } + }, + + /** + Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object. + + @method destroy + */ + destroy: function() { + if (this.ruid) { + this.getRuntime().exec.call(this, 'Image', 'destroy'); + this.disconnectRuntime(); + } + this.unbindAll(); + } + }); + + + function _updateInfo(info) { + if (!info) { + info = this.getRuntime().exec.call(this, 'Image', 'getInfo'); + } + + this.size = info.size; + this.width = info.width; + this.height = info.height; + this.type = info.type; + this.meta = info.meta; + + // update file name, only if empty + if (this.name === '') { + this.name = info.name; + } + } + + + function _load(src) { + var srcType = Basic.typeOf(src); + + try { + // if source is Image + if (src instanceof Image) { + if (!src.size) { // only preloaded image objects can be used as source + throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); + } + _loadFromImage.apply(this, arguments); + } + // if source is o.Blob/o.File + else if (src instanceof Blob) { + if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + _loadFromBlob.apply(this, arguments); + } + // if native blob/file + else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) { + _load.call(this, new File(null, src), arguments[1]); + } + // if String + else if (srcType === 'string') { + // if dataUrl String + if (/^data:[^;]*;base64,/.test(src)) { + _load.call(this, new Blob(null, { data: src }), arguments[1]); + } + // else assume Url, either relative or absolute + else { + _loadFromUrl.apply(this, arguments); + } + } + // if source seems to be an img node + else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') { + _load.call(this, src.src, arguments[1]); + } + else { + throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR); + } + } catch(ex) { + // for now simply trigger error event + this.trigger('error', ex); + } + } + + + function _loadFromImage(img, exact) { + var runtime = this.connectRuntime(img.ruid); + this.ruid = runtime.uid; + runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact)); + } + + + function _loadFromBlob(blob, options) { + var self = this; + + self.name = blob.name || ''; + + function exec(runtime) { + self.ruid = runtime.uid; + runtime.exec.call(self, 'Image', 'loadFromBlob', blob); + } + + if (blob.isDetached()) { + this.bind('RuntimeInit', function(e, runtime) { + exec(runtime); + }); + + // convert to object representation + if (options && typeof(options.required_caps) === 'string') { + options.required_caps = Runtime.parseCaps(options.required_caps); + } + + this.connectRuntime(Basic.extend({ + required_caps: { + access_image_binary: true, + resize_image: true + } + }, options)); + } else { + exec(this.connectRuntime(blob.ruid)); + } + } + + + function _loadFromUrl(url, options) { + var self = this, xhr; + + xhr = new XMLHttpRequest(); + + xhr.open('get', url); + xhr.responseType = 'blob'; + + xhr.onprogress = function(e) { + self.trigger(e); + }; + + xhr.onload = function() { + _loadFromBlob.call(self, xhr.response, true); + }; + + xhr.onerror = function(e) { + self.trigger(e); + }; + + xhr.onloadend = function() { + xhr.destroy(); + }; + + xhr.bind('RuntimeError', function(e, err) { + self.trigger('RuntimeError', err); + }); + + xhr.send(null, options); + } + } + + // virtual world will crash on you if image has a resolution higher than this: + Image.MAX_RESIZE_WIDTH = 6500; + Image.MAX_RESIZE_HEIGHT = 6500; + + Image.prototype = EventTarget.instance; + + return Image; +}); + +// Included from: src/javascript/runtime/html5/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global File:true */ + +/** +Defines constructor for HTML5 runtime. + +@class moxie/runtime/html5/Runtime +@private +*/ +define("moxie/runtime/html5/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/Runtime", + "moxie/core/utils/Env" +], function(Basic, x, Runtime, Env) { + + var type = "html5", extensions = {}; + + function Html5Runtime(options) { + var I = this + , Test = Runtime.capTest + , True = Runtime.capTrue + ; + + var caps = Basic.extend({ + access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL), + access_image_binary: function() { + return I.can('access_binary') && !!extensions.Image; + }, + display_media: Test(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')), + do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()), + drag_and_drop: Test(function() { + // this comes directly from Modernizr: http://www.modernizr.com/ + var div = document.createElement('div'); + // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop + return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && (Env.browser !== 'IE' || Env.version > 9); + }()), + filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest + return (Env.browser === 'Chrome' && Env.version >= 28) || (Env.browser === 'IE' && Env.version >= 10); + }()), + return_response_headers: True, + return_response_type: function(responseType) { + if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported + return true; + } + return Env.can('return_response_type', responseType); + }, + return_status_code: True, + report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload), + resize_image: function() { + return I.can('access_binary') && Env.can('create_canvas'); + }, + select_file: function() { + return Env.can('use_fileinput') && window.File; + }, + select_folder: function() { + return I.can('select_file') && Env.browser === 'Chrome' && Env.version >= 21; + }, + select_multiple: function() { + // it is buggy on Safari Windows and iOS + return I.can('select_file') && + !(Env.browser === 'Safari' && Env.os === 'Windows') && + !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.4", '<')); + }, + send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))), + send_custom_headers: Test(window.XMLHttpRequest), + send_multipart: function() { + return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string'); + }, + slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)), + stream_upload: function(){ + return I.can('slice_blob') && I.can('send_multipart'); + }, + summon_file_dialog: Test(function() { // yeah... some dirty sniffing here... + return (Env.browser === 'Firefox' && Env.version >= 4) || + (Env.browser === 'Opera' && Env.version >= 12) || + (Env.browser === 'IE' && Env.version >= 10) || + !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']); + }()), + upload_filesize: True + }, + arguments[2] + ); + + Runtime.call(this, options, (arguments[1] || type), caps); + + + Basic.extend(this, { + + init : function() { + this.trigger("Init"); + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + destroy = I = null; + }; + }(this.destroy)) + }); + + Basic.extend(this.getShim(), extensions); + } + + Runtime.addConstructor(type, Html5Runtime); + + return extensions; +}); + +// Included from: src/javascript/runtime/html5/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/Blob +@private +*/ +define("moxie/runtime/html5/file/Blob", [ + "moxie/runtime/html5/Runtime", + "moxie/file/Blob" +], function(extensions, Blob) { + + function HTML5Blob() { + function w3cBlobSlice(blob, start, end) { + var blobSlice; + + if (window.File.prototype.slice) { + try { + blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception + return blob.slice(start, end); + } catch (e) { + // depricated slice method + return blob.slice(start, end - start); + } + // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672 + } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) { + return blobSlice.call(blob, start, end); + } else { + return null; // or throw some exception + } + } + + this.slice = function() { + return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments)); + }; + } + + return (extensions.Blob = HTML5Blob); +}); + +// Included from: src/javascript/core/utils/Events.js + +/** + * Events.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +define('moxie/core/utils/Events', [ + 'moxie/core/utils/Basic' +], function(Basic) { + var eventhash = {}, uid = 'moxie_' + Basic.guid(); + + // IE W3C like event funcs + function preventDefault() { + this.returnValue = false; + } + + function stopPropagation() { + this.cancelBubble = true; + } + + /** + Adds an event handler to the specified object and store reference to the handler + in objects internal Plupload registry (@see removeEvent). + + @method addEvent + @for Utils + @static + @param {Object} obj DOM element like object to add handler to. + @param {String} name Name to add event listener to. + @param {Function} callback Function to call when event occurs. + @param {String} [key] that might be used to add specifity to the event record. + */ + var addEvent = function(obj, name, callback, key) { + var func, events; + + name = name.toLowerCase(); + + // Add event listener + if (obj.addEventListener) { + func = callback; + + obj.addEventListener(name, func, false); + } else if (obj.attachEvent) { + func = function() { + var evt = window.event; + + if (!evt.target) { + evt.target = evt.srcElement; + } + + evt.preventDefault = preventDefault; + evt.stopPropagation = stopPropagation; + + callback(evt); + }; + + obj.attachEvent('on' + name, func); + } + + // Log event handler to objects internal mOxie registry + if (!obj[uid]) { + obj[uid] = Basic.guid(); + } + + if (!eventhash.hasOwnProperty(obj[uid])) { + eventhash[obj[uid]] = {}; + } + + events = eventhash[obj[uid]]; + + if (!events.hasOwnProperty(name)) { + events[name] = []; + } + + events[name].push({ + func: func, + orig: callback, // store original callback for IE + key: key + }); + }; + + + /** + Remove event handler from the specified object. If third argument (callback) + is not specified remove all events with the specified name. + + @method removeEvent + @static + @param {Object} obj DOM element to remove event listener(s) from. + @param {String} name Name of event listener to remove. + @param {Function|String} [callback] might be a callback or unique key to match. + */ + var removeEvent = function(obj, name, callback) { + var type, undef; + + name = name.toLowerCase(); + + if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) { + type = eventhash[obj[uid]][name]; + } else { + return; + } + + for (var i = type.length - 1; i >= 0; i--) { + // undefined or not, key should match + if (type[i].orig === callback || type[i].key === callback) { + if (obj.removeEventListener) { + obj.removeEventListener(name, type[i].func, false); + } else if (obj.detachEvent) { + obj.detachEvent('on'+name, type[i].func); + } + + type[i].orig = null; + type[i].func = null; + type.splice(i, 1); + + // If callback was passed we are done here, otherwise proceed + if (callback !== undef) { + break; + } + } + } + + // If event array got empty, remove it + if (!type.length) { + delete eventhash[obj[uid]][name]; + } + + // If mOxie registry has become empty, remove it + if (Basic.isEmptyObj(eventhash[obj[uid]])) { + delete eventhash[obj[uid]]; + + // IE doesn't let you remove DOM object property with - delete + try { + delete obj[uid]; + } catch(e) { + obj[uid] = undef; + } + } + }; + + + /** + Remove all kind of events from the specified object + + @method removeAllEvents + @static + @param {Object} obj DOM element to remove event listeners from. + @param {String} [key] unique key to match, when removing events. + */ + var removeAllEvents = function(obj, key) { + if (!obj || !obj[uid]) { + return; + } + + Basic.each(eventhash[obj[uid]], function(events, name) { + removeEvent(obj, name, key); + }); + }; + + return { + addEvent: addEvent, + removeEvent: removeEvent, + removeAllEvents: removeAllEvents + }; +}); + +// Included from: src/javascript/runtime/html5/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/FileInput +@private +*/ +define("moxie/runtime/html5/file/FileInput", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Events", + "moxie/core/utils/Mime", + "moxie/core/utils/Env" +], function(extensions, Basic, Dom, Events, Mime, Env) { + + function FileInput() { + var _files = [], _options; + + Basic.extend(this, { + init: function(options) { + var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top; + + _options = options; + _files = []; + + // figure out accept string + mimes = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension')); + + shimContainer = I.getShimContainer(); + + shimContainer.innerHTML = ''; + + input = Dom.get(I.uid); + + // prepare file input to be placed underneath the browse_button element + Basic.extend(input.style, { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' + }); + + + browseButton = Dom.get(_options.browse_button); + + // Route click event to the input[type=file] element for browsers that support such behavior + if (I.can('summon_file_dialog')) { + if (Dom.getStyle(browseButton, 'position') === 'static') { + browseButton.style.position = 'relative'; + } + + zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; + + browseButton.style.zIndex = zIndex; + shimContainer.style.zIndex = zIndex - 1; + + Events.addEvent(browseButton, 'click', function(e) { + var input = Dom.get(I.uid); + if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] + input.click(); + } + e.preventDefault(); + }, comp.uid); + } + + /* Since we have to place input[type=file] on top of the browse_button for some browsers, + browse_button loses interactivity, so we restore it here */ + top = I.can('summon_file_dialog') ? browseButton : shimContainer; + + Events.addEvent(top, 'mouseover', function() { + comp.trigger('mouseenter'); + }, comp.uid); + + Events.addEvent(top, 'mouseout', function() { + comp.trigger('mouseleave'); + }, comp.uid); + + Events.addEvent(top, 'mousedown', function() { + comp.trigger('mousedown'); + }, comp.uid); + + Events.addEvent(Dom.get(_options.container), 'mouseup', function() { + comp.trigger('mouseup'); + }, comp.uid); + + + input.onchange = function onChange() { // there should be only one handler for this + _files = []; + + if (_options.directory) { + // folders are represented by dots, filter them out (Chrome 11+) + Basic.each(this.files, function(file) { + if (file.name !== ".") { // if it doesn't looks like a folder + _files.push(file); + } + }); + } else { + _files = [].slice.call(this.files); + } + + // clearing the value enables the user to select the same file again if they want to + if (Env.browser !== 'IE') { + this.value = ''; + } else { + // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it + var clone = this.cloneNode(true); + this.parentNode.replaceChild(clone, this); + clone.onchange = onChange; + } + comp.trigger('change'); + }; + + // ready event is perfectly asynchronous + comp.trigger({ + type: 'ready', + async: true + }); + + shimContainer = null; + }, + + getFiles: function() { + return _files; + }, + + disable: function(state) { + var I = this.getRuntime(), input; + + if ((input = Dom.get(I.uid))) { + input.disabled = !!state; + } + }, + + destroy: function() { + var I = this.getRuntime() + , shim = I.getShim() + , shimContainer = I.getShimContainer() + ; + + Events.removeAllEvents(shimContainer, this.uid); + Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); + Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid); + + if (shimContainer) { + shimContainer.innerHTML = ''; + } + + shim.removeInstance(this.uid); + + _files = _options = shimContainer = shim = null; + } + }); + } + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/html5/file/FileDrop.js + +/** + * FileDrop.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/FileDrop +@private +*/ +define("moxie/runtime/html5/file/FileDrop", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Events", + "moxie/core/utils/Mime" +], function(extensions, Basic, Dom, Events, Mime) { + + function FileDrop() { + var _files = [], _allowedExts = [], _options; + + Basic.extend(this, { + init: function(options) { + var comp = this, dropZone; + + _options = options; + _allowedExts = _extractExts(_options.accept); + dropZone = _options.container; + + Events.addEvent(dropZone, 'dragover', function(e) { + e.preventDefault(); + e.stopPropagation(); + e.dataTransfer.dropEffect = 'copy'; + }, comp.uid); + + Events.addEvent(dropZone, 'drop', function(e) { + e.preventDefault(); + e.stopPropagation(); + + _files = []; + + // Chrome 21+ accepts folders via Drag'n'Drop + if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) { + _readItems(e.dataTransfer.items, function() { + comp.trigger("drop"); + }); + } else { + Basic.each(e.dataTransfer.files, function(file) { + if (_isAcceptable(file)) { + _files.push(file); + } + }); + comp.trigger("drop"); + } + }, comp.uid); + + Events.addEvent(dropZone, 'dragenter', function(e) { + e.preventDefault(); + e.stopPropagation(); + comp.trigger("dragenter"); + }, comp.uid); + + Events.addEvent(dropZone, 'dragleave', function(e) { + e.preventDefault(); + e.stopPropagation(); + comp.trigger("dragleave"); + }, comp.uid); + }, + + getFiles: function() { + return _files; + }, + + destroy: function() { + Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); + _files = _allowedExts = _options = null; + } + }); + + + function _extractExts(accept) { + var exts = []; + for (var i = 0; i < accept.length; i++) { + [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/)); + } + return Basic.inArray('*', exts) === -1 ? exts : []; + } + + + function _isAcceptable(file) { + var ext = Mime.getFileExtension(file.name); + return !ext || !_allowedExts.length || Basic.inArray(ext, _allowedExts) !== -1; + } + + + function _readItems(items, cb) { + var entries = []; + Basic.each(items, function(item) { + var entry = item.webkitGetAsEntry(); + // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579) + if (entry) { + // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61 + if (entry.isFile) { + var file = item.getAsFile(); + if (_isAcceptable(file)) { + _files.push(file); + } + } else { + entries.push(entry); + } + } + }); + + if (entries.length) { + _readEntries(entries, cb); + } else { + cb(); + } + } + + + function _readEntries(entries, cb) { + var queue = []; + Basic.each(entries, function(entry) { + queue.push(function(cbcb) { + _readEntry(entry, cbcb); + }); + }); + Basic.inSeries(queue, function() { + cb(); + }); + } + + function _readEntry(entry, cb) { + if (entry.isFile) { + entry.file(function(file) { + if (_isAcceptable(file)) { + _files.push(file); + } + cb(); + }, function() { + // fire an error event maybe + cb(); + }); + } else if (entry.isDirectory) { + _readDirEntry(entry, cb); + } else { + cb(); // not file, not directory? what then?.. + } + } + + function _readDirEntry(dirEntry, cb) { + var entries = [], dirReader = dirEntry.createReader(); + + // keep quering recursively till no more entries + function getEntries(cbcb) { + dirReader.readEntries(function(moreEntries) { + if (moreEntries.length) { + [].push.apply(entries, moreEntries); + getEntries(cbcb); + } else { + cbcb(); + } + }, cbcb); + } + + // ...and you thought FileReader was crazy... + getEntries(function() { + _readEntries(entries, cb); + }); + } + } + + return (extensions.FileDrop = FileDrop); +}); + +// Included from: src/javascript/runtime/html5/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/file/FileReader +@private +*/ +define("moxie/runtime/html5/file/FileReader", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Encode", + "moxie/core/utils/Basic" +], function(extensions, Encode, Basic) { + + function FileReader() { + var _fr, _convertToBinary = false; + + Basic.extend(this, { + + read: function(op, blob) { + var target = this; + + _fr = new window.FileReader(); + + _fr.addEventListener('progress', function(e) { + target.trigger(e); + }); + + _fr.addEventListener('load', function(e) { + target.trigger(e); + }); + + _fr.addEventListener('error', function(e) { + target.trigger(e, _fr.error); + }); + + _fr.addEventListener('loadend', function() { + _fr = null; + }); + + if (Basic.typeOf(_fr[op]) === 'function') { + _convertToBinary = false; + _fr[op](blob.getSource()); + } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+ + _convertToBinary = true; + _fr.readAsDataURL(blob.getSource()); + } + }, + + getResult: function() { + return _fr && _fr.result ? (_convertToBinary ? _toBinary(_fr.result) : _fr.result) : null; + }, + + abort: function() { + if (_fr) { + _fr.abort(); + } + }, + + destroy: function() { + _fr = null; + } + }); + + function _toBinary(str) { + return Encode.atob(str.substring(str.indexOf('base64,') + 7)); + } + } + + return (extensions.FileReader = FileReader); +}); + +// Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global ActiveXObject:true */ + +/** +@class moxie/runtime/html5/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/html5/xhr/XMLHttpRequest", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Mime", + "moxie/core/utils/Url", + "moxie/file/File", + "moxie/file/Blob", + "moxie/xhr/FormData", + "moxie/core/Exceptions", + "moxie/core/utils/Env" +], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) { + + function XMLHttpRequest() { + var self = this + , _xhr + , _filename + ; + + Basic.extend(this, { + send: function(meta, data) { + var target = this + , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.version >= 4 && Env.version < 7) + , isAndroidBrowser = Env.browser === 'Android Browser' + , mustSendAsBinary = false + ; + + // extract file name + _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase(); + + _xhr = _getNativeXHR(); + _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password); + + + // prepare data to be sent + if (data instanceof Blob) { + if (data.isDetached()) { + mustSendAsBinary = true; + } + data = data.getSource(); + } else if (data instanceof FormData) { + + if (data.hasBlob()) { + if (data.getBlob().isDetached()) { + data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state + mustSendAsBinary = true; + } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) { + // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150 + // Android browsers (default one and Dolphin) seem to have the same issue, see: #613 + _preloadAndSend.call(target, meta, data); + return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D + } + } + + // transfer fields to real FormData + if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart() + var fd = new window.FormData(); + data.each(function(value, name) { + if (value instanceof Blob) { + fd.append(name, value.getSource()); + } else { + fd.append(name, value); + } + }); + data = fd; + } + } + + + // if XHR L2 + if (_xhr.upload) { + if (meta.withCredentials) { + _xhr.withCredentials = true; + } + + _xhr.addEventListener('load', function(e) { + target.trigger(e); + }); + + _xhr.addEventListener('error', function(e) { + target.trigger(e); + }); + + // additionally listen to progress events + _xhr.addEventListener('progress', function(e) { + target.trigger(e); + }); + + _xhr.upload.addEventListener('progress', function(e) { + target.trigger({ + type: 'UploadProgress', + loaded: e.loaded, + total: e.total + }); + }); + // ... otherwise simulate XHR L2 + } else { + _xhr.onreadystatechange = function onReadyStateChange() { + + // fake Level 2 events + switch (_xhr.readyState) { + + case 1: // XMLHttpRequest.OPENED + // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu + break; + + // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu + case 2: // XMLHttpRequest.HEADERS_RECEIVED + break; + + case 3: // XMLHttpRequest.LOADING + // try to fire progress event for not XHR L2 + var total, loaded; + + try { + if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers + total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here + } + + if (_xhr.responseText) { // responseText was introduced in IE7 + loaded = _xhr.responseText.length; + } + } catch(ex) { + total = loaded = 0; + } + + target.trigger({ + type: 'progress', + lengthComputable: !!total, + total: parseInt(total, 10), + loaded: loaded + }); + break; + + case 4: // XMLHttpRequest.DONE + // release readystatechange handler (mostly for IE) + _xhr.onreadystatechange = function() {}; + + // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout + if (_xhr.status === 0) { + target.trigger('error'); + } else { + target.trigger('load'); + } + break; + } + }; + } + + + // set request headers + if (!Basic.isEmptyObj(meta.headers)) { + Basic.each(meta.headers, function(value, header) { + _xhr.setRequestHeader(header, value); + }); + } + + // request response type + if ("" !== meta.responseType && 'responseType' in _xhr) { + if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one + _xhr.responseType = 'text'; + } else { + _xhr.responseType = meta.responseType; + } + } + + // send ... + if (!mustSendAsBinary) { + _xhr.send(data); + } else { + if (_xhr.sendAsBinary) { // Gecko + _xhr.sendAsBinary(data); + } else { // other browsers having support for typed arrays + (function() { + // mimic Gecko's sendAsBinary + var ui8a = new Uint8Array(data.length); + for (var i = 0; i < data.length; i++) { + ui8a[i] = (data.charCodeAt(i) & 0xff); + } + _xhr.send(ui8a.buffer); + }()); + } + } + + target.trigger('loadstart'); + }, + + getStatus: function() { + // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception + try { + if (_xhr) { + return _xhr.status; + } + } catch(ex) {} + return 0; + }, + + getResponse: function(responseType) { + var I = this.getRuntime(); + + try { + switch (responseType) { + case 'blob': + var file = new File(I.uid, _xhr.response); + + // try to extract file name from content-disposition if possible (might be - not, if CORS for example) + var disposition = _xhr.getResponseHeader('Content-Disposition'); + if (disposition) { + // extract filename from response header if available + var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/); + if (match) { + _filename = match[2]; + } + } + file.name = _filename; + + // pre-webkit Opera doesn't set type property on the blob response + if (!file.type) { + file.type = Mime.getFileMime(_filename); + } + return file; + + case 'json': + if (!Env.can('return_response_type', 'json')) { + return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null; + } + return _xhr.response; + + case 'document': + return _getDocument(_xhr); + + default: + return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes + } + } catch(ex) { + return null; + } + }, + + getAllResponseHeaders: function() { + try { + return _xhr.getAllResponseHeaders(); + } catch(ex) {} + return ''; + }, + + abort: function() { + if (_xhr) { + _xhr.abort(); + } + }, + + destroy: function() { + self = _filename = null; + } + }); + + + // here we go... ugly fix for ugly bug + function _preloadAndSend(meta, data) { + var target = this, blob, fr; + + // get original blob + blob = data.getBlob().getSource(); + + // preload blob in memory to be sent as binary string + fr = new window.FileReader(); + fr.onload = function() { + // overwrite original blob + data.append(data.getBlobName(), new Blob(null, { + type: blob.type, + data: fr.result + })); + // invoke send operation again + self.send.call(target, meta, data); + }; + fr.readAsBinaryString(blob); + } + + + function _getNativeXHR() { + if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.version < 8)) { // IE7 has native XHR but it's buggy + return new window.XMLHttpRequest(); + } else { + return (function() { + var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0 + for (var i = 0; i < progIDs.length; i++) { + try { + return new ActiveXObject(progIDs[i]); + } catch (ex) {} + } + })(); + } + } + + // @credits Sergey Ilinsky (http://www.ilinsky.com/) + function _getDocument(xhr) { + var rXML = xhr.responseXML; + var rText = xhr.responseText; + + // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type) + if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) { + rXML = new window.ActiveXObject("Microsoft.XMLDOM"); + rXML.async = false; + rXML.validateOnParse = false; + rXML.loadXML(rText); + } + + // Check if there is no error in document + if (rXML) { + if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") { + return null; + } + } + return rXML; + } + + + function _prepareMultipart(fd) { + var boundary = '----moxieboundary' + new Date().getTime() + , dashdash = '--' + , crlf = '\r\n' + , multipart = '' + , I = this.getRuntime() + ; + + if (!I.can('send_binary_string')) { + throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); + } + + _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); + + // append multipart parameters + fd.each(function(value, name) { + // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), + // so we try it here ourselves with: unescape(encodeURIComponent(value)) + if (value instanceof Blob) { + // Build RFC2388 blob + multipart += dashdash + boundary + crlf + + 'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf + + 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf + + value.getSource() + crlf; + } else { + multipart += dashdash + boundary + crlf + + 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf + + unescape(encodeURIComponent(value)) + crlf; + } + }); + + multipart += dashdash + boundary + dashdash + crlf; + + return multipart; + } + } + + return (extensions.XMLHttpRequest = XMLHttpRequest); +}); + +// Included from: src/javascript/runtime/html5/utils/BinaryReader.js + +/** + * BinaryReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/utils/BinaryReader +@private +*/ +define("moxie/runtime/html5/utils/BinaryReader", [], function() { + return function() { + var II = false, bin; + + // Private functions + function read(idx, size) { + var mv = II ? 0 : -8 * (size - 1), sum = 0, i; + + for (i = 0; i < size; i++) { + sum |= (bin.charCodeAt(idx + i) << Math.abs(mv + i*8)); + } + + return sum; + } + + function putstr(segment, idx, length) { + length = arguments.length === 3 ? length : bin.length - idx - 1; + bin = bin.substr(0, idx) + segment + bin.substr(length + idx); + } + + function write(idx, num, size) { + var str = '', mv = II ? 0 : -8 * (size - 1), i; + + for (i = 0; i < size; i++) { + str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255); + } + + putstr(str, idx, size); + } + + // Public functions + return { + II: function(order) { + if (order === undefined) { + return II; + } else { + II = order; + } + }, + + init: function(binData) { + II = false; + bin = binData; + }, + + SEGMENT: function(idx, length, segment) { + switch (arguments.length) { + case 1: + return bin.substr(idx, bin.length - idx - 1); + case 2: + return bin.substr(idx, length); + case 3: + putstr(segment, idx, length); + break; + default: return bin; + } + }, + + BYTE: function(idx) { + return read(idx, 1); + }, + + SHORT: function(idx) { + return read(idx, 2); + }, + + LONG: function(idx, num) { + if (num === undefined) { + return read(idx, 4); + } else { + write(idx, num, 4); + } + }, + + SLONG: function(idx) { // 2's complement notation + var num = read(idx, 4); + + return (num > 2147483647 ? num - 4294967296 : num); + }, + + STRING: function(idx, size) { + var str = ''; + + for (size += idx; idx < size; idx++) { + str += String.fromCharCode(read(idx, 1)); + } + + return str; + } + }; + }; +}); + +// Included from: src/javascript/runtime/html5/image/JPEGHeaders.js + +/** + * JPEGHeaders.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/JPEGHeaders +@private +*/ +define("moxie/runtime/html5/image/JPEGHeaders", [ + "moxie/runtime/html5/utils/BinaryReader" +], function(BinaryReader) { + + return function JPEGHeaders(data) { + var headers = [], read, idx, marker, length = 0; + + read = new BinaryReader(); + read.init(data); + + // Check if data is jpeg + if (read.SHORT(0) !== 0xFFD8) { + return; + } + + idx = 2; + + while (idx <= data.length) { + marker = read.SHORT(idx); + + // omit RST (restart) markers + if (marker >= 0xFFD0 && marker <= 0xFFD7) { + idx += 2; + continue; + } + + // no headers allowed after SOS marker + if (marker === 0xFFDA || marker === 0xFFD9) { + break; + } + + length = read.SHORT(idx + 2) + 2; + + // APPn marker detected + if (marker >= 0xFFE1 && marker <= 0xFFEF) { + headers.push({ + hex: marker, + name: 'APP' + (marker & 0x000F), + start: idx, + length: length, + segment: read.SEGMENT(idx, length) + }); + } + + idx += length; + } + + read.init(null); // free memory + + return { + headers: headers, + + restore: function(data) { + var max, i; + + read.init(data); + + idx = read.SHORT(2) == 0xFFE0 ? 4 + read.SHORT(4) : 2; + + for (i = 0, max = headers.length; i < max; i++) { + read.SEGMENT(idx, 0, headers[i].segment); + idx += headers[i].length; + } + + data = read.SEGMENT(); + read.init(null); + return data; + }, + + strip: function(data) { + var headers, jpegHeaders, i; + + jpegHeaders = new JPEGHeaders(data); + headers = jpegHeaders.headers; + jpegHeaders.purge(); + + read.init(data); + + i = headers.length; + while (i--) { + read.SEGMENT(headers[i].start, headers[i].length, ''); + } + + data = read.SEGMENT(); + read.init(null); + return data; + }, + + get: function(name) { + var array = []; + + for (var i = 0, max = headers.length; i < max; i++) { + if (headers[i].name === name.toUpperCase()) { + array.push(headers[i].segment); + } + } + return array; + }, + + set: function(name, segment) { + var array = [], i, ii, max; + + if (typeof(segment) === 'string') { + array.push(segment); + } else { + array = segment; + } + + for (i = ii = 0, max = headers.length; i < max; i++) { + if (headers[i].name === name.toUpperCase()) { + headers[i].segment = array[ii]; + headers[i].length = array[ii].length; + ii++; + } + if (ii >= array.length) { + break; + } + } + }, + + purge: function() { + headers = []; + read.init(null); + read = null; + } + }; + }; +}); + +// Included from: src/javascript/runtime/html5/image/ExifParser.js + +/** + * ExifParser.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/ExifParser +@private +*/ +define("moxie/runtime/html5/image/ExifParser", [ + "moxie/core/utils/Basic", + "moxie/runtime/html5/utils/BinaryReader" +], function(Basic, BinaryReader) { + + return function ExifParser() { + // Private ExifParser fields + var data, tags, Tiff, offsets = {}, tagDescs; + + data = new BinaryReader(); + + tags = { + tiff : { + /* + The image orientation viewed in terms of rows and columns. + + 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. + 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. + 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. + 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. + 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. + 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. + 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. + 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. + */ + 0x0112: 'Orientation', + 0x010E: 'ImageDescription', + 0x010F: 'Make', + 0x0110: 'Model', + 0x0131: 'Software', + 0x8769: 'ExifIFDPointer', + 0x8825: 'GPSInfoIFDPointer' + }, + exif : { + 0x9000: 'ExifVersion', + 0xA001: 'ColorSpace', + 0xA002: 'PixelXDimension', + 0xA003: 'PixelYDimension', + 0x9003: 'DateTimeOriginal', + 0x829A: 'ExposureTime', + 0x829D: 'FNumber', + 0x8827: 'ISOSpeedRatings', + 0x9201: 'ShutterSpeedValue', + 0x9202: 'ApertureValue' , + 0x9207: 'MeteringMode', + 0x9208: 'LightSource', + 0x9209: 'Flash', + 0x920A: 'FocalLength', + 0xA402: 'ExposureMode', + 0xA403: 'WhiteBalance', + 0xA406: 'SceneCaptureType', + 0xA404: 'DigitalZoomRatio', + 0xA408: 'Contrast', + 0xA409: 'Saturation', + 0xA40A: 'Sharpness' + }, + gps : { + 0x0000: 'GPSVersionID', + 0x0001: 'GPSLatitudeRef', + 0x0002: 'GPSLatitude', + 0x0003: 'GPSLongitudeRef', + 0x0004: 'GPSLongitude' + } + }; + + tagDescs = { + 'ColorSpace': { + 1: 'sRGB', + 0: 'Uncalibrated' + }, + + 'MeteringMode': { + 0: 'Unknown', + 1: 'Average', + 2: 'CenterWeightedAverage', + 3: 'Spot', + 4: 'MultiSpot', + 5: 'Pattern', + 6: 'Partial', + 255: 'Other' + }, + + 'LightSource': { + 1: 'Daylight', + 2: 'Fliorescent', + 3: 'Tungsten', + 4: 'Flash', + 9: 'Fine weather', + 10: 'Cloudy weather', + 11: 'Shade', + 12: 'Daylight fluorescent (D 5700 - 7100K)', + 13: 'Day white fluorescent (N 4600 -5400K)', + 14: 'Cool white fluorescent (W 3900 - 4500K)', + 15: 'White fluorescent (WW 3200 - 3700K)', + 17: 'Standard light A', + 18: 'Standard light B', + 19: 'Standard light C', + 20: 'D55', + 21: 'D65', + 22: 'D75', + 23: 'D50', + 24: 'ISO studio tungsten', + 255: 'Other' + }, + + 'Flash': { + 0x0000: 'Flash did not fire.', + 0x0001: 'Flash fired.', + 0x0005: 'Strobe return light not detected.', + 0x0007: 'Strobe return light detected.', + 0x0009: 'Flash fired, compulsory flash mode', + 0x000D: 'Flash fired, compulsory flash mode, return light not detected', + 0x000F: 'Flash fired, compulsory flash mode, return light detected', + 0x0010: 'Flash did not fire, compulsory flash mode', + 0x0018: 'Flash did not fire, auto mode', + 0x0019: 'Flash fired, auto mode', + 0x001D: 'Flash fired, auto mode, return light not detected', + 0x001F: 'Flash fired, auto mode, return light detected', + 0x0020: 'No flash function', + 0x0041: 'Flash fired, red-eye reduction mode', + 0x0045: 'Flash fired, red-eye reduction mode, return light not detected', + 0x0047: 'Flash fired, red-eye reduction mode, return light detected', + 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode', + 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', + 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', + 0x0059: 'Flash fired, auto mode, red-eye reduction mode', + 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', + 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode' + }, + + 'ExposureMode': { + 0: 'Auto exposure', + 1: 'Manual exposure', + 2: 'Auto bracket' + }, + + 'WhiteBalance': { + 0: 'Auto white balance', + 1: 'Manual white balance' + }, + + 'SceneCaptureType': { + 0: 'Standard', + 1: 'Landscape', + 2: 'Portrait', + 3: 'Night scene' + }, + + 'Contrast': { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }, + + 'Saturation': { + 0: 'Normal', + 1: 'Low saturation', + 2: 'High saturation' + }, + + 'Sharpness': { + 0: 'Normal', + 1: 'Soft', + 2: 'Hard' + }, + + // GPS related + 'GPSLatitudeRef': { + N: 'North latitude', + S: 'South latitude' + }, + + 'GPSLongitudeRef': { + E: 'East longitude', + W: 'West longitude' + } + }; + + function extractTags(IFD_offset, tags2extract) { + var length = data.SHORT(IFD_offset), i, ii, + tag, type, count, tagOffset, offset, value, values = [], hash = {}; + + for (i = 0; i < length; i++) { + // Set binary reader pointer to beginning of the next tag + offset = tagOffset = IFD_offset + 12 * i + 2; + + tag = tags2extract[data.SHORT(offset)]; + + if (tag === undefined) { + continue; // Not the tag we requested + } + + type = data.SHORT(offset+=2); + count = data.LONG(offset+=2); + + offset += 4; + values = []; + + switch (type) { + case 1: // BYTE + case 7: // UNDEFINED + if (count > 4) { + offset = data.LONG(offset) + offsets.tiffHeader; + } + + for (ii = 0; ii < count; ii++) { + values[ii] = data.BYTE(offset + ii); + } + + break; + + case 2: // STRING + if (count > 4) { + offset = data.LONG(offset) + offsets.tiffHeader; + } + + hash[tag] = data.STRING(offset, count - 1); + + continue; + + case 3: // SHORT + if (count > 2) { + offset = data.LONG(offset) + offsets.tiffHeader; + } + + for (ii = 0; ii < count; ii++) { + values[ii] = data.SHORT(offset + ii*2); + } + + break; + + case 4: // LONG + if (count > 1) { + offset = data.LONG(offset) + offsets.tiffHeader; + } + + for (ii = 0; ii < count; ii++) { + values[ii] = data.LONG(offset + ii*4); + } + + break; + + case 5: // RATIONAL + offset = data.LONG(offset) + offsets.tiffHeader; + + for (ii = 0; ii < count; ii++) { + values[ii] = data.LONG(offset + ii*4) / data.LONG(offset + ii*4 + 4); + } + + break; + + case 9: // SLONG + offset = data.LONG(offset) + offsets.tiffHeader; + + for (ii = 0; ii < count; ii++) { + values[ii] = data.SLONG(offset + ii*4); + } + + break; + + case 10: // SRATIONAL + offset = data.LONG(offset) + offsets.tiffHeader; + + for (ii = 0; ii < count; ii++) { + values[ii] = data.SLONG(offset + ii*4) / data.SLONG(offset + ii*4 + 4); + } + + break; + + default: + continue; + } + + value = (count == 1 ? values[0] : values); + + if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') { + hash[tag] = tagDescs[tag][value]; + } else { + hash[tag] = value; + } + } + + return hash; + } + + function getIFDOffsets() { + var idx = offsets.tiffHeader; + + // Set read order of multi-byte data + data.II(data.SHORT(idx) == 0x4949); + + // Check if always present bytes are indeed present + if (data.SHORT(idx+=2) !== 0x002A) { + return false; + } + + offsets.IFD0 = offsets.tiffHeader + data.LONG(idx += 2); + Tiff = extractTags(offsets.IFD0, tags.tiff); + + if ('ExifIFDPointer' in Tiff) { + offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer; + delete Tiff.ExifIFDPointer; + } + + if ('GPSInfoIFDPointer' in Tiff) { + offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer; + delete Tiff.GPSInfoIFDPointer; + } + return true; + } + + // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported + function setTag(ifd, tag, value) { + var offset, length, tagOffset, valueOffset = 0; + + // If tag name passed translate into hex key + if (typeof(tag) === 'string') { + var tmpTags = tags[ifd.toLowerCase()]; + for (var hex in tmpTags) { + if (tmpTags[hex] === tag) { + tag = hex; + break; + } + } + } + offset = offsets[ifd.toLowerCase() + 'IFD']; + length = data.SHORT(offset); + + for (var i = 0; i < length; i++) { + tagOffset = offset + 12 * i + 2; + + if (data.SHORT(tagOffset) == tag) { + valueOffset = tagOffset + 8; + break; + } + } + + if (!valueOffset) { + return false; + } + + data.LONG(valueOffset, value); + return true; + } + + + // Public functions + return { + init: function(segment) { + // Reset internal data + offsets = { + tiffHeader: 10 + }; + + if (segment === undefined || !segment.length) { + return false; + } + + data.init(segment); + + // Check if that's APP1 and that it has EXIF + if (data.SHORT(0) === 0xFFE1 && data.STRING(4, 5).toUpperCase() === "EXIF\0") { + return getIFDOffsets(); + } + return false; + }, + + TIFF: function() { + return Tiff; + }, + + EXIF: function() { + var Exif; + + // Populate EXIF hash + Exif = extractTags(offsets.exifIFD, tags.exif); + + // Fix formatting of some tags + if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') { + for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) { + exifVersion += String.fromCharCode(Exif.ExifVersion[i]); + } + Exif.ExifVersion = exifVersion; + } + + return Exif; + }, + + GPS: function() { + var GPS; + + GPS = extractTags(offsets.gpsIFD, tags.gps); + + // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..) + if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') { + GPS.GPSVersionID = GPS.GPSVersionID.join('.'); + } + + return GPS; + }, + + setExif: function(tag, value) { + // Right now only setting of width/height is possible + if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') {return false;} + + return setTag('exif', tag, value); + }, + + + getBinary: function() { + return data.SEGMENT(); + }, + + purge: function() { + data.init(null); + data = Tiff = null; + offsets = {}; + } + }; + }; +}); + +// Included from: src/javascript/runtime/html5/image/JPEG.js + +/** + * JPEG.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/JPEG +@private +*/ +define("moxie/runtime/html5/image/JPEG", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/html5/image/JPEGHeaders", + "moxie/runtime/html5/utils/BinaryReader", + "moxie/runtime/html5/image/ExifParser" +], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) { + + function JPEG(binstr) { + var _binstr, _br, _hm, _ep, _info, hasExif; + + function _getDimensions() { + var idx = 0, marker, length; + + // examine all through the end, since some images might have very large APP segments + while (idx <= _binstr.length) { + marker = _br.SHORT(idx += 2); + + if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn + idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte) + return { + height: _br.SHORT(idx), + width: _br.SHORT(idx += 2) + }; + } + length = _br.SHORT(idx += 2); + idx += length - 2; + } + return null; + } + + _binstr = binstr; + + _br = new BinaryReader(); + _br.init(_binstr); + + // check if it is jpeg + if (_br.SHORT(0) !== 0xFFD8) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + + // backup headers + _hm = new JPEGHeaders(binstr); + + // extract exif info + _ep = new ExifParser(); + hasExif = !!_ep.init(_hm.get('app1')[0]); + + // get dimensions + _info = _getDimensions.call(this); + + Basic.extend(this, { + type: 'image/jpeg', + + size: _binstr.length, + + width: _info && _info.width || 0, + + height: _info && _info.height || 0, + + setExif: function(tag, value) { + if (!hasExif) { + return false; // or throw an exception + } + + if (Basic.typeOf(tag) === 'object') { + Basic.each(tag, function(value, tag) { + _ep.setExif(tag, value); + }); + } else { + _ep.setExif(tag, value); + } + + // update internal headers + _hm.set('app1', _ep.getBinary()); + }, + + writeHeaders: function() { + if (!arguments.length) { + // if no arguments passed, update headers internally + return (_binstr = _hm.restore(_binstr)); + } + return _hm.restore(arguments[0]); + }, + + stripHeaders: function(binstr) { + return _hm.strip(binstr); + }, + + purge: function() { + _purge.call(this); + } + }); + + if (hasExif) { + this.meta = { + tiff: _ep.TIFF(), + exif: _ep.EXIF(), + gps: _ep.GPS() + }; + } + + function _purge() { + if (!_ep || !_hm || !_br) { + return; // ignore any repeating purge requests + } + _ep.purge(); + _hm.purge(); + _br.init(null); + _binstr = _info = _hm = _ep = _br = null; + } + } + + return JPEG; +}); + +// Included from: src/javascript/runtime/html5/image/PNG.js + +/** + * PNG.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/PNG +@private +*/ +define("moxie/runtime/html5/image/PNG", [ + "moxie/core/Exceptions", + "moxie/core/utils/Basic", + "moxie/runtime/html5/utils/BinaryReader" +], function(x, Basic, BinaryReader) { + + function PNG(binstr) { + var _binstr, _br, _hm, _ep, _info; + + _binstr = binstr; + + _br = new BinaryReader(); + _br.init(_binstr); + + // check if it's png + (function() { + var idx = 0, i = 0 + , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A] + ; + + for (i = 0; i < signature.length; i++, idx += 2) { + if (signature[i] != _br.SHORT(idx)) { + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + } + } + }()); + + function _getDimensions() { + var chunk, idx; + + chunk = _getChunkAt.call(this, 8); + + if (chunk.type == 'IHDR') { + idx = chunk.start; + return { + width: _br.LONG(idx), + height: _br.LONG(idx += 4) + }; + } + return null; + } + + function _purge() { + if (!_br) { + return; // ignore any repeating purge requests + } + _br.init(null); + _binstr = _info = _hm = _ep = _br = null; + } + + _info = _getDimensions.call(this); + + Basic.extend(this, { + type: 'image/png', + + size: _binstr.length, + + width: _info.width, + + height: _info.height, + + purge: function() { + _purge.call(this); + } + }); + + // for PNG we can safely trigger purge automatically, as we do not keep any data for later + _purge.call(this); + + function _getChunkAt(idx) { + var length, type, start, CRC; + + length = _br.LONG(idx); + type = _br.STRING(idx += 4, 4); + start = idx += 4; + CRC = _br.LONG(idx + length); + + return { + length: length, + type: type, + start: start, + CRC: CRC + }; + } + } + + return PNG; +}); + +// Included from: src/javascript/runtime/html5/image/ImageInfo.js + +/** + * ImageInfo.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/ImageInfo +@private +*/ +define("moxie/runtime/html5/image/ImageInfo", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/html5/image/JPEG", + "moxie/runtime/html5/image/PNG" +], function(Basic, x, JPEG, PNG) { + /** + Optional image investigation tool for HTML5 runtime. Provides the following features: + - ability to distinguish image type (JPEG or PNG) by signature + - ability to extract image width/height directly from it's internals, without preloading in memory (fast) + - ability to extract APP headers from JPEGs (Exif, GPS, etc) + - ability to replace width/height tags in extracted JPEG headers + - ability to restore APP headers, that were for example stripped during image manipulation + + @class ImageInfo + @constructor + @param {String} binstr Image source as binary string + */ + return function(binstr) { + var _cs = [JPEG, PNG], _img; + + // figure out the format, throw: ImageError.WRONG_FORMAT if not supported + _img = (function() { + for (var i = 0; i < _cs.length; i++) { + try { + return new _cs[i](binstr); + } catch (ex) { + // console.info(ex); + } + } + throw new x.ImageError(x.ImageError.WRONG_FORMAT); + }()); + + Basic.extend(this, { + /** + Image Mime Type extracted from it's depths + + @property type + @type {String} + @default '' + */ + type: '', + + /** + Image size in bytes + + @property size + @type {Number} + @default 0 + */ + size: 0, + + /** + Image width extracted from image source + + @property width + @type {Number} + @default 0 + */ + width: 0, + + /** + Image height extracted from image source + + @property height + @type {Number} + @default 0 + */ + height: 0, + + /** + Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs. + + @method setExif + @param {String} tag Tag to set + @param {Mixed} value Value to assign to the tag + */ + setExif: function() {}, + + /** + Restores headers to the source. + + @method writeHeaders + @param {String} data Image source as binary string + @return {String} Updated binary string + */ + writeHeaders: function(data) { + return data; + }, + + /** + Strip all headers from the source. + + @method stripHeaders + @param {String} data Image source as binary string + @return {String} Updated binary string + */ + stripHeaders: function(data) { + return data; + }, + + /** + Dispose resources. + + @method purge + */ + purge: function() {} + }); + + Basic.extend(this, _img); + + this.purge = function() { + _img.purge(); + _img = null; + }; + }; +}); + +// Included from: src/javascript/runtime/html5/image/MegaPixel.js + +/** +(The MIT License) + +Copyright (c) 2012 Shinichi Tomita ; + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +/** + * Mega pixel image rendering library for iOS6 Safari + * + * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel), + * which causes unexpected subsampling when drawing it in canvas. + * By using this library, you can safely render the image with proper stretching. + * + * Copyright (c) 2012 Shinichi Tomita + * Released under the MIT license + */ + +/** +@class moxie/runtime/html5/image/MegaPixel +@private +*/ +define("moxie/runtime/html5/image/MegaPixel", [], function() { + + /** + * Rendering image element (with resizing) into the canvas element + */ + function renderImageToCanvas(img, canvas, options) { + var iw = img.naturalWidth, ih = img.naturalHeight; + var width = options.width, height = options.height; + var x = options.x || 0, y = options.y || 0; + var ctx = canvas.getContext('2d'); + if (detectSubsampling(img)) { + iw /= 2; + ih /= 2; + } + var d = 1024; // size of tiling canvas + var tmpCanvas = document.createElement('canvas'); + tmpCanvas.width = tmpCanvas.height = d; + var tmpCtx = tmpCanvas.getContext('2d'); + var vertSquashRatio = detectVerticalSquash(img, iw, ih); + var sy = 0; + while (sy < ih) { + var sh = sy + d > ih ? ih - sy : d; + var sx = 0; + while (sx < iw) { + var sw = sx + d > iw ? iw - sx : d; + tmpCtx.clearRect(0, 0, d, d); + tmpCtx.drawImage(img, -sx, -sy); + var dx = (sx * width / iw + x) << 0; + var dw = Math.ceil(sw * width / iw); + var dy = (sy * height / ih / vertSquashRatio + y) << 0; + var dh = Math.ceil(sh * height / ih / vertSquashRatio); + ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh); + sx += d; + } + sy += d; + } + tmpCanvas = tmpCtx = null; + } + + /** + * Detect subsampling in loaded image. + * In iOS, larger images than 2M pixels may be subsampled in rendering. + */ + function detectSubsampling(img) { + var iw = img.naturalWidth, ih = img.naturalHeight; + if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image + var canvas = document.createElement('canvas'); + canvas.width = canvas.height = 1; + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, -iw + 1, 0); + // subsampled image becomes half smaller in rendering size. + // check alpha channel value to confirm image is covering edge pixel or not. + // if alpha value is 0 image is not covering, hence subsampled. + return ctx.getImageData(0, 0, 1, 1).data[3] === 0; + } else { + return false; + } + } + + + /** + * Detecting vertical squash in loaded image. + * Fixes a bug which squash image vertically while drawing into canvas for some images. + */ + function detectVerticalSquash(img, iw, ih) { + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = ih; + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + var data = ctx.getImageData(0, 0, 1, ih).data; + // search image edge pixel position in case it is squashed vertically. + var sy = 0; + var ey = ih; + var py = ih; + while (py > sy) { + var alpha = data[(py - 1) * 4 + 3]; + if (alpha === 0) { + ey = py; + } else { + sy = py; + } + py = (ey + sy) >> 1; + } + canvas = null; + var ratio = (py / ih); + return (ratio === 0) ? 1 : ratio; + } + + return { + isSubsampled: detectSubsampling, + renderTo: renderImageToCanvas + }; +}); + +// Included from: src/javascript/runtime/html5/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html5/image/Image +@private +*/ +define("moxie/runtime/html5/image/Image", [ + "moxie/runtime/html5/Runtime", + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/core/utils/Encode", + "moxie/file/File", + "moxie/runtime/html5/image/ImageInfo", + "moxie/runtime/html5/image/MegaPixel", + "moxie/core/utils/Mime", + "moxie/core/utils/Env" +], function(extensions, Basic, x, Encode, File, ImageInfo, MegaPixel, Mime, Env) { + + function HTML5Image() { + var me = this + , _img, _imgInfo, _canvas, _binStr, _blob + , _modified = false // is set true whenever image is modified + , _preserveHeaders = true + ; + + Basic.extend(this, { + loadFromBlob: function(blob) { + var comp = this, I = comp.getRuntime() + , asBinary = arguments.length > 1 ? arguments[1] : true + ; + + if (!I.can('access_binary')) { + throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); + } + + _blob = blob; + + if (blob.isDetached()) { + _binStr = blob.getSource(); + _preload.call(this, _binStr); + return; + } else { + _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) { + if (asBinary) { + _binStr = _toBinary(dataUrl); + } + _preload.call(comp, dataUrl); + }); + } + }, + + loadFromImage: function(img, exact) { + this.meta = img.meta; + + _blob = new File(null, { + name: img.name, + size: img.size, + type: img.type + }); + + _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL()); + }, + + getInfo: function() { + var I = this.getRuntime(), info; + + if (!_imgInfo && _binStr && I.can('access_image_binary')) { + _imgInfo = new ImageInfo(_binStr); + } + + info = { + width: _getImg().width || 0, + height: _getImg().height || 0, + type: _blob.type || Mime.getFileMime(_blob.name), + size: _binStr && _binStr.length || _blob.size || 0, + name: _blob.name || '', + meta: _imgInfo && _imgInfo.meta || this.meta || {} + }; + + return info; + }, + + downsize: function() { + _downsize.apply(this, arguments); + }, + + getAsCanvas: function() { + if (_canvas) { + _canvas.id = this.uid + '_canvas'; + } + return _canvas; + }, + + getAsBlob: function(type, quality) { + if (type !== this.type) { + // if different mime type requested prepare image for conversion + _downsize.call(this, this.width, this.height, false); + } + return new File(null, { + name: _blob.name || '', + type: type, + data: me.getAsBinaryString.call(this, type, quality) + }); + }, + + getAsDataURL: function(type) { + var quality = arguments[1] || 90; + + // if image has not been modified, return the source right away + if (!_modified) { + return _img.src; + } + + if ('image/jpeg' !== type) { + return _canvas.toDataURL('image/png'); + } else { + try { + // older Geckos used to result in an exception on quality argument + return _canvas.toDataURL('image/jpeg', quality/100); + } catch (ex) { + return _canvas.toDataURL('image/jpeg'); + } + } + }, + + getAsBinaryString: function(type, quality) { + // if image has not been modified, return the source right away + if (!_modified) { + // if image was not loaded from binary string + if (!_binStr) { + _binStr = _toBinary(me.getAsDataURL(type, quality)); + } + return _binStr; + } + + if ('image/jpeg' !== type) { + _binStr = _toBinary(me.getAsDataURL(type, quality)); + } else { + var dataUrl; + + // if jpeg + if (!quality) { + quality = 90; + } + + try { + // older Geckos used to result in an exception on quality argument + dataUrl = _canvas.toDataURL('image/jpeg', quality/100); + } catch (ex) { + dataUrl = _canvas.toDataURL('image/jpeg'); + } + + _binStr = _toBinary(dataUrl); + + if (_imgInfo) { + _binStr = _imgInfo.stripHeaders(_binStr); + + if (_preserveHeaders) { + // update dimensions info in exif + if (_imgInfo.meta && _imgInfo.meta.exif) { + _imgInfo.setExif({ + PixelXDimension: this.width, + PixelYDimension: this.height + }); + } + + // re-inject the headers + _binStr = _imgInfo.writeHeaders(_binStr); + } + + // will be re-created from fresh on next getInfo call + _imgInfo.purge(); + _imgInfo = null; + } + } + + _modified = false; + + return _binStr; + }, + + destroy: function() { + me = null; + _purge.call(this); + this.getRuntime().getShim().removeInstance(this.uid); + } + }); + + + function _getImg() { + if (!_canvas && !_img) { + throw new x.ImageError(x.DOMException.INVALID_STATE_ERR); + } + return _canvas || _img; + } + + + function _toBinary(str) { + return Encode.atob(str.substring(str.indexOf('base64,') + 7)); + } + + + function _toDataUrl(str, type) { + return 'data:' + (type || '') + ';base64,' + Encode.btoa(str); + } + + + function _preload(str) { + var comp = this; + + _img = new Image(); + _img.onerror = function() { + _purge.call(this); + comp.trigger('error', new x.ImageError(x.ImageError.WRONG_FORMAT)); + }; + _img.onload = function() { + comp.trigger('load'); + }; + + _img.src = /^data:[^;]*;base64,/.test(str) ? str : _toDataUrl(str, _blob.type); + } + + + function _readAsDataUrl(file, callback) { + var comp = this, fr; + + // use FileReader if it's available + if (window.FileReader) { + fr = new FileReader(); + fr.onload = function() { + callback(this.result); + }; + fr.onerror = function() { + comp.trigger('error', new x.FileException(x.FileException.NOT_READABLE_ERR)); + }; + fr.readAsDataURL(file); + } else { + return callback(file.getAsDataURL()); + } + } + + function _downsize(width, height, crop, preserveHeaders) { + var self = this + , scale + , mathFn + , x = 0 + , y = 0 + , img + , destWidth + , destHeight + , orientation + ; + + _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString()) + + // take into account orientation tag + orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1; + + if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation + // swap dimensions + var tmp = width; + width = height; + height = tmp; + } + + img = _getImg(); + + // unify dimensions + mathFn = !crop ? Math.min : Math.max; + scale = mathFn(width/img.width, height/img.height); + + // we only downsize here + if (scale > 1 && (!crop || preserveHeaders)) { // when cropping one of dimensions may still exceed max, so process it anyway + this.trigger('Resize'); + return; + } + + // prepare canvas if necessary + if (!_canvas) { + _canvas = document.createElement("canvas"); + } + + // calculate dimensions of proportionally resized image + destWidth = Math.round(img.width * scale); + destHeight = Math.round(img.height * scale); + + + // scale image and canvas + if (crop) { + _canvas.width = width; + _canvas.height = height; + + // if dimensions of the resulting image still larger than canvas, center it + if (destWidth > width) { + x = Math.round((destWidth - width) / 2); + } + + if (destHeight > height) { + y = Math.round((destHeight - height) / 2); + } + } else { + _canvas.width = destWidth; + _canvas.height = destHeight; + } + + // rotate if required, according to orientation tag + if (!_preserveHeaders) { + _rotateToOrientaion(_canvas.width, _canvas.height, orientation); + } + + _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight); + + this.width = _canvas.width; + this.height = _canvas.height; + + _modified = true; + self.trigger('Resize'); + } + + + function _drawToCanvas(img, canvas, x, y, w, h) { + if (Env.OS === 'iOS') { + // avoid squish bug in iOS6 + MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y }); + } else { + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, x, y, w, h); + } + } + + + /** + * Transform canvas coordination according to specified frame size and orientation + * Orientation value is from EXIF tag + * @author Shinichi Tomita + */ + function _rotateToOrientaion(width, height, orientation) { + switch (orientation) { + case 5: + case 6: + case 7: + case 8: + _canvas.width = height; + _canvas.height = width; + break; + default: + _canvas.width = width; + _canvas.height = height; + } + + /** + 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. + 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. + 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. + 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. + 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. + 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. + 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. + 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. + */ + + var ctx = _canvas.getContext('2d'); + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(width, 0); + ctx.scale(-1, 1); + break; + case 3: + // 180 rotate left + ctx.translate(width, height); + ctx.rotate(Math.PI); + break; + case 4: + // vertical flip + ctx.translate(0, height); + ctx.scale(1, -1); + break; + case 5: + // vertical flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.scale(1, -1); + break; + case 6: + // 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(0, -height); + break; + case 7: + // horizontal flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(width, -height); + ctx.scale(-1, 1); + break; + case 8: + // 90 rotate left + ctx.rotate(-0.5 * Math.PI); + ctx.translate(-width, 0); + break; + } + } + + + function _purge() { + if (_imgInfo) { + _imgInfo.purge(); + _imgInfo = null; + } + _binStr = _img = _canvas = _blob = null; + _modified = false; + } + } + + return (extensions.Image = HTML5Image); +}); + +// Included from: src/javascript/runtime/flash/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global ActiveXObject:true */ + +/** +Defines constructor for Flash runtime. + +@class moxie/runtime/flash/Runtime +@private +*/ +define("moxie/runtime/flash/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Env", + "moxie/core/utils/Dom", + "moxie/core/Exceptions", + "moxie/runtime/Runtime" +], function(Basic, Env, Dom, x, Runtime) { + + var type = 'flash', extensions = {}; + + /** + Get the version of the Flash Player + + @method getShimVersion + @private + @return {Number} Flash Player version + */ + function getShimVersion() { + var version; + + try { + version = navigator.plugins['Shockwave Flash']; + version = version.description; + } catch (e1) { + try { + version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); + } catch (e2) { + version = '0.0'; + } + } + version = version.match(/\d+/g); + return parseFloat(version[0] + '.' + version[1]); + } + + /** + Constructor for the Flash Runtime + + @class FlashRuntime + @extends Runtime + */ + function FlashRuntime(options) { + var I = this, initTimer; + + options = Basic.extend({ swf_url: Env.swf_url }, options); + + Runtime.call(this, options, type, { + access_binary: function(value) { + return value && I.mode === 'browser'; + }, + access_image_binary: function(value) { + return value && I.mode === 'browser'; + }, + display_media: Runtime.capTrue, + do_cors: Runtime.capTrue, + drag_and_drop: false, + report_upload_progress: function() { + return I.mode === 'client'; + }, + resize_image: Runtime.capTrue, + return_response_headers: false, + return_response_type: function(responseType) { + if (responseType === 'json' && !!window.JSON) { + return true; + } + return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser'; + }, + return_status_code: function(code) { + return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]); + }, + select_file: Runtime.capTrue, + select_multiple: Runtime.capTrue, + send_binary_string: function(value) { + return value && I.mode === 'browser'; + }, + send_browser_cookies: function(value) { + return value && I.mode === 'browser'; + }, + send_custom_headers: function(value) { + return value && I.mode === 'browser'; + }, + send_multipart: Runtime.capTrue, + slice_blob: Runtime.capTrue, + stream_upload: function(value) { + return value && I.mode === 'browser'; + }, + summon_file_dialog: false, + upload_filesize: function(size) { + return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client'; + }, + use_http_method: function(methods) { + return !Basic.arrayDiff(methods, ['GET', 'POST']); + } + }, { + // capabilities that require specific mode + access_binary: function(value) { + return value ? 'browser' : 'client'; + }, + access_image_binary: function(value) { + return value ? 'browser' : 'client'; + }, + report_upload_progress: function(value) { + return value ? 'browser' : 'client'; + }, + return_response_type: function(responseType) { + return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser']; + }, + return_status_code: function(code) { + return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser']; + }, + send_binary_string: function(value) { + return value ? 'browser' : 'client'; + }, + send_browser_cookies: function(value) { + return value ? 'browser' : 'client'; + }, + send_custom_headers: function(value) { + return value ? 'browser' : 'client'; + }, + stream_upload: function(value) { + return value ? 'client' : 'browser'; + }, + upload_filesize: function(size) { + return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser'; + } + }, 'client'); + + + // minimal requirement for Flash Player version + if (getShimVersion() < 10) { + this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before + } + + + Basic.extend(this, { + + getShim: function() { + return Dom.get(this.uid); + }, + + shimExec: function(component, action) { + var args = [].slice.call(arguments, 2); + return I.getShim().exec(this.uid, component, action, args); + }, + + init: function() { + var html, el, container; + + container = this.getShimContainer(); + + // if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc) + Basic.extend(container.style, { + position: 'absolute', + top: '-8px', + left: '-8px', + width: '9px', + height: '9px', + overflow: 'hidden' + }); + + // insert flash object + html = '' + + '' + + '' + + '' + + ''; + + if (Env.browser === 'IE') { + el = document.createElement('div'); + container.appendChild(el); + el.outerHTML = html; + el = container = null; // just in case + } else { + container.innerHTML = html; + } + + // Init is dispatched by the shim + initTimer = setTimeout(function() { + if (I && !I.initialized) { // runtime might be already destroyed by this moment + I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); + } + }, 5000); + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + clearTimeout(initTimer); // initialization check might be still onwait + options = initTimer = destroy = I = null; + }; + }(this.destroy)) + + }, extensions); + } + + Runtime.addConstructor(type, FlashRuntime); + + return extensions; +}); + +// Included from: src/javascript/runtime/flash/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/Blob +@private +*/ +define("moxie/runtime/flash/file/Blob", [ + "moxie/runtime/flash/Runtime", + "moxie/file/Blob" +], function(extensions, Blob) { + + var FlashBlob = { + slice: function(blob, start, end, type) { + var self = this.getRuntime(); + + if (start < 0) { + start = Math.max(blob.size + start, 0); + } else if (start > 0) { + start = Math.min(start, blob.size); + } + + if (end < 0) { + end = Math.max(blob.size + end, 0); + } else if (end > 0) { + end = Math.min(end, blob.size); + } + + blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || ''); + + if (blob) { + blob = new Blob(self.uid, blob); + } + return blob; + } + }; + + return (extensions.Blob = FlashBlob); +}); + +// Included from: src/javascript/runtime/flash/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/FileInput +@private +*/ +define("moxie/runtime/flash/file/FileInput", [ + "moxie/runtime/flash/Runtime" +], function(extensions) { + + var FileInput = { + init: function(options) { + this.getRuntime().shimExec.call(this, 'FileInput', 'init', { + name: options.name, + accept: options.accept, + multiple: options.multiple + }); + this.trigger('ready'); + } + }; + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/flash/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/FileReader +@private +*/ +define("moxie/runtime/flash/file/FileReader", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Encode" +], function(extensions, Encode) { + + var _result = ''; + + function _formatData(data, op) { + switch (op) { + case 'readAsText': + return Encode.atob(data, 'utf8'); + case 'readAsBinaryString': + return Encode.atob(data); + case 'readAsDataURL': + return data; + } + return null; + } + + var FileReader = { + read: function(op, blob) { + var target = this, self = target.getRuntime(); + + // special prefix for DataURL read mode + if (op === 'readAsDataURL') { + _result = 'data:' + (blob.type || '') + ';base64,'; + } + + target.bind('Progress', function(e, data) { + if (data) { + _result += _formatData(data, op); + } + }); + + return self.shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid); + }, + + getResult: function() { + return _result; + }, + + destroy: function() { + _result = null; + } + }; + + return (extensions.FileReader = FileReader); +}); + +// Included from: src/javascript/runtime/flash/file/FileReaderSync.js + +/** + * FileReaderSync.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/file/FileReaderSync +@private +*/ +define("moxie/runtime/flash/file/FileReaderSync", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Encode" +], function(extensions, Encode) { + + function _formatData(data, op) { + switch (op) { + case 'readAsText': + return Encode.atob(data, 'utf8'); + case 'readAsBinaryString': + return Encode.atob(data); + case 'readAsDataURL': + return data; + } + return null; + } + + var FileReaderSync = { + read: function(op, blob) { + var result, self = this.getRuntime(); + + result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid); + if (!result) { + return null; // or throw ex + } + + // special prefix for DataURL read mode + if (op === 'readAsDataURL') { + result = 'data:' + (blob.type || '') + ';base64,' + result; + } + + return _formatData(result, op, blob.type); + } + }; + + return (extensions.FileReaderSync = FileReaderSync); +}); + +// Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/flash/xhr/XMLHttpRequest", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Basic", + "moxie/file/Blob", + "moxie/file/File", + "moxie/file/FileReaderSync", + "moxie/xhr/FormData", + "moxie/runtime/Transporter" +], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter) { + + var XMLHttpRequest = { + + send: function(meta, data) { + var target = this, self = target.getRuntime(); + + function send() { + meta.transport = self.mode; + self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data); + } + + + function appendBlob(name, blob) { + self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid); + data = null; + send(); + } + + + function attachBlob(blob, cb) { + var tr = new Transporter(); + + tr.bind("TransportingComplete", function() { + cb(this.result); + }); + + tr.transport(blob.getSource(), blob.type, { + ruid: self.uid + }); + } + + // copy over the headers if any + if (!Basic.isEmptyObj(meta.headers)) { + Basic.each(meta.headers, function(value, header) { + self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object + }); + } + + // transfer over multipart params and blob itself + if (data instanceof FormData) { + var blobField; + data.each(function(value, name) { + if (value instanceof Blob) { + blobField = name; + } else { + self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value); + } + }); + + if (!data.hasBlob()) { + data = null; + send(); + } else { + var blob = data.getBlob(); + if (blob.isDetached()) { + attachBlob(blob, function(attachedBlob) { + blob.destroy(); + appendBlob(blobField, attachedBlob); + }); + } else { + appendBlob(blobField, blob); + } + } + } else if (data instanceof Blob) { + if (data.isDetached()) { + attachBlob(data, function(attachedBlob) { + data.destroy(); + data = attachedBlob.uid; + send(); + }); + } else { + data = data.uid; + send(); + } + } else { + send(); + } + }, + + getResponse: function(responseType) { + var frs, blob, self = this.getRuntime(); + + blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob'); + + if (blob) { + blob = new File(self.uid, blob); + + if ('blob' === responseType) { + return blob; + } + + try { + frs = new FileReaderSync(); + + if (!!~Basic.inArray(responseType, ["", "text"])) { + return frs.readAsText(blob); + } else if ('json' === responseType && !!window.JSON) { + return JSON.parse(frs.readAsText(blob)); + } + } finally { + blob.destroy(); + } + } + return null; + }, + + abort: function(upload_complete_flag) { + var self = this.getRuntime(); + + self.shimExec.call(this, 'XMLHttpRequest', 'abort'); + + this.dispatchEvent('readystatechange'); + // this.dispatchEvent('progress'); + this.dispatchEvent('abort'); + + //if (!upload_complete_flag) { + // this.dispatchEvent('uploadprogress'); + //} + } + }; + + return (extensions.XMLHttpRequest = XMLHttpRequest); +}); + +// Included from: src/javascript/runtime/flash/runtime/Transporter.js + +/** + * Transporter.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/runtime/Transporter +@private +*/ +define("moxie/runtime/flash/runtime/Transporter", [ + "moxie/runtime/flash/Runtime", + "moxie/file/Blob" +], function(extensions, Blob) { + + var Transporter = { + getAsBlob: function(type) { + var self = this.getRuntime() + , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type) + ; + if (blob) { + return new Blob(self.uid, blob); + } + return null; + } + }; + + return (extensions.Transporter = Transporter); +}); + +// Included from: src/javascript/runtime/flash/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/flash/image/Image +@private +*/ +define("moxie/runtime/flash/image/Image", [ + "moxie/runtime/flash/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/Transporter", + "moxie/file/Blob", + "moxie/file/FileReaderSync" +], function(extensions, Basic, Transporter, Blob, FileReaderSync) { + + var Image = { + loadFromBlob: function(blob) { + var comp = this, self = comp.getRuntime(); + + function exec(srcBlob) { + self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid); + comp = self = null; + } + + if (blob.isDetached()) { // binary string + var tr = new Transporter(); + tr.bind("TransportingComplete", function() { + exec(tr.result.getSource()); + }); + tr.transport(blob.getSource(), blob.type, { ruid: self.uid }); + } else { + exec(blob.getSource()); + } + }, + + loadFromImage: function(img) { + var self = this.getRuntime(); + return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid); + }, + + getAsBlob: function(type, quality) { + var self = this.getRuntime() + , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality) + ; + if (blob) { + return new Blob(self.uid, blob); + } + return null; + }, + + getAsDataURL: function() { + var self = this.getRuntime() + , blob = self.Image.getAsBlob.apply(this, arguments) + , frs + ; + if (!blob) { + return null; + } + frs = new FileReaderSync(); + return frs.readAsDataURL(blob); + } + }; + + return (extensions.Image = Image); +}); + +// Included from: src/javascript/runtime/silverlight/Runtime.js + +/** + * RunTime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global ActiveXObject:true */ + +/** +Defines constructor for Silverlight runtime. + +@class moxie/runtime/silverlight/Runtime +@private +*/ +define("moxie/runtime/silverlight/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/utils/Env", + "moxie/core/utils/Dom", + "moxie/core/Exceptions", + "moxie/runtime/Runtime" +], function(Basic, Env, Dom, x, Runtime) { + + var type = "silverlight", extensions = {}; + + function isInstalled(version) { + var isVersionSupported = false, control = null, actualVer, + actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0; + + try { + try { + control = new ActiveXObject('AgControl.AgControl'); + + if (control.IsVersionSupported(version)) { + isVersionSupported = true; + } + + control = null; + } catch (e) { + var plugin = navigator.plugins["Silverlight Plug-In"]; + + if (plugin) { + actualVer = plugin.description; + + if (actualVer === "1.0.30226.2") { + actualVer = "2.0.30226.2"; + } + + actualVerArray = actualVer.split("."); + + while (actualVerArray.length > 3) { + actualVerArray.pop(); + } + + while ( actualVerArray.length < 4) { + actualVerArray.push(0); + } + + reqVerArray = version.split("."); + + while (reqVerArray.length > 4) { + reqVerArray.pop(); + } + + do { + requiredVersionPart = parseInt(reqVerArray[index], 10); + actualVersionPart = parseInt(actualVerArray[index], 10); + index++; + } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart); + + if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) { + isVersionSupported = true; + } + } + } + } catch (e2) { + isVersionSupported = false; + } + + return isVersionSupported; + } + + /** + Constructor for the Silverlight Runtime + + @class SilverlightRuntime + @extends Runtime + */ + function SilverlightRuntime(options) { + var I = this, initTimer; + + options = Basic.extend({ xap_url: Env.xap_url }, options); + + Runtime.call(this, options, type, { + access_binary: Runtime.capTrue, + access_image_binary: Runtime.capTrue, + display_media: Runtime.capTrue, + do_cors: Runtime.capTrue, + drag_and_drop: false, + report_upload_progress: Runtime.capTrue, + resize_image: Runtime.capTrue, + return_response_headers: function(value) { + return value && I.mode === 'client'; + }, + return_response_type: function(responseType) { + if (responseType !== 'json') { + return true; + } else { + return !!window.JSON; + } + }, + return_status_code: function(code) { + return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]); + }, + select_file: Runtime.capTrue, + select_multiple: Runtime.capTrue, + send_binary_string: Runtime.capTrue, + send_browser_cookies: function(value) { + return value && I.mode === 'browser'; + }, + send_custom_headers: function(value) { + return value && I.mode === 'client'; + }, + send_multipart: Runtime.capTrue, + slice_blob: Runtime.capTrue, + stream_upload: true, + summon_file_dialog: false, + upload_filesize: Runtime.capTrue, + use_http_method: function(methods) { + return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']); + } + }, { + // capabilities that require specific mode + return_response_headers: function(value) { + return value ? 'client' : 'browser'; + }, + return_status_code: function(code) { + return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser']; + }, + send_browser_cookies: function(value) { + return value ? 'browser' : 'client'; + }, + send_custom_headers: function(value) { + return value ? 'client' : 'browser'; + }, + use_http_method: function(methods) { + return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser']; + } + }); + + + // minimal requirement + if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') { + this.mode = false; + } + + + Basic.extend(this, { + getShim: function() { + return Dom.get(this.uid).content.Moxie; + }, + + shimExec: function(component, action) { + var args = [].slice.call(arguments, 2); + return I.getShim().exec(this.uid, component, action, args); + }, + + init : function() { + var container; + + container = this.getShimContainer(); + + container.innerHTML = '' + + '' + + '' + + '' + + '' + + '' + + ''; + + // Init is dispatched by the shim + initTimer = setTimeout(function() { + if (I && !I.initialized) { // runtime might be already destroyed by this moment + I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); + } + }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac) + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + clearTimeout(initTimer); // initialization check might be still onwait + options = initTimer = destroy = I = null; + }; + }(this.destroy)) + + }, extensions); + } + + Runtime.addConstructor(type, SilverlightRuntime); + + return extensions; +}); + +// Included from: src/javascript/runtime/silverlight/file/Blob.js + +/** + * Blob.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/Blob +@private +*/ +define("moxie/runtime/silverlight/file/Blob", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/file/Blob" +], function(extensions, Basic, Blob) { + return (extensions.Blob = Basic.extend({}, Blob)); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileInput +@private +*/ +define("moxie/runtime/silverlight/file/FileInput", [ + "moxie/runtime/silverlight/Runtime" +], function(extensions) { + + var FileInput = { + init: function(options) { + + function toFilters(accept) { + var filter = ''; + for (var i = 0; i < accept.length; i++) { + filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.'); + } + return filter; + } + + this.getRuntime().shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.name, options.multiple); + this.trigger('ready'); + } + }; + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileDrop.js + +/** + * FileDrop.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileDrop +@private +*/ +define("moxie/runtime/silverlight/file/FileDrop", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Dom", + "moxie/core/utils/Events" +], function(extensions, Dom, Events) { + + // not exactly useful, since works only in safari (...crickets...) + var FileDrop = { + init: function() { + var comp = this, self = comp.getRuntime(), dropZone; + + dropZone = self.getShimContainer(); + + Events.addEvent(dropZone, 'dragover', function(e) { + e.preventDefault(); + e.stopPropagation(); + e.dataTransfer.dropEffect = 'copy'; + }, comp.uid); + + Events.addEvent(dropZone, 'dragenter', function(e) { + e.preventDefault(); + var flag = Dom.get(self.uid).dragEnter(e); + // If handled, then stop propagation of event in DOM + if (flag) { + e.stopPropagation(); + } + }, comp.uid); + + Events.addEvent(dropZone, 'drop', function(e) { + e.preventDefault(); + var flag = Dom.get(self.uid).dragDrop(e); + // If handled, then stop propagation of event in DOM + if (flag) { + e.stopPropagation(); + } + }, comp.uid); + + return self.shimExec.call(this, 'FileDrop', 'init'); + } + }; + + return (extensions.FileDrop = FileDrop); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileReader +@private +*/ +define("moxie/runtime/silverlight/file/FileReader", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/file/FileReader" +], function(extensions, Basic, FileReader) { + return (extensions.FileReader = Basic.extend({}, FileReader)); +}); + +// Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js + +/** + * FileReaderSync.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/file/FileReaderSync +@private +*/ +define("moxie/runtime/silverlight/file/FileReaderSync", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/file/FileReaderSync" +], function(extensions, Basic, FileReaderSync) { + return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync)); +}); + +// Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/xhr/XMLHttpRequest" +], function(extensions, Basic, XMLHttpRequest) { + return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest)); +}); + +// Included from: src/javascript/runtime/silverlight/runtime/Transporter.js + +/** + * Transporter.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/runtime/Transporter +@private +*/ +define("moxie/runtime/silverlight/runtime/Transporter", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/runtime/Transporter" +], function(extensions, Basic, Transporter) { + return (extensions.Transporter = Basic.extend({}, Transporter)); +}); + +// Included from: src/javascript/runtime/silverlight/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/silverlight/image/Image +@private +*/ +define("moxie/runtime/silverlight/image/Image", [ + "moxie/runtime/silverlight/Runtime", + "moxie/core/utils/Basic", + "moxie/runtime/flash/image/Image" +], function(extensions, Basic, Image) { + return (extensions.Image = Basic.extend({}, Image, { + + getInfo: function() { + var self = this.getRuntime() + , grps = ['tiff', 'exif', 'gps'] + , info = { meta: {} } + , rawInfo = self.shimExec.call(this, 'Image', 'getInfo') + ; + + if (rawInfo.meta) { + Basic.each(grps, function(grp) { + var meta = rawInfo.meta[grp] + , tag + , i + , length + , value + ; + if (meta && meta.keys) { + info.meta[grp] = {}; + for (i = 0, length = meta.keys.length; i < length; i++) { + tag = meta.keys[i]; + value = meta[tag]; + if (value) { + // convert numbers + if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero) + value = parseInt(value, 10); + } else if (/^\d*\.\d+$/.test(value)) { // double + value = parseFloat(value); + } + info.meta[grp][tag] = value; + } + } + } + }); + } + + info.width = parseInt(rawInfo.width, 10); + info.height = parseInt(rawInfo.height, 10); + info.size = parseInt(rawInfo.size, 10); + info.type = rawInfo.type; + info.name = rawInfo.name; + + return info; + } + })); +}); + +// Included from: src/javascript/runtime/html4/Runtime.js + +/** + * Runtime.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global File:true */ + +/** +Defines constructor for HTML4 runtime. + +@class moxie/runtime/html4/Runtime +@private +*/ +define("moxie/runtime/html4/Runtime", [ + "moxie/core/utils/Basic", + "moxie/core/Exceptions", + "moxie/runtime/Runtime", + "moxie/core/utils/Env" +], function(Basic, x, Runtime, Env) { + + var type = 'html4', extensions = {}; + + function Html4Runtime(options) { + var I = this + , Test = Runtime.capTest + , True = Runtime.capTrue + ; + + Runtime.call(this, options, type, { + access_binary: Test(window.FileReader || window.File && File.getAsDataURL), + access_image_binary: false, + display_media: Test(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))), + do_cors: false, + drag_and_drop: false, + filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest + return (Env.browser === 'Chrome' && Env.version >= 28) || (Env.browser === 'IE' && Env.version >= 10); + }()), + resize_image: function() { + return extensions.Image && I.can('access_binary') && Env.can('create_canvas'); + }, + report_upload_progress: false, + return_response_headers: false, + return_response_type: function(responseType) { + if (responseType === 'json' && !!window.JSON) { + return true; + } + return !!~Basic.inArray(responseType, ['text', 'document', '']); + }, + return_status_code: function(code) { + return !Basic.arrayDiff(code, [200, 404]); + }, + select_file: function() { + return Env.can('use_fileinput'); + }, + select_multiple: false, + send_binary_string: false, + send_custom_headers: false, + send_multipart: true, + slice_blob: false, + stream_upload: function() { + return I.can('select_file'); + }, + summon_file_dialog: Test(function() { // yeah... some dirty sniffing here... + return (Env.browser === 'Firefox' && Env.version >= 4) || + (Env.browser === 'Opera' && Env.version >= 12) || + !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']); + }()), + upload_filesize: True, + use_http_method: function(methods) { + return !Basic.arrayDiff(methods, ['GET', 'POST']); + } + }); + + + Basic.extend(this, { + init : function() { + this.trigger("Init"); + }, + + destroy: (function(destroy) { // extend default destroy method + return function() { + destroy.call(I); + destroy = I = null; + }; + }(this.destroy)) + }); + + Basic.extend(this.getShim(), extensions); + } + + Runtime.addConstructor(type, Html4Runtime); + + return extensions; +}); + +// Included from: src/javascript/runtime/html4/file/FileInput.js + +/** + * FileInput.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/file/FileInput +@private +*/ +define("moxie/runtime/html4/file/FileInput", [ + "moxie/runtime/html4/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Events", + "moxie/core/utils/Mime", + "moxie/core/utils/Env" +], function(extensions, Basic, Dom, Events, Mime, Env) { + + function FileInput() { + var _uid, _files = [], _mimes = [], _options; + + function addInput() { + var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid; + + uid = Basic.guid('uid_'); + + shimContainer = I.getShimContainer(); // we get new ref everytime to avoid memory leaks in IE + + if (_uid) { // move previous form out of the view + currForm = Dom.get(_uid + '_form'); + if (currForm) { + Basic.extend(currForm.style, { top: '100%' }); + } + } + + // build form in DOM, since innerHTML version not able to submit file for some reason + form = document.createElement('form'); + form.setAttribute('id', uid + '_form'); + form.setAttribute('method', 'post'); + form.setAttribute('enctype', 'multipart/form-data'); + form.setAttribute('encoding', 'multipart/form-data'); + + Basic.extend(form.style, { + overflow: 'hidden', + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' + }); + + input = document.createElement('input'); + input.setAttribute('id', uid); + input.setAttribute('type', 'file'); + input.setAttribute('name', _options.name || 'Filedata'); + input.setAttribute('accept', _mimes.join(',')); + + Basic.extend(input.style, { + fontSize: '999px', + opacity: 0 + }); + + form.appendChild(input); + shimContainer.appendChild(form); + + // prepare file input to be placed underneath the browse_button element + Basic.extend(input.style, { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%' + }); + + if (Env.browser === 'IE' && Env.version < 10) { + Basic.extend(input.style, { + filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)" + }); + } + + input.onchange = function() { // there should be only one handler for this + var file; + + if (!this.value) { + return; + } + + if (this.files) { + file = this.files[0]; + } else { + file = { + name: this.value + }; + } + + _files = [file]; + + this.onchange = function() {}; // clear event handler + addInput.call(comp); + + // after file is initialized as o.File, we need to update form and input ids + comp.bind('change', function onChange() { + var input = Dom.get(uid), form = Dom.get(uid + '_form'), file; + + comp.unbind('change', onChange); + + if (comp.files.length && input && form) { + file = comp.files[0]; + + input.setAttribute('id', file.uid); + form.setAttribute('id', file.uid + '_form'); + + // set upload target + form.setAttribute('target', file.uid + '_iframe'); + } + input = form = null; + }, 998); + + input = form = null; + comp.trigger('change'); + }; + + + // route click event to the input + if (I.can('summon_file_dialog')) { + browseButton = Dom.get(_options.browse_button); + Events.removeEvent(browseButton, 'click', comp.uid); + Events.addEvent(browseButton, 'click', function(e) { + if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] + input.click(); + } + e.preventDefault(); + }, comp.uid); + } + + _uid = uid; + + shimContainer = currForm = browseButton = null; + } + + Basic.extend(this, { + init: function(options) { + var comp = this, I = comp.getRuntime(), shimContainer; + + // figure out accept string + _options = options; + _mimes = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension')); + + shimContainer = I.getShimContainer(); + + (function() { + var browseButton, zIndex, top; + + browseButton = Dom.get(options.browse_button); + + // Route click event to the input[type=file] element for browsers that support such behavior + if (I.can('summon_file_dialog')) { + if (Dom.getStyle(browseButton, 'position') === 'static') { + browseButton.style.position = 'relative'; + } + + zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; + + browseButton.style.zIndex = zIndex; + shimContainer.style.zIndex = zIndex - 1; + } + + /* Since we have to place input[type=file] on top of the browse_button for some browsers, + browse_button loses interactivity, so we restore it here */ + top = I.can('summon_file_dialog') ? browseButton : shimContainer; + + Events.addEvent(top, 'mouseover', function() { + comp.trigger('mouseenter'); + }, comp.uid); + + Events.addEvent(top, 'mouseout', function() { + comp.trigger('mouseleave'); + }, comp.uid); + + Events.addEvent(top, 'mousedown', function() { + comp.trigger('mousedown'); + }, comp.uid); + + Events.addEvent(Dom.get(options.container), 'mouseup', function() { + comp.trigger('mouseup'); + }, comp.uid); + + browseButton = null; + }()); + + addInput.call(this); + + shimContainer = null; + + // trigger ready event asynchronously + comp.trigger({ + type: 'ready', + async: true + }); + }, + + getFiles: function() { + return _files; + }, + + disable: function(state) { + var input; + + if ((input = Dom.get(_uid))) { + input.disabled = !!state; + } + }, + + destroy: function() { + var I = this.getRuntime() + , shim = I.getShim() + , shimContainer = I.getShimContainer() + ; + + Events.removeAllEvents(shimContainer, this.uid); + Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); + Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid); + + if (shimContainer) { + shimContainer.innerHTML = ''; + } + + shim.removeInstance(this.uid); + + _uid = _files = _mimes = _options = shimContainer = shim = null; + } + }); + } + + return (extensions.FileInput = FileInput); +}); + +// Included from: src/javascript/runtime/html4/file/FileReader.js + +/** + * FileReader.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/file/FileReader +@private +*/ +define("moxie/runtime/html4/file/FileReader", [ + "moxie/runtime/html4/Runtime", + "moxie/runtime/html5/file/FileReader" +], function(extensions, FileReader) { + return (extensions.FileReader = FileReader); +}); + +// Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js + +/** + * XMLHttpRequest.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/xhr/XMLHttpRequest +@private +*/ +define("moxie/runtime/html4/xhr/XMLHttpRequest", [ + "moxie/runtime/html4/Runtime", + "moxie/core/utils/Basic", + "moxie/core/utils/Dom", + "moxie/core/utils/Url", + "moxie/core/Exceptions", + "moxie/core/utils/Events", + "moxie/file/Blob", + "moxie/xhr/FormData" +], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) { + + function XMLHttpRequest() { + var _status, _response, _iframe; + + function cleanup(cb) { + var target = this, uid, form, inputs, i, hasFile = false; + + if (!_iframe) { + return; + } + + uid = _iframe.id.replace(/_iframe$/, ''); + + form = Dom.get(uid + '_form'); + if (form) { + inputs = form.getElementsByTagName('input'); + i = inputs.length; + + while (i--) { + switch (inputs[i].getAttribute('type')) { + case 'hidden': + inputs[i].parentNode.removeChild(inputs[i]); + break; + case 'file': + hasFile = true; // flag the case for later + break; + } + } + inputs = []; + + if (!hasFile) { // we need to keep the form for sake of possible retries + form.parentNode.removeChild(form); + } + form = null; + } + + // without timeout, request is marked as canceled (in console) + setTimeout(function() { + Events.removeEvent(_iframe, 'load', target.uid); + if (_iframe.parentNode) { // #382 + _iframe.parentNode.removeChild(_iframe); + } + + // check if shim container has any other children, if - not, remove it as well + var shimContainer = target.getRuntime().getShimContainer(); + if (!shimContainer.children.length) { + shimContainer.parentNode.removeChild(shimContainer); + } + + shimContainer = _iframe = null; + cb(); + }, 1); + } + + Basic.extend(this, { + send: function(meta, data) { + var target = this, I = target.getRuntime(), uid, form, input, blob; + + _status = _response = null; + + function createIframe() { + var container = I.getShimContainer() || document.body + , temp = document.createElement('div') + ; + + // IE 6 won't be able to set the name using setAttribute or iframe.name + temp.innerHTML = ''; + _iframe = temp.firstChild; + container.appendChild(_iframe); + + /* _iframe.onreadystatechange = function() { + console.info(_iframe.readyState); + };*/ + + Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8 + var el; + + try { + el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document; + + // try to detect some standard error pages + if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error + _status = el.title.replace(/^(\d+).*$/, '$1'); + } else { + _status = 200; + // get result + _response = Basic.trim(el.body.innerHTML); + + // we need to fire these at least once + target.trigger({ + type: 'progress', + loaded: _response.length, + total: _response.length + }); + + if (blob) { // if we were uploading a file + target.trigger({ + type: 'uploadprogress', + loaded: blob.size || 1025, + total: blob.size || 1025 + }); + } + } + } catch (ex) { + if (Url.hasSameOrigin(meta.url)) { + // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm + // which obviously results to cross domain error (wtf?) + _status = 404; + } else { + cleanup.call(target, function() { + target.trigger('error'); + }); + return; + } + } + + cleanup.call(target, function() { + target.trigger('load'); + }); + }, target.uid); + } // end createIframe + + // prepare data to be sent and convert if required + if (data instanceof FormData && data.hasBlob()) { + blob = data.getBlob(); + uid = blob.uid; + input = Dom.get(uid); + form = Dom.get(uid + '_form'); + if (!form) { + throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); + } + } else { + uid = Basic.guid('uid_'); + + form = document.createElement('form'); + form.setAttribute('id', uid + '_form'); + form.setAttribute('method', meta.method); + form.setAttribute('enctype', 'multipart/form-data'); + form.setAttribute('encoding', 'multipart/form-data'); + form.setAttribute('target', uid + '_iframe'); + + I.getShimContainer().appendChild(form); + } + + if (data instanceof FormData) { + data.each(function(value, name) { + if (value instanceof Blob) { + if (input) { + input.setAttribute('name', name); + } + } else { + var hidden = document.createElement('input'); + + Basic.extend(hidden, { + type : 'hidden', + name : name, + value : value + }); + + // make sure that input[type="file"], if it's there, comes last + if (input) { + form.insertBefore(hidden, input); + } else { + form.appendChild(hidden); + } + } + }); + } + + // set destination url + form.setAttribute("action", meta.url); + + createIframe(); + form.submit(); + target.trigger('loadstart'); + }, + + getStatus: function() { + return _status; + }, + + getResponse: function(responseType) { + if ('json' === responseType) { + // strip off
                        ..
                        tags that might be enclosing the response + if (Basic.typeOf(_response) === 'string' && !!window.JSON) { + try { + return JSON.parse(_response.replace(/^\s*]*>/, '').replace(/<\/pre>\s*$/, '')); + } catch (ex) { + return null; + } + } + } else if ('document' === responseType) { + + } + return _response; + }, + + abort: function() { + var target = this; + + if (_iframe && _iframe.contentWindow) { + if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome + _iframe.contentWindow.stop(); + } else if (_iframe.contentWindow.document.execCommand) { // IE + _iframe.contentWindow.document.execCommand('Stop'); + } else { + _iframe.src = "about:blank"; + } + } + + cleanup.call(this, function() { + // target.dispatchEvent('readystatechange'); + target.dispatchEvent('abort'); + }); + } + }); + } + + return (extensions.XMLHttpRequest = XMLHttpRequest); +}); + +// Included from: src/javascript/runtime/html4/image/Image.js + +/** + * Image.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/** +@class moxie/runtime/html4/image/Image +@private +*/ +define("moxie/runtime/html4/image/Image", [ + "moxie/runtime/html4/Runtime", + "moxie/runtime/html5/image/Image" +], function(extensions, Image) { + return (extensions.Image = Image); +}); + +expose(["moxie/core/utils/Basic","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/utils/Encode","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/file/File","moxie/file/FileInput","moxie/file/FileDrop","moxie/runtime/RuntimeTarget","moxie/file/FileReader","moxie/core/utils/Url","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]); +})(this);/** + * o.js + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + */ + +/*global moxie:true */ + +/** +Globally exposed namespace with the most frequently used public classes and handy methods. + +@class o +@static +@private +*/ +(function() { + "use strict"; + + var o = {}, inArray = moxie.core.utils.Basic.inArray; + + // directly add some public classes + // (we do it dynamically here, since for custom builds we cannot know beforehand what modules were included) + (function addAlias(ns) { + var name, itemType; + for (name in ns) { + itemType = typeof(ns[name]); + if (itemType === 'object' && !~inArray(name, ['Exceptions', 'Env', 'Mime'])) { + addAlias(ns[name]); + } else if (itemType === 'function') { + o[name] = ns[name]; + } + } + })(window.moxie); + + // add some manually + o.Env = window.moxie.core.utils.Env; + o.Mime = window.moxie.core.utils.Mime; + o.Exceptions = window.moxie.core.Exceptions; + + // expose globally + window.mOxie = o; + if (!window.o) { + window.o = o; + } + return o; +})(); diff --git a/lib/scripts/uploader/moxie.min.js b/lib/scripts/uploader/moxie.min.js new file mode 100644 index 0000000..99e119e --- /dev/null +++ b/lib/scripts/uploader/moxie.min.js @@ -0,0 +1,15 @@ +/** + * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill + * v1.2.0 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2014-01-16 + */ +!function(e,t){"use strict";function n(e,t){for(var n,i=[],r=0;r0&&n(o,function(n,o){n!==r&&(e(i[o])===e(n)&&~a(e(n),["array","object"])?t(i[o],n):i[o]=n)})}),i},n=function(e,t){var n,i,r,o;if(e){try{n=e.length}catch(a){n=o}if(n===o){for(i in e)if(e.hasOwnProperty(i)&&t(e[i],i)===!1)return}else for(r=0;n>r;r++)if(t(e[r],r)===!1)return}},i=function(t){var n;if(!t||"object"!==e(t))return!0;for(n in t)return!1;return!0},r=function(t,n){function i(r){"function"===e(t[r])&&t[r](function(e){++rn;n++)if(t[n]===e)return n}return-1},s=function(t,n){var i=[];"array"!==e(t)&&(t=[t]),"array"!==e(n)&&(n=[n]);for(var r in t)-1===a(t[r],n)&&i.push(t[r]);return i.length?i:!1},u=function(e,t){var i=[];return n(e,function(e){-1!==a(e,t)&&i.push(e)}),i.length?i:null},c=function(e){var t,n=[];for(t=0;ti;i++)n+=Math.floor(65535*Math.random()).toString(32);return(t||"o_")+n+(e++).toString(32)}}(),d=function(e){return e?String.prototype.trim?String.prototype.trim.call(e):e.toString().replace(/^\s*/,"").replace(/\s*$/,""):e},f=function(e){if("string"!=typeof e)return e;var t={t:1099511627776,g:1073741824,m:1048576,k:1024},n;return e=/^([0-9]+)([mgk]?)$/.exec(e.toLowerCase().replace(/[^0-9mkg]/g,"")),n=e[2],e=+e[1],t.hasOwnProperty(n)&&(e*=t[n]),e};return{guid:l,typeOf:e,extend:t,each:n,isEmptyObj:i,inSeries:r,inParallel:o,inArray:a,arrayDiff:s,arrayIntersect:u,toArray:c,trim:d,parseSizeStr:f}}),i(c,[u],function(e){var t={};return{addI18n:function(n){return e.extend(t,n)},translate:function(e){return t[e]||e},_:function(e){return this.translate(e)},sprintf:function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e.typeOf(t)?t:""})}}}),i(l,[u,c],function(e,t){var n="application/msword,doc dot,application/pdf,pdf,application/pgp-signature,pgp,application/postscript,ps ai eps,application/rtf,rtf,application/vnd.ms-excel,xls xlb,application/vnd.ms-powerpoint,ppt pps pot,application/zip,zip,application/x-shockwave-flash,swf swfl,application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx,application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx,application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx,application/vnd.openxmlformats-officedocument.presentationml.template,potx,application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx,application/x-javascript,js,application/json,json,audio/mpeg,mp3 mpga mpega mp2,audio/x-wav,wav,audio/x-m4a,m4a,audio/ogg,oga ogg,audio/aiff,aiff aif,audio/flac,flac,audio/aac,aac,audio/ac3,ac3,audio/x-ms-wma,wma,image/bmp,bmp,image/gif,gif,image/jpeg,jpg jpeg jpe,image/photoshop,psd,image/png,png,image/svg+xml,svg svgz,image/tiff,tiff tif,text/plain,asc txt text diff log,text/html,htm html xhtml,text/css,css,text/csv,csv,text/rtf,rtf,video/mpeg,mpeg mpg mpe m2v,video/quicktime,qt mov,video/mp4,mp4,video/x-m4v,m4v,video/x-flv,flv,video/x-ms-wmv,wmv,video/avi,avi,video/webm,webm,video/3gpp,3gpp 3gp,video/3gpp2,3g2,video/vnd.rn-realvideo,rv,video/ogg,ogv,video/x-matroska,mkv,application/vnd.oasis.opendocument.formula-template,otf,application/octet-stream,exe",i={mimes:{},extensions:{},addMimeType:function(e){var t=e.split(/,/),n,i,r;for(n=0;ni;i++)if(e[i]!=t[i]){if(e[i]=u(e[i]),t[i]=u(t[i]),e[i]t[i]){o=1;break}}if(!n)return o;switch(n){case">":case"gt":return o>0;case">=":case"ge":return o>=0;case"<=":case"le":return 0>=o;case"==":case"=":case"eq":return 0===o;case"<>":case"!=":case"ne":return 0!==o;case"":case"<":case"lt":return 0>o;default:return null}}var n=function(e){var t="",n="?",i="function",r="undefined",o="object",a="major",s="model",u="name",c="type",l="vendor",d="version",f="architecture",p="console",h="mobile",m="tablet",g={has:function(e,t){return-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()}},v={rgx:function(){for(var t,n=0,a,s,u,c,l,d,f=arguments;n0?2==c.length?t[c[0]]=typeof c[1]==i?c[1].call(this,d):c[1]:3==c.length?t[c[0]]=typeof c[1]!==i||c[1].exec&&c[1].test?d?d.replace(c[1],c[2]):e:d?c[1].call(this,d,c[2]):e:4==c.length&&(t[c[0]]=d?c[3].call(this,d.replace(c[1],c[2])):e):t[c]=d?d:e;break}if(l)break}return t},str:function(t,i){for(var r in i)if(typeof i[r]===o&&i[r].length>0){for(var a=0;a=9)},use_data_uri_of:function(e){return t.use_data_uri&&33e3>e||t.use_data_uri_over32kb()},use_fileinput:function(){var e=document.createElement("input");return e.setAttribute("type","file"),!e.disabled}};return function(n){var i=[].slice.call(arguments);return i.shift(),"function"===e.typeOf(t[n])?t[n].apply(this,i):!!t[n]}}(),r={can:i,browser:n.browser.name,version:parseFloat(n.browser.major),os:n.os.name,osVersion:n.os.version,verComp:t,swf_url:"../flash/Moxie.swf",xap_url:"../silverlight/Moxie.xap",global_event_dispatcher:"moxie.core.EventTarget.instance.dispatchEvent"};return r.OS=r.os,r}),i(f,[d],function(e){var t=function(e){return"string"!=typeof e?e:document.getElementById(e)},n=function(e,t){if(!e.className)return!1;var n=new RegExp("(^|\\s+)"+t+"(\\s+|$)");return n.test(e.className)},i=function(e,t){n(e,t)||(e.className=e.className?e.className.replace(/\s+$/,"")+" "+t:t)},r=function(e,t){if(e.className){var n=new RegExp("(^|\\s+)"+t+"(\\s+|$)");e.className=e.className.replace(n,function(e,t,n){return" "===t&&" "===n?" ":""})}},o=function(e,t){return e.currentStyle?e.currentStyle[t]:window.getComputedStyle?window.getComputedStyle(e,null)[t]:void 0},a=function(t,n){function i(e){var t,n,i=0,r=0;return e&&(n=e.getBoundingClientRect(),t="CSS1Compat"===s.compatMode?s.documentElement:s.body,i=n.left+t.scrollLeft,r=n.top+t.scrollTop),{x:i,y:r}}var r=0,o=0,a,s=document,u,c;if(t=t,n=n||s.body,t&&t.getBoundingClientRect&&"IE"===e.browser&&(!s.documentMode||s.documentMode<8))return u=i(t),c=i(n),{x:u.x-c.x,y:u.y-c.y};for(a=t;a&&a!=n&&a.nodeType;)r+=a.offsetLeft||0,o+=a.offsetTop||0,a=a.offsetParent;for(a=t.parentNode;a&&a!=n&&a.nodeType;)r-=a.scrollLeft||0,o-=a.scrollTop||0,a=a.parentNode;return{x:r,y:o}},s=function(e){return{w:e.offsetWidth||e.clientWidth,h:e.offsetHeight||e.clientHeight}};return{get:t,hasClass:n,addClass:i,removeClass:r,getStyle:o,getPos:a,getSize:s}}),i(p,[u],function(e){function t(e,t){var n;for(n in e)if(e[n]===t)return n;return null}return{RuntimeError:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": RuntimeError "+this.code}var i={NOT_INIT_ERR:1,NOT_SUPPORTED_ERR:9,JS_ERR:4};return e.extend(n,i),n.prototype=Error.prototype,n}(),OperationNotAllowedException:function(){function t(e){this.code=e,this.name="OperationNotAllowedException"}return e.extend(t,{NOT_ALLOWED_ERR:1}),t.prototype=Error.prototype,t}(),ImageError:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": ImageError "+this.code}var i={WRONG_FORMAT:1,MAX_RESOLUTION_ERR:2};return e.extend(n,i),n.prototype=Error.prototype,n}(),FileException:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": FileException "+this.code}var i={NOT_FOUND_ERR:1,SECURITY_ERR:2,ABORT_ERR:3,NOT_READABLE_ERR:4,ENCODING_ERR:5,NO_MODIFICATION_ALLOWED_ERR:6,INVALID_STATE_ERR:7,SYNTAX_ERR:8};return e.extend(n,i),n.prototype=Error.prototype,n}(),DOMException:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": DOMException "+this.code}var i={INDEX_SIZE_ERR:1,DOMSTRING_SIZE_ERR:2,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,INVALID_CHARACTER_ERR:5,NO_DATA_ALLOWED_ERR:6,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INUSE_ATTRIBUTE_ERR:10,INVALID_STATE_ERR:11,SYNTAX_ERR:12,INVALID_MODIFICATION_ERR:13,NAMESPACE_ERR:14,INVALID_ACCESS_ERR:15,VALIDATION_ERR:16,TYPE_MISMATCH_ERR:17,SECURITY_ERR:18,NETWORK_ERR:19,ABORT_ERR:20,URL_MISMATCH_ERR:21,QUOTA_EXCEEDED_ERR:22,TIMEOUT_ERR:23,INVALID_NODE_TYPE_ERR:24,DATA_CLONE_ERR:25};return e.extend(n,i),n.prototype=Error.prototype,n}(),EventException:function(){function t(e){this.code=e,this.name="EventException"}return e.extend(t,{UNSPECIFIED_EVENT_TYPE_ERR:0}),t.prototype=Error.prototype,t}()}}),i(h,[p,u],function(e,t){function n(){var n={};t.extend(this,{uid:null,init:function(){this.uid||(this.uid=t.guid("uid_"))},addEventListener:function(e,i,r,o){var a=this,s;return e=t.trim(e),/\s/.test(e)?(t.each(e.split(/\s+/),function(e){a.addEventListener(e,i,r,o)}),void 0):(e=e.toLowerCase(),r=parseInt(r,10)||0,s=n[this.uid]&&n[this.uid][e]||[],s.push({fn:i,priority:r,scope:o||this}),n[this.uid]||(n[this.uid]={}),n[this.uid][e]=s,void 0)},hasEventListener:function(e){return e?!(!n[this.uid]||!n[this.uid][e]):!!n[this.uid]},removeEventListener:function(e,i){e=e.toLowerCase();var r=n[this.uid]&&n[this.uid][e],o;if(r){if(i){for(o=r.length-1;o>=0;o--)if(r[o].fn===i){r.splice(o,1);break}}else r=[];r.length||(delete n[this.uid][e],t.isEmptyObj(n[this.uid])&&delete n[this.uid])}},removeAllEventListeners:function(){n[this.uid]&&delete n[this.uid]},dispatchEvent:function(i){var r,o,a,s,u={},c=!0,l;if("string"!==t.typeOf(i)){if(s=i,"string"!==t.typeOf(s.type))throw new e.EventException(e.EventException.UNSPECIFIED_EVENT_TYPE_ERR);i=s.type,s.total!==l&&s.loaded!==l&&(u.total=s.total,u.loaded=s.loaded),u.async=s.async||!1}if(-1!==i.indexOf("::")?function(e){r=e[0],i=e[1]}(i.split("::")):r=this.uid,i=i.toLowerCase(),o=n[r]&&n[r][i]){o.sort(function(e,t){return t.priority-e.priority}),a=[].slice.call(arguments),a.shift(),u.type=i,a.unshift(u);var d=[];t.each(o,function(e){a[0].target=e.scope,u.async?d.push(function(t){setTimeout(function(){t(e.fn.apply(e.scope,a)===!1)},1)}):d.push(function(t){t(e.fn.apply(e.scope,a)===!1)})}),d.length&&t.inSeries(d,function(e){c=!e})}return c},bind:function(){this.addEventListener.apply(this,arguments)},unbind:function(){this.removeEventListener.apply(this,arguments)},unbindAll:function(){this.removeAllEventListeners.apply(this,arguments)},trigger:function(){return this.dispatchEvent.apply(this,arguments)},convertEventPropsToHandlers:function(e){var n;"array"!==t.typeOf(e)&&(e=[e]);for(var i=0;i>16,o=255&d>>8,a=255&d,m[p++]=64==c?String.fromCharCode(r):64==l?String.fromCharCode(r,o):String.fromCharCode(r,o,a);while(f>18,u=63&d>>12,c=63&d>>6,l=63&d,m[p++]=i.charAt(s)+i.charAt(u)+i.charAt(c)+i.charAt(l);while(fa;a++)o+=String.fromCharCode(r[a]);return o}}t.call(this),e.extend(this,{uid:e.guid("uid_"),readAsBinaryString:function(e){return i.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){return i.call(this,"readAsDataURL",e)},readAsText:function(e){return i.call(this,"readAsText",e)}})}}),i(S,[p,u,y],function(e,t,n){function i(){var e,i=[];t.extend(this,{append:function(r,o){var a=this,s=t.typeOf(o);o instanceof n?e={name:r,value:o}:"array"===s?(r+="[]",t.each(o,function(e){a.append(r,e)})):"object"===s?t.each(o,function(e,t){a.append(r+"["+t+"]",e)}):"null"===s||"undefined"===s||"number"===s&&isNaN(o)?a.append(r,"false"):i.push({name:r,value:o.toString()})},hasBlob:function(){return!!this.getBlob()},getBlob:function(){return e&&e.value||null},getBlobName:function(){return e&&e.name||null},each:function(n){t.each(i,function(e){n(e.value,e.name)}),e&&n(e.value,e.name)},destroy:function(){e=null,i=[]}})}return i}),i(A,[u,p,h,m,b,g,x,y,T,S,d,l],function(e,t,n,i,r,o,a,s,u,c,l,d){function f(){this.uid=e.guid("uid_")}function p(){function n(e,t){return y.hasOwnProperty(e)?1===arguments.length?l.can("define_property")?y[e]:v[e]:(l.can("define_property")?y[e]=t:v[e]=t,void 0):void 0}function u(t){function i(){k.destroy(),k=null,s.dispatchEvent("loadend"),s=null}function r(r){k.bind("LoadStart",function(e){n("readyState",p.LOADING),s.dispatchEvent("readystatechange"),s.dispatchEvent(e),I&&s.upload.dispatchEvent(e)}),k.bind("Progress",function(e){n("readyState")!==p.LOADING&&(n("readyState",p.LOADING),s.dispatchEvent("readystatechange")),s.dispatchEvent(e)}),k.bind("UploadProgress",function(e){I&&s.upload.dispatchEvent({type:"progress",lengthComputable:!1,total:e.total,loaded:e.loaded})}),k.bind("Load",function(t){n("readyState",p.DONE),n("status",Number(r.exec.call(k,"XMLHttpRequest","getStatus")||0)),n("statusText",h[n("status")]||""),n("response",r.exec.call(k,"XMLHttpRequest","getResponse",n("responseType"))),~e.inArray(n("responseType"),["text",""])?n("responseText",n("response")):"document"===n("responseType")&&n("responseXML",n("response")),U=r.exec.call(k,"XMLHttpRequest","getAllResponseHeaders"),s.dispatchEvent("readystatechange"),n("status")>0?(I&&s.upload.dispatchEvent(t),s.dispatchEvent(t)):(N=!0,s.dispatchEvent("error")),i()}),k.bind("Abort",function(e){s.dispatchEvent(e),i()}),k.bind("Error",function(e){N=!0,n("readyState",p.DONE),s.dispatchEvent("readystatechange"),D=!0,s.dispatchEvent(e),i()}),r.exec.call(k,"XMLHttpRequest","send",{url:E,method:_,async:w,user:R,password:b,headers:x,mimeType:S,encoding:T,responseType:s.responseType,withCredentials:s.withCredentials,options:P},t)}var s=this;M=(new Date).getTime(),k=new a,"string"==typeof P.required_caps&&(P.required_caps=o.parseCaps(P.required_caps)),P.required_caps=e.extend({},P.required_caps,{return_response_type:s.responseType}),t instanceof c&&(P.required_caps.send_multipart=!0),L||(P.required_caps.do_cors=!0),P.ruid?r(k.connectRuntime(P)):(k.bind("RuntimeInit",function(e,t){r(t)}),k.bind("RuntimeError",function(e,t){s.dispatchEvent("RuntimeError",t)}),k.connectRuntime(P))}function g(){n("responseText",""),n("responseXML",null),n("response",null),n("status",0),n("statusText",""),M=C=null}var v=this,y={timeout:0,readyState:p.UNSENT,withCredentials:!1,status:0,statusText:"",responseType:"",responseXML:null,responseText:null,response:null},w=!0,E,_,x={},R,b,T=null,S=null,A=!1,O=!1,I=!1,D=!1,N=!1,L=!1,M,C,F=null,H=null,P={},k,U="",B;e.extend(this,y,{uid:e.guid("uid_"),upload:new f,open:function(o,a,s,u,c){var l;if(!o||!a)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(/[\u0100-\uffff]/.test(o)||i.utf8_encode(o)!==o)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(~e.inArray(o.toUpperCase(),["CONNECT","DELETE","GET","HEAD","OPTIONS","POST","PUT","TRACE","TRACK"])&&(_=o.toUpperCase()),~e.inArray(_,["CONNECT","TRACE","TRACK"]))throw new t.DOMException(t.DOMException.SECURITY_ERR);if(a=i.utf8_encode(a),l=r.parseUrl(a),L=r.hasSameOrigin(l),E=r.resolveUrl(a),(u||c)&&!L)throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);if(R=u||l.user,b=c||l.pass,w=s||!0,w===!1&&(n("timeout")||n("withCredentials")||""!==n("responseType")))throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);A=!w,O=!1,x={},g.call(this),n("readyState",p.OPENED),this.convertEventPropsToHandlers(["readystatechange"]),this.dispatchEvent("readystatechange")},setRequestHeader:function(r,o){var a=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","content-transfer-encoding","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","user-agent","via"];if(n("readyState")!==p.OPENED||O)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(/[\u0100-\uffff]/.test(r)||i.utf8_encode(r)!==r)throw new t.DOMException(t.DOMException.SYNTAX_ERR);return r=e.trim(r).toLowerCase(),~e.inArray(r,a)||/^(proxy\-|sec\-)/.test(r)?!1:(x[r]?x[r]+=", "+o:x[r]=o,!0)},getAllResponseHeaders:function(){return U||""},getResponseHeader:function(t){return t=t.toLowerCase(),N||~e.inArray(t,["set-cookie","set-cookie2"])?null:U&&""!==U&&(B||(B={},e.each(U.split(/\r\n/),function(t){var n=t.split(/:\s+/);2===n.length&&(n[0]=e.trim(n[0]),B[n[0].toLowerCase()]={header:n[0],value:e.trim(n[1])})})),B.hasOwnProperty(t))?B[t].header+": "+B[t].value:null},overrideMimeType:function(i){var r,o;if(~e.inArray(n("readyState"),[p.LOADING,p.DONE]))throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(i=e.trim(i.toLowerCase()),/;/.test(i)&&(r=i.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))&&(i=r[1],r[2]&&(o=r[2])),!d.mimes[i])throw new t.DOMException(t.DOMException.SYNTAX_ERR);F=i,H=o},send:function(n,r){if(P="string"===e.typeOf(r)?{ruid:r}:r?r:{},this.convertEventPropsToHandlers(m),this.upload.convertEventPropsToHandlers(m),this.readyState!==p.OPENED||O)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(n instanceof s)P.ruid=n.ruid,S=n.type||"application/octet-stream";else if(n instanceof c){if(n.hasBlob()){var o=n.getBlob();P.ruid=o.ruid,S=o.type||"application/octet-stream"}}else"string"==typeof n&&(T="UTF-8",S="text/plain;charset=UTF-8",n=i.utf8_encode(n));this.withCredentials||(this.withCredentials=P.required_caps&&P.required_caps.send_browser_cookies&&!L),I=!A&&this.upload.hasEventListener(),N=!1,D=!n,A||(O=!0),u.call(this,n)},abort:function(){if(N=!0,A=!1,~e.inArray(n("readyState"),[p.UNSENT,p.OPENED,p.DONE]))n("readyState",p.UNSENT);else{if(n("readyState",p.DONE),O=!1,!k)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);k.getRuntime().exec.call(k,"XMLHttpRequest","abort",D),D=!0}},destroy:function(){k&&("function"===e.typeOf(k.destroy)&&k.destroy(),k=null),this.unbindAll(),this.upload&&(this.upload.unbindAll(),this.upload=null)}})}var h={100:"Continue",101:"Switching Protocols",102:"Processing",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",306:"Reserved",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",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",426:"Upgrade Required",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",510:"Not Extended"};f.prototype=n.instance;var m=["loadstart","progress","abort","error","load","timeout","loadend"],g=1,v=2;return p.UNSENT=0,p.OPENED=1,p.HEADERS_RECEIVED=2,p.LOADING=3,p.DONE=4,p.prototype=n.instance,p}),i(O,[u,m,v,h],function(e,t,n,i){function r(){function i(){l=d=0,c=this.result=null}function o(t,n){var i=this;u=n,i.bind("TransportingProgress",function(t){d=t.loaded,l>d&&-1===e.inArray(i.state,[r.IDLE,r.DONE])&&a.call(i)},999),i.bind("TransportingComplete",function(){d=l,i.state=r.DONE,c=null,i.result=u.exec.call(i,"Transporter","getAsBlob",t||"")},999),i.state=r.BUSY,i.trigger("TransportingStarted"),a.call(i)}function a(){var e=this,n,i=l-d;f>i&&(f=i),n=t.btoa(c.substr(d,f)),u.exec.call(e,"Transporter","receive",n,l)}var s,u,c,l,d,f;n.call(this),e.extend(this,{uid:e.guid("uid_"),state:r.IDLE,result:null,transport:function(t,n,r){var a=this;if(r=e.extend({chunk_size:204798},r),(s=r.chunk_size%3)&&(r.chunk_size+=3-s),f=r.chunk_size,i.call(this),c=t,l=t.length,"string"===e.typeOf(r)||r.ruid)o.call(a,n,this.connectRuntime(r));else{var u=function(e,t){a.unbind("RuntimeInit",u),o.call(a,n,t)};this.bind("RuntimeInit",u),this.connectRuntime(r)}},abort:function(){var e=this;e.state=r.IDLE,u&&(u.exec.call(e,"Transporter","clear"),e.trigger("TransportingAborted")),i.call(e)},destroy:function(){this.unbindAll(),u=null,this.disconnectRuntime(),i.call(this)}})}return r.IDLE=0,r.BUSY=1,r.DONE=2,r.prototype=i.instance,r}),i(I,[u,f,p,T,A,g,v,O,d,h,y,w,m],function(e,t,n,i,r,o,a,s,u,c,l,d,f){function p(){function i(e){e||(e=this.getRuntime().exec.call(this,"Image","getInfo")),this.size=e.size,this.width=e.width,this.height=e.height,this.type=e.type,this.meta=e.meta,""===this.name&&(this.name=e.name)}function c(t){var i=e.typeOf(t);try{if(t instanceof p){if(!t.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);m.apply(this,arguments)}else if(t instanceof l){if(!~e.inArray(t.type,["image/jpeg","image/png"]))throw new n.ImageError(n.ImageError.WRONG_FORMAT);g.apply(this,arguments)}else if(-1!==e.inArray(i,["blob","file"]))c.call(this,new d(null,t),arguments[1]);else if("string"===i)/^data:[^;]*;base64,/.test(t)?c.call(this,new l(null,{data:t}),arguments[1]):v.apply(this,arguments);else{if("node"!==i||"img"!==t.nodeName.toLowerCase())throw new n.DOMException(n.DOMException.TYPE_MISMATCH_ERR);c.call(this,t.src,arguments[1])}}catch(r){this.trigger("error",r)}}function m(t,n){var i=this.connectRuntime(t.ruid);this.ruid=i.uid,i.exec.call(this,"Image","loadFromImage",t,"undefined"===e.typeOf(n)?!0:n)}function g(t,n){function i(e){r.ruid=e.uid,e.exec.call(r,"Image","loadFromBlob",t)}var r=this;r.name=t.name||"",t.isDetached()?(this.bind("RuntimeInit",function(e,t){i(t)}),n&&"string"==typeof n.required_caps&&(n.required_caps=o.parseCaps(n.required_caps)),this.connectRuntime(e.extend({required_caps:{access_image_binary:!0,resize_image:!0}},n))):i(this.connectRuntime(t.ruid))}function v(e,t){var n=this,i;i=new r,i.open("get",e),i.responseType="blob",i.onprogress=function(e){n.trigger(e)},i.onload=function(){g.call(n,i.response,!0)},i.onerror=function(e){n.trigger(e)},i.onloadend=function(){i.destroy()},i.bind("RuntimeError",function(e,t){n.trigger("RuntimeError",t)}),i.send(null,t)}a.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,name:"",size:0,width:0,height:0,type:"",meta:{},clone:function(){this.load.apply(this,arguments)},load:function(){this.bind("Load Resize",function(){i.call(this)},999),this.convertEventPropsToHandlers(h),c.apply(this,arguments)},downsize:function(t,i,r,o){try{if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>p.MAX_RESIZE_WIDTH||this.height>p.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);(!t&&!i||"undefined"===e.typeOf(r))&&(r=!1),t=t||this.width,i=i||this.height,o="undefined"===e.typeOf(o)?!0:!!o,this.getRuntime().exec.call(this,"Image","downsize",t,i,r,o)}catch(a){this.trigger("error",a)}},crop:function(e,t,n){this.downsize(e,t,!0,n)},getAsCanvas:function(){if(!u.can("create_canvas"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);var e=this.connectRuntime(this.ruid);return e.exec.call(this,"Image","getAsCanvas")},getAsBlob:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return e||(e="image/jpeg"),"image/jpeg"!==e||t||(t=90),this.getRuntime().exec.call(this,"Image","getAsBlob",e,t)},getAsDataURL:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.getRuntime().exec.call(this,"Image","getAsDataURL",e,t)},getAsBinaryString:function(e,t){var n=this.getAsDataURL(e,t);return f.atob(n.substring(n.indexOf("base64,")+7))},embed:function(i){function r(){if(u.can("create_canvas")){var t=a.getAsCanvas();if(t)return i.appendChild(t),t=null,a.destroy(),o.trigger("embedded"),void 0}var r=a.getAsDataURL(c,l);if(!r)throw new n.ImageError(n.ImageError.WRONG_FORMAT);if(u.can("use_data_uri_of",r.length))i.innerHTML='',a.destroy(),o.trigger("embedded");else{var d=new s;d.bind("TransportingComplete",function(){v=o.connectRuntime(this.result.ruid),o.bind("Embedded",function(){e.extend(v.getShimContainer().style,{top:"0px",left:"0px",width:a.width+"px",height:a.height+"px"}),v=null},999),v.exec.call(o,"ImageView","display",this.result.uid,m,g),a.destroy()}),d.transport(f.atob(r.substring(r.indexOf("base64,")+7)),c,e.extend({},h,{required_caps:{display_media:!0},runtime_order:"flash,silverlight",container:i}))}}var o=this,a,c,l,d,h=arguments[1]||{},m=this.width,g=this.height,v;try{if(!(i=t.get(i)))throw new n.DOMException(n.DOMException.INVALID_NODE_TYPE_ERR);if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>p.MAX_RESIZE_WIDTH||this.height>p.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);if(c=h.type||this.type||"image/jpeg",l=h.quality||90,d="undefined"!==e.typeOf(h.crop)?h.crop:!1,h.width)m=h.width,g=h.height||m;else{var y=t.getSize(i);y.w&&y.h&&(m=y.w,g=y.h)}return a=new p,a.bind("Resize",function(){r.call(o)}),a.bind("Load",function(){a.downsize(m,g,d,!1)}),a.clone(this,!1),a}catch(w){this.trigger("error",w)}},destroy:function(){this.ruid&&(this.getRuntime().exec.call(this,"Image","destroy"),this.disconnectRuntime()),this.unbindAll()}})}var h=["progress","load","error","resize","embedded"];return p.MAX_RESIZE_WIDTH=6500,p.MAX_RESIZE_HEIGHT=6500,p.prototype=c.instance,p}),i(D,[u,p,g,d],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue,c=e.extend({access_binary:s(window.FileReader||window.File&&window.File.getAsDataURL),access_image_binary:function(){return r.can("access_binary")&&!!a.Image},display_media:s(i.can("create_canvas")||i.can("use_data_uri_over32kb")),do_cors:s(window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest),drag_and_drop:s(function(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&("IE"!==i.browser||i.version>9)}()),filter_by_extension:s(function(){return"Chrome"===i.browser&&i.version>=28||"IE"===i.browser&&i.version>=10}()),return_response_headers:u,return_response_type:function(e){return"json"===e&&window.JSON?!0:i.can("return_response_type",e)},return_status_code:u,report_upload_progress:s(window.XMLHttpRequest&&(new XMLHttpRequest).upload),resize_image:function(){return r.can("access_binary")&&i.can("create_canvas")},select_file:function(){return i.can("use_fileinput")&&window.File},select_folder:function(){return r.can("select_file")&&"Chrome"===i.browser&&i.version>=21},select_multiple:function(){return!(!r.can("select_file")||"Safari"===i.browser&&"Windows"===i.os||"iOS"===i.os&&i.verComp(i.osVersion,"7.0.4","<"))},send_binary_string:s(window.XMLHttpRequest&&((new XMLHttpRequest).sendAsBinary||window.Uint8Array&&window.ArrayBuffer)),send_custom_headers:s(window.XMLHttpRequest),send_multipart:function(){return!!(window.XMLHttpRequest&&(new XMLHttpRequest).upload&&window.FormData)||r.can("send_binary_string")},slice_blob:s(window.File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice)),stream_upload:function(){return r.can("slice_blob")&&r.can("send_multipart")},summon_file_dialog:s(function(){return"Firefox"===i.browser&&i.version>=4||"Opera"===i.browser&&i.version>=12||"IE"===i.browser&&i.version>=10||!!~e.inArray(i.browser,["Chrome","Safari"])}()),upload_filesize:u},arguments[2]);n.call(this,t,arguments[1]||o,c),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html5",a={};return n.addConstructor(o,r),a}),i(N,[D,y],function(e,t){function n(){function e(e,t,n){var i;if(!window.File.prototype.slice)return(i=window.File.prototype.webkitSlice||window.File.prototype.mozSlice)?i.call(e,t,n):null;try{return e.slice(),e.slice(t,n)}catch(r){return e.slice(t,n-t)}}this.slice=function(){return new t(this.getRuntime().uid,e.apply(this,arguments))}}return e.Blob=n}),i(L,[u],function(e){function t(){this.returnValue=!1}function n(){this.cancelBubble=!0}var i={},r="moxie_"+e.guid(),o=function(o,a,s,u){var c,l;a=a.toLowerCase(),o.addEventListener?(c=s,o.addEventListener(a,c,!1)):o.attachEvent&&(c=function(){var e=window.event;e.target||(e.target=e.srcElement),e.preventDefault=t,e.stopPropagation=n,s(e)},o.attachEvent("on"+a,c)),o[r]||(o[r]=e.guid()),i.hasOwnProperty(o[r])||(i[o[r]]={}),l=i[o[r]],l.hasOwnProperty(a)||(l[a]=[]),l[a].push({func:c,orig:s,key:u})},a=function(t,n,o){var a,s;if(n=n.toLowerCase(),t[r]&&i[t[r]]&&i[t[r]][n]){a=i[t[r]][n];for(var u=a.length-1;u>=0&&(a[u].orig!==o&&a[u].key!==o||(t.removeEventListener?t.removeEventListener(n,a[u].func,!1):t.detachEvent&&t.detachEvent("on"+n,a[u].func),a[u].orig=null,a[u].func=null,a.splice(u,1),o===s));u--);if(a.length||delete i[t[r]][n],e.isEmptyObj(i[t[r]])){delete i[t[r]];try{delete t[r]}catch(c){t[r]=s}}}},s=function(t,n){t&&t[r]&&e.each(i[t[r]],function(e,i){a(t,i,n)})};return{addEvent:o,removeEvent:a,removeAllEvents:s}}),i(M,[D,u,f,L,l,d],function(e,t,n,i,r,o){function a(){var e=[],a;t.extend(this,{init:function(s){var u=this,c=u.getRuntime(),l,d,f,p,h,m;a=s,e=[],f=a.accept.mimes||r.extList2mimes(a.accept,c.can("filter_by_extension")),d=c.getShimContainer(),d.innerHTML='",l=n.get(c.uid),t.extend(l.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),p=n.get(a.browse_button),c.can("summon_file_dialog")&&("static"===n.getStyle(p,"position")&&(p.style.position="relative"),h=parseInt(n.getStyle(p,"z-index"),10)||1,p.style.zIndex=h,d.style.zIndex=h-1,i.addEvent(p,"click",function(e){var t=n.get(c.uid);t&&!t.disabled&&t.click(),e.preventDefault()},u.uid)),m=c.can("summon_file_dialog")?p:d,i.addEvent(m,"mouseover",function(){u.trigger("mouseenter")},u.uid),i.addEvent(m,"mouseout",function(){u.trigger("mouseleave")},u.uid),i.addEvent(m,"mousedown",function(){u.trigger("mousedown")},u.uid),i.addEvent(n.get(a.container),"mouseup",function(){u.trigger("mouseup")},u.uid),l.onchange=function g(){if(e=[],a.directory?t.each(this.files,function(t){"."!==t.name&&e.push(t)}):e=[].slice.call(this.files),"IE"!==o.browser)this.value="";else{var n=this.cloneNode(!0);this.parentNode.replaceChild(n,this),n.onchange=g}u.trigger("change")},u.trigger({type:"ready",async:!0}),d=null},getFiles:function(){return e},disable:function(e){var t=this.getRuntime(),i;(i=n.get(t.uid))&&(i.disabled=!!e)},destroy:function(){var t=this.getRuntime(),r=t.getShim(),o=t.getShimContainer();i.removeAllEvents(o,this.uid),i.removeAllEvents(a&&n.get(a.container),this.uid),i.removeAllEvents(a&&n.get(a.browse_button),this.uid),o&&(o.innerHTML=""),r.removeInstance(this.uid),e=a=o=r=null}})}return e.FileInput=a}),i(C,[D,u,f,L,l],function(e,t,n,i,r){function o(){function e(e){for(var n=[],i=0;i=4&&u.version<7,f="Android Browser"===u.browser,m=!1;if(h=n.url.replace(/^.+?\/([\w\-\.]+)$/,"$1").toLowerCase(),p=c(),p.open(n.method,n.url,n.async,n.user,n.password),r instanceof o)r.isDetached()&&(m=!0),r=r.getSource();else if(r instanceof a){if(r.hasBlob())if(r.getBlob().isDetached())r=d.call(s,r),m=!0;else if((l||f)&&"blob"===t.typeOf(r.getBlob().getSource())&&window.FileReader)return e.call(s,n,r),void 0;if(r instanceof a){var g=new window.FormData;r.each(function(e,t){e instanceof o?g.append(t,e.getSource()):g.append(t,e)}),r=g}}p.upload?(n.withCredentials&&(p.withCredentials=!0),p.addEventListener("load",function(e){s.trigger(e)}),p.addEventListener("error",function(e){s.trigger(e)}),p.addEventListener("progress",function(e){s.trigger(e)}),p.upload.addEventListener("progress",function(e){s.trigger({type:"UploadProgress",loaded:e.loaded,total:e.total})})):p.onreadystatechange=function v(){switch(p.readyState){case 1:break;case 2:break;case 3:var e,t;try{i.hasSameOrigin(n.url)&&(e=p.getResponseHeader("Content-Length")||0),p.responseText&&(t=p.responseText.length)}catch(r){e=t=0}s.trigger({type:"progress",lengthComputable:!!e,total:parseInt(e,10),loaded:t});break;case 4:p.onreadystatechange=function(){},0===p.status?s.trigger("error"):s.trigger("load")}},t.isEmptyObj(n.headers)||t.each(n.headers,function(e,t){p.setRequestHeader(t,e)}),""!==n.responseType&&"responseType"in p&&(p.responseType="json"!==n.responseType||u.can("return_response_type","json")?n.responseType:"text"),m?p.sendAsBinary?p.sendAsBinary(r):function(){for(var e=new Uint8Array(r.length),t=0;ta;a++)i|=o.charCodeAt(e+a)<s;s++)o+=String.fromCharCode(255&t>>Math.abs(a+8*s));n(o,e,i)}var r=!1,o;return{II:function(e){return e===t?r:(r=e,void 0)},init:function(e){r=!1,o=e},SEGMENT:function(e,t,i){switch(arguments.length){case 1:return o.substr(e,o.length-e-1);case 2:return o.substr(e,t);case 3:n(i,e,t);break;default:return o}},BYTE:function(t){return e(t,1)},SHORT:function(t){return e(t,2)},LONG:function(n,r){return r===t?e(n,4):(i(n,r,4),void 0)},SLONG:function(t){var n=e(t,4);return n>2147483647?n-4294967296:n},STRING:function(t,n){var i="";for(n+=t;n>t;t++)i+=String.fromCharCode(e(t,1));return i}}}}),i(k,[P],function(e){return function t(n){var i=[],r,o,a,s=0;if(r=new e,r.init(n),65496===r.SHORT(0)){for(o=2;o<=n.length;)if(a=r.SHORT(o),a>=65488&&65495>=a)o+=2;else{if(65498===a||65497===a)break;s=r.SHORT(o+2)+2,a>=65505&&65519>=a&&i.push({hex:a,name:"APP"+(15&a),start:o,length:s,segment:r.SEGMENT(o,s)}),o+=s}return r.init(null),{headers:i,restore:function(e){var t,n;for(r.init(e),o=65504==r.SHORT(2)?4+r.SHORT(4):2,n=0,t=i.length;t>n;n++)r.SEGMENT(o,0,i[n].segment),o+=i[n].length;return e=r.SEGMENT(),r.init(null),e},strip:function(e){var n,i,o;for(i=new t(e),n=i.headers,i.purge(),r.init(e),o=n.length;o--;)r.SEGMENT(n[o].start,n[o].length,"");return e=r.SEGMENT(),r.init(null),e},get:function(e){for(var t=[],n=0,r=i.length;r>n;n++)i[n].name===e.toUpperCase()&&t.push(i[n].segment);return t},set:function(e,t){var n=[],r,o,a;for("string"==typeof t?n.push(t):n=t,r=o=0,a=i.length;a>r&&(i[r].name===e.toUpperCase()&&(i[r].segment=n[o],i[r].length=n[o].length,o++),!(o>=n.length));r++);},purge:function(){i=[],r.init(null),r=null}}}}}),i(U,[u,P],function(e,n){return function i(){function i(e,n){var i=a.SHORT(e),r,o,s,u,d,f,p,h,m=[],g={};for(r=0;i>r;r++)if(p=f=e+12*r+2,s=n[a.SHORT(p)],s!==t){switch(u=a.SHORT(p+=2),d=a.LONG(p+=2),p+=4,m=[],u){case 1:case 7:for(d>4&&(p=a.LONG(p)+c.tiffHeader),o=0;d>o;o++)m[o]=a.BYTE(p+o);break;case 2:d>4&&(p=a.LONG(p)+c.tiffHeader),g[s]=a.STRING(p,d-1);continue;case 3:for(d>2&&(p=a.LONG(p)+c.tiffHeader),o=0;d>o;o++)m[o]=a.SHORT(p+2*o);break;case 4:for(d>1&&(p=a.LONG(p)+c.tiffHeader),o=0;d>o;o++)m[o]=a.LONG(p+4*o);break;case 5:for(p=a.LONG(p)+c.tiffHeader,o=0;d>o;o++)m[o]=a.LONG(p+4*o)/a.LONG(p+4*o+4);break;case 9:for(p=a.LONG(p)+c.tiffHeader,o=0;d>o;o++)m[o]=a.SLONG(p+4*o);break;case 10:for(p=a.LONG(p)+c.tiffHeader,o=0;d>o;o++)m[o]=a.SLONG(p+4*o)/a.SLONG(p+4*o+4);break;default:continue}h=1==d?m[0]:m,g[s]=l.hasOwnProperty(s)&&"object"!=typeof h?l[s][h]:h}return g}function r(){var e=c.tiffHeader;return a.II(18761==a.SHORT(e)),42!==a.SHORT(e+=2)?!1:(c.IFD0=c.tiffHeader+a.LONG(e+=2),u=i(c.IFD0,s.tiff),"ExifIFDPointer"in u&&(c.exifIFD=c.tiffHeader+u.ExifIFDPointer,delete u.ExifIFDPointer),"GPSInfoIFDPointer"in u&&(c.gpsIFD=c.tiffHeader+u.GPSInfoIFDPointer,delete u.GPSInfoIFDPointer),!0)}function o(e,t,n){var i,r,o,u=0;if("string"==typeof t){var l=s[e.toLowerCase()];for(var d in l)if(l[d]===t){t=d;break}}i=c[e.toLowerCase()+"IFD"],r=a.SHORT(i);for(var f=0;r>f;f++)if(o=i+12*f+2,a.SHORT(o)==t){u=o+8;break}return u?(a.LONG(u,n),!0):!1}var a,s,u,c={},l;return a=new n,s={tiff:{274:"Orientation",270:"ImageDescription",271:"Make",272:"Model",305:"Software",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37386:"FocalLength",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"}},l={ColorSpace:{1:"sRGB",0:"Uncalibrated"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{1:"Daylight",2:"Fliorescent",3:"Tungsten",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 -5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire.",1:"Flash fired.",5:"Strobe return light not detected.",7:"Strobe return light detected.",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},ExposureMode:{0:"Auto exposure",1:"Manual exposure",2:"Auto bracket"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}},{init:function(e){return c={tiffHeader:10},e!==t&&e.length?(a.init(e),65505===a.SHORT(0)&&"EXIF\0"===a.STRING(4,5).toUpperCase()?r():!1):!1 +},TIFF:function(){return u},EXIF:function(){var t;if(t=i(c.exifIFD,s.exif),t.ExifVersion&&"array"===e.typeOf(t.ExifVersion)){for(var n=0,r="";n=65472&&65475>=t)return e+=5,{height:c.SHORT(e),width:c.SHORT(e+=2)};n=c.SHORT(e+=2),e+=n-2}return null}function s(){d&&l&&c&&(d.purge(),l.purge(),c.init(null),u=f=l=d=c=null)}var u,c,l,d,f,p;if(u=o,c=new i,c.init(u),65496!==c.SHORT(0))throw new t.ImageError(t.ImageError.WRONG_FORMAT);l=new n(o),d=new r,p=!!d.init(l.get("app1")[0]),f=a.call(this),e.extend(this,{type:"image/jpeg",size:u.length,width:f&&f.width||0,height:f&&f.height||0,setExif:function(t,n){return p?("object"===e.typeOf(t)?e.each(t,function(e,t){d.setExif(t,e)}):d.setExif(t,n),l.set("app1",d.getBinary()),void 0):!1},writeHeaders:function(){return arguments.length?l.restore(arguments[0]):u=l.restore(u)},stripHeaders:function(e){return l.strip(e)},purge:function(){s.call(this)}}),p&&(this.meta={tiff:d.TIFF(),exif:d.EXIF(),gps:d.GPS()})}return o}),i(z,[p,u,P],function(e,t,n){function i(i){function r(){var e,t;return e=a.call(this,8),"IHDR"==e.type?(t=e.start,{width:u.LONG(t),height:u.LONG(t+=4)}):null}function o(){u&&(u.init(null),s=d=c=l=u=null)}function a(e){var t,n,i,r;return t=u.LONG(e),n=u.STRING(e+=4,4),i=e+=4,r=u.LONG(e+t),{length:t,type:n,start:i,CRC:r}}var s,u,c,l,d;s=i,u=new n,u.init(s),function(){var t=0,n=0,i=[35152,20039,3338,6666];for(n=0;ng;){for(var v=g+f>a?a-g:f,y=0;o>y;){var w=y+f>o?o-y:f;h.clearRect(0,0,f,f),h.drawImage(e,-y,-g);var E=y*s/o+c<<0,_=Math.ceil(w*s/o),x=g*u/a/m+l<<0,R=Math.ceil(v*u/a/m);d.drawImage(p,0,0,w,v,E,x,_,R),y+=f}g+=f}p=h=null}function t(e){var t=e.naturalWidth,n=e.naturalHeight;if(t*n>1048576){var i=document.createElement("canvas");i.width=i.height=1;var r=i.getContext("2d");return r.drawImage(e,-t+1,0),0===r.getImageData(0,0,1,1).data[3]}return!1}function n(e,t,n){var i=document.createElement("canvas");i.width=1,i.height=n;var r=i.getContext("2d");r.drawImage(e,0,0);for(var o=r.getImageData(0,0,1,n).data,a=0,s=n,u=n;u>a;){var c=o[4*(u-1)+3];0===c?s=u:a=u,u=s+a>>1}i=null;var l=u/n;return 0===l?1:l}return{isSubsampled:t,renderTo:e}}),i(X,[D,u,p,m,w,G,q,l,d],function(e,t,n,i,r,o,a,s,u){function c(){function e(){if(!E&&!y)throw new n.ImageError(n.DOMException.INVALID_STATE_ERR);return E||y}function c(e){return i.atob(e.substring(e.indexOf("base64,")+7))}function l(e,t){return"data:"+(t||"")+";base64,"+i.btoa(e)}function d(e){var t=this;y=new Image,y.onerror=function(){g.call(this),t.trigger("error",new n.ImageError(n.ImageError.WRONG_FORMAT))},y.onload=function(){t.trigger("load")},y.src=/^data:[^;]*;base64,/.test(e)?e:l(e,x.type)}function f(e,t){var i=this,r;return window.FileReader?(r=new FileReader,r.onload=function(){t(this.result)},r.onerror=function(){i.trigger("error",new n.FileException(n.FileException.NOT_READABLE_ERR))},r.readAsDataURL(e),void 0):t(e.getAsDataURL())}function p(n,i,r,o){var a=this,s,u,c=0,l=0,d,f,p,g;if(b=o,g=this.meta&&this.meta.tiff&&this.meta.tiff.Orientation||1,-1!==t.inArray(g,[5,6,7,8])){var v=n;n=i,i=v}return d=e(),u=r?Math.max:Math.min,s=u(n/d.width,i/d.height),s>1&&(!r||o)?(this.trigger("Resize"),void 0):(E||(E=document.createElement("canvas")),f=Math.round(d.width*s),p=Math.round(d.height*s),r?(E.width=n,E.height=i,f>n&&(c=Math.round((f-n)/2)),p>i&&(l=Math.round((p-i)/2))):(E.width=f,E.height=p),b||m(E.width,E.height,g),h.call(this,d,E,-c,-l,f,p),this.width=E.width,this.height=E.height,R=!0,a.trigger("Resize"),void 0)}function h(e,t,n,i,r,o){if("iOS"===u.OS)a.renderTo(e,t,{width:r,height:o,x:n,y:i});else{var s=t.getContext("2d");s.drawImage(e,n,i,r,o)}}function m(e,t,n){switch(n){case 5:case 6:case 7:case 8:E.width=t,E.height=e;break;default:E.width=e,E.height=t}var i=E.getContext("2d");switch(n){case 2:i.translate(e,0),i.scale(-1,1);break;case 3:i.translate(e,t),i.rotate(Math.PI);break;case 4:i.translate(0,t),i.scale(1,-1);break;case 5:i.rotate(.5*Math.PI),i.scale(1,-1);break;case 6:i.rotate(.5*Math.PI),i.translate(0,-t);break;case 7:i.rotate(.5*Math.PI),i.translate(e,-t),i.scale(-1,1);break;case 8:i.rotate(-.5*Math.PI),i.translate(-e,0)}}function g(){w&&(w.purge(),w=null),_=y=E=x=null,R=!1}var v=this,y,w,E,_,x,R=!1,b=!0;t.extend(this,{loadFromBlob:function(e){var t=this,i=t.getRuntime(),r=arguments.length>1?arguments[1]:!0;if(!i.can("access_binary"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);return x=e,e.isDetached()?(_=e.getSource(),d.call(this,_),void 0):(f.call(this,e.getSource(),function(e){r&&(_=c(e)),d.call(t,e)}),void 0)},loadFromImage:function(e,t){this.meta=e.meta,x=new r(null,{name:e.name,size:e.size,type:e.type}),d.call(this,t?_=e.getAsBinaryString():e.getAsDataURL())},getInfo:function(){var t=this.getRuntime(),n;return!w&&_&&t.can("access_image_binary")&&(w=new o(_)),n={width:e().width||0,height:e().height||0,type:x.type||s.getFileMime(x.name),size:_&&_.length||x.size||0,name:x.name||"",meta:w&&w.meta||this.meta||{}}},downsize:function(){p.apply(this,arguments)},getAsCanvas:function(){return E&&(E.id=this.uid+"_canvas"),E},getAsBlob:function(e,t){return e!==this.type&&p.call(this,this.width,this.height,!1),new r(null,{name:x.name||"",type:e,data:v.getAsBinaryString.call(this,e,t)})},getAsDataURL:function(e){var t=arguments[1]||90;if(!R)return y.src;if("image/jpeg"!==e)return E.toDataURL("image/png");try{return E.toDataURL("image/jpeg",t/100)}catch(n){return E.toDataURL("image/jpeg")}},getAsBinaryString:function(e,t){if(!R)return _||(_=c(v.getAsDataURL(e,t))),_;if("image/jpeg"!==e)_=c(v.getAsDataURL(e,t));else{var n;t||(t=90);try{n=E.toDataURL("image/jpeg",t/100)}catch(i){n=E.toDataURL("image/jpeg")}_=c(n),w&&(_=w.stripHeaders(_),b&&(w.meta&&w.meta.exif&&w.setExif({PixelXDimension:this.width,PixelYDimension:this.height}),_=w.writeHeaders(_)),w.purge(),w=null)}return R=!1,_},destroy:function(){v=null,g.call(this),this.getRuntime().getShim().removeInstance(this.uid)}})}return e.Image=c}),i(j,[u,d,f,p,g],function(e,t,n,i,r){function o(){var e;try{e=navigator.plugins["Shockwave Flash"],e=e.description}catch(t){try{e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(n){e="0.0"}}return e=e.match(/\d+/g),parseFloat(e[0]+"."+e[1])}function a(a){var c=this,l;a=e.extend({swf_url:t.swf_url},a),r.call(this,a,s,{access_binary:function(e){return e&&"browser"===c.mode},access_image_binary:function(e){return e&&"browser"===c.mode},display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:function(){return"client"===c.mode},resize_image:r.capTrue,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!e.arrayDiff(t,["","text","document"])||"browser"===c.mode},return_status_code:function(t){return"browser"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:function(e){return e&&"browser"===c.mode},send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"browser"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:function(e){return e&&"browser"===c.mode},summon_file_dialog:!1,upload_filesize:function(t){return e.parseSizeStr(t)<=2097152||"client"===c.mode},use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}},{access_binary:function(e){return e?"browser":"client"},access_image_binary:function(e){return e?"browser":"client"},report_upload_progress:function(e){return e?"browser":"client"},return_response_type:function(t){return e.arrayDiff(t,["","text","json","document"])?"browser":["client","browser"]},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"browser":["client","browser"]},send_binary_string:function(e){return e?"browser":"client"},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"browser":"client"},stream_upload:function(e){return e?"client":"browser"},upload_filesize:function(t){return e.parseSizeStr(t)>=2097152?"client":"browser"}},"client"),o()<10&&(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid)},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var n,r,o;o=this.getShimContainer(),e.extend(o.style,{position:"absolute",top:"-8px",left:"-8px",width:"9px",height:"9px",overflow:"hidden"}),n=''+''+''+''+"","IE"===t.browser?(r=document.createElement("div"),o.appendChild(r),r.outerHTML=n,r=o=null):o.innerHTML=n,l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="flash",u={};return r.addConstructor(s,a),u}),i(V,[j,y],function(e,t){var n={slice:function(e,n,i,r){var o=this.getRuntime();return 0>n?n=Math.max(e.size+n,0):n>0&&(n=Math.min(n,e.size)),0>i?i=Math.max(e.size+i,0):i>0&&(i=Math.min(i,e.size)),e=o.shimExec.call(this,"Blob","slice",n,i,r||""),e&&(e=new t(o.uid,e)),e}};return e.Blob=n}),i(W,[j],function(e){var t={init:function(e){this.getRuntime().shimExec.call(this,"FileInput","init",{name:e.name,accept:e.accept,multiple:e.multiple}),this.trigger("ready")}};return e.FileInput=t}),i(Y,[j,m],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i="",r={read:function(e,t){var r=this,o=r.getRuntime();return"readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"),r.bind("Progress",function(t,r){r&&(i+=n(r,e))}),o.shimExec.call(this,"FileReader","readAsBase64",t.uid)},getResult:function(){return i},destroy:function(){i=null}};return e.FileReader=r}),i($,[j,m],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i,r=this.getRuntime();return(i=r.shimExec.call(this,"FileReaderSync","readAsBase64",t.uid))?("readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"+i),n(i,e,t.type)):null}};return e.FileReaderSync=i}),i(J,[j,u,y,w,T,S,O],function(e,t,n,i,r,o,a){var s={send:function(e,i){function r(){e.transport=l.mode,l.shimExec.call(c,"XMLHttpRequest","send",e,i)}function s(e,t){l.shimExec.call(c,"XMLHttpRequest","appendBlob",e,t.uid),i=null,r()}function u(e,t){var n=new a;n.bind("TransportingComplete",function(){t(this.result)}),n.transport(e.getSource(),e.type,{ruid:l.uid})}var c=this,l=c.getRuntime();if(t.isEmptyObj(e.headers)||t.each(e.headers,function(e,t){l.shimExec.call(c,"XMLHttpRequest","setRequestHeader",t,e.toString())}),i instanceof o){var d;if(i.each(function(e,t){e instanceof n?d=t:l.shimExec.call(c,"XMLHttpRequest","append",t,e)}),i.hasBlob()){var f=i.getBlob();f.isDetached()?u(f,function(e){f.destroy(),s(d,e)}):s(d,f)}else i=null,r()}else i instanceof n?i.isDetached()?u(i,function(e){i.destroy(),i=e.uid,r()}):(i=i.uid,r()):r()},getResponse:function(e){var n,o,a=this.getRuntime();if(o=a.shimExec.call(this,"XMLHttpRequest","getResponseAsBlob")){if(o=new i(a.uid,o),"blob"===e)return o;try{if(n=new r,~t.inArray(e,["","text"]))return n.readAsText(o);if("json"===e&&window.JSON)return JSON.parse(n.readAsText(o))}finally{o.destroy()}}return null},abort:function(e){var t=this.getRuntime();t.shimExec.call(this,"XMLHttpRequest","abort"),this.dispatchEvent("readystatechange"),this.dispatchEvent("abort")}};return e.XMLHttpRequest=s}),i(Z,[j,y],function(e,t){var n={getAsBlob:function(e){var n=this.getRuntime(),i=n.shimExec.call(this,"Transporter","getAsBlob",e);return i?new t(n.uid,i):null}};return e.Transporter=n}),i(K,[j,u,O,y,T],function(e,t,n,i,r){var o={loadFromBlob:function(e){function t(e){r.shimExec.call(i,"Image","loadFromBlob",e.uid),i=r=null}var i=this,r=i.getRuntime();if(e.isDetached()){var o=new n;o.bind("TransportingComplete",function(){t(o.result.getSource())}),o.transport(e.getSource(),e.type,{ruid:r.uid})}else t(e.getSource())},loadFromImage:function(e){var t=this.getRuntime();return t.shimExec.call(this,"Image","loadFromImage",e.uid)},getAsBlob:function(e,t){var n=this.getRuntime(),r=n.shimExec.call(this,"Image","getAsBlob",e,t);return r?new i(n.uid,r):null},getAsDataURL:function(){var e=this.getRuntime(),t=e.Image.getAsBlob.apply(this,arguments),n;return t?(n=new r,n.readAsDataURL(t)):null}};return e.Image=o}),i(Q,[u,d,f,p,g],function(e,t,n,i,r){function o(e){var t=!1,n=null,i,r,o,a,s,u=0;try{try{n=new ActiveXObject("AgControl.AgControl"),n.IsVersionSupported(e)&&(t=!0),n=null}catch(c){var l=navigator.plugins["Silverlight Plug-In"];if(l){for(i=l.description,"1.0.30226.2"===i&&(i="2.0.30226.2"),r=i.split(".");r.length>3;)r.pop();for(;r.length<4;)r.push(0);for(o=e.split(".");o.length>4;)o.pop();do a=parseInt(o[u],10),s=parseInt(r[u],10),u++;while(u=a&&!isNaN(a)&&(t=!0)}}}catch(d){t=!1}return t}function a(a){var c=this,l;a=e.extend({xap_url:t.xap_url},a),r.call(this,a,s,{access_binary:r.capTrue,access_image_binary:r.capTrue,display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:r.capTrue,resize_image:r.capTrue,return_response_headers:function(e){return e&&"client"===c.mode},return_response_type:function(e){return"json"!==e?!0:!!window.JSON},return_status_code:function(t){return"client"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:r.capTrue,send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"client"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:!0,summon_file_dialog:!1,upload_filesize:r.capTrue,use_http_method:function(t){return"client"===c.mode||!e.arrayDiff(t,["GET","POST"])}},{return_response_headers:function(e){return e?"client":"browser"},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"client":["client","browser"]},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"client":"browser"},use_http_method:function(t){return e.arrayDiff(t,["GET","POST"])?"client":["client","browser"]}}),o("2.0.31005.0")&&"Opera"!==t.browser||(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid).content.Moxie},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var e;e=this.getShimContainer(),e.innerHTML=''+''+''+''+''+''+"",l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},"Windows"!==t.OS?1e4:5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="silverlight",u={};return r.addConstructor(s,a),u}),i(et,[Q,u,V],function(e,t,n){return e.Blob=t.extend({},n)}),i(tt,[Q],function(e){var t={init:function(e){function t(e){for(var t="",n=0;no;o++)n=t.keys[o],s=t[n],s&&(/^(\d|[1-9]\d+)$/.test(s)?s=parseInt(s,10):/^\d*\.\d+$/.test(s)&&(s=parseFloat(s)),i.meta[e][n]=s)}),i.width=parseInt(r.width,10),i.height=parseInt(r.height,10),i.size=parseInt(r.size,10),i.type=r.type,i.name=r.name,i}})}),i(ut,[u,p,g,d],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue;n.call(this,t,o,{access_binary:s(window.FileReader||window.File&&File.getAsDataURL),access_image_binary:!1,display_media:s(a.Image&&(i.can("create_canvas")||i.can("use_data_uri_over32kb"))),do_cors:!1,drag_and_drop:!1,filter_by_extension:s(function(){return"Chrome"===i.browser&&i.version>=28||"IE"===i.browser&&i.version>=10}()),resize_image:function(){return a.Image&&r.can("access_binary")&&i.can("create_canvas")},report_upload_progress:!1,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!!~e.inArray(t,["text","document",""])},return_status_code:function(t){return!e.arrayDiff(t,[200,404])},select_file:function(){return i.can("use_fileinput")},select_multiple:!1,send_binary_string:!1,send_custom_headers:!1,send_multipart:!0,slice_blob:!1,stream_upload:function(){return r.can("select_file")},summon_file_dialog:s(function(){return"Firefox"===i.browser&&i.version>=4||"Opera"===i.browser&&i.version>=12||!!~e.inArray(i.browser,["Chrome","Safari"])}()),upload_filesize:u,use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}}),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html4",a={};return n.addConstructor(o,r),a}),i(ct,[ut,u,f,L,l,d],function(e,t,n,i,r,o){function a(){function e(){var r=this,l=r.getRuntime(),d,f,p,h,m,g;g=t.guid("uid_"),d=l.getShimContainer(),a&&(p=n.get(a+"_form"),p&&t.extend(p.style,{top:"100%"})),h=document.createElement("form"),h.setAttribute("id",g+"_form"),h.setAttribute("method","post"),h.setAttribute("enctype","multipart/form-data"),h.setAttribute("encoding","multipart/form-data"),t.extend(h.style,{overflow:"hidden",position:"absolute",top:0,left:0,width:"100%",height:"100%"}),m=document.createElement("input"),m.setAttribute("id",g),m.setAttribute("type","file"),m.setAttribute("name",c.name||"Filedata"),m.setAttribute("accept",u.join(",")),t.extend(m.style,{fontSize:"999px",opacity:0}),h.appendChild(m),d.appendChild(h),t.extend(m.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),"IE"===o.browser&&o.version<10&&t.extend(m.style,{filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)"}),m.onchange=function(){var t;this.value&&(t=this.files?this.files[0]:{name:this.value},s=[t],this.onchange=function(){},e.call(r),r.bind("change",function i(){var e=n.get(g),t=n.get(g+"_form"),o;r.unbind("change",i),r.files.length&&e&&t&&(o=r.files[0],e.setAttribute("id",o.uid),t.setAttribute("id",o.uid+"_form"),t.setAttribute("target",o.uid+"_iframe")),e=t=null},998),m=h=null,r.trigger("change"))},l.can("summon_file_dialog")&&(f=n.get(c.browse_button),i.removeEvent(f,"click",r.uid),i.addEvent(f,"click",function(e){m&&!m.disabled&&m.click(),e.preventDefault()},r.uid)),a=g,d=p=f=null}var a,s=[],u=[],c;t.extend(this,{init:function(t){var o=this,a=o.getRuntime(),s;c=t,u=t.accept.mimes||r.extList2mimes(t.accept,a.can("filter_by_extension")),s=a.getShimContainer(),function(){var e,r,u;e=n.get(t.browse_button),a.can("summon_file_dialog")&&("static"===n.getStyle(e,"position")&&(e.style.position="relative"),r=parseInt(n.getStyle(e,"z-index"),10)||1,e.style.zIndex=r,s.style.zIndex=r-1),u=a.can("summon_file_dialog")?e:s,i.addEvent(u,"mouseover",function(){o.trigger("mouseenter")},o.uid),i.addEvent(u,"mouseout",function(){o.trigger("mouseleave")},o.uid),i.addEvent(u,"mousedown",function(){o.trigger("mousedown")},o.uid),i.addEvent(n.get(t.container),"mouseup",function(){o.trigger("mouseup")},o.uid),e=null}(),e.call(this),s=null,o.trigger({type:"ready",async:!0})},getFiles:function(){return s},disable:function(e){var t;(t=n.get(a))&&(t.disabled=!!e)},destroy:function(){var e=this.getRuntime(),t=e.getShim(),r=e.getShimContainer();i.removeAllEvents(r,this.uid),i.removeAllEvents(c&&n.get(c.container),this.uid),i.removeAllEvents(c&&n.get(c.browse_button),this.uid),r&&(r.innerHTML=""),t.removeInstance(this.uid),a=s=u=c=r=t=null}})}return e.FileInput=a}),i(lt,[ut,F],function(e,t){return e.FileReader=t}),i(dt,[ut,u,f,b,p,L,y,S],function(e,t,n,i,r,o,a,s){function u(){function e(e){var t=this,i,r,a,s,u=!1;if(l){if(i=l.id.replace(/_iframe$/,""),r=n.get(i+"_form")){for(a=r.getElementsByTagName("input"),s=a.length;s--;)switch(a[s].getAttribute("type")){case"hidden":a[s].parentNode.removeChild(a[s]);break;case"file":u=!0}a=[],u||r.parentNode.removeChild(r),r=null}setTimeout(function(){o.removeEvent(l,"load",t.uid),l.parentNode&&l.parentNode.removeChild(l);var n=t.getRuntime().getShimContainer();n.children.length||n.parentNode.removeChild(n),n=l=null,e()},1)}}var u,c,l;t.extend(this,{send:function(d,f){function p(){var n=m.getShimContainer()||document.body,r=document.createElement("div");r.innerHTML='',l=r.firstChild,n.appendChild(l),o.addEvent(l,"load",function(){var n;try{n=l.contentWindow.document||l.contentDocument||window.frames[l.id].document,/^4(0[0-9]|1[0-7]|2[2346])\s/.test(n.title)?u=n.title.replace(/^(\d+).*$/,"$1"):(u=200,c=t.trim(n.body.innerHTML),h.trigger({type:"progress",loaded:c.length,total:c.length}),w&&h.trigger({type:"uploadprogress",loaded:w.size||1025,total:w.size||1025}))}catch(r){if(!i.hasSameOrigin(d.url))return e.call(h,function(){h.trigger("error")}),void 0;u=404}e.call(h,function(){h.trigger("load")})},h.uid)}var h=this,m=h.getRuntime(),g,v,y,w;if(u=c=null,f instanceof s&&f.hasBlob()){if(w=f.getBlob(),g=w.uid,y=n.get(g),v=n.get(g+"_form"),!v)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR)}else g=t.guid("uid_"),v=document.createElement("form"),v.setAttribute("id",g+"_form"),v.setAttribute("method",d.method),v.setAttribute("enctype","multipart/form-data"),v.setAttribute("encoding","multipart/form-data"),v.setAttribute("target",g+"_iframe"),m.getShimContainer().appendChild(v);f instanceof s&&f.each(function(e,n){if(e instanceof a)y&&y.setAttribute("name",n);else{var i=document.createElement("input");t.extend(i,{type:"hidden",name:n,value:e}),y?v.insertBefore(i,y):v.appendChild(i)}}),v.setAttribute("action",d.url),p(),v.submit(),h.trigger("loadstart")},getStatus:function(){return u},getResponse:function(e){if("json"===e&&"string"===t.typeOf(c)&&window.JSON)try{return JSON.parse(c.replace(/^\s*]*>/,"").replace(/<\/pre>\s*$/,""))}catch(n){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})}})}return e.XMLHttpRequest=u}),i(ft,[ut,X],function(e,t){return e.Image=t}),a([u,c,l,d,f,p,h,m,g,v,y,w,E,_,x,R,b,T,S,A,O,I,L])}(this);;(function(){"use strict";var e={},t=moxie.core.utils.Basic.inArray;return function n(r){var i,s;for(i in r)s=typeof r[i],s==="object"&&!~t(i,["Exceptions","Env","Mime"])?n(r[i]):s==="function"&&(e[i]=r[i])}(window.moxie),e.Env=window.moxie.core.utils.Env,e.Mime=window.moxie.core.utils.Mime,e.Exceptions=window.moxie.core.Exceptions,window.mOxie=e,window.o||(window.o=e),e})(); \ No newline at end of file diff --git a/lib/scripts/uploader/plupload.full.min.js b/lib/scripts/uploader/plupload.full.min.js new file mode 100644 index 0000000..69d6ad1 --- /dev/null +++ b/lib/scripts/uploader/plupload.full.min.js @@ -0,0 +1,28 @@ +/** + * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill + * v1.2.0 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2014-01-16 + */ +!function(e,t){"use strict";function n(e,t){for(var n,i=[],r=0;r0&&n(o,function(n,o){n!==r&&(e(i[o])===e(n)&&~a(e(n),["array","object"])?t(i[o],n):i[o]=n)})}),i},n=function(e,t){var n,i,r,o;if(e){try{n=e.length}catch(a){n=o}if(n===o){for(i in e)if(e.hasOwnProperty(i)&&t(e[i],i)===!1)return}else for(r=0;n>r;r++)if(t(e[r],r)===!1)return}},i=function(t){var n;if(!t||"object"!==e(t))return!0;for(n in t)return!1;return!0},r=function(t,n){function i(r){"function"===e(t[r])&&t[r](function(e){++rn;n++)if(t[n]===e)return n}return-1},s=function(t,n){var i=[];"array"!==e(t)&&(t=[t]),"array"!==e(n)&&(n=[n]);for(var r in t)-1===a(t[r],n)&&i.push(t[r]);return i.length?i:!1},u=function(e,t){var i=[];return n(e,function(e){-1!==a(e,t)&&i.push(e)}),i.length?i:null},c=function(e){var t,n=[];for(t=0;ti;i++)n+=Math.floor(65535*Math.random()).toString(32);return(t||"o_")+n+(e++).toString(32)}}(),d=function(e){return e?String.prototype.trim?String.prototype.trim.call(e):e.toString().replace(/^\s*/,"").replace(/\s*$/,""):e},f=function(e){if("string"!=typeof e)return e;var t={t:1099511627776,g:1073741824,m:1048576,k:1024},n;return e=/^([0-9]+)([mgk]?)$/.exec(e.toLowerCase().replace(/[^0-9mkg]/g,"")),n=e[2],e=+e[1],t.hasOwnProperty(n)&&(e*=t[n]),e};return{guid:l,typeOf:e,extend:t,each:n,isEmptyObj:i,inSeries:r,inParallel:o,inArray:a,arrayDiff:s,arrayIntersect:u,toArray:c,trim:d,parseSizeStr:f}}),i(c,[u],function(e){var t={};return{addI18n:function(n){return e.extend(t,n)},translate:function(e){return t[e]||e},_:function(e){return this.translate(e)},sprintf:function(t){var n=[].slice.call(arguments,1);return t.replace(/%[a-z]/g,function(){var t=n.shift();return"undefined"!==e.typeOf(t)?t:""})}}}),i(l,[u,c],function(e,t){var n="application/msword,doc dot,application/pdf,pdf,application/pgp-signature,pgp,application/postscript,ps ai eps,application/rtf,rtf,application/vnd.ms-excel,xls xlb,application/vnd.ms-powerpoint,ppt pps pot,application/zip,zip,application/x-shockwave-flash,swf swfl,application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx,application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx,application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx,application/vnd.openxmlformats-officedocument.presentationml.template,potx,application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx,application/x-javascript,js,application/json,json,audio/mpeg,mp3 mpga mpega mp2,audio/x-wav,wav,audio/x-m4a,m4a,audio/ogg,oga ogg,audio/aiff,aiff aif,audio/flac,flac,audio/aac,aac,audio/ac3,ac3,audio/x-ms-wma,wma,image/bmp,bmp,image/gif,gif,image/jpeg,jpg jpeg jpe,image/photoshop,psd,image/png,png,image/svg+xml,svg svgz,image/tiff,tiff tif,text/plain,asc txt text diff log,text/html,htm html xhtml,text/css,css,text/csv,csv,text/rtf,rtf,video/mpeg,mpeg mpg mpe m2v,video/quicktime,qt mov,video/mp4,mp4,video/x-m4v,m4v,video/x-flv,flv,video/x-ms-wmv,wmv,video/avi,avi,video/webm,webm,video/3gpp,3gpp 3gp,video/3gpp2,3g2,video/vnd.rn-realvideo,rv,video/ogg,ogv,video/x-matroska,mkv,application/vnd.oasis.opendocument.formula-template,otf,application/octet-stream,exe",i={mimes:{},extensions:{},addMimeType:function(e){var t=e.split(/,/),n,i,r;for(n=0;ni;i++)if(e[i]!=t[i]){if(e[i]=u(e[i]),t[i]=u(t[i]),e[i]t[i]){o=1;break}}if(!n)return o;switch(n){case">":case"gt":return o>0;case">=":case"ge":return o>=0;case"<=":case"le":return 0>=o;case"==":case"=":case"eq":return 0===o;case"<>":case"!=":case"ne":return 0!==o;case"":case"<":case"lt":return 0>o;default:return null}}var n=function(e){var t="",n="?",i="function",r="undefined",o="object",a="major",s="model",u="name",c="type",l="vendor",d="version",f="architecture",p="console",h="mobile",m="tablet",g={has:function(e,t){return-1!==t.toLowerCase().indexOf(e.toLowerCase())},lowerize:function(e){return e.toLowerCase()}},v={rgx:function(){for(var t,n=0,a,s,u,c,l,d,f=arguments;n0?2==c.length?t[c[0]]=typeof c[1]==i?c[1].call(this,d):c[1]:3==c.length?t[c[0]]=typeof c[1]!==i||c[1].exec&&c[1].test?d?d.replace(c[1],c[2]):e:d?c[1].call(this,d,c[2]):e:4==c.length&&(t[c[0]]=d?c[3].call(this,d.replace(c[1],c[2])):e):t[c]=d?d:e;break}if(l)break}return t},str:function(t,i){for(var r in i)if(typeof i[r]===o&&i[r].length>0){for(var a=0;a=9)},use_data_uri_of:function(e){return t.use_data_uri&&33e3>e||t.use_data_uri_over32kb()},use_fileinput:function(){var e=document.createElement("input");return e.setAttribute("type","file"),!e.disabled}};return function(n){var i=[].slice.call(arguments);return i.shift(),"function"===e.typeOf(t[n])?t[n].apply(this,i):!!t[n]}}(),r={can:i,browser:n.browser.name,version:parseFloat(n.browser.major),os:n.os.name,osVersion:n.os.version,verComp:t,swf_url:"../flash/Moxie.swf",xap_url:"../silverlight/Moxie.xap",global_event_dispatcher:"moxie.core.EventTarget.instance.dispatchEvent"};return r.OS=r.os,r}),i(f,[d],function(e){var t=function(e){return"string"!=typeof e?e:document.getElementById(e)},n=function(e,t){if(!e.className)return!1;var n=new RegExp("(^|\\s+)"+t+"(\\s+|$)");return n.test(e.className)},i=function(e,t){n(e,t)||(e.className=e.className?e.className.replace(/\s+$/,"")+" "+t:t)},r=function(e,t){if(e.className){var n=new RegExp("(^|\\s+)"+t+"(\\s+|$)");e.className=e.className.replace(n,function(e,t,n){return" "===t&&" "===n?" ":""})}},o=function(e,t){return e.currentStyle?e.currentStyle[t]:window.getComputedStyle?window.getComputedStyle(e,null)[t]:void 0},a=function(t,n){function i(e){var t,n,i=0,r=0;return e&&(n=e.getBoundingClientRect(),t="CSS1Compat"===s.compatMode?s.documentElement:s.body,i=n.left+t.scrollLeft,r=n.top+t.scrollTop),{x:i,y:r}}var r=0,o=0,a,s=document,u,c;if(t=t,n=n||s.body,t&&t.getBoundingClientRect&&"IE"===e.browser&&(!s.documentMode||s.documentMode<8))return u=i(t),c=i(n),{x:u.x-c.x,y:u.y-c.y};for(a=t;a&&a!=n&&a.nodeType;)r+=a.offsetLeft||0,o+=a.offsetTop||0,a=a.offsetParent;for(a=t.parentNode;a&&a!=n&&a.nodeType;)r-=a.scrollLeft||0,o-=a.scrollTop||0,a=a.parentNode;return{x:r,y:o}},s=function(e){return{w:e.offsetWidth||e.clientWidth,h:e.offsetHeight||e.clientHeight}};return{get:t,hasClass:n,addClass:i,removeClass:r,getStyle:o,getPos:a,getSize:s}}),i(p,[u],function(e){function t(e,t){var n;for(n in e)if(e[n]===t)return n;return null}return{RuntimeError:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": RuntimeError "+this.code}var i={NOT_INIT_ERR:1,NOT_SUPPORTED_ERR:9,JS_ERR:4};return e.extend(n,i),n.prototype=Error.prototype,n}(),OperationNotAllowedException:function(){function t(e){this.code=e,this.name="OperationNotAllowedException"}return e.extend(t,{NOT_ALLOWED_ERR:1}),t.prototype=Error.prototype,t}(),ImageError:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": ImageError "+this.code}var i={WRONG_FORMAT:1,MAX_RESOLUTION_ERR:2};return e.extend(n,i),n.prototype=Error.prototype,n}(),FileException:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": FileException "+this.code}var i={NOT_FOUND_ERR:1,SECURITY_ERR:2,ABORT_ERR:3,NOT_READABLE_ERR:4,ENCODING_ERR:5,NO_MODIFICATION_ALLOWED_ERR:6,INVALID_STATE_ERR:7,SYNTAX_ERR:8};return e.extend(n,i),n.prototype=Error.prototype,n}(),DOMException:function(){function n(e){this.code=e,this.name=t(i,e),this.message=this.name+": DOMException "+this.code}var i={INDEX_SIZE_ERR:1,DOMSTRING_SIZE_ERR:2,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,INVALID_CHARACTER_ERR:5,NO_DATA_ALLOWED_ERR:6,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INUSE_ATTRIBUTE_ERR:10,INVALID_STATE_ERR:11,SYNTAX_ERR:12,INVALID_MODIFICATION_ERR:13,NAMESPACE_ERR:14,INVALID_ACCESS_ERR:15,VALIDATION_ERR:16,TYPE_MISMATCH_ERR:17,SECURITY_ERR:18,NETWORK_ERR:19,ABORT_ERR:20,URL_MISMATCH_ERR:21,QUOTA_EXCEEDED_ERR:22,TIMEOUT_ERR:23,INVALID_NODE_TYPE_ERR:24,DATA_CLONE_ERR:25};return e.extend(n,i),n.prototype=Error.prototype,n}(),EventException:function(){function t(e){this.code=e,this.name="EventException"}return e.extend(t,{UNSPECIFIED_EVENT_TYPE_ERR:0}),t.prototype=Error.prototype,t}()}}),i(h,[p,u],function(e,t){function n(){var n={};t.extend(this,{uid:null,init:function(){this.uid||(this.uid=t.guid("uid_"))},addEventListener:function(e,i,r,o){var a=this,s;return e=t.trim(e),/\s/.test(e)?(t.each(e.split(/\s+/),function(e){a.addEventListener(e,i,r,o)}),void 0):(e=e.toLowerCase(),r=parseInt(r,10)||0,s=n[this.uid]&&n[this.uid][e]||[],s.push({fn:i,priority:r,scope:o||this}),n[this.uid]||(n[this.uid]={}),n[this.uid][e]=s,void 0)},hasEventListener:function(e){return e?!(!n[this.uid]||!n[this.uid][e]):!!n[this.uid]},removeEventListener:function(e,i){e=e.toLowerCase();var r=n[this.uid]&&n[this.uid][e],o;if(r){if(i){for(o=r.length-1;o>=0;o--)if(r[o].fn===i){r.splice(o,1);break}}else r=[];r.length||(delete n[this.uid][e],t.isEmptyObj(n[this.uid])&&delete n[this.uid])}},removeAllEventListeners:function(){n[this.uid]&&delete n[this.uid]},dispatchEvent:function(i){var r,o,a,s,u={},c=!0,l;if("string"!==t.typeOf(i)){if(s=i,"string"!==t.typeOf(s.type))throw new e.EventException(e.EventException.UNSPECIFIED_EVENT_TYPE_ERR);i=s.type,s.total!==l&&s.loaded!==l&&(u.total=s.total,u.loaded=s.loaded),u.async=s.async||!1}if(-1!==i.indexOf("::")?function(e){r=e[0],i=e[1]}(i.split("::")):r=this.uid,i=i.toLowerCase(),o=n[r]&&n[r][i]){o.sort(function(e,t){return t.priority-e.priority}),a=[].slice.call(arguments),a.shift(),u.type=i,a.unshift(u);var d=[];t.each(o,function(e){a[0].target=e.scope,u.async?d.push(function(t){setTimeout(function(){t(e.fn.apply(e.scope,a)===!1)},1)}):d.push(function(t){t(e.fn.apply(e.scope,a)===!1)})}),d.length&&t.inSeries(d,function(e){c=!e})}return c},bind:function(){this.addEventListener.apply(this,arguments)},unbind:function(){this.removeEventListener.apply(this,arguments)},unbindAll:function(){this.removeAllEventListeners.apply(this,arguments)},trigger:function(){return this.dispatchEvent.apply(this,arguments)},convertEventPropsToHandlers:function(e){var n;"array"!==t.typeOf(e)&&(e=[e]);for(var i=0;i>16,o=255&d>>8,a=255&d,m[p++]=64==c?String.fromCharCode(r):64==l?String.fromCharCode(r,o):String.fromCharCode(r,o,a);while(f>18,u=63&d>>12,c=63&d>>6,l=63&d,m[p++]=i.charAt(s)+i.charAt(u)+i.charAt(c)+i.charAt(l);while(fa;a++)o+=String.fromCharCode(r[a]);return o}}t.call(this),e.extend(this,{uid:e.guid("uid_"),readAsBinaryString:function(e){return i.call(this,"readAsBinaryString",e)},readAsDataURL:function(e){return i.call(this,"readAsDataURL",e)},readAsText:function(e){return i.call(this,"readAsText",e)}})}}),i(S,[p,u,y],function(e,t,n){function i(){var e,i=[];t.extend(this,{append:function(r,o){var a=this,s=t.typeOf(o);o instanceof n?e={name:r,value:o}:"array"===s?(r+="[]",t.each(o,function(e){a.append(r,e)})):"object"===s?t.each(o,function(e,t){a.append(r+"["+t+"]",e)}):"null"===s||"undefined"===s||"number"===s&&isNaN(o)?a.append(r,"false"):i.push({name:r,value:o.toString()})},hasBlob:function(){return!!this.getBlob()},getBlob:function(){return e&&e.value||null},getBlobName:function(){return e&&e.name||null},each:function(n){t.each(i,function(e){n(e.value,e.name)}),e&&n(e.value,e.name)},destroy:function(){e=null,i=[]}})}return i}),i(A,[u,p,h,m,b,g,x,y,T,S,d,l],function(e,t,n,i,r,o,a,s,u,c,l,d){function f(){this.uid=e.guid("uid_")}function p(){function n(e,t){return y.hasOwnProperty(e)?1===arguments.length?l.can("define_property")?y[e]:v[e]:(l.can("define_property")?y[e]=t:v[e]=t,void 0):void 0}function u(t){function i(){k.destroy(),k=null,s.dispatchEvent("loadend"),s=null}function r(r){k.bind("LoadStart",function(e){n("readyState",p.LOADING),s.dispatchEvent("readystatechange"),s.dispatchEvent(e),I&&s.upload.dispatchEvent(e)}),k.bind("Progress",function(e){n("readyState")!==p.LOADING&&(n("readyState",p.LOADING),s.dispatchEvent("readystatechange")),s.dispatchEvent(e)}),k.bind("UploadProgress",function(e){I&&s.upload.dispatchEvent({type:"progress",lengthComputable:!1,total:e.total,loaded:e.loaded})}),k.bind("Load",function(t){n("readyState",p.DONE),n("status",Number(r.exec.call(k,"XMLHttpRequest","getStatus")||0)),n("statusText",h[n("status")]||""),n("response",r.exec.call(k,"XMLHttpRequest","getResponse",n("responseType"))),~e.inArray(n("responseType"),["text",""])?n("responseText",n("response")):"document"===n("responseType")&&n("responseXML",n("response")),U=r.exec.call(k,"XMLHttpRequest","getAllResponseHeaders"),s.dispatchEvent("readystatechange"),n("status")>0?(I&&s.upload.dispatchEvent(t),s.dispatchEvent(t)):(N=!0,s.dispatchEvent("error")),i()}),k.bind("Abort",function(e){s.dispatchEvent(e),i()}),k.bind("Error",function(e){N=!0,n("readyState",p.DONE),s.dispatchEvent("readystatechange"),D=!0,s.dispatchEvent(e),i()}),r.exec.call(k,"XMLHttpRequest","send",{url:E,method:_,async:w,user:R,password:b,headers:x,mimeType:S,encoding:T,responseType:s.responseType,withCredentials:s.withCredentials,options:P},t)}var s=this;M=(new Date).getTime(),k=new a,"string"==typeof P.required_caps&&(P.required_caps=o.parseCaps(P.required_caps)),P.required_caps=e.extend({},P.required_caps,{return_response_type:s.responseType}),t instanceof c&&(P.required_caps.send_multipart=!0),L||(P.required_caps.do_cors=!0),P.ruid?r(k.connectRuntime(P)):(k.bind("RuntimeInit",function(e,t){r(t)}),k.bind("RuntimeError",function(e,t){s.dispatchEvent("RuntimeError",t)}),k.connectRuntime(P))}function g(){n("responseText",""),n("responseXML",null),n("response",null),n("status",0),n("statusText",""),M=C=null}var v=this,y={timeout:0,readyState:p.UNSENT,withCredentials:!1,status:0,statusText:"",responseType:"",responseXML:null,responseText:null,response:null},w=!0,E,_,x={},R,b,T=null,S=null,A=!1,O=!1,I=!1,D=!1,N=!1,L=!1,M,C,F=null,H=null,P={},k,U="",B;e.extend(this,y,{uid:e.guid("uid_"),upload:new f,open:function(o,a,s,u,c){var l;if(!o||!a)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(/[\u0100-\uffff]/.test(o)||i.utf8_encode(o)!==o)throw new t.DOMException(t.DOMException.SYNTAX_ERR);if(~e.inArray(o.toUpperCase(),["CONNECT","DELETE","GET","HEAD","OPTIONS","POST","PUT","TRACE","TRACK"])&&(_=o.toUpperCase()),~e.inArray(_,["CONNECT","TRACE","TRACK"]))throw new t.DOMException(t.DOMException.SECURITY_ERR);if(a=i.utf8_encode(a),l=r.parseUrl(a),L=r.hasSameOrigin(l),E=r.resolveUrl(a),(u||c)&&!L)throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);if(R=u||l.user,b=c||l.pass,w=s||!0,w===!1&&(n("timeout")||n("withCredentials")||""!==n("responseType")))throw new t.DOMException(t.DOMException.INVALID_ACCESS_ERR);A=!w,O=!1,x={},g.call(this),n("readyState",p.OPENED),this.convertEventPropsToHandlers(["readystatechange"]),this.dispatchEvent("readystatechange")},setRequestHeader:function(r,o){var a=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","content-transfer-encoding","date","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","user-agent","via"];if(n("readyState")!==p.OPENED||O)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(/[\u0100-\uffff]/.test(r)||i.utf8_encode(r)!==r)throw new t.DOMException(t.DOMException.SYNTAX_ERR);return r=e.trim(r).toLowerCase(),~e.inArray(r,a)||/^(proxy\-|sec\-)/.test(r)?!1:(x[r]?x[r]+=", "+o:x[r]=o,!0)},getAllResponseHeaders:function(){return U||""},getResponseHeader:function(t){return t=t.toLowerCase(),N||~e.inArray(t,["set-cookie","set-cookie2"])?null:U&&""!==U&&(B||(B={},e.each(U.split(/\r\n/),function(t){var n=t.split(/:\s+/);2===n.length&&(n[0]=e.trim(n[0]),B[n[0].toLowerCase()]={header:n[0],value:e.trim(n[1])})})),B.hasOwnProperty(t))?B[t].header+": "+B[t].value:null},overrideMimeType:function(i){var r,o;if(~e.inArray(n("readyState"),[p.LOADING,p.DONE]))throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(i=e.trim(i.toLowerCase()),/;/.test(i)&&(r=i.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))&&(i=r[1],r[2]&&(o=r[2])),!d.mimes[i])throw new t.DOMException(t.DOMException.SYNTAX_ERR);F=i,H=o},send:function(n,r){if(P="string"===e.typeOf(r)?{ruid:r}:r?r:{},this.convertEventPropsToHandlers(m),this.upload.convertEventPropsToHandlers(m),this.readyState!==p.OPENED||O)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);if(n instanceof s)P.ruid=n.ruid,S=n.type||"application/octet-stream";else if(n instanceof c){if(n.hasBlob()){var o=n.getBlob();P.ruid=o.ruid,S=o.type||"application/octet-stream"}}else"string"==typeof n&&(T="UTF-8",S="text/plain;charset=UTF-8",n=i.utf8_encode(n));this.withCredentials||(this.withCredentials=P.required_caps&&P.required_caps.send_browser_cookies&&!L),I=!A&&this.upload.hasEventListener(),N=!1,D=!n,A||(O=!0),u.call(this,n)},abort:function(){if(N=!0,A=!1,~e.inArray(n("readyState"),[p.UNSENT,p.OPENED,p.DONE]))n("readyState",p.UNSENT);else{if(n("readyState",p.DONE),O=!1,!k)throw new t.DOMException(t.DOMException.INVALID_STATE_ERR);k.getRuntime().exec.call(k,"XMLHttpRequest","abort",D),D=!0}},destroy:function(){k&&("function"===e.typeOf(k.destroy)&&k.destroy(),k=null),this.unbindAll(),this.upload&&(this.upload.unbindAll(),this.upload=null)}})}var h={100:"Continue",101:"Switching Protocols",102:"Processing",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",306:"Reserved",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",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",426:"Upgrade Required",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",510:"Not Extended"};f.prototype=n.instance;var m=["loadstart","progress","abort","error","load","timeout","loadend"],g=1,v=2;return p.UNSENT=0,p.OPENED=1,p.HEADERS_RECEIVED=2,p.LOADING=3,p.DONE=4,p.prototype=n.instance,p}),i(O,[u,m,v,h],function(e,t,n,i){function r(){function i(){l=d=0,c=this.result=null}function o(t,n){var i=this;u=n,i.bind("TransportingProgress",function(t){d=t.loaded,l>d&&-1===e.inArray(i.state,[r.IDLE,r.DONE])&&a.call(i)},999),i.bind("TransportingComplete",function(){d=l,i.state=r.DONE,c=null,i.result=u.exec.call(i,"Transporter","getAsBlob",t||"")},999),i.state=r.BUSY,i.trigger("TransportingStarted"),a.call(i)}function a(){var e=this,n,i=l-d;f>i&&(f=i),n=t.btoa(c.substr(d,f)),u.exec.call(e,"Transporter","receive",n,l)}var s,u,c,l,d,f;n.call(this),e.extend(this,{uid:e.guid("uid_"),state:r.IDLE,result:null,transport:function(t,n,r){var a=this;if(r=e.extend({chunk_size:204798},r),(s=r.chunk_size%3)&&(r.chunk_size+=3-s),f=r.chunk_size,i.call(this),c=t,l=t.length,"string"===e.typeOf(r)||r.ruid)o.call(a,n,this.connectRuntime(r));else{var u=function(e,t){a.unbind("RuntimeInit",u),o.call(a,n,t)};this.bind("RuntimeInit",u),this.connectRuntime(r)}},abort:function(){var e=this;e.state=r.IDLE,u&&(u.exec.call(e,"Transporter","clear"),e.trigger("TransportingAborted")),i.call(e)},destroy:function(){this.unbindAll(),u=null,this.disconnectRuntime(),i.call(this)}})}return r.IDLE=0,r.BUSY=1,r.DONE=2,r.prototype=i.instance,r}),i(I,[u,f,p,T,A,g,v,O,d,h,y,w,m],function(e,t,n,i,r,o,a,s,u,c,l,d,f){function p(){function i(e){e||(e=this.getRuntime().exec.call(this,"Image","getInfo")),this.size=e.size,this.width=e.width,this.height=e.height,this.type=e.type,this.meta=e.meta,""===this.name&&(this.name=e.name)}function c(t){var i=e.typeOf(t);try{if(t instanceof p){if(!t.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);m.apply(this,arguments)}else if(t instanceof l){if(!~e.inArray(t.type,["image/jpeg","image/png"]))throw new n.ImageError(n.ImageError.WRONG_FORMAT);g.apply(this,arguments)}else if(-1!==e.inArray(i,["blob","file"]))c.call(this,new d(null,t),arguments[1]);else if("string"===i)/^data:[^;]*;base64,/.test(t)?c.call(this,new l(null,{data:t}),arguments[1]):v.apply(this,arguments);else{if("node"!==i||"img"!==t.nodeName.toLowerCase())throw new n.DOMException(n.DOMException.TYPE_MISMATCH_ERR);c.call(this,t.src,arguments[1])}}catch(r){this.trigger("error",r)}}function m(t,n){var i=this.connectRuntime(t.ruid);this.ruid=i.uid,i.exec.call(this,"Image","loadFromImage",t,"undefined"===e.typeOf(n)?!0:n)}function g(t,n){function i(e){r.ruid=e.uid,e.exec.call(r,"Image","loadFromBlob",t)}var r=this;r.name=t.name||"",t.isDetached()?(this.bind("RuntimeInit",function(e,t){i(t)}),n&&"string"==typeof n.required_caps&&(n.required_caps=o.parseCaps(n.required_caps)),this.connectRuntime(e.extend({required_caps:{access_image_binary:!0,resize_image:!0}},n))):i(this.connectRuntime(t.ruid))}function v(e,t){var n=this,i;i=new r,i.open("get",e),i.responseType="blob",i.onprogress=function(e){n.trigger(e)},i.onload=function(){g.call(n,i.response,!0)},i.onerror=function(e){n.trigger(e)},i.onloadend=function(){i.destroy()},i.bind("RuntimeError",function(e,t){n.trigger("RuntimeError",t)}),i.send(null,t)}a.call(this),e.extend(this,{uid:e.guid("uid_"),ruid:null,name:"",size:0,width:0,height:0,type:"",meta:{},clone:function(){this.load.apply(this,arguments)},load:function(){this.bind("Load Resize",function(){i.call(this)},999),this.convertEventPropsToHandlers(h),c.apply(this,arguments)},downsize:function(t,i,r,o){try{if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>p.MAX_RESIZE_WIDTH||this.height>p.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);(!t&&!i||"undefined"===e.typeOf(r))&&(r=!1),t=t||this.width,i=i||this.height,o="undefined"===e.typeOf(o)?!0:!!o,this.getRuntime().exec.call(this,"Image","downsize",t,i,r,o)}catch(a){this.trigger("error",a)}},crop:function(e,t,n){this.downsize(e,t,!0,n)},getAsCanvas:function(){if(!u.can("create_canvas"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);var e=this.connectRuntime(this.ruid);return e.exec.call(this,"Image","getAsCanvas")},getAsBlob:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return e||(e="image/jpeg"),"image/jpeg"!==e||t||(t=90),this.getRuntime().exec.call(this,"Image","getAsBlob",e,t)},getAsDataURL:function(e,t){if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);return this.getRuntime().exec.call(this,"Image","getAsDataURL",e,t)},getAsBinaryString:function(e,t){var n=this.getAsDataURL(e,t);return f.atob(n.substring(n.indexOf("base64,")+7))},embed:function(i){function r(){if(u.can("create_canvas")){var t=a.getAsCanvas();if(t)return i.appendChild(t),t=null,a.destroy(),o.trigger("embedded"),void 0}var r=a.getAsDataURL(c,l);if(!r)throw new n.ImageError(n.ImageError.WRONG_FORMAT);if(u.can("use_data_uri_of",r.length))i.innerHTML='',a.destroy(),o.trigger("embedded");else{var d=new s;d.bind("TransportingComplete",function(){v=o.connectRuntime(this.result.ruid),o.bind("Embedded",function(){e.extend(v.getShimContainer().style,{top:"0px",left:"0px",width:a.width+"px",height:a.height+"px"}),v=null},999),v.exec.call(o,"ImageView","display",this.result.uid,m,g),a.destroy()}),d.transport(f.atob(r.substring(r.indexOf("base64,")+7)),c,e.extend({},h,{required_caps:{display_media:!0},runtime_order:"flash,silverlight",container:i}))}}var o=this,a,c,l,d,h=arguments[1]||{},m=this.width,g=this.height,v;try{if(!(i=t.get(i)))throw new n.DOMException(n.DOMException.INVALID_NODE_TYPE_ERR);if(!this.size)throw new n.DOMException(n.DOMException.INVALID_STATE_ERR);if(this.width>p.MAX_RESIZE_WIDTH||this.height>p.MAX_RESIZE_HEIGHT)throw new n.ImageError(n.ImageError.MAX_RESOLUTION_ERR);if(c=h.type||this.type||"image/jpeg",l=h.quality||90,d="undefined"!==e.typeOf(h.crop)?h.crop:!1,h.width)m=h.width,g=h.height||m;else{var y=t.getSize(i);y.w&&y.h&&(m=y.w,g=y.h)}return a=new p,a.bind("Resize",function(){r.call(o)}),a.bind("Load",function(){a.downsize(m,g,d,!1)}),a.clone(this,!1),a}catch(w){this.trigger("error",w)}},destroy:function(){this.ruid&&(this.getRuntime().exec.call(this,"Image","destroy"),this.disconnectRuntime()),this.unbindAll()}})}var h=["progress","load","error","resize","embedded"];return p.MAX_RESIZE_WIDTH=6500,p.MAX_RESIZE_HEIGHT=6500,p.prototype=c.instance,p}),i(D,[u,p,g,d],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue,c=e.extend({access_binary:s(window.FileReader||window.File&&window.File.getAsDataURL),access_image_binary:function(){return r.can("access_binary")&&!!a.Image},display_media:s(i.can("create_canvas")||i.can("use_data_uri_over32kb")),do_cors:s(window.XMLHttpRequest&&"withCredentials"in new XMLHttpRequest),drag_and_drop:s(function(){var e=document.createElement("div");return("draggable"in e||"ondragstart"in e&&"ondrop"in e)&&("IE"!==i.browser||i.version>9)}()),filter_by_extension:s(function(){return"Chrome"===i.browser&&i.version>=28||"IE"===i.browser&&i.version>=10}()),return_response_headers:u,return_response_type:function(e){return"json"===e&&window.JSON?!0:i.can("return_response_type",e)},return_status_code:u,report_upload_progress:s(window.XMLHttpRequest&&(new XMLHttpRequest).upload),resize_image:function(){return r.can("access_binary")&&i.can("create_canvas")},select_file:function(){return i.can("use_fileinput")&&window.File},select_folder:function(){return r.can("select_file")&&"Chrome"===i.browser&&i.version>=21},select_multiple:function(){return!(!r.can("select_file")||"Safari"===i.browser&&"Windows"===i.os||"iOS"===i.os&&i.verComp(i.osVersion,"7.0.4","<"))},send_binary_string:s(window.XMLHttpRequest&&((new XMLHttpRequest).sendAsBinary||window.Uint8Array&&window.ArrayBuffer)),send_custom_headers:s(window.XMLHttpRequest),send_multipart:function(){return!!(window.XMLHttpRequest&&(new XMLHttpRequest).upload&&window.FormData)||r.can("send_binary_string")},slice_blob:s(window.File&&(File.prototype.mozSlice||File.prototype.webkitSlice||File.prototype.slice)),stream_upload:function(){return r.can("slice_blob")&&r.can("send_multipart")},summon_file_dialog:s(function(){return"Firefox"===i.browser&&i.version>=4||"Opera"===i.browser&&i.version>=12||"IE"===i.browser&&i.version>=10||!!~e.inArray(i.browser,["Chrome","Safari"])}()),upload_filesize:u},arguments[2]);n.call(this,t,arguments[1]||o,c),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html5",a={};return n.addConstructor(o,r),a}),i(N,[D,y],function(e,t){function n(){function e(e,t,n){var i;if(!window.File.prototype.slice)return(i=window.File.prototype.webkitSlice||window.File.prototype.mozSlice)?i.call(e,t,n):null;try{return e.slice(),e.slice(t,n)}catch(r){return e.slice(t,n-t)}}this.slice=function(){return new t(this.getRuntime().uid,e.apply(this,arguments))}}return e.Blob=n}),i(L,[u],function(e){function t(){this.returnValue=!1}function n(){this.cancelBubble=!0}var i={},r="moxie_"+e.guid(),o=function(o,a,s,u){var c,l;a=a.toLowerCase(),o.addEventListener?(c=s,o.addEventListener(a,c,!1)):o.attachEvent&&(c=function(){var e=window.event;e.target||(e.target=e.srcElement),e.preventDefault=t,e.stopPropagation=n,s(e)},o.attachEvent("on"+a,c)),o[r]||(o[r]=e.guid()),i.hasOwnProperty(o[r])||(i[o[r]]={}),l=i[o[r]],l.hasOwnProperty(a)||(l[a]=[]),l[a].push({func:c,orig:s,key:u})},a=function(t,n,o){var a,s;if(n=n.toLowerCase(),t[r]&&i[t[r]]&&i[t[r]][n]){a=i[t[r]][n];for(var u=a.length-1;u>=0&&(a[u].orig!==o&&a[u].key!==o||(t.removeEventListener?t.removeEventListener(n,a[u].func,!1):t.detachEvent&&t.detachEvent("on"+n,a[u].func),a[u].orig=null,a[u].func=null,a.splice(u,1),o===s));u--);if(a.length||delete i[t[r]][n],e.isEmptyObj(i[t[r]])){delete i[t[r]];try{delete t[r]}catch(c){t[r]=s}}}},s=function(t,n){t&&t[r]&&e.each(i[t[r]],function(e,i){a(t,i,n)})};return{addEvent:o,removeEvent:a,removeAllEvents:s}}),i(M,[D,u,f,L,l,d],function(e,t,n,i,r,o){function a(){var e=[],a;t.extend(this,{init:function(s){var u=this,c=u.getRuntime(),l,d,f,p,h,m;a=s,e=[],f=a.accept.mimes||r.extList2mimes(a.accept,c.can("filter_by_extension")),d=c.getShimContainer(),d.innerHTML='",l=n.get(c.uid),t.extend(l.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),p=n.get(a.browse_button),c.can("summon_file_dialog")&&("static"===n.getStyle(p,"position")&&(p.style.position="relative"),h=parseInt(n.getStyle(p,"z-index"),10)||1,p.style.zIndex=h,d.style.zIndex=h-1,i.addEvent(p,"click",function(e){var t=n.get(c.uid);t&&!t.disabled&&t.click(),e.preventDefault()},u.uid)),m=c.can("summon_file_dialog")?p:d,i.addEvent(m,"mouseover",function(){u.trigger("mouseenter")},u.uid),i.addEvent(m,"mouseout",function(){u.trigger("mouseleave")},u.uid),i.addEvent(m,"mousedown",function(){u.trigger("mousedown")},u.uid),i.addEvent(n.get(a.container),"mouseup",function(){u.trigger("mouseup")},u.uid),l.onchange=function g(){if(e=[],a.directory?t.each(this.files,function(t){"."!==t.name&&e.push(t)}):e=[].slice.call(this.files),"IE"!==o.browser)this.value="";else{var n=this.cloneNode(!0);this.parentNode.replaceChild(n,this),n.onchange=g}u.trigger("change")},u.trigger({type:"ready",async:!0}),d=null},getFiles:function(){return e},disable:function(e){var t=this.getRuntime(),i;(i=n.get(t.uid))&&(i.disabled=!!e)},destroy:function(){var t=this.getRuntime(),r=t.getShim(),o=t.getShimContainer();i.removeAllEvents(o,this.uid),i.removeAllEvents(a&&n.get(a.container),this.uid),i.removeAllEvents(a&&n.get(a.browse_button),this.uid),o&&(o.innerHTML=""),r.removeInstance(this.uid),e=a=o=r=null}})}return e.FileInput=a}),i(C,[D,u,f,L,l],function(e,t,n,i,r){function o(){function e(e){for(var n=[],i=0;i=4&&u.version<7,f="Android Browser"===u.browser,m=!1;if(h=n.url.replace(/^.+?\/([\w\-\.]+)$/,"$1").toLowerCase(),p=c(),p.open(n.method,n.url,n.async,n.user,n.password),r instanceof o)r.isDetached()&&(m=!0),r=r.getSource();else if(r instanceof a){if(r.hasBlob())if(r.getBlob().isDetached())r=d.call(s,r),m=!0;else if((l||f)&&"blob"===t.typeOf(r.getBlob().getSource())&&window.FileReader)return e.call(s,n,r),void 0;if(r instanceof a){var g=new window.FormData;r.each(function(e,t){e instanceof o?g.append(t,e.getSource()):g.append(t,e)}),r=g}}p.upload?(n.withCredentials&&(p.withCredentials=!0),p.addEventListener("load",function(e){s.trigger(e)}),p.addEventListener("error",function(e){s.trigger(e)}),p.addEventListener("progress",function(e){s.trigger(e)}),p.upload.addEventListener("progress",function(e){s.trigger({type:"UploadProgress",loaded:e.loaded,total:e.total})})):p.onreadystatechange=function v(){switch(p.readyState){case 1:break;case 2:break;case 3:var e,t;try{i.hasSameOrigin(n.url)&&(e=p.getResponseHeader("Content-Length")||0),p.responseText&&(t=p.responseText.length)}catch(r){e=t=0}s.trigger({type:"progress",lengthComputable:!!e,total:parseInt(e,10),loaded:t});break;case 4:p.onreadystatechange=function(){},0===p.status?s.trigger("error"):s.trigger("load")}},t.isEmptyObj(n.headers)||t.each(n.headers,function(e,t){p.setRequestHeader(t,e)}),""!==n.responseType&&"responseType"in p&&(p.responseType="json"!==n.responseType||u.can("return_response_type","json")?n.responseType:"text"),m?p.sendAsBinary?p.sendAsBinary(r):function(){for(var e=new Uint8Array(r.length),t=0;ta;a++)i|=o.charCodeAt(e+a)<s;s++)o+=String.fromCharCode(255&t>>Math.abs(a+8*s));n(o,e,i)}var r=!1,o;return{II:function(e){return e===t?r:(r=e,void 0)},init:function(e){r=!1,o=e},SEGMENT:function(e,t,i){switch(arguments.length){case 1:return o.substr(e,o.length-e-1);case 2:return o.substr(e,t);case 3:n(i,e,t);break;default:return o}},BYTE:function(t){return e(t,1)},SHORT:function(t){return e(t,2)},LONG:function(n,r){return r===t?e(n,4):(i(n,r,4),void 0)},SLONG:function(t){var n=e(t,4);return n>2147483647?n-4294967296:n},STRING:function(t,n){var i="";for(n+=t;n>t;t++)i+=String.fromCharCode(e(t,1));return i}}}}),i(k,[P],function(e){return function t(n){var i=[],r,o,a,s=0;if(r=new e,r.init(n),65496===r.SHORT(0)){for(o=2;o<=n.length;)if(a=r.SHORT(o),a>=65488&&65495>=a)o+=2;else{if(65498===a||65497===a)break;s=r.SHORT(o+2)+2,a>=65505&&65519>=a&&i.push({hex:a,name:"APP"+(15&a),start:o,length:s,segment:r.SEGMENT(o,s)}),o+=s}return r.init(null),{headers:i,restore:function(e){var t,n;for(r.init(e),o=65504==r.SHORT(2)?4+r.SHORT(4):2,n=0,t=i.length;t>n;n++)r.SEGMENT(o,0,i[n].segment),o+=i[n].length;return e=r.SEGMENT(),r.init(null),e},strip:function(e){var n,i,o;for(i=new t(e),n=i.headers,i.purge(),r.init(e),o=n.length;o--;)r.SEGMENT(n[o].start,n[o].length,"");return e=r.SEGMENT(),r.init(null),e},get:function(e){for(var t=[],n=0,r=i.length;r>n;n++)i[n].name===e.toUpperCase()&&t.push(i[n].segment);return t},set:function(e,t){var n=[],r,o,a;for("string"==typeof t?n.push(t):n=t,r=o=0,a=i.length;a>r&&(i[r].name===e.toUpperCase()&&(i[r].segment=n[o],i[r].length=n[o].length,o++),!(o>=n.length));r++);},purge:function(){i=[],r.init(null),r=null}}}}}),i(U,[u,P],function(e,n){return function i(){function i(e,n){var i=a.SHORT(e),r,o,s,u,d,f,p,h,m=[],g={};for(r=0;i>r;r++)if(p=f=e+12*r+2,s=n[a.SHORT(p)],s!==t){switch(u=a.SHORT(p+=2),d=a.LONG(p+=2),p+=4,m=[],u){case 1:case 7:for(d>4&&(p=a.LONG(p)+c.tiffHeader),o=0;d>o;o++)m[o]=a.BYTE(p+o);break;case 2:d>4&&(p=a.LONG(p)+c.tiffHeader),g[s]=a.STRING(p,d-1);continue;case 3:for(d>2&&(p=a.LONG(p)+c.tiffHeader),o=0;d>o;o++)m[o]=a.SHORT(p+2*o);break;case 4:for(d>1&&(p=a.LONG(p)+c.tiffHeader),o=0;d>o;o++)m[o]=a.LONG(p+4*o);break;case 5:for(p=a.LONG(p)+c.tiffHeader,o=0;d>o;o++)m[o]=a.LONG(p+4*o)/a.LONG(p+4*o+4);break;case 9:for(p=a.LONG(p)+c.tiffHeader,o=0;d>o;o++)m[o]=a.SLONG(p+4*o);break;case 10:for(p=a.LONG(p)+c.tiffHeader,o=0;d>o;o++)m[o]=a.SLONG(p+4*o)/a.SLONG(p+4*o+4);break;default:continue}h=1==d?m[0]:m,g[s]=l.hasOwnProperty(s)&&"object"!=typeof h?l[s][h]:h}return g}function r(){var e=c.tiffHeader;return a.II(18761==a.SHORT(e)),42!==a.SHORT(e+=2)?!1:(c.IFD0=c.tiffHeader+a.LONG(e+=2),u=i(c.IFD0,s.tiff),"ExifIFDPointer"in u&&(c.exifIFD=c.tiffHeader+u.ExifIFDPointer,delete u.ExifIFDPointer),"GPSInfoIFDPointer"in u&&(c.gpsIFD=c.tiffHeader+u.GPSInfoIFDPointer,delete u.GPSInfoIFDPointer),!0)}function o(e,t,n){var i,r,o,u=0;if("string"==typeof t){var l=s[e.toLowerCase()];for(var d in l)if(l[d]===t){t=d;break}}i=c[e.toLowerCase()+"IFD"],r=a.SHORT(i);for(var f=0;r>f;f++)if(o=i+12*f+2,a.SHORT(o)==t){u=o+8;break}return u?(a.LONG(u,n),!0):!1}var a,s,u,c={},l;return a=new n,s={tiff:{274:"Orientation",270:"ImageDescription",271:"Make",272:"Model",305:"Software",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer"},exif:{36864:"ExifVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",36867:"DateTimeOriginal",33434:"ExposureTime",33437:"FNumber",34855:"ISOSpeedRatings",37377:"ShutterSpeedValue",37378:"ApertureValue",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37386:"FocalLength",41986:"ExposureMode",41987:"WhiteBalance",41990:"SceneCaptureType",41988:"DigitalZoomRatio",41992:"Contrast",41993:"Saturation",41994:"Sharpness"},gps:{0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude"}},l={ColorSpace:{1:"sRGB",0:"Uncalibrated"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{1:"Daylight",2:"Fliorescent",3:"Tungsten",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 -5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire.",1:"Flash fired.",5:"Strobe return light not detected.",7:"Strobe return light detected.",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},ExposureMode:{0:"Auto exposure",1:"Manual exposure",2:"Auto bracket"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},GPSLatitudeRef:{N:"North latitude",S:"South latitude"},GPSLongitudeRef:{E:"East longitude",W:"West longitude"}},{init:function(e){return c={tiffHeader:10},e!==t&&e.length?(a.init(e),65505===a.SHORT(0)&&"EXIF\0"===a.STRING(4,5).toUpperCase()?r():!1):!1 +},TIFF:function(){return u},EXIF:function(){var t;if(t=i(c.exifIFD,s.exif),t.ExifVersion&&"array"===e.typeOf(t.ExifVersion)){for(var n=0,r="";n=65472&&65475>=t)return e+=5,{height:c.SHORT(e),width:c.SHORT(e+=2)};n=c.SHORT(e+=2),e+=n-2}return null}function s(){d&&l&&c&&(d.purge(),l.purge(),c.init(null),u=f=l=d=c=null)}var u,c,l,d,f,p;if(u=o,c=new i,c.init(u),65496!==c.SHORT(0))throw new t.ImageError(t.ImageError.WRONG_FORMAT);l=new n(o),d=new r,p=!!d.init(l.get("app1")[0]),f=a.call(this),e.extend(this,{type:"image/jpeg",size:u.length,width:f&&f.width||0,height:f&&f.height||0,setExif:function(t,n){return p?("object"===e.typeOf(t)?e.each(t,function(e,t){d.setExif(t,e)}):d.setExif(t,n),l.set("app1",d.getBinary()),void 0):!1},writeHeaders:function(){return arguments.length?l.restore(arguments[0]):u=l.restore(u)},stripHeaders:function(e){return l.strip(e)},purge:function(){s.call(this)}}),p&&(this.meta={tiff:d.TIFF(),exif:d.EXIF(),gps:d.GPS()})}return o}),i(z,[p,u,P],function(e,t,n){function i(i){function r(){var e,t;return e=a.call(this,8),"IHDR"==e.type?(t=e.start,{width:u.LONG(t),height:u.LONG(t+=4)}):null}function o(){u&&(u.init(null),s=d=c=l=u=null)}function a(e){var t,n,i,r;return t=u.LONG(e),n=u.STRING(e+=4,4),i=e+=4,r=u.LONG(e+t),{length:t,type:n,start:i,CRC:r}}var s,u,c,l,d;s=i,u=new n,u.init(s),function(){var t=0,n=0,i=[35152,20039,3338,6666];for(n=0;ng;){for(var v=g+f>a?a-g:f,y=0;o>y;){var w=y+f>o?o-y:f;h.clearRect(0,0,f,f),h.drawImage(e,-y,-g);var E=y*s/o+c<<0,_=Math.ceil(w*s/o),x=g*u/a/m+l<<0,R=Math.ceil(v*u/a/m);d.drawImage(p,0,0,w,v,E,x,_,R),y+=f}g+=f}p=h=null}function t(e){var t=e.naturalWidth,n=e.naturalHeight;if(t*n>1048576){var i=document.createElement("canvas");i.width=i.height=1;var r=i.getContext("2d");return r.drawImage(e,-t+1,0),0===r.getImageData(0,0,1,1).data[3]}return!1}function n(e,t,n){var i=document.createElement("canvas");i.width=1,i.height=n;var r=i.getContext("2d");r.drawImage(e,0,0);for(var o=r.getImageData(0,0,1,n).data,a=0,s=n,u=n;u>a;){var c=o[4*(u-1)+3];0===c?s=u:a=u,u=s+a>>1}i=null;var l=u/n;return 0===l?1:l}return{isSubsampled:t,renderTo:e}}),i(X,[D,u,p,m,w,G,q,l,d],function(e,t,n,i,r,o,a,s,u){function c(){function e(){if(!E&&!y)throw new n.ImageError(n.DOMException.INVALID_STATE_ERR);return E||y}function c(e){return i.atob(e.substring(e.indexOf("base64,")+7))}function l(e,t){return"data:"+(t||"")+";base64,"+i.btoa(e)}function d(e){var t=this;y=new Image,y.onerror=function(){g.call(this),t.trigger("error",new n.ImageError(n.ImageError.WRONG_FORMAT))},y.onload=function(){t.trigger("load")},y.src=/^data:[^;]*;base64,/.test(e)?e:l(e,x.type)}function f(e,t){var i=this,r;return window.FileReader?(r=new FileReader,r.onload=function(){t(this.result)},r.onerror=function(){i.trigger("error",new n.FileException(n.FileException.NOT_READABLE_ERR))},r.readAsDataURL(e),void 0):t(e.getAsDataURL())}function p(n,i,r,o){var a=this,s,u,c=0,l=0,d,f,p,g;if(b=o,g=this.meta&&this.meta.tiff&&this.meta.tiff.Orientation||1,-1!==t.inArray(g,[5,6,7,8])){var v=n;n=i,i=v}return d=e(),u=r?Math.max:Math.min,s=u(n/d.width,i/d.height),s>1&&(!r||o)?(this.trigger("Resize"),void 0):(E||(E=document.createElement("canvas")),f=Math.round(d.width*s),p=Math.round(d.height*s),r?(E.width=n,E.height=i,f>n&&(c=Math.round((f-n)/2)),p>i&&(l=Math.round((p-i)/2))):(E.width=f,E.height=p),b||m(E.width,E.height,g),h.call(this,d,E,-c,-l,f,p),this.width=E.width,this.height=E.height,R=!0,a.trigger("Resize"),void 0)}function h(e,t,n,i,r,o){if("iOS"===u.OS)a.renderTo(e,t,{width:r,height:o,x:n,y:i});else{var s=t.getContext("2d");s.drawImage(e,n,i,r,o)}}function m(e,t,n){switch(n){case 5:case 6:case 7:case 8:E.width=t,E.height=e;break;default:E.width=e,E.height=t}var i=E.getContext("2d");switch(n){case 2:i.translate(e,0),i.scale(-1,1);break;case 3:i.translate(e,t),i.rotate(Math.PI);break;case 4:i.translate(0,t),i.scale(1,-1);break;case 5:i.rotate(.5*Math.PI),i.scale(1,-1);break;case 6:i.rotate(.5*Math.PI),i.translate(0,-t);break;case 7:i.rotate(.5*Math.PI),i.translate(e,-t),i.scale(-1,1);break;case 8:i.rotate(-.5*Math.PI),i.translate(-e,0)}}function g(){w&&(w.purge(),w=null),_=y=E=x=null,R=!1}var v=this,y,w,E,_,x,R=!1,b=!0;t.extend(this,{loadFromBlob:function(e){var t=this,i=t.getRuntime(),r=arguments.length>1?arguments[1]:!0;if(!i.can("access_binary"))throw new n.RuntimeError(n.RuntimeError.NOT_SUPPORTED_ERR);return x=e,e.isDetached()?(_=e.getSource(),d.call(this,_),void 0):(f.call(this,e.getSource(),function(e){r&&(_=c(e)),d.call(t,e)}),void 0)},loadFromImage:function(e,t){this.meta=e.meta,x=new r(null,{name:e.name,size:e.size,type:e.type}),d.call(this,t?_=e.getAsBinaryString():e.getAsDataURL())},getInfo:function(){var t=this.getRuntime(),n;return!w&&_&&t.can("access_image_binary")&&(w=new o(_)),n={width:e().width||0,height:e().height||0,type:x.type||s.getFileMime(x.name),size:_&&_.length||x.size||0,name:x.name||"",meta:w&&w.meta||this.meta||{}}},downsize:function(){p.apply(this,arguments)},getAsCanvas:function(){return E&&(E.id=this.uid+"_canvas"),E},getAsBlob:function(e,t){return e!==this.type&&p.call(this,this.width,this.height,!1),new r(null,{name:x.name||"",type:e,data:v.getAsBinaryString.call(this,e,t)})},getAsDataURL:function(e){var t=arguments[1]||90;if(!R)return y.src;if("image/jpeg"!==e)return E.toDataURL("image/png");try{return E.toDataURL("image/jpeg",t/100)}catch(n){return E.toDataURL("image/jpeg")}},getAsBinaryString:function(e,t){if(!R)return _||(_=c(v.getAsDataURL(e,t))),_;if("image/jpeg"!==e)_=c(v.getAsDataURL(e,t));else{var n;t||(t=90);try{n=E.toDataURL("image/jpeg",t/100)}catch(i){n=E.toDataURL("image/jpeg")}_=c(n),w&&(_=w.stripHeaders(_),b&&(w.meta&&w.meta.exif&&w.setExif({PixelXDimension:this.width,PixelYDimension:this.height}),_=w.writeHeaders(_)),w.purge(),w=null)}return R=!1,_},destroy:function(){v=null,g.call(this),this.getRuntime().getShim().removeInstance(this.uid)}})}return e.Image=c}),i(j,[u,d,f,p,g],function(e,t,n,i,r){function o(){var e;try{e=navigator.plugins["Shockwave Flash"],e=e.description}catch(t){try{e=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(n){e="0.0"}}return e=e.match(/\d+/g),parseFloat(e[0]+"."+e[1])}function a(a){var c=this,l;a=e.extend({swf_url:t.swf_url},a),r.call(this,a,s,{access_binary:function(e){return e&&"browser"===c.mode},access_image_binary:function(e){return e&&"browser"===c.mode},display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:function(){return"client"===c.mode},resize_image:r.capTrue,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!e.arrayDiff(t,["","text","document"])||"browser"===c.mode},return_status_code:function(t){return"browser"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:function(e){return e&&"browser"===c.mode},send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"browser"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:function(e){return e&&"browser"===c.mode},summon_file_dialog:!1,upload_filesize:function(t){return e.parseSizeStr(t)<=2097152||"client"===c.mode},use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}},{access_binary:function(e){return e?"browser":"client"},access_image_binary:function(e){return e?"browser":"client"},report_upload_progress:function(e){return e?"browser":"client"},return_response_type:function(t){return e.arrayDiff(t,["","text","json","document"])?"browser":["client","browser"]},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"browser":["client","browser"]},send_binary_string:function(e){return e?"browser":"client"},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"browser":"client"},stream_upload:function(e){return e?"client":"browser"},upload_filesize:function(t){return e.parseSizeStr(t)>=2097152?"client":"browser"}},"client"),o()<10&&(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid)},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var n,r,o;o=this.getShimContainer(),e.extend(o.style,{position:"absolute",top:"-8px",left:"-8px",width:"9px",height:"9px",overflow:"hidden"}),n=''+''+''+''+"","IE"===t.browser?(r=document.createElement("div"),o.appendChild(r),r.outerHTML=n,r=o=null):o.innerHTML=n,l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="flash",u={};return r.addConstructor(s,a),u}),i(V,[j,y],function(e,t){var n={slice:function(e,n,i,r){var o=this.getRuntime();return 0>n?n=Math.max(e.size+n,0):n>0&&(n=Math.min(n,e.size)),0>i?i=Math.max(e.size+i,0):i>0&&(i=Math.min(i,e.size)),e=o.shimExec.call(this,"Blob","slice",n,i,r||""),e&&(e=new t(o.uid,e)),e}};return e.Blob=n}),i(W,[j],function(e){var t={init:function(e){this.getRuntime().shimExec.call(this,"FileInput","init",{name:e.name,accept:e.accept,multiple:e.multiple}),this.trigger("ready")}};return e.FileInput=t}),i(Y,[j,m],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i="",r={read:function(e,t){var r=this,o=r.getRuntime();return"readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"),r.bind("Progress",function(t,r){r&&(i+=n(r,e))}),o.shimExec.call(this,"FileReader","readAsBase64",t.uid)},getResult:function(){return i},destroy:function(){i=null}};return e.FileReader=r}),i($,[j,m],function(e,t){function n(e,n){switch(n){case"readAsText":return t.atob(e,"utf8");case"readAsBinaryString":return t.atob(e);case"readAsDataURL":return e}return null}var i={read:function(e,t){var i,r=this.getRuntime();return(i=r.shimExec.call(this,"FileReaderSync","readAsBase64",t.uid))?("readAsDataURL"===e&&(i="data:"+(t.type||"")+";base64,"+i),n(i,e,t.type)):null}};return e.FileReaderSync=i}),i(J,[j,u,y,w,T,S,O],function(e,t,n,i,r,o,a){var s={send:function(e,i){function r(){e.transport=l.mode,l.shimExec.call(c,"XMLHttpRequest","send",e,i)}function s(e,t){l.shimExec.call(c,"XMLHttpRequest","appendBlob",e,t.uid),i=null,r()}function u(e,t){var n=new a;n.bind("TransportingComplete",function(){t(this.result)}),n.transport(e.getSource(),e.type,{ruid:l.uid})}var c=this,l=c.getRuntime();if(t.isEmptyObj(e.headers)||t.each(e.headers,function(e,t){l.shimExec.call(c,"XMLHttpRequest","setRequestHeader",t,e.toString())}),i instanceof o){var d;if(i.each(function(e,t){e instanceof n?d=t:l.shimExec.call(c,"XMLHttpRequest","append",t,e)}),i.hasBlob()){var f=i.getBlob();f.isDetached()?u(f,function(e){f.destroy(),s(d,e)}):s(d,f)}else i=null,r()}else i instanceof n?i.isDetached()?u(i,function(e){i.destroy(),i=e.uid,r()}):(i=i.uid,r()):r()},getResponse:function(e){var n,o,a=this.getRuntime();if(o=a.shimExec.call(this,"XMLHttpRequest","getResponseAsBlob")){if(o=new i(a.uid,o),"blob"===e)return o;try{if(n=new r,~t.inArray(e,["","text"]))return n.readAsText(o);if("json"===e&&window.JSON)return JSON.parse(n.readAsText(o))}finally{o.destroy()}}return null},abort:function(e){var t=this.getRuntime();t.shimExec.call(this,"XMLHttpRequest","abort"),this.dispatchEvent("readystatechange"),this.dispatchEvent("abort")}};return e.XMLHttpRequest=s}),i(Z,[j,y],function(e,t){var n={getAsBlob:function(e){var n=this.getRuntime(),i=n.shimExec.call(this,"Transporter","getAsBlob",e);return i?new t(n.uid,i):null}};return e.Transporter=n}),i(K,[j,u,O,y,T],function(e,t,n,i,r){var o={loadFromBlob:function(e){function t(e){r.shimExec.call(i,"Image","loadFromBlob",e.uid),i=r=null}var i=this,r=i.getRuntime();if(e.isDetached()){var o=new n;o.bind("TransportingComplete",function(){t(o.result.getSource())}),o.transport(e.getSource(),e.type,{ruid:r.uid})}else t(e.getSource())},loadFromImage:function(e){var t=this.getRuntime();return t.shimExec.call(this,"Image","loadFromImage",e.uid)},getAsBlob:function(e,t){var n=this.getRuntime(),r=n.shimExec.call(this,"Image","getAsBlob",e,t);return r?new i(n.uid,r):null},getAsDataURL:function(){var e=this.getRuntime(),t=e.Image.getAsBlob.apply(this,arguments),n;return t?(n=new r,n.readAsDataURL(t)):null}};return e.Image=o}),i(Q,[u,d,f,p,g],function(e,t,n,i,r){function o(e){var t=!1,n=null,i,r,o,a,s,u=0;try{try{n=new ActiveXObject("AgControl.AgControl"),n.IsVersionSupported(e)&&(t=!0),n=null}catch(c){var l=navigator.plugins["Silverlight Plug-In"];if(l){for(i=l.description,"1.0.30226.2"===i&&(i="2.0.30226.2"),r=i.split(".");r.length>3;)r.pop();for(;r.length<4;)r.push(0);for(o=e.split(".");o.length>4;)o.pop();do a=parseInt(o[u],10),s=parseInt(r[u],10),u++;while(u=a&&!isNaN(a)&&(t=!0)}}}catch(d){t=!1}return t}function a(a){var c=this,l;a=e.extend({xap_url:t.xap_url},a),r.call(this,a,s,{access_binary:r.capTrue,access_image_binary:r.capTrue,display_media:r.capTrue,do_cors:r.capTrue,drag_and_drop:!1,report_upload_progress:r.capTrue,resize_image:r.capTrue,return_response_headers:function(e){return e&&"client"===c.mode},return_response_type:function(e){return"json"!==e?!0:!!window.JSON},return_status_code:function(t){return"client"===c.mode||!e.arrayDiff(t,[200,404])},select_file:r.capTrue,select_multiple:r.capTrue,send_binary_string:r.capTrue,send_browser_cookies:function(e){return e&&"browser"===c.mode},send_custom_headers:function(e){return e&&"client"===c.mode},send_multipart:r.capTrue,slice_blob:r.capTrue,stream_upload:!0,summon_file_dialog:!1,upload_filesize:r.capTrue,use_http_method:function(t){return"client"===c.mode||!e.arrayDiff(t,["GET","POST"])}},{return_response_headers:function(e){return e?"client":"browser"},return_status_code:function(t){return e.arrayDiff(t,[200,404])?"client":["client","browser"]},send_browser_cookies:function(e){return e?"browser":"client"},send_custom_headers:function(e){return e?"client":"browser"},use_http_method:function(t){return e.arrayDiff(t,["GET","POST"])?"client":["client","browser"]}}),o("2.0.31005.0")&&"Opera"!==t.browser||(this.mode=!1),e.extend(this,{getShim:function(){return n.get(this.uid).content.Moxie},shimExec:function(e,t){var n=[].slice.call(arguments,2);return c.getShim().exec(this.uid,e,t,n)},init:function(){var e;e=this.getShimContainer(),e.innerHTML=''+''+''+''+''+''+"",l=setTimeout(function(){c&&!c.initialized&&c.trigger("Error",new i.RuntimeError(i.RuntimeError.NOT_INIT_ERR))},"Windows"!==t.OS?1e4:5e3)},destroy:function(e){return function(){e.call(c),clearTimeout(l),a=l=e=c=null}}(this.destroy)},u)}var s="silverlight",u={};return r.addConstructor(s,a),u}),i(et,[Q,u,V],function(e,t,n){return e.Blob=t.extend({},n)}),i(tt,[Q],function(e){var t={init:function(e){function t(e){for(var t="",n=0;no;o++)n=t.keys[o],s=t[n],s&&(/^(\d|[1-9]\d+)$/.test(s)?s=parseInt(s,10):/^\d*\.\d+$/.test(s)&&(s=parseFloat(s)),i.meta[e][n]=s)}),i.width=parseInt(r.width,10),i.height=parseInt(r.height,10),i.size=parseInt(r.size,10),i.type=r.type,i.name=r.name,i}})}),i(ut,[u,p,g,d],function(e,t,n,i){function r(t){var r=this,s=n.capTest,u=n.capTrue;n.call(this,t,o,{access_binary:s(window.FileReader||window.File&&File.getAsDataURL),access_image_binary:!1,display_media:s(a.Image&&(i.can("create_canvas")||i.can("use_data_uri_over32kb"))),do_cors:!1,drag_and_drop:!1,filter_by_extension:s(function(){return"Chrome"===i.browser&&i.version>=28||"IE"===i.browser&&i.version>=10}()),resize_image:function(){return a.Image&&r.can("access_binary")&&i.can("create_canvas")},report_upload_progress:!1,return_response_headers:!1,return_response_type:function(t){return"json"===t&&window.JSON?!0:!!~e.inArray(t,["text","document",""])},return_status_code:function(t){return!e.arrayDiff(t,[200,404])},select_file:function(){return i.can("use_fileinput")},select_multiple:!1,send_binary_string:!1,send_custom_headers:!1,send_multipart:!0,slice_blob:!1,stream_upload:function(){return r.can("select_file")},summon_file_dialog:s(function(){return"Firefox"===i.browser&&i.version>=4||"Opera"===i.browser&&i.version>=12||!!~e.inArray(i.browser,["Chrome","Safari"])}()),upload_filesize:u,use_http_method:function(t){return!e.arrayDiff(t,["GET","POST"])}}),e.extend(this,{init:function(){this.trigger("Init")},destroy:function(e){return function(){e.call(r),e=r=null}}(this.destroy)}),e.extend(this.getShim(),a)}var o="html4",a={};return n.addConstructor(o,r),a}),i(ct,[ut,u,f,L,l,d],function(e,t,n,i,r,o){function a(){function e(){var r=this,l=r.getRuntime(),d,f,p,h,m,g;g=t.guid("uid_"),d=l.getShimContainer(),a&&(p=n.get(a+"_form"),p&&t.extend(p.style,{top:"100%"})),h=document.createElement("form"),h.setAttribute("id",g+"_form"),h.setAttribute("method","post"),h.setAttribute("enctype","multipart/form-data"),h.setAttribute("encoding","multipart/form-data"),t.extend(h.style,{overflow:"hidden",position:"absolute",top:0,left:0,width:"100%",height:"100%"}),m=document.createElement("input"),m.setAttribute("id",g),m.setAttribute("type","file"),m.setAttribute("name",c.name||"Filedata"),m.setAttribute("accept",u.join(",")),t.extend(m.style,{fontSize:"999px",opacity:0}),h.appendChild(m),d.appendChild(h),t.extend(m.style,{position:"absolute",top:0,left:0,width:"100%",height:"100%"}),"IE"===o.browser&&o.version<10&&t.extend(m.style,{filter:"progid:DXImageTransform.Microsoft.Alpha(opacity=0)"}),m.onchange=function(){var t;this.value&&(t=this.files?this.files[0]:{name:this.value},s=[t],this.onchange=function(){},e.call(r),r.bind("change",function i(){var e=n.get(g),t=n.get(g+"_form"),o;r.unbind("change",i),r.files.length&&e&&t&&(o=r.files[0],e.setAttribute("id",o.uid),t.setAttribute("id",o.uid+"_form"),t.setAttribute("target",o.uid+"_iframe")),e=t=null},998),m=h=null,r.trigger("change"))},l.can("summon_file_dialog")&&(f=n.get(c.browse_button),i.removeEvent(f,"click",r.uid),i.addEvent(f,"click",function(e){m&&!m.disabled&&m.click(),e.preventDefault()},r.uid)),a=g,d=p=f=null}var a,s=[],u=[],c;t.extend(this,{init:function(t){var o=this,a=o.getRuntime(),s;c=t,u=t.accept.mimes||r.extList2mimes(t.accept,a.can("filter_by_extension")),s=a.getShimContainer(),function(){var e,r,u;e=n.get(t.browse_button),a.can("summon_file_dialog")&&("static"===n.getStyle(e,"position")&&(e.style.position="relative"),r=parseInt(n.getStyle(e,"z-index"),10)||1,e.style.zIndex=r,s.style.zIndex=r-1),u=a.can("summon_file_dialog")?e:s,i.addEvent(u,"mouseover",function(){o.trigger("mouseenter")},o.uid),i.addEvent(u,"mouseout",function(){o.trigger("mouseleave")},o.uid),i.addEvent(u,"mousedown",function(){o.trigger("mousedown")},o.uid),i.addEvent(n.get(t.container),"mouseup",function(){o.trigger("mouseup")},o.uid),e=null}(),e.call(this),s=null,o.trigger({type:"ready",async:!0})},getFiles:function(){return s},disable:function(e){var t;(t=n.get(a))&&(t.disabled=!!e)},destroy:function(){var e=this.getRuntime(),t=e.getShim(),r=e.getShimContainer();i.removeAllEvents(r,this.uid),i.removeAllEvents(c&&n.get(c.container),this.uid),i.removeAllEvents(c&&n.get(c.browse_button),this.uid),r&&(r.innerHTML=""),t.removeInstance(this.uid),a=s=u=c=r=t=null}})}return e.FileInput=a}),i(lt,[ut,F],function(e,t){return e.FileReader=t}),i(dt,[ut,u,f,b,p,L,y,S],function(e,t,n,i,r,o,a,s){function u(){function e(e){var t=this,i,r,a,s,u=!1;if(l){if(i=l.id.replace(/_iframe$/,""),r=n.get(i+"_form")){for(a=r.getElementsByTagName("input"),s=a.length;s--;)switch(a[s].getAttribute("type")){case"hidden":a[s].parentNode.removeChild(a[s]);break;case"file":u=!0}a=[],u||r.parentNode.removeChild(r),r=null}setTimeout(function(){o.removeEvent(l,"load",t.uid),l.parentNode&&l.parentNode.removeChild(l);var n=t.getRuntime().getShimContainer();n.children.length||n.parentNode.removeChild(n),n=l=null,e()},1)}}var u,c,l;t.extend(this,{send:function(d,f){function p(){var n=m.getShimContainer()||document.body,r=document.createElement("div");r.innerHTML='',l=r.firstChild,n.appendChild(l),o.addEvent(l,"load",function(){var n;try{n=l.contentWindow.document||l.contentDocument||window.frames[l.id].document,/^4(0[0-9]|1[0-7]|2[2346])\s/.test(n.title)?u=n.title.replace(/^(\d+).*$/,"$1"):(u=200,c=t.trim(n.body.innerHTML),h.trigger({type:"progress",loaded:c.length,total:c.length}),w&&h.trigger({type:"uploadprogress",loaded:w.size||1025,total:w.size||1025}))}catch(r){if(!i.hasSameOrigin(d.url))return e.call(h,function(){h.trigger("error")}),void 0;u=404}e.call(h,function(){h.trigger("load")})},h.uid)}var h=this,m=h.getRuntime(),g,v,y,w;if(u=c=null,f instanceof s&&f.hasBlob()){if(w=f.getBlob(),g=w.uid,y=n.get(g),v=n.get(g+"_form"),!v)throw new r.DOMException(r.DOMException.NOT_FOUND_ERR)}else g=t.guid("uid_"),v=document.createElement("form"),v.setAttribute("id",g+"_form"),v.setAttribute("method",d.method),v.setAttribute("enctype","multipart/form-data"),v.setAttribute("encoding","multipart/form-data"),v.setAttribute("target",g+"_iframe"),m.getShimContainer().appendChild(v);f instanceof s&&f.each(function(e,n){if(e instanceof a)y&&y.setAttribute("name",n);else{var i=document.createElement("input");t.extend(i,{type:"hidden",name:n,value:e}),y?v.insertBefore(i,y):v.appendChild(i)}}),v.setAttribute("action",d.url),p(),v.submit(),h.trigger("loadstart")},getStatus:function(){return u},getResponse:function(e){if("json"===e&&"string"===t.typeOf(c)&&window.JSON)try{return JSON.parse(c.replace(/^\s*]*>/,"").replace(/<\/pre>\s*$/,""))}catch(n){return null}return c},abort:function(){var t=this;l&&l.contentWindow&&(l.contentWindow.stop?l.contentWindow.stop():l.contentWindow.document.execCommand?l.contentWindow.document.execCommand("Stop"):l.src="about:blank"),e.call(this,function(){t.dispatchEvent("abort")})}})}return e.XMLHttpRequest=u}),i(ft,[ut,X],function(e,t){return e.Image=t}),a([u,c,l,d,f,p,h,m,g,v,y,w,E,_,x,R,b,T,S,A,O,I,L])}(this);;(function(){"use strict";var e={},t=moxie.core.utils.Basic.inArray;return function n(r){var i,s;for(i in r)s=typeof r[i],s==="object"&&!~t(i,["Exceptions","Env","Mime"])?n(r[i]):s==="function"&&(e[i]=r[i])}(window.moxie),e.Env=window.moxie.core.utils.Env,e.Mime=window.moxie.core.utils.Mime,e.Exceptions=window.moxie.core.Exceptions,window.mOxie=e,window.o||(window.o=e),e})(); +/** + * Plupload - multi-runtime File Uploader + * v2.1.1 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2014-01-16 + */ +;(function(e,t,n){function s(e){function r(e,t,r){var i={chunks:"slice_blob",jpgresize:"send_binary_string",pngresize:"send_binary_string",progress:"report_upload_progress",multi_selection:"select_multiple",dragdrop:"drag_and_drop",drop_element:"drag_and_drop",headers:"send_custom_headers",canSendBinary:"send_binary",triggerDialog:"summon_file_dialog"};i[e]?n[i[e]]=t:r||(n[e]=t)}var t=e.required_features,n={};return typeof t=="string"?o.each(t.split(/\s*,\s*/),function(e){r(e,!0)}):typeof t=="object"?o.each(t,function(e,t){r(t,e)}):t===!0&&(e.multipart||(n.send_binary_string=!0),e.chunk_size>0&&(n.slice_blob=!0),e.resize.enabled&&(n.send_binary_string=!0),o.each(e,function(e,t){r(t,!!e,!0)})),n}var r=e.setTimeout,i={},o={VERSION:"2.1.1",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,FILE_DUPLICATE_ERROR:-602,IMAGE_FORMAT_ERROR:-700,IMAGE_MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,mimeTypes:t.mimes,ua:t.ua,typeOf:t.typeOf,extend:t.extend,guid:t.guid,get:function(n){var r=[],i;t.typeOf(n)!=="array"&&(n=[n]);var s=n.length;while(s--)i=t.get(n[s]),i&&r.push(i);return r.length?r:null},each:t.each,getPos:t.getPos,getSize:t.getSize,xmlEncode:function(e){var t={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},n=/[<>&\"\']/g;return e?(""+e).replace(n,function(e){return t[e]?"&"+t[e]+";":e}):e},toArray:t.toArray,inArray:t.inArray,addI18n:t.addI18n,translate:t.translate,isEmptyObj:t.isEmptyObj,hasClass:t.hasClass,addClass:t.addClass,removeClass:t.removeClass,getStyle:t.getStyle,addEvent:t.addEvent,removeEvent:t.removeEvent,removeAllEvents:t.removeAllEvents,cleanName:function(e){var t,n;n=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"];for(t=0;t0?"&":"?")+n),e},formatSize:function(e){function t(e,t){return Math.round(e*Math.pow(10,t))/Math.pow(10,t)}if(e===n||/\D/.test(e))return o.translate("N/A");var r=Math.pow(1024,4);return e>r?t(e/r,1)+" "+o.translate("tb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("gb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("mb"):e>1024?Math.round(e/1024)+" "+o.translate("kb"):e+" "+o.translate("b")},parseSize:t.parseSizeStr,predictRuntime:function(e,n){var r,i;return r=new o.Uploader(e),i=t.Runtime.thatCan(r.getOption().required_features,n||e.runtimes),r.destroy(),i},addFileFilter:function(e,t){i[e]=t}};o.addFileFilter("mime_types",function(e,t,n){e.length&&!e.regexp.test(t.name)?(this.trigger("Error",{code:o.FILE_EXTENSION_ERROR,message:o.translate("File extension error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("max_file_size",function(e,t,n){var r;e=o.parseSize(e),t.size!==r&&e&&t.size>e?(this.trigger("Error",{code:o.FILE_SIZE_ERROR,message:o.translate("File size error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("prevent_duplicates",function(e,t,n){if(e){var r=this.files.length;while(r--)if(t.name===this.files[r].name&&t.size===this.files[r].size){this.trigger("Error",{code:o.FILE_DUPLICATE_ERROR,message:o.translate("Duplicate file error."),file:t}),n(!1);return}}n(!0)}),o.Uploader=function(e){function g(){var e,t=0,n;if(this.state==o.STARTED){for(n=0;n0?Math.ceil(e.loaded/e.size*100):100,b()}function b(){var e,t;d.reset();for(e=0;e0?Math.ceil(d.uploaded/f.length*100):0:(d.bytesPerSec=Math.ceil(d.loaded/((+(new Date)-p||1)/1e3)),d.percent=d.size>0?Math.ceil(d.loaded/d.size*100):0)}function w(){var e=c[0]||h[0];return e?e.getRuntime().uid:!1}function E(e,n){if(e.ruid){var r=t.Runtime.getInfo(e.ruid);if(r)return r.can(n)}return!1}function S(){this.bind("FilesAdded",C),this.bind("CancelUpload",M),this.bind("BeforeUpload",k),this.bind("UploadFile",L),this.bind("UploadProgress",A),this.bind("StateChanged",O),this.bind("QueueChanged",b),this.bind("Error",D),this.bind("FileUploaded",_),this.bind("Destroy",P)}function x(e,n){var r=this,i=0,s=[],u={accept:e.filters.mime_types,runtime_order:e.runtimes,required_caps:e.required_features,preferred_caps:l,swf_url:e.flash_swf_url,xap_url:e.silverlight_xap_url};o.each(e.runtimes.split(/\s*,\s*/),function(t){e[t]&&(u[t]=e[t])}),e.browse_button&&o.each(e.browse_button,function(n){s.push(function(s){var a=new t.FileInput(o.extend({},u,{name:e.file_data_name,multiple:e.multi_selection,container:e.container,browse_button:n}));a.onready=function(){var e=t.Runtime.getInfo(this.ruid);t.extend(r.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),multi_selection:e.can("select_multiple")}),i++,c.push(this),s()},a.onchange=function(){r.addFile(this.files)},a.bind("mouseenter mouseleave mousedown mouseup",function(r){v||(e.browse_button_hover&&("mouseenter"===r.type?t.addClass(n,e.browse_button_hover):"mouseleave"===r.type&&t.removeClass(n,e.browse_button_hover)),e.browse_button_active&&("mousedown"===r.type?t.addClass(n,e.browse_button_active):"mouseup"===r.type&&t.removeClass(n,e.browse_button_active)))}),a.bind("error runtimeerror",function(){a=null,s()}),a.init()})}),e.drop_element&&o.each(e.drop_element,function(e){s.push(function(n){var s=new t.FileDrop(o.extend({},u,{drop_zone:e}));s.onready=function(){var e=t.Runtime.getInfo(this.ruid);r.features.dragdrop=e.can("drag_and_drop"),i++,h.push(this),n()},s.ondrop=function(){r.addFile(this.files)},s.bind("error runtimeerror",function(){s=null,n()}),s.init()})}),t.inSeries(s,function(){typeof n=="function"&&n(i)})}function T(e,n,r){var i=new t.Image;try{i.onload=function(){i.downsize(n.width,n.height,n.crop,n.preserve_headers)},i.onresize=function(){r(this.getAsBlob(e.type,n.quality)),this.destroy()},i.onerror=function(){r(e)},i.load(e)}catch(s){r(e)}}function N(e,n,r){function f(e,t,n){var r=a[e];switch(e){case"max_file_size":e==="max_file_size"&&(a.max_file_size=a.filters.max_file_size=t);break;case"chunk_size":if(t=o.parseSize(t))a[e]=t;break;case"filters":o.typeOf(t)==="array"&&(t={mime_types:t}),n?o.extend(a.filters,t):a.filters=t,t.mime_types&&(a.filters.mime_types.regexp=function(e){var t=[];return o.each(e,function(e){o.each(e.extensions.split(/,/),function(e){/^\s*\*\s*$/.test(e)?t.push("\\.*"):t.push("\\."+e.replace(new RegExp("["+"/^$.*+?|()[]{}\\".replace(/./g,"\\$&")+"]","g"),"\\$&"))})}),new RegExp("("+t.join("|")+")$","i")}(a.filters.mime_types));break;case"resize":n?o.extend(a.resize,t,{enabled:!0}):a.resize=t;break;case"prevent_duplicates":a.prevent_duplicates=a.filters.prevent_duplicates=!!t;break;case"browse_button":case"drop_element":t=o.get(t);case"container":case"runtimes":case"multi_selection":case"flash_swf_url":case"silverlight_xap_url":a[e]=t,n||(u=!0);break;default:a[e]=t}n||i.trigger("OptionChanged",e,t,r)}var i=this,u=!1;typeof e=="object"?o.each(e,function(e,t){f(t,e,r)}):f(e,n,r),r?(a.required_features=s(o.extend({},a)),l=s(o.extend({},a,{required_features:!0}))):u&&(i.trigger("Destroy"),x.call(i,a,function(e){e?(i.runtime=t.Runtime.getInfo(w()).type,i.trigger("Init",{runtime:i.runtime}),i.trigger("PostInit")):i.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})}))}function C(e,t){[].push.apply(f,t),e.trigger("QueueChanged"),e.refresh()}function k(e,t){if(a.unique_names){var n=t.name.match(/\.([^.]+)$/),r="part";n&&(r=n[1]),t.target_name=t.id+"."+r}}function L(e,n){function h(){u-->0?r(p,1e3):(n.loaded=f,e.trigger("Error",{code:o.HTTP_ERROR,message:o.translate("HTTP Error."),file:n,response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()}))}function p(){var d,v,g,y;if(n.status==o.DONE||n.status==o.FAILED||e.state==o.STOPPED)return;g={name:n.target_name||n.name},s&&a.chunks&&c.size>s?(y=Math.min(s,c.size-f),d=c.slice(f,f+y)):(y=c.size,d=c),s&&a.chunks&&(e.settings.send_chunk_number?(g.chunk=Math.ceil(f/s),g.chunks=Math.ceil(c.size/s)):(g.offset=f,g.total=c.size)),m=new t.XMLHttpRequest,m.upload&&(m.upload.onprogress=function(t){n.loaded=Math.min(n.size,f+t.loaded),e.trigger("UploadProgress",n)}),m.onload=function(){if(m.status>=400){h();return}u=e.settings.max_retries,y=c.size?(n.size!=n.origSize&&(c.destroy(),c=null),e.trigger("UploadProgress",n),n.status=o.DONE,e.trigger("FileUploaded",n,{response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()})):r(p,1)},m.onerror=function(){h()},m.onloadend=function(){this.destroy(),m=null},e.settings.multipart&&a.multipart?(g.name=n.target_name||n.name,m.open("post",i,!0),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),v=new t.FormData,o.each(o.extend(g,e.settings.multipart_params),function(e,t){v.append(t,e)}),v.append(e.settings.file_data_name,d),m.send(v,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url})):(i=o.buildUrl(e.settings.url,o.extend(g,e.settings.multipart_params)),m.open("post",i,!0),m.setRequestHeader("Content-Type","application/octet-stream"),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),m.send(d,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url}))}var i=e.settings.url,s=e.settings.chunk_size,u=e.settings.max_retries,a=e.features,f=0,c;n.loaded&&(f=n.loaded=s*Math.floor(n.loaded/s)),c=n.getSource(),e.settings.resize.enabled&&E(c,"send_binary_string")&&!!~t.inArray(c.type,["image/jpeg","image/png"])?T.call(this,c,e.settings.resize,function(e){c=e,n.size=e.size,p()}):p()}function A(e,t){y(t)}function O(e){if(e.state==o.STARTED)p=+(new Date);else if(e.state==o.STOPPED)for(var t=e.files.length-1;t>=0;t--)e.files[t].status==o.UPLOADING&&(e.files[t].status=o.QUEUED,b())}function M(){m&&m.abort()}function _(e){b(),r(function(){g.call(e)},1)}function D(e,t){t.file&&(t.file.status=o.FAILED,y(t.file),e.state==o.STARTED&&(e.trigger("CancelUpload"),r(function(){g.call(e)},1)))}function P(e){e.stop(),o.each(f,function(e){e.destroy()}),f=[],c.length&&(o.each(c,function(e){e.destroy()}),c=[]),h.length&&(o.each(h,function(e){e.destroy()}),h=[]),l={},v=!1,p=m=null,d.reset()}var u=o.guid(),a,f=[],l={},c=[],h=[],p,d,v=!1,m;a={runtimes:t.Runtime.order,max_retries:0,chunk_size:0,multipart:!0,multi_selection:!0,file_data_name:"file",flash_swf_url:"js/Moxie.swf",silverlight_xap_url:"js/Moxie.xap",filters:{mime_types:[],prevent_duplicates:!1,max_file_size:0},resize:{enabled:!1,preserve_headers:!0,crop:!1},send_chunk_number:!0},N.call(this,e,null,!0),d=new o.QueueProgress,o.extend(this,{id:u,uid:u,state:o.STOPPED,features:{},runtime:null,files:f,settings:a,total:d,init:function(){var e=this;typeof a.preinit=="function"?a.preinit(e):o.each(a.preinit,function(t,n){e.bind(n,t)});if(!a.browse_button||!a.url){this.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")});return}S.call(this),x.call(this,a,function(n){typeof a.init=="function"?a.init(e):o.each(a.init,function(t,n){e.bind(n,t)}),n?(e.runtime=t.Runtime.getInfo(w()).type,e.trigger("Init",{runtime:e.runtime}),e.trigger("PostInit")):e.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})})},setOption:function(e,t){N.call(this,e,t,!this.runtime)},getOption:function(e){return e?a[e]:a},refresh:function(){c.length&&o.each(c,function(e){e.trigger("Refresh")}),this.trigger("Refresh")},start:function(){this.state!=o.STARTED&&(this.state=o.STARTED,this.trigger("StateChanged"),g.call(this))},stop:function(){this.state!=o.STOPPED&&(this.state=o.STOPPED,this.trigger("StateChanged"),this.trigger("CancelUpload"))},disableBrowse:function(){v=arguments[0]!==n?arguments[0]:!0,c.length&&o.each(c,function(e){e.disable(v)}),this.trigger("DisableBrowse",v)},getFile:function(e){var t;for(t=f.length-1;t>=0;t--)if(f[t].id===e)return f[t]},addFile:function(e,n){function l(e,n){var r=[];t.each(s.settings.filters,function(t,n){i[n]&&r.push(function(r){i[n].call(s,t,e,function(e){r(!e)})})}),t.inSeries(r,n)}function c(e){var i=t.typeOf(e);if(e instanceof t.File){if(!e.ruid&&!e.isDetached()){if(!f)return!1;e.ruid=f,e.connectRuntime(f)}c(new o.File(e))}else e instanceof t.Blob?(c(e.getSource()),e.destroy()):e instanceof o.File?(n&&(e.name=n),u.push(function(t){l(e,function(n){n||(a.push(e),s.trigger("FileFiltered",e)),r(t,1)})})):t.inArray(i,["file","blob"])!==-1?c(new t.File(null,e)):i==="node"&&t.typeOf(e.files)==="filelist"?t.each(e.files,c):i==="array"&&(n=null,t.each(e,c))}var s=this,u=[],a=[],f;f=w(),c(e),u.length&&t.inSeries(u,function(){a.length&&s.trigger("FilesAdded",a)})},removeFile:function(e){var t=typeof e=="string"?e:e.id;for(var n=f.length-1;n>=0;n--)if(f[n].id===t)return this.splice(n,1)[0]},splice:function(e,t){var r=f.splice(e===n?0:e,t===n?f.length:t),i=!1;return this.state==o.STARTED&&(i=!0,this.stop()),this.trigger("FilesRemoved",r),o.each(r,function(e){e.destroy()}),this.trigger("QueueChanged"),this.refresh(),i&&this.start(),r},bind:function(e,t,n){var r=this;o.Uploader.prototype.bind.call(this,e,function(){var e=[].slice.call(arguments);return e.splice(0,1,r),t.apply(this,e)},0,n)},destroy:function(){this.trigger("Destroy"),a=d=null,this.unbindAll()}})},o.Uploader.prototype=t.EventTarget.instance,o.File=function(){function n(n){o.extend(this,{id:o.guid(),name:n.name||n.fileName,type:n.type||"",size:n.size||n.fileSize,origSize:n.size||n.fileSize,loaded:0,percent:0,status:o.QUEUED,lastModifiedDate:n.lastModifiedDate||(new Date).toLocaleString(),getNative:function(){var e=this.getSource().getSource();return t.inArray(t.typeOf(e),["blob","file"])!==-1?e:null},getSource:function(){return e[this.id]?e[this.id]:null},destroy:function(){var t=this.getSource();t&&(t.destroy(),delete e[this.id])}}),e[this.id]=n}var e={};return n}(),o.QueueProgress=function(){var e=this;e.size=0,e.loaded=0,e.uploaded=0,e.failed=0,e.queued=0,e.percent=0,e.bytesPerSec=0,e.reset=function(){e.size=e.loaded=e.uploaded=e.failed=e.queued=e.percent=e.bytesPerSec=0}},e.plupload=o})(window,mOxie); \ No newline at end of file diff --git a/lib/scripts/uploader/plupload.min.js b/lib/scripts/uploader/plupload.min.js new file mode 100644 index 0000000..06bcd59 --- /dev/null +++ b/lib/scripts/uploader/plupload.min.js @@ -0,0 +1,13 @@ +/** + * Plupload - multi-runtime File Uploader + * v2.1.1 + * + * Copyright 2013, Moxiecode Systems AB + * Released under GPL License. + * + * License: http://www.plupload.com/license + * Contributing: http://www.plupload.com/contributing + * + * Date: 2014-01-16 + */ +;(function(e,t,n){function s(e){function r(e,t,r){var i={chunks:"slice_blob",jpgresize:"send_binary_string",pngresize:"send_binary_string",progress:"report_upload_progress",multi_selection:"select_multiple",dragdrop:"drag_and_drop",drop_element:"drag_and_drop",headers:"send_custom_headers",canSendBinary:"send_binary",triggerDialog:"summon_file_dialog"};i[e]?n[i[e]]=t:r||(n[e]=t)}var t=e.required_features,n={};return typeof t=="string"?o.each(t.split(/\s*,\s*/),function(e){r(e,!0)}):typeof t=="object"?o.each(t,function(e,t){r(t,e)}):t===!0&&(e.multipart||(n.send_binary_string=!0),e.chunk_size>0&&(n.slice_blob=!0),e.resize.enabled&&(n.send_binary_string=!0),o.each(e,function(e,t){r(t,!!e,!0)})),n}var r=e.setTimeout,i={},o={VERSION:"2.1.1",STOPPED:1,STARTED:2,QUEUED:1,UPLOADING:2,FAILED:4,DONE:5,GENERIC_ERROR:-100,HTTP_ERROR:-200,IO_ERROR:-300,SECURITY_ERROR:-400,INIT_ERROR:-500,FILE_SIZE_ERROR:-600,FILE_EXTENSION_ERROR:-601,FILE_DUPLICATE_ERROR:-602,IMAGE_FORMAT_ERROR:-700,IMAGE_MEMORY_ERROR:-701,IMAGE_DIMENSIONS_ERROR:-702,mimeTypes:t.mimes,ua:t.ua,typeOf:t.typeOf,extend:t.extend,guid:t.guid,get:function(n){var r=[],i;t.typeOf(n)!=="array"&&(n=[n]);var s=n.length;while(s--)i=t.get(n[s]),i&&r.push(i);return r.length?r:null},each:t.each,getPos:t.getPos,getSize:t.getSize,xmlEncode:function(e){var t={"<":"lt",">":"gt","&":"amp",'"':"quot","'":"#39"},n=/[<>&\"\']/g;return e?(""+e).replace(n,function(e){return t[e]?"&"+t[e]+";":e}):e},toArray:t.toArray,inArray:t.inArray,addI18n:t.addI18n,translate:t.translate,isEmptyObj:t.isEmptyObj,hasClass:t.hasClass,addClass:t.addClass,removeClass:t.removeClass,getStyle:t.getStyle,addEvent:t.addEvent,removeEvent:t.removeEvent,removeAllEvents:t.removeAllEvents,cleanName:function(e){var t,n;n=[/[\300-\306]/g,"A",/[\340-\346]/g,"a",/\307/g,"C",/\347/g,"c",/[\310-\313]/g,"E",/[\350-\353]/g,"e",/[\314-\317]/g,"I",/[\354-\357]/g,"i",/\321/g,"N",/\361/g,"n",/[\322-\330]/g,"O",/[\362-\370]/g,"o",/[\331-\334]/g,"U",/[\371-\374]/g,"u"];for(t=0;t0?"&":"?")+n),e},formatSize:function(e){function t(e,t){return Math.round(e*Math.pow(10,t))/Math.pow(10,t)}if(e===n||/\D/.test(e))return o.translate("N/A");var r=Math.pow(1024,4);return e>r?t(e/r,1)+" "+o.translate("tb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("gb"):e>(r/=1024)?t(e/r,1)+" "+o.translate("mb"):e>1024?Math.round(e/1024)+" "+o.translate("kb"):e+" "+o.translate("b")},parseSize:t.parseSizeStr,predictRuntime:function(e,n){var r,i;return r=new o.Uploader(e),i=t.Runtime.thatCan(r.getOption().required_features,n||e.runtimes),r.destroy(),i},addFileFilter:function(e,t){i[e]=t}};o.addFileFilter("mime_types",function(e,t,n){e.length&&!e.regexp.test(t.name)?(this.trigger("Error",{code:o.FILE_EXTENSION_ERROR,message:o.translate("File extension error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("max_file_size",function(e,t,n){var r;e=o.parseSize(e),t.size!==r&&e&&t.size>e?(this.trigger("Error",{code:o.FILE_SIZE_ERROR,message:o.translate("File size error."),file:t}),n(!1)):n(!0)}),o.addFileFilter("prevent_duplicates",function(e,t,n){if(e){var r=this.files.length;while(r--)if(t.name===this.files[r].name&&t.size===this.files[r].size){this.trigger("Error",{code:o.FILE_DUPLICATE_ERROR,message:o.translate("Duplicate file error."),file:t}),n(!1);return}}n(!0)}),o.Uploader=function(e){function g(){var e,t=0,n;if(this.state==o.STARTED){for(n=0;n0?Math.ceil(e.loaded/e.size*100):100,b()}function b(){var e,t;d.reset();for(e=0;e0?Math.ceil(d.uploaded/f.length*100):0:(d.bytesPerSec=Math.ceil(d.loaded/((+(new Date)-p||1)/1e3)),d.percent=d.size>0?Math.ceil(d.loaded/d.size*100):0)}function w(){var e=c[0]||h[0];return e?e.getRuntime().uid:!1}function E(e,n){if(e.ruid){var r=t.Runtime.getInfo(e.ruid);if(r)return r.can(n)}return!1}function S(){this.bind("FilesAdded",C),this.bind("CancelUpload",M),this.bind("BeforeUpload",k),this.bind("UploadFile",L),this.bind("UploadProgress",A),this.bind("StateChanged",O),this.bind("QueueChanged",b),this.bind("Error",D),this.bind("FileUploaded",_),this.bind("Destroy",P)}function x(e,n){var r=this,i=0,s=[],u={accept:e.filters.mime_types,runtime_order:e.runtimes,required_caps:e.required_features,preferred_caps:l,swf_url:e.flash_swf_url,xap_url:e.silverlight_xap_url};o.each(e.runtimes.split(/\s*,\s*/),function(t){e[t]&&(u[t]=e[t])}),e.browse_button&&o.each(e.browse_button,function(n){s.push(function(s){var a=new t.FileInput(o.extend({},u,{name:e.file_data_name,multiple:e.multi_selection,container:e.container,browse_button:n}));a.onready=function(){var e=t.Runtime.getInfo(this.ruid);t.extend(r.features,{chunks:e.can("slice_blob"),multipart:e.can("send_multipart"),multi_selection:e.can("select_multiple")}),i++,c.push(this),s()},a.onchange=function(){r.addFile(this.files)},a.bind("mouseenter mouseleave mousedown mouseup",function(r){v||(e.browse_button_hover&&("mouseenter"===r.type?t.addClass(n,e.browse_button_hover):"mouseleave"===r.type&&t.removeClass(n,e.browse_button_hover)),e.browse_button_active&&("mousedown"===r.type?t.addClass(n,e.browse_button_active):"mouseup"===r.type&&t.removeClass(n,e.browse_button_active)))}),a.bind("error runtimeerror",function(){a=null,s()}),a.init()})}),e.drop_element&&o.each(e.drop_element,function(e){s.push(function(n){var s=new t.FileDrop(o.extend({},u,{drop_zone:e}));s.onready=function(){var e=t.Runtime.getInfo(this.ruid);r.features.dragdrop=e.can("drag_and_drop"),i++,h.push(this),n()},s.ondrop=function(){r.addFile(this.files)},s.bind("error runtimeerror",function(){s=null,n()}),s.init()})}),t.inSeries(s,function(){typeof n=="function"&&n(i)})}function T(e,n,r){var i=new t.Image;try{i.onload=function(){i.downsize(n.width,n.height,n.crop,n.preserve_headers)},i.onresize=function(){r(this.getAsBlob(e.type,n.quality)),this.destroy()},i.onerror=function(){r(e)},i.load(e)}catch(s){r(e)}}function N(e,n,r){function f(e,t,n){var r=a[e];switch(e){case"max_file_size":e==="max_file_size"&&(a.max_file_size=a.filters.max_file_size=t);break;case"chunk_size":if(t=o.parseSize(t))a[e]=t;break;case"filters":o.typeOf(t)==="array"&&(t={mime_types:t}),n?o.extend(a.filters,t):a.filters=t,t.mime_types&&(a.filters.mime_types.regexp=function(e){var t=[];return o.each(e,function(e){o.each(e.extensions.split(/,/),function(e){/^\s*\*\s*$/.test(e)?t.push("\\.*"):t.push("\\."+e.replace(new RegExp("["+"/^$.*+?|()[]{}\\".replace(/./g,"\\$&")+"]","g"),"\\$&"))})}),new RegExp("("+t.join("|")+")$","i")}(a.filters.mime_types));break;case"resize":n?o.extend(a.resize,t,{enabled:!0}):a.resize=t;break;case"prevent_duplicates":a.prevent_duplicates=a.filters.prevent_duplicates=!!t;break;case"browse_button":case"drop_element":t=o.get(t);case"container":case"runtimes":case"multi_selection":case"flash_swf_url":case"silverlight_xap_url":a[e]=t,n||(u=!0);break;default:a[e]=t}n||i.trigger("OptionChanged",e,t,r)}var i=this,u=!1;typeof e=="object"?o.each(e,function(e,t){f(t,e,r)}):f(e,n,r),r?(a.required_features=s(o.extend({},a)),l=s(o.extend({},a,{required_features:!0}))):u&&(i.trigger("Destroy"),x.call(i,a,function(e){e?(i.runtime=t.Runtime.getInfo(w()).type,i.trigger("Init",{runtime:i.runtime}),i.trigger("PostInit")):i.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})}))}function C(e,t){[].push.apply(f,t),e.trigger("QueueChanged"),e.refresh()}function k(e,t){if(a.unique_names){var n=t.name.match(/\.([^.]+)$/),r="part";n&&(r=n[1]),t.target_name=t.id+"."+r}}function L(e,n){function h(){u-->0?r(p,1e3):(n.loaded=f,e.trigger("Error",{code:o.HTTP_ERROR,message:o.translate("HTTP Error."),file:n,response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()}))}function p(){var d,v,g,y;if(n.status==o.DONE||n.status==o.FAILED||e.state==o.STOPPED)return;g={name:n.target_name||n.name},s&&a.chunks&&c.size>s?(y=Math.min(s,c.size-f),d=c.slice(f,f+y)):(y=c.size,d=c),s&&a.chunks&&(e.settings.send_chunk_number?(g.chunk=Math.ceil(f/s),g.chunks=Math.ceil(c.size/s)):(g.offset=f,g.total=c.size)),m=new t.XMLHttpRequest,m.upload&&(m.upload.onprogress=function(t){n.loaded=Math.min(n.size,f+t.loaded),e.trigger("UploadProgress",n)}),m.onload=function(){if(m.status>=400){h();return}u=e.settings.max_retries,y=c.size?(n.size!=n.origSize&&(c.destroy(),c=null),e.trigger("UploadProgress",n),n.status=o.DONE,e.trigger("FileUploaded",n,{response:m.responseText,status:m.status,responseHeaders:m.getAllResponseHeaders()})):r(p,1)},m.onerror=function(){h()},m.onloadend=function(){this.destroy(),m=null},e.settings.multipart&&a.multipart?(g.name=n.target_name||n.name,m.open("post",i,!0),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),v=new t.FormData,o.each(o.extend(g,e.settings.multipart_params),function(e,t){v.append(t,e)}),v.append(e.settings.file_data_name,d),m.send(v,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url})):(i=o.buildUrl(e.settings.url,o.extend(g,e.settings.multipart_params)),m.open("post",i,!0),m.setRequestHeader("Content-Type","application/octet-stream"),o.each(e.settings.headers,function(e,t){m.setRequestHeader(t,e)}),m.send(d,{runtime_order:e.settings.runtimes,required_caps:e.settings.required_features,preferred_caps:l,swf_url:e.settings.flash_swf_url,xap_url:e.settings.silverlight_xap_url}))}var i=e.settings.url,s=e.settings.chunk_size,u=e.settings.max_retries,a=e.features,f=0,c;n.loaded&&(f=n.loaded=s*Math.floor(n.loaded/s)),c=n.getSource(),e.settings.resize.enabled&&E(c,"send_binary_string")&&!!~t.inArray(c.type,["image/jpeg","image/png"])?T.call(this,c,e.settings.resize,function(e){c=e,n.size=e.size,p()}):p()}function A(e,t){y(t)}function O(e){if(e.state==o.STARTED)p=+(new Date);else if(e.state==o.STOPPED)for(var t=e.files.length-1;t>=0;t--)e.files[t].status==o.UPLOADING&&(e.files[t].status=o.QUEUED,b())}function M(){m&&m.abort()}function _(e){b(),r(function(){g.call(e)},1)}function D(e,t){t.file&&(t.file.status=o.FAILED,y(t.file),e.state==o.STARTED&&(e.trigger("CancelUpload"),r(function(){g.call(e)},1)))}function P(e){e.stop(),o.each(f,function(e){e.destroy()}),f=[],c.length&&(o.each(c,function(e){e.destroy()}),c=[]),h.length&&(o.each(h,function(e){e.destroy()}),h=[]),l={},v=!1,p=m=null,d.reset()}var u=o.guid(),a,f=[],l={},c=[],h=[],p,d,v=!1,m;a={runtimes:t.Runtime.order,max_retries:0,chunk_size:0,multipart:!0,multi_selection:!0,file_data_name:"file",flash_swf_url:"js/Moxie.swf",silverlight_xap_url:"js/Moxie.xap",filters:{mime_types:[],prevent_duplicates:!1,max_file_size:0},resize:{enabled:!1,preserve_headers:!0,crop:!1},send_chunk_number:!0},N.call(this,e,null,!0),d=new o.QueueProgress,o.extend(this,{id:u,uid:u,state:o.STOPPED,features:{},runtime:null,files:f,settings:a,total:d,init:function(){var e=this;typeof a.preinit=="function"?a.preinit(e):o.each(a.preinit,function(t,n){e.bind(n,t)});if(!a.browse_button||!a.url){this.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")});return}S.call(this),x.call(this,a,function(n){typeof a.init=="function"?a.init(e):o.each(a.init,function(t,n){e.bind(n,t)}),n?(e.runtime=t.Runtime.getInfo(w()).type,e.trigger("Init",{runtime:e.runtime}),e.trigger("PostInit")):e.trigger("Error",{code:o.INIT_ERROR,message:o.translate("Init error.")})})},setOption:function(e,t){N.call(this,e,t,!this.runtime)},getOption:function(e){return e?a[e]:a},refresh:function(){c.length&&o.each(c,function(e){e.trigger("Refresh")}),this.trigger("Refresh")},start:function(){this.state!=o.STARTED&&(this.state=o.STARTED,this.trigger("StateChanged"),g.call(this))},stop:function(){this.state!=o.STOPPED&&(this.state=o.STOPPED,this.trigger("StateChanged"),this.trigger("CancelUpload"))},disableBrowse:function(){v=arguments[0]!==n?arguments[0]:!0,c.length&&o.each(c,function(e){e.disable(v)}),this.trigger("DisableBrowse",v)},getFile:function(e){var t;for(t=f.length-1;t>=0;t--)if(f[t].id===e)return f[t]},addFile:function(e,n){function l(e,n){var r=[];t.each(s.settings.filters,function(t,n){i[n]&&r.push(function(r){i[n].call(s,t,e,function(e){r(!e)})})}),t.inSeries(r,n)}function c(e){var i=t.typeOf(e);if(e instanceof t.File){if(!e.ruid&&!e.isDetached()){if(!f)return!1;e.ruid=f,e.connectRuntime(f)}c(new o.File(e))}else e instanceof t.Blob?(c(e.getSource()),e.destroy()):e instanceof o.File?(n&&(e.name=n),u.push(function(t){l(e,function(n){n||(a.push(e),s.trigger("FileFiltered",e)),r(t,1)})})):t.inArray(i,["file","blob"])!==-1?c(new t.File(null,e)):i==="node"&&t.typeOf(e.files)==="filelist"?t.each(e.files,c):i==="array"&&(n=null,t.each(e,c))}var s=this,u=[],a=[],f;f=w(),c(e),u.length&&t.inSeries(u,function(){a.length&&s.trigger("FilesAdded",a)})},removeFile:function(e){var t=typeof e=="string"?e:e.id;for(var n=f.length-1;n>=0;n--)if(f[n].id===t)return this.splice(n,1)[0]},splice:function(e,t){var r=f.splice(e===n?0:e,t===n?f.length:t),i=!1;return this.state==o.STARTED&&(i=!0,this.stop()),this.trigger("FilesRemoved",r),o.each(r,function(e){e.destroy()}),this.trigger("QueueChanged"),this.refresh(),i&&this.start(),r},bind:function(e,t,n){var r=this;o.Uploader.prototype.bind.call(this,e,function(){var e=[].slice.call(arguments);return e.splice(0,1,r),t.apply(this,e)},0,n)},destroy:function(){this.trigger("Destroy"),a=d=null,this.unbindAll()}})},o.Uploader.prototype=t.EventTarget.instance,o.File=function(){function n(n){o.extend(this,{id:o.guid(),name:n.name||n.fileName,type:n.type||"",size:n.size||n.fileSize,origSize:n.size||n.fileSize,loaded:0,percent:0,status:o.QUEUED,lastModifiedDate:n.lastModifiedDate||(new Date).toLocaleString(),getNative:function(){var e=this.getSource().getSource();return t.inArray(t.typeOf(e),["blob","file"])!==-1?e:null},getSource:function(){return e[this.id]?e[this.id]:null},destroy:function(){var t=this.getSource();t&&(t.destroy(),delete e[this.id])}}),e[this.id]=n}var e={};return n}(),o.QueueProgress=function(){var e=this;e.size=0,e.loaded=0,e.uploaded=0,e.failed=0,e.queued=0,e.percent=0,e.bytesPerSec=0,e.reset=function(){e.size=e.loaded=e.uploaded=e.failed=e.queued=e.percent=e.bytesPerSec=0}},e.plupload=o})(window,mOxie); \ No newline at end of file diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..a67eea0 --- /dev/null +++ b/license.txt @@ -0,0 +1,344 @@ +AVE.cms - Web publishing software (Content managment system) + +Copyright 2013 by the contributors + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +This program incorporates work covered by the following copyright and +permission notices: + + b2 is (c) 2001, 2002 Michel Valdrighi - m@tidakada.com - + http://tidakada.com + + Wherever third party code has been used, credit has been given in the code's + comments. + + AVE.cms - Web publishing software (Content Managment System) + + Copyright 2007-2014 by the contributors + + AVE.cms is released under the GPL + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + GNU GENERAL PUBLIC LICENSE + Версия 2, июнь 1991г. + + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Каждый вправе копировать и распространять экземпляры настоящей Лицензии без +внесения изменений в ее текст. + +Преамбула + +Большинство лицензий на программное обеспечение лишаeт вас права распространять и +вносить изменения в это программное обеспечение. Стандартная Общественная Лицензия +GNU, напротив, разработана с целью гарантировать вам право совместно использовать и +вносить изменения в свободное программное обеспечение, т.е. обеспечить свободный +доступ к программному обеспечению для всех пользователей. Условия настоящей +Стандартной Общественной Лицензии применяются к большей части программного +обеспечения Free Software Foundation, а также к любому другому программному обеспечению +по желанию его автора. (К некоторому программному обеспечению Free Software Foundation +применяются условия Стандартной Общественной Лицензии GNU для Библиотек). Вы также +можете применять Стандартную Общественную Лицензию к разработанному вами +программному обеспечению. + +Говоря о свободном программном обеспечении, мы имеем в виду свободу, а не +безвозмездность. Настоящая Стандартная Общественная Лицензия разработана с целью +гарантировать вам право распространять экземпляры свободного программного +обеспечения (и при желании получать за это вознаграждение), право получать исходный +текст программного обеспечения или иметь возможность его получить, право вносить +изменения в программное обеспечение или использовать его части в новом свободном +программном обеспечении, а также право знать, что вы имеете все вышеперечисленные +права. + +Чтобы защитить ваши права, мы вводим ряд ограничений с тем, чтобы никто не имел +возможности лишить вас этих прав или обратиться к вам с предложением отказаться от +этих прав. Данные ограничения налагают на вас определенные обязанности в случае, +если вы распространяете экземпляры программного обеспечения или модифицируете +программное обеспечение. + +Например, если вы распространяете экземпляры такого программного обеспечения за +плату или бесплатно, вы обязаны передать новым обладателям все права в том же объеме, +в каком они принадлежат вам. Вы обязаны обеспечить получение новыми обладателями +программы ее исходного текста или возможность его получить. Вы также обязаны +ознакомить их с условиями настоящей Лицензии. + +Для защиты ваших прав мы: (1) оставляем за собой авторские права на программное +обеспечение и (2) предлагаем вам использовать настоящую Лицензию, в соответствии +с условиями которой вы вправе воспроизводить, распространять и/или модифицировать +программное обеспечение. + +Кроме того, для защиты как нашей репутации, так и репутации других авторов +программного обеспечения, мы уведомляем всех пользователей, что на данное +программное обеспечение никаких гарантий не предоставляется. Те, кто приобрел +программное обеспечение, с внесенными в него третьими лицами изменениями, должны +знать, что они получают не оригинал, в силу чего автор оригинала не несет +ответственности за ошибки в работе программного обеспечения, допущенные третьими +лицами при внесении изменений. + +Наконец, программное обеспечение перестает быть свободным в случае, если лицо +приобретает на него исключительные права [1]. Недопустимо, чтобы лица, +распространяющие свободное программное обеспечение, могли приобрести +исключительные права на использование данного программного обеспечения и +зарегистрировать их в Патентном ведомстве. Чтобы избежать этого, мы заявляем, что +обладатель исключительных прав обязан предоставить любому лицу права на +использование программного обеспечения либо не приобретать исключительных прав +вообще. + +Ниже изложены условия воспроизведения, распространения и модификации программного +обеспечения. + +Условия воспроизведения, распространения и модификации + +0. Условия настоящей Лицензии применяются ко всем видам программного обеспечения +или любому иному произведению, которое содержит указание правообладателя на то, что +данное произведение может распространяться на условиях Стандартной Общественной +Лицензии. Под термином "Программа" далее понимается любое подобное программное +обеспечение или иное произведение. Под термином "произведение, производное от +Программы" понимается Программа или любое иное производное произведение в +соответствии с законодательством об авторском праве [2], т.е. произведение, +включающее в себя Программу или ее часть, как с внесенными в ее текст изменениями, +так и без них и/или переведенную на другой язык. (Здесь и далее, понятие "модификация" +включает в себя понятие перевода в самом широком смысле). Каждый приобретатель +экземпляра Программы именуется в дальнейшем "Лицензиат". + +Действие настоящей Лицензии не распространяется на осуществление иных прав, кроме +воспроизведения, распространения и модификации программного обеспечения. Не +устанавливается ограничений на запуск Программы. Условия Лицензии +распространяются на выходные данные из Программы только в том случае, если их +содержание составляет произведение, производное от Программы (независимо от того, +было ли такое произведение создано в результате запуска Программы). Это зависит от +того, какие функции выполняет Программа. + +1. Лицензиат вправе изготовлять и распространять экземпляры исходного текста +Программы в том виде, в каком он его получил, без внесения в него изменений на любом +носителе, при соблюдении следующих условий: на каждом экземпляре помещен знак +охраны авторского права и уведомление об отсутствии гарантий; оставлены без +изменений все уведомления, относящиеся к настоящей Лицензии и отсутствию гарантий; +вместе с экземпляром Программы приобретателю передается копия настоящей Лицензии. + +Лицензиат вправе взимать плату за передачу экземпляра Программы, а также вправе за +плату оказывать услуги по гарантийной поддержке Программы. + +2. Лицензиат вправе модифицировать свой экземпляр или экземпляры Программы +полностью или любую ее часть. Данные действия Лицензиата влекут за собой создание +произведения, производного от Программы. Лицензиат вправе изготовлять и +распространять экземпляры такого произведения, производного от Программы, или +собственно экземпляры изменений в соответствии с пунктом 1 настоящей Лицензии при +соблюдении следующих условий: + +а) файлы, измененные Лицензиатом, должны содержать хорошо заметную пометку, что они +были изменены, а также дату внесения изменений; + +b) при распространении или публикации Лицензиатом любого произведения, которое +содержит Программу или ее часть или является производным от Программы или от ее +части, Лицензиат обязан передавать права на использование данного произведения +третьим лицам на условиях настоящей Лицензии, при этом Лицензиат не вправе +требовать уплаты каких-либо лицензионных платежей. Распространяемое произведение +лицензируется как одно целое; + +c) если модифицированная Программа при запуске обычно читает команды в +интерактивном режиме, Лицензиат обязан обеспечить вывод на экран дисплея или +печатающее устройство сообщения, которое должно включать в себя: +знак охраны авторского права; +уведомление об отсутствии гарантий на Программу (или иное, если Лицензиат +предоставляет гарантии); +указание на то, что пользователи вправе распространять экземпляры Программы в +соответствии с условиями настоящей Лицензии, а также на то, каким образом +пользователь может ознакомиться с текстом настоящей Лицензии. (Исключение: если +оригинальная Программа является интерактивной, но не выводит в своем обычном режиме +работы сообщение такого рода, то вывод подобного сообщения произведением, +производным от Программы, в этом случае не обязателен). + +Вышеуказанные условия применяются к модифицированному произведению, производному +от Программы, в целом. В случае если отдельные части данного произведения не +являются производными от Программы, являются результатом творческой деятельности и +могут быть использованы как самостоятельное произведение, Лицензиат вправе +распространять отдельно такое произведение на иных лицензионных условиях. В случае +если Лицензиат распространяет вышеуказанные части в составе произведения, +производного от Программы, то условия настоящей Лицензии применяются к +произведению в целом, при этом права, приобретаемые сублицензиатами на основании +Лицензии, передаются им в отношении всего произведения, включая все его части, +независимо от того, кто является их авторами. + +Целью настоящего пункта 2 не является заявление прав или оспаривание прав на +произведение, созданное исключительно Лицензиатом. Целью настоящего пункта +является обеспечение права контролировать распространение произведений, +производных от Программы, и составных произведений, производных от Программы. + +Размещение произведения, которое не является производным от Программы, на одном +устройстве для хранения информации или носителе вместе с Программой или +произведением, производным от Программы, не влечет за собой распространения условий +настоящей Лицензии на такое произведение. + +3. Лицензиат вправе воспроизводить и распространять экземпляры Программы или +произведения, которое является производным от Программы, в соответствии с пунктом 2 +настоящей Лицензии, в виде объектного кода или в исполняемой форме в соответствии с +условиями п.п.1 и 2 настоящей Лицензии при соблюдении одного из перечисленных ниже +условий: + +а) к экземпляру должен прилагаться соответствующий полный исходный текст в +машиночитаемой форме, который должен распространяться в соответствии с условиями +п.п. 1 и 2 настоящей Лицензии на носителе, обычно используемом для передачи +программного обеспечения, либо + +b) к экземпляру должно прилагаться действительное в течение трех лет предложение в +письменной форме к любому третьему лицу передать за плату, не превышающую стоимость +осуществления собственно передачи, экземпляр соответствующего полного исходного +текста в машиночитаемой форме в соответствии с условиями п.п. 1 и 2 настоящей Лицензии +на носителе, обычно используемом для передачи программного обеспечения, либо + +c) к экземпляру должна прилагаться полученная Лицензиатом информация о предложении, +в соответствии с которым можно получить соответствующий исходный текст. (Данное +положение применяется исключительно в том случае, если Лицензиат осуществляет +некоммерческое распространение программы, при этом программа была получена самим +Лицензиатом в виде объектного кода или в исполняемой форме и сопровождалась +предложением, соответствующим условиям пп.b п.3 настоящей Лицензии). + +Под исходным текстом произведения понимается такая форма произведения, которая +наиболее удобна для внесения изменений. Под полным исходным текстом исполняемого +произведения понимается исходный текст всех составляющих произведение модулей, а +также всех файлов, связанных с описанием интерфейса, и сценариев, предназначенных +для управления компиляцией и установкой исполняемого произведения. Однако, в +качестве особого исключения, распространяемый исходный текст может не включать +того, что обычно распространяется (в виде исходного текста или в бинарной форме) с +основными компонентами (компилятор, ядро и т.д.) операционной системы, в которой +работает исполняемое произведение, за исключением случаев, когда исполняемое +произведение сопровождается таким компонентом. + +В случае если произведение в виде объектного кода или в исполняемой форме +распространяется путем предоставления доступа для копирования его из +определенного места, обеспечение равноценного доступа для копирования исходного +текста из этого же места удовлетворяет требованиям распространения исходного +текста, даже если третьи лица при этом не обязаны копировать исходный текст вместе с +объектным кодом произведения. + +4. Лицензиат вправе воспроизводить, модифицировать, распространять или передавать +права на использование Программы только на условиях настоящей Лицензии. Любое +воспроизведение, модификация, распространение или передача прав на иных условиях +являются недействительными и автоматически ведут к расторжению настоящей Лицензии +и прекращению всех прав Лицензиата, предоставленных ему настоящей Лицензией. При +этом права третьих лиц, которым Лицензиат в соответствии с настоящей Лицензией +передал экземпляры Программы или права на нее, сохраняются в силе при условии +полного соблюдения ими настоящей Лицензии. + +5. Лицензиат не обязан присоединяться к настоящей Лицензии, поскольку он ее не +подписал. Однако только настоящая Лицензия предоставляет право распространять или +модифицировать Программу или произведение, производное от Программы. Подобные +действия нарушают действующее законодательство, если они не осуществляются в +соответствии с настоящей Лицензией. Если Лицензиат внес изменения или осуществил +распространение экземпляров Программы или произведения, производного от Программы, +Лицензиат тем самым подтвердил свое присоединение к настоящей Лицензии в целом, +включая условия, определяющие порядок воспроизведения, распространения или +модификации Программы или произведения, производного от Программы. + +6. При распространении экземпляров Программы или произведения, производного от +Программы, первоначальный лицензиар автоматически передает приобретателю такого +экземпляра право воспроизводить, распространять и модифицировать Программу в +соответствии с условиями настоящей Лицензии. Лицензиат не вправе ограничивать +каким-либо способом осуществление приобретателями полученных ими прав. Лицензиат +не несет ответственности за несоблюдение условий настоящей Лицензии третьими +лицами. + +7. Лицензиат не освобождается от исполнения обязательств в соответствии с настоящей +Лицензией в случае, если в результате решения суда или заявления о нарушении +исключительных прав или в связи с наступлением иных обстоятельств, не связанных +непосредственно с нарушением исключительных прав, на Лицензиата на основании +решения суда, договора или ином основании возложены обязательства, которые +противоречат условиям настоящей Лицензии. В этом случае Лицензиат не вправе +распространять экземпляры Программы, если он не может одновременно исполнить +условия настоящей Лицензии и возложенные на него указанным выше способом +обязательства. Например, если по условиям лицензионного соглашения сублицензиатам +не может быть предоставлено право бесплатного распространения экземпляров +Программы, которые они приобрели напрямую или через третьих лиц у Лицензиата, то в +этом случае Лицензиат обязан отказаться от распространения экземпляров Программы. + +Если любое положение настоящего пункта при наступлении конкретных обстоятельств +будет признано недействительным или неприменимым, настоящий пункт применяется за +исключением такого положения. Настоящий пункт применяется в целом при прекращении +вышеуказанных обстоятельств или их отсутствии. + +Целью данного пункта не является принуждение Лицензиата к нарушению патента или +заявления на иные права собственности или к оспариванию действительности такого +заявления. Единственной целью данного пункта является защита неприкосновенности +системы распространения свободного программного обеспечения, которая +обеспечивается за счет общественного лицензирования. Многие люди внесли свой +щедрый вклад в создание большого количества программного обеспечения, которое +распространяется через данную систему в надежде на ее длительное и +последовательное применение. Лицензиат не вправе вынуждать автора распространять +программное обеспечение через данную систему. Право выбора системы распространения +программного обеспечения принадлежит исключительно его автору. + +Настоящий пункт 7 имеет целью четко определить те цели, которые преследуют все +остальные положения настоящей Лицензии. + +8. В том случае если распространение и/или использование Программы в отдельных +государствах ограничено соглашениями в области патентных или авторских прав, +первоначальный правообладатель, распространяющий Программу на условиях настоящей +Лицензии, вправе ограничить территорию распространения Программы, указав только те +государства, на территории которых допускается распространение Программы без +ограничений, обусловленных такими соглашениями. В этом случае такое указание в +отношении территорий определенных государств признается одним из условий +настоящей Лицензии. + +9. Free Software Foundation может публиковать исправленные и/или новые версии настоящей +Стандартной Общественной Лицензии. Такие версии могут быть дополнены различными +нормами, регулирующими правоотношения, которые возникли после опубликования +предыдущих версий, однако в них будут сохранены основные принципы, закрепленные в +настоящей версии. + +Каждой версии присваивается свой собственный номер. Если указано, что Программа +распространяется в соответствии с определенной версией, т.е. указан ее номер, или +любой более поздней версией настоящей Лицензии, Лицензиат вправе присоединиться к +любой из этих версий Лицензии, опубликованных Free Software Foundation. Если Программа не +содержит такого указания на номер версии Лицензии Лицензиат вправе присоединиться +к любой из версий Лицензии, опубликованных когда-либо Free Software Foundation. + +10. В случае если Лицензиат намерен включить часть Программы в другое свободное +программное обеспечение, которое распространяется на иных условиях, чем в настоящей +Лицензии, ему следует испросить письменное разрешение на это у автора программного +обеспечения. Разрешение в отношении программного обеспечения, права на которое +принадлежат Free Software Foundation, следует испрашивать у Free Software Foundation. +В некоторых случаях Free Software Foundation делает исключения. При принятии решения +Free Software Foundation будет руководствоваться двумя целями: сохранение статуса свободного +для любого произведения, производного от свободного программного обеспечения Free Software +Foundation и обеспечение наиболее широкого совместного использования программного +обеспечения. + +ОТСУТСТВИЕ ГАРАНТИЙНЫХ ОБЯЗАТЕЛЬСТВ + +11. ПОСКОЛЬКУ НАСТОЯЩАЯ ПРОГРАММА РАСПРОСТРАНЯЕТСЯ БЕСПЛАТНО, ГАРАНТИИ НА НЕЕ НЕ +ПРЕДОСТАВЛЯЮТСЯ В ТОЙ СТЕПЕНИ, В КАКОЙ ЭТО ДОПУСКАЕТСЯ ПРИМЕНИМЫМ ПРАВОМ. НАСТОЯЩАЯ +ПРОГРАММА ПОСТАВЛЯЕТСЯ НА УСЛОВИЯХ "КАК ЕСТЬ". ЕСЛИ ИНОЕ НЕ УКАЗАНО В ПИСЬМЕННОЙ +ФОРМЕ, АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ НЕ ПРИНИМАЕТ НА СЕБЯ НИКАКИХ ГАРАНТИЙНЫХ +ОБЯЗАТЕЛЬСТВ, КАК ЯВНО ВЫРАЖЕННЫХ, ТАК И ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ПРОГРАММЫ, В +ТОМ ЧИСЛЕ ПОДРАЗУМЕВАЕМУЮ ГАРАНТИЮ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ И ПРИГОДНОСТИ +ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ, А ТАКЖЕ ЛЮБЫЕ ИНЫЕ ГАРАНТИИ. ВСЕ РИСКИ, +СВЯЗАННЫЕ С КАЧЕСТВОМ И ПРОИЗВОДИТЕЛЬНОСТЬЮ ПРОГРАММЫ, НЕСЕТ ЛИЦЕНЗИАТ. В СЛУЧАЕ +ЕСЛИ В ПРОГРАММЕ БУДУТ ОБНАРУЖЕНЫ НЕДОСТАТКИ, ВСЕ РАСХОДЫ, СВЯЗАННЫЕ С ТЕХНИЧЕСКИМ +ОБСЛУЖИВАНИЕМ, РЕМОНТОМ ИЛИ ИСПРАВЛЕНИЕМ ПРОГРАММЫ, НЕСЕТ ЛИЦЕНЗИАТ. + +12. ЕСЛИ ИНОЕ НЕ ПРЕДУСМОТРЕНО ПРИМЕНЯЕМЫМ ПРАВОМ ИЛИ НЕ СОГЛАСОВАНО СТОРОНАМИ В +ДОГОВОРЕ В ПИСЬМЕННОЙ ФОРМЕ, АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ, КОТОРЫЙ МОДИФИЦИРУЕТ +И/ИЛИ РАСПРОСТРАНЯЕТ ПРОГРАММУ НА УСЛОВИЯХ НАСТОЯЩЕЙ ЛИЦЕНЗИИ, НЕ НЕСЕТ +ОТВЕТСТВЕННОСТИ ПЕРЕД ЛИЦЕНЗИАТОМ ЗА УБЫТКИ, ВКЛЮЧАЯ ОБЩИЕ, РЕАЛЬНЫЕ, ПРЕДВИДИМЫЕ И +КОСВЕННЫЕ УБЫТКИ (В ТОМ ЧИСЛЕ УТРАТУ ИЛИ ИСКАЖЕНИЕ ИНФОРМАЦИИ, УБЫТКИ, ПОНЕСЕННЫЕ +ЛИЦЕНЗИАТОМ ИЛИ ТРЕТЬИМИ ЛИЦАМИ, НЕВОЗМОЖНОСТЬ РАБОТЫ ПРОГРАММЫ С ЛЮБОЙ ДРУГОЙ +ПРОГРАММОЙ И ИНЫЕ УБЫТКИ). АВТОР И/ИЛИ ИНОЙ ПРАВООБЛАДАТЕЛЬ В СООТВЕТСТВИИ С +НАСТОЯЩИМ ПУНКТОМ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ДАЖЕ В ТОМ СЛУЧАЕ, ЕСЛИ ОНИ БЫЛИ +ПРЕДУПРЕЖДЕНЫ О ВОЗМОЖНОСТИ ВОЗНИКНОВЕНИЯ ТАКИХ УБЫТКОВ. \ No newline at end of file diff --git a/modules/index.php b/modules/index.php new file mode 100644 index 0000000..046ab72 --- /dev/null +++ b/modules/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..536fa08 --- /dev/null +++ b/robots.txt @@ -0,0 +1,18 @@ +User-Agent: * +Disallow: /admin/ +Disallow: /class/ +Disallow: /config/ +Disallow: /fields/ +Disallow: /functions/ +Disallow: /inc/ +Disallow: /lib/ +#Disallow: /modules/ +Disallow: /*?sysblock +Disallow: /*?request +Disallow: /*?module +Disallow: /*index.php?module +#Disallow: /templates/ +Disallow: /tmp/ +# +#Sitemap: http://site.com/sitemap.xml +#Host: site.com \ No newline at end of file diff --git a/templates/default/css/combine.php b/templates/default/css/combine.php new file mode 100644 index 0000000..abe84c3 --- /dev/null +++ b/templates/default/css/combine.php @@ -0,0 +1,201 @@ + diff --git a/templates/default/css/styles.css b/templates/default/css/styles.css new file mode 100644 index 0000000..b3b84c8 --- /dev/null +++ b/templates/default/css/styles.css @@ -0,0 +1,33 @@ +/* Sticky footer styles +-------------------------------------------------- */ +html { + position: relative; + min-height: 100%; +} +body { + /* Margin bottom by footer height */ + margin-bottom: 60px; +} +.footer { + position: absolute; + bottom: 0; + width: 100%; + /* Set the fixed height of the footer here */ + height: 60px; + line-height: 60px; /* Vertically center the text there */ + background-color: #f5f5f5; +} + + +/* Custom page CSS +-------------------------------------------------- */ +/* Not required for template or sticky footer method. */ + +body > .container { + padding: 60px 15px 0; +} + +.footer > .container { + padding-right: 15px; + padding-left: 15px; +} \ No newline at end of file diff --git a/templates/default/images/watermark.gif b/templates/default/images/watermark.gif new file mode 100644 index 0000000..0d5a959 Binary files /dev/null and b/templates/default/images/watermark.gif differ diff --git a/templates/default/index.php b/templates/default/index.php new file mode 100644 index 0000000..5ca71c3 --- /dev/null +++ b/templates/default/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/templates/default/js/combine.php b/templates/default/js/combine.php new file mode 100644 index 0000000..1e613a5 --- /dev/null +++ b/templates/default/js/combine.php @@ -0,0 +1,171 @@ + diff --git a/templates/default/js/main.js b/templates/default/js/main.js new file mode 100644 index 0000000..e69de29 diff --git a/templates/default/lang/ru.txt b/templates/default/lang/ru.txt new file mode 100644 index 0000000..20bf33c --- /dev/null +++ b/templates/default/lang/ru.txt @@ -0,0 +1 @@ +test = "Тест" \ No newline at end of file diff --git a/templates/default/tpl/index.php b/templates/default/tpl/index.php new file mode 100644 index 0000000..4ca25aa --- /dev/null +++ b/templates/default/tpl/index.php @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/templates/default/tpl/request/index.php b/templates/default/tpl/request/index.php new file mode 100644 index 0000000..4ca25aa --- /dev/null +++ b/templates/default/tpl/request/index.php @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/templates/default/tpl/request/public.tpl b/templates/default/tpl/request/public.tpl new file mode 100644 index 0000000..bcdf9ab --- /dev/null +++ b/templates/default/tpl/request/public.tpl @@ -0,0 +1,16 @@ +
                        + + +{foreach from=$ctrlrequest item=items key=selname} + +{/foreach} + + +
                        + + +
                        +
                        \ No newline at end of file diff --git a/templates/index.php b/templates/index.php new file mode 100644 index 0000000..5ca71c3 --- /dev/null +++ b/templates/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/tmp/.htaccess b/tmp/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/attachments/.htaccess b/tmp/attachments/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/attachments/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/backup/.htaccess b/tmp/backup/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/backup/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/.htaccess b/tmp/cache/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/combine/.htaccess b/tmp/cache/combine/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/combine/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/module/.htaccess b/tmp/cache/module/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/module/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/redactor/.htaccess b/tmp/cache/redactor/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/redactor/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/redactor/log.txt b/tmp/cache/redactor/log.txt new file mode 100644 index 0000000..e69de29 diff --git a/tmp/cache/smarty/.htaccess b/tmp/cache/smarty/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/smarty/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/sql/.htaccess b/tmp/cache/sql/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/sql/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/cache/tpl/.htaccess b/tmp/cache/tpl/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/cache/tpl/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/logs/.htaccess b/tmp/logs/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/logs/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/session/.htaccess b/tmp/session/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/session/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/update/.htaccess b/tmp/update/.htaccess new file mode 100644 index 0000000..14249c5 --- /dev/null +++ b/tmp/update/.htaccess @@ -0,0 +1 @@ +Deny from all \ No newline at end of file diff --git a/tmp/update/sql.update.php b/tmp/update/sql.update.php new file mode 100644 index 0000000..994e514 --- /dev/null +++ b/tmp/update/sql.update.php @@ -0,0 +1,445 @@ +Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_rubrics + LIKE + 'rubric_changed' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_rubrics + ADD + `rubric_changed` int(10) NOT NULL DEFAULT '0' + AFTER + `rubric_position` + "); + + $AVE_DB->Real_Query(" + UPDATE + " . PREFIX . "_rubrics + SET + `rubric_changed` = UNIX_TIMESTAMP() + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_rubrics + LIKE + 'rubric_changed_fields' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_rubrics + ADD + `rubric_changed_fields` int(10) NOT NULL DEFAULT '0' + AFTER + `rubric_changed` + "); + + $AVE_DB->Real_Query(" + UPDATE + " . PREFIX . "_rubrics + SET + `rubric_changed_fields` = UNIX_TIMESTAMP() + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW TABLES + LIKE + '" . PREFIX . "_rubric_breadcrumb' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + CREATE TABLE `" . PREFIX . "_rubric_breadcrumb` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `rubric_id` smallint(3) unsigned NOT NULL, + `box` varchar(500) NOT NULL DEFAULT '', + `show_main` enum('1','0') NOT NULL DEFAULT '1', + `show_host` enum('1','0') NOT NULL DEFAULT '1', + `sepparator` varchar(255) NOT NULL, + `sepparator_use` enum('1','0') NOT NULL DEFAULT '1', + `link_box` varchar(500) NOT NULL DEFAULT '', + `link_template` varchar(500) NOT NULL DEFAULT '', + `self_box` varchar(500) NOT NULL DEFAULT '', + `link_box_last` enum('1','0') NOT NULL DEFAULT '1', + PRIMARY KEY (`id`), + KEY `rubric_id` (`rubric_id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0; + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_request + LIKE + 'request_changed' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_request + ADD + `request_changed` int(10) unsigned NOT NULL DEFAULT '0' + AFTER + `request_show_sql` + "); + + $AVE_DB->Real_Query(" + UPDATE + " . PREFIX . "_request + SET + `request_changed` = UNIX_TIMESTAMP() + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_request + LIKE + 'request_changed_elements' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_request + ADD + `request_changed_elements` int(10) unsigned NOT NULL DEFAULT '0' + AFTER + `request_changed` + "); + + $AVE_DB->Real_Query(" + UPDATE + " . PREFIX . "_request + SET + `request_changed_elements` = UNIX_TIMESTAMP() + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_documents + LIKE + 'document_short_alias' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_documents + ADD + `document_short_alias` VARCHAR(10) NOT NULL DEFAULT '' + AFTER + `document_alias_history` + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_document_tags + LIKE + 'rubric_id' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_document_tags + ADD + `rubric_id` int(3) NOT NULL + AFTER + `id` + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_modules_aliases + LIKE + 'document_id' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_modules_aliases + ADD + `document_id` int(10) NOT NULL DEFAULT '0' + AFTER + `id` + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_request + LIKE + 'request_count_items' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_request + ADD + `request_count_items` enum('0','1') NOT NULL DEFAULT '0' + AFTER + `request_use_query` + "); + + $AVE_DB->Real_Query(" + UPDATE + " . PREFIX . "_request + SET + `request_changed_elements` = UNIX_TIMESTAMP() + "); + } + + + /* -------------------------------------------------------------------------------------------------------------- */ + /* -------------------------------------------------------3.25---------------------------------------------------- */ + /* -------------------------------------------------------------------------------------------------------------- */ + + + $check = $AVE_DB->Query(" + SELECT COUNT(1) + FROM INFORMATION_SCHEMA.STATISTICS + WHERE + TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '" . PREFIX . "_document_fields' + AND INDEX_NAME = 'queries'; + ")->GetCell(); + + $exist = ($check > 0) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + CREATE INDEX queries ON " . PREFIX . "_document_fields(document_id, rubric_field_id) + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SELECT 1 + FROM INFORMATION_SCHEMA.COLUMNS + WHERE + TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '" . PREFIX . "_settings' + AND COLUMN_NAME = 'use_editor'; + ")->GetCell(); + + $exist = ($check) ? true : false; + + if ($exist === true) + { + $AVE_DB->Real_Query(" + ALTER TABLE " . PREFIX . "_settings + DROP use_editor; + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SELECT COUNT(1) + FROM INFORMATION_SCHEMA.TABLES + WHERE + TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = '" . PREFIX . "_rubric_template_cache'; + ")->GetCell(); + + $exist = ($check > 0) ? true : false; + + if ($exist === true) + { + $AVE_DB->Real_Query(" + DROP TABLE " . PREFIX . "_rubric_template_cache; + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_sysblocks + LIKE + 'sysblock_eval' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_sysblocks + ADD + `sysblock_eval` enum('0','1') NOT NULL DEFAULT '1' + AFTER + `sysblock_active` + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW TABLES + LIKE + '" . PREFIX . "_sysblocks_groups' + ")->NumRows(); + + $exist = ($check > 0) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + CREATE TABLE `" . PREFIX . "_sysblocks_groups` ( + `id` mediumint(5) unsigned NOT NULL AUTO_INCREMENT, + `position` smallint(3) unsigned NOT NULL, + `title` varchar(255) NOT NULL DEFAULT '', + `description` text NOT NULL, + PRIMARY KEY (`id`) + ) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0; + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_sysblocks + LIKE + 'sysblock_group_id' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_sysblocks + ADD + `sysblock_group_id` int(3) NOT NULL DEFAULT '0' + AFTER + `id` + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_documents + LIKE + 'document_position' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_documents + ADD + `document_position` int(10) NOT NULL DEFAULT '0' + AFTER + `document_property` + "); + } + + // ---------------------------------------------------------------------------------------- + + $check = $AVE_DB->Query(" + SHOW COLUMNS + FROM + " . PREFIX . "_document_alias_history + LIKE + 'document_alias_header' + ")->NumRows(); + + $exist = ($check) ? true : false; + + if ($exist === false) + { + $AVE_DB->Real_Query(" + ALTER TABLE + " . PREFIX . "_document_alias_history + ADD + `document_alias_header` int(3) NOT NULL DEFAULT '301' + AFTER + `document_alias` + "); + } +?> \ No newline at end of file diff --git a/uploads/.htaccess b/uploads/.htaccess new file mode 100644 index 0000000..49d3626 --- /dev/null +++ b/uploads/.htaccess @@ -0,0 +1,5 @@ +#Header set Cache-Control "max-age=7200, must-revalidate" + +RewriteEngine on +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule .(jpg|JPG|jpeg|JPEG|gif|GIF|png|PNG|bmp|BMP|webp|WEBP) /inc/thumb.php [QSA,L] \ No newline at end of file diff --git a/uploads/.quarantine/index.php b/uploads/.quarantine/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/.quarantine/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/.tmb/index.php b/uploads/.tmb/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/.tmb/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/avatars/index.php b/uploads/avatars/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/avatars/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/avatars/new/index.php b/uploads/avatars/new/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/avatars/new/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/gallery/.temp/index.php b/uploads/gallery/.temp/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/gallery/.temp/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/gallery/.uploader/index.php b/uploads/gallery/.uploader/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/gallery/.uploader/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/gallery/index.php b/uploads/gallery/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/gallery/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/gallery/watermark.gif b/uploads/gallery/watermark.gif new file mode 100644 index 0000000..0d5a959 Binary files /dev/null and b/uploads/gallery/watermark.gif differ diff --git a/uploads/images/index.php b/uploads/images/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/images/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/images/noimage.png b/uploads/images/noimage.png new file mode 100644 index 0000000..79eb521 Binary files /dev/null and b/uploads/images/noimage.png differ diff --git a/uploads/index.php b/uploads/index.php new file mode 100644 index 0000000..046ab72 --- /dev/null +++ b/uploads/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/uploads/recycled/.htaccess b/uploads/recycled/.htaccess new file mode 100644 index 0000000..3418e55 --- /dev/null +++ b/uploads/recycled/.htaccess @@ -0,0 +1 @@ +deny from all \ No newline at end of file diff --git a/uploads/recycled/index.php b/uploads/recycled/index.php new file mode 100644 index 0000000..9c20174 --- /dev/null +++ b/uploads/recycled/index.php @@ -0,0 +1,8 @@ + \ No newline at end of file