Comments in text. Also attached git diff for convenience.

On 10/17/2011 10:39 PM, Endi Sukma Dewata wrote:
> On 10/10/2011 10:13 AM, Petr Vobornik wrote:
>> https://fedorahosted.org/freeipa/ticket/1531
>>
>> (3.0 Core Effort Iteration 01 September Y11 Release)
>>
>> Implemented solution:
>> * all entities are created on application start
>> * dependant objects (facets and dialogs) are created at once on their
>> first use in entity.
>>
>> Note(patch naming): patch 022 was second part of 021, but the file name
>> was wrong(021-1)
>
> Some comments/issues:
>
> 1. One of the goals of this bug is to remove the temporary workaround in
> IPA.search_facet.create_content(). We should now be able to call the
> initialize_table_columns() during facet initialization.

Fixed

> 2. Using lazy-loading to create entities, facets, and dialogs makes
> object creations a little bit unpredictable. This is probably fine for
> now, but if there's a problem the other option is to create all objects
> during application initialization. We can use a loop to create all
> entities first, then use another loop to create all dependent objects in
> each entity.

I don't think it's necessary but if it becomes a problem, we can use the initialization loop.

> 3. Another goal is to replace entity names used in spec (see
> other_entity & nested_entity spec properties) with the actual entity
> objects. In this case it might be better to use the loops described in
> #2. This can be done separately.

Wouldn't it lead to the circular dependancy problem again? I think using entity names and calling IPA.get_entity at the time when it is needed is fine. But we should make some naming conversions of function params or object properties to distinguish when we are working with just name or entity itself.

> 4. In the original code, when creating a facet for indirect association
> it will try to find the corresponding direct facet and use it instead of
> creating a new one. In the new code, the indirect facet will always be
> created, but since there is no indirect facet group the facet will never
> appear. It would be better if we can avoid unnecessary creation of
> indirect facets.

Fixed

> 5. In entity.js:201, the use of entity.title for the breadcrumb tooltip
> might not be appropriate because usually the title is plural whereas the
> breadcrumb points to a single object. It would be better to use the
> entity.metadata.label_singular.

Fixed

> 6. Invoking a method by concatenating the method name dynamically such
> as prepare_<facet type>_spec will work, but it's more error prone and
> will clutter up the namespace. It would be better to store the methods
> in a map like this:
>
> that.map.put('search', function(spec) {
> ...
> });
>
> and use it like this:
>
> var method = that.map.get('search');
> method(spec);
>
> This can be done separately.
Reworked. Used object as a map, ordered map isn't necessary.

>
> 7. The code in entity.js:474,998,1000 should have a deeper indentation
> because it's a continuation of the previous line.

Fixed

> 8. The facet_specs and dialog_specs lists can be replaced with
> ordered_map. It already has a method to find an element by its name.
> This can be done separately.
>
My intention was to be able specify entity facets and dialogs simply by specifying their spec in entity spec (without calling builder function), this is possible now. I didn't want to add initialization logic for facet_specs (to fill the ordered_map) to entity in order to keep it as simple as possible. It would be nice though. Maybe we could make an utility object with methods for some simple initialization logic which is used on many places - like checking if boolean is set or some more complicated like initialization of ordered_map (needs key selector fn as parameter).

--
Petr Vobornik
From ac6770e841f1af7476e1b3b34e3d7bbcb1fc77b6 Mon Sep 17 00:00:00 2001
From: Petr Vobornik <pvobo...@redhat.com>
Date: Mon, 10 Oct 2011 13:34:15 +0200
Subject: [PATCH] Circular entity dependency

https://fedorahosted.org/freeipa/ticket/1531

Each entity is created together with its dependent objects (e.g. facets and dialog boxes). This causes a circular dependency problem because some of the objects need to obtain a reference to another entity that has not been created.

Currently this is handled by storing only the other entity name and resolve it when needed (e.g. during rendering stage). In IPA.search_facet this delays the creation of the table widget, making it more difficult to customize.

One solution is to do the object creation in 2 steps:

 * create all entity objects only
 * create the dependent objects in each entity

Implemented solution:
 * all entities are created on application start
 * dependant objects (facets and dialogs) are created at once on their first use in entity.
---
 install/ui/details.js    |   23 +++
 install/ui/entity.js     |  340 +++++++++++++++++++++++++++++++++-------------
 install/ui/navigation.js |    6 +-
 install/ui/search.js     |   10 +-
 4 files changed, 275 insertions(+), 104 deletions(-)

diff --git a/install/ui/details.js b/install/ui/details.js
index e25c45875bcf4950e0c3085fd3930aea764d35bb..1e4a9eb5f1148cb109a89d0affd6aee3c4c6eefd 100644
--- a/install/ui/details.js
+++ b/install/ui/details.js
@@ -295,6 +295,27 @@ IPA.details_facet = function(spec) {
 
     that.sections = $.ordered_map();
 
+    that.add_sections = function(sections) {
+
+        if(sections) {
+            for(var i=0; i < sections.length; i++) {
+
+                    var section_spec = sections[i];
+                    section_spec.entity = that.entity;
+
+                    if (!section_spec.label) {
+                        var obj_messages = IPA.messages.objects[that.entity.name];
+                        section_spec.label = obj_messages[section_spec.name];
+                    }
+
+                    section_spec.factory = section_spec.factory || IPA.details_table_section;
+                    var section = section_spec.factory(section_spec);
+
+                    that.add_section(section);
+            }
+        }
+    };
+
     that.dirty = false;
 
     that.add_section = function(section) {
@@ -717,6 +738,8 @@ IPA.details_facet = function(spec) {
         command.execute();
     };
 
+    that.add_sections(spec.sections);
+
     that.details_facet_create_content = that.create_content;
     that.details_facet_load = that.load;
 
diff --git a/install/ui/entity.js b/install/ui/entity.js
index 3742360115d9dda51f35132b648d785a600d38f3..c82f4a8df727c1a3dd75b133d2b005867e0015ab 100644
--- a/install/ui/entity.js
+++ b/install/ui/entity.js
@@ -128,7 +128,7 @@ IPA.facet = function (spec) {
     that.redirect = function() {
         var entity = that.entity;
         while (entity.containing_entity) {
-            entity = entity.containing_entity;
+            entity = entity.get_containing_entity();
         }
 
         IPA.nav.show_page(
@@ -192,13 +192,13 @@ IPA.facet_header = function(spec) {
 
         if (!that.facet.disable_breadcrumb) {
             var breadcrumb = [];
-            var entity = that.facet.entity.containing_entity;
+            var entity = that.facet.entity.get_containing_entity();
 
             while (entity) {
                 breadcrumb.unshift($('<a/>', {
                     'class': 'breadcrumb-element',
                     text: IPA.nav.get_state(entity.name+'-pkey'),
-                    title: entity.name,
+                    title: entity.metadata.label_singular,
                     click: function(entity) {
                         return function() {
                             IPA.nav.show_page(entity.name, 'default');
@@ -207,7 +207,7 @@ IPA.facet_header = function(spec) {
                     }(entity)
                 }));
 
-                entity = entity.containing_entity;
+                entity = entity.get_containing_entity();
             }
 
             that.path.empty();
@@ -293,7 +293,9 @@ IPA.facet_header = function(spec) {
             }).appendTo(that.breadcrumb);
 
             var entity = that.facet.entity;
-            while (entity.containing_entity) entity = entity.containing_entity;
+            while (entity.containing_entity) {
+                entity = entity.get_containing_entity();
+            }
 
             $('<a/>', {
                 text: entity.metadata.label,
@@ -453,9 +455,13 @@ IPA.entity = function (spec) {
     that.title = spec.title || that.label;
 
     that.dialogs = $.ordered_map();
+    that.dialog_specs = spec.dialogs || [];
+    that.dialogs_created = false;
 
     that.facets = $.ordered_map();
     that.facet_groups = $.ordered_map();
+    that.facet_specs = spec.facets || [];
+    that.facets_created = false;
 
     // current facet
     that.facet = null;
@@ -463,7 +469,20 @@ IPA.entity = function (spec) {
     that.redirect_facet = spec.redirect_facet;
     that.containing_entity = null;
 
+    that.get_containing_entity = function() {
+        return that.containing_entity ?
+                IPA.get_entity(that.containing_entity) : null;
+    };
+
     that.get_dialog = function(name) {
+
+        //build all dialogs on the first time
+        if(!that.dialogs_created) {
+            var builder = IPA.dialog_builder(that);
+            builder.build_dialogs();
+            that.dialogs_created = true;
+        }
+
         return that.dialogs.get(name);
     };
 
@@ -490,6 +509,14 @@ IPA.entity = function (spec) {
     };
 
     that.get_facet = function(name) {
+
+        //build all facets on the first time
+        if(!that.facets_created) {
+            var builder = IPA.facet_builder(that);
+            builder.build_facets();
+            that.facets_created = true;
+        }
+
         if (name === undefined) {
             // return the current facet
             if (that.facet) return that.facet;
@@ -570,14 +597,14 @@ IPA.entity = function (spec) {
     that.get_primary_key_prefix = function() {
         var pkey = [];
         var current_entity = that;
-        current_entity = current_entity.containing_entity;
+        current_entity = current_entity.get_containing_entity();
         while(current_entity !== null){
 
             var key = IPA.nav.get_state(current_entity.name+'-pkey');
             if (key){
                 pkey.unshift(key);
             }
-            current_entity = current_entity.containing_entity;
+            current_entity = current_entity.get_containing_entity();
         }
         return pkey;
     };
@@ -734,20 +761,19 @@ IPA.entity_builder = function(){
     };
 
     that.facet = function(spec) {
+
         spec.entity  = entity;
-        facet = spec.factory(spec);
-        entity.add_facet(facet);
+        entity.facet_specs.push(spec);
+
         return that;
     };
 
     that.search_facet = function(spec) {
-        spec.entity = entity;
-        spec.title = spec.title || entity.metadata.label;
-        spec.label = spec.label || IPA.messages.facets.search;
 
-        var factory = spec.factory || IPA.search_facet;
-        facet = factory(spec);
-        entity.add_facet(facet);
+        spec.type = spec.type || 'search';
+
+        that.facet(spec);
+
         add_redirect_info();
 
         return that;
@@ -755,81 +781,27 @@ IPA.entity_builder = function(){
 
     that.nested_search_facet = function(spec) {
 
-        spec.entity = entity;
-        spec.title = spec.title || entity.metadata.label_singular;
-        spec.label = spec.label || IPA.messages.facets.search;
+        spec.type = spec.type || 'nested_search';
 
-        var factory = spec.factory || IPA.nested_search_facet;
-        facet = factory(spec);
-        entity.add_facet(facet);
+        that.facet(spec);
 
         return that;
     };
 
     that.details_facet = function(spec) {
 
-        var sections = spec.sections;
-        spec.entity = entity;
-        spec.sections = null;
-        spec.title = spec.title || entity.metadata.label_singular;
-        spec.label = spec.label || IPA.messages.facets.details;
+        spec.type = spec.type || 'details';
 
-        var factory = spec.factory || IPA.details_facet;
-        facet = factory(spec);
-        entity.add_facet(facet);
-
-        if (sections) {
-            for (var i=0; i<sections.length; i++) {
-                that.section(sections[i]);
-            }
-        }
+        that.facet(spec);
 
         return that;
     };
 
     that.association_facet = function(spec) {
 
-        spec.entity = entity;
+        spec.type = spec.type || 'association';
 
-        var index = spec.name.indexOf('_');
-        spec.attribute_member = spec.attribute_member ||
-            spec.name.substring(0, index);
-        spec.other_entity = spec.other_entity ||
-            spec.name.substring(index+1);
-
-        spec.add_title = IPA.messages.association.add[spec.attribute_member];
-        spec.remove_title = IPA.messages.association.remove[spec.attribute_member];
-
-        spec.facet_group = spec.facet_group ||
-            spec.attribute_member;
-
-        if (spec.facet_group == 'memberindirect' ||
-            spec.facet_group == 'memberofindirect') {
-
-            var length = spec.attribute_member.length;
-            var direct_attribute_member = spec.attribute_member.substring(0, length-8);
-            var direct_facet_name = direct_attribute_member+'_'+spec.other_entity;
-
-            facet = entity.get_facet(direct_facet_name);
-
-            if (facet) { // merge into previously created direct facet
-                facet.indirect_attribute_member = spec.attribute_member;
-                return that;
-
-            } else {
-                spec.read_only = true;
-            }
-        }
-
-        spec.title = spec.label || entity.metadata.label_singular;
-
-        spec.label = spec.label ||
-            (IPA.metadata.objects[spec.other_entity] ?
-             IPA.metadata.objects[spec.other_entity].label : spec.other_entity);
-
-        var factory = spec.factory || IPA.association_facet;
-        facet = factory(spec);
-        entity.add_facet(facet);
+        that.facet(spec);
 
         return that;
     };
@@ -863,8 +835,15 @@ IPA.entity_builder = function(){
                 var other_entity = other_entities[j];
                 var association_name = attribute_member+'_'+other_entity;
 
-                var facet = entity.get_facet(association_name);
-                if (facet) continue;
+                //already prepared facet
+                var facet = get_spec_by_name(entity.facet_specs, association_name);
+                //already prepared direct facet for indirect facet
+                var direct_facet = get_direct_facet(entity.facet_specs,
+                                                    attribute_member,
+                                                    other_entity);
+                if (facet || direct_facet) {
+                    continue; //in both cases don't prepare new facet
+                }
 
                 var tmp_spec = $.extend({}, spec);
                 tmp_spec.name = association_name;
@@ -876,21 +855,33 @@ IPA.entity_builder = function(){
         return that;
     };
 
-    that.section = function(spec) {
-        spec.entity = entity;
+    function get_spec_by_name(specs, name) {
+        if(!specs || !specs.length) return null;
 
-        if (!spec.label) {
-            var obj_messages = IPA.messages.objects[entity.name];
-            spec.label = obj_messages[spec.name];
+        for(var i=0; i<specs.length; i++) {
+            if(specs[i].name === name) {
+                return specs[i];
+            }
         }
 
-        if (spec.factory) {
-            section = spec.factory(spec);
-        } else {
-            section = IPA.details_table_section(spec);
+        return null;
+    }
+
+    /*
+     * If it's an indirect attribute member, return its direct facets spec
+     * if it exists.
+     */
+    function get_direct_facet(facets, attribute_member, other_entity) {
+
+        var index = attribute_member.indexOf('indirect');
+        if(index > -1) {
+            var direct_attribute_member = attribute_member.substring(0, index);
+            return get_spec_by_name(facets,
+                                    direct_attribute_member+'_'+other_entity);
         }
-        facet.add_section(section);
-    };
+
+        return null;
+    }
 
     function add_redirect_info(facet_name){
         if (!entity.redirect_facet){
@@ -900,30 +891,31 @@ IPA.entity_builder = function(){
 
     that.containing_entity = function(entity_name) {
         add_redirect_info();
-        entity.containing_entity = IPA.get_entity(entity_name);
+        entity.containing_entity = entity_name;
         return that;
     };
 
     that.dialog = function(spec) {
-        var dialog;
+
         if (spec instanceof Object) {
-            var factory = spec.factory || IPA.dialog;
+            spec.factory = spec.factory || IPA.dialog;
             spec.entity = entity;
-            dialog = factory(spec);
+
         } else {
-            dialog = IPA.dialog({
+            spec = {
+                factory: IPA.dialog,
                 name: spec,
                 entity: entity
-            });
+            };
         }
-        entity.dialog(dialog);
+
+        entity.dialog_specs.push(spec);
         return that;
     };
 
     that.adder_dialog = function(spec) {
         spec.factory = spec.factory || IPA.add_dialog;
         spec.name = spec.name || 'add';
-        spec.entity = entity;
 
         if (!spec.title) {
             var title = IPA.messages.dialogs.add_title;
@@ -944,8 +936,164 @@ IPA.entity_builder = function(){
     that.build = function(){
         var item = entity;
         entity = null;
+
         return item;
     };
 
     return that;
 };
+
+IPA.facet_builder = function(entity) {
+
+    var that = {};
+
+    that.prepare_methods = {};
+
+    function init() {
+        that.prepare_methods.search = that.prepare_search_spec;
+        that.prepare_methods.nested_search = that.prepare_nested_search_spec;
+        that.prepare_methods.details = that.prepare_details_spec;
+        that.prepare_methods.association = that.prepare_association_spec;
+    }
+
+    that.build_facets = function() {
+
+        if(entity.facet_specs && entity.facet_specs.length) {
+            var facets = entity.facet_specs;
+            for(var i=0; i<facets.length; i++) {
+                var facet_spec = facets[i];
+                that.build_facet(facet_spec);
+            }
+        }
+    };
+
+    that.build_facet = function(spec) {
+
+        var type = spec.type || 'details';
+        //do common logic
+        spec.entity = entity;
+
+        //prepare spec based on type
+        var prepare_method = that.prepare_methods[type];
+        if(prepare_method) {
+            prepare_method.call(that, spec);
+        }
+
+        //add facet
+        var facet = spec.factory(spec);
+        entity.add_facet(facet);
+    };
+
+    function add_redirect_info(facet_name) {
+
+        facet_name = facet_name || 'search';
+        if (!entity.redirect_facet){
+            entity.redirect_facet = facet_name;
+        }
+    }
+
+    that.prepare_search_spec = function(spec) {
+
+        spec.title = spec.title || entity.metadata.label;
+        spec.label = spec.label || IPA.messages.facets.search;
+        spec.factory = spec.factory || IPA.search_facet;
+
+        add_redirect_info();
+        return spec;
+    };
+
+    that.prepare_nested_search_spec = function(spec) {
+
+        spec.title = spec.title || entity.metadata.label_singular;
+        spec.label = spec.label || IPA.messages.facets.search;
+        spec.factory = spec.factory || IPA.nested_search_facet;
+
+        return spec;
+    };
+
+    that.prepare_details_spec = function(spec) {
+        spec.title = spec.title || entity.metadata.label_singular;
+        spec.label = spec.label || IPA.messages.facets.details;
+        spec.factory = spec.factory || IPA.details_facet;
+
+        return spec;
+    };
+
+    that.prepare_association_spec = function(spec) {
+
+        spec.entity = entity;
+
+        var index = spec.name.indexOf('_');
+        spec.attribute_member = spec.attribute_member ||
+            spec.name.substring(0, index);
+        spec.other_entity = spec.other_entity ||
+            spec.name.substring(index+1);
+
+        spec.add_title = IPA.messages.association.add[spec.attribute_member];
+        spec.remove_title = IPA.messages.association.remove[spec.attribute_member];
+
+        spec.facet_group = spec.facet_group || spec.attribute_member;
+
+        spec.factory = spec.factory || IPA.association_facet;
+
+        spec.title = spec.label || entity.metadata.label_singular;
+
+        spec.label = spec.label ||
+            (IPA.metadata.objects[spec.other_entity] ?
+            IPA.metadata.objects[spec.other_entity].label : spec.other_entity);
+
+        if(that.has_indirect_attribute_member(spec)) {
+
+            spec.indirect_attribute_member = spec.attribute_member + 'indirect';
+        }
+
+        if (spec.facet_group === 'memberindirect' ||
+            spec.facet_group === 'memberofindirect') {
+
+            spec.read_only = true;
+        }
+
+        return spec;
+    };
+
+    that.has_indirect_attribute_member = function(spec) {
+
+        var indirect_members = entity.metadata.attribute_members[spec.attribute_member + 'indirect'];
+        if(indirect_members) {
+            if(indirect_members.indexOf(spec.other_entity) > -1) {
+                return true;
+            }
+        }
+        return false;
+    };
+
+    init();
+
+    return that;
+};
+
+IPA.dialog_builder = function(entity) {
+
+    var that = {};
+
+    that.build_dialogs = function() {
+
+        if(entity.dialog_specs && entity.dialog_specs.length) {
+            var dialogs = entity.dialog_specs;
+            for(var i=0; i<dialogs.length; i++) {
+                that.build_dialog(dialogs[i]);
+            }
+        }
+    };
+
+    that.build_dialog = function(spec) {
+        //do common logic
+        spec.entity = entity;
+
+        //add dialog
+        var dialog = spec.factory(spec);
+        entity.dialog(dialog);
+    };
+
+    return that;
+};
\ No newline at end of file
diff --git a/install/ui/navigation.js b/install/ui/navigation.js
index 76117342511fc9f33e7c81f58d5c6e2fc132208b..84df7f4daf2fb342f54ff2427cafe1b422789639 100644
--- a/install/ui/navigation.js
+++ b/install/ui/navigation.js
@@ -174,7 +174,7 @@ IPA.navigation = function(spec) {
         // update new facet state with new state
         $.extend(facet.state, param_state);
 
-        var entity = tab.entity.containing_entity;
+        var entity = tab.entity.get_containing_entity();
         while (entity) {
             var facet2 = entity.get_facet();
 
@@ -186,7 +186,7 @@ IPA.navigation = function(spec) {
                 if (key_value) facet.state[key_name] = key_value;
             }
 
-            entity = entity.containing_entity;
+            entity = entity.get_containing_entity();
         }
 
         // push entity path and facet state
@@ -233,7 +233,7 @@ IPA.navigation = function(spec) {
                 var current_entity = entity;
                 while (current_entity){
                     state[current_entity.name + '-pkey'] = pkeys.pop();
-                    current_entity = current_entity.containing_entity;
+                    current_entity = current_entity.get_containing_entity();
                 }
             }else{
                 state[entity.name + '-pkey'] = pkeys;
diff --git a/install/ui/search.js b/install/ui/search.js
index c469debc8f76deac0ba72f60c55f3790b8cc6ea2..83b91051c2a5e2cb87e83b61a281dd827f7dfe0c 100644
--- a/install/ui/search.js
+++ b/install/ui/search.js
@@ -100,9 +100,6 @@ IPA.search_facet = function(spec) {
     }
 
     that.create_content = function(container) {
-        /*should be in the initialize section, but can not, due to
-          get_entity circular references.*/
-        initialize_table_columns();
         that.table.create(container);
     };
 
@@ -268,11 +265,11 @@ IPA.search_facet = function(spec) {
         var filter = [];
         var current_entity = entity;
         filter.unshift(IPA.nav.get_state(current_entity.name+'-filter'));
-        current_entity = current_entity.containing_entity;
+        current_entity = current_entity.get_containing_entity();
         while(current_entity !== null){
             filter.unshift(
                 IPA.nav.get_state(current_entity.name+'-pkey'));
-            current_entity = current_entity.containing_entity;
+            current_entity = current_entity.get_containing_entity();
         }
 
         var command = IPA.command({
@@ -292,6 +289,9 @@ IPA.search_facet = function(spec) {
     // methods that should be invoked by subclasses
     that.search_facet_create_content = that.create_content;
 
+    //initialization
+    initialize_table_columns();
+
     return that;
 };
 
-- 
1.7.6.4

diff --git a/install/ui/entity.js b/install/ui/entity.js
index 7545c8a..c82f4a8 100644
--- a/install/ui/entity.js
+++ b/install/ui/entity.js
@@ -198,7 +198,7 @@ IPA.facet_header = function(spec) {
                 breadcrumb.unshift($('<a/>', {
                     'class': 'breadcrumb-element',
                     text: IPA.nav.get_state(entity.name+'-pkey'),
-                    title: entity.title,
+                    title: entity.metadata.label_singular,
                     click: function(entity) {
                         return function() {
                             IPA.nav.show_page(entity.name, 'default');
@@ -471,7 +471,7 @@ IPA.entity = function (spec) {
 
     that.get_containing_entity = function() {
         return that.containing_entity ?
-        IPA.get_entity(that.containing_entity) : null;
+                IPA.get_entity(that.containing_entity) : null;
     };
 
     that.get_dialog = function(name) {
@@ -835,8 +835,15 @@ IPA.entity_builder = function(){
                 var other_entity = other_entities[j];
                 var association_name = attribute_member+'_'+other_entity;
 
+                //already prepared facet
                 var facet = get_spec_by_name(entity.facet_specs, 
association_name);
-                if (facet) continue;
+                //already prepared direct facet for indirect facet
+                var direct_facet = get_direct_facet(entity.facet_specs,
+                                                    attribute_member,
+                                                    other_entity);
+                if (facet || direct_facet) {
+                    continue; //in both cases don't prepare new facet
+                }
 
                 var tmp_spec = $.extend({}, spec);
                 tmp_spec.name = association_name;
@@ -860,6 +867,22 @@ IPA.entity_builder = function(){
         return null;
     }
 
+    /*
+     * If it's an indirect attribute member, return its direct facets spec
+     * if it exists.
+     */
+    function get_direct_facet(facets, attribute_member, other_entity) {
+
+        var index = attribute_member.indexOf('indirect');
+        if(index > -1) {
+            var direct_attribute_member = attribute_member.substring(0, index);
+            return get_spec_by_name(facets,
+                                    direct_attribute_member+'_'+other_entity);
+        }
+
+        return null;
+    }
+
     function add_redirect_info(facet_name){
         if (!entity.redirect_facet){
             entity.redirect_facet = 'search';
@@ -924,6 +947,15 @@ IPA.facet_builder = function(entity) {
 
     var that = {};
 
+    that.prepare_methods = {};
+
+    function init() {
+        that.prepare_methods.search = that.prepare_search_spec;
+        that.prepare_methods.nested_search = that.prepare_nested_search_spec;
+        that.prepare_methods.details = that.prepare_details_spec;
+        that.prepare_methods.association = that.prepare_association_spec;
+    }
+
     that.build_facets = function() {
 
         if(entity.facet_specs && entity.facet_specs.length) {
@@ -941,12 +973,10 @@ IPA.facet_builder = function(entity) {
         //do common logic
         spec.entity = entity;
 
-
         //prepare spec based on type
-        var prepare_method_name = 'prepare_'+type+'_spec';
-        if(that[prepare_method_name] &&
-                typeof that[prepare_method_name] === 'function') {
-            that[prepare_method_name](spec);
+        var prepare_method = that.prepare_methods[type];
+        if(prepare_method) {
+            prepare_method.call(that, spec);
         }
 
         //add facet
@@ -995,9 +1025,9 @@ IPA.facet_builder = function(entity) {
 
         var index = spec.name.indexOf('_');
         spec.attribute_member = spec.attribute_member ||
-        spec.name.substring(0, index);
+            spec.name.substring(0, index);
         spec.other_entity = spec.other_entity ||
-        spec.name.substring(index+1);
+            spec.name.substring(index+1);
 
         spec.add_title = IPA.messages.association.add[spec.attribute_member];
         spec.remove_title = 
IPA.messages.association.remove[spec.attribute_member];
@@ -1037,6 +1067,8 @@ IPA.facet_builder = function(entity) {
         return false;
     };
 
+    init();
+
     return that;
 };
 
diff --git a/install/ui/search.js b/install/ui/search.js
index fe84c2e..83b9105 100644
--- a/install/ui/search.js
+++ b/install/ui/search.js
@@ -100,9 +100,6 @@ IPA.search_facet = function(spec) {
     }
 
     that.create_content = function(container) {
-        /*should be in the initialize section, but can not, due to
-          get_entity circular references.*/
-        initialize_table_columns();
         that.table.create(container);
     };
 
@@ -292,6 +289,9 @@ IPA.search_facet = function(spec) {
     // methods that should be invoked by subclasses
     that.search_facet_create_content = that.create_content;
 
+    //initialization
+    initialize_table_columns();
+
     return that;
 };
 
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to