I have a question regarding the integration of CodeMirror UI in a smartGWT tab.
Basically, I can't display the CodeMirror-UI editor inside the textarea element I attached to a smartGWT tab. Here's what I did:
I installed CodeMirror-UI as described on its page, correcting the paths to match my project's directory hierarchy
I wrote a js script in my project's main html (at head) :
<head>
...
<script>
function fireEditor()
{
var textarea = window.document.getElementById('tab_editor' );
var uiOptions = { path : 'codemirror-ui/js/', searchMode : 'inline' };
var codeMirrorOptions = { mode: 'javascript' };
var editor = new CodeMirrorUI(textarea,uiOptions,codeMirrorOptions);
}
</script>
</head>
I invoked the script while opening a (smartGWT) tab:
// create a smartGWT tab
Tab tab = new Tab("tab");
tab.setID("tab");
tab.setCanClose(true);
// put the CodeMirror UI inside the smartGWT tab
// create a smartGWT canvas
Canvas tabContent = new Canvas();
tabContent.setID("tabc");
tabContent.setWidth100();
tabContent.setHeight100();
// use a GWT HTMLPanel to attach new html elements to the smartGWT canvas
// and invoke the fireEditor() function to load the CodeMirror UI
HTMLPanel editorContainer = new HTMLPanel(
"<div id=\"editor_container\">"
+ "<textarea id=\"tab_editor\" style=\"width:100%;height:100%\" onload=\"fireEditor()\">"
+ "</textarea>"
+ "</div>");
editorContainer.setWidth("100%");
editorContainer.setHeight("100%");
running from a browser (I'm using firefox - iceweasel 10.0.10), this results in a smartGWT tab that shows an empty textarea element.
Checking with firebug, the area within the smartGWT tab contains the HTML I specified in the HTMLPanel, but no CodeMirror UI is shown.
What am I missing?
I'm using Eclipse Indigo, with gwt 2.4.0, smartgwt 3.0p, and codemirror ui 0.0.19 from its git repo (which itself uses CodeMirror 2.3).
Thank you
Found the solution.
First of all, there is no "onload" event for an html textarea element, so the code
HTMLPanel editorContainer = new HTMLPanel(
"<div id=\"editor_container\">"
+ "<textarea id=\"tab_editor\" style=\"width:100%;height:100%\" onload=\"fireEditor()\">"
+ "</textarea>"
+ "</div>");
will just place a textarea in the HTMLPanel, without calling "fireEditor()".
Replacing "onload" with "onclick" does the trick: once the textarea element shows up, click on it, and the CodeMirrorUI will show up as well.
Problem: I need to visualize the CodeMirrorUI interface automatically, ergo the "onclick" approach is useless.
To accomplish this task, I need to somehow modify the DOM of the smartGWT tab, replacing its inner html with CodeMirrorUI's html.
I found this documentation very helpful: http://www.smartclient.com/smartgwtee-latest/javadoc/com/smartgwt/client/docs/DomIntegration.html
this is the resulting code:
1) I kept the js script in my project's main html (at head) :
<head>
...
<script>
function fireEditor()
{
var textarea = window.document.getElementById('tab_editor' );
var uiOptions = { path : 'codemirror-ui/js/', searchMode : 'inline' };
var codeMirrorOptions = { mode: 'javascript' };
var editor = new CodeMirrorUI(textarea,uiOptions,codeMirrorOptions);
}
</script>
</head>
2) I created a new class -"MyEditor", following the example found in the documentation link I mentioned above :
public class MyEditor extends Canvas {
private String editor_id = null;
private static native void replace(String editor) /*-{
$wnd.fireEditor(editor);
}-*/;
public MyEditor(Integer num) {
editor_id = "editor_" + num;
setRedrawOnResize(false);
}
#Override
public String getInnerHTML() {
return "<textarea id=\"" + editor_id + "\"" + "style=\"width:100%;height:100%\"></textarea>";
}
#Override
protected void onDraw() {
MyEditor.replace(editor_id);
}
}
3) finally, I filled the smartGWT tab with an instance of MyEditor:
// create a smartGWT tab
Tab tab = new Tab("tab");
tab.setID("tab");
tab.setCanClose(true);
MyEditor editor = new MyEditor(tabNumber); // an integer number
tab.setPane(editor);
Tested. Working.
Related
I'm trying to create a customized button to appear on a pop up which generates a dynamic link (a URL). I don't seem to be able to do this via the .setHTML because of the timing, can't bind a button to a function at runtime. So I thought I'd try the newish .setDOMContent
There's zero information online as to how this feature works. I'm wondering if anyone has an example of this where a button is added to the popup that can run a function and send data.
Here's my very poor attempt at setting this up.
This function creates the popup
function GameObjectPopup(myObject) {
var features = map.queryRenderedFeatures(myObject.point, {
layers: ['seed']
});
if (!features.length) {
return;
}
var feature = features[0];
// Populate the popup and set its coordinates
// based on the feature found.
var popup = new mapboxgl.Popup()
.setLngLat(feature.geometry.coordinates)
.setHTML(ClickedGameObject(feature))
.setDOMContent(ClickedGameObject2(feature))
.addTo(map);
};
This function adds the html via the .setHTML
function ClickedGameObject(feature){
console.log("clicked on button");
var html = '';
html += "<div id='mapboxgl-popup'>";
html += "<h2>" + feature.properties.title + "</h2>";
html += "<p>" + feature.properties.description + "</p>";
html += "<button class='content' id='btn-collectobj' value='Collect'>";
html += "</div>";
return html;
}
This function wants to add the DOM content via the .setDOMContent
function ClickedGameObject2(feature){
document.getElementById('btn-collectobj').addEventListener('click', function()
{
console.log("clicked a button");
AddGameObjectToInventory(feature.geometry.coordinates);
});
}
I'm trying to pipe the variable from features.geometry.coordinates into the function AddGameObjectToInventory()
the error I'm getting when clicking on an object (so as popup is being generated)
Uncaught TypeError: Cannot read property 'addEventListener' of null
Popup#setHTML takes a string that represents some HTML content:
var str = "<h1>Hello, World!</h1>"
popup.setHTML(str);
while Popup#setDOMContent takes actual HTML nodes. i.e:
var h1 = document.createElement('h1');
h1.innerHTML="Hello, World";
popup.setDOMContent(h1);
both of those code snippets would result in identical Popup HTML contents. You wouldn't want to use both methods on a single popup because they are two different ways to do the same thing.
The problem in the code you shared is that you're trying to use the setDOMContent to add an event listener to your button, but you don't need to access the Popup object to add the event listener once the popup DOM content has been added to the map. Here is a working version of what I think you're trying to do: https://jsfiddle.net/h4j554sk/
I'm trying to add an external web widget from a weather website. It gives me somethink like this:
<div id='cont_5caab8f298a3d34d53973f2d8906d1f7'><script type='text/javascript' async src='https://www.tiempo.com/wid_loader/5caab8f298a3d34d53973f2d8906d1f7'></script></div>
I've tried creating a HTML widget with that code and adding it to my panel, but it doesn't show.
The embed code you have been given only works when it is included in the HTML file. It doesn't work when added dynamically. For example, if you open an empty HTML file in a web browser and run:
document.body.innerHTML += "<div id='cont_5caab8f298a3d34d53973f2d8906d1f7'><script type='text/javascript' async src='https://www.tiempo.com/wid_loader/5caab8f298a3d34d53973f2d8906d1f7'></script></div>";
in the developer (F12) console, you will see that the external content doesn't get loaded. This is because scripts will not automatically be executed when added in this way.
You don't need to execute this external script, however. All it does is create and insert an iframe, and set some attributes and styling. If we look at the source code of the script, we can translate it into a GWT equivalent.
Embed JS script:
conte = document.getElementById("cont_5caab8f298a3d34d53973f2d8906d1f7");
if (conte) {
conte.style.cssText = "width: 176px; color: #868686; background-color:#FFFFFF; border:1px solid #D6D6D6; margin: 0 auto; font-family: Roboto;";
elem = document.createElement("iframe");
elem.style.cssText = "width:176px; color:#868686; height:200px;";
elem.id = "5caab8f298a3d34d53973f2d8906d1f7";
elem.src = "https://www.tiempo.com/getwid/5caab8f298a3d34d53973f2d8906d1f7";
elem.frameBorder = 0;
elem.allowTransparency = true;
elem.scrolling = "no";
elem.name = "flipe";
conte.appendChild(elem);
}
GWT equivalent:
public class Hello implements EntryPoint {
public void onModuleLoad() {
Panel root = RootPanel.get("main"); // replace with your Panel
//This doesn't work:
//HTML embed = new HTML("<div id='cont_5caab8f298a3d34d53973f2d8906d1f7'><script type='text/javascript' async src='https://www.tiempo.com/wid_loader/5caab8f298a3d34d53973f2d8906d1f7'></script></div>");
//This does:
Frame embed = new Frame("https://www.tiempo.com/getwid/5caab8f298a3d34d53973f2d8906d1f7");
embed.setStyleName(""); // remove GWT styling. You could add your own CSS class here.
embed.getElement().setAttribute("style", "width:176px; color:#868686; height:200px;");
embed.getElement().setAttribute("frameborder", "0");
embed.getElement().setAttribute("scrolling", "no");
root.add(embed);
}
}
You can use an IFrame element to load external content.
final Frame frame = new Frame("url");
frame.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
// do stuff here
}
});
RootPanel.get("mydiv").add(frame);
Note though, that you won't be able to interact with the external content due to Cross site scripting.
I am using the ckEditor along with GWT and SmartGWT. I have a problem that whenever the ckEditor displays a dialog (e.g. link button, table button), although the items in the dialog gain focus (input texts work fine, I can write inside them), the dropdowns (select elements) when clicking on them, do not expand to show their option items (they expand only when they have focus and user hits "spacebar"). This happens only in firefox and chrome (latest versions) while on IE11 it works as expected.
Note that I am already aware of the "focus" problem existing if a ckEditor instance exists in a GWT/jquery modal and I have already included a fix:
$wnd.CKEDITOR.on('dialogDefinition', function (evt) {
var dialog = evt.data.definition.dialog;
dialog.on('show', function () {
var element = this.getElement();
var labelledby = element.getAttribute('aria-labelledby');
var nativeElement = $wnd.document.querySelector("[aria-labelledby='" + labelledby + "']");
nativeElement.onclick = function (evt) {
if ((evt.target.tagName == "INPUT" || evt.target.tagName == "SELECT" || evt.target.tagName == "TEXTAREA") &&
-1 != evt.target.className.indexOf("cke_dialog_ui_input")) {
evt.target.focus();
};
}
});
});
Any hint how I can make the dropdowns to behave correctly? To me it looks like the dropdown element does not receive the click event (although on click it gets focus) or somehow the event's propagation stops unexpectedly.
EDIT
Forgot to mention that the problem appears if the ckEditor instance is inside a modal SmartGWT window. More specifically if I set
Window win = new Window(); //com.smartgwt.client.widgets.Window
win.setIsModal(false);
and then add the DynamicForm form which contains the ckEditor item on that window then the dialog dropdowns work fine, however if I set
win.setIsModal(true);
I get the faulty behavior described above
In case anyone else has the same problem with me, the solution is to call win.hideClickMask() upon show event of the dialog. This can be achieved in many ways depending on how ckEditor is integrated with SmartGWT. In my implementation this is achieved by overriding onDialogShow() as below:
final CKEditor ckEditor = new CKEditor(conf) {
#Override
public void onDialogShow() {
// to overcome the problem that smartgwt modality obstruct the dropdowns of a ckeditor dialog to be pressed
final NodeList<Element> allWindowsWithModalMask = findAllWindowsWithModalMask();
if(allWindowsWithModalMask != null ) {
for(int i =0; i<allWindowsWithModalMask.getLength(); i++) {
Element el = allWindowsWithModalMask.getItem(i);
String id = el.getAttribute("eventproxy");
if(Canvas.getById(id) != null) {
hideClickMask(Canvas.getById(id).getOrCreateJsObj());
}
}
}
}
};
and
protected native NodeList<Element> findAllWindowsWithModalMask() /*-{
return $wnd.document.querySelectorAll("[class='windowBackground']");
}-*/;
protected native void hideClickMask(JavaScriptObject windowCanvas) /*-{
windowCanvas.hideClickMask();
}-*/;
I am using the jQuery inline editing plugin Jeditable. Thankfully, Jeditable provides a plugin capability for extending the out of the box inline editing it provides.
I am hoping to not reinvent the wheel-- as such does a PageDown plugin already exist for Jeditable? If one does my Google-fu is not turning up any results.
I never found a ready to go Jeditable PageDown plugin so I wrote my own. The below example is too specific to be used without modification, but should provide a decent enough outline for anyone endeavoring to accomplish a similar task.
Code to add a "markdown" input type to Jeditable:
var converter = Markdown.getSanitizingConverter();
$.editable.addInputType('markdown', {
element: function(settings, original) {
var editorId = original.id.substring(original.id.lastIndexOf("-"));
var input = $('<textarea />');
input.attr('id', 'wmd-input' + editorId);
var panel = $('<div class="wmd-panel" />');
panel.append('<div id="wmd-button-bar' + editorId + '" />');
panel.append(input);
panel.append('<div id="wmd-preview' + editorId + '" />');
$(this).append(panel);
return (input);
},
plugin: function(settings, original) {
var editorId = original.id.substring(original.id.lastIndexOf("-"));
var editor = new Markdown.Editor(converter, editorId);
editor.run();
}
});
The above code goes through a bunch of gyrations concerning the elements id, because in my case I can have several editors on a single page. See the PageDown documentation about Markdown.Editor for more details.
Once I've added the "markdown" input type to Jeditable it's just a matter of utilizing it with this code:
$('.editable-element-area').editable('http://jsfiddle.net/echo/jsonp/', {
onblur: 'submit',
type: 'markdown',
indicator: 'Saving...',
loadurl: 'http://jsfiddle.net/echo/jsonp/', // retrieve existing markdown
callback: function(value, settings) {
$(this).html(converter.makeHtml(value)); // render updated markdown
}
});
I want my users to see the markdown as HTML when they aren't editing it so I have to make use of the callback and loadurl Jeditable parameters. The load url retrieves the text to edit in markdown format, while the callback converts the new text back to html.
I want my page to load javascript dynamically to my body:
<script type= "text/javascript" src="this path should be decided from wicket dynamically"/>
I am using wicket version 1.4 therefore JavaScriptResourceReference does not exist in my version (for my inspection it wasn't ' )
how can I solve this ?
thanks in advance :).
I specify my comment into an answer.
You can use this code snippet:
WebMarkupContainer scriptContainer = new WebMarkupContainer("scriptContainer ");
scriptContainer .add(new AttributeAppender("type", Model.of("text/javascript")));
scriptContainer .add(
new AttributeAppender("src", urlFor(
new JavaScriptResourceReference(
YourClass.class, "JavaScriptFile.js"), null).toString()));
add(scriptContainer );
and the corresponding html:
<script wicket:id="scriptContainer "></script>
Just change the string JavaScriptFile.js to load any other Javascript file.
JavascriptPackageResource.getHeaderContributor() does exactly what you need.
You need nothing in your markup, just add the HeaderContributor it returns to your page.
Update: For Wicket 1.5 see the migration guide, but it goes like this:
public class MyPage extends WebPage {
public MyPage() {
}
public void renderHead(IHeaderResponse response) {
response.renderJavaScriptReference(new PackageResourceReference(YuiLib.class,
"yahoo-dom-event/yahoo-dom-event.js"));
response.renderCSSReference(new PackageResourceReference(AbstractCalendar.class,
"assets/skins/sam/calendar.css"));
}
}
If you want to put your <script> element in the body, you can simply declare it as a WebMarkupContainer and add an AttributeModifier to set the src attribute. Although in that case wicket won't generate the relative URLs for you, you have to do it yourself.
I'm not sure I understood completely.
If you are trying to create and append a script to the body after the page is loaded you should do it this way:
<script type="text/javascript">
function load_js() {
var element = document.createElement("script");
element.src = "scripts/YOUR_SCRIPT_SRC.js"; // <---- HERE <-----
document.body.appendChild(element);
}
// Wait for the page to be loaded
if(window.addEventListener)
window.addEventListener("load",load_js,false);
else if(window.attachEvent)
window.attachEvent("onload",load_js);
else
window.onload = load_js;
</script>
What I did here is create a new script element, and then apply to it its source.
That way you can control dynamicaly the src. After that I append it to the body.
The last part is there so the new element is applied only after the page is loaded.