MacBook, defective by design banner

title:
Put the knife down and take a green herb, dude.


descrip:

One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for www.myfreakinfirst-andlast-name.com

Using 89% of the same design the blog had in 2001.

FOR ENTERTAINMENT PURPOSES ONLY!!!
Back-up your data and, when you bike, always wear white.

As an Amazon Associate, I earn from qualifying purchases. Affiliate links in green.

x

MarkUpDown is the best Markdown editor for professionals on Windows 10.

It includes two-pane live preview, in-app uploads to imgur for image hosting, and MultiMarkdown table support.

Features you won't find anywhere else include...

You've wasted more than $15 of your time looking for a great Markdown editor.

Stop looking. MarkUpDown is the app you're looking for.

Learn more or head over to the 'Store now!

Wednesday, September 26, 2012

Surprisingly little about this on the web, at least from where I'm sitting. I want to create reusable panels in ExtJS, and the inherited code for the project I'm coding doesn't quite understand how it's done. Instead of extending ExtJS components, like the Panel, it creates generic object types that wrap around the components instead. So you have to run myObj.myPanel to get to Panels rather than just myCustomPanel. Weird.

I have ExtJS in Action by Jesus "Jay" Garcia, which is pretty good, but his extension example skips past the simplest case for some reason and dives right in to a filled out example. And the extension example is a singleton. He doesn't really extend a type and instantiate several times until he's going 55 into plugin creation.

Anyhow, here's some code. Just a half baby step past the trivial implementation, so that we can play around a little.

PnlCustom = Ext.extend(Ext.Panel, 
{
        title: "Title",
        html: "spam",

        initComponent : function(){
                PnlCustom.superclass.initComponent.call(this);
                if (null == this.someVal)       {
                        this.someVal = "NOTHING";
                }
                console.log("#" + this.someVal + "#");
        }
});

Ext.onReady(function()  {

        var pnlCustom = new PnlCustom({
                someVal: "3"
        });
        var pnlCustom2 = new PnlCustom({});

        var pnlPlain = new Ext.Panel({
                title: "TITLE",
                items: [
                        pnlCustom,
                        pnlCustom2
                ],
                renderTo: "uiHook"
        });
        //Ext.Msg.alert("test","test"); // compulsory test that Ext is set up correctly.
});
The only other thing you might want to consider is if you want to throw extra "procedural" code into initComponent or the constructor function. There's plenty on the web to help you with that, including some stuff on StackOverflow with one comment that refers to text from one Jay Garcia's books. For now, initComponent is fine.

Also remember that I was looking for an ExtJS 2.2 simplest case. There is some decent (not great, afaict) stuff on 3+.

EDIT: Man, complicated. You can't use your typical Swing/Windows.Forms mental model when building ExtJS UI elements. The items collection can't be accessed inside of a definition of an extended object. Check out this thread (Jay's & Condor's answers are quite useful) to see how what you're apparently really doing is defining a prototype, not a class, per se.

Labels: , ,


posted by ruffin at 9/26/2012 11:55:00 AM
Monday, September 24, 2012

A List Apart: Articles: Getting Out of Binding Situations in JavaScript:

JavaScript is very dynamic and relies on โ€œprototypal inheritance,โ€ which is a significantly different paradigm than class-based inheritance.
...
Perhaps youโ€™re not familiar with languages that treat functions as first-order values, in which case the line var fx = john.greet; may seem weird. This does not call the greet method, but creates a reference to itโ€”an alias of sorts, if you will.

You've probably seen all this before, but this article in particular does a pretty nuanced job of explaining scoping with Javascript, and is from 2008. None of this should be a surprise, though it sometimes is. ;^)

(I'm assigning event listeners in ExtJS as part of a GridPanel's original parameter object, but though it's working fine in one workflow, the listening function and/or the link to the event is being dropped completely in another. So it's time for a quick refresher to see if I can find out where the listener is going.)

Labels: ,


posted by ruffin at 9/24/2012 01:03:00 PM
Thursday, September 20, 2012

Click here for decent coding practices when using ExtJS or Sencha Touch, in this case.

But there are times when I want to use ownerCt. I've got a Toolbar on a TabPanel of GridPanels that needs to, surprise, access the Store of the active GridPanel to get some information. I need to instantiate the Toolbar before the TabPanel if I want to set it as its tbar, but if I can't use ownerCt to drill back up and over from the Toolbar's Button's event handler, then the Toolbar anachronistically needs a reference to its unofficial "parent" when it's created.

Get it?

So sure, there are unclean ways around this, and I'm about to pick one. But if I could use ownerCt, I would be in business already.

Why not use ownerCt? Not just because it's "good advice", above, but because...

toolbars in the current version [ExtJS 2.2 in this case] aren't implemented as containers. I believe this is planned in 3.0
/sigh

I love legacy codebases.

Labels: ,


posted by ruffin at 9/20/2012 12:22:00 PM
Friday, May 04, 2012

TL:WR
The bottom line is that the Model is an extension of the old Record. Profit.

From my post (though the guy's asking more specifically about Proxies. It's in the answer, I think.) on StackOverflow:

I'm coming from ExtJS 2.2 [sic] to 4, and the Model behavior and terminology threw me for a loop too.

The best quick explanation I can find is from this post in the "Countdown to ExtJS 4" series on Sencha's blog. Turns out a Model acts like it does because it's "really" a Record.

The centerpiece of the data package is Ext.data.Model. A Model represents some type of data in an application - for example an e-commerce app might have models for Users, Products and Orders. At its simplest a Model is just a set of fields and their data. Anyone familiar with Ext JS 3 will have used Ext.data.Record, which was the precursor to Ext.data.Model.

Here's the confusing part: A Model is both a model for the data you're using and a single instance of an object following that model. Let's call its two uses "Model qua model" and "Model qua Record".

This is why its load method requires a unique id (full stop). Model qua Record uses that id to create RESTful URLs for retrieving (and saving, etc) a single Record worth of data. The RESTful URL convention is described here and is linked to in this post on Sencha's blog that talks specifically about Model usage.

Here are a few RESTful URLs formed to that standard to get you familiar with the format, which it appears ExtJS' Model does use:

Operate on a Record with id of 1

GET /people/1 <<< That's what's used to retrieve a single record into Model

return the first record with id of 2

DELETE /people/2

destroy the first record with id of 7

POST /people/7?_method=DELETE

Etc etc.

This is also why Models have their own proxies, so that they can run RESTful operations via that URL modified to follow the conventions described in that link. You might pull 100s of records from one URL, which you'd use as your Store's proxy source, but when you want to save what's in the single Model (again, think "Model qua Record" here), you might perform those Record-specific operations through another URL whose backend messes with one record at a time.


So When Do I use Stores?

To store more than one instance of that Model, you'd slap them into a Store. You add lots of Models quaRecords into Stores and then access those "Models" to pull data out. So if you have a grid you'll naturally want to have all that data locally, without having to re-query the server for each row's display.

From the first post:

Models are typically used with a Store, which is basically a collection of Model instances.

And, of course, the Stores apparently pull info from Model qua Model here to know what they're carrying.

Labels:


posted by ruffin at 5/04/2012 03:34:00 PM
Tuesday, April 24, 2012

Ext.Msg.confirm -- their example almost works.:
Ext.onReady(function(){
    Ext.Msg.confirm('Hey!', 'Is this ok?', function(btn, text){
        if (btn.toLowerCase() == 'yes'){
            alert('go ahead');
        } else {
            alert('abort');
        }
    });
});
Had to add .toLowerCase() and change Yes to yes, but otherwise a good note to self.

Labels: ,


posted by ruffin at 4/24/2012 10:32:00 AM
Wednesday, April 11, 2012

If your ExtJS TabPanel doesn't have scrolling arrows (and you do have enableTabScroll set to true), it could be because your chosen layout isn't "a fitting layout'.

Jack Slocum says:
The issue with the code is a TableLayout is not a "fitting" layout. It provides no dimensions to underlying components. Your TabPanel has no width defined, and no layout that provides a width, and so it can't calculate the scroll sizes correctly.
 
Can't quite figure out what happened to Jack and ExtJS, but I sure appreciate his answers more than most of the other guys.  They're well-written and to the point, and only happen when he feels like actually answering a question.  That's a relative rarity on the ExtJS boards. That is, if he posts, it's going to tell you what you haven't learned yet, not tell you to read the fantastic manual or, more common in ExtJS land, the library's source code.

I slapped width:500 in mine, and *poof*, profit.

Lots of wacky stuff in TabPanel, at least back in 2.x. If you have an id with two underscores in a row, that's apparently going to bork their id parser (which figures out tab relationships), for instance, which I found out the hard way. The way layout managers break (as with the above) with my Java-born expectations is also a pain.

Labels:


posted by ruffin at 4/11/2012 01:26:00 PM
Wednesday, March 28, 2012

At least when running against ExtJS 2.2, the example from Listing 7.1 on page 159 of ExtJS in Action, (c) 2011, has a few careless errors. If you use the GridPanel source from Building_our_simple_gridpanel.html to finish things up, you need to make a number of changes. First, he's changed the mapping for the first column from 'name' on page 159 to 'fullName' (case is important) in the example code. That's not technically an error, but is an inconsistency that's surprising given the quality of most of the sample code, which is usually quite thorough down to its whitespace.

That said, there are a number of errors where the code in Listing 7.1 is misdescribed in the corresponding paragraphs. There are numbers that are supposed to match from text to code, and they often don't. So I'm guessing Listing 7.1 isn't up to snuff.

There are two serious, outright errors, afaict. The first is that the Ext.data.Store is never loaded. The second is in the nameRecord declaration. It's an oboe error with indices -- again, at least when used against 2.2 (the book assumes 3.1). He's got the first column at 1 and second at 2. That borks. You want 0 and 1.

Let's just cut to the chase and spit it all out here. Note that I also put in a hardcoded height, since I wasn't rendering to the body.

// Call createGrid from Ext.onReady() to render the simple grid
// to a div with id of 'divUiHook2'.
function createGrid() {

//==============================================
// code from Listing 7.1
//==============================================
var arrayData = [
['Jay Garcia', 'MD'],
['Aaron Baker', 'VA'],
['Susan Smith', 'DC'],
['Mary Stein', 'DE'],
['Bryan Shanley', 'NJ'],
['Nyri Selgado', 'CA']
];


var nameRecord = Ext.data.Record.create([
{ name:'name',mapping:0},
{ name:'state',mapping:1}
]);

var memoryProxy = new Ext.data.MemoryProxy(arrayData);
var arrayReader = new Ext.data.ArrayReader({ id:0 },nameRecord);

var store = new Ext.data.Store({
reader:arrayReader,
proxy:memoryProxy
});

store.load(); // this was missing -mfn
console.log(store.getCount()); // this is what clued me in -mfn


//==============================================
// code from Building_our_simple_gridpanel.html
//==============================================
var cm = new Ext.grid.ColumnModel([ // 1
{
header : 'Full Name',
sortable : true,

// changed this from fullName
dataIndex : 'name' // 2
},
{
header : 'State',
dataIndex : 'state'
}
]);

var gridView = new Ext.grid.GridView(); // 3
var selModel = new Ext.grid.RowSelectionModel({ // 4
singleSelect : true
});

var dummyGrid = new Ext.grid.GridPanel({ // 5
renderTo : 'divUiHook2', // changed from getBody.
//autoHeight : true, // replace with constant
height : 200, // constant height
width : 250,
store : store, // 6
view : gridView, // 7
colModel : cm, // 8
selModel : selModel,

title : 'Our first grid'
});
} // eo fn createGrid


Voila. That works, providing you have a DIV with id name divUiHook2 in your file and that you call the createGrid function.

Labels: , , ,


posted by ruffin at 3/28/2012 11:04:00 AM
Monday, March 05, 2012

I was trying to get an ExtJS 2.2 JsonStore to send raw parameters to a WCF service. Catch-22 was that WCF doesn't accept raw params, and JsonStore seems to like to throw POSTs only (by default) when requesting data. And this breaks the deadlock. Very nice.

Edgardo Rossettoโ€™s Blog ๏ฟฝ Raw HTTP POST with WCF:

Hereโ€™s how you read the input Stream:

public void DoWork(Stream input)

{

StreamReader sr = new StreamReader(input);

string s = sr.ReadToEnd();

sr.Dispose();

NameValueCollection qs = HttpUtility.ParseQueryString(s);

string firstName = qs["firstName"];

string lastName = qs["lastName"];

// Do work here

}

Labels: ,


posted by ruffin at 3/05/2012 02:28:00 PM
Friday, February 10, 2012

Amitava's Technical Diary: Nesting ExtJS 2.0 TreePanel inside Accordian:

Nesting ExtJS 2.0 TreePanel inside Accordian
The Accordian panel in ExtJS 2.0 javascript framework, will error out if an item (Ext.Component) does not possess a header. The easiest way to create an header is to set the title property.


Was having some trouble getting a TreePanel to render as a child in another Panel in ExtJS 2.2. Bizzarre. It'd render if I'd put it directly into a DIV (renderTo set for the TreePanel) and the other Panel into another, but if I removed renderTo from the TreePanel and stuffed it into that other Panel, BLAMMO. ct is null. Enjoy.

Lots of weird stuff in ExtJS. I've seen it act unhappy if you don't have an id set for an object. Now, maybe a header is occasionally assumed as well? /sigh Neat overall, but a little rough around the edges.

Labels: ,


posted by ruffin at 2/10/2012 04:46:00 PM
Friday, February 03, 2012

Unfortunately I'm stuck on ExtJS 2.2 in a current project, so I'm not sure how well this carries over, but I've done a crudload of work looking though the code, extending Store, GridPanel, and JsonReader and creating a custom ColumnModel etc etc. And this is where I think I am with mapping the Store.load() to GridPanel lifecycle, pulled from some code comments:

   1 //==============================================
   2 // Use the reader to create the data store
   3 //==============================================
   4 // note that I've subclassed Store (as MyQueryDataStore) here. 
   5 // No operational difference in this code, however.
   6 var myStore = new MyQueryDataStore({
   7         url: './json/gridValues.json',
   8         reader: myReaderTest
   9 });
  10 
  11 // How to iterate the data once it's returned, remembering that we're
  12 // dealing with an asynchronous paradigm here.
  13 myStore.on("load", function(s,rs) {
  14         console.log("and we're back");
  15         this.each(function(record) {
  16             //var strFieldName = this.fields.get(3).name;
  17             //console.log('record data from callback: ' + record.get(strFieldName));
  18         });
  19 });
  20 myStore.load(); // AJAX call to get the data happens now.
  21 // the Store is going to call the load method of its local
  22 // HttpProxy...
  23 // this.proxy.load(p, this.reader, this.loadRecords, this, options);
  24 // ... the request sent to the server has a callback referenced to
  25 // the store's loadRepsonse method, which includes a call to read
  26 // the response with the referenced DataReader.
  27 //
  28 // Afterwards, the proxy calls the Store's loadRecords method.
  29 // The already Read response is passed with that call as [o] in
  30 // loadRecords' first parameter.
  31 //      loadRecords : function(o, options, success){
  32 //          ...
  33 //          var r = o.records, t = o.totalRecords || r.length;
  34 //
  35 // And voila.  That's the life of a JSON return to DataStore request.

That's close, anyway. I'll clean up the custom objects at some point and post a tutorial, just to add to my other obsolete technology intros, like the Atari 2600 programming on an OS 9- Mac pages.

One quick editorial comment: The "debug" version of ExtJS, at least at version 2.2, shows a programmer more interested in showing off than creating self-commenting code (though don't miss caveats one and two). If you're not going to comment your code, there's no reason to also obfuscate by hand and tell others (like at least one unhelpful dude employed by Sencha won't stop doing on their forums) that the answers to all your questions will be revealed not by asking for help when you're mentally exhausted (okay, some questions are horrible, but still...), but by forensic examination of ext-all-debug.js. This hand-obfuscation is exactly what you find in ExtJS. The best example I've found so far, unless I've missed something, is in JsonReader.

From my flowerbox:
 * In Ext.data.JsonReader, for some reason, the equivalent variable in readRecords
 * for [fieldManager] (in that case, named [f]) was used to perform the tasks of both
 * [fldColumnArchetype] and [fieldCurrent] variables here.  I think it's just an
 * obfuscation technique (like the reused [v] throughout), as the use here seems
 * to have no relationship with the original fieldManager declaration.  That is,
 * you could have used [foo] in either spot if you'd wanted, but they strangely
 * and unintuitively recycled instead. (Or I've missed something important!) The
 * kingdom for a strongly typed language...
 *
 * There were other occurrences of poorly scoped variables and var choices, like...
 *  var s = this.meta;    // This var only made things *less* self-commenting.  Gone.
 * ... that have been removed from the JsonReader codebase.  It's like the code
 * had been minimally minimized and purposely obfuscated, but only partially so --
 * and that obfuscation done by hand.

And let's just say that variables named r,f,fi,fl,v,g are bad enough before they're reused without even a passing regard for typing.

/end rant

Labels: , , ,


posted by ruffin at 2/03/2012 09:10:00 AM

<< Older | Newer >>


Support freedom
All posts can be accessed here:


Just the last year o' posts:

URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* git repo mapped drive setup * Regex Tester
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src) * Break on a Lenovo T430: Fn+Alt+B
email if ya gotta, RSS if ya wanna RSS, (?_?), ยข, & ? if you're keypadless


Powered by Blogger etree.org Curmudgeon Gamer badge
The postings on this site are [usually] my own and do not necessarily reflect the views of any employer, past or present, or other entity.