experiments/animate_folding.html (180 lines of code) (raw):

<!DOCTYPE html> <html lang="en"> <head> <!-- Animate Code Folding Experiment Animates closing of folds in Chrome and WebKit. Requires 3D CSS and CSS transitions. TODO * animate opening * fix closing at the bottom of the file * support folding with closed folds on the screen (rows are off) * support more browsers * speed --> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Editor</title> <style type="text/css" media="screen"> body { overflow: hidden; } pre { margin: 0; } #editor { position: absolute; height: 100%; width: 100%; } #container { -webkit-transform: scaleZ(0.0000001); margin: 0; position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; } .ace_slide { position: absolute; width: 100%; overflow: hidden; background-image: url(zenbg.png); /* ease in sine */ -webkit-transition: height 500ms cubic-bezier(0.470, 0.000, 0.745, 0.715); -webkit-perspective: 2000; -webkit-perspective-origin: 50% 50%; } .ace_anim_slide_top { z-index: -1; background-color: white; background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0) 0%,rgba(0, 0, 0, 0.05) 50%); top: 0; -webkit-transition: -webkit-transform 500ms linear; -webkit-transform-style: preserve-3d; -webkit-transform-origin: top; -webkit-transform: rotateX(0deg); } .ace_anim_slide_bottom { background-color: white; background-image: -webkit-linear-gradient(bottom, rgba(255, 255, 255, 0) 0%,rgba(0, 0, 0, 0.05) 100%); bottom: 0; -webkit-transition: -webkit-transform 500ms linear; -webkit-transform-style: preserve-3d; -webkit-transform-origin: bottom; -webkit-transform: rotateX(0deg); } .ace_anim_hidden .ace_anim_slide_top { -webkit-transform: rotateX(-90deg); } .ace_anim_hidden .ace_anim_slide_bottom { -webkit-transform: rotateX(90deg); } .ace_anim_bottom { /* ease in sine */ -webkit-transition: top 500ms cubic-bezier(0.470, 0.000, 0.745, 0.715); -webkit-transform: scaleZ(0.0000001); } </style> </head> <body> <div id="container"> <div id="editor"></div> </div> <script src="../build/src/ace-uncompressed.js" type="text/javascript" charset="utf-8"></script> <script src="../build/src/mode-javascript.js" type="text/javascript" charset="utf-8"></script> <script id="main"> window.onload = function() { var editor = ace.edit("editor"); var JavaScriptMode = require("ace/mode/javascript").Mode; var EditSession = require("ace/edit_session").EditSession; var lang = require("ace/lib/lang"); var Range = require("ace/range").Range; editor.getSession().setMode(new JavaScriptMode()); editor.getSession().setValue(document.getElementById("main").innerHTML); function cloneSession(session) { var s = new EditSession(session.getDocument(), session.getMode()); // Copy over 'settings' from the session. s.setTabSize(session.getTabSize()); s.setUseSoftTabs(session.getUseSoftTabs()); s.setOverwrite(session.getOverwrite()); s.setBreakpoints(session.getBreakpoints()); s.setUseWrapMode(session.getUseWrapMode()); s.setUseWorker(false); s.setWrapLimitRange(session.$wrapLimitRange.min, session.$wrapLimitRange.max); s.$foldData = session.$cloneFoldData(); return s; } function animateFold(editor, placeholder, range) { var session = editor.getSession(); var ed = document.getElementById("editor"); var parent = ed.parentNode; var clone = ed.cloneNode(); var cloneEd = ace.edit(clone); var renderer = cloneEd.renderer; cloneEd.setSession(cloneSession(session)); cloneEd.setTheme(editor.getTheme()); renderer.scrollToY(editor.renderer.getScrollTop()); parent.appendChild(clone); cloneEd.resize(); renderer.$size = lang.copyObject(cloneEd.renderer.$size); renderer.layerConfig = lang.copyObject(cloneEd.renderer.layerConfig); renderer.$textLayer.$characterSize = lang.copyObject(editor.renderer.$textLayer.$characterSize); renderer.$textLayer._emit("changeCharaterSize", {data: renderer.$textLayer.$characterSize}); renderer.$loop.onRender(renderer.$loop.changes); // top area var clone2 = clone.cloneNode(true); var topHeight = range.start.row * renderer.lineHeight - renderer.scrollTop clone2.style.height = topHeight + "px"; parent.appendChild(clone2); // middle cloneEd.scrollToRow(range.start.row); renderer.$loop.onRender(renderer.$loop.changes); var middleHeight = (range.end.row - range.start.row) * renderer.lineHeight; var slide = document.createElement("div"); slide.className = "ace_slide"; slide.style.top = topHeight + "px"; slide.style.height = middleHeight + "px"; var clone3 = clone.cloneNode(true); clone3.className += " ace_anim_slide_top"; clone3.style.height = middleHeight + "px"; slide.appendChild(clone3); renderer.scrollToY(renderer.scrollTop + Math.floor(middleHeight / 2)); renderer.$loop.onRender(renderer.$loop.changes); var clone3 = clone.cloneNode(true); clone3.className += " ace_anim_slide_bottom"; clone3.style.top = null; clone3.style.height = (middleHeight / 2) + "px"; slide.appendChild(clone3); parent.appendChild(slide); // bottom cloneEd.scrollToRow(range.start.row) cloneEd.getSession().addFold(placeholder, range); renderer.$loop.onRender(renderer.$loop.changes); var clone4 = clone.cloneNode(true); clone4.className += " ace_anim_bottom"; clone4.style.top = (topHeight + middleHeight) + "px"; parent.appendChild(clone4); cloneEd.destroy(); parent.removeChild(clone); ed.style.left = "-10000px"; setTimeout(function() { clone4.style.top = topHeight + "px"; slide.style.height = 0; slide.className += " ace_anim_hidden"; setTimeout(function() { ed.style.left = 0; setTimeout(function() { parent.removeChild(clone2); parent.removeChild(slide); parent.removeChild(clone4); }, 0); }, 500); }, 0); } var origOnFoldWidgetClick = EditSession.prototype.onFoldWidgetClick; EditSession.prototype.onFoldWidgetClick = function() { var orig = EditSession.prototype.addFold; EditSession.prototype.addFold = function(placeholder, range) { EditSession.prototype.addFold = orig; animateFold(editor, placeholder, range); this.addFold(placeholder, range); } var ret = origOnFoldWidgetClick.apply(this, arguments); return ret; } }; </script> </body> </html>