cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jessicaw...@apache.org
Subject [06/39] Format JS
Date Fri, 19 Jul 2013 17:01:19 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f766a9e5/ui/scripts/ui/widgets/detailView.js
----------------------------------------------------------------------
diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js
index 0bccef5..69585ed 100644
--- a/ui/scripts/ui/widgets/detailView.js
+++ b/ui/scripts/ui/widgets/detailView.js
@@ -15,1416 +15,1449 @@
 // specific language governing permissions and limitations
 // under the License.
 (function($, cloudStack, _l) {
-  var replaceListViewItem = function($detailView, newData, options) {
-    var $row = $detailView ? $detailView.data('list-view-row') :
-      options.$row;
+    var replaceListViewItem = function($detailView, newData, options) {
+        var $row = $detailView ? $detailView.data('list-view-row') :
+            options.$row;
 
-    if (!$row) return;
+        if (!$row) return;
 
-    var $listView = $row.closest('.list-view');
+        var $listView = $row.closest('.list-view');
 
-    if (!$listView.parents('html').size()) return;
+        if (!$listView.parents('html').size()) return;
 
-    var $newRow;
-    var jsonObj = $row.data('json-obj');
+        var $newRow;
+        var jsonObj = $row.data('json-obj');
 
-    if($listView.length > 0 ) { //$listView.length is 0 after calling $(window).trigger('cloudStack.fullRefresh')
-      $listView.listView('replaceItem', {
-        $row: $row,
-        data: $.extend(jsonObj, newData),
-        after: function($newRow) {
-          if ($detailView) {
-            $detailView.data('list-view-row', $newRow);
-          }
+        if ($listView.length > 0) { //$listView.length is 0 after calling $(window).trigger('cloudStack.fullRefresh')
+            $listView.listView('replaceItem', {
+                $row: $row,
+                data: $.extend(jsonObj, newData),
+                after: function($newRow) {
+                    if ($detailView) {
+                        $detailView.data('list-view-row', $newRow);
+                    }
+
+                    setTimeout(function() {
+                        $('.data-table').dataTable('selectRow', $newRow.index());
+                    }, 100);
+                }
+            });
+        }
 
-          setTimeout(function() {
-            $('.data-table').dataTable('selectRow', $newRow.index());
-          }, 100);
+        // Refresh detail view context
+        if ($detailView) {
+            $.extend(
+                $detailView.data('view-args').context[
+                    $detailView.data('view-args').section
+                ][0], newData
+            );
         }
-      });
-    }
-
-    // Refresh detail view context
-    if ($detailView) {
-      $.extend(
-        $detailView.data('view-args').context[
-          $detailView.data('view-args').section
-        ][0], newData
-      );
-    }
-  };
-
-  /**
-   * Available UI actions to perform for buttons
-   */
-  var uiActions = {
+    };
+
     /**
-     * Default behavior for actions -- just show a confirmation popup and add notification
+     * Available UI actions to perform for buttons
      */
-    standard: function($detailView, args, additional) {
-      var tab = args.tabs[args.activeTab];
-      var isMultiple = tab.multiple;
-      var action = isMultiple ? tab.actions[args.actionName] : args.actions[args.actionName];
-      var preAction = action.preAction;
-      var notification = action.notification ?
-            action.notification : {};
-      var messages = action.messages;
-      var id = args.id;
-      var context = $.extend(true, {},
-                             args.context ? args.context : $detailView.data('view-args').context);
-      var _custom = $detailView.data('_custom');
-      var customAction = action.action.custom;
-      var noAdd = action.noAdd;
-      var noRefresh = additional.noRefresh;
-      var messageArgs = {
-        name: $detailView.find('tr.name td.value').html(),
-        context: context
-      };
-
-      // Handle pre-action (occurs before any other behavior happens)
-      if (preAction) {
-        if (!preAction({ context: context })) return false;
-      }
-
-      var updateTabContent = function(newData) {
-        var $detailViewElems = $detailView.find('ul.ui-tabs-nav, .detail-group').remove();
-        var viewArgs = $detailView.data('view-args');
-        var context =  viewArgs.context;
-        var activeContextItem = viewArgs.section ? context[viewArgs.section][0] : null;
-        
-        $detailView.tabs('destroy');
-        $detailView.data('view-args').jsonObj = newData;
+    var uiActions = {
+        /**
+         * Default behavior for actions -- just show a confirmation popup and add notification
+         */
+        standard: function($detailView, args, additional) {
+            var tab = args.tabs[args.activeTab];
+            var isMultiple = tab.multiple;
+            var action = isMultiple ? tab.actions[args.actionName] : args.actions[args.actionName];
+            var preAction = action.preAction;
+            var notification = action.notification ?
+                action.notification : {};
+            var messages = action.messages;
+            var id = args.id;
+            var context = $.extend(true, {},
+                args.context ? args.context : $detailView.data('view-args').context);
+            var _custom = $detailView.data('_custom');
+            var customAction = action.action.custom;
+            var noAdd = action.noAdd;
+            var noRefresh = additional.noRefresh;
+            var messageArgs = {
+                name: $detailView.find('tr.name td.value').html(),
+                context: context
+            };
+
+            // Handle pre-action (occurs before any other behavior happens)
+            if (preAction) {
+                if (!preAction({
+                    context: context
+                })) return false;
+            }
 
-        if (activeContextItem) {
-          $.extend(activeContextItem, newData);
-        }
+            var updateTabContent = function(newData) {
+                var $detailViewElems = $detailView.find('ul.ui-tabs-nav, .detail-group').remove();
+                var viewArgs = $detailView.data('view-args');
+                var context = viewArgs.context;
+                var activeContextItem = viewArgs.section ? context[viewArgs.section][0] : null;
 
-        makeTabs(
-          $detailView,
-          $detailView.data('view-args').tabs,
-          {
-            context: context,
-            tabFilter: $detailView.data('view-args').tabFilter,
-            newData: newData
-          }
-        ).appendTo($detailView);
+                $detailView.tabs('destroy');
+                $detailView.data('view-args').jsonObj = newData;
 
-        $detailView.tabs();
-      };
+                if (activeContextItem) {
+                    $.extend(activeContextItem, newData);
+                }
 
-      var performAction = function(data, options) {
-        if (!options) options = {};
+                makeTabs(
+                    $detailView,
+                    $detailView.data('view-args').tabs, {
+                        context: context,
+                        tabFilter: $detailView.data('view-args').tabFilter,
+                        newData: newData
+                    }
+                ).appendTo($detailView);
 
-        var $form = options.$form;
-        var viewArgs = $detailView.data('view-args');
-        var $loading = $('<div>').addClass('loading-overlay');
+                $detailView.tabs();
+            };
 
-        var setLoadingState = function() {
-          if (viewArgs && viewArgs.onPerformAction) {
-            viewArgs.onPerformAction();
-          }
+            var performAction = function(data, options) {
+                if (!options) options = {};
 
-          $detailView.addClass('detail-view-loading-state');
-          $detailView.prepend($loading);
-        };
+                var $form = options.$form;
+                var viewArgs = $detailView.data('view-args');
+                var $loading = $('<div>').addClass('loading-overlay');
 
-        if (customAction && !noAdd) {
-          customAction({
-            context: context,
-            $detailView: $detailView,
-            start: setLoadingState,
-            complete: function(args) {
-              if (!$detailView.hasClass('detail-view-loading-state')) {
-                setLoadingState();
-              }
-              
-              args = args ? args : {};
-
-              var $item = args.$item;
-              var $row = $detailView.data('list-view-row');
-
-              notification.desc = messages.notification(args.messageArgs);
-              notification._custom = $.extend(args._custom ? args._custom : {}, {
-                $detailView: $detailView
-              });
-
-              cloudStack.ui.notifications.add(
-                notification,
-
-                // Success
-                function(args) {
-                  if (viewArgs && viewArgs.onActionComplete) {
-                    viewArgs.onActionComplete();
-                  }
-
-                  if (!$detailView.parents('html').size()) {
-                    replaceListViewItem(null, args.data, { $row: $row });
-                    return;
-                  }
-
-                  replaceListViewItem($detailView, args.data);
-                  $loading.remove();
-                  $detailView.removeClass('detail-view-loading-state');
-
-                  if (!noRefresh) {
-                    updateTabContent(args.data);
-                  }
-                },
+                var setLoadingState = function() {
+                    if (viewArgs && viewArgs.onPerformAction) {
+                        viewArgs.onPerformAction();
+                    }
 
-                {},
+                    $detailView.addClass('detail-view-loading-state');
+                    $detailView.prepend($loading);
+                };
+
+                if (customAction && !noAdd) {
+                    customAction({
+                        context: context,
+                        $detailView: $detailView,
+                        start: setLoadingState,
+                        complete: function(args) {
+                            if (!$detailView.hasClass('detail-view-loading-state')) {
+                                setLoadingState();
+                            }
+
+                            args = args ? args : {};
+
+                            var $item = args.$item;
+                            var $row = $detailView.data('list-view-row');
+
+                            notification.desc = messages.notification(args.messageArgs);
+                            notification._custom = $.extend(args._custom ? args._custom : {}, {
+                                $detailView: $detailView
+                            });
+
+                            cloudStack.ui.notifications.add(
+                                notification,
+
+                                // Success
+
+                                function(args) {
+                                    if (viewArgs && viewArgs.onActionComplete) {
+                                        viewArgs.onActionComplete();
+                                    }
+
+                                    if (!$detailView.parents('html').size()) {
+                                        replaceListViewItem(null, args.data, {
+                                            $row: $row
+                                        });
+                                        return;
+                                    }
+
+                                    replaceListViewItem($detailView, args.data);
+                                    $loading.remove();
+                                    $detailView.removeClass('detail-view-loading-state');
 
-                // Error
-                function(args) {
-                  $loading.remove();
+                                    if (!noRefresh) {
+                                        updateTabContent(args.data);
+                                    }
+                                },
+
+                                {},
+
+                                // Error
+
+                                function(args) {
+                                    $loading.remove();
+                                }
+                            );
+                        }
+                    });
+                } else {
+                    // Set loading appearance
+                    var $loading = $('<div>').addClass('loading-overlay');
+                    $detailView.prepend($loading);
+
+                    action.action({
+                        data: data,
+                        _custom: _custom,
+                        ref: options.ref,
+                        context: context,
+                        $form: $form,
+                        response: {
+                            success: function(args) {
+                                args = args ? args : {};
+                                notification._custom = $.extend(args._custom ? args._custom : {}, {
+                                    $detailView: $detailView
+                                });
+
+                                if (additional && additional.success) additional.success(args);
+
+                                // Setup notification
+                                cloudStack.ui.notifications.add(
+                                    notification,
+                                    function(args2) { //name parameter as "args2" instead of "args" to avoid override "args" from success: function(args) {
+                                        if ($detailView.parents('html').size()) {
+                                            $loading.remove();
+
+                                            if (!noRefresh && !viewArgs.compact) {
+                                                if (isMultiple) {
+                                                    $detailView.find('.refresh').click();
+                                                } else {
+                                                    updateTabContent(args.data ? args.data : args2.data);
+                                                }
+                                            }
+                                        }
+
+                                        if (messages.complete) {
+                                            cloudStack.dialog.notice({
+                                                message: messages.complete(args2.data)
+                                            });
+                                        }
+                                        if (additional && additional.complete) additional.complete($.extend(true, args, {
+                                            $detailView: $detailView
+                                        }));
+
+                                        replaceListViewItem($detailView, args.data ? args.data : args2.data);
+
+                                        if (viewArgs && viewArgs.onActionComplete) {
+                                            viewArgs.onActionComplete();
+                                        }
+                                    },
+
+                                    {},
+
+                                    // Error
+
+                                    function(args) {
+                                        $loading.remove();
+                                    }
+                                );
+
+                                return true;
+                            },
+                            error: function(args) { //args here is parsed errortext from API response
+                                if (args != null & args.length > 0) {
+                                    cloudStack.dialog.notice({
+                                        message: args
+                                    });
+                                }
+                                $loading.remove();
+                            }
+                        }
+                    });
+
+                    if (viewArgs && viewArgs.onPerformAction) {
+                        viewArgs.onPerformAction();
+                    }
+                }
+            };
+
+            var externalLinkAction = action.action.externalLink;
+            if (externalLinkAction) {
+                // Show popup immediately, do not proceed through normal action process
+                window.open(
+                    // URL
+                    externalLinkAction.url({
+                        context: context
+                    }),
+
+                    // Title
+                    externalLinkAction.title({
+                        context: context
+                    }),
+
+                    // Window options
+                    'menubar=0,resizable=0,' + 'width=' + externalLinkAction.width + ',' + 'height=' + externalLinkAction.height
+                );
+            } else {
+                notification.desc = messages.notification(messageArgs);
+                notification.section = 'instances';
+
+                if (!action.createForm && !action.listView) {
+                    if (messages && messages.confirm) {
+                        cloudStack.dialog.confirm({
+                            message: messages.confirm(messageArgs),
+                            action: function() {
+                                performAction({
+                                    id: id
+                                });
+                            }
+                        });
+                    } else {
+                        performAction({
+                            id: id
+                        });
+                    }
+                } else if (action.createForm) {
+                    cloudStack.dialog.createForm({
+                        form: action.createForm,
+                        after: function(args) {
+                            performAction(args.data, {
+                                ref: args.ref,
+                                context: context,
+                                $form: args.$form
+                            });
+                        },
+                        ref: {
+                            id: id
+                        },
+                        context: context
+                    });
+                } else if (action.listView) {
+                    cloudStack.dialog.listView({
+                        context: context,
+                        listView: action.listView,
+                        after: function(args) {
+                            context = args.context;
+                            performAction();
+                        }
+                    });
                 }
-              );
             }
-          });
-        } else {
-          // Set loading appearance
-          var $loading = $('<div>').addClass('loading-overlay');
-          $detailView.prepend($loading);
-
-          action.action({
-            data: data,
-            _custom: _custom,
-            ref: options.ref,
-            context: context,
-            $form: $form,
-            response: {
-              success: function(args) {
-                args = args ? args : {};
-                notification._custom = $.extend(args._custom ? args._custom : {}, {
-                  $detailView: $detailView
-                });
+        },
 
-                if (additional && additional.success) additional.success(args);
+        remove: function($detailView, args) {
+            var tab = args.tabs[args.activeTab];
+            var isMultiple = tab.multiple;
 
-                // Setup notification
-                cloudStack.ui.notifications.add(
-                  notification,
-                  function(args2) { //name parameter as "args2" instead of "args" to avoid override "args" from success: function(args) {
-                    if ($detailView.parents('html').size()) {
-                      $loading.remove();
+            uiActions.standard($detailView, args, {
+                noRefresh: true,
+                complete: function(args) {
+                    if (isMultiple && $detailView.is(':visible')) {
+                        $detailView.find('.refresh').click(); // Reload tab
+                    } else {
+                        var $browser = $('#browser .container');
+                        var $panel = $detailView.closest('.panel');
 
-                      if (!noRefresh && !viewArgs.compact) {
-                        if (isMultiple) {
-                          $detailView.find('.refresh').click();
-                        } else {
-                          updateTabContent(args.data? args.data : args2.data);
+                        if ($detailView.is(':visible')) {
+                            $browser.cloudBrowser('selectPanel', {
+                                panel: $panel.prev()
+                            });
                         }
-                      }
-                    }
 
-                    if (messages.complete) {
-                      cloudStack.dialog.notice({
-                        message: messages.complete(args2.data)
-                      });
+                        if ($detailView.data("list-view-row") != null) {
+                            var $row = $detailView.data('list-view-row');
+                            var $tbody = $row.closest('tbody');
+
+                            $row.remove();
+                            if (!$tbody.find('tr').size()) {
+                                $("<tr>").addClass('empty').append(
+                                    $("<td>").html(_l('label.no.data'))
+                                ).appendTo($tbody);
+                            }
+                            $tbody.closest('table').dataTable('refresh');
+                        }
                     }
-                    if (additional && additional.complete) additional.complete($.extend(true, args, {
-                      $detailView: $detailView
-                    }));
+                }
+            });
+        },
 
-                    replaceListViewItem($detailView, args.data ? args.data : args2.data);
+        /**
+         * Convert editable fields to text boxes; clicking again saves data
+         *
+         * @param $detailView
+         * @param callback
+         */
+        edit: function($detailView, args) {
+            $detailView.addClass('edit-mode');
+
+            if ($detailView.find('.button.done').size()) return false;
+
+            // Convert value TDs
+            var $inputs = $detailView.find('input, select').filter(function() {
+                return !$(this).closest('.tagger').size() && !$(this).attr('type') == 'submit';
+            });
+            var action = args.actions[args.actionName];
+            var id = $detailView.data('view-args').id;
+            var $editButton = $('<div>').addClass('button done').html(_l('label.apply')).hide();
+            var $cancelButton = $('<div>').addClass('button cancel').html(_l('label.cancel')).hide();
+
+            // Show buttons
+            $.merge($editButton, $cancelButton)
+                .appendTo(
+                    $detailView.find('.ui-tabs-panel .detail-group.actions')
+            ).fadeIn();
+
+            $detailView.find('.tagger').find('input[type=text]').val('');
+
+            $('div.container div.panel div.detail-group .details .main-groups').find('.cidr').toolTip({
+                docID: 'helpIPReservationCidr',
+                mode: 'hover',
+                tooltip: '.tooltip-box'
+            });
 
-                    if (viewArgs && viewArgs.onActionComplete) {
-                      viewArgs.onActionComplete();
+            var convertInputs = function($inputs) {
+                // Save and turn back into labels
+                $inputs.each(function() {
+                    if ($(this).closest('.tagger').size()) return true;
+
+                    var $input = $(this);
+                    var $value = $input.closest('td.value span');
+
+                    if ($input.is('input[type=text]'))
+                        $value.html(_s(
+                            $input.attr('value')
+                        ));
+                    else if ($input.is('input[type=checkbox]')) {
+                        var val = $input.is(':checked');
+
+                        $value.data('detail-view-boolean-value', _s(val));
+                        $value.html(_s(val) ? _l('label.yes') : _l('label.no'));
+                    } else if ($input.is('select')) {
+                        $value.html(_s(
+                            $input.find('option:selected').html()
+                        ));
+                        $value.data('detail-view-selected-option', _s($input.find('option:selected').val()));
                     }
-                  },
+                });
+            };
 
-                  {},
+            var removeEditForm = function() {
+                $detailView.removeClass('edit-mode');
+
+                // Remove Edit form
+                var $form = $detailView.find('form').filter(function() {
+                    return !$(this).closest('.tagger').size();
+                });
+                if ($form.size()) {
+                    var $mainGroups = $form.find('div.main-groups').detach();
+                    $form.parent('div').append($mainGroups);
+                    $form.remove();
+                }
+                //Remove required labels
+                $detailView.find('span.field-required').remove();
+            };
+
+            // Put in original values
+            var cancelEdits = function($inputs, $editButton) {
+                $inputs.each(function() {
+                    if ($(this).closest('.tagger').size()) return true;
+
+                    var $input = $(this);
+                    var $value = $input.closest('td.value span');
+                    var originalValue = $input.data('original-value');
+
+                    $value.html(_s(originalValue));
+                });
+
+                $editButton.fadeOut('fast', function() {
+                    $editButton.remove();
+                });
+
+                removeEditForm();
+            };
+
+            var applyEdits = function($inputs, $editButton) {
+                if ($inputs.size()) {
+                    $inputs.animate({
+                        opacity: 0.5
+                    }, 500);
+
+                    var data = {};
+                    $inputs.each(function() {
+                        var $input = $(this);
+
+                        if ($input.is('[type=checkbox]')) {
+                            data[$input.attr('name')] = $input.is(':checked') ? 'on' : 'off';
+                        } else {
+                            data[$input.attr('name')] = $input.val();
+                        }
+                    });
+
+                    $editButton.fadeOut('fast', function() {
+                        $editButton.remove();
+                    });
+
+                    var $loading = $('<div>').addClass('loading-overlay');
+
+                    action.action({
+                        data: data,
+                        _custom: $detailView.data('_custom'),
+                        context: $detailView.data('view-args').context,
+                        response: {
+                            success: function(args) {
+                                var notificationArgs = {
+                                    section: id,
+                                    desc: _l('changed.item.properties'),
+                                    _custom: args ? args._custom : null
+                                };
+
+                                if (!action.notification) {
+                                    convertInputs($inputs);
+                                    cloudStack.ui.notifications.add(
+                                        notificationArgs, function() {}, []
+                                    );
+                                    replaceListViewItem($detailView, data);
+                                    removeEditForm();
+                                } else {
+                                    $loading.appendTo($detailView);
+                                    cloudStack.ui.notifications.add(
+                                        $.extend(true, {}, action.notification, notificationArgs),
+                                        function(args) {
+                                            replaceListViewItem($detailView, data);
+
+                                            convertInputs($inputs);
+                                            removeEditForm();
+                                            $loading.remove();
+                                        }, [],
+                                        function() {
+                                            $loading.remove();
+                                            $inputs.closest('.detail-view').find('.toolbar .refresh').click();
+                                        }, []
+                                    );
+                                }
+                            },
+                            error: function(message) {
+                                cancelEdits($inputs, $editButton);
+                                if (message) cloudStack.dialog.notice({
+                                    message: message
+                                });
+                            }
+                        }
+                    });
+                }
+            };
+
+            $editButton.click(function() {
+                var $inputs = $detailView.find('input, select').filter(function() {
+                    return !$(this).closest('.tagger').size();
+                });
+                var $form = $detailView.find('form').filter(function() {
+                    return !$(this).closest('.tagger').size();
+                });
+
+                if ($(this).hasClass('done')) {
+                    if (!$form.valid()) {
+                        // Ignore hidden field validation
+                        if ($form.find('input.error:visible, select.error:visible').size()) {
+                            return false;
+                        }
+                    }
+                    applyEdits($inputs, $editButton);
+                } else { // Cancel
+                    cancelEdits($inputs, $editButton);
+                }
 
-                  // Error
-                  function(args) {
-                    $loading.remove();
-                  }
-                );
-								
                 return true;
-              },
-              error: function(args) {		//args here is parsed errortext from API response
-                if(args != null & args.length > 0) {
-                  cloudStack.dialog.notice({
-                    message: args
-                  });
+            });
+
+            $('div.container div.panel div.detail-group .details .main-groups').find('.reservediprange').toolTip({
+                docID: 'helpReservedIPRange',
+                mode: 'hover',
+                tooltip: '.tooltip-box'
+            });
+            $('div.container div.panel div.detail-group .details .main-groups').find('.networkcidr').toolTip({
+                docID: 'helpIPReservationNetworkCidr',
+                mode: 'hover',
+                tooltip: '.tooltip-box'
+            });
+
+
+            $detailView.find('td.value span').each(function() {
+                var name = $(this).closest('tr').data('detail-view-field');
+                var $value = $(this);
+                if (!$value.data('detail-view-is-editable')) return true;
+
+                // Turn into form field
+                var selectData = $value.data('detail-view-editable-select');
+                var isBoolean = $value.data('detail-view-editable-boolean');
+                var data = !isBoolean ? cloudStack.sanitizeReverse($value.html()) : $value.data('detail-view-boolean-value');
+                var rules = $value.data('validation-rules') ? $value.data('validation-rules') : {};
+
+                $value.html('');
+
+                if (selectData) {
+                    // Select
+                    $value.append(
+                        $('<select>')
+                        .attr({
+                            name: name,
+                            type: 'text',
+                            value: data
+                        })
+                        .data('original-value', data)
+                    );
+
+                    // Make option values from given array
+                    $(selectData).each(function() {
+                        $('<option>')
+                            .attr({
+                                value: _s(this.id)
+                            })
+                            .html(_s(this.description))
+                            .appendTo($value.find('select'));
+                    });
+
+                    $value.find('select').val($value.data('detail-view-selected-option'));
+                } else if (isBoolean) {
+                    $value.append(
+                        $('<input>').attr({
+                            name: name,
+                            type: 'checkbox',
+                            checked: data
+                        })
+                    );
+                } else {
+                    // Text input
+                    $value.append(
+                        $('<input>').attr({
+                            name: name,
+                            type: 'text',
+                            value: data
+                        }).data('original-value', data)
+                    );
                 }
-                $loading.remove();
-              }
+
+                if (rules && rules.required) {
+                    var $required = $('<span>').addClass('field-required').text(' *');
+                    $value.parent('td.value').prev('td.name').append($required);
+                }
+
+                return true;
+            });
+
+            if ($detailView.find('td.value span:data(detail-view-is-editable)').size()) {
+                var $detailsEdit = $detailView.find('div.main-groups').detach(),
+                    $detailsEditForm = $('<form>').append($detailsEdit);
+
+                $detailView.find('div.details').append($detailsEditForm);
             }
-          });
 
-          if (viewArgs && viewArgs.onPerformAction) {
-            viewArgs.onPerformAction();
-          }
+            // Setup form validation
+            var $form = $detailView.find('form').filter(function() {
+                return !$(this).closest('.tagger').size();
+            });
+            $form.validate();
+            $form.find('input, select').each(function() {
+                var data = $(this).parent('span').data('validation-rules');
+                if (data) {
+                    $(this).rules('add', data);
+                } else {
+                    $(this).rules('add', {});
+                }
+            });
+
+            return $detailView;
         }
-      };
-
-      var externalLinkAction = action.action.externalLink;
-      if (externalLinkAction) {
-        // Show popup immediately, do not proceed through normal action process
-        window.open(
-          // URL
-          externalLinkAction.url({
-            context: context
-          }),
-
-          // Title
-          externalLinkAction.title({
-            context: context
-          }),
-
-          // Window options
-          'menubar=0,resizable=0,'
-            + 'width=' + externalLinkAction.width + ','
-            + 'height=' + externalLinkAction.height
-        );
-      } else {
-        notification.desc = messages.notification(messageArgs);
-        notification.section = 'instances';
-
-        if (!action.createForm && !action.listView) {
-          if (messages && messages.confirm) {
-            cloudStack.dialog.confirm({
-              message: messages.confirm(messageArgs),
-              action: function() {
-                performAction({
-                  id: id
-                });
-              }
+    };
+
+    var viewAll = function(viewAllID, options) {
+        var $detailView = $('div.detail-view:last');
+        var args = $detailView.data('view-args');
+        var cloudStackArgs = $('[cloudstack-container]').data('cloudStack-args');
+        var $browser = args.$browser;
+        var listViewArgs, viewAllPath;
+        var $listView;
+        var isCustom = $.isFunction(viewAllID.custom);
+        var updateContext = options.updateContext;
+        var customTitle = options.title;
+
+        if (isCustom) {
+            $browser.cloudBrowser('addPanel', {
+                title: _l(viewAllID.label),
+                maximizeIfSelected: true,
+                complete: function($newPanel) {
+                    $newPanel.append(
+                        viewAllID.custom({
+                            $browser: $browser,
+                            context: $detailView.data('view-args').context,
+                            listViewArgs: $detailView.data('list-view') ? $detailView.data('list-view').data('view-args') : null
+                        })
+                    );
+                }
             });
-          } else {
-            performAction({ id: id });
-          }
-        } else if (action.createForm) {
-          cloudStack.dialog.createForm({
-            form: action.createForm,
-            after: function(args) {
-              performAction(args.data, {
-                ref: args.ref,
-                context: context,
-                $form: args.$form
-              });
-            },
-            ref: {
-              id: id
-            },
-            context: context
-          });
-        } else if (action.listView) {
-          cloudStack.dialog.listView({
-            context: context,
-            listView: action.listView,
-            after: function(args) {
-              context = args.context;
-              performAction();
-            }
-          });
+
+            return;
         }
-      }
-    },
-
-    remove: function($detailView, args) {
-      var tab = args.tabs[args.activeTab];
-      var isMultiple = tab.multiple;
-
-      uiActions.standard($detailView, args, {
-        noRefresh: true,
-        complete: function(args) {
-          if (isMultiple && $detailView.is(':visible')) {
-            $detailView.find('.refresh').click(); // Reload tab
-          } else {
-            var $browser = $('#browser .container');
-            var $panel = $detailView.closest('.panel');
-
-            if ($detailView.is(':visible')) {
-              $browser.cloudBrowser('selectPanel', {
-                panel: $panel.prev()
-              });
-            }
 
-            if($detailView.data("list-view-row") != null) {
-              var $row = $detailView.data('list-view-row');
-              var $tbody = $row.closest('tbody');
-
-              $row.remove();
-              if(!$tbody.find('tr').size()) {
-                $("<tr>").addClass('empty').append(
-                  $("<td>").html(_l('label.no.data'))
-                ).appendTo($tbody);
-              }
-              $tbody.closest('table').dataTable('refresh');
+        // Get path in cloudStack args
+        viewAllPath = viewAllID.split('.');
+
+        if (viewAllPath.length == 2) {
+            if (viewAllPath[0] != '_zone')
+                listViewArgs = cloudStackArgs.sections[viewAllPath[0]].sections[viewAllPath[1]];
+            else {
+                // Sub-section of the zone chart
+                listViewArgs = cloudStackArgs.sections.system
+                    .subsections[viewAllPath[1]];
             }
-          }
+        } else
+            listViewArgs = cloudStackArgs.sections[viewAllPath[0]];
+
+        // Make list view
+        listViewArgs.$browser = $browser;
+
+        if (viewAllPath.length == 2)
+            listViewArgs.id = viewAllPath[0];
+        else
+            listViewArgs.id = viewAllID;
+
+        listViewArgs.ref = {
+            id: args.id,
+            type: $detailView.data('view-args').section
+        };
+
+        // Load context data
+        var context = $.extend(true, {}, $detailView.data('view-args').context);
+
+        if (updateContext) {
+            $.extend(context, updateContext({
+                context: context
+            }));
         }
-      });
-    },
+
+        // Make panel
+        var $panel = $browser.cloudBrowser('addPanel', {
+            title: customTitle ? customTitle({
+                context: context
+            }) : _l(listViewArgs.title),
+            data: '',
+            noSelectPanel: true,
+            maximizeIfSelected: true,
+            complete: function($newPanel) {
+                return $('<div>').listView(listViewArgs, {
+                    context: context
+                }).appendTo($newPanel);
+            }
+        });
+    };
 
     /**
-     * Convert editable fields to text boxes; clicking again saves data
+     * Make action button elements
      *
-     * @param $detailView
-     * @param callback
+     * @param actions {object} Actions to generate
      */
-    edit: function($detailView, args) {
-      $detailView.addClass('edit-mode');
-
-      if ($detailView.find('.button.done').size()) return false;
-
-      // Convert value TDs
-      var $inputs = $detailView.find('input, select').filter(function() {
-        return !$(this).closest('.tagger').size() && !$(this).attr('type') == 'submit';
-      });
-      var action = args.actions[args.actionName];
-      var id = $detailView.data('view-args').id;
-      var $editButton = $('<div>').addClass('button done').html(_l('label.apply')).hide();
-      var $cancelButton = $('<div>').addClass('button cancel').html(_l('label.cancel')).hide();
-
-      // Show buttons
-      $.merge($editButton, $cancelButton)
-        .appendTo(
-          $detailView.find('.ui-tabs-panel .detail-group.actions')
-        ).fadeIn();
-
-      $detailView.find('.tagger').find('input[type=text]').val('');
-
-      $('div.container div.panel div.detail-group .details .main-groups').find('.cidr').toolTip({ docID:'helpIPReservationCidr' , mode:'hover' , tooltip:'.tooltip-box' });
-
-      var convertInputs = function($inputs) {
-        // Save and turn back into labels
-        $inputs.each(function() {
-          if ($(this).closest('.tagger').size()) return true;
-          
-          var $input = $(this);
-          var $value = $input.closest('td.value span');
-
-          if ($input.is('input[type=text]'))
-            $value.html(_s(
-              $input.attr('value')
-            ));
-          else if ($input.is('input[type=checkbox]')) {
-            var val = $input.is(':checked');
-
-            $value.data('detail-view-boolean-value', _s(val));
-            $value.html(_s(val) ? _l('label.yes') : _l('label.no'));
-          }
-          else if ($input.is('select')) {
-            $value.html(_s(
-              $input.find('option:selected').html()
-            ));
-            $value.data('detail-view-selected-option', _s($input.find('option:selected').val()));
-          }
-        });
-      };
-	    
-	    var removeEditForm = function() {
-        $detailView.removeClass('edit-mode');
-        
-		    // Remove Edit form
-		    var $form = $detailView.find('form').filter(function() {
-          return !$(this).closest('.tagger').size();
-        });
-		    if ($form.size()) {
-			    var $mainGroups = $form.find('div.main-groups').detach();
-			    $form.parent('div').append($mainGroups);
-			    $form.remove();
-		    }
-		    //Remove required labels
-		    $detailView.find('span.field-required').remove();
-	    };
-
-      // Put in original values
-      var cancelEdits = function($inputs, $editButton) {
-        $inputs.each(function() {
-          if ($(this).closest('.tagger').size()) return true;
-
-          var $input = $(this);
-          var $value = $input.closest('td.value span');
-          var originalValue = $input.data('original-value');
-
-          $value.html(_s(originalValue));
-        });
-
-        $editButton.fadeOut('fast', function() {
-          $editButton.remove();
-        });
-		    
-		    removeEditForm();
-      };
+    var makeActionButtons = function(actions, options) {
+        options = options ? options : {};
+        var $actions = $('<td>').addClass('detail-actions').append(
+            $('<div>').addClass('buttons')
+        );
 
-      var applyEdits = function($inputs, $editButton) {
-        if ($inputs.size()) {
-          $inputs.animate({ opacity: 0.5 }, 500);
+        var allowedActions = [];
 
-          var data = {};
-          $inputs.each(function() {
-            var $input = $(this);
+        if (actions) {
+            allowedActions = $.map(actions, function(value, key) {
+                return key;
+            });
 
-            if ($input.is('[type=checkbox]')) {
-              data[$input.attr('name')] = $input.is(':checked') ? 'on' : 'off';
-            } else {
-              data[$input.attr('name')] = $input.val();
-            }
-          });
+            if (options.actionFilter)
+                allowedActions = options.actionFilter({
+                    context: $.extend(true, {}, options.context, {
+                        actions: allowedActions,
+                        item: options.data
+                    })
+                });
 
-          $editButton.fadeOut('fast', function() {
-            $editButton.remove();
-          });
+            $.each(actions, function(key, value) {
+                if ($.inArray(key, allowedActions) == -1 ||
+                    (options.ignoreAddAction && key == 'add') ||
+                    (key == 'edit' && options.compact)) {
+                    return true;
+                }
 
-          var $loading = $('<div>').addClass('loading-overlay');
+                var $action = $('<div></div>')
+                    .addClass('action').addClass(key)
+                    .appendTo($actions.find('div.buttons'))
+                    .attr({
+                        title: _l(value.label),
+                        alt: _l(value.label)
+                    });
+                var $actionLink = $('<a></a>')
+                    .attr({
+                        href: '#',
+                        title: _l(value.label),
+                        alt: _l(value.label),
+                        'detail-action': key
+                    })
+                    .data('detail-view-action-callback', value.action)
+                    .append(
+                        $('<span>').addClass('icon').html('&nbsp;')
+                )
+                    .appendTo($action);
+
+                if (value.textLabel || options.compact) {
+                    $action
+                        .addClass('single text')
+                        .prepend(
+                            $('<span>').addClass('label').html(
+                                _l(
+                                    options.compact ?
+                                    (value.compactLabel ?
+                                        value.compactLabel : value.label) : value.textLabel
+                                )
+                            )
+                    );
+                }
 
-          action.action({
-            data: data,
-            _custom: $detailView.data('_custom'),
-            context: $detailView.data('view-args').context,
-            response: {
-              success: function(args) {
-                var notificationArgs = {
-                  section: id,
-                  desc: _l('changed.item.properties'),
-                  _custom: args ? args._custom : null
-                };
+                return true;
+            });
 
-                if (!action.notification) {
-                  convertInputs($inputs);
-                  cloudStack.ui.notifications.add(
-                    notificationArgs, function() {}, []
-                  );
-                  replaceListViewItem($detailView, data);
-				          removeEditForm();
-                } else {
-                  $loading.appendTo($detailView);
-                  cloudStack.ui.notifications.add(
-                    $.extend(true, {}, action.notification, notificationArgs),
-                    function(args) {
-                      replaceListViewItem($detailView, data);
-
-                      convertInputs($inputs);
-					            removeEditForm();
-                      $loading.remove();
-                    }, [],
-                    function() {
-                      $loading.remove();
-                      $inputs.closest('.detail-view').find('.toolbar .refresh').click();
-                    }, []
-                  );
-                }
-              },
-              error: function(message) {
-                cancelEdits($inputs, $editButton);
-                if (message) cloudStack.dialog.notice({ message: message });
-              }
+            var $actionButtons = $actions.find('div.action:not(.text)');
+            if ($actionButtons.size() == 1)
+                $actionButtons.addClass('single');
+            else {
+                $actionButtons.filter(':first').addClass('first');
+                $actionButtons.filter(':last').addClass('last');
             }
-          });
         }
-      };
 
-	    $editButton.click(function() {
-        var $inputs = $detailView.find('input, select').filter(function() {
-          return !$(this).closest('.tagger').size();
-        });
-			  var $form = $detailView.find('form').filter(function() {
-          return !$(this).closest('.tagger').size();
-        });
+        return $('<div>')
+            .addClass('detail-group actions')
+            .append(
+                $('<table>').append(
+                    $('<tbody>').append(
+                        $('<tr>').append($actions)
+                    )
+                )
+        );
+    };
 
-        if ($(this).hasClass('done')) {
-			    if (!$form.valid()) {
-				    // Ignore hidden field validation
-				    if ($form.find('input.error:visible, select.error:visible').size()) {
-					    return false;
-				    }
-			    }
-			    applyEdits($inputs, $editButton);
-        } else { // Cancel
-          cancelEdits($inputs, $editButton);
+    /**
+     * Generate attribute field rows in tab
+     */
+    var makeFieldContent = function(tabData, $detailView, data, args) {
+        if (!args) args = {};
+
+        var $detailGroups = $('<div>').addClass('details');
+        var isOddRow = false; // Even/odd row coloring
+        var $header;
+        var detailViewArgs = $detailView.data('view-args');
+        var fields = tabData.fields;
+        var hiddenFields;
+        var context = $.extend(true, {}, detailViewArgs ? detailViewArgs.context : cloudStack.context);
+        var isMultiple = tabData.multiple || tabData.isMultiple;
+        var actions = tabData.actions;
+
+        if (isMultiple) {
+            context[tabData.id] = [data];
+            $detailGroups.data('item-context', context);
         }
 
-        return true;
-      });
-	   
-         $('div.container div.panel div.detail-group .details .main-groups').find('.reservediprange').toolTip({ docID:'helpReservedIPRange' , mode:'hover' , tooltip:'.tooltip-box' });
-          $('div.container div.panel div.detail-group .details .main-groups').find('.networkcidr').toolTip({ docID:'helpIPReservationNetworkCidr' , mode:'hover' , tooltip:'.tooltip-box' });
-
- 
-	    $detailView.find('td.value span').each(function() {
-        var name = $(this).closest('tr').data('detail-view-field');
-        var $value = $(this);
-        if (!$value.data('detail-view-is-editable')) return true;
-
-        // Turn into form field
-        var selectData = $value.data('detail-view-editable-select');
-        var isBoolean = $value.data('detail-view-editable-boolean');
-        var data = !isBoolean ? cloudStack.sanitizeReverse($value.html()) : $value.data('detail-view-boolean-value');
-		    var rules = $value.data('validation-rules') ? $value.data('validation-rules') : {};
-
-        $value.html('');
-
-        if (selectData) {
-          // Select
-          $value.append(
-            $('<select>')
-              .attr({
-                name: name,
-                type: 'text',
-                value: data
-              })
-              .data('original-value', data)
-          );
-
-          // Make option values from given array
-          $(selectData).each(function() {
-            $('<option>')
-              .attr({
-                value: _s(this.id)
-              })
-              .html(_s(this.description))
-              .appendTo($value.find('select'));
-          });
-
-          $value.find('select').val($value.data('detail-view-selected-option'));
-        } else if (isBoolean) {
-          $value.append(
-            $('<input>').attr({
-              name: name,
-              type: 'checkbox',
-              checked: data
-            })
-          );
-        } else {
-          // Text input
-          $value.append(
-            $('<input>').attr({
-              name: name,
-              type: 'text',
-              value: data
-			      }).data('original-value', data)
-          );
+        // Make header
+        if (args.header) {
+            $detailGroups.addClass('group-multiple');
+            $header = $('<table>').addClass('header').appendTo($detailGroups);
+            $header.append($('<thead>').append($('<tr>')));
+            $header.find('tr').append($('<th>'));
         }
-		    
-		    if (rules && rules.required) {
-		      var $required = $('<span>').addClass('field-required').text(' *');
-		      $value.parent('td.value').prev('td.name').append($required);
-		    }
 
-        return true;
-      });
-
-		  if ($detailView.find('td.value span:data(detail-view-is-editable)').size()) {
-			  var $detailsEdit = $detailView.find('div.main-groups').detach(),
-				 $detailsEditForm = $('<form>').append($detailsEdit);
-
-			  $detailView.find('div.details').append($detailsEditForm);
-		  }
-	    
-		  // Setup form validation
-      var $form = $detailView.find('form').filter(function() {
-        return !$(this).closest('.tagger').size();
-      });
-		  $form.validate();
-		  $form.find('input, select').each(function() {
-			  var data = $(this).parent('span').data('validation-rules');
-			  if (data) {
-				  $(this).rules('add', data);
-			  } else {
-			    $(this).rules('add', {});
-			  }
-		  });
-
-      return $detailView;
-    }
-  };
-
-  var viewAll = function(viewAllID, options) {
-    var $detailView = $('div.detail-view:last');
-    var args = $detailView.data('view-args');
-    var cloudStackArgs = $('[cloudstack-container]').data('cloudStack-args');
-    var $browser = args.$browser;
-    var listViewArgs, viewAllPath;
-    var $listView;
-    var isCustom = $.isFunction(viewAllID.custom);
-    var updateContext = options.updateContext;
-    var customTitle = options.title;
-    
-    if (isCustom) {
-      $browser.cloudBrowser('addPanel', {
-        title: _l(viewAllID.label),
-        maximizeIfSelected: true,
-        complete: function($newPanel) {
-          $newPanel.append(
-            viewAllID.custom({
-              $browser: $browser,
-              context: $detailView.data('view-args').context,
-              listViewArgs: $detailView.data('list-view') ?
-                $detailView.data('list-view').data('view-args') : null
-            })
-          );
+        if (tabData.preFilter) {
+            hiddenFields = tabData.preFilter({
+                context: context,
+                fields: $.map(fields, function(fieldGroup) {
+                    return $.map(fieldGroup, function(value, key) {
+                        return key;
+                    });
+                })
+            });
         }
-      });
-
-      return;
-    }
-
-    // Get path in cloudStack args
-    viewAllPath = viewAllID.split('.');
-
-    if (viewAllPath.length == 2) {
-      if (viewAllPath[0] != '_zone')
-        listViewArgs = cloudStackArgs.sections[viewAllPath[0]].sections[viewAllPath[1]];
-      else {
-        // Sub-section of the zone chart
-        listViewArgs = cloudStackArgs.sections.system
-          .subsections[viewAllPath[1]];
-      }
-    }
-    else
-      listViewArgs = cloudStackArgs.sections[viewAllPath[0]];
-
-    // Make list view
-    listViewArgs.$browser = $browser;
-
-    if (viewAllPath.length == 2)
-      listViewArgs.id = viewAllPath[0];
-    else
-      listViewArgs.id = viewAllID;
-
-    listViewArgs.ref = {
-      id: args.id,
-      type: $detailView.data('view-args').section
-    };
 
-    // Load context data
-    var context = $.extend(true, {}, $detailView.data('view-args').context);
-
-    if (updateContext) {
-      $.extend(context, updateContext({ context: context }));
-    }
-
-    // Make panel
-    var $panel = $browser.cloudBrowser('addPanel', {
-      title: customTitle ? customTitle({ context: context }) : _l(listViewArgs.title),
-      data: '',
-      noSelectPanel: true,
-      maximizeIfSelected: true,
-      complete: function($newPanel) {
-        return $('<div>').listView(listViewArgs, { context: context }).appendTo($newPanel);
-      }
-    });
-  };
-
-  /**
-   * Make action button elements
-   *
-   * @param actions {object} Actions to generate
-   */
-  var makeActionButtons = function(actions, options) {
-    options = options ? options : {};
-    var $actions = $('<td>').addClass('detail-actions').append(
-      $('<div>').addClass('buttons')
-    );
-
-    var allowedActions = [];
-
-    if (actions) {
-      allowedActions = $.map(actions, function(value, key) {
-        return key;
-      });
-
-      if (options.actionFilter)
-        allowedActions = options.actionFilter({
-          context: $.extend(true, {}, options.context, {
-            actions: allowedActions,
-            item: options.data
-          })
-        });
+        $detailGroups.append($('<div>').addClass('main-groups'));
 
-      $.each(actions, function(key, value) {
-        if ($.inArray(key, allowedActions) == -1 ||
-            (options.ignoreAddAction && key == 'add') ||
-            (key == 'edit' && options.compact)) {
-          return true;
-        }
+        $(fields).each(function() {
+            var fieldGroup = this;
 
-        var $action = $('<div></div>')
-              .addClass('action').addClass(key)
-              .appendTo($actions.find('div.buttons'))
-              .attr({
-                title: _l(value.label),
-                alt: _l(value.label)
-              });
-        var $actionLink = $('<a></a>')
-              .attr({
-                href: '#',
-                title: _l(value.label),
-                alt: _l(value.label),
-                'detail-action': key
-              })
-              .data('detail-view-action-callback', value.action)
-              .append(
-                $('<span>').addClass('icon').html('&nbsp;')
-              )
-              .appendTo($action);
-
-        if (value.textLabel || options.compact) {
-          $action
-            .addClass('single text')
-            .prepend(
-              $('<span>').addClass('label').html(
-                _l(
-                  options.compact ?
-                    (value.compactLabel ?
-                     value.compactLabel : value.label) : value.textLabel
-                )
-              )
-            );
-        }
+            var $detailTable = $('<tbody></tbody>').appendTo(
+                $('<table></table>').appendTo(
+                    $('<div></div>').addClass('detail-group').appendTo($detailGroups.find('.main-groups'))
+                ));
 
-        return true;
-      });
-
-      var $actionButtons = $actions.find('div.action:not(.text)');
-      if ($actionButtons.size() == 1)
-        $actionButtons.addClass('single');
-      else {
-        $actionButtons.filter(':first').addClass('first');
-        $actionButtons.filter(':last').addClass('last');
-      }
-    }
-
-    return $('<div>')
-      .addClass('detail-group actions')
-      .append(
-        $('<table>').append(
-          $('<tbody>').append(
-            $('<tr>').append($actions)
-          )
-        )
-      );
-  };
-
-  /**
-   * Generate attribute field rows in tab
-   */
-  var makeFieldContent = function(tabData, $detailView, data, args) {
-    if (!args) args = {};
-
-    var $detailGroups = $('<div>').addClass('details');
-    var isOddRow = false; // Even/odd row coloring
-    var $header;
-    var detailViewArgs = $detailView.data('view-args');
-    var fields = tabData.fields;
-    var hiddenFields;
-    var context = $.extend(true, {}, detailViewArgs ? detailViewArgs.context : cloudStack.context);
-    var isMultiple = tabData.multiple || tabData.isMultiple;
-    var actions = tabData.actions;
-
-    if (isMultiple) {
-      context[tabData.id] = [data];
-      $detailGroups.data('item-context', context);
-    }
-
-    // Make header
-    if (args.header) {
-      $detailGroups.addClass('group-multiple');
-      $header = $('<table>').addClass('header').appendTo($detailGroups);
-      $header.append($('<thead>').append($('<tr>')));
-      $header.find('tr').append($('<th>'));
-    }
-
-    if (tabData.preFilter) {
-      hiddenFields = tabData.preFilter({
-        context: context,
-        fields: $.map(fields, function(fieldGroup) {
-          return $.map(fieldGroup, function(value, key) { return key; });
-        })
-      });
-    }
-
-    $detailGroups.append($('<div>').addClass('main-groups'));
-
-    $(fields).each(function() {
-      var fieldGroup = this;
-
-      var $detailTable = $('<tbody></tbody>').appendTo(
-        $('<table></table>').appendTo(
-          $('<div></div>').addClass('detail-group').appendTo($detailGroups.find('.main-groups'))
-        ));
-
-      $.each(fieldGroup, function(key, value) {
-        if (hiddenFields && $.inArray(key, hiddenFields) >= 0) return true;
-        if ($header && key == args.header) {
-          $header.find('th').html(_s(data[key]));
-          return true;
-        }
+            $.each(fieldGroup, function(key, value) {
+                if (hiddenFields && $.inArray(key, hiddenFields) >= 0) return true;
+                if ($header && key == args.header) {
+                    $header.find('th').html(_s(data[key]));
+                    return true;
+                }
 
-        var $detail = $('<tr></tr>').addClass(key).appendTo($detailTable);
-        var $name = $('<td></td>').addClass('name').appendTo($detail);
-        var $value = $('<span>').appendTo($('<td></td>').addClass('value').appendTo($detail));
-        var content = data[key];
+                var $detail = $('<tr></tr>').addClass(key).appendTo($detailTable);
+                var $name = $('<td></td>').addClass('name').appendTo($detail);
+                var $value = $('<span>').appendTo($('<td></td>').addClass('value').appendTo($detail));
+                var content = data[key];
 
-        if (this.converter) content = this.converter(content);
+                if (this.converter) content = this.converter(content);
 
-        $detail.data('detail-view-field', key);
+                $detail.data('detail-view-field', key);
 
-        // Even/odd row coloring
-        if (isOddRow && key != 'name') {
-          $detail.addClass('odd');
-          isOddRow = false;
-        } else if (key != 'name') {
-          isOddRow = true;
-        }
-				
-				//???
-				/*
-				 if("pollAgainIfValueIsIn" in value) {				  
+                // Even/odd row coloring
+                if (isOddRow && key != 'name') {
+                    $detail.addClass('odd');
+                    isOddRow = false;
+                } else if (key != 'name') {
+                    isOddRow = true;
+                }
+
+                //???
+                /*
+				 if("pollAgainIfValueIsIn" in value) {
 				 if ((content in value.pollAgainIfValueIsIn) && (value.pollAgainFn != null)) {
-				 //poll again 
-				 var intervalKey = setInterval(function() {						  
-				 var toClearInterval = value.pollAgainFn(context);							
+				 //poll again
+				 var intervalKey = setInterval(function() {
+				 var toClearInterval = value.pollAgainFn(context);
 				 if(toClearInterval == true) {
-				 clearInterval(intervalKey);		
-				 $('.detail-view .toolbar .button.refresh').click();	 //click Refresh button to refresh detailView				
+				 clearInterval(intervalKey);
+				 $('.detail-view .toolbar .button.refresh').click();	 //click Refresh button to refresh detailView
 				 }
-				 }, 2000);						            
+				 }, 2000);
 				 }
 				 }
 				 */
-				
-        $name.html(_l(value.label));
-        $value.html(_s(content));
-
-        // Set up validation metadata
-        $value.data('validation-rules', value.validation);
-
-        // Set up editable metadata				
-				if(typeof(value.isEditable) == 'function')
-				  $value.data('detail-view-is-editable', value.isEditable(context));
-				else //typeof(value.isEditable) == 'boolean' or 'undefined'
-          $value.data('detail-view-is-editable', value.isEditable);
-        if (value.select) {
-          value.selected = $value.html();
-
-          value.select({
-            context: context,
-            response: {
-              success: function(args) {
-                // Get matching select data
-                var matchedSelectValue = $.grep(args.data, function(option, index) {
-                  return option.id == value.selected;
-                })[0];
-
-                if(matchedSelectValue != null) {
-                  $value.html(_s(matchedSelectValue.description));
-                  $value.data('detail-view-selected-option', matchedSelectValue.id);
-                }
 
-                $value.data('detail-view-editable-select', args.data);
+                $name.html(_l(value.label));
+                $value.html(_s(content));
+
+                // Set up validation metadata
+                $value.data('validation-rules', value.validation);
+
+                // Set up editable metadata
+                if (typeof(value.isEditable) == 'function')
+                    $value.data('detail-view-is-editable', value.isEditable(context));
+                else //typeof(value.isEditable) == 'boolean' or 'undefined'
+                    $value.data('detail-view-is-editable', value.isEditable);
+                if (value.select) {
+                    value.selected = $value.html();
+
+                    value.select({
+                        context: context,
+                        response: {
+                            success: function(args) {
+                                // Get matching select data
+                                var matchedSelectValue = $.grep(args.data, function(option, index) {
+                                    return option.id == value.selected;
+                                })[0];
+
+                                if (matchedSelectValue != null) {
+                                    $value.html(_s(matchedSelectValue.description));
+                                    $value.data('detail-view-selected-option', matchedSelectValue.id);
+                                }
+
+                                $value.data('detail-view-editable-select', args.data);
+
+                                return true;
+                            }
+                        }
+                    });
+                } else if (value.isBoolean) {
+                    $value.data('detail-view-editable-boolean', true);
+                    $value.data('detail-view-boolean-value', content == 'Yes' ? true : false);
+                }
 
                 return true;
-              }
-            }
-          });
-        } else if (value.isBoolean) {
-          $value.data('detail-view-editable-boolean', true);
-          $value.data('detail-view-boolean-value', content == 'Yes' ? true : false);
-        }
-
-        return true;
-      });
-    });
+            });
+        });
 
-    if (args.isFirstPanel) {
-      var $firstRow = $detailGroups.filter(':first').find('div.detail-group:first table tr:first');
-      var $actions;
-      var actions = detailViewArgs.actions;
-      var actionFilter = args.actionFilter;
-
-      // Detail view actions
-      if (actions || detailViewArgs.viewAll)
-        $actions = makeActionButtons(detailViewArgs.actions, {
-          actionFilter: actionFilter,
-          data: data,
-          context: $detailView.data('view-args').context,
-          compact: detailViewArgs.compact
-        }).prependTo($firstRow.closest('div.detail-group').closest('.details'));
-
-      // 'View all' button
-      var showViewAll = detailViewArgs.viewAll ?
-            (
-              detailViewArgs.viewAll.preFilter ?
+        if (args.isFirstPanel) {
+            var $firstRow = $detailGroups.filter(':first').find('div.detail-group:first table tr:first');
+            var $actions;
+            var actions = detailViewArgs.actions;
+            var actionFilter = args.actionFilter;
+
+            // Detail view actions
+            if (actions || detailViewArgs.viewAll)
+                $actions = makeActionButtons(detailViewArgs.actions, {
+                    actionFilter: actionFilter,
+                    data: data,
+                    context: $detailView.data('view-args').context,
+                    compact: detailViewArgs.compact
+                }).prependTo($firstRow.closest('div.detail-group').closest('.details'));
+
+            // 'View all' button
+            var showViewAll = detailViewArgs.viewAll ?
+                (
+                detailViewArgs.viewAll.preFilter ?
                 detailViewArgs.viewAll.preFilter({
-                  context: context
+                    context: context
                 }) : true
             ) : true;
-      if ($actions && ($actions.find('div.action').size() || (detailViewArgs.viewAll && showViewAll))) {
-        $actions.prependTo($firstRow.closest('div.detail-group').closest('.details'));
-      }
-      if (detailViewArgs.viewAll && showViewAll) {
-        if (!$.isArray(detailViewArgs.viewAll)) {
-          $('<div>')
-            .addClass('view-all')
-            .append(
-              $('<a>')
-                .attr({ href: '#' })
-                .data('detail-view-link-view-all', detailViewArgs.viewAll)
-                .append(
-                  $('<span>').html(_l('label.view') + ' ' + _l(detailViewArgs.viewAll.label))
-                )
-            )
-            .append(
-              $('<div>').addClass('end')
-            )
-            .appendTo(
-              $('<td>')
-                .addClass('view-all')
-                .appendTo($actions.find('tr'))
-            );
-        } else {
-          $(detailViewArgs.viewAll).each(function() {
-            var viewAllItem = this;
+            if ($actions && ($actions.find('div.action').size() || (detailViewArgs.viewAll && showViewAll))) {
+                $actions.prependTo($firstRow.closest('div.detail-group').closest('.details'));
+            }
+            if (detailViewArgs.viewAll && showViewAll) {
+                if (!$.isArray(detailViewArgs.viewAll)) {
+                    $('<div>')
+                        .addClass('view-all')
+                        .append(
+                            $('<a>')
+                            .attr({
+                                href: '#'
+                            })
+                            .data('detail-view-link-view-all', detailViewArgs.viewAll)
+                            .append(
+                                $('<span>').html(_l('label.view') + ' ' + _l(detailViewArgs.viewAll.label))
+                            )
+                    )
+                        .append(
+                            $('<div>').addClass('end')
+                    )
+                        .appendTo(
+                            $('<td>')
+                            .addClass('view-all')
+                            .appendTo($actions.find('tr'))
+                    );
+                } else {
+                    $(detailViewArgs.viewAll).each(function() {
+                        var viewAllItem = this;
 
-            if (viewAllItem.preFilter &&
-                !viewAllItem.preFilter({ context: context })) {
-              return true;
+                        if (viewAllItem.preFilter && !viewAllItem.preFilter({
+                            context: context
+                        })) {
+                            return true;
+                        }
+
+                        $('<div>')
+                            .addClass('view-all')
+                            .append(
+                                $('<a>')
+                                .attr({
+                                    href: '#'
+                                })
+                                .data('detail-view-link-view-all', viewAllItem)
+                                .append(
+                                    $('<span>').html(_l('label.view') + ' ' + _l(viewAllItem.label))
+                                )
+                        )
+                            .append(
+                                $('<div>').addClass('end')
+                        )
+                            .appendTo(
+                                $('<td>')
+                                .addClass('view-all multiple')
+                                .appendTo($actions.find('tr'))
+                        );
+
+                        $actions.find('td.view-all:first').addClass('first');
+                        $actions.find('td.view-all:last').addClass('last');
+                        $actions.find('td.detail-actions').addClass('full-length');
+                    });
+                }
             }
+        }
+
+        return $detailGroups;
+    };
 
-            $('<div>')
-              .addClass('view-all')
-              .append(
-                $('<a>')
-                  .attr({ href: '#' })
-                  .data('detail-view-link-view-all', viewAllItem)
-                  .append(
-                    $('<span>').html(_l('label.view') + ' ' + _l(viewAllItem.label))
-                  )
-              )
-              .append(
-                $('<div>').addClass('end')
-              )
-              .appendTo(
-                $('<td>')
-                  .addClass('view-all multiple')
-                  .appendTo($actions.find('tr'))
-              );
-
-            $actions.find('td.view-all:first').addClass('first');
-            $actions.find('td.view-all:last').addClass('last');
-            $actions.find('td.detail-actions').addClass('full-length');
-          });
+    /**
+     * Load field data for specific tab from data provider
+     *
+     * @param $tabContent {jQuery} tab div to load content into
+     * @param args {object} Detail view data
+     * @param options {object} Additional options
+     */
+    var loadTabContent = function($tabContent, args, options) {
+        if (!options) options = {};
+        $tabContent.html('');
+
+        var targetTabID = $tabContent.data('detail-view-tab-id');
+        var tabList = args.tabs;
+        var tabs = tabList[targetTabID];
+        var dataProvider = tabs.dataProvider;
+        var isMultiple = tabs.multiple || tabs.isMultiple;
+        var viewAllArgs = args.viewAll;
+        var $detailView = $tabContent.closest('.detail-view');
+        var jsonObj = $detailView.data('view-args').jsonObj;
+
+        if (tabs.custom) {
+            return tabs.custom({
+                context: args.context
+            }).appendTo($tabContent);
         }
-      }
-    }
-
-    return $detailGroups;
-  };
-
-  /**
-   * Load field data for specific tab from data provider
-   *
-   * @param $tabContent {jQuery} tab div to load content into
-   * @param args {object} Detail view data
-   * @param options {object} Additional options
-   */
-  var loadTabContent = function($tabContent, args, options) {
-    if (!options) options = {};
-    $tabContent.html('');
-
-    var targetTabID = $tabContent.data('detail-view-tab-id');
-    var tabList = args.tabs;
-    var tabs = tabList[targetTabID];
-    var dataProvider = tabs.dataProvider;
-    var isMultiple = tabs.multiple || tabs.isMultiple;
-    var viewAllArgs = args.viewAll;
-    var $detailView = $tabContent.closest('.detail-view');
-    var jsonObj = $detailView.data('view-args').jsonObj;
-
-    if (tabs.custom) {
-      return tabs.custom({
-        context: args.context
-      }).appendTo($tabContent);
-    }
-
-    $detailView.find('.detail-group:hidden').html('');
-
-    if (tabs.listView) {
-      return $('<div>').listView({
-        context: args.context,
-        listView: tabs.listView
-      }).appendTo($tabContent);
-    }
-
-    $.extend(
-      $detailView.data('view-args'),
-      { activeTab: targetTabID }
-    );
-
-    if (!$detailView.data('view-args').compact) {
-      $tabContent.append(
-        $('<div>').addClass('loading-overlay')
-      );
-    }
-
-    return dataProvider({
-      tab: targetTabID,
-      id: args.id,
-      jsonObj: jsonObj,
-      context: args.context,
-      response: {
-        success: function(args) {
-          if (options.newData) {
-            $.extend(args.data, options.newData);
-          }
-
-          if (args._custom) {
-            $detailView.data('_custom', args._custom);
-          }
-          var tabData = $tabContent.data('detail-view-tab-data');
-          var data = args.data;
-
-          var isFirstPanel = $tabContent.index($detailView.find('div.detail-group.ui-tabs-panel')) == 0;
-          var actionFilter = args.actionFilter;
-
-          $tabContent.find('.loading-overlay').remove();
-
-          if (isMultiple) {
-            $(data).each(function() {
-              var item = this;
-
-              var $fieldContent = makeFieldContent(
-                $.extend(true, {}, tabs, {
-                  id: targetTabID
-                }),
-                $tabContent.closest('div.detail-view'), this, {
-                  header: 'name',
-                  isFirstPanel: isFirstPanel,
-                  actionFilter: actionFilter
-                }
-              ).appendTo($tabContent);
-
-              if (tabData.viewAll) {
-                $fieldContent.find('tr')
-                  .filter('.' + tabData.viewAll.attachTo).find('td.value')
-                  .append(
-                    $('<div>').addClass('view-all').append(
-                      $('<span>').html(
-                        tabData.viewAll.label ?
-                          _l(tabData.viewAll.label) :
-                          _l('label.view.all')
-                      ),
-                      $('<div>').addClass('end')
-                    ).click(function() {
-                      viewAll(
-                        tabData.viewAll.path,
-                        {
-                          updateContext: function(args) {
-                            var obj = {};
-
-                            obj[targetTabID] = [item];
-
-                            return obj;
-                          },
-                          title: tabData.viewAll.title
-                        }
-                      ); 
-                    })
-                  );
-              }
-
-              // Add action bar
-              if (tabData.multiple && tabData.actions) {
-                var $actions = makeActionButtons(tabData.actions, {
-                  actionFilter: actionFilter,
-                  data: item,
-                  context: $.extend(true, {}, $detailView.data('view-args').context, {
-                    item: [item]
-                  }),
-                  ignoreAddAction: true
-                });
 
-                $fieldContent.find('th').append($actions);
-              }
-            });
+        $detailView.find('.detail-group:hidden').html('');
 
-            // Add item action
-            if (tabData.multiple && tabData.actions && tabData.actions.add) {
-              $tabContent.prepend(
-                $('<div>').addClass('button add').append(
-                  $('<span>').addClass('icon').html('&nbsp;'),
-                  $('<span>').html(_l(tabData.actions.add.label))
-                ).click(function() {
-                  uiActions.standard(
-                    $detailView,
-                    {
-                      tabs: tabList,
-                      activeTab: targetTabID,
-                      actions: tabData.actions,
-                      actionName: 'add'
-                    }, {
-                      noRefresh: true,
-                      complete: function(args) {
-                        if ($detailView.is(':visible')) {
-                          loadTabContent(
-                            $detailView.find('div.detail-group:visible'),
-                            $detailView.data('view-args')
-                          );
+        if (tabs.listView) {
+            return $('<div>').listView({
+                context: args.context,
+                listView: tabs.listView
+            }).appendTo($tabContent);
+        }
+
+        $.extend(
+            $detailView.data('view-args'), {
+                activeTab: targetTabID
+            }
+        );
+
+        if (!$detailView.data('view-args').compact) {
+            $tabContent.append(
+                $('<div>').addClass('loading-overlay')
+            );
+        }
+
+        return dataProvider({
+            tab: targetTabID,
+            id: args.id,
+            jsonObj: jsonObj,
+            context: args.context,
+            response: {
+                success: function(args) {
+                    if (options.newData) {
+                        $.extend(args.data, options.newData);
+                    }
+
+                    if (args._custom) {
+                        $detailView.data('_custom', args._custom);
+                    }
+                    var tabData = $tabContent.data('detail-view-tab-data');
+                    var data = args.data;
+
+                    var isFirstPanel = $tabContent.index($detailView.find('div.detail-group.ui-tabs-panel')) == 0;
+                    var actionFilter = args.actionFilter;
+
+                    $tabContent.find('.loading-overlay').remove();
+
+                    if (isMultiple) {
+                        $(data).each(function() {
+                            var item = this;
+
+                            var $fieldContent = makeFieldContent(
+                                $.extend(true, {}, tabs, {
+                                    id: targetTabID
+                                }),
+                                $tabContent.closest('div.detail-view'), this, {
+                                    header: 'name',
+                                    isFirstPanel: isFirstPanel,
+                                    actionFilter: actionFilter
+                                }
+                            ).appendTo($tabContent);
+
+                            if (tabData.viewAll) {
+                                $fieldContent.find('tr')
+                                    .filter('.' + tabData.viewAll.attachTo).find('td.value')
+                                    .append(
+                                        $('<div>').addClass('view-all').append(
+                                            $('<span>').html(
+                                                tabData.viewAll.label ?
+                                                _l(tabData.viewAll.label) :
+                                                _l('label.view.all')
+                                            ),
+                                            $('<div>').addClass('end')
+                                        ).click(function() {
+                                            viewAll(
+                                                tabData.viewAll.path, {
+                                                    updateContext: function(args) {
+                                                        var obj = {};
+
+                                                        obj[targetTabID] = [item];
+
+                                                        return obj;
+                                                    },
+                                                    title: tabData.viewAll.title
+                                                }
+                                            );
+                                        })
+                                );
+                            }
+
+                            // Add action bar
+                            if (tabData.multiple && tabData.actions) {
+                                var $actions = makeActionButtons(tabData.actions, {
+                                    actionFilter: actionFilter,
+                                    data: item,
+                                    context: $.extend(true, {}, $detailView.data('view-args').context, {
+                                        item: [item]
+                                    }),
+                                    ignoreAddAction: true
+                                });
+
+                                $fieldContent.find('th').append($actions);
+                            }
+                        });
+
+                        // Add item action
+                        if (tabData.multiple && tabData.actions && tabData.actions.add) {
+                            $tabContent.prepend(
+                                $('<div>').addClass('button add').append(
+                                    $('<span>').addClass('icon').html('&nbsp;'),
+                                    $('<span>').html(_l(tabData.actions.add.label))
+                                ).click(function() {
+                                    uiActions.standard(
+                                        $detailView, {
+                                            tabs: tabList,
+                                            activeTab: targetTabID,
+                                            actions: tabData.actions,
+                                            actionName: 'add'
+                                        }, {
+                                            noRefresh: true,
+                                            complete: function(args) {
+                                                if ($detailView.is(':visible')) {
+                                                    loadTabContent(
+                                                        $detailView.find('div.detail-group:visible'),
+                                                        $detailView.data('view-args')
+                                                    );
+                                                }
+                                            }
+                                        }
+                                    )
+                                })
+                            );
                         }
-                      }
+
+                        return true;
                     }
-                  )
-                })
-              );
+
+                    makeFieldContent(tabs, $tabContent.closest('div.detail-view'), data, {
+                        isFirstPanel: isFirstPanel,
+                        actionFilter: actionFilter
+                    }).appendTo($tabContent);
+
+                    if (tabs.tags &&
+                        $detailView.data('view-args') && !$detailView.data('view-args').compact) {
+                        $('<div>').tagger(
+                            $.extend(true, {}, tabs.tags, {
+                                context: $detailView.data('view-args').context,
+                                jsonObj: $detailView.data('view-args').jsonObj
+                            })
+                        ).appendTo($detailView.find('.main-groups'));
+                    }
+
+                    if ($detailView.data('view-args').onLoad) {
+                        $detailView.data('view-args').onLoad($detailView);
+                    }
+
+                    return true;
+                },
+                error: function() {
+                    alert('error!');
+                }
             }
+        });
+    };
+
+    var makeTabs = function($detailView, tabs, options) {
+        if (!options) options = {};
+
+        var $tabs = $('<ul>');
+        var $tabContentGroup = $('<div>');
+        var removedTabs = [];
+        var tabFilter = options.tabFilter;
+        var context = options.context ? options.context : {};
+        var updateContext = $detailView.data('view-args').updateContext;
+        var compact = options.compact;
+
+        if (updateContext) {
+            $.extend($detailView.data('view-args').context, updateContext({
+                context: $detailView

<TRUNCATED>

Mime
View raw message