I want the list of all style properties/values applied to a UIComponent's selector via css but I can't seem to find a list of them anywhere.
For example, I have a BorderContainer and the CSS gives it
backgroundColor: #869ca7;
backgroundAlpha: .5;
and from an ActionScript function I would like to retrieve the list {backgroundColor:#869ca7, backgroundAlpha:.5}. But in an abstract way that works for all UIComponents (i.e. I can't just call getStyle("backgroundColor");
I've tried two ways and I feel very close but can't actually retrieve the list.
It feels like I should be able to get the list of properties from the UIComponents by using the styleDeclaration property on the UIComponent, but it doesn't seem to show the list of style properties it has.
It also seems like I should be able to get the values by calling "uiComponent.getStyle(_)" but that requires that I already know the property names.
Thank you for any insight you can help me with.
For reference, the CSSStyleDeclaration class:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/styles/CSSStyleDeclaration.html
So my initial research shows that there is no direct function call or list for retrieving an array of style properties.
I think the only way is to check the cascading arrays for the property name.
Code for getStyle for reference:
public function getStyle(styleProp:String):*
{
var o:*;
var v:*;
// First look in the overrides, in case setStyle()
// has been called on this CSSStyleDeclaration.
if (overrides)
{
// If the property exists in our overrides, but
// has 'undefined' as its value, it has been
// cleared from this stylesheet so return
// undefined.
if (styleProp in overrides &&
overrides[styleProp] === undefined)
return undefined;
v = overrides[styleProp];
if (v !== undefined) // must use !==
return v;
}
// Next look in the style object that this CSSStyleDeclaration's
// factory function produces; it contains styles that
// were specified in an instance tag of an MXML component
// (if this CSSStyleDeclaration is attached to a UIComponent).
if (factory != null)
{
factory.prototype = {};
o = new factory();
v = o[styleProp];
if (v !== undefined) // must use !==
return v;
}
// Next look in the style object that this CSSStyleDeclaration's
// defaultFactory function produces; it contains styles that
// were specified on the root tag of an MXML component.
if (defaultFactory != null)
{
defaultFactory.prototype = {};
o = new defaultFactory();
v = o[styleProp];
if (v !== undefined) // must use !==
return v;
}
// Return undefined if the style isn't specified
// in any of these three places.
return undefined;
}
Related
I try to understand the whole GObject stuff and tried a class with three properties,
where two properties have getter and setters: 'example-property-a', 'example-property-b'
Each emit the notify signal different.
'example-property-a' emits, whenever the property changed its value.
'example-property-b' emits, whenever the property is set.
for 'example-property-c' i dont use a getter or setter. i use the GObject instance methods.
instance.set_property ([ property name STR] , [value STR] );
instance.get_property ([ property name STR] , [value GValue] );
https://docs.gtk.org/gobject/method.Object.get_property.html says a GValue is needed as parameter.
But i get an error :g_object_get_property: can't retrieve property 'example-property-c' of type 'gchararray' as value of type 'GValue'
hm ... how to get a gchararray? - the complete class try
const GOBJECT = imports.gi.GObject;
//-- prefix: 'go_' ... instances of classes and classes themselves, which inherit from GOBJECT.Object have this prefix
const go_Example = GOBJECT.registerClass(
{
GTypeName: 'SubclassExample',
Properties: {
'example-property-a': GOBJECT.ParamSpec.double('example-property-a', '', '', GOBJECT.ParamFlags.READWRITE, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, 0),
'example-property-b': GOBJECT.ParamSpec.boolean('example-property-b', '', '', GOBJECT.ParamFlags.READWRITE, true),
'example-property-c': GOBJECT.ParamSpec.string('example-property-c', '', '', GOBJECT.ParamFlags.READWRITE, null) },
Signals: {
'example-signal': { flags: GOBJECT.SignalFlags.RUN_LAST, param_types: [GOBJECT.TYPE_STRING], accumulator: GOBJECT.AccumulatorType.TRUE_HANDLED, return_type: GOBJECT.TYPE_BOOLEAN } }
},
class go_Example extends GOBJECT.Object
{
_init (properties) //-- _init ... name of the constructor in GObject classes
{
//-- set standard defined above in properties
this._example_property_a=0;
this._example_property_b=true;
this.example_property_c=null;
super._init(properties);
}
//-- 'example_property_a' get, set link on '_example_property_a' -> notify, only if value has changed
get example_property_a () { return this._example_property_a; }
set example_property_a (value) { if (this._example_property_a === value) return; this._example_property_a = value; this.notify ("example-property-a"); }
//-- 'example_property_b' get, set link on '_example_property_b'; notify, if value is set
get example_property_b () { return this._example_property_b; }
set example_property_b (value) { this._example_property_b = value; this.notify ("example-property-b"); }
//-- no get, set of example_propertyC -> notify over GOBJECT.Object.set_property function
});
let go_Obj=new go_Example ({example_property_a:12.5585, example_property_b:true, example_property_c: "hello world"});
let GValue_RV=new GOBJECT.Value; //-- return Value
GValue_RV.init(GOBJECT.TYPE_STRING)
go_Obj.connect ("notify::example-property-c", function (instance, ParamSpec) {log (instance+" - "+ParamSpec.get_name ());});
go_Obj.set_property ("example-property-c","hello");
go_Obj.get_property ("example-property-c",GValue_RV);
log (GValue_RV.get_string());
here i construct a GValue for returning the value of get_property
let GValue_RV=new GOBJECT.Value; //-- return Value
GValue_RV.init(GOBJECT.TYPE_STRING)
whats wrong?
other questions- if i construct a GObject.Object instance, can i install a ParamSpec property on a special object instance, because i only found install properties on a complete class?
Usually you won't want to use GObject.get_property() or GObject.set_property() in GJS. Instead you should just use the native accessors and allow GJS to do the heavy lifting for you:
const myObject = new MyObject();
// Getting a property
let stringValue = myObject.example_property_c;
// Setting a property
myObject.example_property_c = 'string value';
There is an introduction to GObject and a more thorough guide on subclassing on the gjs.guide website:
The Basics of GObject: Properties
GObject Subclassing: Properties
if i construct a GObject.Object instance, can i install a ParamSpec property on a special object instance, because i only found install properties on a complete class?
No, you can only install GObject properties on a class when it is defined, not on an instance. You can, however, add native JavaScript properties with Object.defineProperty().
I'm not sure of the best approach for handling scoping of "this" in TypeScript.
Here's an example of a common pattern in the code I am converting over to TypeScript:
class DemonstrateScopingProblems {
private status = "blah";
public run() {
alert(this.status);
}
}
var thisTest = new DemonstrateScopingProblems();
// works as expected, displays "blah":
thisTest.run();
// doesn't work; this is scoped to be the document so this.status is undefined:
$(document).ready(thisTest.run);
Now, I could change the call to...
$(document).ready(thisTest.run.bind(thisTest));
...which does work. But it's kinda horrible. It means that code can all compile and work fine in some circumstances, but if we forget to bind the scope it will break.
I would like a way to do it within the class, so that when using the class we don't need to worry about what "this" is scoped to.
Any suggestions?
Update
Another approach that works is using the fat arrow:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
Is that a valid approach?
You have a few options here, each with its own trade-offs. Unfortunately there is no obvious best solution and it will really depend on the application.
Automatic Class Binding
As shown in your question:
class DemonstrateScopingProblems {
private status = "blah";
public run = () => {
alert(this.status);
}
}
Good/bad: This creates an additional closure per method per instance of your class. If this method is usually only used in regular method calls, this is overkill. However, if it's used a lot in callback positions, it's more efficient for the class instance to capture the this context instead of each call site creating a new closure upon invoke.
Good: Impossible for external callers to forget to handle this context
Good: Typesafe in TypeScript
Good: No extra work if the function has parameters
Bad: Derived classes can't call base class methods written this way using super.
Bad: The exact semantics of which methods are "pre-bound" and which aren't create an additional non-typesafe contract between your class and its consumers.
Function.bind
Also as shown:
$(document).ready(thisTest.run.bind(thisTest));
Good/bad: Opposite memory/performance trade-off compared to the first method
Good: No extra work if the function has parameters
Bad: In TypeScript, this currently has no type safety
Bad: Only available in ECMAScript 5, if that matters to you
Bad: You have to type the instance name twice
Fat arrow
In TypeScript (shown here with some dummy parameters for explanatory reasons):
$(document).ready((n, m) => thisTest.run(n, m));
Good/bad: Opposite memory/performance trade-off compared to the first method
Good: In TypeScript, this has 100% type safety
Good: Works in ECMAScript 3
Good: You only have to type the instance name once
Bad: You'll have to type the parameters twice
Bad: Doesn't work with variadic parameters
Another solution that requires some initial setup but pays off with its invincibly light, literally one-word syntax is using Method Decorators to JIT-bind methods through getters.
I've created a repo on GitHub to showcase an implementation of this idea (it's a bit lengthy to fit into an answer with its 40 lines of code, including comments), that you would use as simply as:
class DemonstrateScopingProblems {
private status = "blah";
#bound public run() {
alert(this.status);
}
}
I haven't seen this mentioned anywhere yet, but it works flawlessly. Also, there is no notable downside to this approach: the implementation of this decorator -- including some type-checking for runtime type-safety -- is trivial and straightforward, and comes with essentially zero overhead after the initial method call.
The essential part is defining the following getter on the class prototype, which is executed immediately before the first call:
get: function () {
// Create bound override on object instance. This will hide the original method on the prototype, and instead yield a bound version from the
// instance itself. The original method will no longer be accessible. Inside a getter, 'this' will refer to the instance.
var instance = this;
Object.defineProperty(instance, propKey.toString(), {
value: function () {
// This is effectively a lightweight bind() that skips many (here unnecessary) checks found in native implementations.
return originalMethod.apply(instance, arguments);
}
});
// The first invocation (per instance) will return the bound method from here. Subsequent calls will never reach this point, due to the way
// JavaScript runtimes look up properties on objects; the bound method, defined on the instance, will effectively hide it.
return instance[propKey];
}
Full source
The idea can be also taken one step further, by doing this in a class decorator instead, iterating over methods and defining the above property descriptor for each of them in one pass.
Necromancing.
There's an obvious simple solution that doesn't require arrow-functions (arrow-functions are 30% slower), or JIT-methods through getters.
That solution is to bind the this-context in the constructor.
class DemonstrateScopingProblems
{
constructor()
{
this.run = this.run.bind(this);
}
private status = "blah";
public run() {
alert(this.status);
}
}
You can write an autobind method to automatically bind all functions in the constructor of the class:
class DemonstrateScopingProblems
{
constructor()
{
this.autoBind(this);
}
[...]
}
export function autoBind(self)
{
for (const key of Object.getOwnPropertyNames(self.constructor.prototype))
{
const val = self[key];
if (key !== 'constructor' && typeof val === 'function')
{
// console.log(key);
self[key] = val.bind(self);
} // End if (key !== 'constructor' && typeof val === 'function')
} // Next key
return self;
} // End Function autoBind
Note that if you don't put the autobind-function into the same class as a member function, it's just autoBind(this); and not this.autoBind(this);
And also, the above autoBind function is dumbed down, to show the principle.
If you want this to work reliably, you need to test if the function is a getter/setter of a property as well, because otherwise - boom - if your class contains properties, that is.
Like this:
export function autoBind(self)
{
for (const key of Object.getOwnPropertyNames(self.constructor.prototype))
{
if (key !== 'constructor')
{
// console.log(key);
let desc = Object.getOwnPropertyDescriptor(self.constructor.prototype, key);
if (desc != null)
{
if (!desc.configurable) {
console.log("AUTOBIND-WARNING: Property \"" + key + "\" not configurable ! (" + self.constructor.name + ")");
continue;
}
let g = desc.get != null;
let s = desc.set != null;
if (g || s)
{
var newGetter = null;
var newSetter = null;
if (g)
newGetter = desc.get.bind(self);
if (s)
newSetter = desc.set.bind(self);
if (newGetter != null && newSetter == null) {
Object.defineProperty(self, key, {
get: newGetter,
enumerable: desc.enumerable,
configurable: desc.configurable
});
}
else if (newSetter != null && newGetter == null) {
Object.defineProperty(self, key, {
set: newSetter,
enumerable: desc.enumerable,
configurable: desc.configurable
});
}
else {
Object.defineProperty(self, key, {
get: newGetter,
set: newSetter,
enumerable: desc.enumerable,
configurable: desc.configurable
});
}
continue; // if it's a property, it can't be a function
} // End if (g || s)
} // End if (desc != null)
if (typeof (self[key]) === 'function')
{
let val = self[key];
self[key] = val.bind(self);
} // End if (typeof (self[key]) === 'function')
} // End if (key !== 'constructor')
} // Next key
return self;
} // End Function autoBind
In your code, have you tried just changing the last line as follows?
$(document).ready(() => thisTest.run());
I'm trying to use Ember to dynamically create child views in a ContainerView.
The problem is those child views need data bindings to a value from an attribute given to the container view.
Here is a bit of code showing roughly what I'm doing:
ReferenceCat.EditorView = Ember.ContainerView.extend({
init: function(){
this._super();
if(this.get('model.type') != undefined){
this.modelTypeChanges();
}
},
modelTypeChanges : function(){
// 1st step: Remove all children of my view
this.removeAllChildren();
var model = this.get('model');
// 2nd step is to run through all of the type information
// generating the views that we need to actually
// fill in this reference
var tI = model.get('typeInfo');
var self = this;
tI.forEach(function(field){
// Now we have a field
switch(field.type){
case "string":
// add new child view here with data binding to data.<field.name>
break;
}
});
}
});
And this class is referenced like this:
{{view ReferenceCat.EditorView
modelBinding=model}}
In your modelTypeChanges function instead of using a switch statement to create the different types of childViews you need to override the ContainerView's createChildView function (http://emberjs.com/api/classes/Ember.ContainerView.html#method_createChildView). The createChildView function itself will return the instantiated childView and in that overidded function itself you can place your switch statement. So it will look something like this...
createChildView: function(view, attrs) {
switch(attr.type) {
case "string":
view = yourview //your view class here, it is overriding the default
break;
}
.....
...
//Once you place all your case statements above
//make sure to call the parents createChildView function.
//This line is actually creating the view you want with the
//properties that are defined in the object attrs
return this._super(view, attrs);
}
So make sure when you call your overridden createChildView function to pass it the object you want bounded in the childView as a property of the object you pass as its second parameter...
var self = this,
tempviewarray = [];
tI.forEach(function(field){
var view = self.createChildView(null, field);
tempviewarray.push(view);
});
// add all the instantiated views to the ContainerView as children views
this.pushObjects(tempviewarray);
Im trying to extend the flex ArrayCollection to be able to search for an object containing specific data and give it back.
Here is my function:
public function getItemContaining(value: String): Object {
//Loop through the collection
for each(var i: Object in this) {
//Loop through fields
for(var j: String in i) {
//If field value is equal to input value
if(i[j] == value) {
return i;
}
}
}
//If not found
return null;
}
Problem is j is always null so the second loop never works. So I read flex loop descriptions and actually it should work just fine. What can possibly be the problem?
Try it like this:
for (var name:String in myObject){
trace(name + ":" + myObject[name];
}
Okay that was actually the same you were doing. The error must be in this line:
for each(var i: Object in this) {
Try using this:
for each(var i: Object in this.source) {
My first instinct would be to have a look at data type. You're setting up a loop declaring j:String and the symptom is that j is always null. This suggests to me that Flex is failing to interpret the elements of i as strings. If Flex only recognizes the elements of i as Objects (because all Strings are Objects, and Objects are the lowest common denominator), it would return null for j:String.
Try this for your inner loop:
for(var j: Object in i) {
//If field value is equal to input value
if(i[j] is String && (i[j] as String) == value) {
return i;
}
}
if you are using ArrayCollection as your datasource, you should look at using the IViewCursor interface. You can supply a custom compare function, or supply the fields top compare to. This interface is well documented with examples in adobe/livedocs
var _cursor:IViewCursor;
var _idSortField:SortField;
var _idSort:Sort = new Sort();
_idSortField = new SortField();
_idSortField.compareFunction = this.myCompareFunction;
_idSort.fields = [_idSortField];
myArrayCollection.sort = _idSort;
myArrayCollection.refresh();
_cursor = myArrayCollection.createCursor();
if (_cursor.findAny(search))
return _cursor;
if you are search for a value in a specific property, then its even easier. Here's the link to adobe livedocs on this topic
I just want to know if the object in question, has any sub-objects within it or not.
Do I really have to do THIS:
public static function getLength(o:Object):bool
{
for (var item:* in o)
if (item != "mx_internal_uid")
return true;
return false;
}
Isn't there some way to say SOMETHING LIKE: Object.hasChildren();
OR EVEN Object.childCount();
The Object in question does NOT extend the DisplayObjectContainer. It is just something like:
var Ob:Object;
Ob.SomeProp="xxx";
Ob.SomeOtherProp="zzz";
How can I know how many "entries" there are in the object. (in this case 2).
In other words, how does "for (var item:* in Ob)" know when to stop.
???
A good class to inspect objects is the flex built in ObjectUtil. I think what you're trying to achieve would be done by using (obj is the object to analyze):
ObjectUtil.getClassInfo(obj).properties.length
But ObjectUtil.getClassInfo would be a good place too look if you're trying to analyze an object, it returns a lot of information (read more on LiveDocs).
It also has a function to check if a variable is a simple one - ObjectUtil.isSimple
By object you mean the Object class, hence counting the properties, or the object on the displaylist, if the latter, that objects surely extends DisplayObjectContainer wich has the numChildren property
As kajyr says, if it's a DisplayObjectContainer you can check for numChildren.
If you want to check if a generic objects contains simple properties ( primitives like Number,int, uint, String, Boolean ) or complex properties (subObjects, instances of some class ) that you might regards as children to that generic object, you do the following:
var testObj:Object = {id:1,name:'DumDum'};
var testObj2:Object = {id:2,name:'NumNum',data:[1,2,3,4,5,6,7,8,9],somethingComplex:{firstName:'Num',lastName:'Num'}};
trace(isSimple(testObj).length == 0);//prints true
trace(isSimple(testObj2).length == 0);//prints false
trace(isSimple(testObj2));
function isSimple(obj:*):Array{
var complex:Array = [];
for(var prop in obj){
if(!(obj[prop] is String || obj[prop] is int || obj[prop] is uint || obj[prop] is Number || obj[prop] is Boolean))
complex.push({prop: obj[prop]});
}
return complex;
}
If you want to get the number of members (variables associated with an object), that is easy enough to get:
var Ob:Object = {};
Ob.SomeProp="xxx";
Ob.SomeOtherProp="zzz";
trace(getMembersNum(Ob));//prints 2
function getMembersNum(obj:*):int{
var result:int = 0;
for(var prop in obj) result++;
return result;
}
You would write this in your utility package/class maybe like this:
public static function get numMembers(obj:*):int{
var result:int = 0;
for(var prop in obj) result++;
return result;
}
HTH