diff --git a/modules/backend/assets/js/october.tabformexpandcontrols.js b/modules/backend/assets/js/october.tabformexpandcontrols.js
new file mode 100644
index 000000000..499886966
--- /dev/null
+++ b/modules/backend/assets/js/october.tabformexpandcontrols.js
@@ -0,0 +1,163 @@
+/*
+ * Extends the fancy tabs layout with expand controls in the tab
+ * form sections. See main Builder page for example.
+ * TODO: A similar layout is used in the CMS, Pages and Builder areas,
+ * but only Builder uses this class.
+ */
++function ($) { "use strict";
+ var Base = $.oc.foundation.base,
+ BaseProto = Base.prototype
+
+ var TabFormExpandControls = function ($tabsControlElement, options) {
+ this.$tabsControlElement = $tabsControlElement
+ this.options = $.extend(TabFormExpandControls.DEFAULTS, typeof options == 'object' && options)
+ this.tabsControlId = null
+
+ Base.call(this)
+ this.init()
+ }
+
+ TabFormExpandControls.prototype = Object.create(BaseProto)
+ TabFormExpandControls.prototype.constructor = TabFormExpandControls
+
+ TabFormExpandControls.prototype.init = function() {
+ this.tabsControlId = this.$tabsControlElement.attr('id')
+
+ if (!this.tabsControlId) {
+ throw new Error('The tab controls element should have the id attribute value.')
+ }
+
+ this.registerHandlers()
+ }
+
+ TabFormExpandControls.prototype.dispose = function() {
+ this.unregisterHandlers()
+
+ this.$tabsControlElement = null
+
+ BaseProto.dispose.call(this)
+ }
+
+ TabFormExpandControls.prototype.registerHandlers = function() {
+ this.$tabsControlElement.on('initTab.oc.tab', this.proxy(this.initTab))
+ this.$tabsControlElement.on('click', '[data-control="tabless-collapse-icon"]', this.proxy(this.tablessCollapseClicked))
+ this.$tabsControlElement.on('click', '[data-control="primary-collapse-icon"]', this.proxy(this.primaryCollapseClicked))
+ }
+
+ TabFormExpandControls.prototype.unregisterHandlers = function() {
+ this.$tabsControlElement.off('initTab.oc.tab', this.proxy(this.initTab))
+ this.$tabsControlElement.off('click', '[data-control="tabless-collapse-icon"]', this.proxy(this.tablessCollapseClicked))
+ this.$tabsControlElement.off('click', '[data-control="primary-collapse-icon"]', this.proxy(this.primaryCollapseClicked))
+ }
+
+ TabFormExpandControls.prototype.initTab = function(ev, data) {
+ if ($(ev.target).attr('id') != this.tabsControlId)
+ return
+
+ var $primaryPanel = this.findPrimaryPanel(data.pane),
+ $panel = $('.form-tabless-fields', data.pane),
+ $secondaryPanel = this.findSecondaryPanel(data.pane),
+ hasSecondaryTabs = $secondaryPanel.length > 0
+
+ $secondaryPanel.addClass('secondary-content-tabs')
+ $panel.append(this.createTablessCollapseIcon())
+
+ if (!hasSecondaryTabs) {
+ $('.tab-pane', $primaryPanel).addClass('pane-compact')
+ }
+
+ $('.nav-tabs', $primaryPanel).addClass('master-area')
+
+ if ($primaryPanel.length > 0) {
+ $secondaryPanel.append(this.createPrimaryCollapseIcon())
+ } else {
+ $secondaryPanel.addClass('primary-collapsed')
+ }
+
+ if (!$('a', data.tab).hasClass('new-template') && this.getLocalStorageValue('tabless', 0) == 1) {
+ $panel.addClass('collapsed')
+ }
+
+ if (this.getLocalStorageValue('primary', 0) == 1 && hasSecondaryTabs) {
+ $primaryPanel.addClass('collapsed')
+ $secondaryPanel.addClass('primary-collapsed')
+ }
+
+ if (this.options.onInitTab) {
+ this.options.onInitTab($('form', data.pane))
+ }
+ }
+
+ TabFormExpandControls.prototype.tablessCollapseClicked = function(ev) {
+ var $panel = $(ev.target).closest('.form-tabless-fields')
+
+ $panel.toggleClass('collapsed')
+ this.setLocalStorageValue('tabless', $panel.hasClass('collapsed') ? 1 : 0)
+ window.setTimeout(this.proxy(this.updateUi), 500)
+
+ ev.stopPropagation()
+ return false
+ }
+
+ TabFormExpandControls.prototype.primaryCollapseClicked = function(ev) {
+ var $pane = $(ev.target).closest('.tab-pane'),
+ $primaryPanel = this.findPrimaryPanel($pane),
+ $secondaryPanel = this.findSecondaryPanel($pane)
+
+ $primaryPanel.toggleClass('collapsed')
+ $secondaryPanel.toggleClass('primary-collapsed')
+
+ this.updateUi()
+ this.setLocalStorageValue('primary', $primaryPanel.hasClass('collapsed') ? 1 : 0)
+
+ return false
+ }
+
+ TabFormExpandControls.prototype.updateUi = function() {
+ $(window).trigger('oc.updateUi')
+ }
+
+ TabFormExpandControls.prototype.createTablessCollapseIcon = function() {
+ return $('')
+ }
+
+ TabFormExpandControls.prototype.createPrimaryCollapseIcon = function() {
+ return $('')
+ }
+
+ TabFormExpandControls.prototype.generateStorageKey = function(section) {
+ return 'oc' + section + this.tabsControlId.replace('-', '') + 'collapsed'
+ }
+
+ TabFormExpandControls.prototype.findPrimaryPanel = function(pane) {
+ return $(pane).find('.control-tabs.primary-tabs')
+ }
+
+ TabFormExpandControls.prototype.findSecondaryPanel = function(pane) {
+ return $(pane).find('.control-tabs.secondary-tabs')
+ }
+
+ TabFormExpandControls.prototype.getLocalStorageValue = function(section, defaultValue) {
+ var key = this.generateStorageKey(section)
+
+ if (typeof(localStorage) !== 'undefined') {
+ return localStorage[key]
+ }
+
+ return defaultValue
+ }
+
+ TabFormExpandControls.prototype.setLocalStorageValue = function(section, value) {
+ var key = this.generateStorageKey(section)
+
+ if (typeof(localStorage) !== 'undefined') {
+ localStorage[key] = value
+ }
+ }
+
+ TabFormExpandControls.DEFAULTS = {
+ onInitTab: null
+ }
+
+ $.oc.tabFormExpandControls = TabFormExpandControls
+}(window.jQuery);
\ No newline at end of file