Creating CodeMirror dynamically - rendering issues - javascript

I recently started to develop a class that manipulates over CodeMirror - dynamically links necessary libraries, provides comunication with server and so on.
Because of that I hold everything in variables, and upon initialisation, the CodeMirror is appended to DOM node which is not within document tree. Just like that:
var holder = document.createElement("div");
var textarea = document.createElement("textarea");
holder.appendChild(textarea);
this.editor = CodeMirror.fromTextArea(textarea, {/*options*/});
Then I append the DIV myself when .show() method is called upon my class:
this.show(node) {
if(this.editor!=null) {
node.parentNode.replaceChild(holder,node);
}
}
The editor is OK since click into it and try to draw, or after I resize window. But before, I just see blank area with disabled scroll bar. I believe this is because of way I initialise whole CodeMirror.
So what should I do to make it work, if I want to keep my class structure?
Link to live code (not for IE).

A more direct way would be to call .refresh() on the CodeMirror instance after showing it. See http://codemirror.net/doc/manual.html#refresh

So I solved the issue very simply - I dispatch onresize event after adding editor to dom tree:
node.parentNode.replaceChild(holder,node);
var evt = document.createEvent('UIEvents');
evt.initUIEvent('resize', true, false,window,0);
window.dispatchEvent(evt);
Based on How to dispatch resize event? question.

Related

How to Add Event Listeners to SVG Elements Loaded From File Dynamically?

Problem Statement
I'm trying to load an svg file dynamically, and then listen to click events on the individual svg elements. The svg loads fine, but I'm having trouble detecting /when/ it has loaded so that I can add the listeners.
Context
The svg is a map that will pop up when the user clicks on a field. They should then be able to select a country from the map. The svg needs to be loaded dynamically because the field can be parameterized with different maps.
What I've tried
It seems like the common recommendation is to listen for a "load" event on the dynamically created element and then access the actual svg elements through the element.contentDocument property or the element.getSVGDocument() function.
var element = document.createElement('embed');
element.src = this.mapSrc_;
element.type = 'image/svg+xml';
document.body.appendChild(element );
element.addEventListener('load', function() {
console.log(element.firstChild, element.contentDocument, element.getSVGDocument());
});
or:
var element = document.createElement('object');
element.setAttribute('data', this.mapSrc_);
element.setAttribute('type', 'image/svg+xml';
document.body.appendChild(element);
element.addEventListener('load', function() {
console.log(element.firstChild, element.contentDocument, element.getSVGDocument());
});
But in both cases I get a console log of:
null undefined null
What is the proper way to load an svg from a file and then add event listeners to it?
Thank you for taking the time to read this! I really appreciate any help :D
[EDIT: If you like you can view my actual code here, but be warned it is pretty thoroughly tied to the Blockly framework.]
After some trial and error it seems like this is a problem with running the page from file, specifically on Chrome and Firefox (works on Edge and IE11).
You can test this by downloading this example page. If you run it from file the icons stay orange, but the online page works.
I will continue with this by testing on Edge instead of Chrome, but other people may have different solutions for this problem.

change default cursor style in PIXI.js

I want to change my cursor when triggering a mousedown event. I found a lot of hints how to achieve that - but these have one major issue. To change the defaultCursorStyle property I need to instantiate the InteractionManager prototype.
var renderer = PIXI.autoDetectRenderer(640, 480),
var interactionManager = new PIXI.interaction.InteractionManager(renderer)
interactionManager.defaultCursorStyle = "crosshair" // a native html/css cursor style
That looks fine at first but the problem here is that this InteractionManager seems to batch-register all events applied to PIXI object via the .on(event, callback) event-binding function per instance.
That means that if there would be a second instance of this InteractionManager, all events would be bound twice and therefore triggered twice. I had this exact issue.
So I needed to revert my changes and try to access the default InteractionManager. Somebody in the HTML5GameDev forum told me to access it like this:
renderer.plugins.interaction
knowing that I tried the following:
renderer.plugins.interaction.defaultCursorStyle = "crosshair"
My events now worked properly again. But the cursor change did not happen. However debugging the line told me that the property defaultCursorStyle was successfully set to "crosshair". Now I'm looking for a way to make this change visible.
My question:
Is there a better way to change the cursor style than the mentioned one above? If no, how can I make my default cursor change visible after setting the new style to the default InteractionManager?
There's a setCursorMode method in the docs, guess it's what you need.
const app = new PIXI.Application({ height, width })
app.renderer.plugins.interaction.cursorStyles.default = 'crosshair'
setTimeout(() => {
app.renderer.plugins.interaction.setCursorMode('pointer')
}, 1000)
Whenever cursor leaves the renderer, PIXI resets cursor mode (here's exactly the line). So you might want to set new cursor mode as default each time you change it.
function changeCursorMode (cursorMode) {
app.renderer.plugins.interaction.cursorStyles.default = cursorMode
app.renderer.plugins.interaction.setCursorMode(cursorMode)
}
app.renderer.plugins.interaction.cursorStyles.crosshair = 'crosshair'
changeCursorMode('crosshair')

Proper Way Of Modifying Toolbar After Init in TinyMCE

I am extending a cloud-hosted LMS with javascript. Therefore, we can add javascript to the page, but cannot modify the vendor javascript for different components.
The LMS uses tinyMCE frequently. The goal is to add a new button on to the toolbar of each tinyMCE editor.
The problem is that since the tinyMCE modules are initialized in the vendor's untouchable code, we cannot modify the init() call. Therefore, we cannot add any text on to the "toolbar" property of the init() object.
So I accomplished this in a moderately hacky way:
tinyMCE.on('AddEditor', function(e){
e.editor.on('init', function(){
tinyMCE.ui.Factory.create({
type: 'button',
icon: 'icon'
}).on('click', function(){
// button pressing logic
})
.renderTo($(e.editor.editorContainer).find('.mce-container-body .mce-toolbar:last .mce-btn-group > div')[0])
});
});
So this works, but needless to say I am not totally comfortable having to look for such a specific location in the DOM like that to insert the button. Although this works, I do not believe it was the creator's intention for it to be used like this.
Is there a proper way to add the button to a toolbar, after initialization, if we cannot modify the initialization code?
I found a more elegant solution, but it still feels a bit like a hack. Here is what I got:
// get an instance of the editor
var editor=tinymce.activeEditor; //or tinymce.editors[0], or loop, whatever
//add a button to the editor buttons
editor.addButton('mysecondbutton', {
text: 'My second button',
icon: false,
onclick: function () {
editor.insertContent(' <b>It\'s my second button!</b> ');
}
});
//the button now becomes
var button=editor.buttons['mysecondbutton'];
//find the buttongroup in the toolbar found in the panel of the theme
var bg=editor.theme.panel.find('toolbar buttongroup')[0];
//without this, the buttons look weird after that
bg._lastRepaintRect=bg._layoutRect;
//append the button to the group
bg.append(button);
I feel like there should be something better than this, but I didn't find it.
Other notes:
the ugly _lastRepaintRect is needed because of the repaint
method, which makes the buttons look ugly regardless if you add new
controls or not
looked in the code, there is no way of adding new controls to the
toolbar without repainting and there is no way to get around it
without the ugly hack
append(b) is equivalent to add(b).renderNew()
you can use the following code to add the button without the hack, but you are shortcircuiting a lot of other stuff:
Code:
bg.add(button);
var buttonElement=bg.items().filter(function(i) { return i.settings.text==button.text; })[0];
var bgElement=bg.getEl('body');
buttonElement.renderTo(bgElement);

TinyMCE opened in jqueryUI modal dialog

When using tinyMCE in a jqueryUI modal dialog, I can't use the hyperlink or 'insert image' features.
Basically, after lots of searching, I've found this:
http://www.tinymce.com/develop/bugtracker_view.php?id=5917
The weird thing is that to me it seams less of a tinyMCE issue and more of a jqueryUI issue since the problem is not present when jqueryUI's modal property is set to false.
With a richer form I saw that what happens is that whenever the tinyMCE loses focus, the first element in the form gets focus even if it's not the one focused / clicked.
Does some JavaScript guru have any idea how I might be able to keep the dialog modal and make tinyMCE work?
This fixed it for me when overriding _allowInteraction would not:
$(document).on('focusin', function(e) {
if ($(event.target).closest(".mce-window").length) {
e.stopImmediatePropagation();
}
});
I can't really take credit for it. I got it from this thread on the TinyMCE forums.
(They have moved their bugtracker to github. tinymce/issues/703 is the corresponding github issue.)
It seems there are no propper solution for this issue yet. This is kind of a hack but it really worked for me.
Every time you open the Dialog remove the text area and re add it like following,
var myDialog = $('#myDialog');
var myTextarea = myDialog.find('textarea');
var clonedTextArea = myTextarea.clone(); // create a copy before deleting from the DOM
var myTextAreaParent = myTextarea.parent(); // get the parent to add the created copy later
myTextarea.remove(); // remove the textarea
myDialog.find('.mce-container').remove(); // remove existing mce control if exists
myTextAreaParent.append(clonedTextArea); // re-add the copy
myDialog.dialog({
open: function(e1,e2){
setTimeout(function () {
// Add your tinymce creation code here
},50);
}
});
myDialog.dialog('open');
This seems to fix it for me, or at least work around it (put it somewhere in your $(document).ready()):
$.widget('ui.dialog', $.ui.dialog, {
_allowInteraction: function(event) {
return ($('.mce-panel:visible').length > 0);
}
});

jquery minimal rich textbox plugin

I am looking for a very minimal jQuery rich textbox plugin for a web app I am working on.
The user will only need to see the 'textbox', and not any toolbars as all of the rich formatting will be coded depending on what they type.
I have attempted to create my own with an iframe, but there are problems. One of them being when wrapping strings in divs, the caret is moved to the beginning and it can't be moved inside the div without clicking. http://jsfiddle.net/DVjYa/
This is a problem because I need it to behave like a normal textbox. In a normal textbox, you would be able to navigate with the arrow keys without having to click. Hence why I am looking for a plugin which has already overcome these problems.
You can use CLEDITOR which is very lightweight. You can disable all the toolbar buttons and hide the toolbar as well. In addition to this, it lets you make the selection bold/italic using keyboard shortcuts (CTRL+B/CTRL+I) even though the toolbar does not exist.
Demo: http://jsfiddle.net/Rft3A/
var editorDoc;
$(function() {
var editor = document.getElementById ("editable");
if (editor.contentDocument) {
editorDoc = editor.contentDocument;
} else {
editorDoc = editor.contentWindow.document;
}
var editorBody = editorDoc.body;
if ('contentEditable' in editorBody) {
// allow contentEditable
editorBody.contentEditable = true;
}
else { // Firefox earlier than version 3
if ('designMode' in editorDoc) {
// turn on designMode
editorDoc.designMode = "on";
}
}
});
will add another answer although post is a little old
Trumbowyg A lightweight and amazing WYSIWYG JavaScript editor - 15kB only (from github page)

Categories