CodeMirror with 2 text editors and live preview? - javascript

I'm trying to create a live editor like jsfiddle where users can put html in html box (textarea) and css in css box(textarea) and preview the changes live in an iframe.
I am using codemirror as the editor.
So far I can only get the preview of one of the textareas in my iframe and I cannot figure out how to get the values of both textareas (css/html) and display them in my iframe exactly like jsfiddle.
This is what I have so far:
http://jsfiddle.net/vwqgtznv/
and this is my javascript code:
<script>
var delay;
// Initialize CodeMirror editor with a nice html5 canvas demo.
var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
lineNumbers: true,
styleActiveLine: true,
matchBrackets: true,
mode: 'text/html'
});
editor.on("change", function() {
clearTimeout(delay);
//alert("hellooooo");
delay = setTimeout(updatePreview, 300);
});
function updatePreview() {
var previewFrame = document.getElementById('preview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
preview.write(editor.getValue());
preview.close();
}
setTimeout(updatePreview, 300);
</script>
<script>
var delay2;
// Initialize CodeMirror editor with a nice html5 canvas demo.
var editor2 = CodeMirror.fromTextArea(document.getElementById('codert'), {
lineNumbers: true,
styleActiveLine: true,
matchBrackets: true,
mode: 'text/html'
});
editor2.on("change", function() {
clearTimeout(delay2);
//alert("hellooooo");
delay2 = setTimeout(updatePreview2, 300);
});
function updatePreview2() {
var previewFrame2 = document.getElementById('preview');
var preview2 = previewFrame2.contentDocument || previewFrame2.contentWindow.document;
preview2.open();
preview2.write(editor2.getValue());
preview2.close();
}
setTimeout(updatePreview2, 300);
</script>
could someone please help me out and advise on this issue?
Thanks in advance.

Your problem is append CSS to iframe head. Use the code below to update your iframe head for CSS.
function loadCSS() {
var $head = $("#preview").contents().find("head");
$head.html("<style>" + editor.getValue() + "</style>");
};
HTML textarea should be updated with CSS. Add loadCSS() to your updatePreview2()(html textarea update function).
function updatePreview2() {
var previewFrame2 = document.getElementById('preview');
var preview2 = previewFrame2.contentDocument || previewFrame2.contentWindow.document;
preview2.open();
preview2.write(editor2.getValue());
preview2.close();
// added this line
loadCSS();
}
And when your CSS textarea changes, the preview content will be updated by updatePreview()(CSS textarea update function) with CSS content. It should update head only.
function updatePreview() {
loadCSS();
}
Here is the Jsfiddle, please take a demo here.
By the way, try to name your variable and function precisely will make more people help you.
Update
A clean JsFiddle version.

Building upon #North's answer and guidance, I propose this answer. If you +1 this answer, please give +1 to North's answer as well. This is an optimization and expansion up North's anwser, building up a jsfiddle-clone. It therefor demo an answer to the question of this current page.
Jsfiddle -- richer code to go further
Blogpost -- Medium post with some other helpers.
In .html :
<!-- load the relevant dependencies via script and style/link tags. -->
<textarea class="code" id="editor-html">
<textarea class="code" id="editor-css">
<textarea class="code" id="editor-js">
In .js file :
var editorsSettings = {
lineWrapping: true,
lint: true,
lineNumbers: true,
foldGutter: true,
gutters: ["CodeMirror-lint-markers","CodeMirror-linenumbers", "CodeMirror-foldgutter"],
tabSize: 2,
indentUnit: 2,
matchBrackets: true
}
// Editors HTML, CSS, JS : init, bind, define settings.
let editorHTML = CodeMirror.fromTextArea(document.querySelector('#editor-html'), {
mode : "htmlmixed", // require modes for xml, css, js.
htmlMode: true,
...editorsSettings
});
let editorCSS = CodeMirror.fromTextArea(document.querySelector('#editor-css'), {
mode: 'text/css',
...editorsSettings
});
let editorJS = CodeMirror.fromTextArea(document.querySelector('#editor-js'), {
mode: 'text/javascript',
...editorsSettings
});
// Fetch and organize into results
let updatePreview = function() {
let preview = document.querySelector('#preview');
let previewDocument = preview.contentDocument || preview.contentWindow.document;
previewDocument.open();
previewDocument.write(editorHTML.getValue());
previewDocument.write("<script>"+editorJS.getValue()+"<"+"/script>");
previewDocument.close();
previewDocument.querySelector('head').innerHTML = '<style>' + editorCSS.getValue() + '</style>';
}

Related

jPlayer jPlayerAndroidFix not working?

I'm working on a website using jPlayer. The problem appeared when I tried to use it with my android phone, so I started recoding it. Now I'm trying to use the jPlayerAndroidFix class. I'm doing it just like in the example given in the source code in the tutorial, and still it's not working.
Here's the code:
function playSound(sound) {
if (playToggle) {
return;
}
var id = "#jplayer-play";
var media = {
mp3: sound
};
var options = {
swfPath: $('body').data('jplayer-swf'),
solution: 'flash,html',
wmode:"window",
supplied: 'mp3',
preload: 'metadata',
volume: 0.8,
muted: false,
errorAlerts: false,
warningAlerts: false,
customCssIds: true
};
var myAndroidFix = new jPlayerAndroidFix(id, media, options);
myAndroidFix.setMedia(media);
myAndroidFix.play();
}
Important thing to add - the audio is received dynamically, for example from a link:
http://granie.t-mobile.pl/sets/play/69986
and that's the "sound" variable.
What may cause the problem? What am I doing wrong?
The jPlayerAndroidFix class can be found in the source code of
http://jplayer.org/latest/demo-01-android/?theme=0

Angular-leaflet-directive Custom HTML popup

I'm attempting to create a custom popup while using the angular-leaflet-directive. I'm opening the popup from the leaflet.draw on:create event. Here:
map.on('draw:created', function(e) {
layer = e.layer;
drawnItems.addLayer(layer);
var newComment = "Enter Comment";
var newID = "ID";
var newGeoJsonFeat = layer.toGeoJSON();
newGeoJsonFeat.properties = {"comment":newComment, "id":newID};
console.log(newGeoJsonFeat);
onEachFeature(newGeoJsonFeat,layer);
layer.openPopup();
});
Then I'm using #blackjid's logic as seen here: https://github.com/tombatossals/angular-leaflet-directive/issues/238 to bind the custom popup
function onEachFeature(feature, layer) {
// Create get the view template
var popupContent = '<div ng-include="\'partials/popup_newfeat.html\'"></div>';
console.log("assigning popup");
// Bind the popup
// HACK: I have added the stream in the popup options
layer.bindPopup(popupContent,{
closeButton: false,
maxHeight: 300,
feature: feature
});
};
$scope.$on('leafletDirectiveMap.popupopen', function(event, leafletEvent){
// Create the popup view when is opened
var feature = leafletEvent.leafletEvent.popup.options.feature;
var newScope = $scope.$new();
newScope.stream = feature;
$compile(leafletEvent.leafletEvent.popup._contentNode)(newScope);
});
Long story short, Everything works fine except the popup container isn't resizing properly to fit the new content. The height seems right, but the width is off.
I tried using:
.leaflet-popup-content {
width:auto !important;
}
Which will probably suffice, but this causes the popup anchor to shift to the bottom left of the popup for some reason. AutoPan is also broken when clicking near the top of the map.
Does anyone know where and how I can get popup.update() to fire? I believe thats what needs to happen, but I don't know where to implement it. I've tried calling it after layer.openPopup() like so:
onEachFeature(newGeoJsonFeat,layer);
layer.openPopup();
layer.getPopup().update();
});
But that doesn't seem to do anything. Any help is greatly appreciated!
You need to use the 'leafletEvent'. Try this:
myApp.controller('YourController', ['$scope', 'leafletEvent', function($scope) {
// after all your crazy custom popup stuff ...
leafletData.getMap().then(function(map) {
layer.getPopup().update();
});
}]);
I ended up storing the image width in the properties of the GeoJson, and then setting the minWidth to that value in the bindPopup function.
layer.bindPopup(popupContent,{
closeButton: true,
closeOnClick: false,
minWidth: feature.properties.width,
autoPanPadding: L.point(20,20),
keepInView: false,
feature: feature
});

Call Back Editable IFrames Changes into Codemirror

http://jsbin.com/aNirEnUB/3/edit
I've been experimenting with Codemirror for a bit, and today I decided to make the iframe editable, but haven't figured out a way to call back the changes I make to the iframe via change and apply those changes directly to Codemirror.
Is this possible?
JavaScript/JQuery:
var delay;
// Initialize CodeMirror editor
var editor = CodeMirror.fromTextArea(document.getElementById('code'), {
mode: 'text/html',
tabMode: 'indent',
styleActiveLine: true,
lineNumbers: true,
lineWrapping: true,
autoCloseTags: true
});
// Live preview
editor.on("change", function() {
clearTimeout(delay);
delay = setTimeout(updatePreview, 300);
});
function updatePreview() {
var previewFrame = document.getElementById('preview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
preview.write(editor.getValue());
preview.close();
}
setTimeout(updatePreview, 300);
// Make the preview editable
window.onload = function() {
preview.document.designMode = 'On';
};
// Update the Editor Code from Preview Edit
preview.on('change', function() {
clearTimeout(delay);
delay = setTimeout(updateEditor, 300);
});
function updateEditor() {
var previewFrame = document.getElementById('preview');
var preview = previewFrame.contentDocument || previewFrame.contentWindow.document;
preview.open();
editor.setValue(preview.body.innerHTML());
preview.close();
}
setTimeout(updateEditor, 300);
HTML:
<textarea id="code" name="code"><!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>HTML5 canvas demo</title>
<style>p {font-family: monospace;}</style>
</head>
<body>
<p>Canvas pane goes here:</p>
<canvas id=pane width=300 height=200></canvas>
<script>
var canvas = document.getElementById('pane');
var context = canvas.getContext('2d');
context.fillStyle = 'rgb(250,0,0)';
context.fillRect(10, 10, 55, 50);
context.fillStyle = 'rgba(0, 0, 250, 0.5)';
context.fillRect(30, 30, 55, 50);
</script>
</body>
</html></textarea>
<iframe id="preview"></iframe>
Via
https://developer.mozilla.org/en-US/docs/Web/API/Window.frames
I've next to no experience with codemirror, but raw DOM allows access to iframes using Window.frames[]. If you pull the data back in through dom using .addEventListener("onchange",function), you should be able to work with it.
If this answer isn't specific enough (or out of scope, since I don't know a way to do this inside of your framework), please provide me with what exactly you're trying to pull back, and i'll do some more research.
http://jsbin.com/aNirEnUB/4/edit
This is the best I've been able to do.
I got rid of Codemirror, and used a regular textbox/textarea.
I set it all up in a form for easier callbacks.
I could not figure out how to callback an onchange or onkeyup event for the iframe. So instead I call it back by toggling the textbox.
window.onload = function() {
preview.document.designMode = 'On';
preview.document.execCommand("enableObjectResizing", false, "false");
preview.document.execCommand("enableInlineTableEditing", false, "false");
};
// Calls code from preview to textbox
function submit_form() {
var theForm = document.getElementById("container");
theForm.elements.code.value = window.frames.preview.document.body.innerHTML;
theForm.onclick();
}
$(document).ready(function() {
var code = $('#code'),
preview = $('[ID$=preview]');
// Live Debugging
code.keyup(IntPrev);
function IntPrev(e) {
preview.contents().find('body').html(code.val());
}
// Toggle between Designer and Code
$("#design-n-code").click(function() {
preview.toggle();
code.toggle();
}); code.hide();
});

html2canvas - no screenshot for iframe

I have a task where i need to load a URL (e.g www.yahoo.com) , on my webpage, and take screenshot. I am using html2canvas for screenshot and appending it to the body of the page.
The page specified by the URL is successfully loaded in an iframe inside a div element. But when i try to take screenshot of that, the iframe area comes blank.
Below is the code for previewURL and screenshot.
//to preview the URL content
function previewUrl(url,target){
//use timeout coz mousehover fires several times
clearTimeout(window.ht);
window.ht = setTimeout(function(){
var div = document.getElementById(target);
div.innerHTML = '<iframe style="width:100%;height:100%;" frameborder="0" src="' + url + '" />';
},20);
}
function pic() {
html2canvas(document.body, {
onrendered: function(canvas) {
document.body.appendChild(canvas);
}
});
};
And the HTML part goes here :
<body>
<input type="button" class="clear-button" onclick="pic();" value="Take Screenshot" >
Hover to load
<div id="div1"></div>
</body>
The screenshot looks something like this :
I am stuck and don't understand why is this happening. I want something similar to this which can load URL and then onclick can give me screenshot.
The problem here is that you are not pointing correctly to the part of the iframe that you want to take the screenshot, instead you are pointing directly to the document body.
you can try this:
var body = $(iframe).contents().find('body')[0];
html2canvas(body, {
onrendered: function( canvas ) {
$("#content").empty().append(canvas);
},
Hope this helps!
Seems like it's not possible:
The script doesn't render plugin content such as Flash or Java applets. It doesn't render iframe content either.
http://html2canvas.hertzen.com/documentation.html#limitations
This code worked 4 me:
setTimeout(() => {
html2canvas($('#'+idd2).contents().find('body')[0], {
allowTaint : true,
logging: true,
profile: true,
useCORS: true
}).then(function(canvas) {
document.getElementById('screen').appendChild(canvas);
}); }, 3000);

Bootstrap + Zeroclipboard = Tooltips can't be shown on hover?

I'm trying to use ZeroClipboard for a "Click to copy" feature on an element and the same time show a bootstrap tooltip.
Unfortunately the tooltip doesn't work if I use ZeroClipboard on an element. Any help would be greatly appreciated...
// BOOTSTRAP TOOLTIP
$('.myDiv').tooltip({
title: 'Click to copy',
placement: 'right',
trigger: 'hover',
animation: true
});
// ZEROCLIPBOARD
var clip = new ZeroClipboard.Client();
clip.setHandCursor(true);
$('.myDiv').live('mouseover', function () {
clip.setText($(this).text());
if (clip.div) {
clip.receiveEvent('mouseout', null);
clip.reposition(this);
} else clip.glue(this);
clip.receiveEvent('mouseover', null);
});
Managed to get it working in a very simple way
var zero = new ZeroClipboard($el);
$(zero.htmlBridge).tooltip({title: "copy to clipboard", placement: 'bottom'});
Sometimes it is hard to get all the snippets together and to work ... this is a complete solution using ZeroClipboard 1.3.2 and Bootstrap 3.1.0:
HTML:
<a id="copycommand" href="#" data-clipboard-text="text to copy">Copy ...</a>
ZeroClipboard create a container with the ID global-zeroclipboard-html-bridge, this is the access point for the Bootstrap Tooltip.
jQuery:
// initialize Tooltip
$('#global-zeroclipboard-html-bridge').tooltip();
// ZeroClipboad
ZeroClipboard.config({ moviePath: 'ZeroClipboard.swf' });
var clip = new ZeroClipboard(document.getElementById('copycommand'));
clip.on('complete', function(client, args){
alert("Copied text to clipboard: " + args.text);
});
// settings for the Tooltip
clip.on('load', function(client) {
$('#global-zeroclipboard-html-bridge').attr({
'data-toggle':'tooltip',
'data-title': 'Tooltip text goes here ...',
'data-placement': 'bottom',
'data-html': true
});
// show the tooltip
$('#global-zeroclipboard-html-bridge').tooltip('show');
});
If you run Tooltip after ZeroClipboard it should work without problems!
Found a workaround by putting the tooltip to be shown on click for Bootstrap, but then using hooks in ZeroClipboard to show and hide it upon hover.
Here is how I did it:
$('div.color-inspiration span').tooltip({
title: 'Click to copy',
placement: 'right',
trigger: 'click',
animation: false
});
var element = null;
var clip = new ZeroClipboard.Client();
clip.setHandCursor(true);
$('div.color-inspiration span').live('mouseover', function () {
element = $(this);
clip.setText($(this).text());
if (clip.div) {
clip.receiveEvent('mouseout', null);
clip.reposition(this);
} else clip.glue(this);
clip.receiveEvent('mouseover', null);
});
clip.addEventListener( 'onMouseOver', my_mouse_over_handler );
function my_mouse_over_handler( client ) {
$(element).tooltip('show');
}
clip.addEventListener( 'onMouseOut', my_mouse_out_handler );
function my_mouse_out_handler( client ) {
$(element).tooltip('hide');
}
clip.addEventListener( 'onMouseUp', my_mouse_up_handler );
function my_mouse_up_handler( client ) {
$(element).tooltip('hide');
}
Old question but I recently encountered this problem and was able to find a solution, it's rather simple but a bit blanket. Because the flash element positions itself with a zindex of 10000 on top of whatever element you have on the page you'll have to append the flash element with a selector and title. This can be done with the ZeroClipboard callbacks.
clip.on( 'load', function(client) {
$('#global-zeroclipboard-html-bridge').attr('rel', 'tooltip').attr('title', 'Click Here To Copy URL');
} );
With Zero Clipboard 2.2 and Bootstrap 3 I got it to work like this
var $copyButton = $('.clipboard');
var clip = new ZeroClipboard($copyButton);
clip
.on('ready', function() {
$('#global-zeroclipboard-html-bridge').attr({
'data-toggle': 'tooltip',
'data-title': 'Copy to clipboard...',
'data-placement': 'right'
});
$('#global-zeroclipboard-html-bridge').tooltip({
container: 'body',
trigger: 'hover'
});
})
.on('aftercopy', function() {
$('#global-zeroclipboard-html-bridge').tooltip('hide');
});
Change the selector on line one.
the #global-zeroclipboard-html-bridge selector targets a div that is inserted by the Zero Clipboard component and that overlays the copy button.
bug is a known issue and mentioned here: Zeroclipboard bug causing issue: see # https://github.com/zeroclipboard/zeroclipboard/issues/369
Adding to #gnorsilva's answer. Here is how I set new text on the tooltip once it was copied successfully:
$(clip.htmlBridge).tooltip({
title: 'copy to clipboard',
placement: 'bottom'
});
clip.on('load', function(client) {
client.on('complete', function() {
$('.tooltip .tooltip-inner').text('copied!');
});
});
This achieves the same effect as GitHub when you click one of their ZeroClipboard elements such as copy SHA or when you click the clone URL button

Categories

Resources