Idea:
After dynamic content is loaded, on mouseover I'm trying to render google share button like it says on the official google developer's site.
Code I'm using is:
gapi.plus.render(div);
Facts:
If I change plus to plusone, it renders google plus button instead share. ( Means: Scripts load up )
If I remove {"parsetags": "explicit"}, Buttons load up ( But doesn't load up on hover )
Problem:
Share button doesn't load up.
Debuging links with plus.render and plusone.render:
http://romanlosev.igloro.info/googleshare.php?load=plusone ( plusone - works, but plus+ buttons load up )
http://romanlosev.igloro.info/googleshare.php?load=plus ( plus - doesn't works )
There's a similar question on StackOverflow here.
What you need to do is call the explicit render method for the share buttons. Replacing your function that selects the div with the following code will delay render for the share objects on screen.
$("#clickme").click(function()
{
gapi.plus.go();
});
To render individual buttons, you must pass an object with the action parameter set to share, for example:
gapi.plus.render("plusOne", {action: "share"});
The following is a more complete example, that does asynchronous script loading and renders various share targets, visible here:
<html>
<body>
<p>
<div data-action="share" class="g-plus" id="plusOne"></div>
<button onClick="gapi.plus.render('plusOne', getParamBag('https://www.google.com'))"></button>
</p>
<p>
<div data-action="share" class="g-plus" id="plusTwo"></div>
<button onClick="gapi.plus.render('plusTwo', getParamBag('https://plus.google.com'))"> </button>
</p>
<p>
<div data-action="share" class="g-plus" id="plusThree"></div>
<button onClick="gapi.plus.render('plusThree', getParamBag('https://developers.google.com'))"></button>
</p>
</body>
<script type="text/javascript">
window.___gcfg = {
lang: 'en-US',
parsetags: 'explicit'
};
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
function getParamBag(url){
return {
action: "share",
href: url
};
}
</script>
</html>
Related
I am building an Asp.Net Core web application using Razor.
The intended audience for this app will be using it on tablets.
Part of the application consists of several pages/forms that will require user signatures.
We could retrieve an image of a user's signature and display that on demand in the web page.
Is it possible to be more interactive and allow users to "sign" the form/page within the browser? Are there any 3rd party control libraries that would support this functionality?
I pretty sure this can be done on native applications, but can I achieve this through Asp.Net Core?
I found signature_pad in github, and it works for me.
You can take a look at the screenshots of my test steps first, and I will add the test code at the bottom.
Test Code
1. signature.cshtml
#*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*#
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad#2.3.2/dist/signature_pad.min.js"></script>
<form method="POST">
<p>
<canvas width="500" height="400" id="signature"
style="border:1px solid black"></canvas><br>
<button type="button" id="accept"
class="btn btn-primary">
Accept signature
</button>
<button type="submit" id="save"
class="btn btn-primary">
Save
</button><br>
<img width="500" height="400" id="savetarget"
style="border:1px solid black"><br>
<input id="SignatureDataUrl" type="text">
</p>
</form>
<script>
$(function () {
var canvas = document.querySelector('#signature');
var pad = new SignaturePad(canvas);
$('#accept').click(function () {
var data = pad.toDataURL();
$('#savetarget').attr('src', data);
$('#SignatureDataUrl').val(data);
pad.off();
});
$('#save').click(function () {
$.ajax({
url: "/ForTest/get_signature",
type: "POST",
data: { base64png:$('#SignatureDataUrl').val()},
success: function (data) {
console.log("success");
},
error: function (hata, ajaxoptions, throwerror) {
alert("failed");
}
});
});
});
</script>
2. C# code
[HttpPost]
public string get_signature(string base64png) {
var dataUri = base64png;//"data:image/png;base64,iVBORw0K...";
var encodedImage = dataUri.Split(',')[1];
var decodedImage = Convert.FromBase64String(encodedImage);
System.IO.File.WriteAllBytes("signature_pic/"+DateTime.Now.ToString("yyyyMMddHHmmss")+"signature.png", decodedImage);
return "ok";
}
Tips
If you want test my code, you need create signature_pic folder like me.
I have a page with an embedded Ace code editor that will contain Java code. I want to get its contents via a POST request after a button is pressed.
I'm aware that one can do this in order to get the value:
var code = editor.getValue();
However, I'm not too sure how I would get this value from my route handler. Ideally, I'd like to have the editor script inside a separate .js file, but I can't seem to get it to be recognized by anything.
In my handlebars template for /myroute/*
<div class = "bigclass">
some divs
<div id = "containerclass">
<div id = "editor"></div>
<script src = "https://pagecdn.io/lib/ace/1.4.8/ace.js", type = "text/javascript" charset = "utf-8"></script>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/github");
editor.session.setMode("ace/mode/java");
editor.session.setUseWrapMode(true);
editor.setValue("Hello");
editor.clearSelection();
</script>
</div>
some more divs
<div id = "someotherclass">
<form method = "POST" action = "">
<button style = "text-align: center" type="submit" class="btn"> Submit</button>
</form>
</div>
</div>
Route Handler for /myroute/*
app.post('/myroute/*', function(req, res) {
// Get the contents of the editor
});
You've to set an input inside your form, and fill it every time a change is done on the editor.
On clicking submit, you can have the value from the req.body
<div class = "bigclass">
some divs
<div id = "containerclass">
<div id = "editor"></div>
<script src = "https://pagecdn.io/lib/ace/1.4.8/ace.js", type = "text/javascript" charset = "utf-8"></script>
</div>
some more divs
<div id = "someotherclass">
<form method = "POST" action = "">
<textarea name="content" id="content"></textarea>
<button style = "text-align: center" type="submit" class="btn"> Submit</button>
</form>
</div>
</div>
<script>
var editor = ace.edit("editor");
editor.setTheme("ace/theme/github");
editor.session.setMode("ace/mode/java");
editor.session.setUseWrapMode(true);
editor.getSession().on("change", function () {
document.getElementById('content').val(editor.getSession().getValue());
});
editor.setValue("Hello");
editor.clearSelection();
</script>
Server:
app.post('/myroute/*', function(req, res) {
const content = req.body.content;
});
I have a search bar within my header and a seperate search page,
When you do a search request in the search bar. It returns a querystring which looks like '?q=querystring', it automatically links this querystring to my search page.
Question
How can I take the querystring from the address bar and use it to fill in the Google Custom Search bar.
You did not specify what you were using, so I will make the assumption that you want the easiest way out:
If you are using the new Element API v2, then you have two options to handle 2-page search:
Full Render
Index.html
<!-- GOOGLE SEARCH JS Search Only Implementation-->
<div>
<script>
(function() {
var cx = 'YOUR_API_KEY';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
<gcse:searchbox-only resultsUrl="search.html"></gcse:searchbox-only>
</div>
search.html
<!-- GOOGLE SEARCH JS Implementation-->
<div>
<script>
(function() {
//Same code from Index.html
</script>
<gcse:search></gcse:search>
</div>
Custom Index + Search Page Render
You create your own search form at the Index page where it sends a HTTP GET with a parameter that you will hook on the queryParameterName. This will be specified in the gsce element being rendered. An example URL would be http://localhost:3939/search?search_term=Miku
Index.html
<form method="get" action="search.html" name="searchform" id="searchform">
<label for="words">Search:</label>
<input name="search_term" alt="Search_term" value="" size="16" id="words" type="text" accesskey="s">
<button type="submit" value="Submit" accesskey="g">Search</button>
</form>
Search.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div>
<script>
(function() {
var cx = 'YOUR CSE KEY';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = 'https://cse.google.com/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
<gcse:search queryParameterName="search_term"></gcse:search>
</div>
</body>
</html>
From my experience dealing with the element API v2, this is one of the few exposed hooks in which you can customize on the client side. Also, you should render your own code at the CSE Page, then add the queryParameterName.
I started to use Pubnub for making video group chats. However, when I was testing it, I found a little problem: As I connect my computer to their servers, my webcam turns on and never turns off, unless I leave the page.
However, I wish to be able to close a video chatting, and turning off the webcam at the same time. How to do it?
Thank you very much!
EDIT: Here is a code I'm using for my tests, I'm using the one given in the tutorial:
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/jquery-ui.min.js"></script>
<script src="js/pubnub-3.7.18.min.js"></script>
<script src="js/webrtc.js"></script>
<script src="js/rtc-controller.js"></script>
<div id="vid-box"></div>
<div id="vid-thumb"></div>
<form name="loginForm" id="login" action="#" onsubmit="return login(this);">
<input type="text" name="username" id="username" placeholder="Pick a username!" />
<input type="submit" name="login_submit" value="Log In">
</form>
<form name="callForm" id="call" action="#" onsubmit="return makeCall(this);">
<input type="text" name="number" placeholder="Enter user to dial!" />
<input type="submit" value="Call"/>
</form>
<div id="inCall"> <!-- Buttons for in call features -->
<button id="end" onclick="end()">End</button> <button id="mute" onclick="mute()">Mute</button> <button id="pause" onclick="pause()">Pause</button>
</div>
<script>
var video_out = document.getElementById("vid-box");
var vid_thumb = document.getElementById("vid-thumb");
function login(form) {
var phone = window.phone = PHONE({
number : form.username.value || "Anonymous", // listen on username line else Anonymous
media : { audio : true, video : true },
publish_key : 'pub-c-c66a9681-5497-424d-b613-e44bbbea45a0',
subscribe_key : 'sub-c-35aca7e0-a55e-11e5-802b-02ee2ddab7fe',
});
var ctrl = window.ctrl = CONTROLLER(phone);
ctrl.ready(function(){
form.username.style.background="#55ff5b"; // Turn input green
form.login_submit.hidden="true"; // Hide login button
ctrl.addLocalStream(vid_thumb); // Place local stream in div
}); // Called when ready to receive call
ctrl.receive(function(session){
session.connected(function(session){ video_out.appendChild(session.video); });
session.ended(function(session) { ctrl.getVideoElement(session.number).remove(); });
});
ctrl.videoToggled(function(session, isEnabled){
ctrl.getVideoElement(session.number).toggle(isEnabled); // Hide video is stream paused
});
ctrl.audioToggled(function(session, isEnabled){
ctrl.getVideoElement(session.number).css("opacity",isEnabled ? 1 : 0.75); // 0.75 opacity is audio muted
});
return false; //prevents form from submitting
}
function makeCall(form){
if (!window.ctrl) alert("Login First!");
else ctrl.dial(form.number.value);
return false;
}
function end(){
ctrl.hangup();
}
function mute(){
var audio = ctrl.toggleAudio();
if (!audio) $("#mute").html("Unmute");
else $("#mute").html("Mute");
}
function pause(){
var video = ctrl.toggleVideo();
if (!video) $('#pause').html('Unpause');
else $('#pause').html('Pause');
}
</script>
Note that I tried to find the function through the console in addition to my searches, but I was unable to find it...
The problem is that the TabConainer inside the Dialog is empty after opening although selected="true" is given (see the screenshot below). The content is called with dojo/html html.set(node, contentHTML, {parseContent: true});
When changing the tab by clicking on another one the content appears and the class "dijitVisible" is set for this div as it should be from the beginning. The attribute nested="true" is necessary since otherwise three select bars are shown over the tabContainer.
What can I do so that the content appears from the start on?
<div data-dojo-type="dijit/Dialog" id="formDialog" data-dojo-id="formDialog" title="Edit member data">
<div id="formContent" class="dijitDialogPaneContentArea" data-dojo-attach-point="formContent">
</div>
</div>
Update:
Here is the whole javascript for getting the content
getForm = function(formID, urlAction){
var contentHTML;
var xhrArgs = {
url: urlAction,
handleAs: "text",
load: function(data){
contentHTML = data;
},
error: function(error){
contentHTML = text_error_unexpected + ": " + error;
},
handle: function(error, ioargs){
var node = dom.byId(formID);
html.set(node, contentHTML, {parseContent: true});
}
}
var deferred = dojo.xhrGet(xhrArgs);
};
Update 2:
This is the content that gets called and inserted in the above div "formContent" (I thought I make the description as simple as possible and lost some details on the way)
<div id="form" data-dojo-type="dijit/form/Form" data-dojo-attach-point="form" encType="multipart/form-data" action="#">
<div style="width: 450px; height: 370px;">
<div data-dojo-type="dijit/layout/TabContainer" nested="true">
<div data-dojo-type="dijit/layout/ContentPane" title="Personal data" selected="true">
Content 1
</div>
<div data-dojo-type="dijit/layout/ContentPane" title="Detailed data">
Content 2
</div>
<div data-dojo-type="dijit/layout/ContentPane" title="Contact data">
Content 3
</div>
</div>
</div>
</div>
Have you tried calling either dialog.resize() or tabcontainer.layout() after adding it to the dialog?
I am not sure as to how the code below will place contents inside the first ContentPane (title="Personal data"). I am assuming that the parameter formID = "form"
html.set(node, contentHTML, {parseContent: true});
I can suggest an alterantive.
Use an id with the content pane as shown below.
<div id="content1" data-dojo-type="dijit/layout/ContentPane" title="Personal data" selected="true">
Content 1
</div>
Then use dijit/registry to get the contentpane widget in the handle function call as shown below.
handle: function(error, ioargs){
var content= registry.bId(formId); // over here formId = "content1"
content.set("content","<p>This is content for <b>Personal Data</b></p>");
//content.set("content", contentHTML);
}
EDIT 1
This is may be one possible solution.
#Richard had suggested dialog.resize(), which I did try to put it after the html.set code but it would not work.
What I have noticed is that the html.set takes some time to execute and the dialog.resize() does not work because it is
called before the completion of the html.set call.
html.set also complicates the issue as it does not provide any handle (promise object) to let us know when it has finished execution.
so the below solution uses a setTimeout call to delay the execution of the dialog.resize(). Hence would advice to put the value of delay time depending upon some actual UI testing.
Modified code.
handle: function(error, ioargs){
var node = dom.byId(formID);
html.set(node, contentHTML, {parseContent: true});
var dialog = registry.bId("formDialog");
setTimeout( function(){
dialog.show();
dialog.resize();
},2000) // time delay of 2 seconds
}