diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd98ea028..47666763d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,7 @@ - 2가지 이상 서로 다른 문제가 있는 경우, 각각 이슈를 등록해 주십시오. - 보안 취약점은 공개적으로 언급하지 말고 devops@rhymix.org로 알려 주시면 감사하겠습니다. - **버그 신고 전 자신의 서버가 Rhymix의 실행 환경을 충족하는지 확인해 주십시오.** - - PHP 5.3 미만, EUC-KR 환경, 퍼미션 오류 등은 호스팅 업체에 문의하셔야 합니다. + - PHP 5.5 미만, EUC-KR 환경, 퍼미션 오류 등은 호스팅 업체에 문의하셔야 합니다. - 자신의 서버 환경은 `phpinfo`를 사용하여 확인할 수 있습니다. - **버그 신고에는 아래의 내용을 반드시 포함시켜 주십시오.** - 실행 환경 @@ -30,10 +30,13 @@ 작성 후에 수정할 것이 있으면 이 브랜치에서 계속 작업하고 커밋하시면 됩니다. PR 페이지에 자동으로 반영됩니다. - 개발 진행 및 안정화에 따라 브랜치별 운영 정책이 변경될 수 있으니 유의하십시오. - 아래의 코딩 규칙을 지키려고 노력해 주시기 바랍니다. -- 코딩 규칙에 맞지 않는 소스를 발견하더라도 PR의 주제외 관계없는 부분은 함부로 고치지 마세요! - 코딩 규칙에 맞도록 소스를 수정하는 작업은 모두 별도의 PR로 처리하여야 합니다. -- 단, PR을 검토하는 개발자들은 괄호의 위치와 같은 사소한 문제를 지적하느라고 - 실제 기능에 관심을 주지 못하는 오류를 범하지 않도록 노력해야 합니다. +- **코딩 규칙에 맞지 않는 소스를 발견하더라도 PR의 주제와 관계없는 부분은 함부로 고치지 마세요! + 코딩 규칙에 맞도록 소스를 수정하는 작업은 모두 별도의 PR로 처리하여야 합니다.** +- **단, PR을 검토하는 개발자들은 괄호의 위치와 같은 사소한 문제를 지적하느라고 + 실제 기능에 관심을 주지 못하는 오류를 범하지 않도록 노력해야 합니다.** +- PR의 제목은 커밋 메시지에 적용되는 규칙을 참고하되, 가능하면 한글로 작성해 주십시오. +- 유닛 테스트를 통과하지 못하거나, 통과하기 위해 테스트를 삭제할 경우 PR이 거부될 수 있습니다. + 단, 테스트 자체에 문제가 있거나 테스트 내용을 변경해야 한다고 생각되는 경우 개발팀과 의논해 주십시오. ## 저작권 및 라이선스 @@ -73,10 +76,23 @@ PHP 코드만으로 이루어진 파일은 맨 끝에 `?>` 태그를 사용하 } } -단, 클로져는 같은 줄에 중괄호를 쓸 수 있으며, 이 경우 중괄호 앞뒤에 한 칸씩 공백을 둡니다. +조건문이나 순환문 내에 하나의 명령만 있는 경우에도 반드시 중괄호를 사용합니다. +그래야 나중에 명령이 추가될 경우 수정하기 편리합니다. + + if (!$foo) return false; // WRONG + if (!$bar) // RIGHT + { + return true; + } + +단, 클로져는 같은 줄에 중괄호를 쓸 수 있으며, +이 경우 중괄호 앞뒤에 한 칸씩 공백을 두어 클로져가 시작되고 끝나는 지점을 찾기 쉽도록 합니다. 닫는 중괄호와 그 뒤의 기호 사이에는 공백을 두지 않습니다. $foo = function($bar) { return $bar + 1; }; // RIGHT + $foo = function($bar) { // RIGHT + return $bar + 1; + }; $foo = function($bar){return $bar + 1;}; // WRONG 자바스크립트에서는 거의 모든 함수가 클로져이며, 잘못 줄바꿈할 경우 세미콜론이 삽입될 수 있으므로 @@ -101,6 +117,24 @@ PHP 코드만으로 이루어진 파일은 맨 끝에 `?>` 태그를 사용하 if($foo === $bar) // OK for XE Compatibility if($foo==$bar){ // WRONG +여러 줄에 걸쳐 배열을 선언할 경우, 마지막 구성요소 뒤에 쉼표를 남깁니다. +그래야 나중에 구성요소를 추가할 때 편리합니다. + + $animals = array( + 'bear', + 'cat', + 'dog', // COMMA + ); + +단, 자바스크립트 및 JSON에서는 마지막 쉼표를 반드시 삭제해야 합니다. +쉼표를 남겨둘 경우 일부 브라우저에서 오류가 발생할 수 있기 때문입니다. + + var animals = [ + 'bear', + 'cat', + 'dog' // NO COMMA + ]; + ### 주석 주석은 관련 코드 윗줄에 써야 합니다. 조건문이나 루프의 경우에도 마찬가지입니다. @@ -150,9 +184,27 @@ PHPDoc 주석 작성에 어려움이 있는 경우, 다른 클래스와 함수 불가피한 경우를 제외하면 주석은 영문으로 쓰는 것을 원칙으로 하며, 대문자로 시작하는 완전한 문장으로 이루어져야 합니다. +### 커밋 메시지 + +커밋 메시지는 가능하면 영문으로 작성하며, **현재형** 동사로 시작하는 **명령형** 문장 사용을 원칙으로 합니다. + + Delete unnecessary condition // RIGHT + Fix #1234 // RIGHT + Deletes unnecessary condition // WRONG (불필요한 동사변화) + Fixed #1234 // WRONG (불필요한 과거형) + +이 규칙에 맞추어 영문으로 커밋 메시지를 작성하기 어려운 경우, 한글로 작성해도 무방합니다. +한글 커밋 메시지는 **어디서** **무엇을** **어떻게** 했는지 간결하고 명확하고 격식있게 표현하며, +가능하면 현재형 동사로 마치도록 합니다. + + 크롬 최신 버전에서 스크립트 오류 해결 // RIGHT + Foo 클래스에 bar() 메소드 추가 // RIGHT + 파일첨부 에러나는거 고쳤쩌염~^^ // WRONG (격식없는 표현) + 함수 개선 // WRONG (두리뭉실한 표현) + ### 기타 -Rhymix에서 정한 `error_reporting` 설정 하에서 어떤 에러도 발생하지 않도록 하는 것을 목표로 합니다. +Rhymix의 기본 `error_reporting` 설정 하에서 어떤 에러도 발생하지 않도록 하는 것을 목표로 합니다. 문자열과 문자열, 정수와 정수를 비교할 때는 가능하면 `==` 대신 `===`을 사용합니다. 실제 자료형이 다를 가능성이 있는 경우 `intval()`, `strval()` 등의 함수와 함께 사용합니다. @@ -160,5 +212,8 @@ Rhymix에서 정한 `error_reporting` 설정 하에서 어떤 에러도 발생 PHP 5.4 이상에서 지원하는 간단한 배열 문법(`[1, 2, 3]`)을 사용할 수 있으나, 복잡한 구조의 배열을 선언할 때는 이 문법이 오히려 가독성을 해칠 수 있으니 주의하시기 바랍니다. +전역 상수를 참조할 때는 `\RX_CLIENT_IP`와 같이 `\`를 앞에 붙여서, +추후 다른 네임스페이스로 코드를 이동 또는 복사하더라도 문제가 생기지 않도록 합니다. + 여기에서 규정하지 않은 내용은 [PSR-1](http://www.php-fig.org/psr/psr-1/)과 [PSR-2](http://www.php-fig.org/psr/psr-2/)를 따릅니다. diff --git a/addons/autolink/autolink.js b/addons/autolink/autolink.js index 8b9973c82..3d2e49f40 100644 --- a/addons/autolink/autolink.js +++ b/addons/autolink/autolink.js @@ -5,13 +5,13 @@ */ (function($){ var protocol_re = '(https?|ftp|news|telnet|irc|mms)://'; - var domain_re = '(?:[\\w\\-]+\\.)+(?:[a-z]+)'; + var domain_re = '(?:[^./]+\\.)+[^./]+'; var max_255_re = '(?:1[0-9]{2}|2[0-4][0-9]|25[0-5]|[1-9]?[0-9])'; var ip_re = '(?:'+max_255_re+'\\.){3}'+max_255_re; var port_re = '(?::([0-9]+))?'; - var user_re = '(?:/~[\\w-]+)?'; - var path_re = '((?:/[\\w!"$-/:-@]+)*)'; - var hash_re = '(?:#([\\w!-@]+))?'; + var user_re = '(?:/~\\w+)?'; + var path_re = '(?:/[\\w!@$%&!?="/.,:;-]+)*'; + var hash_re = '(?:#[\\w!@$%&!?="/.,:;-]*)?'; var url_regex = new RegExp('('+protocol_re+'('+domain_re+'|'+ip_re+'|localhost'+')'+port_re+user_re+path_re+hash_re+')', 'ig'); @@ -36,7 +36,7 @@ var content = textNode.nodeValue; var dummy = $(''); - content = content.replace(//g, '>'); + //content = content.replace(//g, '>'); content = content.replace(url_regex, '$1'); $(textNode).before(dummy); @@ -52,9 +52,7 @@ return; } - $(obj) - .contents() - .each(function(){ + $(obj).contents().each(function(){ var node_name = this.nodeName.toLowerCase(); if($.inArray(node_name, ['a', 'pre', 'xml', 'textarea', 'input', 'select', 'option', 'code', 'script', 'style', 'iframe', 'button', 'img', 'embed', 'object', 'ins']) != -1) return; @@ -77,4 +75,4 @@ }); xe.registerPlugin(new AutoLink()); -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/addons/photoswipe/PhotoSwipe/LICENSE b/addons/photoswipe/PhotoSwipe/LICENSE new file mode 100644 index 000000000..3391c00e1 --- /dev/null +++ b/addons/photoswipe/PhotoSwipe/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2015 Dmitry Semenov, http://dimsemenov.com + +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. \ No newline at end of file diff --git a/addons/photoswipe/PhotoSwipe/default-skin/default-skin.css b/addons/photoswipe/PhotoSwipe/default-skin/default-skin.css new file mode 100644 index 000000000..f99db1be6 --- /dev/null +++ b/addons/photoswipe/PhotoSwipe/default-skin/default-skin.css @@ -0,0 +1,483 @@ +/*! PhotoSwipe Default UI CSS by Dmitry Semenov | photoswipe.com | MIT license */ +/* + + Contents: + + 1. Buttons + 2. Share modal and links + 3. Index indicator ("1 of X" counter) + 4. Caption + 5. Loading indicator + 6. Additional styles (root element, top bar, idle state, hidden state, etc.) + +*/ +/* + + 1. Buttons + + */ +/* + + + + + + + + + +
+
+
+
+
+
+
+ + +
+ +
+ + + + + +
+
+
+ + + + + + \ No newline at end of file diff --git a/addons/photoswipe/conf/info.xml b/addons/photoswipe/conf/info.xml new file mode 100644 index 000000000..c48bf732f --- /dev/null +++ b/addons/photoswipe/conf/info.xml @@ -0,0 +1,23 @@ + + + 넘겨보는 사진 + PhotoSwipe + + 본문 이미지를 하나의 갤러리 처럼 볼 수 있도록 하는 애드온입니다. + + + Swipe your images of an document on your screens. + + MIT License (codes from http://photoswipe.com/), GPLv2 (other codes by Rhymix contributors) + 1.0.1 + 2016-04-27 + + + misol + misol + + + Rhymix contributors + Rhymix contributors + + \ No newline at end of file diff --git a/addons/photoswipe/photoswipe.addon.php b/addons/photoswipe/photoswipe.addon.php new file mode 100644 index 000000000..4a1afbf86 --- /dev/null +++ b/addons/photoswipe/photoswipe.addon.php @@ -0,0 +1,28 @@ + + * @brief Add-on to highlight an activated image. + */ +if($called_position == 'after_module_proc' && Context::getResponseMethod() == "HTML" && Context::get('module') != 'admin' && !isCrawler()) +{ + Context::loadFile(array('./addons/photoswipe/PhotoSwipe/photoswipe.css', '', '', null), true); + Context::loadFile(array('./addons/photoswipe/PhotoSwipe/default-skin/default-skin.css', '', '', null), true); + + Context::loadFile(array('./addons/photoswipe/PhotoSwipe/photoswipe.js', 'body', '', null), true); + Context::loadFile(array('./addons/photoswipe/PhotoSwipe/photoswipe-ui-default.js', 'body', '', null), true); + Context::loadFile(array('./addons/photoswipe/rx_photoswipe.js', 'body', '', null), true); + + $footer = FileHandler::readFile('./addons/photoswipe/PhotoSwipe/pswp.html'); + Context::addHtmlFooter($footer); +} + +/* End of file photoswipe.addon.php */ +/* Location: ./addons/photoswipe/photoswipe.addon.php */ diff --git a/addons/photoswipe/rx_photoswipe.js b/addons/photoswipe/rx_photoswipe.js new file mode 100644 index 000000000..4dbf8bf7c --- /dev/null +++ b/addons/photoswipe/rx_photoswipe.js @@ -0,0 +1,245 @@ +/* Modified version of a http://photoswipe.com/documentation/getting-started.html example. Modified by misol for rhymix */ +var getPSImageSize = function(src) { + var testImg = new Image(); + testImg.src = src; + + var size = new Array(); + size[0] = testImg.width; + size[1] = testImg.height; + + return size; +} + +var initPhotoSwipeFromDOM = function(gallerySelector) { + + // parse slide data (url, title, size ...) from DOM elements + // (children of gallerySelector) + var parseThumbnailElements = function(el) { + var imgElements = $(el).find("img"), + numNodes = imgElements.length, + items = [], + imgEl, + size, + item; + + for(var i = 0; i < numNodes; i++) { + + imgEl = imgElements.get(i); // element + + // include only element nodes + if(imgEl.nodeType !== 1 || !$(imgEl).attr('data-pswp-pid')) { + continue; + } + + size = getPSImageSize($(imgEl).attr('src')); + + // create slide object + item = { + src: $(imgEl).attr('src'), + w: parseInt( size[0] , 10), + h: parseInt( size[1] , 10), + pid: $(imgEl).attr('data-pswp-pid') + }; + + if(imgEl.alt) { + item.title = imgEl.alt; + } + + if(imgEl.title) { + item.title = imgEl.title; + } + + item.el = imgEl; // save link to element for getThumbBoundsFn + items.push(item); + } + + return items; + }; + + // find nearest parent element + var closest = function closest(el, fn) { + return el && ( fn(el) ? el : closest(el.parentNode, fn) ); + }; + + // triggers when user clicks on thumbnail + var onThumbnailsClick = function(e) { + var eTarget = e.target || e.srcElement; + + // find root element of slide + var clickedListItem = closest(eTarget, function(el) { + return (el.tagName && el.tagName.toUpperCase() === 'IMG'); + }); + + if(!clickedListItem) { + return; + } + + e = e || window.event; + e.preventDefault ? e.preventDefault() : e.returnValue = false; + + // find index of clicked item by looping through all child nodes + // alternatively, you may define index via data- attribute + var clickedGallery = $(clickedListItem).closest(gallerySelector).get(0), + childNodes = $(clickedGallery).find('img'), + numChildNodes = childNodes.length, + nodeIndex = 0, + index; + + /*for (var i = 0; i < numChildNodes; i++) { + if($(childNodes[i]).attr('data-pswp-pid') === $(clickedListItem).attr('data-pswp-pid')) { + index = nodeIndex; + break; + } + nodeIndex++; + }*/ + + for (var i = 0; i < numChildNodes; i++) { + if(childNodes[i].nodeType !== 1 || !$(childNodes[i]).attr('data-pswp-pid')) { + continue; + } + + if(childNodes[i] === clickedListItem) { + index = nodeIndex; + break; + } + nodeIndex++; + } + + if(index >= 0) { + // open PhotoSwipe if valid index found + openPhotoSwipe( index, clickedGallery, false, false); + } + return false; + }; + + // parse picture index and gallery index from URL (#&pid=1&gid=2) + var photoswipeParseHash = function() { + var hash = window.location.hash.substring(1), + params = {}; + + if(hash.length < 5) { + return params; + } + + var vars = hash.split('&'); + for (var i = 0; i < vars.length; i++) { + if(!vars[i]) { + continue; + } + var pair = vars[i].split('='); + if(pair.length < 2) { + continue; + } + params[pair[0]] = pair[1]; + } + + if(params.gid) { + params.gid = parseInt(params.gid, 10); + } + + return params; + }; + + var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) { + var pswpElement = document.querySelectorAll('.pswp')[0], + gallery, + options, + items; + + items = parseThumbnailElements(galleryElement); + + // define options (if needed) + options = { + + // define gallery index (for URL) + galleryUID: galleryElement.getAttribute('data-pswp-uid'), + + getThumbBoundsFn: function(index) { + // See Options -> getThumbBoundsFn section of documentation for more info + var thumbnail = items[index].el, + pageYScroll = window.pageYOffset || document.documentElement.scrollTop, + rect = thumbnail.getBoundingClientRect(); + + return {x:rect.left, y:rect.top + pageYScroll, w:rect.width}; + }, + + addCaptionHTMLFn: function(item, captionEl, isFake) { + if(!item.title) { + captionEl.children[0].innerText = ''; + return false; + } + captionEl.children[0].innerHTML = item.title; + return true; + }, + + }; + + // PhotoSwipe opened from URL + if(fromURL) { + if(options.galleryPIDs) { + // parse real index when custom PIDs are used + // http://photoswipe.com/documentation/faq.html#custom-pid-in-url + for(var j = 0; j < items.length; j++) { + if(items[j].pid == index) { + options.index = j; + break; + } + } + } else { + // in URL indexes start from 1 + options.index = parseInt(index, 10) - 1; + } + } else { + options.index = parseInt(index, 10); + } + + // exit if index not found + if( isNaN(options.index) ) { + return; + } + + if(disableAnimation) { + options.showAnimationDuration = 0; + } + + // Pass data to PhotoSwipe and initialize it + gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options); + gallery.init(); + }; + + // loop through all gallery elements and bind events + var galleryElements = document.querySelectorAll( gallerySelector ); + + for(var i = 0, l = galleryElements.length; i < l; i++) { + galleryElements[i].setAttribute('data-pswp-uid', i+1); + galleryElements[i].onclick = onThumbnailsClick; + + // do not activate PhotoSwipe at the editor-component or other module components + var regx_skip = /(?:(modules|addons|classes|common|layouts|libs|widgets|widgetstyles)\/)/i; + var regx_allow_i6pngfix = /(?:common\/tpl\/images\/blank\.gif$)/i; + var galleryImgEls = $(galleryElements[i]).find('img'); + for(var j = 0, jl = galleryImgEls.length; j < jl; j++) { + if(regx_skip.test($(galleryImgEls[j]).attr('src')) && !regx_allow_i6pngfix.test($(galleryImgEls[j]).attr('src'))) continue; + + //$(galleryImgEls[j]).attr('data-pswp-uid', i+1); + $(galleryImgEls[j]).attr('data-pswp-pid', j+1); + + } + } + + // Parse URL and open gallery if it contains #&pid=3&gid=1 + var hashData = photoswipeParseHash(); + if(hashData.pid && hashData.gid) { + openPhotoSwipe( hashData.pid , galleryElements[ hashData.gid - 1 ], true, true ); + } + window.addEventListener("hashchange", function() { + var hashData = photoswipeParseHash(); + if(hashData.pid && hashData.gid) { + openPhotoSwipe( hashData.pid , galleryElements[ hashData.gid - 1 ], true, true ); + } + }, false); +}; + + +// execute above function +initPhotoSwipeFromDOM('.xe_content'); \ No newline at end of file diff --git a/classes/display/HTMLDisplayHandler.php b/classes/display/HTMLDisplayHandler.php index cf2556c27..b106ef3cf 100644 --- a/classes/display/HTMLDisplayHandler.php +++ b/classes/display/HTMLDisplayHandler.php @@ -6,7 +6,7 @@ class HTMLDisplayHandler /** * Reserved scripts */ - public static $reservedCSS = '@\bcommon/css/(?:xe|mobile)\.(?:min\.)?css$@'; + public static $reservedCSS = '@\bcommon/css/(?:xe|rhymix|mobile)\.(?:min\.)?(?:s?css|less)$@'; public static $reservedJS = '@\bcommon/js/(?:jquery(?:-[123][0-9.x-]+)?|xe?|common|js_app|xml_handler|xml_js_filter)\.(?:min\.)?js$@'; /** @@ -416,7 +416,7 @@ class HTMLDisplayHandler */ private function _loadCommonJSCSS() { - Context::loadFile(array('./common/css/xe.css', '', '', -1600000), true); + Context::loadFile(array('./common/css/rhymix.scss', '', '', -1600000), true); $original_file_list = array('x', 'common', 'js_app', 'xml_handler', 'xml_js_filter'); $jquery_version = preg_match('/MSIE [5-8]\./', $_SERVER['HTTP_USER_AGENT']) ? '1.11.3' : '2.1.4'; @@ -433,14 +433,14 @@ class HTMLDisplayHandler { Context::loadFile(array('./common/js/jquery-' . $jquery_version . '.min.js', 'head', '', -1730000), true); Context::loadFile(array('./common/js/plugins/jquery.migrate/jquery-migrate-1.2.1.min.js', 'head', '', -1720000), true); - $concat_target_filename = 'files/cache/minify/xe.min.js'; - if(file_exists(_XE_PATH_ . $concat_target_filename)) + $concat_target_filename = 'files/cache/assets/minified/rhymix.min.js'; + if(file_exists(\RX_BASEDIR . $concat_target_filename)) { - $concat_target_mtime = filemtime(_XE_PATH_ . $concat_target_filename); + $concat_target_mtime = filemtime(\RX_BASEDIR . $concat_target_filename); $original_mtime = 0; foreach($original_file_list as $filename) { - $original_mtime = max($original_mtime, filemtime(_XE_PATH_ . 'common/js/' . $filename . '.js')); + $original_mtime = max($original_mtime, filemtime(\RX_BASEDIR . 'common/js/' . $filename . '.js')); } if($concat_target_mtime > $original_mtime) { @@ -448,12 +448,9 @@ class HTMLDisplayHandler return; } } - $minifier = new MatthiasMullie\Minify\JS(); - foreach($original_file_list as $filename) - { - $minifier->add(_XE_PATH_ . 'common/js/' . $filename . '.js'); - } - FileHandler::writeFile(_XE_PATH_ . $concat_target_filename, $minifier->execute()); + Rhymix\Framework\Formatter::minifyJS(array_map(function($str) { + return \RX_BASEDIR . 'common/js/' . $str . '.js'; + }, $original_file_list), \RX_BASEDIR . $concat_target_filename); Context::loadFile(array('./' . $concat_target_filename, 'head', '', -100000), true); } } diff --git a/classes/file/FileHandler.class.php b/classes/file/FileHandler.class.php index 20b6ead6e..e0f61a435 100644 --- a/classes/file/FileHandler.class.php +++ b/classes/file/FileHandler.class.php @@ -16,7 +16,18 @@ class FileHandler */ public static function getRealPath($source) { - return (strncmp($source, './', 2) === 0) ? (\RX_BASEDIR . substr($source, 2)) : $source; + if (strncmp($source, './', 2) === 0) + { + return \RX_BASEDIR . substr($source, 2); + } + elseif (strncmp($source, '/', 1) === 0) + { + return $source; + } + else + { + return \RX_BASEDIR . $source; + } } /** diff --git a/classes/frontendfile/FrontEndFileHandler.class.php b/classes/frontendfile/FrontEndFileHandler.class.php index 38758d4ef..e2c69ac95 100644 --- a/classes/frontendfile/FrontEndFileHandler.class.php +++ b/classes/frontendfile/FrontEndFileHandler.class.php @@ -7,45 +7,52 @@ * */ class FrontEndFileHandler extends Handler { - - public static $isSSL = null; + /** + * Minification and concatenation configuration. + */ public static $minify = null; + public static $concat = null; + + /** + * Directory for minified, compiled, and concatenated CSS/JS assets. + */ + public static $assetdir = 'files/cache/assets'; /** * Map for css * @var array */ - var $cssMap = array(); + public $cssMap = array(); /** * Map for Javascript at head * @var array */ - var $jsHeadMap = array(); + public $jsHeadMap = array(); /** * Map for Javascript at body * @var array */ - var $jsBodyMap = array(); + public $jsBodyMap = array(); /** * Index for css * @var array */ - var $cssMapIndex = array(); + public $cssMapIndex = array(); /** * Index for javascript at head * @var array */ - var $jsHeadMapIndex = array(); + public $jsHeadMapIndex = array(); /** * Index for javascript at body * @var array */ - var $jsBodyMapIndex = array(); + public $jsBodyMapIndex = array(); /** * Check SSL @@ -53,17 +60,9 @@ class FrontEndFileHandler extends Handler * @return bool If using ssl returns true, otherwise returns false. * @deprecated */ - function isSsl() + public function isSsl() { - if(!is_null(self::$isSSL)) - { - return self::$isSSL; - } - - $url_info = parse_url(Context::getRequestUrl()); - self::$isSSL = ($url_info['scheme'] == 'https'); - - return self::$isSSL; + return \RX_SSL; } /** @@ -82,12 +81,13 @@ class FrontEndFileHandler extends Handler * $args[1]: media * $args[2]: target IE * $args[3]: index + * $args[4]: vars for LESS and SCSS * * * @param array $args Arguments * @return void * */ - function loadFile($args) + public function loadFile($args) { if(!is_array($args)) { @@ -99,21 +99,21 @@ class FrontEndFileHandler extends Handler { return; } - $file = $this->getFileInfo($args[0], $args[2], $args[1], $isCommon); + $file = $this->getFileInfo($args[0], $args[2], $args[1], $args[4], $isCommon); $file->index = (int)$args[3]; - $availableExtension = array('css' => 1, 'js' => 1); + $availableExtension = array('css' => 1, 'js' => 1, 'less' => 1, 'scss' => 1); if(!isset($availableExtension[$file->fileExtension])) { return; } - if($file->fileExtension == 'css') + if($file->fileExtension == 'css' || $file->fileExtension == 'less' || $file->fileExtension == 'scss') { $map = &$this->cssMap; $mapIndex = &$this->cssMapIndex; - $this->_arrangeCssIndex($pathInfo['dirname'], $file); + $this->_arrangeCssIndex($file->fileRealPath, $file); } else if($file->fileExtension == 'js') { @@ -131,7 +131,7 @@ class FrontEndFileHandler extends Handler if(!isset($mapIndex[$file->key]) || $mapIndex[$file->key] > $file->index) { - $this->unloadFile($args[0], $args[2], $args[1]); + //$this->unloadFile($args[0], $args[2], $args[1]); $map[$file->index][$file->key] = $file; $mapIndex[$file->key] = $file->index; } @@ -143,18 +143,13 @@ class FrontEndFileHandler extends Handler * @param string $fileName The file name * @param string $targetIe Target IE of file * @param string $media Media of file + * @param array $vars Variables for LESS and SCSS * @param bool $forceMinify Whether this file should be minified * @return stdClass The file information */ - private function getFileInfo($fileName, $targetIe = '', $media = 'all', $forceMinify = false) + protected function getFileInfo($fileName, $targetIe = '', $media = 'all', $vars = array(), $isCommon = false) { static $existsInfo = array(); - - if(self::$minify === null) - { - self::$minify = config('view.minify_scripts') ?: 'common'; - } - if(isset($existsInfo[$existsKey])) { return $existsInfo[$existsKey]; @@ -165,8 +160,9 @@ class FrontEndFileHandler extends Handler $file->fileName = $pathInfo['basename']; $file->filePath = $this->_getAbsFileUrl($pathInfo['dirname']); $file->fileRealPath = FileHandler::getRealPath($pathInfo['dirname']); + $file->fileFullPath = $file->fileRealPath . '/' . $pathInfo['basename']; $file->fileExtension = strtolower($pathInfo['extension']); - if(preg_match('/^(.+)\.min$/', $pathInfo['filename'], $matches)) + if (preg_match('/^(.+)\.min$/', $pathInfo['filename'], $matches)) { $file->fileNameNoExt = $matches[1]; $file->isMinified = true; @@ -178,72 +174,32 @@ class FrontEndFileHandler extends Handler } $file->isExternalURL = preg_match('@^(https?:)?//@i', $file->filePath) ? true : false; $file->isCachedScript = !$file->isExternalURL && strpos($file->filePath, 'files/cache/') !== false; + $file->isCommon = $isCommon; $file->keyName = $file->fileNameNoExt . '.' . $file->fileExtension; $file->cdnPath = $this->_normalizeFilePath($pathInfo['dirname']); - $originalFilePath = $file->fileRealPath . '/' . $pathInfo['basename']; + $file->vars = (array)$vars; // Fix incorrectly minified URL - if($file->isMinified && !$file->isExternalURL && (!file_exists($originalFilePath) || is_link($originalFilePath) || - (filesize($originalFilePath) < 32 && trim(file_get_contents($originalFilePath)) === $file->keyName))) + if($file->isMinified && !$file->isExternalURL && (!file_exists($file->fileFullPath) || is_link($file->fileFullPath) || + (filesize($file->fileFullPath) < 32 && trim(file_get_contents($file->fileFullPath)) === $file->keyName))) { if(file_exists($file->fileRealPath . '/' . $file->fileNameNoExt . '.' . $file->fileExtension)) { $file->fileName = $file->fileNameNoExt . '.' . $file->fileExtension; $file->isMinified = false; - $originalFilePath = $file->fileRealPath . '/' . $file->fileNameNoExt . '.' . $file->fileExtension; + $file->fileFullPath = $file->fileRealPath . '/' . $file->fileNameNoExt . '.' . $file->fileExtension; } } - - // Decide whether to minify this file - if(self::$minify === 'all') - { - $minify_enabled = true; - } - elseif(self::$minify === 'none') - { - $minify_enabled = false; - } - else - { - $minify_enabled = $forceMinify; - } - // Minify file - if($minify_enabled && !$file->isMinified && !$file->isExternalURL && !$file->isCachedScript && strpos($file->filePath, 'common/js/plugins') === false) + // Do not minify common JS plugins + if (strpos($file->filePath, 'common/js/plugins') !== false) { - if(($file->fileExtension === 'css' || $file->fileExtension === 'js') && file_exists($originalFilePath)) - { - $minifiedFileName = $file->fileNameNoExt . '.min.' . $file->fileExtension; - $minifiedFileHash = ltrim(str_replace(array('/', '\\'), '.', $pathInfo['dirname']), '.'); - $minifiedFilePath = _XE_PATH_ . 'files/cache/minify/' . $minifiedFileHash . '.' . $minifiedFileName; - - if(!file_exists($minifiedFilePath) || filemtime($minifiedFilePath) < filemtime($originalFilePath)) - { - if($file->fileExtension === 'css') - { - $minifier = new MatthiasMullie\Minify\CSS($originalFilePath); - $content = $minifier->execute($minifiedFilePath); - } - else - { - $minifier = new MatthiasMullie\Minify\JS($originalFilePath); - $content = $minifier->execute($minifiedFilePath); - } - FileHandler::writeFile($minifiedFilePath, $content); - } - - $file->fileName = $minifiedFileHash . '.' . $minifiedFileName; - $file->filePath = $this->_getAbsFileUrl('./files/cache/minify'); - $file->fileRealPath = _XE_PATH_ . 'files/cache/minify'; - $file->keyName = $minifiedFileHash . '.' . $file->fileNameNoExt . '.' . $file->fileExtension; - $file->cdnPath = $this->_normalizeFilePath('./files/cache/minify'); - $file->isMinified = true; - } + $file->isMinified = true; } - + // Process targetIe and media attributes $file->targetIe = $targetIe; - if($file->fileExtension == 'css') + if($file->fileExtension == 'css' || $file->fileExtension == 'less' || $file->fileExtension == 'scss') { $file->media = $media; if(!$file->media) @@ -259,6 +215,88 @@ class FrontEndFileHandler extends Handler return $file; } + + /** + * Process CSS and JS file + * + * @param object $file + * @param bool $minify + * @return void + */ + protected function proc_CSS_JS($file, $minify) + { + if (!$minify || !file_exists($file->fileFullPath)) + { + return; + } + + $minifiedFileName = $file->fileNameNoExt . '.min.' . $file->fileExtension; + $minifiedFileHash = ltrim(str_replace(array('/', '\\'), '.', substr($file->fileRealPath, strlen(\RX_BASEDIR))), '.'); + $minifiedFilePath = \RX_BASEDIR . self::$assetdir . '/minified/' . $minifiedFileHash . '.' . $minifiedFileName; + + if (!file_exists($minifiedFilePath) || filemtime($minifiedFilePath) < filemtime($file->fileFullPath)) + { + $method_name = 'minify' . $file->fileExtension; + $success = Rhymix\Framework\Formatter::$method_name($file->fileFullPath, $minifiedFilePath); + if ($success === false) + { + return; + } + } + + $file->fileName = $minifiedFileHash . '.' . $minifiedFileName; + $file->filePath = \RX_BASEURL . self::$assetdir . '/minified'; + $file->fileRealPath = \RX_BASEDIR . self::$assetdir . '/minified'; + $file->fileFullPath = $minifiedFilePath; + $file->keyName = $minifiedFileHash . '.' . $file->fileNameNoExt . '.' . $file->fileExtension; + $file->cdnPath = './' . self::$assetdir . '/minified'; + $file->isMinified = true; + } + + /** + * Process LESS and SCSS file + * + * @param object $file + * @param bool $minify + * @return void + */ + protected function proc_LESS_SCSS($file, $minify) + { + if (!file_exists($file->fileFullPath)) + { + return; + } + + if ($default_font_config = Context::get('default_font_config')) + { + $file->vars = array_merge($file->vars, $default_font_config); + } + if ($file->fileExtension === 'less') + { + $file->vars = array_map(function($str) { + return preg_match('/^[0-9a-zA-Z\.%_-]+$/', $str) ? $str : ('~"' . str_replace('"', '\\"', $str) . '"'); + }, $file->vars); + } + + $compiledFileName = $file->fileName . ($minify ? '.min' : '') . '.css'; + $compiledFileHash = sha1($file->fileRealPath . ':' . serialize($file->vars)); + $compiledFilePath = \RX_BASEDIR . self::$assetdir . '/compiled/' . $compiledFileHash . '.' . $compiledFileName; + + if (!file_exists($compiledFilePath) || filemtime($compiledFilePath) < filemtime($file->fileFullPath)) + { + $method_name = 'compile' . $file->fileExtension; + $success = Rhymix\Framework\Formatter::$method_name($file->fileFullPath, $compiledFilePath, $file->vars, $minify); + } + + $file->fileName = $compiledFileHash . '.' . $compiledFileName; + $file->filePath = \RX_BASEURL . self::$assetdir . '/compiled'; + $file->fileRealPath = \RX_BASEDIR . self::$assetdir . '/compiled'; + $file->fileFullPath = $compiledFilePath; + $file->keyName = $compiledFileHash . '.' . $file->fileNameNoExt . '.' . $file->fileExtension; + $file->cdnPath = './' . self::$assetdir . '/compiled'; + $file->isMinified = true; + $file->fileExtension = 'css'; + } /** * Unload front end file @@ -268,7 +306,7 @@ class FrontEndFileHandler extends Handler * @param string $media Media of file to unload. Only use when file is css. * @return void */ - function unloadFile($fileName, $targetIe = '', $media = 'all') + public function unloadFile($fileName, $targetIe = '', $media = 'all') { $file = $this->getFileInfo($fileName, $targetIe, $media); @@ -301,7 +339,7 @@ class FrontEndFileHandler extends Handler * @param string $type Type to unload. all, css, js * @return void */ - function unloadAllFiles($type = 'all') + public function unloadAllFiles($type = 'all') { if($type == 'css' || $type == 'all') { @@ -323,25 +361,81 @@ class FrontEndFileHandler extends Handler * * @return array Returns css file list. Array contains file, media, targetie. */ - function getCssFileList() + public function getCssFileList() { $map = &$this->cssMap; $mapIndex = &$this->cssMapIndex; - + $minify = self::$minify !== null ? self::$minify : (config('view.minify_scripts') ?: 'common'); + $concat = strpos(self::$concat !== null ? self::$concat : config('view.concat_scripts'), 'css') !== false; $this->_sortMap($map, $mapIndex); - - $result = array(); - foreach($map as $indexedMap) + + // Minify all scripts, and compile LESS/SCSS into CSS. + foreach ($map as $indexedMap) { - foreach($indexedMap as $file) + foreach ($indexedMap as $file) { - $noneCache = (is_readable($file->cdnPath . '/' . $file->fileName)) ? '?' . date('YmdHis', filemtime($file->cdnPath . '/' . $file->fileName)) : ''; - $fullFilePath = $file->filePath . '/' . $file->fileName . $noneCache; - - $result[] = array('file' => $fullFilePath, 'media' => $file->media, 'targetie' => $file->targetIe); + $minify_this_file = !$file->isMinified && !$file->isExternalURL && !$file->isCachedScript && (($file->isCommon && $minify !== 'none') || $minify === 'all'); + if ($file->fileExtension === 'css') + { + $this->proc_CSS_JS($file, $minify_this_file); + } + else + { + $this->proc_LESS_SCSS($file, $minify_this_file); + } + } + } + + // Add all files to the final result. + $result = array(); + if ($concat && count($concat_list = $this->_concatMap($map))) + { + foreach ($concat_list as $concat_fileset) + { + if (count($concat_fileset) === 1) + { + $file = reset($concat_fileset); + $url = $file->filePath . '/' . $file->fileName; + if (!$file->isExternalURL && is_readable($file->fileFullPath)) + { + $url .= '?' . date('YmdHis', filemtime($file->fileFullPath)); + } + $result[] = array('file' => $url, 'media' => $file->media, 'targetie' => $file->targetIe); + } + else + { + $concat_files = array(); + $concat_max_timestamp = 0; + foreach ($concat_fileset as $file) + { + $concat_files[] = $file->media === 'all' ? $file->fileFullPath : array($file->fileFullPath, $file->media); + $concat_max_timestamp = max($concat_max_timestamp, filemtime($file->fileFullPath)); + } + $concat_filename = self::$assetdir . '/combined/' . sha1(serialize($concat_files)) . '.css'; + if (!file_exists(\RX_BASEDIR . $concat_filename) || filemtime(\RX_BASEDIR . $concat_filename) < $concat_max_timestamp) + { + Rhymix\Framework\Storage::write(\RX_BASEDIR . $concat_filename, Rhymix\Framework\Formatter::concatCSS($concat_files, $concat_filename)); + } + $concat_filename .= '?' . date('YmdHis', filemtime(\RX_BASEDIR . $concat_filename)); + $result[] = array('file' => \RX_BASEURL . $concat_filename, 'media' => 'all', 'targetie' => ''); + } + } + } + else + { + foreach ($map as $indexedMap) + { + foreach ($indexedMap as $file) + { + $url = $file->filePath . '/' . $file->fileName; + if (!$file->isExternalURL && is_readable($file->fileFullPath)) + { + $url .= '?' . date('YmdHis', filemtime($file->fileFullPath)); + } + $result[] = array('file' => $url, 'media' => $file->media, 'targetie' => $file->targetIe); + } } } - return $result; } @@ -351,7 +445,7 @@ class FrontEndFileHandler extends Handler * @param string $type Type of javascript. head, body * @return array Returns javascript file list. Array contains file, targetie. */ - function getJsFileList($type = 'head') + public function getJsFileList($type = 'head') { if($type == 'head') { @@ -363,24 +457,105 @@ class FrontEndFileHandler extends Handler $map = &$this->jsBodyMap; $mapIndex = &$this->jsBodyMapIndex; } - + + $minify = self::$minify !== null ? self::$minify : (config('view.minify_scripts') ?: 'common'); + $concat = strpos(self::$concat !== null ? self::$concat : config('view.concat_scripts'), 'js') !== false; $this->_sortMap($map, $mapIndex); - - $result = array(); - foreach($map as $indexedMap) + + // Minify all scripts. + foreach ($map as $indexedMap) { - foreach($indexedMap as $file) + foreach ($indexedMap as $file) { - $noneCache = (is_readable($file->cdnPath . '/' . $file->fileName)) ? '?' . date('YmdHis', filemtime($file->cdnPath . '/' . $file->fileName)) : ''; - $fullFilePath = $file->filePath . '/' . $file->fileName . $noneCache; - - $result[] = array('file' => $fullFilePath, 'targetie' => $file->targetIe); + if (!$file->isMinified && !$file->isExternalURL && !$file->isCachedScript && (($file->isCommon && $minify !== 'none') || $minify === 'all')) + { + $this->proc_CSS_JS($file, true); + } + } + } + + // Add all files to the final result. + $result = array(); + if ($concat && $type === 'head' && count($concat_list = $this->_concatMap($map))) + { + foreach ($concat_list as $concat_fileset) + { + if (count($concat_fileset) === 1) + { + $file = reset($concat_fileset); + $url = $file->filePath . '/' . $file->fileName; + if (!$file->isExternalURL && is_readable($file->fileFullPath)) + { + $url .= '?' . date('YmdHis', filemtime($file->fileFullPath)); + } + $result[] = array('file' => $url, 'targetie' => $file->targetIe); + } + else + { + $concat_files = array(); + $concat_max_timestamp = 0; + foreach ($concat_fileset as $file) + { + $concat_files[] = $file->targetIe ? array($file->fileFullPath, $file->targetIe) : $file->fileFullPath; + $concat_max_timestamp = max($concat_max_timestamp, filemtime($file->fileFullPath)); + } + $concat_filename = self::$assetdir . '/combined/' . sha1(serialize($concat_files)) . '.js'; + if (!file_exists(\RX_BASEDIR . $concat_filename) || filemtime(\RX_BASEDIR . $concat_filename) < $concat_max_timestamp) + { + Rhymix\Framework\Storage::write(\RX_BASEDIR . $concat_filename, Rhymix\Framework\Formatter::concatJS($concat_files, $concat_filename)); + } + $concat_filename .= '?' . date('YmdHis', filemtime(\RX_BASEDIR . $concat_filename)); + $result[] = array('file' => \RX_BASEURL . $concat_filename, 'targetie' => ''); + } + } + } + else + { + foreach ($map as $indexedMap) + { + foreach ($indexedMap as $file) + { + $url = $file->filePath . '/' . $file->fileName; + if (!$file->isExternalURL && is_readable($file->fileFullPath)) + { + $url .= '?' . date('YmdHis', filemtime($file->fileFullPath)); + } + $result[] = array('file' => $url, 'targetie' => $file->targetIe); + } } } - return $result; } - + + /** + * Create a concatenation map, skipping external URLs and unreadable scripts. + * + * @param array $map + * @return array + */ + protected function _concatMap(&$map) + { + $concat_list = array(); + $concat_key = 0; + foreach ($map as $indexedMap) + { + foreach ($indexedMap as $file) + { + if ($file->isExternalURL || ($file->fileExtension === 'css' && $file->targetIe) || !is_readable($file->fileFullPath)) + { + $concat_key++; + $concat_list[$concat_key][] = $file; + $concat_key++; + } + else + { + $concat_list[$concat_key][] = $file; + } + } + } + return $concat_list; + } + /** * Sort a map * @@ -388,7 +563,7 @@ class FrontEndFileHandler extends Handler * @param array $index Not used * @return void */ - function _sortMap(&$map, &$index) + protected function _sortMap(&$map, &$index) { ksort($map); } @@ -399,7 +574,7 @@ class FrontEndFileHandler extends Handler * @param string $path Path to normalize * @return string Normalized path */ - function _normalizeFilePath($path) + protected function _normalizeFilePath($path) { if(strpos($path, '://') === FALSE && $path{0} != '/' && $path{0} != '.') { @@ -426,50 +601,40 @@ class FrontEndFileHandler extends Handler * @param string $path Path to get absolute url * @return string Absolute url */ - function _getAbsFileUrl($path) + protected function _getAbsFileUrl($path) { - $path = $this->_normalizeFilePath($path); - - if(strpos($path, './') === 0) + $path = Rhymix\Framework\Filters\FilenameFilter::cleanPath($path); + if (!strncmp($path, \RX_BASEDIR, strlen(\RX_BASEDIR))) { - if(dirname($_SERVER['SCRIPT_NAME']) == '/' || dirname($_SERVER['SCRIPT_NAME']) == '\\') - { - $path = '/' . substr($path, 2); - } - else - { - $path = dirname($_SERVER['SCRIPT_NAME']) . '/' . substr($path, 2); - } + $path = \RX_BASEURL . substr($path, strlen(\RX_BASEDIR)); } - else if(strpos($file, '../') === 0) - { - $path = $this->_normalizeFilePath(dirname($_SERVER['SCRIPT_NAME']) . "/{$path}"); - } - return $path; } /** * Arrage css index * - * @param string $dirName First directory name of css path - * @param array $file file info. + * @param string $dirname + * @param object $file * @return void */ - function _arrangeCssIndex($dirName, &$file) + protected function _arrangeCssIndex($dirname, $file) { - if($file->index !== 0) + if ($file->index !== 0) { return; } - - $dirName = str_replace('./', '', $dirName); - $tmp = explode('/', $dirName); + + $dirname = substr($dirname, strlen(\RX_BASEDIR)); + if (strncmp($dirname, self::$assetdir . '/', strlen(self::$assetdir) + 1) === 0) + { + $dirname = substr($dirname, strlen(self::$assetdir) + 1); + } + $tmp = array_first(explode('/', strtr($dirname, '\\.', '//'))); $cssSortList = array('common' => -100000, 'layouts' => -90000, 'modules' => -80000, 'widgets' => -70000, 'addons' => -60000); $file->index = $cssSortList[$tmp[0]]; } - } /* End of file FrontEndFileHandler.class.php */ /* Location: ./classes/frontendfile/FrontEndFileHandler.class.php */ diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php index 1d88f0b1c..fc99576ea 100644 --- a/classes/template/TemplateHandler.class.php +++ b/classes/template/TemplateHandler.class.php @@ -688,6 +688,8 @@ class TemplateHandler } break; case 'css': + case 'less': + case 'scss': if($doUnload) { $result = "Context::unloadFile('{$attr['target']}','{$attr['targetie']}','{$attr['media']}');"; @@ -695,7 +697,7 @@ class TemplateHandler else { $metafile = $attr['target']; - $result = "\$__tmp=array('{$attr['target']}','{$attr['media']}','{$attr['targetie']}','{$attr['index']}');Context::loadFile(\$__tmp);unset(\$__tmp);"; + $result = "\$__tmp=array('{$attr['target']}','{$attr['media']}','{$attr['targetie']}','{$attr['index']}'," . ($attr['vars'] ? self::_replaceVar($attr['vars']) : 'array()') . ");Context::loadFile(\$__tmp);unset(\$__tmp);"; } break; } diff --git a/common/css/rhymix.scss b/common/css/rhymix.scss new file mode 100644 index 000000000..674786d9b --- /dev/null +++ b/common/css/rhymix.scss @@ -0,0 +1,419 @@ +@charset "UTF-8"; + +/* Element Reset */ +body, table, input, textarea, select, button { + font-family: sans-serif; + font-size: 12px; +} +article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { + display: block; +} +body { + position: relative; +} +a img { + border: 0; +} +[hidden] { + display: none; +} + +/* Content Default Styles */ +.xe_content { + font-family: $default_font_family; + font-size: $default_font_size; + line-height: $default_line_height; + @if $default_word_break == 'none' { + white-space: nowrap; + } @else { + word-break: $default_word_break; + word-wrap: break-word; + } + p { + margin: 0 0 $default_paragraph_spacing 0; + } + img { + max-width: 100%; + height: auto; + } +} +@media \0screen { + img { + max-width: none; + } +} + +/* Clearfix */ +.xe-clearfix { + &:before, &:after { + content: " "; + display: table; + } + &:after { + clear: both; + } + zoom: 1; +} +.xe-widget-wrapper { + overflow: hidden; +} + +/* Popup Menu Area */ +#popup_menu_area { + position: absolute; + z-index: 9999; + margin: 10px 0; + padding: 0; + border: 1px solid #eeeeee; + border-radius: 2px; + font-size: 12px; + box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); + background: #fff; + min-width:80px; + ul { + margin: 0; + padding: 0; + list-style: none; + } + li { + margin: 0; + padding: 0; + line-height: 1.5; + } + a { + display: block; + padding: 5px; + text-decoration: none; + color: #212121; + &:hover, &:active, &:focus { + background: #eeeeee; + outline: none; + } + } +} +@media screen and (max-width: 400px) { + #popup_menu_area { + min-width:120px; + max-width:95%; + font-size: 13px; + a { + display: block; + padding: 10px; + text-decoration: none; + color: #212121; + } + } +} + +/* Message */ +.message { + position: relative; + margin: 1em 0; + padding: 0 1em; + border: 1px solid #ddd; + border-radius: 4px; + line-height: 1.4; + font-size: 13px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #f8f8f8; + p { + margin: 1em 0 !important; + } + &.info { + border-color: #BCE8F1; + color: #3A87AD; + background-color: #D9EDF7; + } + &.error { + border-color: #EED3D7; + color: #B94A48; + background-color: #F2DEDE; + } + &.update { + border-color: #D6E9C6; + color: #468847; + background-color: #DFF0D8; + } +} +body > .message { + margin: 1em; +} + +/* Waiting for server response */ +.wfsr { + z-index: 100; + display: none; + position: fixed; + left: 0; + top: 0; + right: 0; + margin: 0; + padding: 20px 0 0 0; + border-bottom: 1px solid #ccc; + text-align: center; + font: bold 16px/60px "Helvetica Neue", Helvetica, Arial, 돋움, Dotum, sans-serif; + color: #fff; + opacity: .8; + filter: alpha(opacity=80); + box-shadow: 0 0 5px #000; + background: #333 url("../../common/img/msg.loading.gif") no-repeat center 15px; +} + +/* Button */ +.btnArea { + clear: both; + margin: 10px 0; + padding: 0; + text-align: right; + zoom: 1; + &:after { + clear: both; + display: block; + content: ""; + } +} +.btn { + display: inline-block; + *display: inline; + margin: 0; + padding: 0 12px !important; + height: 24px !important; + overflow: visible; + border: 1px solid #bbbbbb; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #a2a2a2; + border-radius: 2px; + text-decoration: none !important; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: top; + line-height: 24px !important; + font-family: inherit; + font-size: 12px; + color: #333333; + *zoom: 1; + cursor: pointer; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(top, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); + filter: progid: DXImageTransform.Microsoft.gradient(enabled=false); + &:hover, &:active, &[disabled] { + color: #333; + background-color: #e6e6e6; + *background-color: #d9d9d9; + } + >a, >button, >input, >span { + display: inline-block; + *zoom: 1; + margin: 0 -12px !important; + padding: 0 12px !important; + overflow: visible; + width: auto; + height: 24px; + border: 0; + vertical-align: top; + text-decoration: none !important; + line-height: 24px; + font-family: inherit; + font-size: 12px; + color: #333; + cursor: pointer; + background: none; + } +} +input.btn, button.btn { + height: 26px !important; +} +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + white-space: nowrap; + vertical-align: middle; + font-size: 0; + *zoom: 1; + &:first-child { + *margin-left: 0; + } + &+.btn-group { + margin-left: 5px; + } + >.btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + &+.btn { + margin-left: -1px; + } + &:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; + border-top-left-radius: 4px; + } + &:last-child { + -webkit-border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; + border-bottom-right-radius: 4px; + } + &:hover, &:focus, &:active, &.active { + z-index: 2; + } + } +} + +/* Debug */ +#rhymix_debug_button { + display: none; + position: fixed; + left: 0; bottom: 40px; + background: #eeeeee; + background: linear-gradient(to bottom, #f4f4f4 0%, #eaeaea 100%); + border: 1px solid #ccc; border-left: 0; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.18), 0 0 6px 0 rgba(0, 0, 0, 0.12); + z-index: 1073741824; + &:hover { + background: #dddddd; + background: linear-gradient(to bottom, #e8e8e8 0%, #d9d9d9 100%); + } + a { + display: block; + font: bold 12px/14px Arial, sans-serif; + color: #444; + text-decoration: none; + padding: 4px 8px; + &.has_errors { + color: #f44336; + } + } +} +#rhymix_debug_panel { + display: none; + position: fixed; + left: 0; top: 0; + max-width: 100%; + height: 100%; + overflow-y: scroll; + background: #fcfcfc; + box-sizing: border-box; + border-right: 1px solid #ccc; + box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.18), 0 0 8px 0 rgba(0, 0, 0, 0.12); + z-index: 1073741824; + .debug_header { + clear: both; + width: 100%; + height: 36px; + background: #444444; + background: linear-gradient(to right, #222222 0%, #444444 40%, #eeeeee 100%); + position: relative; + h2 { + font: bold 16px/20px Arial, sans-serif; + color: #fcfcfc; + position: absolute; + left: 10px; top: 10px; + margin: 0; padding: 0; + } + .debug_maximize { + font: normal 20px/24px Arial, sans-serif; + text-decoration: none; + color: #444444; + position: absolute; + right: 32px; top: 6px; + } + .debug_close { + font: normal 28px/28px Arial, sans-serif; + text-decoration: none; + color: #444444; + position: absolute; + right: 10px; top: 4px; + &:hover { + color: #f44336; + } + } + } + .debug_page { + clear: both; + margin: 12px 10px; + font: normal 12px/16px Arial, NanumBarunGothic, NanumGothic, "Malgun Gothic", sans-serif; + .debug_page_header { + padding-bottom: 8px; + border-bottom: 1px solid #ddd; + position: relative; + cursor: pointer; + h3 { + color: #444; + font: inherit; + font-size: 14px; + font-weight: bold; + margin: 0; + padding: 0; + } + } + .debug_page_collapse { + display: block; + position: absolute; + right: 0; top: 0; + color: #999; + font-size: 10px; + line-height: 12px; + text-decoration: none; + padding: 2px 2px; + } + .debug_page_body { + margin: 8px 4px 8px 10px; + h4 { + color: #444; + font: inherit; + font-size: 13px; + font-weight: bold; + margin: 0 0 8px 0; + padding: 0; + } + } + .debug_entry { + font-family: Consolas, "Courier New", monospace; + color: #444; + margin-left: 38px; + margin-bottom: 8px; + text-indent: -28px; + word-wrap: break-word; + word-break: break-all; + &.pre_wrap { + white-space: pre-wrap; + } + ul.debug_metadata { + margin: 0 0 0 -16px; padding: 0; + li { + list-style: disc; + margin: 0; padding: 0; text-indent: 0; + } + } + ul.debug_backtrace { + margin: 4px 0 0 16px; padding: 0; + li { + list-style: disc; + margin: 0; padding: 0; text-indent: 0; + color: #888; + } + } + } + } +} diff --git a/common/css/xe.css b/common/css/xe.css deleted file mode 100644 index 2db142d54..000000000 --- a/common/css/xe.css +++ /dev/null @@ -1,432 +0,0 @@ -@charset "utf-8"; -/*! Copyright (C) NAVER */ -/* @author NAVER */ -/*csslint unqualified-attributes: false, display-property-grouping: false*/ - -/* Element Reset */ -body, -table, -input, -textarea, -select, -button { - font-family: Tahoma, Geneva, sans-serif; - font-size: 12px; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -nav, -section { - display: block; -} -body { - position: relative; - word-wrap: break-word; -} -a img { - border: 0; -} -[hidden] { - display: none; -} -.xe_content img { - max-width: 100%; - height: auto; -} -@media \0screen { - img { - max-width: none; - } -} -.xe-clearfix:before, -.xe-clearfix:after { - content: " "; - display: table; -} -.xe-clearfix:after { - clear: both; -} -.xe-clearfix { - zoom: 1; -} - -.xe-widget-wrapper { - overflow: hidden; -} - -/* Popup Menu Area */ -#popup_menu_area { - position: absolute; - z-index:9999; - margin: 10px 0; - padding: 0; - border: 1px solid #eeeeee; - border-radius: 2px; - font-size: 12px; - box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); - background: #fff; - min-width:80px; -} -#popup_menu_area ul { - margin: 0; - padding: 0; - list-style: none; -} -#popup_menu_area li { - margin: 0; - padding: 0; - line-height: 1.5; -} -#popup_menu_area a { - display: block; - padding: 5px; - text-decoration: none; - color: #212121; -} -#popup_menu_area a:hover, -#popup_menu_area a:active, -#popup_menu_area a:focus { - background: #eeeeee; - outline:none; -} -@media screen and (max-width: 400px) { - #popup_menu_area { - min-width:120px; - max-width:95%; - font-size: 13px; - } - #popup_menu_area a { - display: block; - padding: 10px; - text-decoration: none; - color: #212121; - } -} - -/* Message */ -.message { - position: relative; - margin: 1em 0; - padding: 0 1em; - border: 1px solid #ddd; - border-radius: 4px; - line-height: 1.4; - font-size: 13px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - background-color: #f8f8f8; -} -body>.message { - margin: 1em; -} -.message p { - margin: 1em 0 !important; -} -.message.info { - border-color: #BCE8F1; - color: #3A87AD; - background-color: #D9EDF7; -} -.message.error { - border-color: #EED3D7; - color: #B94A48; - background-color: #F2DEDE; -} -.message.update { - border-color: #D6E9C6; - color: #468847; - background-color: #DFF0D8; -} - -/* Waiting for server response */ -.wfsr { - z-index: 100; - display: none; - position: fixed; - left: 0; - top: 0; - right: 0; - margin: 0; - padding: 20px 0 0 0; - border-bottom: 1px solid #ccc; - text-align: center; - font: bold 16px/60px "Helvetica Neue", Helvetica, Arial, 돋움, Dotum, sans-serif; - color: #fff; - opacity: .8; - filter: alpha(opacity=80); - box-shadow: 0 0 5px #000; - background: #333 url("../../common/img/msg.loading.gif") no-repeat center 15px; -} - -/* Button */ -.btnArea { - clear: both; - margin: 10px 0; - padding: 0; - text-align: right; - zoom: 1; -} -.btnArea:after { - clear: both; - display: block; - content: ""; -} -.btn { - display: inline-block; - *display: inline; - margin: 0; - padding: 0 12px !important; - height: 24px !important; - overflow: visible; - border: 1px solid #bbbbbb; - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - border-bottom-color: #a2a2a2; - border-radius: 2px; - text-decoration: none !important; - text-align: center; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - vertical-align: top; - line-height: 24px !important; - font-family: inherit; - font-size: 12px; - color: #333333; - *zoom: 1; - cursor: pointer; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - background-color: #f5f5f5; - *background-color: #e6e6e6; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(top, #ffffff, #e6e6e6); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0); - filter: progid: DXImageTransform.Microsoft.gradient(enabled=false); -} -input.btn, -button.btn { - height: 26px !important; -} -.btn:hover, -.btn:active, -.btn[disabled] { - color: #333; - background-color: #e6e6e6; - *background-color: #d9d9d9; -} -.btn>a, -.btn>button, -.btn>input, -.btn>span { - display: inline-block; - *zoom: 1; - margin: 0 -12px !important; - padding: 0 12px !important; - overflow: visible; - width: auto; - height: 24px; - border: 0; - vertical-align: top; - text-decoration: none !important; - line-height: 24px; - font-family: inherit; - font-size: 12px; - color: #333; - cursor: pointer; - background: none; -} -.btn-group { - position: relative; - display: inline-block; - *display: inline; - *margin-left: .3em; - white-space: nowrap; - vertical-align: middle; - font-size: 0; - *zoom: 1; -} -.btn-group:first-child { - *margin-left: 0; -} -.btn-group+.btn-group { - margin-left: 5px; -} -.btn-group>.btn { - position: relative; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} -.btn-group>.btn+.btn { - margin-left: -1px; -} -.btn-group>.btn:first-child { - margin-left: 0; - -webkit-border-bottom-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; - border-bottom-left-radius: 4px; - -webkit-border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; - border-top-left-radius: 4px; -} -.btn-group>.btn:last-child { - -webkit-border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; - border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - -moz-border-radius-bottomright: 4px; - border-bottom-right-radius: 4px; -} -.btn-group>.btn:hover, -.btn-group>.btn:focus, -.btn-group>.btn:active, -.btn-group>.btn.active { - z-index: 2; -} - -/* Debug */ -#rhymix_debug_button { - display: none; - position: fixed; - left: 0; bottom: 40px; - background: #eeeeee; - background: linear-gradient(to bottom, #f4f4f4 0%, #eaeaea 100%); - border: 1px solid #ccc; border-left: 0; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.18), 0 0 6px 0 rgba(0, 0, 0, 0.12); - z-index: 1073741824; -} -#rhymix_debug_button:hover { - background: #dddddd; - background: linear-gradient(to bottom, #e8e8e8 0%, #d9d9d9 100%); -} -#rhymix_debug_button a { - display: block; - font: bold 12px/14px Arial, sans-serif; - color: #444; - text-decoration: none; - padding: 4px 8px; -} -#rhymix_debug_button a.has_errors { - color: #f44336; -} -#rhymix_debug_panel { - display: none; - position: fixed; - left: 0; top: 0; - max-width: 100%; - height: 100%; - overflow-y: scroll; - background: #fcfcfc; - box-sizing: border-box; - border-right: 1px solid #ccc; - box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.18), 0 0 8px 0 rgba(0, 0, 0, 0.12); - z-index: 1073741824; -} -#rhymix_debug_panel .debug_header { - clear: both; - width: 100%; - height: 36px; - background: #444444; - background: linear-gradient(to right, #222222 0%, #444444 40%, #eeeeee 100%); - position: relative; -} -#rhymix_debug_panel .debug_header h2 { - font: bold 16px/20px Arial, sans-serif; - color: #fcfcfc; - position: absolute; - left: 10px; top: 10px; - margin: 0; padding: 0; -} -#rhymix_debug_panel .debug_header .debug_maximize { - font: normal 20px/24px Arial, sans-serif; - text-decoration: none; - color: #444444; - position: absolute; - right: 32px; top: 6px; -} -#rhymix_debug_panel .debug_header .debug_close { - font: normal 28px/28px Arial, sans-serif; - text-decoration: none; - color: #444444; - position: absolute; - right: 10px; top: 4px; -} -#rhymix_debug_panel .debug_header .debug_close:hover { - color: #f44336; -} -#rhymix_debug_panel .debug_page { - clear: both; - margin: 12px 10px; - font: normal 12px/16px Arial, NanumBarunGothic, NanumGothic, "Malgun Gothic", sans-serif; -} -#rhymix_debug_panel .debug_page .debug_page_header { - padding-bottom: 8px; - border-bottom: 1px solid #ddd; - position: relative; - cursor: pointer; -} -#rhymix_debug_panel .debug_page .debug_page_header h3 { - color: #444; - font: inherit; - font-size: 14px; - font-weight: bold; - margin: 0; - padding: 0; -} -#rhymix_debug_panel .debug_page .debug_page_collapse { - display: block; - position: absolute; - right: 0; top: 0; - color: #999; - font-size: 10px; - line-height: 12px; - text-decoration: none; - padding: 2px 2px; -} -#rhymix_debug_panel .debug_page .debug_page_body { - margin: 8px 4px 8px 10px; -} -#rhymix_debug_panel .debug_page .debug_page_body h4 { - color: #444; - font: inherit; - font-size: 13px; - font-weight: bold; - margin: 0 0 8px 0; - padding: 0; -} -#rhymix_debug_panel .debug_page .debug_entry { - font-family: Consolas, "Courier New", monospace; - color: #444; - margin-left: 38px; - margin-bottom: 8px; - text-indent: -28px; - word-wrap: break-word; - word-break: break-all; -} -#rhymix_debug_panel .debug_page .debug_entry.pre_wrap { - white-space: pre-wrap; -} -#rhymix_debug_panel .debug_page .debug_entry ul.debug_metadata { - margin: 0 0 0 -16px; padding: 0; -} -#rhymix_debug_panel .debug_page .debug_entry ul.debug_metadata li { - list-style: disc; - margin: 0; padding: 0; text-indent: 0; -} -#rhymix_debug_panel .debug_page .debug_entry ul.debug_backtrace { - margin: 4px 0 0 16px; padding: 0; -} -#rhymix_debug_panel .debug_page .debug_entry ul.debug_backtrace li { - list-style: disc; - margin: 0; padding: 0; text-indent: 0; - color: #888; -} diff --git a/common/framework/drivers/cache/file.php b/common/framework/drivers/cache/file.php index c351ce808..bd1d5d62a 100644 --- a/common/framework/drivers/cache/file.php +++ b/common/framework/drivers/cache/file.php @@ -161,7 +161,7 @@ class File implements \Rhymix\Framework\Drivers\CacheInterface public function incr($key, $amount) { $value = intval($this->get($key)); - $success = $this->set($key, $value + $amount, 0); + $success = $this->set($key, $value + $amount, 0, true); return $success ? ($value + $amount) : false; } diff --git a/common/framework/formatter.php b/common/framework/formatter.php index 6865a17c1..4ce0d84f5 100644 --- a/common/framework/formatter.php +++ b/common/framework/formatter.php @@ -176,7 +176,7 @@ class Formatter public static function compileLESS($source_filename, $target_filename, $variables = array(), $minify = false) { // Get the cleaned and concatenated content. - $content = self::_concatenate($source_filename, $target_filename); + $content = self::concatCSS($source_filename, $target_filename); // Compile! try @@ -189,7 +189,8 @@ class Formatter $less_compiler->setVariables($variables); } - $content = '@charset "UTF-8";' . "\n" . $less_compiler->compile($content) . "\n"; + $charset = strpos($content, '@charset') === false ? ('@charset "UTF-8";' . "\n") : ''; + $content = $charset . $less_compiler->compile($content) . "\n"; $result = true; } catch (\Exception $e) @@ -215,7 +216,7 @@ class Formatter public static function compileSCSS($source_filename, $target_filename, $variables = array(), $minify = false) { // Get the cleaned and concatenated content. - $content = self::_concatenate($source_filename, $target_filename); + $content = self::concatCSS($source_filename, $target_filename); // Compile! try @@ -228,7 +229,8 @@ class Formatter $scss_compiler->setVariables($variables); } - $content = '@charset "UTF-8";' . "\n" . $scss_compiler->compile($content) . "\n"; + $charset = strpos($content, '@charset') === false ? ('@charset "UTF-8";' . "\n") : ''; + $content = $charset . $scss_compiler->compile($content) . "\n"; $result = true; } catch (\Exception $e) @@ -251,7 +253,18 @@ class Formatter */ public static function minifyCSS($source_filename, $target_filename) { - $minifier = new \MatthiasMullie\Minify\CSS($source_filename); + $minifier = new \MatthiasMullie\Minify\CSS(); + if (is_array($source_filename)) + { + foreach ($source_filename as $filename) + { + $minifier->add($filename); + } + } + else + { + $minifier->add($source_filename); + } $content = $minifier->execute($target_filename); Storage::write($target_filename, $content); return strlen($content) ? true : false; @@ -266,7 +279,18 @@ class Formatter */ public static function minifyJS($source_filename, $target_filename) { - $minifier = new \MatthiasMullie\Minify\JS($source_filename); + $minifier = new \MatthiasMullie\Minify\JS(); + if (is_array($source_filename)) + { + foreach ($source_filename as $filename) + { + $minifier->add($filename); + } + } + else + { + $minifier->add($source_filename); + } $content = $minifier->execute($target_filename); Storage::write($target_filename, $content); return strlen($content) ? true : false; @@ -279,7 +303,7 @@ class Formatter * @param string $target_filename * @return string */ - protected static function _concatenate($source_filename, $target_filename) + public static function concatCSS($source_filename, $target_filename) { $result = ''; @@ -287,25 +311,173 @@ class Formatter { $source_filename = array($source_filename); } + foreach ($source_filename as $filename) { + // Get the media query. + if (is_array($filename) && count($filename) >= 2) + { + list($filename, $media) = $filename; + } + else + { + $media = null; + } + + // Clean the content. $content = utf8_clean(file_get_contents($filename)); + + // Convert all paths in LESS and SCSS imports, too. + $import_type = ends_with('.scss', $filename) ? 'scss' : 'normal'; + $content = preg_replace_callback('/@import\s+(?:\\([^()]+\\))?([^;]+);/', function($matches) use($filename, $target_filename, $import_type) { + $import_content = ''; + $import_files = array_map(function($str) use($filename, $import_type) { + $str = trim(trim(trim(preg_replace('/^url\\(([^()]+)\\)$/', '$1', trim($str))), '"\'')); + return dirname($filename) . '/' . ($import_type === 'scss' ? "_$str.scss" : $str); + }, explode(',', $matches[1])); + foreach ($import_files as $import_filename) + { + if (file_exists($import_filename)) + { + $import_content .= self::concatCSS($import_filename, $target_filename); + } + } + return trim($import_content); + }, $content); + + // Convert all paths to be relative to the new filename. $path_converter = new \MatthiasMullie\PathConverter\Converter($filename, $target_filename); $content = preg_replace_callback('/\burl\\(([^)]+)\\)/iU', function($matches) use ($path_converter) { $url = trim($matches[1], '\'"'); - if (!strlen($url) || $url[0] === '/') + if (!strlen($url) || $url[0] === '/' || preg_match('#^(?:https?|data):#', $url)) { return $matches[0]; } else { - return 'url("' . escape_dqstr($path_converter->convert($url)) . '")'; + return 'url("' . str_replace('\\$', '$', escape_dqstr($path_converter->convert($url))) . '")'; } }, $content); unset($path_converter); - $result .= trim($content) . "\n\n"; + + // Wrap the content in a media query if there is one. + if ($media !== null) + { + $content = "@media $media {\n\n" . trim($content) . "\n\n}"; + } + + // Append to the result string. + $original_filename = starts_with(\RX_BASEDIR, $filename) ? substr($filename, strlen(\RX_BASEDIR)) : $filename; + $result .= '/* Original file: ' . $original_filename . ' */' . "\n\n" . trim($content) . "\n\n"; } return $result; } + + /** + * JS concatenation subroutine. + * + * @param string|array $source_filename + * @param string $target_filename + * @return string + */ + public static function concatJS($source_filename, $target_filename) + { + $result = ''; + + if (!is_array($source_filename)) + { + $source_filename = array($source_filename); + } + + foreach ($source_filename as $filename) + { + // Get the IE condition. + if (is_array($filename) && count($filename) >= 2) + { + list($filename, $targetie) = $filename; + } + else + { + $targetie = null; + } + + // Clean the content. + $content = utf8_clean(file_get_contents($filename)); + + // Wrap the content in an IE condition if there is one. + if ($targetie !== null) + { + $content = 'if (' . self::convertIECondition($targetie) . ') {' . "\n\n" . trim($content) . ";\n\n" . '}'; + } + + // Append to the result string. + $original_filename = starts_with(\RX_BASEDIR, $filename) ? substr($filename, strlen(\RX_BASEDIR)) : $filename; + $result .= '/* Original file: ' . $original_filename . ' */' . "\n\n" . trim($content) . ";\n\n"; + } + + return $result; + } + + /** + * Convert IE conditional comments to JS conditions. + * + * @param string $condition + * @return string + */ + public static function convertIECondition($condition) + { + $conversions = array( + '/^true$/i' => 'true', + '/^false$/i' => 'false', + '/^IE$/i' => 'window.navigator.userAgent.match(/MSIE\s/)', + '/^IE\s*(\d+)$/i' => '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] == %d)', + '/^gt IE\s*(\d+)$/i' => '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] > %d)', + '/^gte IE\s*(\d+)$/i' => '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] >= %d)', + '/^lt IE\s*(\d+)$/i' => '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] < %d)', + '/^lte IE\s*(\d+)$/i' => '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] <= %d)', + ); + + $result = array(); + $conditions = preg_split('/([\&\|])/', $condition, -1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); + foreach ($conditions as $condition) + { + $condition = trim(preg_replace('/[\(\)]/', '', $condition)); + if ($condition === '') + { + continue; + } + + if ($condition === '&' || $condition === '|') + { + $result[] = $condition . $condition; + continue; + } + + $negation = $condition[0] === '!'; + if ($negation) + { + $condition = trim(substr($condition, 1)); + } + + foreach ($conversions as $regexp => $replacement) + { + if (preg_match($regexp, $condition, $matches)) + { + if (count($matches) > 1) + { + array_shift($matches); + $result[] = ($negation ? '!' : '') . vsprintf($replacement, $matches); + } + else + { + $result[] = ($negation ? '!' : '') . $replacement; + } + break; + } + } + } + + return count($result) ? implode(' ', $result) : 'false'; + } } diff --git a/modules/admin/admin.admin.controller.php b/modules/admin/admin.admin.controller.php index a0d287b68..b02a9530f 100644 --- a/modules/admin/admin.admin.controller.php +++ b/modules/admin/admin.admin.controller.php @@ -550,7 +550,7 @@ class adminAdminController extends admin Rhymix\Framework\Config::save(); $this->setMessage('success_updated'); - $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigGeneral')); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigGeneral')); } /** @@ -617,7 +617,7 @@ class adminAdminController extends admin Rhymix\Framework\Config::save(); $this->setMessage('success_updated'); - $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigSecurity')); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigSecurity')); } /** @@ -699,13 +699,14 @@ class adminAdminController extends admin Rhymix\Framework\Config::set('session.delay', $vars->delay_session === 'Y'); Rhymix\Framework\Config::set('session.use_db', $vars->use_db_session === 'Y'); Rhymix\Framework\Config::set('view.minify_scripts', $vars->minify_scripts ?: 'common'); + Rhymix\Framework\Config::set('view.concat_scripts', $vars->concat_scripts ?: 'none'); Rhymix\Framework\Config::set('view.gzip', $vars->use_gzip === 'Y'); // Save Rhymix\Framework\Config::save(); $this->setMessage('success_updated'); - $this->setRedirectUrl(Context::get('success_return_url') ?: $default_url . 'index.php?act=dispAdminConfigAdvanced'); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigAdvanced')); } /** @@ -763,7 +764,7 @@ class adminAdminController extends admin Rhymix\Framework\Config::save(); $this->setMessage('success_updated'); - $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigDebug')); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigDebug')); } /** @@ -802,7 +803,7 @@ class adminAdminController extends admin Rhymix\Framework\Config::save(); $this->setMessage('success_updated'); - $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigSitelock')); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigSitelock')); } /** @@ -874,7 +875,7 @@ class adminAdminController extends admin Rhymix\Framework\Config::save(); $this->setMessage('success_updated'); - $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'act', 'dispAdminConfigFtp')); + $this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl('', 'module', 'admin', 'act', 'dispAdminConfigFtp')); } /** diff --git a/modules/admin/admin.admin.view.php b/modules/admin/admin.admin.view.php index 7bc617e75..4c6cc6d0b 100644 --- a/modules/admin/admin.admin.view.php +++ b/modules/admin/admin.admin.view.php @@ -417,7 +417,7 @@ class adminAdminView extends admin $oModuleModel = getModel('module'); $config = $oModuleModel->getModuleConfig('module'); Context::set('site_title', escape($config->siteTitle)); - Context::set('html_footer', escape($config->htmlFooter)); + Context::set('all_html_footer', escape($config->htmlFooter)); // Index module $columnList = array('modules.mid', 'modules.browser_title', 'sites.index_module_srl'); @@ -502,7 +502,7 @@ class adminAdminView extends admin } else { - $object_cache_type = 'file'; + $object_cache_type = 'dummy'; } $cache_default_ttl = 86400; $cache_servers = Rhymix\Framework\Config::get('cache'); @@ -530,6 +530,7 @@ class adminAdminView extends admin Context::set('delay_session', Rhymix\Framework\Config::get('session.delay')); Context::set('use_db_session', Rhymix\Framework\Config::get('session.use_db')); Context::set('minify_scripts', Rhymix\Framework\Config::get('view.minify_scripts')); + Context::set('concat_scripts', Rhymix\Framework\Config::get('view.concat_scripts')); Context::set('use_gzip', Rhymix\Framework\Config::get('view.gzip')); $this->setTemplateFile('config_advanced'); diff --git a/modules/admin/lang/en.php b/modules/admin/lang/en.php index 3e0edabf8..f2f7cc5e5 100644 --- a/modules/admin/lang/en.php +++ b/modules/admin/lang/en.php @@ -81,11 +81,17 @@ $lang->about_server_ports = 'If your web server does not use 80 for HTTP or 443 $lang->use_db_session = 'Use Session DB'; $lang->about_db_session = 'This setting will use PHP session as DB during authentication. For the Websites which do not use web server frequently, you can uncheck this setting to improve response time. However, session DB will make it impossible to get current users, so you cannot use related functions.'; $lang->qmail_compatibility = 'Enable Qmail'; -$lang->minify_scripts = 'Auto-minify scripts'; +$lang->minify_scripts = 'Minify scripts'; $lang->cmd_minify_all = 'All files'; $lang->cmd_minify_common = 'Common files only'; $lang->cmd_minify_none = 'None'; $lang->about_minify_scripts = 'Automatically minify all CSS and JS scripts in the Core and all modules.'; +$lang->concat_scripts = 'Combine scripts'; +$lang->cmd_concat_none = 'Do not combine'; +$lang->cmd_concat_css_only = 'Combine all CSS'; +$lang->cmd_concat_js_only = 'Combine all JS'; +$lang->cmd_concat_css_js = 'Combine both CSS and JS'; +$lang->about_concat_scripts = 'Automatically combine CSS and JS scripts into as few files as possible. External scripts are not combined.'; $lang->use_gzip = 'gzip Compression'; $lang->delay_session = 'Delay session start'; $lang->about_delay_session = 'To improve performance when using a caching proxy server such as Varnish, do not issue sessions to visitors until they log in.
Selecting this option may cause view counts and visitor counts to become inaccurate.'; diff --git a/modules/admin/lang/ja.php b/modules/admin/lang/ja.php index caa9b2df6..be7615755 100644 --- a/modules/admin/lang/ja.php +++ b/modules/admin/lang/ja.php @@ -83,6 +83,12 @@ $lang->cmd_minify_all = '全てのファイルを圧縮'; $lang->cmd_minify_common = '共通のファイルを圧縮'; $lang->cmd_minify_none = '圧縮されません'; $lang->about_minify_scripts = 'コアとすべてのモジュールに含まれたCSS、JSファイルを自動的に圧縮(minify)して配信します。'; +$lang->concat_scripts = 'スクリプト自動結合'; +$lang->cmd_concat_none = '結合しません'; +$lang->cmd_concat_css_only = 'CSSのみ結合'; +$lang->cmd_concat_js_only = 'JSのみ結合'; +$lang->cmd_concat_css_js = 'CSSやJSの両方を結合'; +$lang->about_concat_scripts = 'CSS、JSファイルを一つにまとめて送信されます。外部からロードするスクリプトは、合わせてされません.'; $lang->use_gzip = 'gzip 圧縮'; $lang->delay_session = 'セッションの開始を遅延'; $lang->about_delay_session = 'Varnishなどのプロキシキャッシュサーバ使用時のパフォーマンスを向上させるために、ログインしていないユーザーには、認証セッションを付与しません。
このオプションを選択した場合、訪問者数とヒット集計が正確でない場合があります。'; diff --git a/modules/admin/lang/ko.php b/modules/admin/lang/ko.php index b115f00e9..4970668d2 100644 --- a/modules/admin/lang/ko.php +++ b/modules/admin/lang/ko.php @@ -85,7 +85,13 @@ $lang->minify_scripts = '스크립트 자동 압축'; $lang->cmd_minify_all = '모든 파일을 압축'; $lang->cmd_minify_common = '공통 파일만 압축'; $lang->cmd_minify_none = '압축하지 않음'; -$lang->about_minify_scripts = '코어와 모든 모듈에 포함된 CSS, JS 파일들을 자동으로 압축(minify)하여 전송합니다.'; +$lang->about_minify_scripts = 'CSS, JS 파일들을 자동으로 압축(minify)하여 전송합니다. 트래픽을 절약할 수 있습니다.'; +$lang->concat_scripts = '스크립트 합치기'; +$lang->cmd_concat_none = '합치지 않음'; +$lang->cmd_concat_css_only = 'CSS만 합침'; +$lang->cmd_concat_js_only = 'JS만 합침'; +$lang->cmd_concat_css_js = 'CSS와 JS를 모두 합침'; +$lang->about_concat_scripts = 'CSS, JS 파일들을 하나로 합쳐서 전송합니다. 외부에서 로딩하는 스크립트는 합쳐지지 않습니다.'; $lang->use_gzip = 'gzip 압축'; $lang->delay_session = '세션 시작 지연'; $lang->about_delay_session = 'Varnish 등의 프록시 캐싱 서버 사용시 성능 개선을 위해, 로그인하지 않은 사용자에게는 인증 세션을 부여하지 않습니다.
이 옵션을 선택할 경우 방문자 수 및 조회수 집계가 정확하게 이루어지지 않을 수 있습니다.'; diff --git a/modules/admin/tpl/config_advanced.html b/modules/admin/tpl/config_advanced.html index 2bc11806e..ee9ec8025 100644 --- a/modules/admin/tpl/config_advanced.html +++ b/modules/admin/tpl/config_advanced.html @@ -86,6 +86,17 @@

{$lang->about_minify_scripts}

+
+ +
+ + + + +
+

{$lang->about_concat_scripts}

+
+
diff --git a/modules/admin/tpl/config_general.html b/modules/admin/tpl/config_general.html index 3837dc106..76f7bc620 100644 --- a/modules/admin/tpl/config_general.html +++ b/modules/admin/tpl/config_general.html @@ -25,7 +25,7 @@
- +
diff --git a/modules/admin/tpl/css/admin.css b/modules/admin/tpl/css/admin.css index a0d16fea2..f38aa5585 100644 --- a/modules/admin/tpl/css/admin.css +++ b/modules/admin/tpl/css/admin.css @@ -1,6 +1,5 @@ @charset "utf-8"; - /* Reset */ html, body { @@ -497,7 +496,7 @@ margin-bottom: 10px; .x .x_form-horizontal .x_controls { margin-left: 0; } -; + } /* Custom Styles */ .x .section { @@ -674,7 +673,7 @@ margin-bottom: 10px; width: 90%; margin-left: -45%; } -; + } @media all and (max-width: 450px) { @@ -682,7 +681,7 @@ margin-bottom: 10px; width: 90%; margin-left: -45%; } -; + } .x_modal._common._nobody .x_modal-body, .x_modal._common._type_alert .x_modal-header, @@ -718,7 +717,7 @@ margin-bottom: 10px; float: none; width: auto; } -; + } /* Image Sprite */ .x a[target="_blank"]:after, @@ -740,7 +739,7 @@ margin-bottom: 10px; background-image: url(../img/glyphicons-halflings-white.png); background-repeat: no-repeat; } -; + } /* Layout */ .x>.skipNav { @@ -768,7 +767,6 @@ margin-bottom: 10px; zoom: 1; border-bottom: 1px solid #ddd; background-color: #fff; - zoom: 1; } .x>.header:after { content: ""; @@ -850,7 +848,7 @@ margin-bottom: 10px; .x>.body.wide>.gnb { width: auto; } -; + } /* Header */ .x>.header>h1 { @@ -928,23 +926,24 @@ margin-bottom: 10px; } .x>.header>.account .lang+#lang .x_active>a { color: #fff; - background: #0081c2 -webkit-linear-gradient(top, #0088cc, #0077b3); - background: #0081c2 -moz-linear-gradient(top, #0088cc, #0077b3); - background: #0081c2 -o-linear-gradient(top, #0088cc, #0077b3); + background-color: #0081c2; + background: -webkit-linear-gradient(top, #0088cc, #0077b3); + background: -moz-linear-gradient(top, #0088cc, #0077b3); + background: -o-linear-gradient(top, #0088cc, #0077b3); } @media all and (max-width: 480px) { .x>.header>.site { margin-top: 0; } -; + } @media all and (max-width: 800px) { .x>.header>.account { margin-top: 0; } -; + } /* Footer */ .x>.footer { @@ -1118,7 +1117,7 @@ margin-bottom: 10px; } .x>.body>.gnb>a[href="#gnbNav"] { opacity: .5; - filter: alpha(opacity=50%); + filter: alpha(opacity=50); } .x>.body>.gnb>a[href="#gnbNav"]:before { content: ""; @@ -1139,7 +1138,7 @@ margin-bottom: 10px; left: 50%; margin: -7px 0 0 -7px; } -; + } /* li */ .x>.body>.gnb>ul>li { @@ -1240,7 +1239,7 @@ margin-bottom: 10px; color: #fff; text-shadow: none; background: #222; - background: -webkit-linear-gradient(top,from(#555),to(#222)); + background: -webkit-linear-gradient(top,#555, #222); background: -moz-linear-gradient(top,#555,#222); background: -o-linear-gradient(top,#555,#222); } @@ -1427,7 +1426,7 @@ margin-bottom: 10px; color: #767676; } .x .dashboard>div>.member>h2:before { - background-position: -168px 0px; + background-position: -168px 0; } .x .dashboard>div>.document>h2:before { background-position: -264px -48px; @@ -1536,7 +1535,7 @@ margin-bottom: 10px; float: none !important; width: auto; } -; + } .x .g11n>.x_add-on { font-size: 0; @@ -1622,10 +1621,10 @@ html[lang="ko"] .x .g11n.active>[disabled], #g11n .flag.ko { background-image: url(../img/flag.ko.gif); } -html[lang="jp"] .x .g11n.active>[disabled], -#g11n .item .jp, -#g11n .flag.jp { - background-image: url(../img/flag.jp.gif); +html[lang="ja"] .x .g11n.active>[disabled], +#g11n .item .ja, +#g11n .flag.ja { + background-image: url(../img/flag.ja.gif); } html[lang="zh"] .x .g11n.active>[disabled], #g11n .item .zh-CN, @@ -1767,7 +1766,7 @@ html[lang="mn"] .x .g11n.active>[disabled], border: 0; cursor: n-resize; white-space: nowrap; - font-size: 0px; + font-size: 0; } /* Favicon Preview */ .x #faviconPreview { @@ -2415,10 +2414,10 @@ html:lang(ko) .x textarea, html:lang(ko) .x select, html:lang(ko) .x button{font-family: 'NanumGothic', 'Malgun Gothic', 'Apple SD Gothic Neo', 'Dotum', Arial, Helvetica, sans-serif} -/* Japanese admin_jp.css */ +/* Japanese admin_ja.css */ html:lang(ja) body>.x, html:lang(ja) .x table, html:lang(ja) .x input, html:lang(ja) .x textarea, html:lang(ja) .x select, -html:lang(ja) .x button{font-family:'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS Pゴシック',sans-serif} \ No newline at end of file +html:lang(ja) .x button{font-family:'ヒラギノ角ゴ Pro W3','Hiragino Kaku Gothic Pro','メイリオ',Meiryo,'MS Pゴシック',sans-serif} diff --git a/modules/admin/tpl/img/flag.ja.gif b/modules/admin/tpl/img/flag.ja.gif new file mode 100644 index 000000000..d5fe72de4 Binary files /dev/null and b/modules/admin/tpl/img/flag.ja.gif differ diff --git a/modules/board/board.controller.php b/modules/board/board.controller.php index 4b726a63a..dfe95b9ff 100644 --- a/modules/board/board.controller.php +++ b/modules/board/board.controller.php @@ -88,7 +88,7 @@ class boardController extends board $obj->member_srl = -1*$logged_info->member_srl; } $obj->email_address = $obj->homepage = $obj->user_id = ''; - $obj->user_name = $obj->nick_name = 'anonymous'; + $obj->user_name = $obj->nick_name = $this->createAnonymousName($this->module_info->anonymous_name ?: 'anonymous', $logged_info->member_srl, $obj->document_srl); $bAnonymous = true; if($is_update===false) { @@ -187,7 +187,7 @@ class boardController extends board $oMail = new Mail(); $oMail->setTitle($obj->title); $oMail->setContent( sprintf("From : %s
\r\n%s", getFullUrl('','document_srl',$obj->document_srl), getFullUrl('','document_srl',$obj->document_srl), $obj->content)); - $oMail->setSender($obj->user_name ? $obj->user_name : 'anonymous', $obj->email_address ? $obj->email_address : $member_config->webmaster_email); + $oMail->setSender($obj->user_name ?: null, $obj->email_address ? $obj->email_address : $member_config->webmaster_email); $target_mail = explode(',',$this->module_info->admin_mail); for($i=0;$inotify_message = 'N'; $obj->member_srl = -1*$logged_info->member_srl; $obj->email_address = $obj->homepage = $obj->user_id = ''; - $obj->user_name = $obj->nick_name = 'anonymous'; + $obj->user_name = $obj->nick_name = $this->createAnonymousName($this->module_info->anonymous_name ?: 'anonymous', $logged_info->member_srl, $obj->document_srl); $bAnonymous = true; } else @@ -632,4 +632,38 @@ class boardController extends board return new Object(); } + + /** + * Create an anonymous nickname. + * + * @param string $format + * @param int $member_srl + * @param int $document_srl + * @return string + */ + public function createAnonymousName($format, $member_srl, $document_srl) + { + if (strpos($format, '$NUM') !== false) + { + $num = hash_hmac('sha256', $member_srl ?: \RX_CLIENT_IP, config('crypto.authentication_key')); + $num = sprintf('%08d', hexdec(substr($num, 0, 8)) % 100000000); + return strtr($format, array('$NUM' => $num)); + } + elseif (strpos($format, '$DAILYNUM') !== false) + { + $num = hash_hmac('sha256', ($member_srl ?: \RX_CLIENT_IP) . ':date:' . date('Y-m-d'), config('crypto.authentication_key')); + $num = sprintf('%08d', hexdec(substr($num, 0, 8)) % 100000000); + return strtr($format, array('$DAILYNUM' => $num)); + } + elseif (strpos($format, '$DOCNUM') !== false) + { + $num = hash_hmac('sha256', ($member_srl ?: \RX_CLIENT_IP) . ':document_srl:' . $document_srl, config('crypto.authentication_key')); + $num = sprintf('%08d', hexdec(substr($num, 0, 8)) % 100000000); + return strtr($format, array('$DOCNUM' => $num)); + } + else + { + return $format; + } + } } diff --git a/modules/board/lang/ko.php b/modules/board/lang/ko.php index 23e90484a..b0c8c3414 100644 --- a/modules/board/lang/ko.php +++ b/modules/board/lang/ko.php @@ -2,6 +2,7 @@ $lang->board = '게시판'; $lang->except_notice = '공지사항 제외'; $lang->use_anonymous = '익명 사용'; +$lang->anonymous_name = '익명 닉네임'; $lang->cmd_manage_menu = '메뉴관리'; $lang->list_target_item = '대상 항목'; $lang->list_display_item = '표시 항목'; @@ -26,6 +27,7 @@ $lang->about_layout_setup = '블로그의 레이아웃 코드를 직접 수정 $lang->about_board_category = '분류를 만들 수 있습니다. 분류가 오동작을 할 경우 캐시파일 재생성을 수동으로 해주시면 해결이 될 수 있습니다.'; $lang->about_except_notice = '목록 상단에 늘 나타나는 공지사항을 일반 목록에서 공지사항을 출력하지 않도록 합니다.'; $lang->about_use_anonymous = '글쓴이의 정보를 없애고 익명으로 게시판 사용을 할 수 있게 합니다. 스킨설정에서 글쓴이 정보등을 보이지 않도록 하시면 더욱 유용합니다. 추가설정의 문서 히스토리 사용이 꺼져있지 않으면 문서 수정시 작성자가 표시될 수 있습니다.'; +$lang->about_anonymous_name = '익명 기능을 사용할 때 표시할 익명 닉네임을 정할 수 있습니다.
$NUM을 사용하면 회원마다 고유한 난수를 부여할 수 있습니다. (예: 익명_$NUM → 익명_12345678)
$DAILYNUM을 사용하면 매일 난수가 변경되고, $DOCNUM을 사용하면 문서마다 변경됩니다.'; $lang->about_board = '게시판을 생성하고 관리할 수 있습니다.'; $lang->about_consultation = '상담 기능은 관리권한이 없는 회원은 자신이 쓴 글만 보이도록 하는 기능입니다. 단 상담기능 사용시 비회원 글쓰기는 자동으로 금지됩니다.'; $lang->about_secret = '게시판 및 댓글의 비밀글 기능을 사용할 수 있도록 합니다.'; diff --git a/modules/board/skins/default/_comment.html b/modules/board/skins/default/_comment.html index 99c6983ac..ada266cb0 100644 --- a/modules/board/skins/default/_comment.html +++ b/modules/board/skins/default/_comment.html @@ -9,9 +9,9 @@ Profile

- {$comment->getNickName()} - {$comment->getNickName()} - {$comment->getNickName()} + {$comment->getNickName()} + {$comment->getNickName()} + {$comment->getNickName()}

{$comment->getRegdate('Y.m.d H:i')}

diff --git a/modules/board/skins/default/_read.html b/modules/board/skins/default/_read.html index 280c3461e..f99b11ab1 100644 --- a/modules/board/skins/default/_read.html +++ b/modules/board/skins/default/_read.html @@ -9,9 +9,9 @@ {$oDocument->getRegdate('Y.m.d H:i')}

- {$oDocument->getNickName()} - {$oDocument->getNickName()} - {$oDocument->getNickName()} + {$oDocument->getNickName()} + {$oDocument->getNickName()} + {$oDocument->getNickName()} {$lang->readed_count}:{$oDocument->get('readed_count')} {$lang->cmd_vote}:{$oDocument->get('voted_count')} diff --git a/modules/board/skins/xedition/_comment.html b/modules/board/skins/xedition/_comment.html index fabb798c7..e2fffcbbd 100644 --- a/modules/board/skins/xedition/_comment.html +++ b/modules/board/skins/xedition/_comment.html @@ -9,9 +9,9 @@ Profile

- {$comment->getNickName()} - {$comment->getNickName()} - {$comment->getNickName()} + {$comment->getNickName()} + {$comment->getNickName()} + {$comment->getNickName()}

{$comment->getRegdate('Y.m.d H:i')}

diff --git a/modules/board/skins/xedition/_read.html b/modules/board/skins/xedition/_read.html index f0102cb25..8558205ec 100644 --- a/modules/board/skins/xedition/_read.html +++ b/modules/board/skins/xedition/_read.html @@ -7,9 +7,9 @@

- {$oDocument->getNickName()} - {$oDocument->getNickName()} - {$oDocument->getNickName()} + {$oDocument->getNickName()} + {$oDocument->getNickName()} + {$oDocument->getNickName()} {$oDocument->getRegdate('Y.m.d H:i')} diff --git a/modules/board/tpl/board_insert.html b/modules/board/tpl/board_insert.html index 0dbdcb961..d7b3ae8da 100644 --- a/modules/board/tpl/board_insert.html +++ b/modules/board/tpl/board_insert.html @@ -205,6 +205,14 @@

+
+ +
+ + {$lang->help} + +
+
diff --git a/modules/comment/comment.admin.view.php b/modules/comment/comment.admin.view.php index 0ea4d7bb3..057eb978e 100644 --- a/modules/comment/comment.admin.view.php +++ b/modules/comment/comment.admin.view.php @@ -67,6 +67,7 @@ class commentAdminView extends comment Context::set('page_navigation', $output->page_navigation); Context::set('secret_name_list', $secretNameList); + // Module List $oModuleModel = getModel('module'); $module_list = array(); $mod_srls = array(); @@ -75,7 +76,6 @@ class commentAdminView extends comment $mod_srls[] = $val->module_srl; } $mod_srls = array_unique($mod_srls); - // Module List $mod_srls_count = count($mod_srls); if($mod_srls_count) { @@ -90,7 +90,32 @@ class commentAdminView extends comment } } Context::set('module_list', $module_list); - + + // Get anonymous nicknames + $anonymous_member_srls = array(); + foreach($output->data as $val) + { + if($val->get('member_srl') < 0) + { + $anonymous_member_srls[] = abs($val->get('member_srl')); + } + } + if($anonymous_member_srls) + { + $member_args = new stdClass(); + $member_args->member_srl = $anonymous_member_srls; + $member_output = executeQueryArray('member.getMembers', $member_args); + if($member_output) + { + $member_nick_neme = array(); + foreach($member_output->data as $member) + { + $member_nick_neme[$member->member_srl] = $member->nick_name; + } + } + } + Context::set('member_nick_name', $member_nick_neme); + // set the template $this->setTemplatePath($this->module_path . 'tpl'); $this->setTemplateFile('comment_list'); diff --git a/modules/comment/comment.item.php b/modules/comment/comment.item.php index 9242cc3bd..5856a735a 100644 --- a/modules/comment/comment.item.php +++ b/modules/comment/comment.item.php @@ -496,7 +496,7 @@ class commentItem extends Object */ function getProfileImage() { - if(!$this->isExists() || !$this->get('member_srl')) + if(!$this->isExists() || $this->get('member_srl') <= 0) { return; } @@ -517,7 +517,7 @@ class commentItem extends Object function getSignature() { // pass if the posting not exists. - if(!$this->isExists() || !$this->get('member_srl')) + if(!$this->isExists() || $this->get('member_srl') <= 0) { return; } diff --git a/modules/comment/tpl/comment_list.html b/modules/comment/tpl/comment_list.html index 40f8be128..4ce9ff983 100644 --- a/modules/comment/tpl/comment_list.html +++ b/modules/comment/tpl/comment_list.html @@ -53,7 +53,11 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}'; {$comment}{$lang->no_text_comment} - {$val->getNickName()} + + {$val->getNickName()} + ({$member_nick_name[abs($val->get('member_srl'))]}) + {$val->getNickName()} + {number_format($val->get('voted_count'))}/{number_format($val->get('blamed_count'))} {(zdate($val->regdate,"Y-m-d\nH:i:s"))} {$val->ipaddress} diff --git a/modules/document/document.admin.view.php b/modules/document/document.admin.view.php index 5e322fc38..44d5ac579 100644 --- a/modules/document/document.admin.view.php +++ b/modules/document/document.admin.view.php @@ -72,13 +72,34 @@ class documentAdminView extends document } Context::set('search_option', $search_option); + // Module List $oModuleModel = getModel('module'); $module_list = array(); $mod_srls = array(); - $anonymous_member_srls = array(); foreach($output->data as $oDocument) { $mod_srls[] = $oDocument->get('module_srl'); + } + $mod_srls = array_unique($mod_srls); + $mod_srls_count = count($mod_srls); + if($mod_srls_count) + { + $columnList = array('module_srl', 'mid', 'browser_title'); + $module_output = $oModuleModel->getModulesInfo($mod_srls, $columnList); + if($module_output && is_array($module_output)) + { + foreach($module_output as $module) + { + $module_list[$module->module_srl] = $module; + } + } + } + Context::set('module_list', $module_list); + + // Get anonymous nicknames + $anonymous_member_srls = array(); + foreach($output->data as $oDocument) + { if($oDocument->get('member_srl') < 0) { $anonymous_member_srls[] = abs($oDocument->get('member_srl')); @@ -99,22 +120,6 @@ class documentAdminView extends document } } Context::set('member_nick_name', $member_nick_neme); - $mod_srls = array_unique($mod_srls); - // Module List - $mod_srls_count = count($mod_srls); - if($mod_srls_count) - { - $columnList = array('module_srl', 'mid', 'browser_title'); - $module_output = $oModuleModel->getModulesInfo($mod_srls, $columnList); - if($module_output && is_array($module_output)) - { - foreach($module_output as $module) - { - $module_list[$module->module_srl] = $module; - } - } - } - Context::set('module_list', $module_list); // Specify a template $this->setTemplatePath($this->module_path.'tpl'); diff --git a/modules/document/document.item.php b/modules/document/document.item.php index 63b8747e6..9b38b216a 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -1168,7 +1168,7 @@ class documentItem extends Object */ function getProfileImage() { - if(!$this->isExists() || !$this->get('member_srl')) return; + if(!$this->isExists() || $this->get('member_srl') <= 0) return; $oMemberModel = getModel('member'); $profile_info = $oMemberModel->getProfileImage($this->get('member_srl')); if(!$profile_info) return; @@ -1183,7 +1183,7 @@ class documentItem extends Object function getSignature() { // Pass if a document doesn't exist - if(!$this->isExists() || !$this->get('member_srl')) return; + if(!$this->isExists() || $this->get('member_srl') <= 0) return; // Get signature information $oMemberModel = getModel('member'); $signature = $oMemberModel->getSignature($this->get('member_srl')); diff --git a/modules/document/queries/getDocumentSrlByTitle.xml b/modules/document/queries/getDocumentSrlByTitle.xml index ff2cb5512..fa1cb49f3 100644 --- a/modules/document/queries/getDocumentSrlByTitle.xml +++ b/modules/document/queries/getDocumentSrlByTitle.xml @@ -1,4 +1,4 @@ - +
diff --git a/modules/document/tpl/document_list.html b/modules/document/tpl/document_list.html index 82c917227..a4f6afcdc 100644 --- a/modules/document/tpl/document_list.html +++ b/modules/document/tpl/document_list.html @@ -53,8 +53,9 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}'; {htmlspecialchars($oDocument->getTitleText())}{$lang->no_title_document} diff --git a/modules/editor/editor.admin.controller.php b/modules/editor/editor.admin.controller.php index baf7750a3..fa2660fd4 100644 --- a/modules/editor/editor.admin.controller.php +++ b/modules/editor/editor.admin.controller.php @@ -146,25 +146,30 @@ class editorAdminController extends editor $configVars = Context::getRequestVars(); $config = new stdClass; - if($configVars->font_defined != 'Y') $config->font_defined = $configVars->font_defined = 'N'; - else $config->font_defined = 'Y'; - - if($config->font_defined == 'Y') - $config->content_font = $configVars->content_font_defined; - else - $config->content_font = $configVars->content_font; - $config->editor_skin = $configVars->editor_skin; $config->editor_height = $configVars->editor_height; $config->comment_editor_skin = $configVars->comment_editor_skin; $config->comment_editor_height = $configVars->comment_editor_height; $config->content_style = $configVars->content_style; - - $config->content_font_size= $configVars->content_font_size.'px'; $config->sel_editor_colorset= $configVars->sel_editor_colorset; $config->sel_comment_editor_colorset= $configVars->sel_comment_editor_colorset; + + if ($configVars->font_defined === 'Y') + { + $config->font_defined = 'Y'; + $config->content_font = $configVars->content_font_defined; + } + else + { + $config->font_defined = $configVars->font_defined = 'N'; + $config->content_font = $configVars->content_font; + } + $config->content_font_size = intval($configVars->content_font_size) . 'px'; + $config->content_line_height = intval($configVars->content_line_height) . '%'; + $config->content_paragraph_spacing = intval($configVars->content_paragraph_spacing) . 'px'; + $config->content_word_break = $configVars->content_word_break; - $oModuleController->insertModuleConfig('editor',$config); + $oModuleController->insertModuleConfig('editor', $config); $this->setRedirectUrl(Context::get('error_return_url')); } diff --git a/modules/editor/editor.admin.view.php b/modules/editor/editor.admin.view.php index 48e3c1383..e90ba5649 100644 --- a/modules/editor/editor.admin.view.php +++ b/modules/editor/editor.admin.view.php @@ -74,7 +74,7 @@ class editorAdminView extends editor { if($packages[$xml_info->package_srl]) $xml_info->need_update = $packages[$xml_info->package_srl]->need_update; } - $editor_config_default = array( "editor_height" => "300", "comment_editor_height" => "100","content_font_size"=>"13"); + $editor_config_default = array('editor_height' => 300, 'comment_editor_height' => 100); //editor preview $config = $oEditorModel->getEditorConfig(); @@ -84,6 +84,9 @@ class editorAdminView extends editor $option->content_style = $config->content_style; $option->content_font = $config->content_font; $option->content_font_size = $config->content_font_size; + $option->content_line_height = $config->content_line_height; + $option->content_paragraph_spacing = $config->content_paragraph_spacing; + $option->content_word_break = $config->content_word_break; $option->enable_autosave = false; $option->enable_default_component = true; $option->enable_component = true; @@ -102,6 +105,9 @@ class editorAdminView extends editor $option_com->content_style = $config->content_style; $option_com->content_font = $config->content_font; $option_com->content_font_size = $config->content_font_size; + $option_com->content_line_height = $config->content_line_height; + $option_com->content_paragraph_spacing = $config->content_paragraph_spacing; + $option_com->content_word_break = $config->content_word_break; $option_com->enable_autosave = false; $option_com->enable_default_component = true; $option_com->enable_component = true; diff --git a/modules/editor/editor.controller.php b/modules/editor/editor.controller.php index b1a97de71..9479be8c3 100644 --- a/modules/editor/editor.controller.php +++ b/modules/editor/editor.controller.php @@ -86,6 +86,8 @@ class editorController extends editor else $module_srl = array($module_srl); $editor_config = new stdClass; + $editor_config->default_editor_settings = Context::get('default_editor_settings'); + if($editor_config->default_editor_settings !== 'Y') $editor_config->default_editor_settings = 'N'; $editor_config->editor_skin = Context::get('editor_skin'); $editor_config->comment_editor_skin = Context::get('comment_editor_skin'); $editor_config->content_style = Context::get('content_style'); @@ -157,8 +159,15 @@ class editorController extends editor $module_srl = $module_info->module_srl; if($module_srl) { - $oEditorModel = getModel('editor'); - $editor_config = $oEditorModel->getEditorConfig($module_srl); + $editor_config = getModel('editor')->getEditorConfig($module_srl); + } + else + { + $editor_config = getModel('module')->getModuleConfig('editor'); + } + + if ($editor_config) + { $content_style = $editor_config->content_style; if($content_style) { @@ -182,17 +191,53 @@ class editorController extends editor } } } - $content_font = $editor_config->content_font; - $content_font_size = $editor_config->content_font_size; - if($content_font || $content_font_size) + + Context::set('default_font_config', array( + 'default_font_family' => $editor_config->content_font ?: 'inherit', + 'default_font_size' => $editor_config->content_font_size ?: '13px', + 'default_line_height' => $editor_config->content_line_height ?: '160%', + 'default_paragraph_spacing' => $editor_config->content_paragraph_spacing ?: '0', + 'default_word_break' => $editor_config->content_word_break ?: 'normal', + )); + + /* + $buff = array(); + $buff[] = ''; - Context::addHtmlHeader(implode('', $buff)); + $buff[] = "font-family: $content_font;"; } + if ($content_font_size) + { + $buff[] = "font-size: $content_font_size;"; + } + if ($content_line_height) + { + $buff[] = "line-height: $content_line_height;"; + } + if ($content_word_break === 'none') + { + $buff[] = 'white-space: nowrap;'; + } + else + { + $buff[] = 'word-break: ' . ($content_word_break ?: 'normal') . '; word-wrap: break-word;'; + } + $buff[] = '}'; + $buff[] = '.xe_content p { margin: 0 0 ' . ($content_paragraph_spacing ?: 0) . ' 0; }'; + $buff[] = ''; + Context::addHtmlHeader(implode(' ', $buff)); + */ + } + else + { + Context::set('default_font_config', array( + 'default_font_family' => 'inherit', + 'default_font_size' => '13px', + 'default_line_height' => '160%', + 'default_paragraph_spacing' => '0', + 'default_word_break' => 'normal', + )); } $content = $this->transComponent($content); diff --git a/modules/editor/editor.model.php b/modules/editor/editor.model.php index 5a95186b5..fb71bffdf 100644 --- a/modules/editor/editor.model.php +++ b/modules/editor/editor.model.php @@ -46,45 +46,66 @@ class editorModel extends editor if(!is_array($editor_config->enable_component_grant)) $editor_config->enable_component_grant = array(); if(!is_array($editor_config->enable_comment_component_grant)) $editor_config->enable_comment_component_grant= array(); - if(!$editor_config->editor_height) + if($editor_config->default_editor_settings !== 'Y' && $editor_default_config->editor_skin && $editor_config->editor_skin && $editor_default_config->editor_skin !== $editor_config->editor_skin) + { + $editor_config->default_editor_settings = 'N'; + } + if(!$editor_config->default_editor_settings) + { + $editor_config->default_editor_settings = 'Y'; + } + + if(!$editor_config->editor_height || $editor_config->default_editor_settings === 'Y') { $editor_config->editor_height = ($editor_default_config->editor_height) ? $editor_default_config->editor_height : 500; } - if(!$editor_config->comment_editor_height) + if(!$editor_config->comment_editor_height || $editor_config->default_editor_settings === 'Y') { $editor_config->comment_editor_height = ($editor_default_config->comment_editor_height) ? $editor_default_config->comment_editor_height : 120; } - if(!$editor_config->editor_skin) + if(!$editor_config->editor_skin || $editor_config->default_editor_settings === 'Y') { $editor_config->editor_skin = ($editor_default_config->editor_skin) ? $editor_default_config->editor_skin : 'ckeditor'; } - if(!$editor_config->comment_editor_skin) + if(!$editor_config->comment_editor_skin || $editor_config->default_editor_settings === 'Y') { $editor_config->comment_editor_skin = ($editor_default_config->comment_editor_skin) ? $editor_default_config->comment_editor_skin : 'ckeditor'; } - if(!$editor_config->content_style) + if(!$editor_config->content_style || $editor_config->default_editor_settings === 'Y') { $editor_config->content_style = ($editor_default_config->content_style) ? $editor_default_config->content_style : 'ckeditor_light'; } - if(!$editor_config->content_font && $editor_default_config->content_font) + if((!$editor_config->content_font && $editor_default_config->content_font) || $editor_config->default_editor_settings === 'Y') { $editor_config->content_font = $editor_default_config->content_font; } - if(!$editor_config->content_font_size && $editor_default_config->content_font_size) + if((!$editor_config->content_font_size && $editor_default_config->content_font_size) || $editor_config->default_editor_settings === 'Y') { $editor_config->content_font_size = $editor_default_config->content_font_size; } - if(!$editor_config->sel_editor_colorset && $editor_default_config->sel_editor_colorset) + if((!$editor_config->content_line_height && $editor_default_config->content_line_height) || $editor_config->default_editor_settings === 'Y') + { + $editor_config->content_line_height = $editor_default_config->content_line_height; + } + if((!$editor_config->content_paragraph_spacing && $editor_default_config->content_paragraph_spacing) || $editor_config->default_editor_settings === 'Y') + { + $editor_config->content_paragraph_spacing = $editor_default_config->content_paragraph_spacing; + } + if((!$editor_config->content_word_break && $editor_default_config->content_word_break) || $editor_config->default_editor_settings === 'Y') + { + $editor_config->content_word_break = $editor_default_config->content_word_break; + } + if((!$editor_config->sel_editor_colorset && $editor_default_config->sel_editor_colorset) || $editor_config->default_editor_settings === 'Y') { $editor_config->sel_editor_colorset = $editor_default_config->sel_editor_colorset; } - if(!$editor_config->sel_comment_editor_colorset && $editor_default_config->sel_comment_editor_colorset) + if((!$editor_config->sel_comment_editor_colorset && $editor_default_config->sel_comment_editor_colorset) || $editor_config->default_editor_settings === 'Y') { $editor_config->sel_comment_editor_colorset = $editor_default_config->sel_comment_editor_colorset; } - if(!$editor_config->comment_content_style && $editor_default_config->comment_content_style) + if(!$editor_config->comment_content_style || $editor_config->default_editor_settings === 'Y') { - $editor_config->comment_content_style = $editor_default_config->comment_content_style; + $editor_config->comment_content_style = ($editor_default_config->comment_content_style) ? $editor_default_config->comment_content_style : 'ckeditor_light'; } return $editor_config; @@ -209,8 +230,11 @@ class editorModel extends editor Context::set('content_style', $option->content_style); Context::set('content_style_path', $this->module_path . 'styles/' . $option->content_style); // Default font setting - Context::set('content_font', addslashes($option->content_font)); + Context::set('content_font', $option->content_font); Context::set('content_font_size', $option->content_font_size); + Context::set('content_line_height', $option->content_line_height); + Context::set('content_paragraph_spacing', $option->content_paragraph_spacing); + Context::set('content_word_break', $option->content_word_break); // Option setting to allow auto-save if(!$option->enable_autosave) $enable_autosave = false; @@ -370,6 +394,9 @@ class editorModel extends editor $config->content_style = $editor_config->content_style; $config->content_font = $editor_config->content_font; $config->content_font_size = $editor_config->content_font_size; + $config->content_line_height = $editor_config->content_line_height; + $config->content_paragraph_spacing = $editor_config->content_paragraph_spacing; + $config->content_word_break = $editor_config->content_word_break; $config->sel_editor_colorset = $editor_config->sel_editor_colorset; $config->upload_file_grant = $editor_config->upload_file_grant; $config->enable_default_component_grant = $editor_config->enable_default_component_grant; @@ -384,6 +411,9 @@ class editorModel extends editor $config->content_style = $editor_config->comment_content_style; $config->content_font = $editor_config->content_font; $config->content_font_size = $editor_config->content_font_size; + $config->content_line_height = $editor_config->content_line_height; + $config->content_paragraph_spacing = $editor_config->content_paragraph_spacing; + $config->content_word_break = $editor_config->content_word_break; $config->sel_editor_colorset = $editor_config->sel_comment_editor_colorset; $config->upload_file_grant = $editor_config->comment_upload_file_grant; $config->enable_default_component_grant = $editor_config->enable_comment_default_component_grant; @@ -409,6 +439,9 @@ class editorModel extends editor $option->content_style = $config->content_style; $option->content_font = $config->content_font; $option->content_font_size = $config->content_font_size; + $option->content_line_height = $config->content_line_height; + $option->content_paragraph_spacing = $config->content_paragraph_spacing; + $option->content_word_break = $config->content_word_break; $option->colorset = $config->sel_editor_colorset; // Permission check for file upload $option->allow_fileupload = false; diff --git a/modules/editor/editor.view.php b/modules/editor/editor.view.php index d0dd2777b..01f8b5da9 100644 --- a/modules/editor/editor.view.php +++ b/modules/editor/editor.view.php @@ -108,7 +108,7 @@ class editorView extends editor $info = $oModuleModel->loadSkinInfo($this->module_path,$style,'styles'); $content_style_list[$style] = new stdClass(); $content_style_list[$style]->title = $info->title; - } + } Context::set('content_style_list', $content_style_list); // Get a group list $oMemberModel = getModel('member'); @@ -121,7 +121,7 @@ class editorView extends editor $security->encodeHTML('group_list..title'); $security->encodeHTML('group_list..description'); $security->encodeHTML('content_style_list..'); - $security->encodeHTML('editor_comment_colorset_list..title'); + $security->encodeHTML('editor_comment_colorset_list..title'); // Set a template file $oTemplate = &TemplateHandler::getInstance(); @@ -161,6 +161,9 @@ class editorView extends editor $option_com->content_style = $config->content_style; $option_com->content_font = $config->content_font; $option_com->content_font_size = $config->content_font_size; + $option_com->content_line_height = $config->content_line_height; + $option_com->content_paragraph_spacing = $config->content_paragraph_spacing; + $option_com->content_word_break = $config->content_word_break; $option_com->enable_autosave = false; $option_com->enable_default_component = true; $option_com->enable_component = true; @@ -180,6 +183,9 @@ class editorView extends editor $option->content_style = $config->content_style; $option->content_font = $config->content_font; $option->content_font_size = $config->content_font_size; + $option->content_line_height = $config->content_line_height; + $option->content_paragraph_spacing = $config->content_paragraph_spacing; + $option->content_word_break = $config->content_word_break; $option->enable_autosave = false; $option->enable_default_component = true; $option->enable_component = true; diff --git a/modules/editor/lang/en.php b/modules/editor/lang/en.php index cbdbe5a99..12d32fbdd 100644 --- a/modules/editor/lang/en.php +++ b/modules/editor/lang/en.php @@ -2,14 +2,22 @@ $lang->editor_component = 'Editor Component'; $lang->main_editor = 'Main editor'; $lang->comment_editor = 'Comment editor'; -$lang->editor_option = 'Editor Option'; -$lang->guide_choose_main_editor = 'Main editor.'; -$lang->guide_set_height_main_editor = 'Height of the main editor.'; -$lang->guide_choose_comment_editor = 'Comment editor.'; -$lang->guide_set_height_comment_editor = 'Height of the comment editor.'; -$lang->guide_choose_text_formatting = 'Text formatting'; -$lang->guide_choose_font_body = 'Font body'; -$lang->guide_choose_font_size_body = 'Size body'; +$lang->editor_option = 'Editor Options'; +$lang->guide_choose_main_editor = 'Main editor'; +$lang->guide_set_height_main_editor = 'Main editor height'; +$lang->guide_choose_comment_editor = 'Comment editor'; +$lang->guide_set_height_comment_editor = 'Comment editor height'; +$lang->guide_choose_text_formatting = 'Text formatting style'; +$lang->guide_choose_font_preview = 'Preview'; +$lang->guide_choose_font_body = 'Default font'; +$lang->guide_choose_font_size_body = 'Default font size'; +$lang->guide_choose_line_height = 'Line spacing'; +$lang->guide_choose_paragraph_spacing = 'Paragraph spacing'; +$lang->guide_choose_word_break = 'Line wrapping'; +$lang->word_break_normal = 'Wrap Asian scripts at character boundary and Latin scripts at word boundary (default)'; +$lang->word_break_keep_all = 'Wrap at word boundary'; +$lang->word_break_break_all = 'Wrap at character boundary'; +$lang->word_break_none = 'Do not wrap long lines'; $lang->font_preview = 'The quick brown fox jumps over the lazy dog. いろはにほへと / ちりぬるを / わかよたれそ / つねならむ / うゐのおくやま / けふこえて / あさきゆめみし / ゑひもせす 키스의 고유 조건은 입술끼리 만나야 하고 특별한 기술은 필요치 않다.'; @@ -41,6 +49,7 @@ $lang->msg_auto_saved = 'Automatically Saved.'; $lang->cmd_disable = 'Inactive'; $lang->cmd_enable = 'Active'; $lang->cmd_select_cover = 'Be a cover image'; +$lang->default_editor_settings = 'Default settings for this module'; $lang->editor_skin = 'Editor Skin'; $lang->upload_file_grant = 'Permission to upload files'; $lang->enable_default_component_grant = 'Permission to use default components'; @@ -49,6 +58,7 @@ $lang->enable_html_grant = 'Permission to edit HTML'; $lang->enable_autosave = 'Enable Auto-Save'; $lang->height_resizable = 'Height Resizable'; $lang->editor_height = 'Height of Editor'; +$lang->about_default_editor_settings = 'Follow editor settings of Rhymix Admin page through whole site.'; $lang->about_content_font = 'Please use comma for multiple input.'; $lang->about_content_font_size = 'Please input units such as px or em.'; $lang->about_enable_autosave = 'You may decide whether the auto-save function will be used.'; @@ -59,11 +69,14 @@ $lang->edit['fontlist']['arial'] = 'Arial, Helvetica, sans-serif'; $lang->edit['fontlist']['tahoma'] = 'Tahoma, Geneva, sans-serif'; $lang->edit['fontlist']['verdana'] = 'Verdana, Geneva, sans-serif'; $lang->edit['fontlist']['sans-serif'] = 'Sans-serif'; -$lang->edit['fontlist']['georgia'] = 'Georgia, \'Times New Roman\', Times, serif'; -$lang->edit['fontlist']['palatinoLinotype'] = '\'Palatino Linotype\', \'Book Antiqua\', Palatino, serif'; -$lang->edit['fontlist']['timesNewRoman'] = '\'Times New Roman\', Times, serif'; +$lang->edit['fontlist']['georgia'] = 'Georgia, Times New Roman, Times, serif'; +$lang->edit['fontlist']['palatinoLinotype'] = 'Palatino Linotype, Book Antiqua, Palatino, serif'; +$lang->edit['fontlist']['timesNewRoman'] = 'Times New Roman, Times, serif'; $lang->edit['fontlist']['serif'] = 'Serif'; -$lang->edit['fontlist']['courierNew'] = '\'Courier New\', Courier, monospace'; +$lang->edit['fontlist']['consolas'] = 'Consolas, monospace'; +$lang->edit['fontlist']['courierNew'] = 'Courier New, Courier, monospace'; +$lang->edit['fontlist']['lucidaConsole'] = 'Lucida Console, Monaco, monospace'; +$lang->edit['fontlist']['monospace'] = 'Monospace'; $lang->edit['header'] = 'Style'; $lang->edit['header_list']['h1'] = 'Header 1'; $lang->edit['header_list']['h2'] = 'Header 2'; diff --git a/modules/editor/lang/ja.php b/modules/editor/lang/ja.php index f4ae0102e..0f9b0f163 100644 --- a/modules/editor/lang/ja.php +++ b/modules/editor/lang/ja.php @@ -56,9 +56,9 @@ $lang->about_enable_autosave = '書き込みの際に自動保存機能をオン $lang->edit['fontname'] = 'フォント'; $lang->edit['fontsize'] = 'フォントサイズ'; $lang->edit['use_paragraph'] = '段落機能'; -$lang->edit['fontlist']['meiryo'] = '\'メイリオ\', \'Meiryo\', Arial, Helvetica, sans-serif'; -$lang->edit['fontlist']['hiragino'] = '\'ヒラギノ角ゴ Pro\', \'Hiragino Kaku Gothic Pro\', Arial, Helvetica, sans-serif'; -$lang->edit['fontlist']['ms_pgothic'] = '\'MS Pゴシック\', \'MS PGothic\', Arial, Helvetica, sans-serif'; +$lang->edit['fontlist']['meiryo'] = 'メイリオ, Meiryo, Arial, Helvetica, sans-serif'; +$lang->edit['fontlist']['hiragino'] = 'ヒラギノ角ゴ Pro, Hiragino Kaku Gothic Pro, Arial, Helvetica, sans-serif'; +$lang->edit['fontlist']['ms_pgothic'] = 'MS Pゴシック, MS PGothic, Arial, Helvetica, sans-serif'; $lang->edit['header'] = '書式'; $lang->edit['header_list']['h1'] = '見出し1'; $lang->edit['header_list']['h2'] = '見出し2'; diff --git a/modules/editor/lang/ko.php b/modules/editor/lang/ko.php index 3df0e1144..4d3aeb1a4 100644 --- a/modules/editor/lang/ko.php +++ b/modules/editor/lang/ko.php @@ -9,8 +9,16 @@ $lang->guide_set_height_main_editor = '본문 에디터 높이'; $lang->guide_choose_comment_editor = '댓글 에디터'; $lang->guide_set_height_comment_editor = '댓글 에디터 높이'; $lang->guide_choose_text_formatting = '본문 서식'; +$lang->guide_choose_font_preview = '미리보기'; $lang->guide_choose_font_body = '본문 글꼴'; -$lang->guide_choose_font_size_body = '본문 글꼴크기'; +$lang->guide_choose_font_size_body = '글꼴 크기'; +$lang->guide_choose_line_height = '줄 간격'; +$lang->guide_choose_paragraph_spacing = '문단 간격'; +$lang->guide_choose_word_break = '줄바꿈 방식'; +$lang->word_break_normal = '한글은 글자 단위로 줄바꿈, 영문은 단어 단위로 줄바꿈 (기본값)'; +$lang->word_break_keep_all = '모든 언어를 단어 단위로 줄바꿈'; +$lang->word_break_break_all = '모든 언어를 글자 단위로 줄바꿈'; +$lang->word_break_none = '줄을 바꾸지 않음'; $lang->font_preview = 'The quick brown fox jumps over the lazy dog. いろはにほへと / ちりぬるを / わかよたれそ / つねならむ / うゐのおくやま / けふこえて / あさきゆめみし / ゑひもせす 키스의 고유 조건은 입술끼리 만나야 하고 특별한 기술은 필요치 않다.'; @@ -42,6 +50,7 @@ $lang->msg_auto_saved = '자동 저장되었습니다.'; $lang->cmd_disable = '비활성'; $lang->cmd_enable = '활성'; $lang->cmd_select_cover = '커버이미지로 선택'; +$lang->default_editor_settings = '기본 에디터 설정 사용'; $lang->editor_skin = '에디터 스킨'; $lang->upload_file_grant = '파일 첨부 권한'; $lang->enable_default_component_grant = '기본 컴포넌트 사용 권한'; @@ -50,6 +59,7 @@ $lang->enable_html_grant = 'HTML 편집 권한'; $lang->enable_autosave = '자동저장 사용'; $lang->height_resizable = '높이 조절 가능'; $lang->editor_height = '에디터 높이'; +$lang->about_default_editor_settings = '사이트 전체 에디터 설정을 통일하여서 모듈별 에디터 설정을 단순하게 합니다.'; $lang->about_content_font = '콤마(,)로 여러 폰트를 지정할 수 있습니다.'; $lang->about_content_font_size = '12px, 1em등 단위까지 포함해서 입력해주세요.'; $lang->about_enable_autosave = '글 작성 시 자동 저장 기능을 활성화 시킬 수 있습니다.'; @@ -59,13 +69,21 @@ $lang->edit['use_paragraph'] = '문단기능'; $lang->edit['fontlist']['arial'] = 'Arial, Helvetica, sans-serif'; $lang->edit['fontlist']['tahoma'] = 'Tahoma, Geneva, sans-serif'; $lang->edit['fontlist']['verdana'] = 'Verdana, Geneva, sans-serif'; -$lang->edit['fontlist']['sans-serif'] = 'Sans-serif'; -$lang->edit['fontlist']['georgia'] = 'Georgia, \'Times New Roman\', Times, serif'; -$lang->edit['fontlist']['palatinoLinotype'] = '\'Palatino Linotype\', \'Book Antiqua\', Palatino, serif'; -$lang->edit['fontlist']['timesNewRoman'] = '\'Times New Roman\', Times, serif'; -$lang->edit['fontlist']['serif'] = 'Serif'; -$lang->edit['fontlist']['courierNew'] = '\'Courier New\', Courier, monospace'; -$lang->edit['fontlist']['lucidaConsole'] = '\'Lucida Console\', Monaco, monospace'; +$lang->edit['fontlist']['sans-serif'] = 'sans-serif'; +$lang->edit['fontlist']['georgia'] = 'Georgia, Times New Roman, Times, serif'; +$lang->edit['fontlist']['palatinoLinotype'] = 'Palatino Linotype, Book Antiqua, Palatino, serif'; +$lang->edit['fontlist']['timesNewRoman'] = 'Times New Roman, Times, serif'; +$lang->edit['fontlist']['serif'] = 'serif'; +$lang->edit['fontlist']['consolas'] = 'Consolas, monospace'; +$lang->edit['fontlist']['courierNew'] = 'Courier New, Courier, monospace'; +$lang->edit['fontlist']['lucidaConsole'] = 'Lucida Console, Monaco, monospace'; +$lang->edit['fontlist']['monospace'] = 'monospace'; +$lang->edit['fontlist']['gulim'] = '굴림, Gulim, sans-serif'; +$lang->edit['fontlist']['gungsuh'] = '궁서, Gungsuh, serif'; +$lang->edit['fontlist']['dotum'] = '돋움, Dotum, sans-serif'; +$lang->edit['fontlist']['batang'] = '바탕, Batang, serif'; +$lang->edit['fontlist']['malgunGothic'] = '맑은 고딕, Malgun Gothic, Meiryo, Microsoft YaHei, Segoe UI, sans-serif'; +$lang->edit['fontlist']['nanumGothic'] = '나눔고딕, NanumGothic, Malgun Gothic, sans-serif'; $lang->edit['header'] = '형식'; $lang->edit['header_list']['h1'] = '제목 1'; $lang->edit['header_list']['h2'] = '제목 2'; diff --git a/modules/editor/skins/ckeditor/editor.html b/modules/editor/skins/ckeditor/editor.html index ad3149792..b485c7a71 100755 --- a/modules/editor/skins/ckeditor/editor.html +++ b/modules/editor/skins/ckeditor/editor.html @@ -14,17 +14,14 @@ var auto_saved_msg = "{$lang->msg_auto_saved}"; {@ $css_content = null } - {@ $css_content = '.xe_content.editable p { margin: 0;'. chr(125); } - {@ $css_content .= ' .xe_content.editable { '} - - {@ $css_content .= 'font-family:' . $content_font . ';';} - - - - {@ $css_content .= 'font-size:' . $content_font_size . ';';} - + {@ $css_content .= 'font-family:' . $content_font . ';';} + {@ $css_content .= 'font-size:' . $content_font_size . ';';} + {@ $css_content .= 'line-height:' . $content_line_height . ';';} + {@ $css_content .= 'white-space: nowrap;';} + {@ $css_content .= 'word-break:' . ($content_word_break ?: 'normal') . '; word-wrap: break-word;';} {@ $css_content .= chr(125);} + {@ $css_content .= '.xe_content.editable p { margin: 0 0 ' . ($content_paragraph_spacing ?: 0) . ' 0;' . chr(125);} @@ -48,12 +45,55 @@ var auto_saved_msg = "{$lang->msg_auto_saved}"; // editor $(function(){ CKEDITOR.config.customConfig = ''; + + // Import CSS content from PHP. + var css_content = {json_encode($css_content)}; + + // Get default font name and list of other supported fonts. + var default_font_name = {json_encode($content_font ? trim(array_first(explode(',', $content_font)), '\'" ') : null)}; + var default_font_fullname = {json_encode($content_font ?: null)}; + if (default_font_fullname === null && window.getComputedStyle) { + var test_content = $('
').hide().appendTo($(document.body)); + var test_styles = window.getComputedStyle(test_content[0], null); + if (test_styles && test_styles.getPropertyValue) { + default_font_fullname = test_styles.getPropertyValue("font-family"); + if (default_font_fullname) { + default_font_name = $.trim(default_font_fullname.split(',')[0].replace(/['"]/g, '')); + css_content = ".xe_content.editable { font-family:" + default_font_fullname + "; } " + css_content; + } + } + } + var font_list = []; + font_list.push({json_encode($fontname)}); + if (default_font_fullname !== null && !$.inArray(default_font_fullname, font_list)) { + font_list.push(default_font_fullname); + } + font_list = $.map(font_list, function(val) { + return $.trim(val.split(",")[0]) + "/" + val; + }).join(";"); + + // Get default font size and list of other supported sizes. + var default_font_size = {json_encode($content_font_size ?: '13')}; + default_font_size = parseInt(default_font_size.replace(/\D/, ''), 10); + var font_sizes = [8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 24, 28, 32, 36, 40, 48]; + if (!$.inArray(default_font_size, font_sizes)) { + font_sizes.push(default_font_size); + font_sizes.sort(); + } + font_sizes = $.map(font_sizes, function(val) { + return val + "/" + val + "px"; + }).join(";"); + var settings = { ckeconfig: { height: '{$editor_height}', skin: '{$colorset}', - contentsCss: '{$content_style_path}/editor.css', + contentsCss: '{$content_style_path}/editor.css?{date("YmdHis", @filemtime($content_style_path."/editor.css"))}', xe_editor_sequence: {$editor_sequence}, + font_defaultLabel: default_font_name, + font_names: font_list, + fontSize_defaultLabel: default_font_size, + fontSize_sizes: font_sizes, toolbarCanCollapse: true, language: "{str_replace('jp','ja',$lang_type)}" }, @@ -89,7 +129,7 @@ var auto_saved_msg = "{$lang->msg_auto_saved}"; settings.ckeconfig.removeButtons = 'Save,Preview,Print,Cut,Copy,Paste,Source'; - CKEDITOR.addCss('{$css_content}'); + CKEDITOR.addCss(css_content); var ckeApp = $('#ckeditor_instance_{$editor_sequence}').XeCkEditor(settings); diff --git a/modules/editor/skins/xpresseditor/css/default.css b/modules/editor/skins/xpresseditor/css/default.css index a5d75a0eb..d118ed5dd 100644 --- a/modules/editor/skins/xpresseditor/css/default.css +++ b/modules/editor/skins/xpresseditor/css/default.css @@ -80,7 +80,7 @@ .xpress-editor .tool li.html span button, .xpress-editor .tool li.preview span button{left:2px;height:21px;background-position:right top;font:11px/21px Tahoma, Sans-serif;padding:0 4px;*overflow:visible;*line-height:20px} .xpress-editor .tool ul.type li{float:none;display:inline;*top:1px} -.xpress-editor .tool ul.type li select{height:21px;width:64px;white-space:nowrap;min-width:64px;padding:0} +.xpress-editor .tool ul.type li select{height:21px;width:64px;white-space:nowrap;min-width:64px;padding:0;font-size:12px} .xpress-editor .tool ul.type li option{white-space:nowrap} .xpress-editor.black .tool ul.type li select{color:#fff;background-color:#000} /* Content > Tool > Button Default */ @@ -345,4 +345,4 @@ /* Auto Save */ .xpress-editor .autosave_message {display:none;background: #f6ffdb;padding:6px 10px;margin:0;line-height:1} .xpress-editor.black .autosave_message {display:none;background:#222;padding:6px 10px;margin:0;line-height:1;color:#fff} -.xpress-editor .input_syntax.black {background:transparent;color:#fff} \ No newline at end of file +.xpress-editor .input_syntax.black {background:transparent;color:#fff} diff --git a/modules/editor/skins/xpresseditor/editor.html b/modules/editor/skins/xpresseditor/editor.html index 3fb8f3e2d..3baf416bc 100644 --- a/modules/editor/skins/xpresseditor/editor.html +++ b/modules/editor/skins/xpresseditor/editor.html @@ -60,7 +60,8 @@ @@ -458,7 +459,7 @@ var auto_saved_msg = "{$lang->msg_auto_saved}"; var oEditor; jQuery(function(){ - oEditor = editorStart_xe("{$editor_sequence}", "{$editor_primary_key_name}", "{$editor_content_key_name}", "{$editor_height}", "{$colorset}", "{$content_style}",'{$content_font}','{$content_font_size}'); + oEditor = editorStart_xe("{$editor_sequence}", "{$editor_primary_key_name}", "{$editor_content_key_name}", "{$editor_height}", "{$colorset}", "{$content_style}", '{$content_font}', '{$content_font_size}', '{$content_line_height}', '{$content_paragraph_spacing}', '{$content_word_break}'); diff --git a/modules/editor/skins/xpresseditor/js/xe_interface.js b/modules/editor/skins/xpresseditor/js/xe_interface.js index 3d8884403..2de25d180 100644 --- a/modules/editor/skins/xpresseditor/js/xe_interface.js +++ b/modules/editor/skins/xpresseditor/js/xe_interface.js @@ -2,11 +2,14 @@ if (!window.xe) xe = {}; xe.Editors = []; -function editorStart_xe(editor_sequence, primary_key, content_key, editor_height, colorset, content_style, content_font, content_font_size) { +function editorStart_xe(editor_sequence, primary_key, content_key, editor_height, colorset, content_style, content_font, content_font_size, content_line_height, content_paragraph_spacing, content_word_break) { if(typeof(colorset)=='undefined') colorset = 'white'; if(typeof(content_style)=='undefined') content_style = 'xeStyle'; if(typeof(content_font)=='undefined') content_font= ''; if(typeof(content_font_size)=='undefined') content_font_size= ''; + if(typeof(content_line_height)=='undefined') content_line_height= ''; + if(typeof(content_paragraph_spacing)=='undefined') content_paragraph_spacing= ''; + if(typeof(content_word_break)=='undefined') content_word_break= ''; var target_src = request_uri+'modules/editor/styles/'+content_style+'/editor.html'; @@ -132,7 +135,36 @@ function editorStart_xe(editor_sequence, primary_key, content_key, editor_height if(content_font_size && !doc.body.style.fontSize) { doc.body.style.fontSize = content_font_size; } - + if(content_line_height && !doc.body.style.lineHeight) { + doc.body.style.lineHeight = content_line_height; + } + if(content_word_break === "none") { + doc.body.style.whiteSpace = "nowrap"; + } else { + doc.body.style.wordBreak = content_word_break ? content_word_break : "normal"; + doc.body.style.wordWrap = "break-word"; + } + + var paragraph_css; + if(!content_paragraph_spacing) { + paragraph_css = '.xe_content.editable p { margin: 0; }'; + } else { + paragraph_css = '.xe_content.editable p { margin: 0 0 ' + content_paragraph_spacing + ' 0; }'; + } + var style = doc.createElement('style'); + style.type = 'text/css'; + if (style.styleSheet){ + style.styleSheet.cssText = paragraph_css; + } else { + style.appendChild(doc.createTextNode(paragraph_css)); + } + var head = doc.head || doc.getElementsByTagName('head')[0]; + head.appendChild(style); + + if(content_style === "ckeditor_light") { + doc.body.style.margin = "0"; + } + // run oEditor.run(); } catch(e) { diff --git a/modules/editor/styles/ckeditor_light/editor.css b/modules/editor/styles/ckeditor_light/editor.css index 62fff8f8f..0c896c0f9 100644 --- a/modules/editor/styles/ckeditor_light/editor.css +++ b/modules/editor/styles/ckeditor_light/editor.css @@ -1,6 +1,6 @@ @charset "utf-8"; /* NAVER (developers@xpressengine.com) */ -.xe_content.editable {color:#000;font-size:13px;font-family:sans-serif;line-height:1.5;word-break:break-all;word-wrap:break-word} +.xe_content.editable { } .xe_content.editable img{border:0;max-width:100%;} .xe_content.editable blockquote.q1, .xe_content.editable blockquote.q2, @@ -17,4 +17,3 @@ .xe_content.editable blockquote.q6{border:1px dashed #707070} .xe_content.editable blockquote.q7{border:1px dashed #707070;background:#fbfbfb} .xe_content.editable table .xe_selected_cell{background-color:#d6e9ff} -.xe_content.editable p{margin:0} diff --git a/modules/editor/styles/ckeditor_light/skin.xml b/modules/editor/styles/ckeditor_light/skin.xml index 9d52c13f8..ab06ded8e 100644 --- a/modules/editor/styles/ckeditor_light/skin.xml +++ b/modules/editor/styles/ckeditor_light/skin.xml @@ -1,8 +1,9 @@ - XE CKEditor 기본 서식 - 1.8 - 2014-02-27 + Rhymix 기본 서식 + Rhymix Default + 1.9 + 2016-04-27 NAVER diff --git a/modules/editor/styles/ckeditor_light/style.css b/modules/editor/styles/ckeditor_light/style.css index af512236a..16c39fb0b 100755 --- a/modules/editor/styles/ckeditor_light/style.css +++ b/modules/editor/styles/ckeditor_light/style.css @@ -16,4 +16,3 @@ .xe_content blockquote.q6{border:1px dashed #707070} .xe_content blockquote.q7{border:1px dashed #707070;background:#fbfbfb} .xe_content p{margin:0} - diff --git a/modules/editor/styles/ckeditor_light/style.ini b/modules/editor/styles/ckeditor_light/style.ini index e8c7365cf..8b1378917 100644 --- a/modules/editor/styles/ckeditor_light/style.ini +++ b/modules/editor/styles/ckeditor_light/style.ini @@ -1 +1 @@ -style.css + diff --git a/modules/editor/styles/ckeditor_recommend/editor.css b/modules/editor/styles/ckeditor_recommend/editor.css deleted file mode 100644 index bb51a135a..000000000 --- a/modules/editor/styles/ckeditor_recommend/editor.css +++ /dev/null @@ -1,19 +0,0 @@ -@charset "utf-8"; -/* NAVER (developers@xpressengine.com) */ -.xe_content.editable {color:#000;font-size:14px;font-family:sans-serif;line-height:1.6;word-break:break-all;word-wrap:break-word} -.xe_content.editable img{border:0;max-width:100%;} -.xe_content.editable blockquote.q1, -.xe_content.editable blockquote.q2, -.xe_content.editable blockquote.q3, -.xe_content.editable blockquote.q4, -.xe_content.editable blockquote.q5, -.xe_content.editable blockquote.q6, -.xe_content.editable blockquote.q7{padding:10px;margin:0 15px} -.xe_content.editable blockquote.q1{padding:0 10px;border-left:2px solid #ccc} -.xe_content.editable blockquote.q2{padding:0 10px;background:url(./img/bg_qmark.gif) no-repeat left top} -.xe_content.editable blockquote.q3{border:1px solid #d9d9d9} -.xe_content.editable blockquote.q4{border:1px solid #d9d9d9;background:#fbfbfb} -.xe_content.editable blockquote.q5{border:2px solid #707070} -.xe_content.editable blockquote.q6{border:1px dashed #707070} -.xe_content.editable blockquote.q7{border:1px dashed #707070;background:#fbfbfb} -.xe_content.editable table .xe_selected_cell{background-color:#d6e9ff} diff --git a/modules/editor/styles/ckeditor_recommend/editor.html b/modules/editor/styles/ckeditor_recommend/editor.html deleted file mode 100755 index 976795b75..000000000 --- a/modules/editor/styles/ckeditor_recommend/editor.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - -Rhymix - - - - diff --git a/modules/editor/styles/ckeditor_recommend/img/bg_qmark.gif b/modules/editor/styles/ckeditor_recommend/img/bg_qmark.gif deleted file mode 100644 index 5a8a44625..000000000 Binary files a/modules/editor/styles/ckeditor_recommend/img/bg_qmark.gif and /dev/null differ diff --git a/modules/editor/styles/ckeditor_recommend/skin.xml b/modules/editor/styles/ckeditor_recommend/skin.xml deleted file mode 100644 index f485bf0ae..000000000 --- a/modules/editor/styles/ckeditor_recommend/skin.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - XE CKEditor 권장 서식 - 1.8 - 2014-02-27 - - NAVER - - diff --git a/modules/editor/styles/ckeditor_recommend/style.css b/modules/editor/styles/ckeditor_recommend/style.css deleted file mode 100755 index 3aa6448fd..000000000 --- a/modules/editor/styles/ckeditor_recommend/style.css +++ /dev/null @@ -1,17 +0,0 @@ -@charset "utf-8"; -/* NAVER (developers@xpressengine.com) */ -.xe_content {color:#000;font-size:14px;font-family:sans-serif;line-height:1.6} -.xe_content blockquote.q1, -.xe_content blockquote.q2, -.xe_content blockquote.q3, -.xe_content blockquote.q4, -.xe_content blockquote.q5, -.xe_content blockquote.q6, -.xe_content blockquote.q7{padding:10px;margin:0 15px} -.xe_content blockquote.q1{padding:0 10px;border-left:2px solid #ccc} -.xe_content blockquote.q2{padding:0 10px;background:url(./img/bg_qmark.gif) no-repeat left top} -.xe_content blockquote.q3{border:1px solid #d9d9d9} -.xe_content blockquote.q4{border:1px solid #d9d9d9;background:#fbfbfb} -.xe_content blockquote.q5{border:2px solid #707070} -.xe_content blockquote.q6{border:1px dashed #707070} -.xe_content blockquote.q7{border:1px dashed #707070;background:#fbfbfb} diff --git a/modules/editor/styles/ckeditor_recommend/style.ini b/modules/editor/styles/ckeditor_recommend/style.ini deleted file mode 100644 index e8c7365cf..000000000 --- a/modules/editor/styles/ckeditor_recommend/style.ini +++ /dev/null @@ -1 +0,0 @@ -style.css diff --git a/modules/editor/tpl/admin_index.html b/modules/editor/tpl/admin_index.html index b99743896..4054dea72 100644 --- a/modules/editor/tpl/admin_index.html +++ b/modules/editor/tpl/admin_index.html @@ -87,32 +87,65 @@ +
+ +
+ +
+
- {@ - if($editor_config->content_font_size) $fontSize = str_replace('px','',$editor_config->content_font_size); - else $fontSize = str_replace('px','',$editor_config_default['content_font_size']); - } -
- -
-
- +
- px + px +
+
+
+ +
+ % +
+
+
+ +
+ px +
+
+
+ +
+ + + +
@@ -192,16 +225,21 @@ jQuery(function($){ var fontPreview = $('.fontPreview'); var fontSelector = $('.fontSelector'); var checkedFont = fontSelector.filter(':checked').css('fontFamily'); - var changedSize = $('#fontSize').val(); + var changedSize = $('#font_size').val(); //change event fontSelector.change(function(){ - var myFont = $(this).css('fontFamily'); - fontPreview.css('fontFamily',myFont); + var myFont = $(this).css('font-family'); + if ($(this).val() === 'Y') { + myFont = $("input[name='content_font_defined']").val(); + } + fontPreview.css('font-family', myFont); }); - $('#fontSize').keyup(function(){ - var mySize = $(this).val(); - fontPreview.css('fontSize',mySize+'px'); + $('#font_size').keyup(function(){ + fontPreview.css('font-size', $(this).val() + 'px'); + }).change(function(){$(this).keyup()}); + $('#line_height').keyup(function(){ + fontPreview.css('line-height', $(this).val() + '%'); }).change(function(){$(this).keyup()}); $('input[name=font_defined]').click(function(){ diff --git a/modules/editor/tpl/editor_module_config.html b/modules/editor/tpl/editor_module_config.html index 054403925..6cfdc6802 100644 --- a/modules/editor/tpl/editor_module_config.html +++ b/modules/editor/tpl/editor_module_config.html @@ -18,6 +18,15 @@
+ + + + - + - + - + - + @@ -122,3 +131,20 @@ + + \ No newline at end of file diff --git a/modules/ncenterlite/ncenterlite.admin.controller.php b/modules/ncenterlite/ncenterlite.admin.controller.php index 2d56d7e07..97a438ae3 100644 --- a/modules/ncenterlite/ncenterlite.admin.controller.php +++ b/modules/ncenterlite/ncenterlite.admin.controller.php @@ -41,15 +41,15 @@ class ncenterliteAdminController extends ncenterlite { $config->use = array(); } - if (!$config->anonymous_name) - { - $config->anonymous_name = null; - } + } + + if ($obj->disp_act == 'dispNcenterliteAdminAdvancedconfig') + { if (!$config->mention_suffixes) { $config->mention_suffixes = array(); } - if (!is_array($config->mention_suffixes)) + else if (!is_array($config->mention_suffixes)) { $config->mention_suffixes = array_map('trim', explode(',', $config->mention_suffixes)); } diff --git a/modules/ncenterlite/ncenterlite.controller.php b/modules/ncenterlite/ncenterlite.controller.php index 059a78079..ebaa58db2 100644 --- a/modules/ncenterlite/ncenterlite.controller.php +++ b/modules/ncenterlite/ncenterlite.controller.php @@ -658,10 +658,8 @@ class ncenterliteController extends ncenterlite return; } - $logged_info = Context::get('logged_info'); - // 로그인 상태가 아니면 중지 - if(!$logged_info) + if(!Context::get('is_logged')) { return; } @@ -707,8 +705,6 @@ class ncenterliteController extends ncenterlite $js_args = array('./modules/ncenterlite/tpl/js/ncenterlite.js', 'body', '', 100000); Context::loadFile($js_args); - $oNcenterliteModel = getModel('ncenterlite'); - // 알림 목록 가져오기 $logged_info = Context::get('logged_info'); $_output = $oNcenterliteModel->getMyNotifyList($logged_info->member_srl); @@ -855,6 +851,12 @@ class ncenterliteController extends ncenterlite $output = executeQuery('ncenterlite.updateNotifyReaded', $args); //$output = executeQuery('ncenterlite.deleteNotify', $args); + //Remove flag files + $flag_path = \RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($args->member_srl) . $args->member_srl . '.php'; + if(file_exists($flag_path)) + { + FileHandler::removeFile($flag_path); + } return $output; } @@ -866,6 +868,12 @@ class ncenterliteController extends ncenterlite $output = executeQuery('ncenterlite.updateNotifyReadedByTargetSrl', $args); //$output = executeQuery('ncenterlite.deleteNotifyByTargetSrl', $args); + //Remove flag files + $flag_path = \RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($args->member_srl) . $args->member_srl . '.php'; + if(file_exists($flag_path)) + { + FileHandler::removeFile($flag_path); + } return $output; } @@ -876,6 +884,12 @@ class ncenterliteController extends ncenterlite $output = executeQuery('ncenterlite.updateNotifyReadedAll', $args); //$output = executeQuery('ncenterlite.deleteNotifyByMemberSrl', $args); + //Remove flag files + $flag_path = \RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($args->member_srl) . $args->member_srl . '.php'; + if(file_exists($flag_path)) + { + FileHandler::removeFile($flag_path); + } return $output; } @@ -956,36 +970,24 @@ class ncenterliteController extends ncenterlite function _insertNotify($args, $anonymous = FALSE) { - $oNcenterliteModel = getModel('ncenterlite'); - $config = $oNcenterliteModel->getConfig(); // 비회원 노티 제거 if($args->member_srl <= 0) { return new Object(); } - $logged_info = Context::get('logged_info'); + if($anonymous == TRUE) { - // 설정에서 익명 이름이 설정되어 있으면 익명 이름을 설정함. 없을 경우 Anonymous 를 사용한다. - if(!$config->anonymous_name) - { - $anonymous_name = 'Anonymous'; - } - else - { - $anonymous_name = $config->anonymous_name; - } - // 익명 노티 시 회원정보 제거 $args->target_member_srl = 0; - $args->target_nick_name = $anonymous_name; - $args->target_user_id = $anonymous_name; - $args->target_email_address = $anonymous_name; + $args->target_user_id = $args->target_nick_name; + $args->target_email_address = $args->target_nick_name; } - else if($logged_info) + // 로그인을 했을경우 logged_info 정보를 가져와 검사한다. + else if(Context::get('is_logged')) { - // 익명 노티가 아닐 때 로그인 세션의 회원정보 넣기 + $logged_info = Context::get('logged_info'); $args->target_member_srl = $logged_info->member_srl; $args->target_nick_name = $logged_info->nick_name; $args->target_user_id = $logged_info->user_id; @@ -1022,7 +1024,7 @@ class ncenterliteController extends ncenterlite } } - $flag_path = \RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($args->target_member_srl) . $args->target_member_srl . '.php'; + $flag_path = \RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($args->member_srl) . $args->member_srl . '.php'; if(file_exists($flag_path)) { //remove flag files @@ -1044,7 +1046,7 @@ class ncenterliteController extends ncenterlite return; } - FileHandler::makeDir(\RX_BASEDIR . 'files/cache/ncenterlite/new_notify' . getNumberingPath($member_srl)); + FileHandler::makeDir(\RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($member_srl)); $buff = "skin) $config->skin = 'default'; if(!$config->colorset) $config->colorset = 'black'; if(!$config->zindex) $config->zindex = '9999'; - if(!$config->anonymous_name) $config->anonymous_name = 'Anonymous'; self::$config = $config; } @@ -215,7 +214,8 @@ class ncenterliteModel extends ncenterlite } $output->data = $list; - if($page <= 1) + + if($page <= 1 && $output->flag_exists !== true) { $oNcenterliteController = getController('ncenterlite'); $oNcenterliteController->updateFlagFile($member_srl, $output); @@ -256,11 +256,13 @@ class ncenterliteModel extends ncenterlite $member_srl = $logged_info->member_srl; } $flag_path = \RX_BASEDIR . 'files/cache/ncenterlite/new_notify/' . getNumberingPath($member_srl) . $member_srl . '.php'; + if(FileHandler::exists($flag_path) && $page <= 1) { $output = require_once $flag_path; - if(is_object($output->data)) + if(is_object($output)) { + $output->flag_exists = true; return $output; } } @@ -269,7 +271,7 @@ class ncenterliteModel extends ncenterlite $args->page = $page ? $page : 1; if($readed) $args->readed = $readed; $output = executeQueryArray('ncenterlite.getNotifyList', $args); - + $output->flag_exists = false; if(!$output->data) $output->data = array(); return $output; diff --git a/modules/ncenterlite/tpl/advancedconfig.html b/modules/ncenterlite/tpl/advancedconfig.html index a6fe098bc..640b0c0af 100644 --- a/modules/ncenterlite/tpl/advancedconfig.html +++ b/modules/ncenterlite/tpl/advancedconfig.html @@ -39,14 +39,6 @@

{$lang->about_mention_suffix_always_cut}

- -
- -
- -

{$lang->about_anonymous_nick_name}

-
-
diff --git a/modules/point/point.model.php b/modules/point/point.model.php index 5f3a802af..a50638745 100644 --- a/modules/point/point.model.php +++ b/modules/point/point.model.php @@ -21,35 +21,11 @@ class pointModel extends point */ function isExistsPoint($member_srl) { - $member_srl = abs($member_srl); - - // Get from instance memory - if($this->pointList[$member_srl]) return true; - - // Get from file cache - $path = sprintf(_XE_PATH_ . 'files/member_extra_info/point/%s',getNumberingPath($member_srl)); - $cache_filename = sprintf('%s%d.cache.txt', $path, $member_srl); - if(file_exists($cache_filename)) - { - if(!$this->pointList[$member_srl]) - $this->pointList[$member_srl] = trim(FileHandler::readFile($cache_filename)); - return true; - } - - $args =new stdClass(); - $args->member_srl = $member_srl; - $output = executeQuery('point.getPoint', $args); - if($output->data->member_srl == $member_srl) - { - if(!$this->pointList[$member_srl]) - { - $this->pointList[$member_srl] = (int)$output->data->point; - FileHandler::makeDir($path); - FileHandler::writeFile($cache_filename, (int)$output->data->point); - } - return true; - } - return false; + $args = new stdClass; + $args->member_srl = abs($member_srl); + $output = executeQuery('point.getPoint', $args, array('member_srl')); + + return isset($output->data->member_srl); } /** @@ -70,7 +46,7 @@ class pointModel extends point return $this->pointList[$member_srl] = trim(FileHandler::readFile($cache_filename)); // Get from the DB - $args =new stdClass(); + $args = new stdClass; $args->member_srl = $member_srl; $output = executeQuery('point.getPoint', $args); diff --git a/modules/trash/trash.admin.view.php b/modules/trash/trash.admin.view.php index 459a24bea..a3c6e561d 100644 --- a/modules/trash/trash.admin.view.php +++ b/modules/trash/trash.admin.view.php @@ -78,7 +78,6 @@ class trashAdminView extends trash } - // Trash View - sejin7940 function dispTrashAdminView() { @@ -103,6 +102,7 @@ class trashAdminView extends trash Context::set('module_info', $module_info); if($originObject) { + $args_extra = new stdClass; $args_extra->module_srl = $originObject->module_srl; $args_extra->document_srl = $originObject->document_srl; $output_extra = executeQueryArray('trash.getDocumentExtraVars', $args_extra); diff --git a/tests/_data/formatter/concat.source1.css b/tests/_data/formatter/concat.source1.css new file mode 100644 index 000000000..6a1940909 --- /dev/null +++ b/tests/_data/formatter/concat.source1.css @@ -0,0 +1,4 @@ +@charset "UTF-8"; +.rhymix { + background: url("foo/bar.jpg"); +} diff --git a/tests/_data/formatter/concat.source1.js b/tests/_data/formatter/concat.source1.js new file mode 100644 index 000000000..315c8d4d5 --- /dev/null +++ b/tests/_data/formatter/concat.source1.js @@ -0,0 +1,6 @@ +(function($) { + $(".foo").click(function(event) { + event.preventDefault(); + $(this).attr("bar", "baz"); + }); +})(jQuery); diff --git a/tests/_data/formatter/concat.source2.css b/tests/_data/formatter/concat.source2.css new file mode 100644 index 000000000..639cfbcdd --- /dev/null +++ b/tests/_data/formatter/concat.source2.css @@ -0,0 +1,8 @@ +@charset "UTF-8"; +@import url(concat.source3.css); +.wordpress { + border-radius: 4px; +} +.xpressengine { + margin: 320px; +} diff --git a/tests/_data/formatter/concat.source2.js b/tests/_data/formatter/concat.source2.js new file mode 100644 index 000000000..43f22ddab --- /dev/null +++ b/tests/_data/formatter/concat.source2.js @@ -0,0 +1,3 @@ +(function($) { + $(".xe").hide(); +})(jQuery); diff --git a/tests/_data/formatter/concat.source3.css b/tests/_data/formatter/concat.source3.css new file mode 100644 index 000000000..6dbf2de24 --- /dev/null +++ b/tests/_data/formatter/concat.source3.css @@ -0,0 +1,4 @@ +.imported { + background-image: url("test.jpg"); + font-family: sans-serif; +} diff --git a/tests/_data/formatter/concat.target1.css b/tests/_data/formatter/concat.target1.css new file mode 100644 index 000000000..be34a85e9 --- /dev/null +++ b/tests/_data/formatter/concat.target1.css @@ -0,0 +1,22 @@ +/* Original file: tests/_data/formatter/concat.source1.css */ + +@charset "UTF-8"; +.rhymix { + background: url("../_data/formatter/foo/bar.jpg"); +} + +/* Original file: tests/_data/formatter/concat.source2.css */ + +@charset "UTF-8"; +/* Original file: tests/_data/formatter/concat.source3.css */ + +.imported { + background-image: url("../_data/_data/formatter/test.jpg"); + font-family: sans-serif; +} +.wordpress { + border-radius: 4px; +} +.xpressengine { + margin: 320px; +} diff --git a/tests/_data/formatter/concat.target1.js b/tests/_data/formatter/concat.target1.js new file mode 100644 index 000000000..7ad72cf6c --- /dev/null +++ b/tests/_data/formatter/concat.target1.js @@ -0,0 +1,14 @@ +/* Original file: tests/_data/formatter/concat.source1.js */ + +(function($) { + $(".foo").click(function(event) { + event.preventDefault(); + $(this).attr("bar", "baz"); + }); +})(jQuery);; + +/* Original file: tests/_data/formatter/concat.source2.js */ + +(function($) { + $(".xe").hide(); +})(jQuery);; diff --git a/tests/_data/formatter/concat.target2.css b/tests/_data/formatter/concat.target2.css new file mode 100644 index 000000000..59145933c --- /dev/null +++ b/tests/_data/formatter/concat.target2.css @@ -0,0 +1,26 @@ +/* Original file: tests/_data/formatter/concat.source1.css */ + +@media screen and (max-width: 640px) { + +@charset "UTF-8"; +.rhymix { + background: url("../_data/formatter/foo/bar.jpg"); +} + +} + +/* Original file: tests/_data/formatter/concat.source2.css */ + +@charset "UTF-8"; +/* Original file: tests/_data/formatter/concat.source3.css */ + +.imported { + background-image: url("../_data/_data/formatter/test.jpg"); + font-family: sans-serif; +} +.wordpress { + border-radius: 4px; +} +.xpressengine { + margin: 320px; +} diff --git a/tests/_data/formatter/concat.target2.js b/tests/_data/formatter/concat.target2.js new file mode 100644 index 000000000..d7e8e3ba6 --- /dev/null +++ b/tests/_data/formatter/concat.target2.js @@ -0,0 +1,18 @@ +/* Original file: tests/_data/formatter/concat.source1.js */ + +(function($) { + $(".foo").click(function(event) { + event.preventDefault(); + $(this).attr("bar", "baz"); + }); +})(jQuery);; + +/* Original file: tests/_data/formatter/concat.source2.js */ + +if ((/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] >= 6) && (/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] <= 8)) { + +(function($) { + $(".xe").hide(); +})(jQuery);; + +}; diff --git a/tests/_data/formatter/scss.target1.css b/tests/_data/formatter/scss.target1.css index 8e961b07d..2d78eacef 100644 --- a/tests/_data/formatter/scss.target1.css +++ b/tests/_data/formatter/scss.target1.css @@ -1,4 +1,6 @@ @charset "UTF-8"; +/* Original file: tests/_data/formatter/scss.source1.scss */ +/* Original file: tests/_data/formatter/scss.source2.scss */ .rhymix { color: #123456; background: url("../_data/formatter/foo/bar.jpg"); diff --git a/tests/unit/classes/FrontEndFileHandlerTest.php b/tests/unit/classes/FrontEndFileHandlerTest.php index dfa45ec0c..7d782ccf1 100644 --- a/tests/unit/classes/FrontEndFileHandlerTest.php +++ b/tests/unit/classes/FrontEndFileHandlerTest.php @@ -15,8 +15,9 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test HTMLDisplayHandler::$reservedCSS = '/xxx$/'; HTMLDisplayHandler::$reservedJS = '/xxx$/'; FrontEndFileHandler::$minify = 'none'; + FrontEndFileHandler::$concat = 'none'; - $this->specify("js(head)", function() { + $this->specify("js (head)", function() { $handler = new FrontEndFileHandler(); $handler->loadFile(array('./common/js/js_app.js', 'head')); $handler->loadFile(array('./common/js/common.js', 'body')); @@ -24,23 +25,27 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $handler->loadFile(array('./common/js/xml_js_filter.js', 'body')); $expected[] = array('file' => '/rhymix/common/js/js_app.js' . $this->_filemtime('common/js/js_app.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/common.js' . $this->_filemtime('common/js/common.js'), 'targetie' => null); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); - $this->specify("js(body)", function() { + $this->specify("js (body)", function() { $handler = new FrontEndFileHandler(); $handler->loadFile(array('./common/js/xml_js_filter.js', 'head')); $expected = array(); - $this->assertEquals($handler->getJsFileList('body'), $expected); + $this->assertEquals($expected, $handler->getJsFileList('body')); }); - $this->specify("css", function() { + $this->specify("css and scss", function() { $handler = new FrontEndFileHandler(); - $handler->loadFile(array('./common/css/xe.css')); + $handler->loadFile(array('./common/css/rhymix.scss')); $handler->loadFile(array('./common/css/mobile.css')); - $expected[] = array('file' => '/rhymix/common/css/xe.css' . $this->_filemtime('common/css/xe.css'), 'media' => 'all', 'targetie' => null); - $expected[] = array('file' => '/rhymix/common/css/mobile.css' . $this->_filemtime('common/css/mobile.css'), 'media' => 'all', 'targetie' => null); - $this->assertEquals($handler->getCssFileList(), $expected); + $result = $handler->getCssFileList(); + $this->assertRegexp('/\.rhymix\.scss\.css\?\d+$/', $result[0]['file']); + $this->assertEquals('all', $result[0]['media']); + $this->assertEmpty($result[0]['targetie']); + $this->assertEquals('/rhymix/common/css/mobile.css' . $this->_filemtime('common/css/mobile.css'), $result[1]['file']); + $this->assertEquals('all', $result[1]['media']); + $this->assertEmpty($result[1]['targetie']); }); $this->specify("order (duplicate)", function() { @@ -57,7 +62,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '/rhymix/common/js/common.js' . $this->_filemtime('common/js/common.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/xml_handler.js' . $this->_filemtime('common/js/xml_handler.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/xml_js_filter.js' . $this->_filemtime('common/js/xml_js_filter.js'), 'targetie' => null); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); $this->specify("order (redefine)", function() { @@ -70,7 +75,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '/rhymix/common/js/common.js' . $this->_filemtime('common/js/common.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/xml_js_filter.js' . $this->_filemtime('common/js/xml_js_filter.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/xml_handler.js' . $this->_filemtime('common/js/xml_handler.js'), 'targetie' => null); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); $this->specify("unload", function() { @@ -83,10 +88,10 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '/rhymix/common/js/common.js' . $this->_filemtime('common/js/common.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/xml_handler.js' . $this->_filemtime('common/js/xml_handler.js'), 'targetie' => null); $expected[] = array('file' => '/rhymix/common/js/xml_js_filter.js' . $this->_filemtime('common/js/xml_js_filter.js'), 'targetie' => null); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); - $this->specify("target IE(js)", function() { + $this->specify("target IE (js)", function() { $handler = new FrontEndFileHandler(); $handler->loadFile(array('./common/js/js_app.js', 'head', 'ie6')); $handler->loadFile(array('./common/js/js_app.js', 'head', 'ie7')); @@ -94,7 +99,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '/rhymix/common/js/js_app.js' . $this->_filemtime('common/js/js_app.js'), 'targetie' => 'ie6'); $expected[] = array('file' => '/rhymix/common/js/js_app.js' . $this->_filemtime('common/js/js_app.js'), 'targetie' => 'ie7'); $expected[] = array('file' => '/rhymix/common/js/js_app.js' . $this->_filemtime('common/js/js_app.js'), 'targetie' => 'ie8'); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); $this->specify("external file - schemaless", function() { @@ -108,7 +113,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => 'https://external.host/js/script.js', 'targetie' => null); $expected[] = array('file' => '//external.host/js/script1.js', 'targetie' => null); $expected[] = array('file' => '//external.host/js/script2.js', 'targetie' => null); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); $this->specify("external file - schemaless", function() { @@ -117,10 +122,10 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $handler->loadFile(array('///external.host/js/script.js')); $expected[] = array('file' => '//external.host/js/script.js', 'targetie' => null); - $this->assertEquals($handler->getJsFileList(), $expected); + $this->assertEquals($expected, $handler->getJsFileList()); }); - $this->specify("target IE(css)", function() { + $this->specify("target IE (css)", function() { $handler = new FrontEndFileHandler(); $handler->loadFile(array('./common/css/common.css', null, 'ie6')); $handler->loadFile(array('./common/css/common.css', null, 'ie7')); @@ -129,7 +134,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '/rhymix/common/css/common.css', 'media'=>'all', 'targetie' => 'ie6'); $expected[] = array('file' => '/rhymix/common/css/common.css','media'=>'all', 'targetie' => 'ie7'); $expected[] = array('file' => '/rhymix/common/css/common.css', 'media'=>'all', 'targetie' => 'ie8'); - $this->assertEquals($handler->getCssFileList(), $expected); + $this->assertEquals($expected, $handler->getCssFileList()); }); $this->specify("media", function() { @@ -141,23 +146,76 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '/rhymix/common/css/common.css', 'media'=>'all', 'targetie' => null); $expected[] = array('file' => '/rhymix/common/css/common.css','media'=>'screen', 'targetie' => null); $expected[] = array('file' => '/rhymix/common/css/common.css', 'media'=>'handled', 'targetie' => null); - $this->assertEquals($handler->getCssFileList(), $expected); + $this->assertEquals($expected, $handler->getCssFileList()); }); FrontEndFileHandler::$minify = 'all'; - $this->specify("minify", function() { + $this->specify("minify (css)", function() { $handler = new FrontEndFileHandler(); - $handler->loadFile(array('./common/css/xe.css')); + $handler->loadFile(array('./common/css/rhymix.scss')); $handler->loadFile(array('./common/css/mobile.css')); - $expected[] = array('file' => '/rhymix/files/cache/minify/common.css.xe.min.css', 'media' => 'all', 'targetie' => null); - $expected[] = array('file' => '/rhymix/files/cache/minify/common.css.mobile.min.css', 'media' => 'all', 'targetie' => null); $result = $handler->getCssFileList(); - $result[0]['file'] = preg_replace('/\?\d+$/', '', $result[0]['file']); - $result[1]['file'] = preg_replace('/\?\d+$/', '', $result[1]['file']); - $this->assertEquals($result, $expected); + $this->assertRegexp('/\.rhymix\.scss\.min\.css\b/', $result[0]['file']); + $this->assertEquals('all', $result[0]['media']); + $this->assertEmpty($result[0]['targetie']); + $this->assertRegexp('/minified\/common\.css\.mobile\.min\.css\?\d+$/', $result[1]['file']); + $this->assertEquals('all', $result[1]['media']); + $this->assertEmpty($result[1]['targetie']); }); - + + $this->specify("minify (js)", function() { + $handler = new FrontEndFileHandler(); + $handler->loadFile(array('./common/js/common.js', 'head')); + $result = $handler->getJsFileList(); + $this->assertRegexp('/minified\/common\.js\.common\.min\.js\?\d+$/', $result[0]['file']); + $this->assertEmpty($result[0]['targetie']); + }); + + FrontEndFileHandler::$minify = 'none'; + + FrontEndFileHandler::$concat = 'css'; + + $this->specify("concat (css)", function() { + $handler = new FrontEndFileHandler(); + $handler->loadFile(array('./common/css/rhymix.scss')); + $handler->loadFile(array('./common/css/mobile.css')); + $handler->loadFile(array('http://external.host/style.css')); + $handler->loadFile(array('./common/css/bootstrap.css', null, 'IE')); + $handler->loadFile(array('./tests/_data/formatter/concat.source1.css')); + $handler->loadFile(array('./tests/_data/formatter/concat.source2.css')); + $handler->loadFile(array('./tests/_data/formatter/concat.target1.css')); + $handler->loadFile(array('./tests/_data/formatter/concat.target2.css')); + $result = $handler->getCssFileList(); + $this->assertEquals(4, count($result)); + $this->assertRegexp('/combined\/[0-9a-f]+\.css\?\d+$/', $result[0]['file']); + $this->assertEquals('http://external.host/style.css', $result[1]['file']); + $this->assertEquals('/rhymix/common/css/bootstrap.css' . $this->_filemtime('common/css/bootstrap.css'), $result[2]['file']); + $this->assertEquals('IE', $result[2]['targetie']); + $this->assertRegexp('/combined\/[0-9a-f]+\.css\?\d+$/', $result[3]['file']); + }); + + FrontEndFileHandler::$concat = 'js'; + + $this->specify("concat (js)", function() { + $handler = new FrontEndFileHandler(); + $handler->loadFile(array('./common/js/common.js', 'head')); + $handler->loadFile(array('./common/js/debug.js', 'head')); + $handler->loadFile(array('./common/js/html5.js', 'head')); + $handler->loadFile(array('///external.host/js/script.js')); + $handler->loadFile(array('./tests/_data/formatter/concat.source1.js', 'head', 'lt IE 8')); + $handler->loadFile(array('./tests/_data/formatter/concat.source2.js', 'head', 'gt IE 7')); + $handler->loadFile(array('./tests/_data/formatter/concat.target1.js')); + $handler->loadFile(array('./tests/_data/formatter/concat.target2.js')); + $result = $handler->getJsFileList(); + $this->assertEquals(3, count($result)); + $this->assertRegexp('/combined\/[0-9a-f]+\.js\?\d+$/', $result[0]['file']); + $this->assertEquals('//external.host/js/script.js', $result[1]['file']); + $this->assertRegexp('/combined\/[0-9a-f]+\.js\?\d+$/', $result[2]['file']); + }); + + FrontEndFileHandler::$concat = 'none'; + $this->specify("external file", function() { $handler = new FrontEndFileHandler(); $handler->loadFile(array('http://external.host/css/style1.css')); @@ -165,7 +223,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => 'http://external.host/css/style1.css', 'media'=>'all', 'targetie' => null); $expected[] = array('file' => 'https://external.host/css/style2.css', 'media'=>'all', 'targetie' => null); - $this->assertEquals($handler->getCssFileList(), $expected); + $this->assertEquals($expected, $handler->getCssFileList()); }); $this->specify("external file - schemaless", function() { @@ -175,7 +233,7 @@ class FrontEndFileHandlerTest extends \Codeception\TestCase\Test $expected[] = array('file' => '//external.host/css/style.css', 'media'=>'all', 'targetie' => null); $expected[] = array('file' => '//external.host/css2/style2.css', 'media'=>'all', 'targetie' => null); - $this->assertEquals($handler->getCssFileList(), $expected); + $this->assertEquals($expected, $handler->getCssFileList()); }); diff --git a/tests/unit/classes/TemplateHandlerTest.php b/tests/unit/classes/TemplateHandlerTest.php index 028e6039a..34b2d33ea 100644 --- a/tests/unit/classes/TemplateHandlerTest.php +++ b/tests/unit/classes/TemplateHandlerTest.php @@ -110,7 +110,7 @@ class TemplateHandlerTest extends \Codeception\TestCase\Test // array( '', - '?>' + '?>' ), // array( diff --git a/tests/unit/framework/FormatterTest.php b/tests/unit/framework/FormatterTest.php index b90d16fb4..1f8e26c37 100644 --- a/tests/unit/framework/FormatterTest.php +++ b/tests/unit/framework/FormatterTest.php @@ -131,4 +131,63 @@ class FormatterTest extends \Codeception\TestCase\Test unlink($test_target); } + + public function testConcatCSS() + { + $source1 = \RX_BASEDIR . 'tests/_data/formatter/concat.source1.css'; + $source2 = \RX_BASEDIR . 'tests/_data/formatter/concat.source2.css'; + $real_target1 = \RX_BASEDIR . 'tests/_data/formatter/concat.target1.css'; + $real_target2 = \RX_BASEDIR . 'tests/_data/formatter/concat.target2.css'; + $test_target = \RX_BASEDIR . 'tests/_output/concat.target.css'; + + $test_without_media_query = Rhymix\Framework\Formatter::concatCSS(array($source1, $source2), $test_target); + $this->assertEquals(trim(file_get_contents($real_target1)), trim($test_without_media_query)); + + $test_with_media_query = Rhymix\Framework\Formatter::concatCSS(array(array($source1, 'screen and (max-width: 640px)'), $source2), $test_target); + $this->assertEquals(trim(file_get_contents($real_target2)), trim($test_with_media_query)); + } + + public function testConcatJS() + { + $source1 = \RX_BASEDIR . 'tests/_data/formatter/concat.source1.js'; + $source2 = \RX_BASEDIR . 'tests/_data/formatter/concat.source2.js'; + $real_target1 = \RX_BASEDIR . 'tests/_data/formatter/concat.target1.js'; + $real_target2 = \RX_BASEDIR . 'tests/_data/formatter/concat.target2.js'; + $test_target = \RX_BASEDIR . 'tests/_output/concat.target.js'; + + $test_without_targetie = Rhymix\Framework\Formatter::concatJS(array($source1, $source2), $test_target); + $this->assertEquals(trim(file_get_contents($real_target1)), trim($test_without_targetie)); + + $test_with_targetie = Rhymix\Framework\Formatter::concatJS(array($source1, array($source2, '(gte IE 6) & (lte IE 8)')), $test_target); + $this->assertEquals(trim(file_get_contents($real_target2)), trim($test_with_targetie)); + } + + public function testConvertIECondition() + { + $this->assertEquals('window.navigator.userAgent.match(/MSIE\s/)', Rhymix\Framework\Formatter::convertIECondition('IE')); + $this->assertEquals('!window.navigator.userAgent.match(/MSIE\s/)', Rhymix\Framework\Formatter::convertIECondition('!IE')); + $this->assertEquals('!window.navigator.userAgent.match(/MSIE\s/)', Rhymix\Framework\Formatter::convertIECondition('!(IE)')); + $this->assertEquals('true && false', Rhymix\Framework\Formatter::convertIECondition('true&false')); + $this->assertEquals('false', Rhymix\Framework\Formatter::convertIECondition('gobbledygook')); + + $source = 'gt IE 7'; + $target = '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] > 7)'; + $this->assertEquals($target, Rhymix\Framework\Formatter::convertIECondition($source)); + + $source = 'lte IE 8'; + $target = '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] <= 8)'; + $this->assertEquals($target, Rhymix\Framework\Formatter::convertIECondition($source)); + + $source = '(gte IE 6) & (lt IE 8)'; + $target = '(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] >= 6) && (/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] < 8)'; + $this->assertEquals($target, Rhymix\Framework\Formatter::convertIECondition($source)); + + $source = '!(gt IE 9)'; + $target = '!(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] > 9)'; + $this->assertEquals($target, Rhymix\Framework\Formatter::convertIECondition($source)); + + $source = '!lt IE 8|lt IE 6'; + $target = '!(/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] < 8) || (/MSIE (\d+)/.exec(window.navigator.userAgent) && /MSIE (\d+)/.exec(window.navigator.userAgent)[1] < 6)'; + $this->assertEquals($target, Rhymix\Framework\Formatter::convertIECondition($source)); + } }
- {$oDocument->getNickName()} - ({$lang->anonymous}) {$member_nick_name[abs($oDocument->get('member_srl'))]} + {$oDocument->getNickName()} + ({$member_nick_name[abs($oDocument->get('member_srl'))]}) + {$oDocument->getNickName()} {$oDocument->get('readed_count')} {$oDocument->get('voted_count')}/{$oDocument->get('blamed_count')}
{$lang->default_editor_settings} + +
{$lang->editor_skin}
{$lang->content_style}
{$lang->editor_height} px @@ -60,14 +69,14 @@ px
content_font)}" placeholder="Ex) Tahoma, Geneva, sans-serif" /> {$lang->about_content_font}
{$lang->about_content_font_size}