How to modify drag and drop behavior from a browser? - javascript

Conventionally, if I click on a link on a browser and drag, the data that is 'fetched' is the URL and its name, and that can be used by the target application (MS Word or a Java Swing app).
I want to modify the default behavior of a browser on drag to include some more data.
One good application is dragging from a google search results page. For example, as shown in the diagram below, when I drag from anywhere in the first result area (marked in yellow), I want to capture not just the url of the page, but also all additional information (like the links for "Actions", "In Mac OS" links at the bottom of the first result).
I am not sure what I need to get this behavior. Javascript might be one solution I guess (maybe an extension that makes a javascript code run on all the pages that load?), but am not sure at all. Any pointers / tips / suggestions would be useful.

To enable drag and drop, simply add draggable="true" as an attribute on an element.
Example:
<div draggable="true">Little brother</div>
All drag events have a property called dataTransfer which is used to hold the drag data. dataTransfer contains two pieces of information, the data format(MIME) and the stored data. The information is set using event.dataTransfer.setData().
event.dataTransfer.setData("text/plain", "Text to drag");
Here's an example that changes the drag and drop behavior.
Setup:
Go to Google.com using Google Chrome.
Search for anything, like "dog".
Press F12 to open up the Dev console.
Copy and Paste the content of jQuery in the console.
Copy and Paste the content of Drag-N-Drop Script in the console.
Usage:
Drag and drop a search result section from the web browser to a text editor, like wordpad.
Result:
A collection of links should show up in your text editor. The links are markdown styled.
Drag-N-Drop Script
(function () {
// #author Larry Battle (http://bateru.com/news) 12.07.2012
var URLS = {
JQUERY : "http://code.jquery.com/jquery-1.8.3.min.js"
};
var SELECTORS = {
GOOGLE_LINK_SECTIONS : ".g"
};
var getNameAndURLFromLinks = function (el) {
var info = ["Links:\n"];
$(el).find("a").each(function () {
var url = $(this).attr("href");
if (/https?:\/\//.test(url)) {
info.push( "- [" + $(this).text() + "](" + url + ")");
}
});
return info.join("\n");
};
var storeDataInEvent = function (evt) {
var info = getNameAndURLFromLinks($(this));
event.dataTransfer.setData('text/plain', info);
};
var main = function () {
$(SELECTORS.GOOGLE_LINK_SECTIONS)
.attr("draggable", true)
.css("border", "3px orange solid")
.bind("dragstart", storeDataInEvent);
};
if(!window.jQuery){
window.alert("Paste the source of jQuery in the console and then run this script again. URL:" + URLS.JQUERY);
}else if(!/search/.test(document.location.href)){
window.alert("Google for something, then run this script in the console again.");
}
main();
}());
You should be able to create a Google Chrome extension that has this functionality for a set number of websites. Each site should have a different main() function. However, you might be able to create a general algorithm if you test against the top 100 sites.
Info on Drag and Drop: https://developer.mozilla.org/en-US/docs/DragDrop/Drag_Operations
dataTransfer Object: http://help.dottoro.com/ljvspfdo.php
List of MIME: http://en.wikipedia.org/wiki/Internet_media_type

Related

Wordpress Detect Click on Gallery Shortcode Preview in TinyMCE

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();
});
}'
)

How to use links in Medium Editor?

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. . .

SharePoint 2013 List - Tooltip over Items

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!

Initialize media player only if query string parameter is present

I have a SharePoint page that has a hyperlink which points to a video clip. Clicking on the link will play the video in an overlay window (uses Silverlight). If Silverlight runtime is not present, it displays the "install Silverlight" prompt. When the page is invoked with a IsDlg=1 query string, the hyperlink is hidden (it is in the left navigation bar), and only the main content page is shown. But I still get the "install Silverlight" prompt. I want to get rid of the prompt when IsDlg=1 is present.
Below is the relevant javascript code on the page. I've modified it slightly to initialize the media player only if IsDlg=1 is not present. But it is not working as expected. Any ideas?
// original code
$(function () {
mediaPlayer.createOverlayPlayer();
mediaPlayer.attachToMediaLinks(document.getElementById('videoList'), ['wmv', 'avi', 'mp4']);
});
// modified code
$(function () {
var field = 'IsDlg';
var url = window.location.href;
if (url.indexOf('?' + field + '=') != -1) {
} else {
mediaPlayer.createOverlayPlayer();
mediaPlayer.attachToMediaLinks(document.getElementById('videoList'), ['wmv', 'avi', 'mp4']);
}
});
As long as the HTML which embeds the Silverlight control is present, it will show the "Install Silverlight" dialog. If you don't want the dialog to show, you'll have to change the HTML source. You could add JavaScript code to add the HTML dynamically, so that it only shows when necessary. That answer would depend on how you're currently embedding the Silverlight control.
EDIT: You could try code like this:
$(function () {
if (window.location.search.indexOf('IsDlg=1') === -1) {
$.getScript('/_layouts/mediaplayer.js', function () {
mediaPlayer.createOverlayPlayer();
mediaPlayer.attachToMediaLinks(document.getElementById('videoList'), ['wmv', 'avi', 'mp4']);
});
}
});
Your code should work, so you probably want to debug for other possible issues.
$(document).ready(function () { // add explicit wait until dom ready
console.log(window.location.search); // just to check that the parameter is present
if(window.location.search.indexOf("IsDlg=1") < 0){ // testing the query string part only
mediaPlayer.createOverlayPlayer();
mediaPlayer.attachToMediaLinks(document.getElementById('videoList'), ['wmv', 'avi', 'mp4']);
}
});
Try that and see how you get on.

Manually trigger 'open file dialog' using plupload

I'm using plupload to client scaling of pictures before they are uploaded. I like the feature that it gracefully falls back to html4 if the user doesn't have flash, silverlight etc engines installed.
I want to be able to start the upload when the user clicks certain elements on the page and i want to handle the events (sometimes stopping a file dialog from opening). In fact i'd like to pop open the file dialog using javascript.
Ok, so HTML4 (or rather the browser, except chrome :P) won't let me do this, unless the user clicks a browse-button (or an overlay covering a browse-button), so when i get the fallback to HTML4 i'll accept that i can't do it, but most users will have flash or silverlight installed and they do not have this restriction. So my question is this:
How do i trigger the file open dialog in plupload (keeping in mind i only need the flash and silverlight engines to do this).
The former solutions not worked on iPhones with plupload 2.1.2.
The following code did the trick (jquery needed):
$("#id_of_the_second_button").click(function() {
$('div.moxie-shim input[type=file]').trigger('click');
});
Fallback runtimes will become irrelevant as times goes by. This means that sooner or later, we'll be all using HTML5 runtime. In case that you are using HTML5 runtime, but don't use pluploadQueue(), this will work as well:
// Set up and initialise uploader
var uploader = new plupload.Uploader({
'runtimes' : 'html5',
'browse_button' : 'id_of_the_first_button'
// Other options
});
uploader.init();
// Hook in the second button
plupload.addEvent(document.getElementById('id_of_the_second_button'), 'click', function(e) {
var input = document.getElementById(uploader.id + '_html5');
if (input && !input.disabled) {
input.click();
} // if
e.preventDefault();
});
If someone is searching for the HTML5 solution, here it is:
var up= $('#uploader').pluploadQueue();
if (up.features.triggerDialog) {
plupload.addEvent(document.getElementById('idOtherButton'), 'click', function(e) {
var input = document.getElementById(up.id + '_html5');
if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
input.click();
}
e.preventDefault();
});
}
Ok. It doesn't seem possible to do this, so unless someone implements event handles for the silverlight and flash components i'm out of luck
I read your problem.
I found some articles that may help to figure this out. check them. It may help...!
01. https://stackoverflow.com/questions/210643/in-javascript-can-i-make-a-click-event-fire-programmatically-for-a-file-input-e
02. https://stackoverflow.com/questions/2048026/open-file-dialog-box-in-javascript
#Per Hornshøj-Schierbeck
After uploader has been init. It take few time to render input file to select. So you need to wait like below:
this.uploader.init();
var task = new Ext.util.DelayedTask(function () {
var inputArray = $('div.moxie-shim input[type=file]');
var input = inputArray.length > 1 ? inputArray[inputArray.length - 1] :
inputArray[0];
$(input).trigger('click');
});
task.delay(100);
The code in javascript is similar. Worked for me with plupload 2.3.6
Hop this help!

Categories