/** * plugin.js * * Copyright, Moxiecode Systems AB * Released under LGPL License. * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /*global tinymce:true */ tinymce.PluginManager.add('layer', function(editor) { function getParentLayer(node) { do { if (node.className && node.className.indexOf('mceItemLayer') != -1) { return node; } } while ((node = node.parentNode)); } function visualAid(e) { var dom = editor.dom; tinymce.each(dom.select('div,p', e), function(e) { if (/^(absolute|relative|fixed)$/i.test(e.style.position)) { if (e.hasVisual) { dom.addClass(e, 'mceItemVisualAid'); } else { dom.removeClass(e, 'mceItemVisualAid'); } dom.addClass(e, 'mceItemLayer'); } }); } function move(d) { var i, z = [], le = getParentLayer(editor.selection.getNode()), ci = -1, fi = -1, nl; nl = []; tinymce.walk(editor.getBody(), function(n) { if (n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position)) { nl.push(n); } }, 'childNodes'); // Find z-indexes for (i = 0; i < nl.length; i++) { z[i] = nl[i].style.zIndex ? parseInt(nl[i].style.zIndex, 10) : 0; if (ci < 0 && nl[i] == le) { ci = i; } } if (d < 0) { // Move back // Try find a lower one for (i = 0; i < z.length; i++) { if (z[i] < z[ci]) { fi = i; break; } } if (fi > -1) { nl[ci].style.zIndex = z[fi]; nl[fi].style.zIndex = z[ci]; } else { if (z[ci] > 0) { nl[ci].style.zIndex = z[ci] - 1; } } } else { // Move forward // Try find a higher one for (i = 0; i < z.length; i++) { if (z[i] > z[ci]) { fi = i; break; } } if (fi > -1) { nl[ci].style.zIndex = z[fi]; nl[fi].style.zIndex = z[ci]; } else { nl[ci].style.zIndex = z[ci] + 1; } } editor.execCommand('mceRepaint'); } function insertLayer() { var dom = editor.dom, p = dom.getPos(dom.getParent(editor.selection.getNode(), '*')); var body = editor.getBody(); editor.dom.add(body, 'div', { style: { position: 'absolute', left: p.x, top: (p.y > 20 ? p.y : 20), width: 100, height: 100 }, 'class': 'mceItemVisualAid mceItemLayer' }, editor.selection.getContent() || editor.getLang('layer.content')); // Workaround for IE where it messes up the JS engine if you insert a layer on IE 6,7 if (tinymce.Env.ie) { dom.setHTML(body, body.innerHTML); } } function toggleAbsolute() { var le = getParentLayer(editor.selection.getNode()); if (!le) { le = editor.dom.getParent(editor.selection.getNode(), 'DIV,P,IMG'); } if (le) { if (le.style.position.toLowerCase() == "absolute") { editor.dom.setStyles(le, { position: '', left: '', top: '', width: '', height: '' }); editor.dom.removeClass(le, 'mceItemVisualAid'); editor.dom.removeClass(le, 'mceItemLayer'); } else { if (!le.style.left) { le.style.left = 20 + 'px'; } if (!le.style.top) { le.style.top = 20 + 'px'; } if (!le.style.width) { le.style.width = le.width ? (le.width + 'px') : '100px'; } if (!le.style.height) { le.style.height = le.height ? (le.height + 'px') : '100px'; } le.style.position = "absolute"; editor.dom.setAttrib(le, 'data-mce-style', ''); editor.addVisual(editor.getBody()); } editor.execCommand('mceRepaint'); editor.nodeChanged(); } } // Register commands editor.addCommand('mceInsertLayer', insertLayer); editor.addCommand('mceMoveForward', function() { move(1); }); editor.addCommand('mceMoveBackward', function() { move(-1); }); editor.addCommand('mceMakeAbsolute', function() { toggleAbsolute(); }); // Register buttons editor.addButton('moveforward', {title: 'layer.forward_desc', cmd: 'mceMoveForward'}); editor.addButton('movebackward', {title: 'layer.backward_desc', cmd: 'mceMoveBackward'}); editor.addButton('absolute', {title: 'layer.absolute_desc', cmd: 'mceMakeAbsolute'}); editor.addButton('insertlayer', {title: 'layer.insertlayer_desc', cmd: 'mceInsertLayer'}); editor.on('init', function() { if (tinymce.Env.ie) { editor.getDoc().execCommand('2D-Position', false, true); } }); // Remove serialized styles when selecting a layer since it might be changed by a drag operation editor.on('mouseup', function(e) { var layer = getParentLayer(e.target); if (layer) { editor.dom.setAttrib(layer, 'data-mce-style', ''); } }); // Fixes edit focus issues with layers on Gecko // This will enable designMode while inside a layer and disable it when outside editor.on('mousedown', function(e) { var node = e.target, doc = editor.getDoc(), parent; if (tinymce.Env.gecko) { if (getParentLayer(node)) { if (doc.designMode !== 'on') { doc.designMode = 'on'; // Repaint caret node = doc.body; parent = node.parentNode; parent.removeChild(node); parent.appendChild(node); } } else if (doc.designMode == 'on') { doc.designMode = 'off'; } } }); editor.on('NodeChange', visualAid); });