1// WITHIN SCOPE OF JQUERY 2(function ($) { 3 $.fn.tabify = function (sender, e) { 4 try { 5 // FOR COLLECTIONS 6 $(sender).each(function () { 7 try { 8 // DEFAULT VALUES WE NEED 9 var _defaults = { 10 sender: this, 11 e: e 12 // ADD CUSTOM SETTINGS 13 , showActions: true 14 , allowActionsToWrapAround: false 15 , tabMovementMustBeSequential: true 16 , startTabIndex: 0 17 , lastTabIndex: 0 || $(this).find('[id*=hiddenData]').find('[id*=hfLastTabIndex]').val() 18 , currentTabIndex: 0 || $(this).find('[id*=hiddenData]').find('[id*=hfCurrentTabIndex]').val() 19 // ADD CUSTOM OVERRIDABLE EVENTS 20 , tabClickEvent: function (sender, e) { 21 try { 22 var continueOn = true; 23 if (typeof onTabClick_Before == 'function') { continueOn = onTabClick_Before(sender, e); } 24 if (continueOn) { 25 // CHECK IF THIS EXISTS! 26 if (this) { 27 // CURRENT SELECTION 28 var toTab = $(this); // THE CURRENT TAB 29 var toPane = null; 30 31 // SECTION AREAS 32 var tabifyObject = toTab.parent().parent(); 33 var tabifyHiddenData = tabifyObject.find('[plugin=data]'); 34 var tabifyTabs = tabifyObject.find('[plugin=tabs]'); 35 var tabifyPanes = tabifyObject.find('[plugin=panes]'); 36 37 // VISUALIZATION SETTINGS 38 var tabMovementMustBeSequential = (tabifyTabs.attr('tabMovementMustBeSequential').toString().toLowerCase() == 'true') || false; 39 40 // DATA CONTROLS 41 var controlLastTabIndex = tabifyHiddenData.find('[id*=hfLastTabIndex]'); 42 var controlCurrentTabIndex = tabifyHiddenData.find('[id*=hfCurrentTabIndex]'); 43 44 // FROM DATA 45 var fromTab = tabifyObject.find('.active'); 46 var fromPane = tabifyPanes.find('.active'); 47 48 var fromLastTabIndex = controlLastTabIndex.val(); 49 var fromTabIndex = controlCurrentTabIndex.val(); 50 var fromPaneID = fromTab.attr('associatepane'); 51 52 // SET ANY SETTINGS WE NEED 53 var _defaults = { 54 tabIndexValue: toTab.attr('tabindex') || -1, 55 associatePaneID: toTab.attr('associatepane') || '' 56 }; 57 var workingSettings = $.extend(true, {}, _defaults, e); 58 59 // CHECK IF I CAN ACTUALLY PROCEED WITH THIS CLICK 60 var doAction = true; 61 var expectedMaxTab = (parseInt(controlCurrentTabIndex.val()) + 1) 62 var expectedMinTab = (parseInt(controlCurrentTabIndex.val()) - 1) 63 64 if (tabMovementMustBeSequential) { 65 if (workingSettings.tabIndexValue != expectedMinTab && workingSettings.tabIndexValue != expectedMaxTab) { 66 doAction = false; 67 // DON'T ALLOW CLICK TO COMPLETE 68 event.stopPropagation(); 69 } 70 } 71 72 if (doAction) { 73 // ANIMATE THE OLD TAB/PANE OF
73F 74 fromTab.removeClass('active'); 75 fromPane.removeClass('active').removeClass('in').stop().fadeOut().hide(); 76 77 // REMOVE ACTIVE CLASS ON BOTH TAB & PANE 78 tabifyObject.find('.active').removeClass('active'); 79 80 // SWAP VALUES 81 // SET LAST TAB INDEX TO LAST CLICK CURRENT TAB INDEX; SO WE CAN SET CURRENT TAB INDEX TO THIS TAB INDEX 82 controlLastTabIndex.val(controlCurrentTabIndex.val()).change(); 83 // SET THE ATTRIBUTE TO WHAT WE JUST SET IT TO 84 controlLastTabIndex.attr('value', controlLastTabIndex.val()); 85 86 87 // COMPLETE THE SWAP AND SET CURRENT TAB INDEX TO THIS TAB INDEX; PRESERVED FOR INCASE OF POSTBACKS 88 controlCurrentTabIndex.val(workingSettings.tabIndexValue).change(); 89 // SET THE ATTRIBUTE TO WHAT WE JUST SET IT TO 90 controlCurrentTabIndex.attr('value', controlCurrentTabIndex.val()); 91 92 // GET THE CURRENT ToPANE FROM THE CURRENT ToTAB ATTRIBUTE 93 toPane = tabifyPanes.find('[id*=' + workingSettings.associatePaneID + ']'); 94 95 96 // ANIMATE THE NEW TAB/PANE ON 97 toTab.addClass('active'); 98 toPane.addClass('active').addClass('in').stop().fadeIn().show(); 99 } 100 } 101 } 102 if (typeof onTabClick_After == 'function') { continueOn = onTabClick_After(sender, e); } 103 } catch (ex) { console.log('Tab Event Click Errored! ' + ex.message); } 104 } 105 , actionClickEvent: function (sender, e) { 106 try { 107 var continueOn = true; 108 if (typeof onActionClick_Before == 'function') { continueOn = onActionClick_Before(sender, e); } 109 if (continueOn) { 110 // CHECK IF THIS EXISTS! 111 if (this) { 112 var selectedAction = $(this); // THE CURRENT ACTION 113 114 // SECTION AREAS 115 var tabifyObject = selectedAction.parent().parent(); 116 var tabifyHiddenData = tabifyObject.find('[plugin=data]'); 117 var tabifyTabs = tabifyObject.find('[plugin=tabs]'); 118 var tabifyPanes = tabifyObject.find('[plugin=panes]'); 119 120 // DATA CONTROLS 121 var controlLastTabIndex = tabifyHiddenData.find('[id*=hfLastTabIndex]'); 122 var controlCurrentTabIndex = tabifyHiddenData.find('[id*=hfCurrentTabIndex]'); 123 124 // SET ANY SETTINGS WE NEED 125 var _defaults = { 126 actionOf: selectedAction.attr('action') || 'actionClicked', 127 allowActionsToWrapAround: selectedAction.attr('allowActionsToWrapAround') || false 128 }; 129 130 var workingSettings = $.extend(true, {}, _defaults, e); 131 workingSettings.allowActionsToWrapAround = (workingSettings.allowActionsToWrapAround.toString().toLowerCase() == 'true'); 132 133 // GET THE CURRENT TAB INDEX 134 var autoClickIndex = parseInt(controlCurrentTabIndex.val()); 135 136 // GET ALL THE TABINDICES (MAP INTO AN ARRAY) 137 var availableTabIndices = $.map($(tabifyTabs.find('[plugin=tab]')), function (element) { 138 return parseInt($(element).attr('tabIndex')); 139 }) || [0]; 140 141 // GET THE LOWER AND UPPER BOUND OF INDEXES AVAILABLE 142 var minTabIndices = 0; 143 var maxTabIndices = Math.max.apply(0, availableTabIndices); 144 145 // HANDLE THE ACTION TO DO 146 switch (workingSettings.actionOf.toString().toLowerCase()) { 147 case 'previous': 148 autoClickIndex -= 1; 149 break; 150 case 'next': 151 autoClickIndex += 1;
152 break; 153 } 154 155 // CHECK IF I CAN ACTUALLY PROCEED WITH THIS CLICK 156 var doAction = true; 157 158 // CAN I DO THIS ACTION? 159 if (autoClickIndex < minTabIndices) { 160 if (!workingSettings.allowActionsToWrapAround) { 161 doAction = false; 162 } 163 else { 164 autoClickIndex = maxTabIndices; 165 } 166 } 167 else if (autoClickIndex > maxTabIndices) { 168 if (!workingSettings.allowActionsToWrapAround) { 169 doAction = false; 170 } 171 else { 172 autoClickIndex = 0; 173 } 174 } 175 176 if (doAction) { 177 tabifyTabs.find('[plugin=tab][tabindex=' + autoClickIndex + ']').click(); 178 } 179 } 180 } 181 if (typeof onActionClick_After == 'function') { continueOn = onActionClick_After(sender, e); } 182 } 183 catch (ex) { console.log('Action Event Click Errored! ' + ex.message); } 184 } 185 }; 186 var workingSettings = $.extend(true, {}, _defaults, e); 187 188 // GET THE OBJECT AND OBJECT SECTIONS WE WORK WITH 189 var myPluginWidget = $(workingSettings.sender); 190 191 myPluginWidget.stop().fadeOut().hide(); 192 193 var myWidgetData = myPluginWidget.find('[plugin=data]'); 194 var myWidgetTabs = myPluginWidget.find('[plugin=tabs]'); 195 var myWidgetPanes = myPluginWidget.find('[plugin=panes]'); 196 var myWidgetActions = myPluginWidget.find('[plugin=actions]'); 197 198 // ADD OUR EVENTS 199 myWidgetTabs.find('[plugin=tab]').on('click', workingSettings.tabClickEvent); 200 myWidgetActions.find('[plugin=action]').on('click', workingSettings.actionClickEvent); 201 202 // SETUP PLUGIN DISPLAY CLASSES 203 // FOR TABS 204 if (!myWidgetTabs.hasClass('nav')) { myWidgetTabs.addClass('nav'); } 205 if (!myWidgetTabs.hasClass('nav-tabs')) { myWidgetTabs.addClass('nav-tabs'); } 206 // if (!myWidgetTabs.hasClass('nav-justified')) { myWidgetTabs.addClass('nav-justified'); } 207 208 myWidgetTabs.attr('tabMovementMustBeSequential', workingSettings.tabMovementMustBeSequential); 209 210 myWidgetTabs.find('[plugin=tab]').each(function () { 211 try { 212 var currentTab = $(this) 213 var templateAnchor = '<a data-toggle="tab" href="#">{0}</a>'; 214 var currentData = currentTab.html(); 215 216 if (currentData.indexOf('data-toggle') < 0) { 217 currentTab.html(templateAnchor.replace('{0}', currentData)); 218 } 219 220 if (!currentTab.hasClass('tab')) { currentTab.addClass('tab') } 221 } 222 catch (ex) { 223 console.log(ex.message); 224 } 225 }); 226 227 // FOR PANES 228 if (!myWidgetPanes.hasClass('tab-content')) { myWidgetPanes.addClass('tab-content'); } 229 230 // FOR ACTIONS 231 if (!myWidgetActions.hasClass('FormButtons')) { myWidgetActions.addClass('FormButtons'); } 232 if (!myWidgetActions.hasClass('buttons')) { myWidgetActions.addClass('buttons'); } 233 myWidgetActions.find('[plugin=action]').each(function () { 234 try { 235 var currentAction = $(this); 236 currentAction.attr('allowActionsToWrapAround', workingSettings.allowActionsToWrapAround); 237 if (!currentAction.hasClass('FormButton')) { currentAction.addClass('FormButton'); } 238 if (!currentAction.hasClass('button')) { currentAction.addClass('button'); } 239 if (!currentAction.hasClass('NO-COPY')) { currentAction.addClass('NO-COPY'); } 240 } 241 catch (ex) { 242 console.log(ex.message); 243 } 244 }); 245 if (!workingSettings.showActions) { myWidgetActions.hide(); } 246 247 // INITIALIZE AND TURN OFF ALL THE PANES 248 myWidgetPanes.find('[plugin=pane]').css('display', 'none'); 249 myWidgetPanes.find('[plugin=pane]').each(function () { 250 try { 251 var currentPane = $(this) 252 if (!currentPane.hasClass('tab-pane')) { currentPane.addClass('tab-pane fade'); } 253 if (!currentPane.hasClass('fade')) { currentPane.addClass('fade'); } 254 } 255 catch (ex) { 256 console.log(ex.message); 257 } 258 }); 259 260 // CLICK THE startTabIndex TAB TO START ON 261 myWidgetTabs.find('[plugin=tab][tabindex=' + workingSettings.startTabIndex + ']').click(); 262 263 264 myPluginWidget.stop().fadeIn().show(); 265 } catch (ex) { console.log(ex.message); } 266 }); 267 } 268 catch (ex) { 269 console.log('plugin global try...catch'); 270 } 271 } 272 273 // EXAMPLE USAGE 274 //$(document).ready(function () { 275 // try { $.fn.tabify($('[plugin=tabify]'), { showActions: true, allowActionsToWrapAround: false, tabMovementMustBeSequential: true, startTabIndex: 0 }); } catch (ex) { console.log('Plugin failed! ' + ex.message); } 276 //}); 277})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.