Identify true activeElement in a frame hierarchy - google-chrome-extension

I'm looking for a way to get the focused input of any page with the goal to update it's value.
I have a content script that receives the value and checks if activeElement is an <input>.
The challenge is when the main document's activeElement is an iframe. I can set all_frames: true in manifest, which will find any active <input>, but I only want to set the value of the activeElement of the active iframe.
Currently I'm solving this by letting the child content script(s) blur() all activeElements except the current one (attaching a handler to focusin), but a solution that does not modify the document state would be better imho.
Is it possible to send a message only to the main document and if this one's activeElement is an iframe, get that frameId (and try again)?
I don't control the web pages.

Inject a new content script that checks the full hierarchy of frames, including cross-domain frames.
main content script asks the background/event page if needed:
if (document.activeElement.matches('input') && window == parent) {
console.log('Input', document.activeElement);
document.activeElement.value += ' gotcha!';
} else {
chrome.runtime.sendMessage({action: 'modifyInput'});
}
background/event page script executes the additional content script in all frames:
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse)) {
if (msg.action == 'modifyInput') {
chrome.tabs.executeScript(sender.tab && sender.tab.id, {
file: 'modify-input.js',
allFrames: true,
matchAboutBlank: true,
runAt: 'document_end',
});
}
});
modify-input.js, IIFE is used to makes sure garbage collection removes the injected stuff.
;(function() {
if (isInputActive()) {
if (window == parent) {
foundTheInput();
} else {
askParent();
}
} else if (isFrameActive()) {
window.addEventListener('message', function onMessage(e) {
if (!e.data || e.data.id != chrome.runtime.id)
return;
switch (e.data.action) {
// request from a child frame
case 'checkme':
if (window == parent) {
confirmChild(e.source);
window.removeEventListener('message', onMessage);
} else {
askParent();
}
break;
// response from a parent
case 'confirmed':
window.removeEventListener('message', onMessage);
if (isInputActive()) {
foundTheInput();
} else if (isFrameActive()) {
confirmChild(e.source);
}
break;
}
});
}
function isInputActive() {
return document.activeElement.matches('input');
}
function isFrameActive() {
return document.activeElement.matches('frame, iframe');
}
function askParent() {
parent.postMessage({id: chrome.runtime.id, action: 'checkme'}, '*');
}
function confirmChild(childWindow) {
console.log('Frame', document.activeElement);
childWindow.postMessage({id: chrome.runtime.id, action: 'confirmed': true}, '*');
}
function foundTheInput() {
console.log('Input', document.activeElement);
document.activeElement.value += ' gotcha!';
}
})();
I didn't test this, but did use and saw similar code previously.

Related

How to conditional statements in action output in Bixby

Hi I want to go to another action by putting a conditional statement in the action output.
What should I do?
For example
action (~~) {
description (Validate items passed from javascript)
collect {
input (~~) {
type (~~)
min (~~) max (~~)
}
}
type(~~~)
output (items){
on-empty(items.item1){ // if items.item1 is empty.
replan { // go to case1Action.
intent {
goal : case1Action
value : ~~~~~
}
}
}else{ // else
replan { // go to case2Action.
intent {
goal : case2Action
value : ~~~~~
}
}
}
}
or I want to select the view according to the output value.(Actually this is the purpose of the question)
output (items){
if(items.item1 == "goFirstCase"){
// First case view
}else{
// Second case view
}
}
I think by "select a different view according to the output value" I presume you mean you want to change what shows on the screen? because a "view" actually is comprised of the dialog, layout, and conversation-drivers.
https://bixbydevelopers.com/dev/docs/dev-guide/developers/building-views.views
For majority of use cases, there's really only one result-view that will be used, and any of the three contents of a view can be changed based on your preferred conditions as the above answer suggests.
within a view you can have the three different components defined with these three blocks: message for dialog, render for layout, and conversation-drivers
using your example,
//in a result-view
message {
if (items.item1 == "firstCase") {
template-macro (firstCase-result-dialog) {//enter params}
}
}
render {
if (size(items) > 1) {
list-of (items) {
where-each (item) {
if (item == "firstCase") {
layout-match (item) {
mode (Summary)
}
// OR use layout-macro
layout-macro (firstCase-result-summary-thumbnail-card) {//enter params}
}
}
}
}
}
similar conditional work can be done on conversation-drivers of course.
In your case, you would not need on-empty in action, but use template-macro-def as briefly explained in https://corp.bixbydevelopers.com/dev/docs/dev-guide/developers/refining-dialog.dialog-macros
// template file one
template-macro-def (id1) {
params {
param (x) {
Type (Items) ....
}
// template file two
template-macro-def (id2) {
// param x is type Items
}
//view file
result-view {
match: Items(this)
// after some checking make sure is single item
// it is possible to use other condition like if (this.sub1 == 2)
if (exists(this.sub1)) {
template-macro (id1) {
param (x) { expression (this) }
}
}
else {
template-macro (id2) {
param (x) { expression (this) }
}
}
The above would be the recommended way to handle different views for same concept in Bixby.
on-empty in action would be used for the purpose of either replan or relax some search condition in order to avoid 0 result. Bixby does not support on-empty(key) {} syntax according to https://corp.bixbydevelopers.com/dev/docs/reference/type/action.output.on-empty and on-empty would only apply in your case if output(items) itself is empty and would not check any sub-property of items.
Another option.
instead to use 'on-empty' block, you can use 'throws - error'
in action model,
output (items) {
throws {
error (case1ActionError) {
on-catch {
replan {
intent {
goal : case1Action
value : ~~~~~
}
}
}
}
error (case2ActionError) {
on-catch {
replan {
intent {
goal : case2Action
value : ~~~~~
}
}
}
}
}
}
And, in js code,,
if (error condition1) {
throw fail.checkedError('case 1 error', 'case1ActionError')
} else if (error condition2) {
throw fail.checkedError('case 2 error', 'case2ActionError')
}
For fail, refer to https://bixbydevelopers.com/dev/docs/reference/JavaScriptAPI/fail#failcheckederrormessage-errorid-errorobj

how to pass along structure property via similar method to Bixby onclick

In a Bixby result-view on the Detail mode I want to provide the user with the option to select from one or more Actions and pass along a hidden parameter "identifier" that corresponds to a database field name to include in the http request made by the Action.
layout {
match: AltBrainsData (this)
mode (Details)
content{
section {
content {
image {
//aspect-ratio (16:9)
url {
template ("#{value(this.icon_image)}")
}
}
}
}
section {
content {
title-area {
slot1 {
text("[#{value(this.name)}]")
{style(Title_M)}
}
}
}
}
section {
content {
paragraph { value ("#{value(this.description)}") style (Detail_L) }
}
}
section {
content {
cell-card {
slot2 {
content {
order (PrimarySecondary)
primary ("Show me the latest news headlines")
}
}
on-click {
intent {
goal: altbrains.persistencetest.GetNews
value: altbrains.persistencetest.AltBrainsData("#{value(this.identifier)}")
}
}
}
}
}
...
I get an error saying that the value must be a primitive.
How can I accomplish this? Basically, I want the result "Detail" card to be populated with one or more possible Actions and each action should pass along this identifier to the corresponding function in code/.
A bit difficult to include all the necessary bits and pieces in Stack Overflow. The money part of the GetNews function is:
function getNews(AltBrainsData) {
const url = properties.get("config", "baseUrl") + "content"
console.log("i got this far and the url is ", url);
const query = {
apikey: properties.get("secret", "apiKey"),
q: "{\"" + "identifier" + "\":\"" + AltBrainsData.identifier + "\"}"
}
Change to the following:
on-click {
intent {
goal: altbrains.persistencetest.GetNews
value: $expr(this)
}
}
You can read more about $expr() syntax in expression language

Click on something that's not a sprite

I'm tryng to handle a click event that does not clicked on a sprite.
My first aproach would be handling normal JS events:
class EditorListener {
constructor(editor) {
...
if(window) {
window.addEventListener('click', this.onWindowClick.bind(this));
}
}
onWindowClick(event) {
if(event.target && event.target.tagName == 'CANVAS') {
Events.fire(EventType.CLICK_NOWHERE);
}
}
}
...
The problem is that this is called when I click sprites.
The goal is to simply close a dialog when I click nowhere.
Tap anywhere and run the function:
game.input.onTap.add(onTap, this);
function onTap(pointer)
{
}
Tap on these objects and run the function onDown
// enable input for some objects
yourObject1.inputEnabled = true;
yourObject2.inputEnabled = true;
yourObject1.events.onInputDown.add(onDown, this);
yourObject2.events.onInputDown.add(onDown, this);
function onDown(object, pointer)
{
// on down function
}

Calling a view on click of the kendo context menu in MVC5

I am have implemented a kendo context menu and grid on my MVC 5 page. I need to navigate to another page on click of edit by passing the requestid to it. When I try to call the #{Html.RenderAction("NewRequest_Read", "Request");} it loads the view upfront along with view contains the context menu. Could somebody tell me how do I go about it
Context Menu
#(Html.Kendo().ContextMenu()
.Name("RequestMenu")
.Target("#GridRequest")
.Filter("tr")
.Orientation(ContextMenuOrientation.Vertical)
.Animation(animation =>
{
animation.Open(open =>
{
open.Fade(FadeDirection.In);
open.Duration(500);
});
})
.Items(items =>
{
items.Add()
.Text("Edit");
items.Add()
.Text("Cancel");
})
.Events(e =>
{
e.Select("onSelect");
})
)
Script
function onSelect(e) {
var grid = $("#GridTeam").data("kendoGrid");
switch ($(e.item).children(".k-link").text()) {
case "Edit":
#{Html.RenderAction("NewRequest_Read", "Request");}
break;
case "Cancel":
grid.removeRow(e.target);
break;
}
}
Controller method
public ActionResult NewRequest_Read(string id)
{
NewRequestViewModel newReqeustViewModel = new NewRequestViewModel();
return View("NewRequestView", newReqeustViewModel);
}
function onSelect(e) {
var grid = $("#GridTeam").data("kendoGrid");
switch ($(e.item).children(".k-link").text()) {
case "Edit":
window.location.href = '#Url.Action("NewRequest_Read", "Request", new { id = //add request id parameter here })';
break;
case "Cancel":
grid.removeRow(e.target);
break;
}
}

How to create and call the method(Using Thread C#) in for each loop?

I wanted to call my custom method in the Thread.
public void LoopOverAllLists(String _webAndSiteXml)
{
try
{
XmlNode _nodelist = SharePoint.ListsGetListCollection();
foreach (System.Xml.XmlNode _item in _nodelist.ChildNodes)
{
string title = _item.Attributes["Title"].Value;
//check for hidden list
if (_item.Attributes["Hidden"].Value.ToLower() == "false")
{
switch (_item.Attributes["ServerTemplate"].Value)
{
//Check whether list is document library
case SharePoint.LIST_ID_DOCUMENT_LIBRARY:
case SharePoint.LIST_ID_XML_FORMS:
case SharePoint.Publishing_ID_Pages:
{
//Get all documents info
try
{
GetAllDocumentsInfo(_item, _webAndSiteXml);
}
catch
{
}
break;
}
//Check whether list is having attachment
case SharePoint.LIST_ID_GENERIC:
case SharePoint.LIST_ID_ANNOUNCEMENTS:
case SharePoint.LIST_ID_CONTACTS:
case SharePoint.LIST_ID_TASKS:
case SharePoint.LIST_ID_EVENTS:
case SharePoint.LIST_ID_CUSTOM_GRID:
case SharePoint.LIST_ID_MEETING_SERIES:
case SharePoint.LIST_ID_MEETING_AGENDA:
case SharePoint.LIST_ID_MEETING_ATTENDEES:
case SharePoint.LIST_ID_MEETING_DECISIONS:
case SharePoint.LIST_ID_MEETING_OBJECTIVES:
case SharePoint.LIST_ID_MEETING_TTB:
case SharePoint.LIST_ID_MEETING_WS_PAGES:
case SharePoint.LIST_ID_PORTAL_SITE_LIST:
{
//Get all list items info having attachment
try
{
GetAllListItemsInfoOnlyAttachments(_item, _webAndSiteXml);
}
catch
{
}
break;
}
default:
GetAllListItemsInfoOnlyAttachments(_item, _webAndSiteXml);
break;
}
// Get All the List Forms
try
{
GetAllListForms(title, _webAndSiteXml);
}
catch
{
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
in above method three methods which is " GetAllDocumentsInfo , GetAllListItemsInfoOnlyAttachments and GetAllListForms " I wanted to call these function using thread in C#.
Thanks
Here is how I would approach the problem. Notice that I encapsulated the contents of the foreach loop into a separate method and then queued the execution of that method into the ThreadPool so that each iteration of the loop occurs in parallel. I also use a well established pattern to wait for all pending work items to complete. This code is compatible with .NET 3.5.
public void LoopOverAllLists(String _webAndSiteXml)
{
int pending = 1; // Used to track the number of pending work items.
var finished = new ManualResetEvent(false); // Used to wait for all work items to complete.
XmlNode nodes = SharePoint.ListsGetListCollection();
foreach (XmlNode item in nodes)
{
XmlNode capture = item; // This is required to capture the loop variable correctly.
Interlocked.Increment(ref pending); // There is another work item in progress.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
ProcessNode(capture);
}
finally
{
// Signal the event if this is the last work item to complete.
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
}
}, null);
}
// Signal the event if the for loop was last work item to complete.
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
// Wait for all work items to complete.
finished.WaitOne();
}
private void ProcessNode(XmlNode item)
{
// Put the contents of your loop here.
}
instead of calling
GetAllDocumentsInfo(_item, _webAndSiteXml);
use
Task.Factory.StartNew(() => GetAllDocumentsInfo(_item, _webAndSiteXml));
repeat this pattern for the other method calls as well

Resources