Working on customizing the wordpress gallery with some different settings for different gallery types.
Short of the long is I'm using multiple wp_editors on page and I'm having a focus problem when jumping between editors.
I'm making use of wp.media.view.Settings.Gallery.extend to switch between gallery types and display different js templates.
The functionality is actually all good and gallery shortcodes are going where they need to and being updated as needed.
For certain gallery types I am extending the attachment details with
an extend that looks something like this slimed down version:
var $gal_media = wp.media;
$gal_media.view.Attachment.Details = $gal_media.view.Attachment.Details.extend({
initialize: function(){
this.model.on('change', this.render, this);
},
render: function(){
var check_active_editor = window.wpActiveEditor;
return this;
}
});
The problem lies here when I'm attempting to detect the current editor during the render part of the function with window.wpActiveEditor;
It's working correctly providing you get focus on the current editor but if you just click the gallery preview or edit gallery pencil window.wpActiveEditor; will return the last focused editor.
Tried several different attempts to change focus on the editor in the wp_editor call using on click events during init like so:
'tinymce' => array(
'init_instance_callback' => 'function(gallery_editor) {
gallery_editor.on("click", function(){
tinyMCE.get(gallery_editor.id).focus();
});
}'
)
but they are not called when clicking on the gallery preview or edit.
Any suggestion on either:
1) Getting the proper id?
Obviously the Gallery knows it as it's returning the shortcode to the proper editor.
or
2) Toggling Focus/Blur on Multiple Editors when Gallery Preview or Edit button is pressed.
Much appreciated!
If anyone finds themselves in a similar situation I was able to resolve this issue with an on click callback on my editors that cycles through all the editors and removes the data-mce-selected attribute from any other gallery nodes that were selected.
Then it sets focus on the editor that was just clicked.
Not the prettiest but it's behaving as expected.
The key for me was using tinyMCE.dom.DomQuery
'tinymce' => array(
'init_instance_callback' => 'function(ed) {
ed.on("click", function(){
for (edId in tinyMCE.editors){
if(edId !== ed.id){
var this_editor = tinyMCE.get(edId);
var $ = tinyMCE.dom.DomQuery;
$("div[data-wpview-type]", this_editor.dom.doc).removeAttr("data-mce-selected");
}
}
tinyMCE.get(ed.id).focus();
});
}'
)
Related
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);
I've been trying out the excellent Medium Editor. The problem that I've been having is that I can't seem to get links to "work".
At the simplest, here's some HTML/JS to use to demonstrate the problem:
HTML:
<html>
<head>
<script src="//cdn.jsdelivr.net/medium-editor/latest/js/medium-editor.min.js"></script>
<link rel="stylesheet" href="//cdn.jsdelivr.net/medium-editor/latest/css/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/medium-editor/latest/css/themes/beagle.min.css" type="text/css">
</head>
<body>
<div class='editable'>
Hello world. link
</div>
</body>
</html>
Javascript:
var editor = new MediumEditor('.editable');
This fiddle demonstrates the problem (using the code above).
If you hover on the link, a popup appears.
If you click the link, nothing happens.
If you click the popup, a form appears where you can edit the link.
It seems to me that clicking the link should take me wherever the link's href is targeting. The only way to use the link is to right click and either open in a new tab or new window -- which I don't want to ask my users to do.
I feel like I must be missing something simple in the configuration (either the Anchor Preview Options or the Anchor Form Options). Unfortunately, I'm not seeing it.
In my actual application, I'm not using jQuery, but I am using angularjs. If a strictly Medium Editor answer doesn't exist, I can fall back to using basic JS or anything that angularjs provides.
I've found how to bind event.
Here is full event list https://github.com/yabwe/medium-editor/blob/master/CUSTOM-EVENTS.md
Try to change your code to
var editor = new MediumEditor('.editable')
.subscribe("editableClick", function(e){if (e.target.href) {window.open(e.target.href)}})
https://jsfiddle.net/fhr18gm1/
So medium-editor is built on top of the built-in browser support for contenteditable elements. When you instantiate medium-editor, it will add the contenteditable=true attribute to whatever element(s) you provided it.
By default, since the text is now editable (the contenteditable attribute makes the browser treat it as WYSIWYG text) the browser no longer supports clicking on the links to navigate. So, medium-editor is not blocking these link clicks from happening, the browsers do it inherently as part of making the text editable.
medium-editor has built in extensions for interacting with links:
anchor extension
allows for adding/removing links
anchor-preview extension
shows a tooltip when hovering a link
when the tooltip is clicked, allows for editing the href of the link via the anchor extension
I think the underlying goal of the editor is the misunderstanding here. The editor allows for editing text, and in order to add/remove/update links, you need to be able to click into it without automatically navigating away. This is what I think of as 'edit' mode.
However, the html produced as a result of editing is valid html, and if you take that html and put it inside an element that does NOT have the contenteditable=true attribute, everything will work as expected. I think of this as 'publish mode'
I look at editors like word or google docs, and you see a similar kind of behavior where when you edit the document, the links don't just navigate away when you click on them, you have to actually choose to navigate them through a separate action after you click the link. However, on a 'published' version of the document, clicking the link will actually open a browser window and navigate there.
I think this does make for a good suggestion as an enhancement to the existing anchor-preview extension. Perhaps the tooltip that appears when hovering a link could have multiple options in it (ie Edit Link | Remove Link | Navigate to URL).
tldr;
Links are not navigable on click when 'editing' text in a browser via the built-in WYSIWYG support (contenteditable). When not in 'edit' mode, the links will work as expected.
This could make for a nice enhancement to the medium-editor anchor-preview extension.
Working off some ideas from #Valijon in the comments, I was able to get it to work using the following code:
var iElement = angular.element(mediumEditorElement);
iElement.on('click', function(event) {
if (
event.target && event.target.tagName == 'A' &&
event.target.href && !event.defaultPrevented) {
$window.open(event.target.href, '_blank');
}
});
I think the key is that apparently the editor lets the event propogate to the ancestor elements, so I was able to just listen for the click on the top level editor element.
Here, $window is angular's $window service -- If you're not using angularjs, window would do the trick and I used angular.element to ease the event listener registry, but you could do it the old-fashioned way (or using the JS framework of your choice).
What I really wanted when I asked the question was behavior similar to Google Docs when in "edit" mode (as described by Nate Mielnik). I opened an issue on the Medium Editor tracker and they decided not to implement it as part of the core medium editor, but they noted that they would be happy to have someone add that functionality as an extension.
So, I decided to implement that functionality as an extension as suggested. It can be found as part of MediumTools1. The project is still in very early stages (e.g. I haven't done anything to make the styling look better, or to use better minifying practices, etc. but we'll happily accept Pull Requests for that).
The guts of the code look like this:
var ClassName = {
INNER: 'medium-editor-toolbar-anchor-preview-inner',
INNER_CHANGE: 'medium-editor-toolbar-anchor-preview-inner-change',
INNER_REMOVE: 'medium-editor-toolbar-anchor-preview-inner-remove'
}
var AnchorPreview = MediumEditor.extensions.anchorPreview;
GdocMediumAnchorPreview = MediumEditor.Extension.extend.call(
AnchorPreview, {
/** #override */
getTemplate: function () {
return '<div class="medium-editor-toolbar-anchor-preview">' +
' <a class="' + ClassName.INNER + '"></a>' +
' -' +
' <a class="' + ClassName.INNER_CHANGE + '">Change</a>' +
' |' +
' <a class="' + ClassName.INNER_REMOVE + '">Remove</a>' +
'</div>';
},
/** #override */
createPreview: function () {
var el = this.document.createElement('div');
el.id = 'medium-editor-anchor-preview-' + this.getEditorId();
el.className = 'medium-editor-anchor-preview';
el.innerHTML = this.getTemplate();
var targetBlank =
this.getEditorOption('targetBlank') ||
this.getEditorOption('gdocAnchorTargetBlank');
if (targetBlank) {
el.querySelector('.' + ClassName.INNER).target = '_blank';
}
var changeEl = el.querySelector('.' + ClassName.INNER_CHANGE);
this.on(changeEl, 'click', this.handleClick.bind(this));
var unlinkEl = el.querySelector('.' + ClassName.INNER_REMOVE);
this.on(unlinkEl, 'click', this.handleUnlink.bind(this));
return el;
},
/** Unlink the currently active anchor. */
handleUnlink: function() {
var activeAnchor = this.activeAnchor;
if (activeAnchor) {
this.activeAnchor.outerHTML = this.activeAnchor.innerHTML;
this.hidePreview();
}
}
});
As an explanation, I just use medium's flavor of prototypical inheritance to "subclass" the original/builtin AnchorPreview extension. I override the getTemplate method to add the additional links into the markup. Then I borrowed a lot from the base implementation of getPreview, but I bound new actions to each of the links as appropriate. Finally, I needed to have an action for "unlinking" the link when "Remove" is clicked, so I added a method for that. The unlink method could probably be done a little better using contenteditable magic (to make sure that it is part of the browser's undo stack), but I didn't spend the time to figure that out (though it would make a good Pull Request for anyone interested :-).
1Currently, it's the only part, but I hope that'll change at some point. . .
We have large SharePoint lists with lots of columns. Our users are forgetting which cells they are viewing because after scrolling the headers disappear (no way to freeze headers like in Excel).
We want to try adding tooltips to the cell items so when they hover over it will display a tooltip with the column name.
Has anyone ever tried doing this before?
I have the following code which works initially on the load but stops working after the user sorts, filters or switches the list into Edit mode:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
jQuery(
function()
{
$('td').hover
(
function()
{
var idx = jQuery(this).parent().children().index(jQuery(this));
jQuery(this).attr('title',jQuery(this).parent().parent().parent().find('th').eq(idx).text());
jQuery('div.ms-core-brandingText').html(jQuery(this).parent().parent().parent().find('th').eq(idx).text());
}
)
}
);
</script>
Your code stops working because SharePoint reloads the list content. This is a common issue when adding client side scripts to SharePoint pages.
First, you should actually be able to render a view with frozen headers. Right, it doesn't come out of the box, but there are third party datatable tools available.
Another option is to include your code via the Client Side Rendering option. This is a broad topic, so probably the first step would be to google it.
Okay, getting closer, using CSR instead of just jQuery. This works but needs each field specified manually. Looking for a way to apply this to every field in the view.
<script type="text/javascript">
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
Templates: {
Fields: {
'Comments': {
'View': function (ctx) {
return String.format('<span title="{0}">{1}</span>', this.FieldTitle, ctx.CurrentItem.Comments);
}
},
'Name': {
'View': function (ctx) {
return String.format('<span title="{0}">{1}</span>', this.FieldTitle, ctx.CurrentItem.Name);
}
}
}
}
});
It occurs since when filtering/sorting is getting applied the List View is reloaded.
How to hover List Item in SharePoint 2013
The following function could be used for hovering List Item cells in SharePoint 2013:
function hoverListItems()
{
$('tr.ms-itmhover td').hover(
function() {
var $td = $(this);
var $th = $td.closest('table').find('th').eq($td.index());
$td.attr('title',$th.text());
}
);
}
Since in SharePoint 2013 Client-Side-Rendering (CSR) is the default rendering mode, the example below demonstrates how to register hoverListItem function using OnPostRender event
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function() {
hoverListItems();
}
});
Note: using the specified technique List Item hover will also work after
sorting/filtering is applied.
References
Introduction to Client-Side Rendering in SharePoint 2013
Tool-Tip Work-around:
The solution I have been using is a simple, non-html solution. I simply create a link to an item; insert it's own address (so that it doesn't go anywhere); then under the new LINK tab type the tip you want in the Description box.
save the page then try mousing over your new link, voilĂ
Hope that helps some!
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);
}
});
I am trying to find in the Galleria JavaScript file a place where I tell it to run a JavaScript function every time the current picture is changed (prev, next, or clicking on a thumbnail)
Does anyone with experience with galleria have any ideas?
http://galleria.io/
When you set up your Gallery bind to the image function and you will receive the event every time the image changes. I use it to load text into another area of my page like so.
Galleria.ready(function() {
this.bind("image", function(e) {
$("#text_div").text(arrayOfText[e.index]);
});
});
To make sure you have things setup correctly use it like this,
Galleria.loadTheme('galleria/themes/kscreates/galleria.classic.js');
Galleria.configure();
Galleria.ready(function() {
this.bind("image", function(e) {
console.log(e.index);
});
});
Galleria.run('#galleria');
and have a look in your Safari console and you will see the index of the currently displayed image.
Hope this helps.