Does a PageDown plugin exist for Jeditable? - plugins

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.

Related

Inserting text following selection in Office-JS

I am trying to append a hyperlink immediately following a piece of selected text in Word 2013 using the Shared JS API.
Inserting the hyperlink using OOXML works fine when inserting at current cursor with no selection. My problem is 'finding' the end of the selected text to append the OOXML.
Just using setSelectedDataAsync overwrites the existing text. I have tried reading the selected text as OOXML and concatenating the hyperlink XML to it but without success.
I have not tried reading the current selection and then modifying that OOXML but would prefer to avoid.
In the Word JS API a before and after are provided on the selection so it is straightforward to do. Is it possible to do this in the Shared API? Thanks.
The following code sample illustrates the approach that Marc described in his comment above (with one exception: it gets the selected data as Text, not as HTML).
This snippet uses getSelectedDataAsync to get the selected data (as Text), and then appends a hyperlink to that data and uses setSelectedDataAsync to push that string back into the document (as HTML).
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
{ valueFormat: "unformatted" },
function (asyncResult) {
var error = asyncResult.error;
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(error.name + ": " + error.message);
}
else {
// Get selected data.
var dataValue = asyncResult.value;
console.log("Selected data is: " + dataValue);
// Create newText by appending hyperlink to dataValue.
var myHyperlink = "<a href='https://www.bing.com'>https://www.bing.com</a>";
var newText = dataValue + " " + myHyperlink;
console.log("New text is: " + newText);
// Replace selected text with newText value.
Office.context.document.setSelectedDataAsync(newText, { coercionType: "html" },
function (asyncResult) {
var error = asyncResult.error;
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(error.name + ": " + error.message);
}
});
}
});
Note: One side-effect of getting the selected data as Text, as this snippet does, is that when you write back that string (with the hyperlink appended) to the document, you'll lose any formatting (for example: font color, style, etc.) that was previously present in the selected text. If it's important that you preserve formatting of the originally selected text, you'll need to get the selected data as HTML and then append your hyperlink to the the portion of HTML which contains the originally selected text, before writing that HTML back to the document.
You can quickly and easily try this code snippet yourself in Word by using Script Lab (https://aka.ms/getscriptlab). Simply install the Script Lab add-in (free), then choose "Import" in the navigation menu, and use the following GIST URL: https://gist.github.com/kbrandl/8e235fb0ccc190bf42ed9ce1874f5559.

Mapbox GL Popup .setDOMContent example

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/

TinyMCE 3 - textarea id which fired blur event

When a TinyMCE editor blur occurs, I am trying to find the element id (or name) of the textarea which fired the blur event. I also want the element id (or name) of the element which gains the focus, but that part should be similar.
I'm getting closer in being able to get the iframe id of the tinymce editor, but I've only got it working in Chrome and I'm sure there is a better way of doing it. I need this to work across different browsers and devices.
For example, this below code returns the iframe id in Chrome which is okay since the iframe id only appends a suffix of "_ifr" to my textarea element id. I would prefer the element id of the textarea, but it's okay if I need to remove the iframe suffix.
EDIT: I think it's more clear if I add a complete TinyMCE Fiddle (instead of the code below):
http://fiddle.tinymce.com/HIeaab/1
setup : function(ed) {
ed.onInit.add(function(ed) {
ed.pasteAsPlainText = true;
/* BEGIN: Added this to handle JS blur event */
/* example modified from: http://tehhosh.blogspot.com/2012/06/setting-focus-and-blur-event-for.html */
var dom = ed.dom,
doc = ed.getDoc(),
el = doc.content_editable ? ed.getBody() : (tinymce.isGecko ? doc : ed.getWin());
tinymce.dom.Event.add(el, 'blur', function(e) {
//console.log('blur');
var event = e || window.event;
var target = event.target || event.srcElement;
console.log(event);
console.log(target);
console.log(target.frameElement.id);
console.log('the above outputs the following iframe id which triggered the blur (but only in Chrome): ' + 'idPrimeraVista_ifr');
})
tinymce.dom.Event.add(el, 'focus', function(e) {
//console.log('focus');
})
/* END: Added this to handle JS blur event */
});
}
Maybe it's better to give a background of what I'm trying to accomplish:
We have multiple textareas on a form which we're trying to "grammarcheck" with software called "languagetool" (that uses TinyMCE version 3.5.6). Upon losing focus on a textarea, we would like to invoke the grammarcheck for the textarea that lost focus and then return the focus to where it's supposed to go after the grammar check.
I've struggled with this for quite some time, and would greatly appreciate any feedback (even if it's general advice for doing this differently).
Many Thanks!
Simplify
TinyMCE provides a property on the Editor object for getting the editor instance ID: Editor.id
It also seems overkill to check for doc.content_editable and tinyMCE.isGecko because Editor.getBody() allows for cross-browser compatible event binding already (I checked IE8-11, and latest versions of Firefox and Chrome).
Note: I actually found that the logic was failing to properly assign ed.getBody() to el in Internet Explorer, so it wasn't achieving the cross-browser functionality you need anyway.
Try the following simplified event bindings:
tinyMCE.init({
mode : "textareas",
setup : function (ed) {
ed.onInit.add(function (ed) {
/* onBlur */
tinymce.dom.Event.add(ed.getBody(), 'blur', function (e) {
console.log('Editor with ID "' + ed.id + '" has blur.');
});
/* onFocus */
tinymce.dom.Event.add(ed.getBody(), 'focus', function (e) {
console.log('Editor with ID "' + ed.id + '" has focus.');
});
});
}
});
…or see this working TinyMCE Fiddle »
Aside: Your Fiddle wasn't properly initializing the editors because the plugin was failing to load. Since you don't need the plugin for this example, I removed it from the Fiddle to get it working.

Prevent TinyMCE from removing span elements

Here is the problem demonstration
You can try it here: http://fiddle.tinymce.com/SLcaab
This is TinyMCE default configuration
less all the plugins
with extended_valid_elements: "span"
1 - Open the Html Source Editor
2 - Paste this html into the Html Source Editor:
<p><span>Hello</span></p>
<p>Google 1</p>
<p>Google 2</p>
3 - Click update in the Html Source Editor to paste the html in the editor
4 - Remember there is a span around 'Hello'.
5 - Place your cursor just before Google 2 and press backspace (the two links should merge inside the same paragraph element).
6 - Look at the resulting html using the Html Source Editor.
Result (problem): No more span in the html document even though we added 'span' to the extended_valid_elements in the TinyMCE settings.
Note: I removed all the plugins to make sure the problem is at the core of TinyMCE.
Edit 1 - I also tried: valid_children : "+p[span]" - still does not work
Edit 2: Only reproduced on WebKit (OK on Firefox and IE)
Insert extended_valid_elements : 'span' into tinymce.init:
tinymce.init({
selector: 'textarea.tinymce',
extended_valid_elements: 'span',
//other options
});
I have the same problem and I find solutions. Tiny MCE deleted SPAN tag without any attribute. Try us span with class or another attribute for example:
<h3><span class="emptyClass">text</span></h3>
In TinyMCE 4+ this method good work.
Tinymce remove span tag without any attribute. We can use span with any attribute so that it is not removed.
e.g <span class="my-class">Mahen</span>
Try this for 3.5.8:
Replace cleanupStylesWhenDeleting in tiny_mce_src.js (line 1121) with this::
function cleanupStylesWhenDeleting() {
function removeMergedFormatSpans(isDelete) {
var rng, blockElm, wrapperElm, bookmark, container, offset, elm;
function isAtStartOrEndOfElm() {
if (container.nodeType == 3) {
if (isDelete && offset == container.length) {
return true;
}
if (!isDelete && offset === 0) {
return true;
}
}
}
rng = selection.getRng();
var tmpRng = [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
if (!rng.collapsed) {
isDelete = true;
}
container = rng[(isDelete ? 'start' : 'end') + 'Container'];
offset = rng[(isDelete ? 'start' : 'end') + 'Offset'];
if (container.nodeType == 3) {
blockElm = dom.getParent(rng.startContainer, dom.isBlock);
// On delete clone the root span of the next block element
if (isDelete) {
blockElm = dom.getNext(blockElm, dom.isBlock);
}
if (blockElm && (isAtStartOrEndOfElm() || !rng.collapsed)) {
// Wrap children of block in a EM and let WebKit stick is
// runtime styles junk into that EM
wrapperElm = dom.create('em', {'id': '__mceDel'});
each(tinymce.grep(blockElm.childNodes), function(node) {
wrapperElm.appendChild(node);
});
blockElm.appendChild(wrapperElm);
}
}
// Do the backspace/delete action
rng = dom.createRng();
rng.setStart(tmpRng[0], tmpRng[1]);
rng.setEnd(tmpRng[2], tmpRng[3]);
selection.setRng(rng);
editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
// Remove temp wrapper element
if (wrapperElm) {
bookmark = selection.getBookmark();
while (elm = dom.get('__mceDel')) {
dom.remove(elm, true);
}
selection.moveToBookmark(bookmark);
}
}
editor.onKeyDown.add(function(editor, e) {
var isDelete;
isDelete = e.keyCode == DELETE;
if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
e.preventDefault();
removeMergedFormatSpans(isDelete);
}
});
editor.addCommand('Delete', function() {removeMergedFormatSpans();});
};
put an external link to tiny_mce_src.js in your html below the tiny_mce.js
It's possible to use the work around by writing it as a JavaScript script which prevents WYSIWIG from stripping empty tags. Here my issue was with including Font Awesome icons which use empty <i> or <span> tags.
<script>document.write('<i class="fa fa-facebook"></i>');</script>
In the Tinymce plugin parameters enable:
Use Joomla Text Filter.
Be sure your user group have set "No filtered" Option in global config > text filters.
Came across this question and was not happy with all the provided answers.
We do need to update wordpress at some point so changing core files is not an option. Adding attributes to elements just to fix a tinyMCE behaviour also doesn't seem to be the right thing.
With the following hook in the functions.php file tinyMCE will no longer remove empty <span></span> tags.
function tinyMCEoptions($options) {
// $options is the existing array of options for TinyMCE
// We simply add a new array element where the name is the name
// of the TinyMCE configuration setting. The value of the array
// object is the value to be used in the TinyMCE config.
$options['extended_valid_elements'] = 'span';
return $options;
}
add_filter('tiny_mce_before_init', 'tinyMCEoptions');
I was having same issue. empty SPAN tags are being removed. The solution i found is
verify_html: false,
Are you running the newest version of TinyMCE? I had the opposite problem - new versions of TinyMCE would add in unwanted span elements. Downgrading to v3.2.7 fixed the issue for me, that might also work for you if you are willing to use an old version.
Similar bugs have been reported, see the following link for bugs filtered on "span" element:
http://www.tinymce.com/develop/bugtracker_bugs.php#!order=desc&column=number&filter=span&status=open,verified&type=bug

CodeMirror-UI in smartGWT tab

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.