제목 | 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) |
||
이전글 | Javascript animated collapsibl... (1) | ||
darkninja
/
2023/03/06 21:16:15 /
추천
0
|
지금 실력으로는 이것이 최선의 결과물입니다;
원소스의 'data-nested-control' => 'data-nested-button' 으로 바뀌었습니다.
쿠키 저장과 불러오는 부분이 수정되었습니다
쿠키저장 데이타의 형식은 확장성과 가독성을 봤을때 이 방법이 무난해 보입니다.
더 나은 방법이 있다면 알려주세요.