google extension inline install and Verified not working - google-chrome-extension

google.com/webstore i have add my extension
i Have check "This item uses inline install."
Websites: chose Verify site
google.com/webmasters i have add site and Verifyed.
when i put this code on me site:
<link rel="chrome-webstore-item"href="https://chrome.google.com/webstore/detail/itemID">
<button onclick="chrome.webstore.install()" id="install-button">Add to Chrome</button>
<script>
if (document.getElementById('extension-is-installed')) {
document.getElementById('install-button').style.display = 'none';
}
</script>
i click on button "Add to Chrome" install app extension, but when i refresh site button "Add to Chrome" is display. why? i cant Understanding

You're obviously following the guide at https://developer.chrome.com/webstore/inline_installation
In that case, you missed a step.. Let's look at the code.
if (document.getElementById('extension-is-installed')) {
document.getElementById('install-button').style.display = 'none';
}
The condition here is whether an element with ID extension-is-installed is present on the page. But what adds it?
A step back:
For example, you could have a content script that targets the installation page:
var isInstalledNode = document.createElement('div');
isInstalledNode.id = 'extension-is-installed';
document.body.appendChild(isInstalledNode);
So, you need to add a Content Script that adds that element to the page.
However, I doubt that guide will work. By default, content scripts execute after DOM is loaded (and therefore, that hiding script has executed). You can make them run at document_start, but then body does not exist yet.
Let me make an alternative hiding script, based on communicating with the extension using "externally_connectable". Suppose your website is example.com, and your extension's ID is itemID
Add example.com to sites you want to be messaged from:
"externally_connectable" : {
"matches" : [
"*://*.example.com/*"
]
},
In your background page, prepare for the message from the webpage:
chrome.runtime.onMessageExternal.addListener(
function(message, sender, sendResponse) {
if(message.areYouThere) sendResponse(true);
}
);
In your page at example.com, add a button (hidden by default) and code to show it when appropriate:
<button onclick="chrome.webstore.install()"
id="install-button" style="display:none;">
Add to Chrome
</button>
<script>
if (chrome) {
// The browser is Chrome, so we may need to show the button
if(chrome.runtime && chrome.runtime.sendMessage) {
// Some extension is ready to receive messages from us
// Test it:
chrome.runtime.sendMessage(
"itemID",
{areYouThere: true},
function(response) {
if(response) {
// Extension is already installed, keep hidden
} else {
// No positive answer - it wasn't our extension
document.getElementById('install-button').style.display = 'block';
}
}
);
} else {
// Extension is not installed, show button
document.getElementById('install-button').style.display = 'block';
}
}
</script>
Was requested to add page reload after install. chrome.webstore.install has a callback parameter specifically for this.
Instead of using onclick attribute, assign a function:
document.getElementById('install-button').addEventListener("click", function(e) {
chrome.webstore.install(function() {
// Installation successful
location.reload();
});
});

Related

Orchard and editing page - adding script

I can add a script to a page via the dashboard (by editing the page Content Item as html). The script is added to the page and evaluated, but too early - none of scripts are loaded yet (for example, jQuery).
I don't want to add the script to Layout, as it makes no sense to add this script for all pages.
Is there any way to add a script to a single page's content via the dashboard, so that it can be evaluated properly?
Or should I create a separate module that contains a special content part (to include proper scripts for the view/shape) and add that part to a custom ContentType (that also contains BodyPart and others such as Page Content Items)?
Or should I separate the whole content in such a way that interactive parts are widgets and should not be edited in Page Content Item?
Can you use the Script.Foot() extension method ?
#using(Script.Foot()) {
...
}
Using jQuery from Orchard module page
You can add the script file to the top of the html content like below:
<p>
<script type="text/javascript" src="/*path of the file*/">// <![CDATA[
// ]]></script>
</p>
Steps to add: Dashboard->Content->open the particular page->Html source editor->In the top add the above script with your script file path.
I suggest adding a part for your script, something like:
public class CustomScriptPart : ContentPart<CustomScriptPartRecord>
{
public bool AtFoot
{
get { return Record.AtFoot; }
set { Record.AtFoot = value; }
}
public string Script
{
get { return Record.Script; }
set { Record.Script = value; }
}
}
Views/Parts/CustomScript.cshtml
#if(Model.AtFoot) {
using(Script.Foot()) {
<script type="text/javascript">
#Model.Script
</script>
}
} else {
<script type="text/javascript">
#Model.Script
</script>
}
But probably something similar is already done, by Vandelay Industries for example.

PJax not working with MVC project

I've followed the samples. I added a _PjaxLayout:
<title>#ViewBag.Title</title>
#RenderBody()
Modified my _Layout:
<div id="shell">
#RenderBody()
</div>
<script type="text/javascript">
$(function () {
// pjax
$.pjax.defaults.timeout = 5000;
$('a').pjax('#shell');
})
</script>
Updated ViewStart:
#{
if (Request.Headers["X-PJAX"] != null) {
Layout = "~/Views/Shared/_PjaxLayout.cshtml";
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
Yet every time I click on an 'a' tag, the pjax code doesn't get called. It's as if the selector isn't working when I set up pjax. What am I doing wrong?
UPDATE:
If I do this:
$('document').ready(function () {
$('a').pjax({
container: '#shell',
timeout: 5000
});
});
I see the pjax code getting hit and the Request headers get updated, and the new content loads on the page, but the styling and layout get really messed up and duplicated...
UPDATE:
Inspecting the DOM after this craziness happens reveals that the new page content is getting loaded directly into the anchor that I click, instead of into the element with id #shell. WTF?
You are using a legacy syntax, the new pjax uses the following:
$(document).pjax('a', '#shell', { fragment: '#shell' });
Also I am not familiar with the language you use, but in order to make pjax happen there has to be an HTML element with the id shell in your ViewStart.
As I am not sure about the syntax in that language, try something similar to this for testing:
#{
if (Request.Headers["X-PJAX"] != null) {
echo "<ul id="shell"> pjaaxxx </ul>"; // Would work in php, update syntax
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
I am not seeing that syntax as valid in the PJax documentation.
Are you sure you didn't mean $(document).pjax('a',{});?
$.pjax immediately executes from what I can tell.

Chrome page action popup disappears

I need a page action popup icon to appear when a tab has a specific URL in the address bar.
I have this in my background page
chrome.tabs.query({url:"MYURL.COM"} , function(tab)
{
for(i=0;i<tab.length;i++)
{
console.log(tab[i].id);
chrome.pageAction.show(tab[i].id);
}
});
The popup shows whenever I reload the extension but as soon as user refreshes, it goes away and doesn't come back.
The reason is that the background.js page is only loaded once, so you need to add a listener to every time the page tab is updated to check whether the page action should be shown, something like this:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (tab.url.indexOf("MYURL.COM") > -1) {
chrome.pageAction.show(tabId);
}
});
There is no reason to iterate over each tab as you have done.
As Adam has already said, the tabs.onUpdated event is the way to do it.
Anyway, it [seems like I'm not the only one who experienced that the tabs.onUpdated event doesn't always fire when it should - even when waiting for complete status.
So if you're having the same issue, you might want to try my modified version that has proven reliable for me 100%.
chrome.tabs.onUpdated.addListener(function(tabId, change) {
if (change.status == "complete") {
chrome.tabs.query({active: true}, function(tabs) {
var tab = tabs[0];
// Now do stuff with tab .. Eg:
if (tab.url.indexOf("MYURL.COM") > -1) {
chrome.pageAction.show(tab.id); }
else {
chrome.pageAction.hide(tab.id); }
});
}
});
Use chrome.tabs.onUpdated to listen to new tabs and tab reloads of the domain you are interested in.

chrome extension: Injecting code which references a script that I am also injecting - why it fails?

I am trying to create a jquery popup on any page, triggered on demand, when the user presses on my chrome extension.
I have permissions set to [ "tabs", "http:///", "https:///" ]
I have a background page which tries to do the following:
chrome.browserAction.onClicked.addListener(function(tab) {
//chrome.tabs.executeScript(null, { code: "alert(document.title);" }, null);
chrome.tabs.executeScript(null, {file: "demo.js"}, null);
chrome.tabs.executeScript(null, { code: "document.body.appendChild(document.createElement('script')).src='demo.js'" }, null);
});
If I uncomment the alert, it appears when I click on the extension icon.
But with the comment as it is it doesn't do anything.
Any thoughts why it fails?
UPDATE
I managed to get it working, by referencing a url and not a local resource(demo.js).
Now the code, that works, looks like this:
chrome.tabs.executeScript(tab.id, { code: "document.body.appendChild(document.createElement('script')).src='http://iamnotagoodartist.com/stuff/wikiframe.js'" }, null);
My local "demo.js" was a copy of the content from that url anyway.
I am not sure why it doesn't work when I reference the local file... ?
You must use chrome.extension.getURL to get the full path to the "demo.js" file.
chrome.tabs.executeScript(null, {
code: "document.body.appendChild(document.createElement('script')).src='" +
chrome.extension.getURL("demo.js") +"';"
}, null);
BTW if you set tabId parameter to null, the script won't be injected into the background page but into the selected tab of the current window.
You are not passing the tab id to executeScript so the scripts are getting injected into the backround page where you can't interact with them.
chrome.tabs.executeScript(tab, {file: "demo.js"}, null);

SharePoint: commonModalDialogClose does not close cross-domain dialog

I have a page hosted in 'virtualcasa1' domain opening a modal dialog:
var options = {
title: "Repro",
width: 400,
height: 600,
url: http://domain2:999/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx //[1]
//url: http://virtualcasa1/sites/blank/_layouts/XDomainTest/XDomainTestTarget.aspx [2]
};
SP.UI.ModalDialog.showModalDialog(options);
And I have this code to close it:
alert(document.domain);
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked');
If both are in the same domain (case [2] above), the dialog closes well, no issues.
But - if target page hosted in the dialog (case [1] above), dialog does NOT close :-(
document.domain above shows the correct domain where page exists.
I suspect I'm facing a cross-domain issue here (duh), but how to fix it? Or am I wrong and issue is not XDomain-related?
Thanks much!
HTML5's postMessage is your answer.
https://developer.mozilla.org/en-US/docs/Web/API/Window.postMessage
Your parent window that initiates the dialog must have the following javascript:
function listener(event) {
//alert(event.data);
if (event.data == 'Cancel') {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancel clicked');
}
else {
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, event.data);
}
}
if (window.addEventListener) {
addEventListener("message", listener, false)
} else {
attachEvent("onmessage", listener)
}
Javascript for OK and Cancel buttons in your popup:
<input type="button" value="OK" onclick="parent.postMessage('Message to be displayed by the parent', '*');" class="ms-ButtonHeightWidth" />
<input type="button" value="Cancel" onclick="parent.postMessage('Cancel', '*');" class="ms-ButtonHeightWidth" />
Ajay's answer from the 1st of August 2014 is good, but it needs a bit more explanation. The reason for the failure to close the dialog is simple. Cross site scripting security features of modern browsers disallow a few things, one of which is the use of window.frameElement from within the framed window. This is a read-only property on the window object and it becomes set to null (or with IE, it actually throws an exception when you try to access it). The ordinary Cancel event handlers in the modal dialog conclude with a call to window.frameElement.cancelPopup(). This will fail of course. The ordinary Save handler where the Save worked on the server side results in SharePoint sending back a single line as the replacement document, which is a scriptlet to call window.frameElement.commitPopup(). This also will not work, and it's a real pain to overcome because the page has been reloaded and there is no script available to handle anything. XSS won't give us access to the framed DOM from the calling page.
In order to make a cross domain hosted form work seamlessly, you need to add script to both the page that opens the dialog and the framed page. In the page that opens the dialog, you set the message listener as suggested by Ajay. In the framed form page, you need something like below:
(function() {
$(document).ready(function() {
var frameElement = null;
// Try/catch to overcome IE Access Denied exception on window.frameElement
try {
frameElement = window.frameElement;
} catch (Exception) {}
// Determine that the page is hosted in a dialog from a different domain
if (window.parent && !frameElement) {
// Set the correct height for #s4-workspace
var frameHeight = $(window).height();
var ribbonHeight = $('#s4-ribbonrow').height();
$('#s4-workspace').height(frameHeight - ribbonHeight);
// Finds the Save and Cancel buttons and hijacks the onclick
function applyClickHandlers(theDocument) {
$(theDocument).find('input[value="Cancel"]').removeAttr('onclick').on('click', doTheClose);
$(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Cancel-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheClose);
$(theDocument).find('input[value="Save"]').removeAttr('onclick').on('click', doTheCommit);
$(theDocument).find('a[id="Ribbon.ListForm.Edit.Commit.Publish-Large"]').removeAttr('onclick').removeAttr('href').on('click', doTheCommit);
}
// Function to perform onclick for Cancel
function doTheClose(evt) {
evt.preventDefault();
parent.postMessage('Cancel', '*');
}
// Function to perform onclick for Save
function doTheCommit(evt) {
evt.preventDefault();
if (!PreSaveItem()) return false;
var targetName = $('input[value="Save"]').attr('name');
var oldOnSubmit = WebForm_OnSubmit;
WebForm_OnSubmit = function() {
var retVal = oldOnSubmit.call(this);
if (retVal) {
var theForm = $('#aspnetForm');
// not sure whether following line is needed,
// but doesn't hurt
$('#__EVENTTARGET').val(targetName);
var formData = new FormData(theForm[0]);
$.ajax(
{
url: theForm.attr('action'),
data: formData,
cache: false,
contentType: false,
processData: false,
method: 'POST',
type: 'POST', // For jQuery < 1.9
success: function(data, status, transport) {
console.log(arguments);
// hijack the response if it's just script to
// commit the popup (which will break)
if (data.startsWith('<script') &&
data.indexOf('.commitPopup()') > -1)
{
parent.postMessage('OK', '*');
return;
}
// popup not being committed, so actually
// submit the form and replace the page.
theForm.submit();
}
}).fail(function() {
console.log('Ajax post failed.');
console.log(arguments);
});
}
return false;
}
WebForm_DoPostBackWithOptions(
new WebForm_PostBackOptions(targetName,
"",
true,
"",
"",
false,
true)
);
WebForm_OnSubmit = oldOnSubmit;
}
applyClickHandlers(document);
}
});
})();
This solution makes use of the jQuery library, which our organization uses extensively. It is our preferred framework (chosen by me). I'm sure someone very clever could rewrite this without that dependency, but this is a good starting point. I hope someone finds it useful, as it represents a good two days work. Some things to note:
SharePoint does a postback on all sorts of events on the page, including putting the page into edit mode. Because of this, it makes more sense to trap the specific button clicks, both on the form and in the ribbon, rather than wholesale redefinition of, for example, the global WebForm_OnSubmit function. We briefly override that on a Save click and then set it back.
On any Save click event, we defeat the normal posting of the form and replace that with an identical POST request using AJAX. This allows us to discard the returned scriptlet when the form was successfully posted. When the form submission was not successful, perhaps because of blank required values, we just post the form properly to allow the page to be updated. This is fine, since the form will not have been processed. An earlier version of this solution took the resulting HTML document and replaced all of the page contents, but Internet Explorer doesn't like this.
The FormData api allows us to post the form as multipart-mime. This api has at least basic support in all modern browsers, and there are workarounds for older ones.
Another thing that seems to fail in the cross domain hosted dialog is the scrolling of the content window. For whatever reason, the height is not set correctly on the div with id s4-workspace, so we also set that in the solution.
EDIT:
Almost forgot. You may also need to add this control to your framed ASPX page, which can be done with SharePoint Designer:
<WebPartPages:AllowFraming runat="server"/>
I have exactly the same issue - a dialog opening a view page for an item works fine when opened from a site collection on the same web app/domain, but the Close button fails to work when opening the same item from a site collection hosted in a separate web application. I'm assuming it is a cross-domain thing so I've altered the solution to accomodate this restriction, however, I'm not 100% happy about it as it does make the overall solution a little awkward to use from a user-perspective. I've put the issue to one side for now due to project timescales, but I'm still curious as to why. The only things I can think of is the whole cross-domain thing causing it and that maybe it is there by design to prevent XSS security holes.

Resources