제목 | nested panel - sk-rt / handy-collapse | ||
---|---|---|---|
글쓴이 | darkninja | 작성시각 | 2023/02/25 23:23:23 |
|
|||
https://github.com/sk-rt/handy-collapse 취미로 코딩을 하는 것은 정말 재미있고 흥미로운 것입니다. 초보자들이 코딩에 빠져들수 있는 재미를 가져볼수 있게 만들고 싶었는데 코드조각들이 점점 암호문처럼 되어가는. <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Test page</title> <style> pre { padding: 0px; border-left: 3px solid #ccc; border-right: 2px solid #ccc; margin: 0px; overflow: auto; width: 99.7%; background-color: #F5F5F5; } </style> <style> /* handy-collapse */ /* top, right, bottom, left */ .handy-panel { background: #eee; margin: 1px; border: 1px solid #CCC; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-subpanel { background: #eee; margin: 1px 10px 1px 10px; border: 1px solid #CCC; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-panel.collapsed, .handy-subpanel.collapsed { border: 1px solid #999; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-panel.expand, .handy-subpanel.expand { border-left: 1px solid #CCC; border-right: 1px solid #CCC; border-bottom: 1px solid #CCC; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-panel > button, .handy-subpanel > button { margin: 0px; padding: 2px 2px 2px 5px; background: #CCC url(images/arrow-up.gif) no-repeat 99.2% center; border: 0px; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-panel > button:hover, .handy-subpanel > button:hover { background-color: #A9BCEF; cursor:pointer; } .handy-panel.collapsed > button, .handy-subpanel.collapsed > button { margin: 0px; padding: 2px 2px 2px 5px; background: #CCC url(images/arrow-dn.gif) no-repeat 99.2% center; border-color: #CCC; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-panel.collapsed > button:hover, .handy-subpanel.collapsed > button:hover { margin: 0px; padding: 2px 2px 2px 5px; background: #A9BCEF url(images/arrow-dn.gif) no-repeat 99.2% center; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .handy-panelcontent { padding: 2px 3px 2px 4px; margin: 0px 0px 0px 0px; overflow: hidden; list-style-type: none; } .handy-panelcontent.is-1 { background-color:#FFFFFF; } .handy-panelcontent.is-2 { background-color:#F7F7F7; } .handy-panelcontent.is-3 { background-color:#EEEEEE; } .handy-panelcontent.is-4 { background-color:#E7E7E7; } .handy-panelcontent.is-5 { background-color:#CACACA; } .handy-panelcontent p { margin: 0px; padding: 0px 0px 2px 0px; } /* collapsed panel content */ .handy-panel.collapsed .handy-panelcontent { display: none; } .handy-subpanel.collapsed .handy-panelcontent { display: none; } .button.is-fullwidth{ display:flex; width:100% } </style> </head> <body> <?php //source //https://www.media-division.com/javascript-animated-collapsible-panels-without-frameworks/ //https://github.com/sk-rt/handy-collapse //https://www.cssscript.com/nested-accordion-content-toggle-handy-collapse/ //https://www.cssscript.com/demo/Nested-Accordion-Content-Toggle-handy-collapse/ //https://stackoverflow.com/questions/6054033/pretty-printing-json-with-php //https://github.com/LorDOniX/json-viewer //https://github.com/JAAulde/cookies ?> <div class="handy-panel left expand"> <button type="button" class="button is-fullwidth" data-nested-button="handy-panel-nested">handy-panel-nested</button> <div class="handy-panelcontent is-1" data-nested-content="handy-panel-nested"> <button type="button" id="loadjsondata">load jsondata</button> <div class="handy-panel left"> <button type="button" class="button is-fullwidth" data-nested-button="handy-panel">handy-panel</button> <div class="handy-panelcontent is-1" data-nested-content="handy-panel"> <div id="handycookiesArray" name="handycookiesArray"></div> <div id="allcookiesArray" name="allcookiesArray"></div> </div> </div> <div class="handy-panel left"> <button type="button" class="button is-fullwidth" data-nested-button="jsonformatview">jsonformatview</button> <div class="handy-panelcontent is-1" data-nested-content="jsonformatview"> <div id="disp_format_json" name="disp_format_json">0</div> <div id="disp_format_json1" name="disp_format_json1">1</div> <div id="disp_format_json2" name="disp_format_json2">2</div> </div> </div> </div> </div> <script type="text/javascript"> var HANDY_PANEL = "handy-panel"; var HANDY_SUBPANEL = "handy-subpanel"; var HANDY_PANELCONTENT = "handy-panelcontent"; var HANDY_NAMESPACE_HEAD = "data" var HANDY_NAMESPACE = "basic" var HANDY_HEADING_TAG = "button"; var HANDY_CONTENT_TAG = "content"; var HANDY_EXPAND_CLASS = "expand"; var HANDY_COLLAPSED_CLASS = "collapsed"; var HANDY_COOKIE_NAME = "handy-panels"; var HANDY_CSS_EASING = "ease-in-out"; var HANDY_ANIMATION_DELAY = 400; /*ms*/ var HANDY_ANIMATION_STEPS = 10; var HANDY_PANEL_LEFT = "left"; var HANDY_PANEL_RIGHT = "right"; var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) { return typeof obj; } : function(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; var _extends = Object.assign || function(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function() { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function(Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var HandyCollapse = function() { function HandyCollapse() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, HandyCollapse); _extends(this, { nameSpace: HANDY_NAMESPACE, toggleHeadingAttr: HANDY_NAMESPACE_HEAD + "-" + (options.nameSpace || HANDY_NAMESPACE) + "-" + HANDY_HEADING_TAG, toggleContentAttr: HANDY_NAMESPACE_HEAD + "-" + (options.nameSpace || HANDY_NAMESPACE) + "-" + HANDY_CONTENT_TAG, isAimation: true, closeOthers: true, animatinSpeed: HANDY_ANIMATION_DELAY, cssEasing: HANDY_CSS_EASING, cookie_name : HANDY_COOKIE_NAME + "-" + options.nameSpace, onSlideStart: function onSlideStart() { return false; }, onSlideEnd: function onSlideEnd() { return false; } }, options); this.toggleHeadingEls = document.querySelectorAll("[" + this.toggleHeadingAttr + "]"); this.toggleContentEls = document.querySelectorAll("[" + this.toggleContentAttr + "]"); this.itemsStatus = {}; this.loadSettings(); this.init(); } _createClass( HandyCollapse, [ { key: "init", value: function init() { if (this.toggleHeadingEls) { this.setListner(); } if (this.toggleContentEls) { this.setItem(); } this.refresh(); } }, { key: "loadSettings", value: function loadSettings() { // prepare the object that will keep the panel statuses this.itemsStatus = {}; var cookie = this.getcookie(); if (cookie[0] == "empty") return; var cookieData = cookie[1]; for( var key in cookieData ) { var value = cookieData[key]; if (key == "undefined" || key == null || key == "") { //alert(key + " " + value); } else { this.itemsStatus[key] = value; } } } }, { key: "saveSettings", value: function saveSettings(id, expand) { // put the new expanding in the object this.itemsStatus[id] = expand; // create an array that will keep the contentid:expanding pairs var panelsData = []; for (var cid in this.itemsStatus) { if (cid == "undefined" || cid == null || cid == "") { //alert(cid + " " + this.itemsStatus[cid]); } else { panelsData.push(cid+":"+this.itemsStatus[cid]); } } // set the cookie expiration date 1 year from now var today = new Date(); var expirationDate = new Date(today.getTime() + 1 * 1000 * 60 * 60 * 24); // write the cookie document.cookie = this.cookie_name + "=" + escape(panelsData.join(",")) + ";expires=" + expirationDate.toGMTString(); } }, { key: "getSubcookie", value: function getSubcookie(cookieValue) { var itemsArray = {}; var cData = cookieValue.split(","); // split each key:value pair and put in object for (var i=0; i< cData.length; i++) { var pair = cData[i].split(":"); itemsArray[pair[0]] = pair[1]; } return itemsArray; } }, { key: "getAllcookies", value: function getAllcookies() { var c = []; if (document.cookie && document.cookie != '') { var split = document.cookie.split(';'); for (var i = 0; i < split.length; i++) { var name_value = split[i].split("="); name_value[0] = name_value[0].replace(/^ /, ''); var name = decodeURIComponent(name_value[0]); var value = this.getSubcookie(decodeURIComponent(name_value[1])); c.push([name, value]); } } else { c = { "empty": "cookie" }; } return c; } }, { key: "getcookie", value: function getcookie() { var c = this.getAllcookies(); var cr = { "empty": "cookie" }; for (var i = 0; i < c.length; i++) { //alert(c[i][0]); if (c[i][0] == this.cookie_name) { cr = [ c[i][0], c[i][1] ]; break; } } return cr; } }, { key: "setListner", value: function setListner() { var _this2 = this; Array.prototype.slice.call(this.toggleHeadingEls).forEach(function(buttonEl, index) { var id = buttonEl.getAttribute(_this2.toggleHeadingAttr); if (id) { buttonEl.addEventListener("click", function(e) { e.preventDefault(); _this2.toggleSlide(id, buttonEl); }, false); } }); } }, { key: "setItem", value: function setItem() { var _this = this; Array.prototype.slice.call(this.toggleContentEls).forEach(function(contentEl) { contentEl.style.maxHeight = "none"; }); } }, { key: "setItemStatus", value: function setItemStatus(id, collapsed) { this.itemsStatus[id] = collapsed; } }, { key: "expandAll", value: function expandAll() { for (var id in this.itemsStatus) this.setItemStatus(id, HANDY_EXPAND_CLASS); this.saveSettings(); this.refresh(); } }, { key: "collapseAll", value: function collapseAll() { for (var id in this.itemsStatus) this.setItemStatus(id, HANDY_COLLAPSED_CLASS); this.saveSettings(); this.refresh(); } }, { key: "refresh", value: function refresh() { var _this2 = this; Array.prototype.slice.call(this.toggleHeadingEls).forEach(function(buttonEl, index) { var id = buttonEl.getAttribute(_this2.toggleHeadingAttr); if (id) { // look for the id in loaded settings, apply the normal/collapsed class if (_this2.itemsStatus.hasOwnProperty(id)) { if (_this2.itemsStatus[id] == HANDY_EXPAND_CLASS) { buttonEl.parentNode.classList.remove(HANDY_COLLAPSED_CLASS); buttonEl.parentNode.classList.add(HANDY_EXPAND_CLASS); } else { buttonEl.parentNode.classList.remove(HANDY_EXPAND_CLASS); buttonEl.parentNode.classList.add(HANDY_COLLAPSED_CLASS); } } else { // if no saved setting, see the initial setting _this2.itemsStatus[id] = (buttonEl.parentNode.classList.contains(HANDY_EXPAND_CLASS)) ? HANDY_EXPAND_CLASS : HANDY_COLLAPSED_CLASS; } var expand = buttonEl.parentNode.classList.contains(HANDY_EXPAND_CLASS); _this2.setItemStatus(id, expand ? HANDY_EXPAND_CLASS : HANDY_COLLAPSED_CLASS); if (expand) { _this2.open(id, false, false); } else { _this2.close(id, false, false); } } }); } }, { key: "toggleSlide", value: function toggleSlide(id, buttonEl) { var isRunCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; if (this.itemsStatus[id] == HANDY_EXPAND_CLASS) { this.saveSettings(id, HANDY_COLLAPSED_CLASS); this.close(id, isRunCallback, this.isAimation); } else { this.saveSettings(id, HANDY_EXPAND_CLASS); this.open(id, isRunCallback, this.isAimation); } } }, { key: "open", value: function open(id) { var _this3 = this; var isRunCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var isAimation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; if (!id) return; if (this.closeOthers) { Array.prototype.slice.call(this.toggleHeadingEls).forEach(function(buttonEl, index) { var closeId = buttonEl.getAttribute(_this3.toggleHeadingAttr); if (closeId !== id) _this3.close(closeId, false, isAimation); }); } if (isRunCallback !== false) this.onSlideStart(true, id); var toggleButton = document.querySelector("[" + this.toggleHeadingAttr + "='" + id + "']"); var toggleContent = document.querySelector("[" + this.toggleContentAttr + "='" + id + "']"); var clientHeight = this.getTargetHeight(toggleContent); toggleButton.parentNode.classList.remove(HANDY_COLLAPSED_CLASS); toggleButton.parentNode.classList.add(HANDY_EXPAND_CLASS); if (isAimation) { toggleContent.style.transition = this.animatinSpeed + "ms " + this.cssEasing; toggleContent.style.maxHeight = (clientHeight || "1000") + "px"; setTimeout(function() { if (isRunCallback !== false) _this3.onSlideEnd(true, id); toggleContent.style.maxHeight = "none"; toggleContent.style.transition = ""; }, this.animatinSpeed); } else { toggleContent.style.maxHeight = "none"; } this.itemsStatus[id] = HANDY_EXPAND_CLASS; } }, { key: "close", value: function close(id) { var _this4 = this; var isRunCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; var isAimation = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; if (!id) return; if (isRunCallback !== false) this.onSlideStart(false, id); var toggleButton = document.querySelector("[" + this.toggleHeadingAttr + "='" + id + "']"); var toggleContent = document.querySelector("[" + this.toggleContentAttr + "='" + id + "']"); toggleButton.parentNode.classList.remove(HANDY_EXPAND_CLASS); toggleButton.parentNode.classList.add(HANDY_COLLAPSED_CLASS); toggleContent.style.maxHeight = toggleContent.clientHeight + "px"; setTimeout(function() { toggleContent.style.maxHeight = "0px"; }, 5); if (isAimation) { toggleContent.style.transition = this.animatinSpeed + "ms " + this.cssEasing; setTimeout(function() { if (isRunCallback !== false) _this4.onSlideEnd(false, id); toggleContent.style.transition = ""; }, this.animatinSpeed); } else { this.onSlideEnd(false, id); } this.itemsStatus[id] = HANDY_COLLAPSED_CLASS; } }, { key: "getTargetHeight", value: function getTargetHeight(targetEl) { if (!targetEl) return; var cloneEl = targetEl.cloneNode(true); var parentEl = targetEl.parentNode; cloneEl.style.maxHeight = "none"; cloneEl.style.opacity = "0"; parentEl.appendChild(cloneEl); targetEl.style.display = "block"; var clientHeight = cloneEl.clientHeight; parentEl.removeChild(cloneEl); return clientHeight; } } ] ); return HandyCollapse; }(); if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === 'object') { module.exports = HandyCollapse; } </script> <script type="text/javascript"> //Nested let handy_nested = new HandyCollapse({ nameSpace: "nested", closeOthers: false }); </script> <script type="text/javascript"> </script> <script type="text/javascript"> function formatJSON(jsonstr, html = false) { var tabcount = 0; var result = ""; var inquote = false; var ignorenext = false; var tab = " "; var newline = "\n"; if (html) { tab = " "; newline = "<br/>"; } for(var i = 0; i < jsonstr.length; i++) { c = jsonstr[i]; if (ignorenext) { result += c; ignorenext = false; } else { switch(c) { case '[': case '{': tabcount++; result += c + newline + tab.repeat( tabcount*2); break; case ']': case '}': tabcount--; result = result.trim() + newline + tab.repeat( tabcount*2) + c; break; case ',': result += c + newline + tab.repeat( tabcount*2); break; case '"': if ( !inquote ) { if ( jsonstr[i-1] == ':' || jsonstr[i-2] == ':' ) result += '<span style="color:#0000ff;">'; else result += '<span style="color:#ff0000;">'; } if (inquote) result += '</span>'; inquote = !inquote; result += c; break; case '\\': if (inquote) ignorenext = true; result += c; break; default: result += c; } } } if (result == "") result = "no data..."; else result = "<pre>"+result+"</pre>"; return result; } var json_data1 = {a:1, 'b':'foo', c:[false, 'false', null, 'null', {d:{e:1.3e5, f:'1.3e5'}}]}; var json_data2 = { "data": { "x": 1, "y": 1, "url": "http://url.com" }, "event": "start", "show": 1, "id": 50 }; var json_data = { key0: "<script>alert('no xss!')<\/script>", key1: "alert('no xss!')", key2: 12345, key3: new Date(), key4: [], key5: [ 123, "123", { a: 5, b: 6, c: null, d: true } ], key6: { a: 1, b: 3, c: { d: 4 } } }; function all_cookiesArray() { function getSubcookie(cookieValue) { var itemsArray = {}; var cData = cookieValue.split(","); // split each key:value pair and put in object for (var i=0; i< cData.length; i++) { var pair = cData[i].split(":"); itemsArray[pair[0]] = pair[1]; } return itemsArray; } var c = []; if (document.cookie && document.cookie != '') { var split = document.cookie.split(';'); for (var i = 0; i < split.length; i++) { var name_value = split[i].split("="); name_value[0] = name_value[0].replace(/^ /, ''); c.push(decodeURIComponent(name_value[0]), getSubcookie(decodeURIComponent(name_value[1]))); } } else { c = { "empty": "cookie" }; } return c; } function loadjsondata() { var json_data_str = JSON.stringify(json_data); document.getElementById("disp_format_json").innerHTML = "json_data<br>"+formatJSON(json_data_str); var json_data_str1 = JSON.stringify(json_data1); document.getElementById("disp_format_json1").innerHTML = "json_data1<br>"+formatJSON(json_data_str1); var json_data_str2 = JSON.stringify(json_data2); document.getElementById("disp_format_json2").innerHTML = "json_data2<br>"+formatJSON(json_data_str2); var handycookiesArray = handy_nested.getcookie(); var handycookiesArray_str = JSON.stringify(handycookiesArray); document.getElementById("handycookiesArray").innerHTML = "handycookiesArray<br>"+formatJSON(handycookiesArray_str); var allcookiesArray = all_cookiesArray(); var allcookiesArray_str = JSON.stringify(allcookiesArray); document.getElementById("allcookiesArray").innerHTML = "allcookiesArray<br>"+formatJSON(allcookiesArray_str); } loadjsondata(); </script> <script type="text/javascript"> document.getElementById("loadjsondata").addEventListener('click', function(event) { event.preventDefault(); loadjsondata(); return false; } ); </script> </body> </html>
|
|||
첨부파일 |
handy-nested-panel.zip (5.9 KB) |
||
다음글 | ci4 초 간단 csv 작성 [한글 안깨짐] | ||
이전글 | Javascript animated collapsibl... (1) | ||
darkninja
/
2023/03/06 21:16:15 /
추천
0
|
darkninja
/
2023/03/29 23:19:21 /
추천
0
key: "saveSettings", value: function saveSettings(id, expand) { ... ... 메인페이지에서는 쿠키가 작동하지만 서브페이지에서는 제대로 일을 하지 않는데요... 아래와 같이 "; path=/" 를 추가하여 쿠키저장위치를 모든 페이지에서 공통으로 사용하도록 해야 하는거 같습니다. 이걸 안해줘도 이론적으로는 어느 위치에서 쿠키가 보관되어도 정상작동해야 되지 않나 하는 생각도 들지만 현실은 그렇지 않으니. (우연히 그렇게 되는 경우도 있긴 한데) 아래 코드로 수정한 후에 Ctrl + Shift + Del 키를 눌러서 묵은 쿠키를 지워야 그 다음 부터는 정상 동작합니다. // write the cookie document.cookie = this.cookie_name + "=" + encodeURIComponent(state) + "; expires=" + expirationDate.toGMTString() + "; path=/"; } 이제 하나를 배우면 하나를 까먹는.
|
지금 실력으로는 이것이 최선의 결과물입니다;
원소스의 'data-nested-control' => 'data-nested-button' 으로 바뀌었습니다.
쿠키 저장과 불러오는 부분이 수정되었습니다
쿠키저장 데이타의 형식은 확장성과 가독성을 봤을때 이 방법이 무난해 보입니다.
더 나은 방법이 있다면 알려주세요.