Insert an HTML Object element in Webbrowser's document - dom

In a Webbrowser control there is a webpage (the document). I know how to insert any HTML element into the body.
The problem is, how can I insert an <object> along with its <param>? I must keep the existing document, so I wouldn't use Webbrowser1.Document.Write().
Dim player As HtmlElement = Webbrowser1.Document.CreateElement("object")
player.SetAttribute("width", "640")
player.SetAttribute("height", "480")
Dim param As HtmlElement = Webbrowser1.Document.CreateElement("param")
param.SetAttribute("name", "movie")
param.SetAttribute("value", "http://foo.bar.com/player.swf")
player.AppendChild(param) '<== throws an exception
Webbrowser1.Document.Body.AppendChild(player)
Thrown exception: "Value is not among the set of valid lookup values" (I guess, because I'm using french version of VS2010, which gives me "La valeur n'est pas comprise dans la plage attendue.")
WORKAROUND
Finally I could append an <object> element using Navigate() method with Javascript URI. It's a bit ugly, but it works.

Well, I realized my answer was exactly what you were doing. Oops.
The MSDN documentation shows a lot of methods for the object Object, but it doesn't specify appendChild. The appendChild method documentation specifies that it is a part of a bunch of objects, but not object. applyElement looks like it might work.
Also, the insertAdjacentHTML method and innerHTML parameter are valid on object Objects, and may be helpful.
Hrm - I'm not familiar with .net, but I have done something similar in Javascript. Chrome seems to produce the correct document setup with the following:
<script>
var newObj=document.createElement( "object" );
newObj.setAttribute( 'width', '640' );
newObj.setAttribute( 'height', '480' );
newObj.setAttribute( 'data', 'http://ozdoctorwebsite.com/test-4938161.gif' );
var newParam=document.createElement( "param" );
newParam.setAttribute( 'name', 'test' );
newObj.appendChild( newParam );
document.body.appendChild( newObj );
</script>
Basically - append your param element to the player and append the player to the document.body.

Related

TYPO3 8.7.13 - getArguments() return no response

\Templates\Snippets\Search.html
<f:form id="snippetSearchForm"
action="search"
controller="Snippets"
extensionName="snippet_highlight_syntax"
pluginName="feshs"
name="searchSnippets"
method="POST"
pageType="5513">
<f:form.textfield class="form-control" property="searchWords"/>
<f:form.submit id="searchBtn" value="Search"/>
</f:form>
SnippetsController.php
public function searchAction()
{
$arguments = $this->request->getArguments();
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($arguments);
}
ajax.js
$("#snippetSearchForm").submit(function (event) {
event.preventDefault();
var form = $(this);
var action = form.attr("action"),
method = form.attr("method"),
data = form.serialize();
$.ajax({
url: action,
type: method,
data: data,
cache: false
}).done(function (data) {
console.log(data);
}).fail(function () {
( "div.tx-feshs" ).replaceWith("errorMessage");
}).always(function () {
});
});
Request URL
index.php?id=148&type=5513&tx_snippet_highlight_syntax_feshs[action]=search&tx_snippet_highlight_syntax_feshs[controller]=Snippets&cHash=4662b6b5a3fa0dc4e590e8d5c90fa
I can't solve this problem with getArguments(). The response and console.log are (empty). Seems like I'm missing something but I can't pinpoint where :/
You have a few common errors in your code and most of them has already been mentioned here, but please allow me to sum up.
Extension key/name
First, a lot of people confuses extension name with extension key. The directory name of your extension is your extension key, in this case snippet_highlight_syntax. The extension key is used all over TYPO3 as the unique identifier of your extension. With Extbase a new convention did come along called extension name to satisfy PSR2 coding convention and is primarily used in Extbase context. The extension name is a upper camel case edition of your extension key.
ExtbaseFluidBook: CodingGuidelines - It´s a bid old but still valid
The name of the extension in UpperCamelCase. For example, if the extension-key is blog_example, then this part of the classname is BlogExample.
Extension key: snippet_highlight_syntax
Extension name: SnippetHighlightSyntax
Be aware of what the TYPO3/Extbase framework asks for, key or name - it will help you a lot.
Plugin name
You have also declared a plugin named feshs. According to the DocBlock documentation of both \TYPO3\CMS\Extbase\Utility\ExtensionUtility::(configure|register)Plugin() methods it should, as with the extension name, be in upper camel case format like Feshs. It´s not well documented and I do not think it has any negative impacted on your application jet but now you knows and has a change to future proof your application by correcting it.
/**
* ...
*
* #param string $extensionName The extension name (in UpperCamelCase) or the extension key (in lower_underscore)
* #param string $pluginName must be a unique id for your plugin in UpperCamelCase (the string length of the extension key added to the length of the plugin name should be less than 32!)
* #param array $controllerActions is an array of allowed combinations of controller and action stored in an array (controller name as key and a comma separated list of action names as value, the first controller and its first action is chosen as default)
* #param array $nonCacheableControllerActions is an optional array of controller name and action names which should not be cached (array as defined in $controllerActions)
* #param string $pluginType either \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_PLUGIN (default) or \TYPO3\CMS\Extbase\Utility\ExtensionUtility::PLUGIN_TYPE_CONTENT_ELEMENT
* #throws \InvalidArgumentException
*/
public static function configurePlugin($extensionName, $pluginName, array $controllerActions, array $nonCacheableControllerActions = [], $pluginType = self::PLUGIN_TYPE_PLUGIN)
Plugin signature
Together with your extension name it will form a plugin signature called snippethighlightsyntax_feshs. This signature is the valued stored in the tt_content database table as list_type or ctype depending of the plugin configuration.
The plugin signature is further used in TypoScript and GET/POST arguments prefixed with tx_. In your case tx_snippethighlightsyntax_feshs.
Fluid & Extbase forms
In your form snippet you have declared a element <f:form:textfield /> with the property tag. The property tag is only used together with the object and objectName tags on the <f:form /> element and is used to bind values to this objects properties (autofill, validation result etc.).
See \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper::initializeArguments.
Name of Object Property. If used in conjunction with <f:form object="...">, "name" and "value" properties will be ignored.
In your case you should properly just use name in stead of property.
Your updated form should look something like below:
<f:form id="snippetSearchForm"
action="search"
controller="Snippets"
extensionName="SnippetHighlightSyntax"
pluginName="Feshs"
method="POST"
pageType="5513">
<f:form.textfield class="form-control" name="searchWords"/>
<f:form.submit id="searchBtn" value="Search"/>
</f:form>
Controller arguments
You should declare your arguments as controller arguments.
/**
* #param string $searchWords
*/
public function searchAction(string $searchWords = null)
{
if (is_string($searchWords)) {
// TODO: Do something here...
}
}
Note how I have given the argument a default value. This should suppress the error Required argument "searchWords" is not set for... you are getting.
This was a long write up. Hopes it helps your or some others.
Happy coding
$this->request->getArguments() will only return field value arguments that are prefixed with the extensions / plugins identifier like tx_anything_pi1[anything]
Please checkout if the "name"-tag of the fields is correct. Maybe those tags are wrong because you are reffering to a "property" of an object in your textfield but there is no object bound to your f:form tag.
Since the response should at least return the HTML of an empty debug, maybe something is wrong with your action. Can you call it in the browser?
First of all use name attribute instead of property in <f:form.textfield> tag.
Then you need to register argument as follows
public function searchAction(string $searchWords)
Furthermore PHP docblock must contain the parameter as #param string $searchWords. After clearing all caches in the Install Tool you should get your arguments.
Assumed your extension-key (=foldername) is "snippet_highlight_syntax" the parameter for URLs is usually like this:
tx_snippethighlightsyntax_feshs
That means all underscores of the extension-key are removed.
Probably it's possible to make it different, but that's not standard.
Therefore $this->request->getArguments() never returns anything.
You've to adjust the parameters in the url like this:
index.php?id=148&type=5513&tx_snippethighlightsyntax_feshs[action]=search&tx_snippethighlightsyntax_feshs[controller]=Snippets&cHash=4662b6b5a3fa0dc4e590e8d5c90fa
In the TypoScript-Object-Browser you should find your plugin with that name:
plugin.tx_snippethighlightsyntax_feshs
After many tries, I've sent the extension to test on another computer and it's working.
I've cleared all the caches, disabled/enabled, and so on. Seems like my environment is at fault.
Thanks to all of you for the help !

How to debug in TYPO3 if <f:debug> returns strings instead of object?

In a custom TYPO3 8.7.12 extbase extension I am unable to f:debug items in templates.
We are in the listAction controller and simply do:
$institutions = $this->institutionRepository->findAll();
$this->view->assignMultiple([
'institutions' => $institutions,
// ... pagination limit ...
]
);
And in the template:
<f:debug>
{institutions}
</f:debug>
This returns
sometimes the string 'Array' in the fluid debugger (can't reproduce now)
When the code is on 3 lines: #1273753083: Cannot cast object of type "TYPO3\CMS\Extbase\Persistence\Generic\QueryResult" to string.
Or also #1273753083: Cannot cast object of type "TYPO3\CMS\Extbase\Persistence\Generic\LazyObjectStorage" to string.
When the code is on 1 line: #1234386924: Cannot create empty instance of the class "TYPO3\CMS\Extbase\Persistence\ObjectStorage" because it does not implement the TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface.
If I loop through {institutions} with f:for and then f:debug:
<f:for each="{institutions}" as="institution" iteration="i">
<f:debug>
{institution}
</f:debug>
</f:for>
I get the first property of the object, e.g. the name.
EDIT: this is due to a __toString() magic method in the model. If I remove it, instead I get the namespace and uid STUBR\Extension\Domain\Model\Institution:55 – this looks again as if the object isn't rendered.
Wait... php.net says The __toString() method allows a class to decide how it will react when it is treated like a string. So could something be treating (typecasting?) the object as a string?
Working with the properties is normal, the issue just occurs when trying to print the whole object.
Where should I look? Lazy loading? There are some lazy loading properties, but not that many. Or maybe something is missing from the class? Or is there a workaround.
PS:
Unable to print_r or var_dump the query result, I get a memory limit error.
I saw https://wiki.typo3.org/Exception/CMS/1234386924 but initStorageObjects() is already called in the constructor
To answer the question;
<f:debug>{institutions}</f:debug>
will be parsed as an object, but any whitespace inside will make it parse as a string so.
The following methods do the same job as <f:debug> and work similarly in my case:
\TYPO3\CMS\Core\Utility\DebugUtility::debug(
$var = $variable,
$header = 'Institutions',
$group = ''
);
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump(
$variable,
$title = 'Institutions',
$maxDepth = 8,
$plainText = FALSE,
$ansiColors = TRUE,
$return = FALSE,
$blacklistedClassNames = NULL,
$blacklistedPropertyNames = NULL
);
execute in list or show action in controller.
It's less convenient than with f:debug (because you have to do the work in two different places, e.g. when you're in a loop in the template, you have to go to the controller and build that loop again), but it's a helpful workaround.
EDIT: I found it's sufficient to do
<f:debug>{var}</f:debug>
on one line

Can't get changed property from attachPropertyChange

I would like to know which property in the JSON model has changed when modified by a view.
For a test I took OpenUI5 walkthrough example and added the following lines in the application controller
oProductModel.attachPropertyChange( function(oEvent){
console.log("event: ", oEvent);
}, this);
When I change a property in the text input, the function in the attachPropertyChange is called but oEvent object is empty as I print it in console.
I know I could connect to text input change event, but I would like to use attachPropertyChange in case there would be multiple views of the same model.
As far as I understood, you'd like to avoid using the change event of the Input control because there is no information about which property in the model has changed. However, you can still get all the relevant information within the change handler via:
oControl.getBinding(/*controlPropertyName*/).getPath() to get the name of the bound property, or
oControl.getBindingContext(/*modelName*/).getPath(/*suffix*/) to get the path of the bound context. The getPath here awaits an optional suffix that will be appended to the context path with a "/" in between.
Combine those two APIs to get an absolute path in case the property binding was relative. E.g.:
onInputChange: function (event) {
const inputControl = event.getSource();
const property = inputControl.getBinding("value").getPath(); // "myProperty"
const absolutePath = inputControl.getBindingContext(/*modelName*/).getPath(property) // "/0/myProperty"
// ...
},
You can use change event for all input field in UI, and write event handling method in the controller. You will get the property as well as value in the oEvent of the event handling method easily. I hope you understood.

How to define a `separator` tag in play-1.x without modifing play's source code

I want to define a tag separator tag, which inside a list tag, can add separator between items.
The sample code is:
List<String> users = new ArrayList<String>();
users.add("Jeff");
users.add("Mike");
#{list users, as: 'user'}
#{separator ' + ' /}
<span>${user}</span>
#{/list}
If I don't use the separator tag, the code will be:
#{list users, as: 'user'}
${user_isFirst ? '' : ' + '}
<span>${user}</span>
#{/list}
The generated html code will be:
<span>Jeff</span> + <span>Mike</span>
I tried defined a fastTag:
public static void _separator(Map<?, ?> args, Closure body, PrintWriter out, GroovyTemplate.ExecutableTemplate template, int fromLine) {
Object value = args.get("arg");
// TODO how to get the value of `as` defined in parent `list` tag?
out.print(value);
}
But the problem is I can't get the value of as defined in list tag (which is user) in this case.
You can create a custom list tag in groovy like this
#{list items:_arg, as:'tmp'}
%{
attrs = [:]
attrs.put(_as, tmp)
}%
#{ifnot tmp_isFirst}${_sep}#{/ifnot}
#{doBody vars:attrs /}
#{/list}
and use it like this
#{myList users, as:'user', sep:','}
${user}
#{/myList}
You should trace into your FastTag implementation. I think you'll see all the variables in scope inside the args map. This is from memory - so, sorry if not.
That said, I think it might be simpler if you copy the Java code for #{list} and add a new parameter, like
#{list users, as: 'user', separator: '+' }
and handle the logic in there. It seems a bit cleaner too from a design point of view - if it is a separator, how come you can put it anywhere you like in the code (and why not put it in twice!).
A final option is to look at Groovy or Java collection operators. http://groovy.codehaus.org/groovy-jdk/java/util/Collection.html

How to access element and elementId from within didInsertElement

Using Ember.CollectionView I want to access and manipulate the DOM element which is being inserted by each child view. The issue I have is that I don’t know how to get a reference to the element from within didInsertElement. Here is the jsFiddle -- the summery of coffeescript is below:
window.App = Ember.Application.create()
window.App.initialize()
App.Item = Em.View.extend
didInsertElement: () ->
console.log ">>> element is: ", this.element
App.items = Em.ArrayController.create()
App.items.set('content',[
Em.Object.create({title:"AN", id:"item-one"}),
Em.Object.create({title:"Epic", id:"item-two"}),
Em.Object.create({title:"View", id:"item-three"})
])
App.EpicView = Ember.CollectionView.extend
classNames: ['epic-view']
contentBinding: 'App.items'
itemViewClass: 'App.Item'
this.element is undefined. I have also tried calling element and that is undefined as well. According to the docs, there is an element property available inside the view, but I don’t know how to access it, and I am not sure if it is available from within didInsertElement or not.
How can I get the id of the DOM element that was just inserted into the view? Ideally, I would like not having to search for it in the DOM since the view should already be aware of what it is inserting into the DOM.
ps: I am using Ember 1.0pre
Use get('element') or get('elementId') to access properties in Ember