Is it possible, using Google Closure compiler, to define a class in two files? For example, if I auto-generate one class and want to keep another one for user-entered code:
In MyClass.AutoGenerated.js
goog.provide("MyClass");
MyClass = function() {
}
MyClass.prototype.SomeMember = 15;
And then in MyClass.js, continue declaring members and functions:
MyClass.prototype.AnotherMember = 15;
MyClass.prototype.SomeAwesomeFunction = function() {};
As long as the files are ordered correctly this isn't a problem. The ordering can be tricky however if it is possible to instantiate the class before the prototypes are filled out.
The only way I found to come close to this, without relying on build order is this:
In MyClass.js
goog.provide("MyClass");
MyClass = function() {
}
MyClass.prototype.SomeMember = 15;
And then in MyClass.Partial.js, continue declaring members and functions and provide a namespace with .Partial (for example):
goog.require("MyClass");
goog.provide("MyClass.Partial");
MyClass.prototype.AnotherMember = 15;
MyClass.prototype.SomeAwesomeFunction = function() {};
Then the calling code must call:
goog.require("MyClass");
goog.require("MyClass.Partial");
in order to include both files in the right order. The MyClass.Partial class does not need to exist in any way; it is just an identifier used by the goog.require and goog.provide methods.
Related
I'm trying to convert the JavaScript code
if (window.ifEdit.editIsDirty()) { }
into Typescript. I got as far as the following
var iframe = document.getElementById('ifEdit');
var iWindow = <HTMLIFrameElement>(iframe).contentWindow;
var _editIsDirty = iWindow.editIsDirty();
I get the red squiggles under 'contentWindow' and 'editIsDirty' saying the method/property does not exist on the type. The .ts doesn't compile to a .js file.
I have searched, but did not manage to find a solution.
For the contentWindow part, the problem with your code is that the casting is done wrong, should be:
var iWindow = (<HTMLIFrameElement> iframe).contentWindow;
As for the editIsDirty, it's not a standard property of Window.
If it's something which is added in the environment in which you are running your javascript then you need to declare it like so:
interface IfEdit {
editIsDirty(): boolean;
}
interface Window {
ifEdit: IfEdit;
}
var iframe = document.getElementById("ifEdit");
var iWindow = (<HTMLIFrameElement> iframe).contentWindow;
var _editIsDirty = iWindow.ifEdit.editIsDirty();
Use the code in Playground.
Casting will be through as. this assures .contentWindow is accessible.
const iframe = document.getElementById('embed-player') as HTMLIFrameElement;
if (!iframe) {
// Handle case where iframe not found
return;
}
const contentWindow = iframe.contentWindow;
// Note: You will likely need more null handling for contentWindow's properties
console.log(contentWindow?.document);
From time to time I have the requirement to bind a control property to based on data out of model A to another model B.
For example the syntax could look like this (but will not work):
text : "{B>/rootB/{A>someValue}/propertyB}"
I normally solve this problem by "misusing" an unused control property in combination with the format function. It would look like this:
tooltip : {
path : "A>someValue",
formatter : function(oValue) {
// do some checks on oValue
var path = "B>/rootB/"+oValue+"/propertyB";
this.bindProperty("text", path);
return undefined; // because tooltip is not used
}
The benefit of this, each time "A>someValue" will be changed the binding of "text" will be updated automatically.
It is also possible to do this in template code (like items aggregations).
But you may smell the code ;)
Any suggestions to make it cleaner?
As far as I know, there is no such possibility in UI5 (yet). I always use a formatter function as you already mentioned. I say not YET, because developers seem to be aware of this feature request: see on GitHub
BUT, you dont need to missuse a random control property! Just use the formatter to read the needed values from any model you have access to:
text : {
path : "A>someValue1",
formatter : function(oValue) {
// read model B to get someValue2 (based on someValue1)
var path = "B>/rootB/"+oValue+"/propertyB";
var B = getModel("someModel");
var someValue2 = B.getProperty(path);
return someValue2
}
OK I am looping through the properties in an object like so:
private var _propsList:Object = {'Type':'product_type'
,'Kind':'product_type_sub'
,'Stone':'primary_stone'
,'Stone Color':'primary_stone_sub'
,'Metal':'metal_type'
,'Brand':'product_brand'};
for(key in _propsList)
{
val = _propsList[key];
trace(key +" = "+ val);
}
I am expecting the first trace to be Type = property_type since that is the first one defined in the array, however it is coming up random everytime. I guess this is because my keys are strings and not integers, however is there a way to specify the order it loops through them?
Thanks!!
You can't rely on for (v in someObject) ... to return things in a predictable order, no.
Depending on your specific situation, you could just use an array to hold the keys, and just iterate through that:
private var keys:Array = ["Type", "Kind", "Stone", "Stone Color", "Metal", "Brand"];
private function iterate():void
{
for each (var k:String in keys)
{
trace(_propsList[k]);
}
}
Maybe a bit obvious or non-elegant, but it'd get the job done. :)
you could hack it by classing-out your "_propsList" object creating an array inside of the newly created PropsList class that references the properties in order. At that point, you could run a FOR loop on the array and get your properties in order.
OR, you could have a function inside that new class that would return an Array of those properties. like this:
public function getProps():Array {
return [myPropertyOne, myPropertyTwo, myPropertyThree];
}
In general, I think this is a case where you shouldn't depend on a particular behavior from the framework/language you are using. This type of behavior is generally poorly documented and can change from version to version.
If you really need a specific retrieval order, I would create a wrapper class as jevinkones suggested above. Maybe there's even a utility class in the framework somewhere to accomplish this (Dictionary, etc.?)
HTH,
Karthik
I found this link that gives some background:
Subtle Change in for..in Loops for ActionScript 3
This question is actually a dup of this one.
How about using an array representation like this:
var _propsList:Array = [
['Type', 'product_type'],
['Kind', 'product_type_sub'],
['Stone', 'primary_stone'],
['Stone Color', 'primary_stone_sub'],
['Metal', 'metal_type'],
['Brand', 'product_brand']
];
for(var i in _propsList) {
var elem = _propsList[i];
var key = elem[0];
var val = elem[1]
}
I am trying to create an API utility using Adobe AIR where given a component name it should list all it methods, variables, and other properties of that component.
But I could not find an API to list all the UIComponents of Flex/Flash.
is there an API to lookup all the UIComponent or if there is no such API, can anyone tell me how do i lookup the components?
Note: I have tried using flash.utils.describeType() but it is not able to suit my requirement as the input to the method is passed dynamically using TextInput.
~Jegan
It sounds like you are asking two things:
How to list all of the properties/methods of a UIComponent.
How to list all of the UIComponents in the Flex SDK.
The first one can be done with describeType(). Given that the method is passed dynamically using TextInput, you need to just include all of the UIComponents into the SWF. You can do that with the following include statement for each component in the SDK (this example is with the Button):
include mx.controls.Button; Button;.
Then you can do something like this:
var className:String = myTextArea.text; // mx.controls::Button or mx.controls.Button
var clazz:Class = flash.utils.getDefinitionByName(className);
var methods:Array = getMethods(clazz);
var properties:Array = getProperties(clazz); // write a similar method for accessors and variables
/**
* Returns a list of methods for the class.
* Pass in the superclass depth for how many classes
* you want this to return (class tree). If it's -1, it will return the whole method list
*/
public static function getMethods(target:Object, superclassDepth:int = -1, keepGeneratedMethods:Boolean = false):Array
{
var description:XML = DescribeTypeCache.describeType(target).typeDescription;
var hierarchy:Array = getHierarchy(target);
var methodList:XMLList = description..method;
methodList += description.factory..method; // factory is required if target is Class
var methodName:String
var methods:Array = [];
var declaredBy:String;
var methodXML:XML;
var i:int = 0;
var n:int = methodList.length();
for (i; i < n; i++)
{
methodXML = methodList[i];
declaredBy = methodXML.#declaredBy;
methodName = methodXML.#name;
// we break because the xml list is orded hierarchically by class!
if (superclassDepth != -1 && hierarchy.indexOf(declaredBy) >= superclassDepth)
break;
// ignore methods that start with underscore:
if (methodName.charAt(0) == "_" && !keepGeneratedMethods)
continue;
methods.push(methodName);
}
// sort the method list, so there's some kind of order to the report:
methods.sort(Array.CASEINSENSITIVE);
return methods;
}
The second one, listing the UIComponents in the SDK, is a bit more complex because there's no stable list of components in the SDK (depends on version, etc.). What you can do, however, is get a list of every class included in the swf. You do this by generating a Link Report (which is used for helping out modules), which is just a compiler argument:
-link-report=my_report.xml
Then you can figure out a way to find the unique xml nodes in that file, and which ones extend UIComponent. I use ruby and the nokogiri xml parser for ruby to do that. There is also a neat AIR app to visualize the Link Report.
If you're doing the first case, that method should get you started on listing all properties/methods of a UIComponent. If you're doing the second, that will give you a list of all UIComponents included in the swf.
Let me know if that helps,
Lance
Do you need to do anything with the data, other than displaying it? If not, it might be easiest to pull up the right page from Adobe's online API docs.
I've created an ASP.Net user control that will get placed more than once inside of web page. In this control I've defined a javascript object such as:
function MyObject( options )
{
this.x = options.x;
}
MyObject.prototype.someFunction=function someFunctionF()
{
return this.x + 1;
}
In the code behind I've created MyObject in a startup script --
var opts = { x: 99 };
var myObject = new MyObject( opts );
When a certain button in the control is pressed it will call myObject.someFunction(). Now lets say the value of x will be 99 for one control but 98 for another control. The problem here is that the var myObject will be repeated and only the last instance will matter. Surely there's a way to make the var myObject unique using some concept I've haven't run across yet. Ideas?
Thanks,
Craig
Your Javascript like this:-
function MyObject(options) { this.x = options.x; }
MyObject.prototype.someFunction = function() { return this.x + 1; }
MyObject.create(id, options) {
if (!this._instances) this._instances = {};
return this._instances[id] = new MyObject(options);
}
MyObject.getInstance(id) { return this._instances[id]; }
Your startup javascript like this:-
MyObject.create(ClientID, {x: 99});
Other code that needs to use an instance (say in the client-side onclick event)
String.Format("onclick=\"MyObject.getInstance('{0}').someFunction()\", ClientID);
Note the low impact on the clients global namespace, only the MyObject identifier is added to the global namespace, regardless of how many instances of your control are added to the page.
If it is just one value, why not have the function take it as a parameter and build your onclick handler so that it puts the correct value in for each control. If it is more complex than that, then consider making options an array and, for each control, insert the correct options into the spot in the array that corresponds to each particular control. Then pass the proper index into the array into the function.
I do this by using ScriptManager.RegisterClientScriptBlock to register a string as a JavaScript block on the client side. I can then modify my script string using {0}, {1}..,{n} place holders to inject necessary ids. It depends on the structure of your code as to if this is the most elegant fashion, but it works in a pinch. You could then inject variable names using references to Me.ClientID.
You can make the value of "x" static and access it anywhere in the code, such as:
function MyObject( options ) { MyObject.x = options.x; }
MyObject.x = 99; // static
MyObject.prototype.someFunction = function () { return MyObject.x + 1; }
This way you can access MyObject.x anywhere in your code, even without re-instanciating MyObject.
Excellent solution Anthony. The other solutions offered were as good and I did consider them but I was looking for something a little more elegant like this solution.
Thanks!