Related
I've read that you can make a Google Apps Script that shows a Facebook Feed, and then embed this in a Google Site, but I can't find any more information on how to do it and I can't figure it out myself.
When I try to make an Apps Script web app with a Facebook feed I get errors like:
Uncaught DOMException: Failed to set the 'domain' property on 'Document': Assignment is forbidden for sandboxed iframes.
This is from copying the "Facebook Javascript SDK" and "Page Feed" from Facebook Developers into an HTML file and deploying it as a web app. I gather it has something to do with how Apps Script sandboxes your code but I don't know what I have to do here.
For that matter, even if I try to make a simpler Apps Script with some static HTML, when I try to embed it from Drive into the site I get an error "Some of the selected items could not be embedded".
The New Google Sites doesn't support Google Apps Script.
Related question: Google App Scripts For New Google Sites Release
The new Google Sites does now support embedding apps script (make sure to deploy the apps script as a web app, set the right permissions, and use the /exec url and not your /dev one to embed).
I found I couldn't use the facebook SDK for videos because of the sandboxing. I used an iframe solution instead for videos, but maybe you could try something like this for the feed (I'm assuming you've registered your app in fb so you can get generate tokens):
In apps script, create a .gs file and an html file, roughly along the lines below (I haven't actually worked with returning feeds, so check the returned data structure and adjust accordingly)
//**feed.gs**
function doGet(e) {
return HtmlService
.createTemplateFromFile('my-html-file')
.evaluate();
}
function getToken() { //use your fb app info here (and make sure this script is protected / runs as you
var url = 'https://graph.facebook.com'
+ '/oauth/access_token'
+ '?client_id=0000000000000000'
+ '&client_secret=0x0x0x0x0x0x0x0x0x0x0x0x'
+ '&grant_type=client_credentials';
var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
var json = response.getContentText();
var jsondata = JSON.parse(json);
return jsondata.access_token;
}
function getFeed() {
var url = 'https://graph.facebook.com'
+ '/your-page/feed'
+ '?access_token=' + encodeURIComponent(getToken());
var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
var json = response.getContentText();
var jsondata = JSON.parse(json);
//Logger.log(jsondata); //check this and adjust following for loop and html showFeed function accordingly
var posts = {};
for (var i in jsondata) {
posts[i] = {"post":jsondata[i].message};
}
return posts;
}
<!--**my-html-file.html**-->
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
// The code in this function runs when the page is loaded (asynchronous).
$(function() {
google.script.run
.withSuccessHandler(showFeed)
.withFailureHandler(onFailure)
.getFeed(); //this function is back in .gs file and must return an array or object which gets auto-passed to the showFeed function below
});
function showFeed(posts) { //parameter name must match array or object returned by getFeed in gs file
var html = '';
for (var p in posts) {
html += '<p>' + posts[p].post + '</p>'; //instead of a string, you can build an array for speed
}
$('#feed').empty().append(html); //if you used an array for the html, you'd split it here
}
function onFailure(error) {
$('#feed').empty().append("Unable to retrieve feed: " + error.message); ;
}
</script>
</head>
<body>
<div id="feed">
Loading...
</div>
</body>
</html>
I'm playing with the idea of making a completely JavaScript-based zip/unzip utility that anyone can access from a browser. They can just drag their zip directly into the browser and it'll let them download all the files within. They can also create new zip files by dragging individual files in.
I know it'd be better to do it serverside, but this project is just for a bit of fun.
Dragging files into the browser should be easy enough if I take advantage of the various methods available. (Gmail style)
Encoding/decoding should hopefully be fine. I've seen some as3 zip libraries so I'm sure I should be fine with that.
My issue is downloading the files at the end.
window.location = 'data:jpg/image;base64,/9j/4AAQSkZJR....'
this works fine in Firefox but not in Chrome.
I can embed the files as images just fine in chrome using <img src="data:jpg/image;ba.." />, but the files won't necessarily be images. They could be any format.
Can anyone think of another solution or some kind of workaround?
If you also want to give a suggested name to the file (instead of the default 'download') you can use the following in Chrome, Firefox and some IE versions:
function downloadURI(uri, name) {
var link = document.createElement("a");
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
And the following example shows it's use:
downloadURI("data:text/html,HelloWorld!", "helloWorld.txt");
function download(dataurl, filename) {
const link = document.createElement("a");
link.href = dataurl;
link.download = filename;
link.click();
}
download("data:text/html,HelloWorld!", "helloWorld.txt");
or:
function download(url, filename) {
fetch(url)
.then(response => response.blob())
.then(blob => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
})
.catch(console.error);
}
download("https://get.geojs.io/v1/ip/geo.json","geoip.json")
download("data:text/html,HelloWorld!", "helloWorld.txt");
Ideas:
Try a <a href="data:...." target="_blank"> (Untested)
Use downloadify instead of data URLs (would work for IE as well)
Want to share my experience and help someone stuck on the downloads not working in Firefox and updated answer to 2014.
The below snippet will work in both firefox and chrome and it will accept a filename:
// Construct the <a> element
var link = document.createElement("a");
link.download = thefilename;
// Construct the uri
var uri = 'data:text/csv;charset=utf-8;base64,' + someb64data
link.href = uri;
document.body.appendChild(link);
link.click();
// Cleanup the DOM
document.body.removeChild(link);
Here is a pure JavaScript solution I tested working in Firefox and Chrome but not in Internet Explorer:
function downloadDataUrlFromJavascript(filename, dataUrl) {
// Construct the 'a' element
var link = document.createElement("a");
link.download = filename;
link.target = "_blank";
// Construct the URI
link.href = dataUrl;
document.body.appendChild(link);
link.click();
// Cleanup the DOM
document.body.removeChild(link);
delete link;
}
Cross-browser solutions found up until now:
downloadify -> Requires Flash
databounce -> Tested in IE 10 and 11, and doesn't work for me. Requires a servlet and some customization. (Incorrectly detects navigator. I had to set IE in compatibility mode to test, default charset in servlet, JavaScript options object with correct servlet path for absolute paths...) For non-IE browsers, it opens the file in the same window.
download.js -> http://danml.com/download.html Another library similar but not tested. Claims to be pure JavaScript, not requiring servlet nor Flash, but doesn't work on IE <= 9.
There are several solutions but they depend on HTML5 and haven't been implemented completely in some browsers yet. Examples below were tested in Chrome and Firefox (partly works).
Canvas example with save to file support. Just set your document.location.href to the data URI.
Anchor download example. It uses <a href="your-data-uri" download="filename.txt"> to specify file name.
Combining answers from #owencm and #Chazt3n, this function will allow download of text from IE11, Firefox, and Chrome. (Sorry, I don't have access to Safari or Opera, but please add a comment if you try and it works.)
initiate_user_download = function(file_name, mime_type, text) {
// Anything but IE works here
if (undefined === window.navigator.msSaveOrOpenBlob) {
var e = document.createElement('a');
var href = 'data:' + mime_type + ';charset=utf-8,' + encodeURIComponent(text);
e.setAttribute('href', href);
e.setAttribute('download', file_name);
document.body.appendChild(e);
e.click();
document.body.removeChild(e);
}
// IE-specific code
else {
var charCodeArr = new Array(text.length);
for (var i = 0; i < text.length; ++i) {
var charCode = text.charCodeAt(i);
charCodeArr[i] = charCode;
}
var blob = new Blob([new Uint8Array(charCodeArr)], {type: mime_type});
window.navigator.msSaveOrOpenBlob(blob, file_name);
}
}
// Example:
initiate_user_download('data.csv', 'text/csv', 'Sample,Data,Here\n1,2,3\n');
This can be solved 100% entirely with HTML alone. Just set the href attribute to "data:(mimetypeheader),(url)". For instance...
<a
href="data:video/mp4,http://www.example.com/video.mp4"
target="_blank"
download="video.mp4"
>Download Video</a>
Working example: JSFiddle Demo.
Because we use a Data URL, we are allowed to set the mimetype which indicates the type of data to download. Documentation:
Data URLs are composed of four parts: a prefix (data:), a MIME type indicating the type of data, an optional base64 token if non-textual, and the data itself. (Source: MDN Web Docs: Data URLs.)
Components:
<a ...> : The link tag.
href="data:video/mp4,http://www.example.com/video.mp4" : Here we are setting the link to the a data: with a header preconfigured to video/mp4. This is followed by the header mimetype. I.E., for a .txt file, it would would be text/plain. And then a comma separates it from the link we want to download.
target="_blank" : This indicates a new tab should be opened, it's not essential, but it helps guide the browser to the desired behavior.
download: This is the name of the file you're downloading.
If you only need to actually have a download action, like if you bind it to some button that will generate the URL on the fly when clicked (in Vue or React for example), you can do something as easy as this:
const link = document.createElement('a')
link.href = url
link.click()
In my case, the file is already properly named but you can set it thanks to filename if needed.
For anyone having issues in IE:
dataURItoBlob = function(dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for(var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
}
var blob = dataURItoBlob(uri);
window.navigator.msSaveOrOpenBlob(blob, "my-image.png");
This code was originally provided by #Yetti on this answer (separate question).
Your problem essentially boils down to "not all browsers will support this".
You could try a workaround and serve the unzipped files from a Flash object, but then you'd lose the JS-only purity (anyway, I'm not sure whether you currently can "drag files into browser" without some sort of Flash workaround - is that a HTML5 feature maybe?)
Coming late to the party, if you'd like to use a function without using the DOM, here it goes, since the DOM might not even be available for whatever reason.
It should be applicable in any Browser which has the fetch API.
Just test it here:
// declare the function
function downloadAsDataURL (url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(res => res.blob())
.then(blob => {
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onloadend = () => resolve(reader.result)
reader.onerror = err => reject(err)
})
.catch(err => reject(err))
})
}
// simply use it like this
downloadAsDataURL ('https://cdn-icons-png.flaticon.com/512/3404/3404134.png')
.then((res) => {
console.log(res)
})
.catch((err) => {
console.error(err)
})
export const downloadAs = async (url: string, name: string) => {
const blob = await axios.get(url, {
headers: {
'Content-Type': 'application/octet-stream',
},
responseType: 'blob',
});
const a = document.createElement('a');
const href = window.URL.createObjectURL(blob.data);
a.href = href;
a.download = name;
a.click();
};
You can use a clean code solution, inform your url in a constant, and set it as param of open method instead in object window.
const url = "file url here"
window.open(url)
I want to create xul based frame in one of my firefox extension. The frame should look like https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/ui_frame
or
how to use below node js code in xul:
var { Frame } = require("sdk/ui/frame");
var frame = new Frame({
url: "./city-info.html"
});
In node.js, its working fine, but I dont know how to create the same thing with xul. Anybody can help?
thanks in advance.
You have provided very little detail as to what you desire. If all that you desire is to create an <iframe> in which you can load HTML content, then something along the lines of the following will do so:
//The URL of the HTML you desire to load.
let chromeUrl = '[Some URL here]';
//Whatever element you want the iframe placed under.
let parentEl = document.getElementById('foo');
//* Overlay and bootstrap (from almost any context/scope):
Components.utils.import('resource://gre/modules/Services.jsm');//Services
let activeWindow = Services.wm.getMostRecentWindow('navigator:browser');
//*/
let mainDocument = activeWindow.document;
//Create the <iframe> use
//mainDocument for the XUL namespace.
let iframeEl;
if(options.useBrowser){
iframeEl = mainDocument.createElement('browser');
} else {
iframeEl = mainDocument.createElement('iframe');
}
iframeEl.id = id;
iframeEl.setAttribute('src',chromeUrl);
iframeEl.setAttribute("tooltip", "aHTMLTooltip");
iframeEl.setAttribute("autocompleteenabled", true);
iframeEl.setAttribute("autocompletepopup", "PopupAutoComplete");
iframeEl.setAttribute("disablehistory",true);
iframeEl.setAttribute('type', 'content');
parentEl.appendChild(iframeEl);
The above code was taken from my answer to Firefox SDK Add-on with a sidebar on both the right and left at the same time, which creates sidebars. One option of how those sidebars are created is to have them contain an <iframe>.
Finally I got the answer:
let chromeUrl = 'YOUR HTML PAGE URL';
Components.utils.import('resource://gre/modules/Services.jsm');//Services
let activeWindow = Services.wm.getMostRecentWindow('navigator:browser');
//*/
let mainDocument = activeWindow.document;
let iframeEl;
iframeEl = mainDocument.createElement('iframe');
iframeEl.id = "d";
iframeEl.setAttribute('src',chromeUrl);
iframeEl.setAttribute("tooltip", "aHTMLTooltip");
iframeEl.setAttribute("autocompleteenabled", true);
iframeEl.setAttribute("autocompletepopup", "PopupAutoComplete");
iframeEl.setAttribute("disablehistory",true);
iframeEl.setAttribute('type', 'content');
iframeEl.setAttribute('height', '32px');
window.document.documentElement.appendChild(iframeEl);
In my Page_Load event of my custom DNN module I retrieve the settings that I have stored using the following.
if (((string)Settings["username"] != null) && ((string)Settings["username"] != ""))
username = "";
{
username = (string)Settings["username"];
if (((string)Settings["password"] != null) && ((string)Settings["password"] != ""))
{
password = (string)Settings["password"];
}
if (((string)Settings["baseServiceUrl"] != null) && ((string)Settings["baseServiceUrl"] != ""))
{
baseServiceUrl = (string)Settings["baseServiceUrl"];
}
baseServiceUrl = "";
Now my question is how do I redirect it to my module settings(called settings.ascx) control if username, password or baseServiceurl is null.
I'm sure it's not as simple as Response.Redirect('settings.ascx');
my aim is to replace
username = "";
with a snippet similar to Response.Redirect('settings.ascx');
Please help
If you want to load a different ASCX file that is registered in DNN (registered in the Module Definition, via the MANIFEST file) you do so by calling either the EditUrl method, or the NavigateURL Method in DNN.
EditUrl("Settings") where Settings is the ControlKey defined in the Module definition.
Edit URL is available off of PortalModuleBase, assuming your controls inherit from PMB.
Thanks again Chris, your answer is correct but I decided to get the settings of the module via the modal pop up. This is what I did to get the answer to get the javascript popup script and url i right clicked on the gear icon using google chrome an inspected the element.
I then copied the contents the anchor tag href attribute, this looked a bit like
href="javascript:dnnModal.show('http://localhost/TestPage/ctl/Module/ModuleId/417?ReturnURL=/TestPage&popUp=true',/*showReturn*/false,550,950,true,'')">
In my default.aspx page I created an anchor tag without the href. I made it a server control by putting runat=server and adding an ID to it and made the visibility false (in my logic i make it visible if it does not meet my criteria)
<a runat="server" class="btn btn-success" id="settingsLink" visible="false" > <img src="/images/action_settings.gif"><span>Settings</span></a>
Next I create a method to dynamically build my link
private string settingsUrlBuilder()
{
var s = new StringBuilder();
var urlPartArray = TabController.CurrentPage.FullUrl.ToString().Split('/');
var partUrl = urlPartArray[3].ToString();
s.Append("javascript:dnnModal.show('");
s.Append(TabController.CurrentPage.FullUrl.ToString().ToLower());
s.Append("/ctl/Module/ModuleId/" + ModuleId.ToString());
s.Append("?ReturnURL=/");
s.Append(partUrl);
s.Append("&popUp=true");
s.Append("',/*showReturn*/false,550,950,true,'')");
return s.ToString();
}
This is where i use the function in the page load
settingsLink.HRef = settingsUrlBuilder(); settingsLink.Visible = true;
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