I'm building a FF extension, and I'm processing some xhtml for myself in order to supporn subforms loading, so I have to identify the elements with l10n attributes defined and add them the string value. Because the l10n can't be shared from main code to content scripts (because isn't a simple JSON object), I managed the situation by getting the loaded keys values and defining an "localized array bundle", like this:
lStrings = ["step_title", ........ ];
for (var i = 0; i < lStrings.length; i++) {
bundle[lStrings[i]] = this.locale(lStrings[i]);
}
The thing is, I have to write here every entry in the .properties files... SO, do you know how to access this key values? I already tryed with .toString .toLocalString and inspecting the object, but can't find the way the object to be capable of returning all the key collection.
Do you have a better idea for improvement?
var yourStringBundle = Services.strings.createBundle('chrome://blah#jetpack/content/bootstrap.properties?' + Math.random()); /* Randomize URI to work around bug 719376 */
var props = yourStringBundle.getSimpleEnumeration();
// MDN says getSimpleEnumeration returns nsIPropertyElement // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIStringBundle#getSimpleEnumeration%28%29
while (props.hasMoreElements()) {
var prop = props.getNext();
// doing console.log(prop) says its an XPCWrappedObject but we see QueryInterface (QI), so let's try QI'ing to nsiPropertyElement
var propEl = prop.QueryInterface(Ci.nsIPropertyElement);
// doing console.log(propEl) shows the object has some fields that interest us
var key = propEl.key;
var str = propEl.value;
console.info(key, str); // there you go
}
See comments for learning. Nice quesiton. I learned more about QI from replying.
Related
I'm running a Apps Script to create a data entry form. Sometimes my searchRecord function works if I run it several times. Sometimes it doesn't pull any info, but never gives me the warning screen, sometimes it pulls the info from the last search. I'm not sure where the problem is. I have copied the code below.
//Function to Search the record
function searchRecord(){
var myGoogleSheet=SpreadsheetApp.getActiveSpreadsheet(); //declare a variable and set with active Google Sheet
var shUserForm=myGoogleSheet.getSheetByName("User Form"); //declare a variable and set with the User Form reference
var datasheet=myGoogleSheet.getSheetByName("Existing Customers"); //declare variable and set the reference of database sheet
var str=shUserForm.getRange("B2").getValue(); //get data input for search button
var values=datasheet.getDataRange().getValues(); //getting the entire values from the used range and assigning it to values variable
var valuesFound=false; //variable to store boolean value
for (var i=0; i<values.length; i++)
{
var rowValue=values[i]; //declare a variable and storing the value
//checking the first value of the record is equal to search item
if(rowValue[6]==str){
shUserForm.getRange("B12").setValue(rowValue[0]);
shUserForm.getRange("B15").setValue(rowValue[1]);
shUserForm.getRange("B23").setValue(rowValue[2]);
shUserForm.getRange("B17").setValue(rowValue[3]);
shUserForm.getRange("E17").setValue(rowValue[4]);
shUserForm.getRange("B8").setValue(rowValue[6]);
shUserForm.getRange("E8").setValue(rowValue[7]);
shUserForm.getRange("B19").setValue(rowValue[8]);
shUserForm.getRange("E19").setValue(rowValue[9]);
shUserForm.getRange("B21").setValue(rowValue[10]);
shUserForm.getRange("E21").setValue(rowValue[11]);
shUserForm.getRange("E23").setValue(rowValue[12]);
shUserForm.getRange("E12").setValue(rowValue[13]);
shUserForm.getRange("B25").setValue(rowValue[14]);
shUserForm.getRange("E25").setValue(rowValue[15]);
shUserForm.getRange("B27").setValue(rowValue[16]);
shUserForm.getRange("E27").setValue(rowValue[17]);
shUserForm.getRange("B29").setValue(rowValue[18]);
shUserForm.getRange("E29").setValue(rowValue[19]);
shUserForm.getRange("B31").setValue(rowValue[20]);
shUserForm.getRange("E10").setValue(rowValue[21]);
shUserForm.getRange("B33").setValue(rowValue[22]);
shUserForm.getRange("B35").setValue(rowValue[23]);
shUserForm.getRange("B37").setValue(rowValue[24]);
shUserForm.getRange("E31").setValue(rowValue[25]);
shUserForm.getRange("E35").setValue(rowValue[26]);
shUserForm.getRange("B39").setValue(rowValue[27]);
shUserForm.getRange("E39").setValue(rowValue[27]);
shUserForm.getRange("B41").setValue(rowValue[29]);
shUserForm.getRange("E15").setValue(rowValue[30]);
shUserForm.getRange("B43").setValue(rowValue[31]);
shUserForm.getRange("E43").setValue(rowValue[32]);
shUserForm.getRange("B45").setValue(rowValue[33]);
shUserForm.getRange("E45").setValue(rowValue[34]);
shUserForm.getRange("B47").setValue(rowValue[35]);
shUserForm.getRange("B49").setValue(rowValue[36]);
shUserForm.getRange("B10").setValue(rowValue[37]);
shUserForm.getRange("E37").setValue(rowValue[5]);
valuesFound=true;
return;//come out from the loop
}
if(valuesFound=false){
//to create the instance of the user-interface environment to use the alert function
var ui=SpreadsheetApp.getui();
ui.alert("No Record Found");}
}
}
Solution
There are different points in your code that could be improved, I attach the updated function correcting the basics:
Indentation: This is easy to fix, just press ctrl + shft + i to correctly indent the code.
Break statement: Use the word break to break a loop.
Wrong comparison operator: The second if has only one = instead of two ==. Check Expressions and operators
Structural logic: Inside the for loop there are two ifs. Only the second one depends on the value of the valuesFound variable, which when modified breaks the loop, so it is not really doing anything.
Readability: It is difficult to understand what the code is doing and so many setValue boxes with no apparent connection is confusing.
In addition, it is difficult to offer help if the behavior of the function is variable and the reason is not known. Apparently, it should always give the same result.
Updated code
function searchRecord() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); //declare a variable and set with active Google Sheet
var shUserForm = ss.getSheetByName("User Form"); //declare a variable and set with the User Form reference
var datasheet = ss.getSheetByName("Existing Customers"); //declare variable and set the reference of database sheet
var str = shUserForm.getRange("B2").getValue(); //get data input for search button
var values = datasheet.getDataRange().getValues(); //getting the entire values from the used range and assigning it to values variable
var valuesFound = false; //variable to store boolean value
var ui = SpreadsheetApp.getui();
for (var i = 0; i < values.length; i++) {
var rowValue = values[i]; //declare a variable and storing the value
//checking the first value of the record is equal to search item
if (rowValue[6] == str) {
shUserForm.getRange("B12").setValue(rowValue[0]);
shUserForm.getRange("B15").setValue(rowValue[1]);
shUserForm.getRange("B23").setValue(rowValue[2]);
shUserForm.getRange("B17").setValue(rowValue[3]);
shUserForm.getRange("E17").setValue(rowValue[4]);
shUserForm.getRange("B8").setValue(rowValue[6]);
shUserForm.getRange("E8").setValue(rowValue[7]);
shUserForm.getRange("B19").setValue(rowValue[8]);
shUserForm.getRange("E19").setValue(rowValue[9]);
shUserForm.getRange("B21").setValue(rowValue[10]);
shUserForm.getRange("E21").setValue(rowValue[11]);
shUserForm.getRange("E23").setValue(rowValue[12]);
shUserForm.getRange("E12").setValue(rowValue[13]);
shUserForm.getRange("B25").setValue(rowValue[14]);
shUserForm.getRange("E25").setValue(rowValue[15]);
shUserForm.getRange("B27").setValue(rowValue[16]);
shUserForm.getRange("E27").setValue(rowValue[17]);
shUserForm.getRange("B29").setValue(rowValue[18]);
shUserForm.getRange("E29").setValue(rowValue[19]);
shUserForm.getRange("B31").setValue(rowValue[20]);
shUserForm.getRange("E10").setValue(rowValue[21]);
shUserForm.getRange("B33").setValue(rowValue[22]);
shUserForm.getRange("B35").setValue(rowValue[23]);
shUserForm.getRange("B37").setValue(rowValue[24]);
shUserForm.getRange("E31").setValue(rowValue[25]);
shUserForm.getRange("E35").setValue(rowValue[26]);
shUserForm.getRange("B39").setValue(rowValue[27]);
shUserForm.getRange("E39").setValue(rowValue[27]);
shUserForm.getRange("B41").setValue(rowValue[29]);
shUserForm.getRange("E15").setValue(rowValue[30]);
shUserForm.getRange("B43").setValue(rowValue[31]);
shUserForm.getRange("E43").setValue(rowValue[32]);
shUserForm.getRange("B45").setValue(rowValue[33]);
shUserForm.getRange("E45").setValue(rowValue[34]);
shUserForm.getRange("B47").setValue(rowValue[35]);
shUserForm.getRange("B49").setValue(rowValue[36]);
shUserForm.getRange("B10").setValue(rowValue[37]);
shUserForm.getRange("E37").setValue(rowValue[5]);
valuesFound = true;
break
}
if (valuesFound == false) {
//to create the instance of the user-interface environment to use the alert function
ui.alert("No Record Found");
}
}
}
According to the documentation, it needs to follows the Form Post rules at: https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4. When looking at that information it did not give me much to work with in terms of complex objects or maps.
Right now, If I have a list for example: Each item in the list needs to be stringified.
var params = {"list": [1,2,3]};
// needs to be stringed.
params["list"] = params["list"].map((item)=>item.toString()).toList();
Simple. Also all base items need to be a string as well
var params = {"number": 1, "boolean": true};
params = params.forEach((k,v)=> params[k].toString());
But how do we handle maps?
var params = {"map": {"a":1,"b":"foo","c":false,"d":[]}};
// ??
It seems that after testing in my app and in dart pad, you need to make sure everything is strings, so i am trying to come up with a way to effectively cover lists, maps, and maybe more complex objects for encoding.
var params = {};
params["list"] = [1,2,3];
params["number"] = 1;
params["boolean"] = true;
params["map"] = {"a":1,"b":"foo","c":false,"d":[]};
params.forEach((String key, dynamic value){
if(value is List){
params[key] = value.map((v)=>v.toString()).toList();
}else if(value is Map){
// ????
}else{
params[key] = value.toString();
}
//maybe have an additional one for custom classes, but if they are being passed around they should already have their own JSON Parsing implementations.
}
Ideally, the result of this would be passed into:
Uri myUri = new Uri(queryParameters: params);
and right now, while i solved the list issue, it doesn't like receiving maps. Part of me just wanted to stringify the map as a whole, but i wasn't not sure if there was a better way. I know that when someone accidentally stringified the array, it was not giving me: ?id=1&id=2 but instead ?id=%5B1%2C2%5D which was not correct.
I don't think there is any special support for maps. Query parameters itself is a map from string to string or string to list-of-strings.
Everything else need to be brought into this format first before you can pass it as query parameter.
A simple approach would be to JSON encode the map and pass the resulting string as a single query parameter.
I'm having problems with an object that returns me in Realm, the strange thing is that if I printo console the object if I start it well but however if I try to access its value it tells me that it is empty.
The structure of the object is as follows:
class Favourite : Object {
var character : Character!
}
I create an object and add it to the DB
let fav = Favourite()
fav.character = character
FavouriteDao.sharedInstance.addFavourite(characterFavourite: fav)
Get all objects of favorite type
func getAllFavourites() -> Results {
return realm.objects(Favourite.self)
}
When I get the item and do a print
Favourite {
character = Character {
name = Spider-Man;
descriptionC = Bitten by a radioactive spider, high school student Peter Parker gained the speed, strength and powers of a spider. Adopting the name Spider-Man, Peter hoped to start a career using his new abilities. Taught that with great power comes great responsibility, Spidey has vowed to use his powers to help people.;
thumbnail = Thumbnail {
id = 815D93D0-C116-4267-978C-9E47C0074D0D;
path = http://i.annihil.us/u/prod/marvel/i/mg/3/50/526548a343e4b;
extensionImage = jpg;
};
};
If I try to access the character element it tells me that it is nil
Somebody manages to understand because if I make a print of the favorite object it shows me that there is inside a character object but nevertheless if I try to accede to it it says that it does not exist?
What you do is totally wrong from the very beginning. You should read the realm docs first. https://realm.io/docs/swift/latest/#getting-started
For example.
class Favourite : Object {
var character : Character!
}
is not something you should do in Realm.
Assuming your Character is well-defined, the code should be dynamic var character : Character? = nil at least.
Given a Map, assignment, what is the fastest way to check if it contains any duplicate values in Dart? I am currently using a Set formed from the Map's values and checking its length against the original Map, which works of course, but I'm wondering if there's an especially performant alternative.
Set d = new Set.from(assignment.values);
if (d.length < assignment.length) {
return false; // indicates has duplicates in this context
}
EDIT:
Tried #mezoni's solution modified for my program, but it actually ran a bit slower than my original version. It probably has more to do with constant times than anything else.
List values = new List.from(assignment.values);
Set set = new Set();
for (var i = 0; i < assignment.length; i++) {
if (!set.add(values[i])) {
return false;
}
}
Complexity wise you won't be able to get anything faster. Creating the Set and filling it with the values of the Map is linear in the number of elements. Clearly you have to run through all the values, so you can't do any better than that.
Maybe you could find a solution with a smaller constant factor, but that's not clear. In particular for larger sets I think the Set solution is pretty efficient.
This is more of a algorithms question than a Dart question. In any case, you have to check every value against the others, giving n-1 + n-2 + ... + n-(n-1) checks, or n^2/2. Programmatically, it's easy to create a set, but you could also generate an array, sort the array, and then iterate once to check for duplicates. That finishes in O(n log n).
Fastets way (if you realy need better performance):
void main() {
// Values from map
var values = [1,2,3,2,1,3,2,1];
var length = values.length;
var set = new Set();
var duplicate = false;
// Only for statistics purpose
var statistics = 0;
for(var i = 0; i < length; i++) {
statistics++;
if(!set.add(values[i])) {
duplicate = true;
break;
}
}
print("Duplicate: $duplicate");
print("Performed in ${statistics} iteration(s) from $length possible");
}
Output:
Duplicate: true
Performed in 4 iteration(s) from 8 possible
P.S.
The first example can be recommended to use with List values.
But because Map.values not a List but Iterable then it would be more efficient do not convert them to List but use as is.
Here is modified sample for use with Iterable objects.
It will be work faster because in this algorithm not required convert all values to the List object because it not want using of all elements without exception.
Instead it wants use as less as possible access operation on original source. If the source supports lazy operation of the access to values (as Iterable) this will be even better.
void main() {
// Values from map
var values = [1,2,3,2,1,3,2,1];
var assignment = {};
var length = values.length;
var key = 0;
for(var value in values) {
assignment[key++] = value;
}
var set = new Set();
var duplicate = false;
// Only for statistics purpose
var statistics = 0;
for(var value in assignment.values) {
statistics++;
if(!set.add(value)) {
duplicate = true;
break;
}
}
print("Duplicate: $duplicate");
print("Performed in ${statistics} iteration(s) from $length possible");
}
Its a little tricky to search for 'var:*' because most search engines wont find it.
I'm not clear exactly what var:* means, compared to say var:Object
I thought it would let me set arbitrary properties on an object like :
var x:* = myObject;
x.nonExistantProperty = "123";
but this gives me an error :
Property nonExistantProperty not found on x
What does * mean exactly?
Edit: I fixed the original var:* to the correct var x:*. Lost my internet connection
Expanding on the other answers, declaring something with type asterisk is exactly the same as leaving it untyped.
var x:* = {};
var y = {}; // equivalent
However, the question of whether you are allowed to assign non-existant properties to objects has nothing to do with the type of the reference, and is determined by whether or not the object is an instance of a dynamic class.
For example, since Object is dynamic and String is not:
var o:Object = {};
o.foo = 1; // fine
var a:* = o;
a.bar = 1; // again, fine
var s:String = "";
s.foo = 1; // compile-time error
var b:* = s;
b.bar = 1; // run-time error
Note how you can always assign new properties to the object, regardless of what kind of reference you use. Likewise, you can never assign new properties to the String, but if you use a typed reference then this will be caught by the compiler, and with an untyped reference the compiler doesn't know whether b is dynamic or not, so the error occurs at runtime.
Incidentally, doc reference on type-asterisk can be found here:
http://livedocs.adobe.com/labs/air/1/aslr/specialTypes.html#*
(The markup engine refuses to linkify that, because of the asterisk.)
It's a way of specifying an untyped variable so that you can basically assign any type to it. The code
var x:* = oneTypeObject;
creates the variable x then assigns the oneTypeObject variable to it. You can assign an entirely different type to it as well as follows:
var x:* = anotherTypeObject;
However, you still can't arbitrarily set or access properties; they have to exist in the underlying type (of either oneTypeObject or anotherTypeObject).
Both types may have identically named properties which means you can access or set that property in x without having to concern yourself with the underlying type.
It's the "untyped" type. It just means that the variable can be of any type. Basically the same effect as using this:
var x = myObject;
It means that the type is not specified and can be used with any type. However, you can't set random properties on it. It will behave like whatever type you set it to. The exact syntax is:
var x:*;
As they said before, it's untyped, so it may hold any kind of data. However, you cannot treat it as such in operations. For example, this is valid code:
var untyped:* = functionThatReturnsSomeValue();
But if you go one step farther, you have to watch out or you might get bitten:
var name:String = untyped.name;
Now, if the object returned by that function happens to be an object with a field with an id of "name," you are in the clear. However, unless you know for sure that this is the case, it's better to use typed objects. In this way, the compiler will alert you if you do something that might throw an error at runtime:
(elsewhere)
public class TypedObject()
{
public var name:String = "";
}
(and the code at hand)
var typed:TypedObject = functionThatReturnsTypedObject();
var name:String = typed.name;